From 019c080687ce4a07031bdfe2263397f4f868c3c3 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 31 Aug 2016 14:30:35 -0400 Subject: added --store-directory --- CHANGELOG | 3 ++- CmdLine.hs | 10 +++++++++- HTTP/Server.hs | 24 +++++++++++++----------- INSTALL | 4 ++++ Storage.hs | 18 +++++++++--------- Storage/Local.hs | 14 ++++++++------ Storage/Network.hs | 6 +++--- Types/Storage.hs | 2 ++ keysafe.hs | 7 ++++--- 9 files changed, 54 insertions(+), 34 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index e9dc8c2..073f2d9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ keysafe (0.20160820) UNRELEASED; urgency=medium - * Server implementation. + * Server implementation is ready for deployment. * Removed embedded copy of secret-sharing library, since finite-field only supports prime fields. This caused shares to be twice the size of the input value. @@ -9,6 +9,7 @@ keysafe (0.20160820) UNRELEASED; urgency=medium * Tuned argon2 hash parameters on better hardware than my fanless laptop. * Improve time estimates, taking into account the number of cores. * Added basic test suite. + * Added options: --store-directory -- Joey Hess Mon, 22 Aug 2016 13:56:16 -0400 diff --git a/CmdLine.hs b/CmdLine.hs index a8201c8..05ba7da 100644 --- a/CmdLine.hs +++ b/CmdLine.hs @@ -6,6 +6,7 @@ module CmdLine where import Types +import Types.Storage import Tunables import qualified Gpg import Options.Applicative @@ -17,6 +18,7 @@ data CmdLine = CmdLine { mode :: Maybe Mode , secretkeysource :: Maybe SecretKeySource , localstorage :: Bool + , localstoragedirectory :: Maybe LocalStorageDirectory , gui :: Bool , testMode :: Bool , customShareParams :: Maybe ShareParams @@ -36,6 +38,7 @@ parse = CmdLine <$> optional (backup <|> restore <|> uploadqueued <|> server <|> benchmark <|> test) <*> optional (gpgswitch <|> fileswitch) <*> localstorageswitch + <*> localstoragedirectory <*> guiswitch <*> testmodeswitch <*> optional (ShareParams <$> totalobjects <*> neededobjects) @@ -77,7 +80,12 @@ parse = CmdLine ) localstorageswitch = switch ( long "store-local" - <> help "Store data locally, in ~/.keysafe/objects/local/. (The default is to store data in the cloud.)" + <> help "Store data locally. (The default is to store data in the cloud.)" + ) + localstoragedirectory = optional $ LocalStorageDirectory <$> option str + ( long "store-directory" + <> metavar "DIR" + <> help "Where to store data locally. (default: ~/.keysafe/objects/)" ) testmodeswitch = switch ( long "testmode" diff --git a/HTTP/Server.hs b/HTTP/Server.hs index 3e0b9aa..5d5c87f 100644 --- a/HTTP/Server.hs +++ b/HTTP/Server.hs @@ -24,23 +24,25 @@ import qualified Data.ByteString as B data ServerState = ServerState { obscurerRequest :: TMVar () + , storageDirectory :: Maybe LocalStorageDirectory } -newServerState :: IO ServerState -newServerState = ServerState +newServerState :: Maybe LocalStorageDirectory -> IO ServerState +newServerState d = ServerState <$> newEmptyTMVarIO + <*> pure d -runServer :: String -> Port -> IO () -runServer bindaddress port = do - st <- newServerState +runServer :: Maybe LocalStorageDirectory -> String -> Port -> IO () +runServer d bindaddress port = do + st <- newServerState d _ <- forkIO $ obscurerThread st runSettings settings (app st) where settings = setHost host $ setPort port $ defaultSettings host = fromString bindaddress -serverStorage :: Storage -serverStorage = localStorage userStorageDir "server" +serverStorage :: ServerState -> Storage +serverStorage st = localStorage (storageDir $ storageDirectory st) "server" app :: ServerState -> Application app st = serve userAPI (server st) @@ -59,7 +61,7 @@ motd = return $ Motd "Hello World!" getObject :: ServerState -> StorableObjectIdent -> Maybe ProofOfWork -> Handler (ProofOfWorkRequirement StorableObject) getObject st i _pow = do - r <- liftIO $ retrieveShare serverStorage dummyShareNum i + r <- liftIO $ retrieveShare (serverStorage st) dummyShareNum i liftIO $ requestObscure st case r of RetrieveSuccess (Share _n o) -> return $ Result o @@ -69,7 +71,7 @@ putObject :: ServerState -> StorableObjectIdent -> Maybe ProofOfWork -> Storable putObject st i _pow o = do if validObjectsize o then do - r <- liftIO $ storeShare serverStorage i (Share dummyShareNum o) + r <- liftIO $ storeShare (serverStorage st) i (Share dummyShareNum o) liftIO $ requestObscure st return $ Result r else return $ Result $ StoreFailure "invalid object size" @@ -80,7 +82,7 @@ validObjectsize o = any (sz ==) knownObjectSizes sz = B.length (fromStorableObject o) countObjects :: ServerState -> Maybe ProofOfWork -> Handler (ProofOfWorkRequirement CountResult) -countObjects _st _pow = liftIO $ Result <$> countShares serverStorage +countObjects st _pow = liftIO $ Result <$> countShares (serverStorage st) -- | 1 is a dummy value; the server does not know the actual share numbers. dummyShareNum :: ShareNum @@ -91,7 +93,7 @@ dummyShareNum = 1 -- the thread runs a maximum of once per half-hour. obscurerThread :: ServerState -> IO () obscurerThread st = do - _ <- obscureShares serverStorage + _ <- obscureShares (serverStorage st) putStrLn "obscured shares" threadDelay (1000000*60*30) _ <- atomically $ takeTMVar (obscurerRequest st) diff --git a/INSTALL b/INSTALL index 78d7c7f..97b0935 100644 --- a/INSTALL +++ b/INSTALL @@ -8,3 +8,7 @@ Then to build and install keysafe: stack install keysafe Note that there is a manpage, but stack doesn't install it yet. + +## Server installation + +useradd --system keysafe diff --git a/Storage.hs b/Storage.hs index c9446c5..43e16cd 100644 --- a/Storage.hs +++ b/Storage.hs @@ -16,15 +16,15 @@ import System.FilePath import Control.Monad import qualified Data.Set as S -allStorageLocations :: IO StorageLocations -allStorageLocations = do +allStorageLocations :: Maybe LocalStorageDirectory -> IO StorageLocations +allStorageLocations d = do servers <- networkServers return $ StorageLocations $ - map networkStorage servers <> map uploadQueue servers + map networkStorage servers <> map (uploadQueue d) servers -localStorageLocations :: StorageLocations -localStorageLocations = StorageLocations $ - map (localStorage userStorageDir . ("local" ) . show) +localStorageLocations :: Maybe LocalStorageDirectory -> StorageLocations +localStorageLocations d = StorageLocations $ + map (localStorage (storageDir d) . ("local" ) . show) [1..100 :: Int] type UpdateProgress = IO () @@ -99,7 +99,7 @@ retrieveShares (StorageLocations locs) sis updateprogress = do -- all of them. go (unusedlocs++[loc]) usedlocs' rest shares' -uploadQueued :: IO () -uploadQueued = do +uploadQueued :: Maybe LocalStorageDirectory -> IO () +uploadQueued d = do servers <- networkServers - forM_ servers $ \s -> moveShares (uploadQueue s) (networkStorage s) + forM_ servers $ \s -> moveShares (uploadQueue d s) (networkStorage s) diff --git a/Storage/Local.hs b/Storage/Local.hs index d0a1d15..38fc5b7 100644 --- a/Storage/Local.hs +++ b/Storage/Local.hs @@ -3,7 +3,7 @@ - Licensed under the GNU AGPL version 3 or higher. -} -module Storage.Local (localStorage, userStorageDir, testStorageDir, uploadQueue) where +module Storage.Local (localStorage, storageDir, testStorageDir, uploadQueue) where import Types import Types.Storage @@ -38,8 +38,8 @@ localStorage getsharedir n = Storage where section = Section n -uploadQueue :: Server -> Storage -uploadQueue s = localStorage userStorageDir ("uploadqueue" serverName s) +uploadQueue :: Maybe LocalStorageDirectory -> Server -> Storage +uploadQueue d s = localStorage (storageDir d) ("uploadqueue" serverName s) store :: Section -> GetShareDir -> StorableObjectIdent -> Share -> IO StoreResult store section getsharedir i s = onError (StoreFailure . show) $ do @@ -117,13 +117,15 @@ onError f a = do Left e -> f e Right r -> r -userStorageDir :: GetShareDir -userStorageDir (Section section) = do +storageDir :: Maybe LocalStorageDirectory -> GetShareDir +storageDir Nothing (Section section) = do u <- getUserEntryForID =<< getEffectiveUserID return $ homeDirectory u dotdir section +storageDir (Just (LocalStorageDirectory d)) (Section section) = + pure $ d section testStorageDir :: FilePath -> GetShareDir -testStorageDir tmpdir (Section section) = pure $ tmpdir section +testStorageDir tmpdir = storageDir (Just (LocalStorageDirectory tmpdir)) -- | The takeFileName ensures that, if the StorableObjectIdent somehow -- contains a path (eg starts with "../" or "/"), it is not allowed diff --git a/Storage/Network.hs b/Storage/Network.hs index 356f5ad..d16d693 100644 --- a/Storage/Network.hs +++ b/Storage/Network.hs @@ -42,9 +42,9 @@ serverUrl srv = BaseUrl Http (serverName srv) (serverPort srv) "" -- Using tor is highly recommended, to avoid correlation attacks. networkServers :: IO [Server] networkServers = return - [ Server "localhost" 8080 - , Server "localhost" 8080 - , Server "localhost" 8080 + [ Server "localhost" 4242 + , Server "localhost" 4242 + , Server "localhost" 4242 ] networkStorage :: Server -> Storage diff --git a/Types/Storage.hs b/Types/Storage.hs index d8cc181..bc186e7 100644 --- a/Types/Storage.hs +++ b/Types/Storage.hs @@ -17,6 +17,8 @@ import Data.Aeson.Types newtype StorageLocations = StorageLocations [Storage] deriving (Monoid) +newtype LocalStorageDirectory = LocalStorageDirectory FilePath + -- | Storage interface. This can be used both for local storage, -- an upload queue, or a remote server. -- diff --git a/keysafe.hs b/keysafe.hs index 3bb5793..2bb857b 100644 --- a/keysafe.hs +++ b/keysafe.hs @@ -43,8 +43,8 @@ main = do return (mkt testModeTunables, [mkt testModeTunables]) else return (mkt defaultTunables, map (mkt . snd) knownTunings) storagelocations <- if CmdLine.localstorage cmdline - then return localStorageLocations - else allStorageLocations + then pure $ localStorageLocations (CmdLine.localstoragedirectory cmdline) + else allStorageLocations (CmdLine.localstoragedirectory cmdline) dispatch cmdline ui storagelocations tunables possibletunables dispatch :: CmdLine.CmdLine -> UI -> StorageLocations -> Tunables -> [Tunables] -> IO () @@ -63,9 +63,10 @@ dispatch cmdline ui storagelocations tunables possibletunables = do go CmdLine.Restore Nothing = restore storagelocations ui possibletunables Gpg.anyKey go CmdLine.UploadQueued _ = - uploadQueued + uploadQueued (CmdLine.localstoragedirectory cmdline) go (CmdLine.Server) _ = runServer + (CmdLine.localstoragedirectory cmdline) (CmdLine.serverAddress $ CmdLine.serverConfig cmdline) (CmdLine.serverPort $ CmdLine.serverConfig cmdline) go CmdLine.Benchmark _ = -- cgit v1.2.3