module Ssb.Identity where import Protolude hiding ( Identity ) import Control.Monad.Fail import Data.Aeson hiding ( encode ) import qualified Data.ByteString.Base64 as Base64 import qualified Crypto.Saltine.Core.Sign as Nacl import qualified Crypto.Saltine.Class as Nacl import Data.Serialize ( Serialize ) import Data.Either.Combinators ( mapLeft ) import qualified Data.ByteString as S import qualified Data.Text as T newtype PrivateKey = PrivateKey ByteString deriving (Eq,Generic,Ord,Show) extractPrivateKey :: PrivateKey -> ByteString extractPrivateKey (PrivateKey a) = a instance Serialize PrivateKey formatPrivateKey :: PrivateKey -> Text formatPrivateKey (PrivateKey buf) = "@" <> pubKey <> ".ed25519" where pubKey = decodeUtf8 $ Base64.encode buf parsePrivateKey :: Text -> Either Text PrivateKey parsePrivateKey arg = decode $ T.dropEnd constLen $ T.drop 1 arg where constLen = T.length ".ed25519" decode = fmap PrivateKey . mapLeft toS . Base64.decode . encodeUtf8 instance FromJSON PrivateKey where parseJSON = withText "PrivateKey" $ \v -> case parsePrivateKey v of Left err -> fail $ toS err Right a -> return a instance ToJSON PrivateKey where toJSON arg = String $ formatPrivateKey arg newtype PublicKey = PublicKey ByteString deriving (Eq,Generic,Ord,Show) extractPublicKey :: PublicKey -> ByteString extractPublicKey (PublicKey a) = a instance Serialize PublicKey formatPublicKey :: PublicKey -> Text formatPublicKey (PublicKey buf) = "@" <> pubKey <> ".ed25519" where pubKey = decodeUtf8 $ Base64.encode buf parsePublicKey :: Text -> Either Text PublicKey parsePublicKey arg = decode $ T.dropEnd constLen $ T.drop 1 arg where constLen = T.length ".ed25519" decode = fmap PublicKey . mapLeft toS . Base64.decode . encodeUtf8 instance FromJSON PublicKey where parseJSON = withText "PublicKey" $ \v -> case parsePublicKey v of Left err -> fail $ toS err Right a -> return a instance ToJSON PublicKey where toJSON arg = String $ formatPublicKey arg -- | Identity represents a user or agent on the scuttlebutt network. Each of -- these entities own their own append-only message feed. data Identity = Identity { privateKey :: Maybe PrivateKey , publicKey :: PublicKey } deriving (Eq,Generic,Show) instance FromJSON Identity instance ToJSON Identity newIdentity :: IO Identity newIdentity = do (secret, public) <- Nacl.newKeypair return Identity { privateKey = Just $ PrivateKey $ Nacl.encode secret , publicKey = PublicKey $ Nacl.encode public }