1
0
Fork 0
mirror of https://code.sup39.dev/repos/Wqawg synced 2024-12-29 02:34:51 +09:00
vervis/src/Web/ActivityAccess.hs

89 lines
2.8 KiB
Haskell

{- This file is part of Vervis.
-
- Written in 2019 by fr33domlover <fr33domlover@riseup.net>.
-
- ♡ Copying is an act of love. Please copy, reuse and share.
-
- The author(s) have dedicated all copyright and related and neighboring
- rights to this software to the public domain worldwide. This software is
- distributed without any warranty.
-
- You should have received a copy of the CC0 Public Domain Dedication along
- with this software. If not, see
- <http://creativecommons.org/publicdomain/zero/1.0/>.
-}
module Web.ActivityAccess
( SignedAccessToken ()
, AccessTokenSecretKey ()
, encodeSignedAccessToken
, decodeSignedAccessToken
, signAccessToken
, verifyAccessToken
)
where
import Prelude
import Crypto.Hash
import Crypto.MAC.HMAC
import Crypto.Random
import Data.ByteString (ByteString)
import Data.KeyFile
import qualified Data.ByteArray as BA
import qualified Data.ByteString as B
import qualified Data.ByteString.Base64 as B64
import qualified Data.ByteString.Char8 as BC
data SignedAccessToken = SignedAccessToken
{ _accessTokenMsg :: ByteString
, _accessTokenHMAC :: HMAC SHA256
}
newtype AccessTokenSecretKey = AccessTokenSecretKey ByteString
instance KeyFile AccessTokenSecretKey where
generateKey = AccessTokenSecretKey <$> getRandomBytes 32
parseKey b =
if B.length b == 32
then return $ AccessTokenSecretKey b
else fail "AccessTokenSigningKey parseKey invalid length"
renderKey (AccessTokenSecretKey b) = b
encodeSignedAccessToken :: SignedAccessToken -> ByteString
encodeSignedAccessToken (SignedAccessToken msg sig) = B.concat
[ msg
, "-"
, B64.encode $ BA.convert sig
]
decodeSignedAccessToken :: ByteString -> Either String SignedAccessToken
decodeSignedAccessToken token = do
let (msg, rest) = BC.break (== '-') token
sigB64 <-
case B.stripPrefix "-" rest of
Nothing -> err "Invalid format, separator not found"
Just rest' -> return rest'
sigBin <-
case B64.decode sigB64 of
Left s -> err $ "Base64 decoding sig failed: " ++ s
Right b -> return b
digest <-
case digestFromByteString sigBin of
Nothing -> err "Decoding sig hash failed, invalid length"
Just d -> return d
return $ SignedAccessToken msg $ HMAC digest
where
err s = Left $ "decodeSignedAccessToken: " ++ s
signAccessToken :: AccessTokenSecretKey -> ByteString -> SignedAccessToken
signAccessToken (AccessTokenSecretKey key) msg =
SignedAccessToken msg $ hmac key msg
verifyAccessToken
:: AccessTokenSecretKey -> SignedAccessToken -> Maybe ByteString
verifyAccessToken (AccessTokenSecretKey key) (SignedAccessToken msg sig) =
if hmac key msg == sig
then Just msg
else Nothing