Implement key persistence for server

This commit is contained in:
Tissevert 2020-01-27 16:00:03 +01:00
parent 81ec84abaf
commit f1b44d649d
4 changed files with 46 additions and 4 deletions

View file

@ -1,4 +1,4 @@
# Revision history for hanafudapi # Revision history for hanafuda-server
## 0.2.3.0 -- 2019-08-24 ## 0.2.3.0 -- 2019-08-24

View file

@ -1,4 +1,4 @@
-- Initial hanafudapi.cabal generated by cabal init. For further -- Initial hanafuda-server.cabal generated by cabal init. For further
-- documentation, see http://haskell.org/cabal/users-guide/ -- documentation, see http://haskell.org/cabal/users-guide/
name: hanafuda-server name: hanafuda-server
@ -35,6 +35,8 @@ executable hanafudapi
build-depends: base >=4.9 && <4.13 build-depends: base >=4.9 && <4.13
, bytestring , bytestring
, containers >= 0.5.9 , containers >= 0.5.9
, directory
, filepath
, unordered-containers , unordered-containers
, hanafuda >= 0.3.3 , hanafuda >= 0.3.3
, hanafuda-protocol >= 0.1.0 , hanafuda-protocol >= 0.1.0

View file

@ -1,6 +1,10 @@
module Config ( module Config (
listenPort libDir
, listenPort
) where ) where
libDir :: FilePath
libDir = "/var/lib/hanafuda-server"
listenPort :: Int listenPort :: Int
listenPort = 3000 listenPort = 3000

View file

@ -1,3 +1,4 @@
{-# LANGUAGE NamedFieldPuns #-}
module Keys ( module Keys (
T(..) T(..)
, getKeys , getKeys
@ -5,19 +6,54 @@ module Keys (
, secret , secret
) where ) where
import Config (libDir)
import Control.Monad.State (MonadState(..), StateT(..), evalStateT, lift)
import Crypto.Saltine.Class (IsEncoding(..))
import qualified Crypto.Saltine.Core.SecretBox as Encrypt (Key, newKey) import qualified Crypto.Saltine.Core.SecretBox as Encrypt (Key, newKey)
import qualified Crypto.Saltine.Core.Sign as Sign ( import qualified Crypto.Saltine.Core.Sign as Sign (
Keypair, PublicKey, SecretKey, newKeypair Keypair, PublicKey, SecretKey, newKeypair
) )
import qualified Data.ByteString as BS (
ByteString, length, readFile, singleton, splitAt, uncons, writeFile
)
import System.Directory (createDirectoryIfMissing, doesFileExist)
import System.Exit (die)
import System.FilePath ((</>))
data T = T { data T = T {
encrypt :: Encrypt.Key encrypt :: Encrypt.Key
, sign :: Sign.Keypair , sign :: Sign.Keypair
} }
serialize :: T -> BS.ByteString
serialize (T {encrypt, sign = (secretKey, publicKey)}) =
mconcat [encodeKey encrypt, encodeKey secretKey, encodeKey publicKey]
where
encodeKey key =
let encodedKey = encode key in
(BS.singleton . toEnum $ BS.length encodedKey) <> encodedKey
unserialize :: BS.ByteString -> Maybe T
unserialize = evalStateT $ T <$> decodeKey <*> ((,) <$> decodeKey <*> decodeKey)
where
decodeKey :: IsEncoding a => StateT BS.ByteString Maybe a
decodeKey = do
keyLength <- fromEnum <$> StateT BS.uncons
lift . decode =<< state (BS.splitAt keyLength)
getKeys :: IO T getKeys :: IO T
getKeys = do getKeys = do
T <$> Encrypt.newKey <*> Sign.newKeypair fileExists <- doesFileExist keyRing
if fileExists
then BS.readFile keyRing >>= tryUnserialize
else do
newT <- T <$> Encrypt.newKey <*> Sign.newKeypair
createDirectoryIfMissing True libDir
BS.writeFile keyRing $ serialize newT
return newT
where
keyRing = libDir </> "keys"
tryUnserialize = maybe (die "Could not unserialize key") return . unserialize
public :: Sign.Keypair -> Sign.PublicKey public :: Sign.Keypair -> Sign.PublicKey
public = snd public = snd