Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions realworld-hs.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ library
TypeFamilies
GADTs
ViewPatterns
NoFieldSelectors
ghc-options: -Wall -Wno-orphans -Wno-unrecognised-pragmas -O1
build-depends:
aeson
Expand Down Expand Up @@ -113,7 +112,7 @@ library
mixins:
base hiding (Prelude)
, relude (Relude as Prelude)
, relude
, relude
default-language: GHC2021

executable app
Expand Down Expand Up @@ -169,7 +168,7 @@ executable app
mixins:
base hiding (Prelude)
, relude (Relude as Prelude)
, relude
, relude
default-language: GHC2021

test-suite spec
Expand Down Expand Up @@ -232,5 +231,5 @@ test-suite spec
mixins:
base hiding (Prelude)
, relude (Relude as Prelude)
, relude
, relude
default-language: GHC2021
5 changes: 2 additions & 3 deletions src/Conduit/Features/Articles/Articles/FeedArticles.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ import Conduit.Utils ((.-))
import Data.List (lookup)
import Database.Esqueleto.Experimental (groupBy, in_, limit, offset, orderBy, select, val, valList, where_, (:&)(..), (==.))
import Database.Esqueleto.Experimental qualified as E
import Relude.Extra (bimapBoth)
import UnliftIO (MonadUnliftIO)
import Web.Scotty.Trans (ActionT, ScottyT, captureParams, get, json)
import Web.Scotty.Trans.Strict (ActionT, ScottyT, captureParams, get, json)

data FilterOps = FilterOps
{ filterLimit :: Int64
Expand All @@ -39,7 +38,7 @@ getFeedArticles userID ops = runExceptT do

parseFilterOps :: ActionT AppM FilterOps
parseFilterOps = do
params <- captureParams <&> map (bimapBoth toStrict)
params <- captureParams

pure $ FilterOps
{ filterLimit = (lookup "limit" params >>= toString .- readMaybe) ?: 20
Expand Down
3 changes: 1 addition & 2 deletions src/Conduit/Features/Articles/Articles/ListArticles.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import Data.Text.Lazy.Builder qualified as TB
import Database.Esqueleto.Experimental (exists, from, groupBy, in_, just, leftJoin, limit, offset, on, orderBy, select, subSelectList, table, val, valList, where_, (:&) (..), (==.))
import Database.Esqueleto.Experimental qualified as E
import Database.Esqueleto.Internal.Internal (unsafeSqlValue)
import Relude.Extra (bimapBoth)
import UnliftIO (MonadUnliftIO)
import Web.Scotty.Trans (ActionT, ScottyT, captureParams, get, json)

Expand All @@ -39,7 +38,7 @@ handleListArticles = get "/api/articles/" $ maybeWithAuth \user -> do

parseFilterOps :: ActionT AppM FilterOps
parseFilterOps = do
params <- captureParams <&> map (bimapBoth toStrict)
params <- captureParams

pure $ FilterOps
{ filterTag = lookup "tag" params
Expand Down
4 changes: 2 additions & 2 deletions src/Conduit/Identity/JWT.hs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Conduit.Identity.JWT where

import Conduit.Features.Account.Types (UserID, unID)
import Conduit.Features.Account.Types (UserID(..))
import Data.Aeson (FromJSON)
import Data.Time (NominalDiffTime)
import Web.JWT (EncodeSigner, JWTClaimsSet(..), VerifySigner, hmacSecret, numericDate, stringOrURI, toVerify)
Expand Down Expand Up @@ -41,6 +41,6 @@ mkClaims :: NominalDiffTime -> Seconds -> UserID -> JWTClaimsSet
mkClaims currTime (Seconds ttl) userID = mempty
{ iss = stringOrURI "conduit-api"
, aud = Left <$> stringOrURI "conduit-client"
, sub = stringOrURI $ show userID.unID
, sub = stringOrURI $ show (unID userID)
, exp = numericDate $ currTime + fromIntegral ttl
}
20 changes: 17 additions & 3 deletions src/Conduit/Identity/Password.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{-# LANGUAGE UndecidableInstances, FieldSelectors #-}
{-# LANGUAGE CPP #-}

module Conduit.Identity.Password
( HashedPassword(..)
Expand All @@ -15,7 +16,10 @@ import Crypto.KDF.Argon2 qualified as Argon
import Crypto.Random (MonadRandom (getRandomBytes))
import Data.Aeson (FromJSON)
import Data.ByteArray (Bytes, convert)
import Data.ByteString.Base64 (decodeBase64, encodeBase64)
import Data.ByteString.Base64
#if MIN_VERSION_base64(1,0,0)
import Data.Base64.Types
#endif
import Data.Text (splitOn)
import Relude.Unsafe as Unsafe ((!!))

Expand Down Expand Up @@ -45,7 +49,7 @@ argonOptions = defaultOptions
{ variant = Argon2id
, parallelism = 2
, iterations = 2
, memory = 65536
, memory = 65536
}

hashStrParams :: Text
Expand All @@ -56,7 +60,11 @@ newSalt :: (MonadIO m) => m ByteString
newSalt = liftIO $ getRandomBytes 16

extractSalt :: HashedPassword -> Maybe ByteString
#if MIN_VERSION_base64(1,0,0)
extractSalt (HashedPassword hash') = rightToMaybe . decodeBase64Untyped . encodeUtf8 $ splitOn "$" hash' Unsafe.!! 4
#else
extractSalt (HashedPassword hash') = rightToMaybe . decodeBase64 . encodeUtf8 $ splitOn "$" hash' Unsafe.!! 4
#endif

text2bytes :: Text -> Bytes
text2bytes = convert . encodeUtf8 @_ @ByteString
Expand All @@ -69,7 +77,13 @@ hashPasswordWithSalt (UnsafePassword password) salt =
in mkHashedPassword (convert digest) salt

mkHashedPassword :: ByteString -> ByteString -> HashedPassword
mkHashedPassword digest salt = HashedPassword $ hashStrParams <> salt' <> "$" <> digest'
#if MIN_VERSION_base64(1,0,0)
mkHashedPassword digest salt = HashedPassword $
hashStrParams <> extractBase64 salt' <> "$" <> extractBase64 digest'
#else
mkHashedPassword digest salt = HashedPassword $
hashStrParams <> salt' <> "$" <> digest'
#endif
where digest' = encodeBase64 digest; salt' = encodeBase64 salt;

-- | Validates a plaintext password against its hashed potential counterpart.
Expand Down