11module Registry.SSH
22 ( PublicKey
33 , PrivateKey
4+ , PrivateKeyParseError (..)
5+ , printPrivateKeyParseError
46 , Signature (..)
57 , parsePublicKey
68 , parsePrivateKey
7- , parsePrivateKeyWithPassword
9+ , publicKeyToOwner
810 , sign
911 , verify
1012 ) where
1113
1214import Prelude
1315
16+ import Data.Bifunctor (bimap )
1417import Data.Either (Either (..))
1518import Data.Function.Uncurried (Fn1 , Fn2 , Fn3 , Fn4 , runFn1 , runFn2 , runFn3 , runFn4 )
19+ import Data.Maybe (Maybe )
1620import Data.Newtype (class Newtype )
17- import Data.Nullable (Nullable , notNull , null )
21+ import Data.Nullable (Nullable , null )
22+ import Data.Nullable as Nullable
1823import Effect.Exception as Exception
24+ import Registry.Owner (Owner (..))
1925
2026-- | A parsed SSH public key which can be used to verify payloads.
2127newtype PublicKey = PublicKey ParsedKey
@@ -37,18 +43,23 @@ foreign import parseKeyImpl :: forall r. Fn4 (Exception.Error -> r) (ParsedKey -
3743parse :: String -> Either String ParsedKey
3844parse buf = runFn4 parseKeyImpl (Left <<< Exception .message) Right buf null
3945
40- -- | Parse a non-password-protected private SSH key
41- parsePrivateKey :: String -> Either String PrivateKey
42- parsePrivateKey key = case parse key of
43- Right parsed | not (isPrivateKey parsed) -> Left $ " Expected private key, but this is a public key of type " <> keyType parsed
44- result -> map PrivateKey result
46+ data PrivateKeyParseError
47+ = GotPublicKeyInstead String
48+ | RequiresPassphrase
49+ | OtherParseError String
4550
46- -- | Parse a password-protected private SSH key
47- parsePrivateKeyWithPassword :: { key :: String , passphrase :: String } -> Either String PrivateKey
48- parsePrivateKeyWithPassword { key, passphrase } =
49- case runFn4 parseKeyImpl (Left <<< Exception .message) Right key (notNull passphrase) of
50- Right parsed | not (isPrivateKey parsed) -> Left $ " Expected private key, but this is a public key of type " <> keyType parsed
51- result -> map PrivateKey result
51+ printPrivateKeyParseError :: PrivateKeyParseError -> String
52+ printPrivateKeyParseError = case _ of
53+ GotPublicKeyInstead keyType' -> " Expected private key, but got public key of type " <> keyType'
54+ RequiresPassphrase -> " Encrypted private key requires a passphrase"
55+ OtherParseError message -> message
56+
57+ parsePrivateKey :: { key :: String , passphrase :: Maybe String } -> Either PrivateKeyParseError PrivateKey
58+ parsePrivateKey { key, passphrase } =
59+ case runFn4 parseKeyImpl (Left <<< Exception .message) Right key (Nullable .toNullable passphrase) of
60+ Right parsed | not (isPrivateKey parsed) -> Left $ GotPublicKeyInstead $ keyType parsed
61+ Left " Encrypted private OpenSSH key detected, but no passphrase given" -> Left RequiresPassphrase
62+ result -> bimap OtherParseError PrivateKey result
5263
5364-- | Parse a public SSH key
5465parsePublicKey :: String -> Either String PublicKey
@@ -88,3 +99,10 @@ isPrivateKey :: ParsedKey -> Boolean
8899isPrivateKey = runFn1 isPrivateKeyImpl
89100
90101foreign import equalsImpl :: Fn2 ParsedKey ParsedKey Boolean
102+
103+ foreign import publicToOwnerImpl :: Fn1 PublicKey { keytype :: String , public :: String , id :: Nullable String }
104+
105+ publicKeyToOwner :: PublicKey -> Owner
106+ publicKeyToOwner key = do
107+ let { id: nullableId, keytype, public } = runFn1 publicToOwnerImpl key
108+ Owner { keytype, public, id: Nullable .toMaybe nullableId }
0 commit comments