{-# LANGUAGE OverloadedStrings #-}
module SDJWT.Internal.Serialization
( serializeSDJWT
, deserializeSDJWT
, serializePresentation
, deserializePresentation
, parseTildeSeparated
) where
import SDJWT.Internal.Types (SDJWT(..), SDJWTPresentation(..), SDJWTError(..), EncodedDisclosure(..))
import Data.Maybe (fromMaybe)
import qualified Data.Text as T
serializeSDJWT :: SDJWT -> T.Text
serializeSDJWT :: SDJWT -> Text
serializeSDJWT (SDJWT Text
jwt [EncodedDisclosure]
sdDisclosures) =
let
disclosureParts :: [Text]
disclosureParts = (EncodedDisclosure -> Text) -> [EncodedDisclosure] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map EncodedDisclosure -> Text
unEncodedDisclosure [EncodedDisclosure]
sdDisclosures
allParts :: [Text]
allParts = Text
jwt Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text]
disclosureParts [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [Text
""]
in
Text -> [Text] -> Text
T.intercalate Text
"~" [Text]
allParts
deserializeSDJWT :: T.Text -> Either SDJWTError SDJWT
deserializeSDJWT :: Text -> Either SDJWTError SDJWT
deserializeSDJWT Text
input =
case Text -> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text)
parseTildeSeparated Text
input of
Left SDJWTError
err -> SDJWTError -> Either SDJWTError SDJWT
forall a b. a -> Either a b
Left SDJWTError
err
Right (Text
jwt, [EncodedDisclosure]
sdDisclosures, Maybe Text
Nothing) ->
SDJWT -> Either SDJWTError SDJWT
forall a b. b -> Either a b
Right (SDJWT -> Either SDJWTError SDJWT)
-> SDJWT -> Either SDJWTError SDJWT
forall a b. (a -> b) -> a -> b
$ Text -> [EncodedDisclosure] -> SDJWT
SDJWT Text
jwt [EncodedDisclosure]
sdDisclosures
Right (Text
_, [EncodedDisclosure]
_, Just Text
_) ->
SDJWTError -> Either SDJWTError SDJWT
forall a b. a -> Either a b
Left (SDJWTError -> Either SDJWTError SDJWT)
-> SDJWTError -> Either SDJWTError SDJWT
forall a b. (a -> b) -> a -> b
$ Text -> SDJWTError
SerializationError Text
"SD-JWT should not have Key Binding JWT (use SD-JWT+KB format)"
serializePresentation :: SDJWTPresentation -> T.Text
serializePresentation :: SDJWTPresentation -> Text
serializePresentation (SDJWTPresentation Text
jwt [EncodedDisclosure]
sdDisclosures Maybe Text
mbKbJwt) =
let
disclosureParts :: [Text]
disclosureParts = (EncodedDisclosure -> Text) -> [EncodedDisclosure] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map EncodedDisclosure -> Text
unEncodedDisclosure [EncodedDisclosure]
sdDisclosures
kbPart :: Text
kbPart = Text -> Maybe Text -> Text
forall a. a -> Maybe a -> a
fromMaybe Text
"" Maybe Text
mbKbJwt
allParts :: [Text]
allParts = Text
jwt Text -> [Text] -> [Text]
forall a. a -> [a] -> [a]
: [Text]
disclosureParts [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [Text
kbPart]
in
Text -> [Text] -> Text
T.intercalate Text
"~" [Text]
allParts
deserializePresentation :: T.Text -> Either SDJWTError SDJWTPresentation
deserializePresentation :: Text -> Either SDJWTError SDJWTPresentation
deserializePresentation Text
input =
case Text -> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text)
parseTildeSeparated Text
input of
Left SDJWTError
err -> SDJWTError -> Either SDJWTError SDJWTPresentation
forall a b. a -> Either a b
Left SDJWTError
err
Right (Text
jwt, [EncodedDisclosure]
sdDisclosures, Maybe Text
mbKbJwt) ->
SDJWTPresentation -> Either SDJWTError SDJWTPresentation
forall a b. b -> Either a b
Right (SDJWTPresentation -> Either SDJWTError SDJWTPresentation)
-> SDJWTPresentation -> Either SDJWTError SDJWTPresentation
forall a b. (a -> b) -> a -> b
$ Text -> [EncodedDisclosure] -> Maybe Text -> SDJWTPresentation
SDJWTPresentation Text
jwt [EncodedDisclosure]
sdDisclosures Maybe Text
mbKbJwt
parseTildeSeparated :: T.Text -> Either SDJWTError (T.Text, [EncodedDisclosure], Maybe T.Text)
parseTildeSeparated :: Text -> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text)
parseTildeSeparated Text
input =
let
parts :: [Text]
parts = HasCallStack => Text -> Text -> [Text]
Text -> Text -> [Text]
T.splitOn Text
"~" Text
input
in
case [Text]
parts of
[] -> SDJWTError
-> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text)
forall a b. a -> Either a b
Left (SDJWTError
-> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text))
-> SDJWTError
-> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text)
forall a b. (a -> b) -> a -> b
$ Text -> SDJWTError
SerializationError Text
"Empty SD-JWT"
[Text
jwt] ->
(Text, [EncodedDisclosure], Maybe Text)
-> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text)
forall a b. b -> Either a b
Right (Text
jwt, [], Maybe Text
forall a. Maybe a
Nothing)
Text
jwt : [Text]
rest ->
let
([Text]
disclosureParts, Maybe Text
lastPart) = case [Text] -> [Text]
forall a. [a] -> [a]
reverse [Text]
rest of
[] -> [Char] -> ([Text], Maybe Text)
forall a. HasCallStack => [Char] -> a
error [Char]
"parseTildeSeparated: impossible case - rest should be non-empty"
Text
lastItem : [Text]
revDisclosures ->
if Text -> Bool
T.null Text
lastItem
then ([Text] -> [Text]
forall a. [a] -> [a]
reverse [Text]
revDisclosures, Maybe Text
forall a. Maybe a
Nothing)
else ([Text] -> [Text]
forall a. [a] -> [a]
reverse [Text]
revDisclosures, Text -> Maybe Text
forall a. a -> Maybe a
Just Text
lastItem)
sdDisclosures :: [EncodedDisclosure]
sdDisclosures = (Text -> EncodedDisclosure) -> [Text] -> [EncodedDisclosure]
forall a b. (a -> b) -> [a] -> [b]
map Text -> EncodedDisclosure
EncodedDisclosure [Text]
disclosureParts
in
(Text, [EncodedDisclosure], Maybe Text)
-> Either SDJWTError (Text, [EncodedDisclosure], Maybe Text)
forall a b. b -> Either a b
Right (Text
jwt, [EncodedDisclosure]
sdDisclosures, Maybe Text
lastPart)