diff options
author | Joey Hess <joeyh@joeyh.name> | 2016-09-12 22:35:47 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2016-09-12 22:39:21 -0400 |
commit | 13c408d2295597540f0b2dfb6f7b86e739876c90 (patch) | |
tree | cac72a6d5a75fb15d71d5e86395543829fe2f2df /HTTP/Server.hs | |
parent | 483cc9e1fe40899c7f045d71d75aaa5ca99db3fb (diff) | |
download | keysafe-13c408d2295597540f0b2dfb6f7b86e739876c90.tar.gz |
implement client-server Proof Of Work
Mashed up a argon2-based PoW with token buckets and bloom filters.
This is intended to prevent a few abuses including:
* Using a keysafe server for general file storage, by storing a whole
lot of chunks.
* An attacker guessing names that people will use, and uploading junk
to keysafe servers under those names, to make it harder for others to use
keysafe later.
* An attacker trying to guess the names used for objects on keysafe
servers in order to download them and start password cracking.
(As a second level of defense, since the name generation hash
is expensive already.)
Completely untested, but it builds!
This commit was sponsored by Andreas on Patreon.
Diffstat (limited to 'HTTP/Server.hs')
-rw-r--r-- | HTTP/Server.hs | 21 |
1 files changed, 12 insertions, 9 deletions
diff --git a/HTTP/Server.hs b/HTTP/Server.hs index ab27aaa..dd35d1c 100644 --- a/HTTP/Server.hs +++ b/HTTP/Server.hs @@ -9,6 +9,7 @@ module HTTP.Server (runServer) where import HTTP import HTTP.ProofOfWork +import HTTP.RateLimit import Types import Types.Storage import Tunables @@ -26,12 +27,14 @@ import qualified Data.ByteString as B data ServerState = ServerState { obscurerRequest :: TMVar () , storageDirectory :: Maybe LocalStorageDirectory + , rateLimiter :: RateLimiter } newServerState :: Maybe LocalStorageDirectory -> IO ServerState newServerState d = ServerState <$> newEmptyTMVarIO <*> pure d + <*> newRateLimiter runServer :: Maybe LocalStorageDirectory -> String -> Port -> IO () runServer d bindaddress port = do @@ -60,30 +63,30 @@ server st = motd motd :: Handler Motd motd = return $ Motd "Hello World!" -getObject :: ServerState -> StorableObjectIdent -> Maybe ProofOfWork -> Handler (ProofOfWorkRequirement StorableObject) -getObject st i _pow = do +getObject :: ServerState -> StorableObjectIdent -> Maybe ProofOfWork -> Handler (POWGuarded StorableObject) +getObject st i pow = rateLimit (rateLimiter st) pow i $ do r <- liftIO $ retrieveShare (serverStorage st) dummyShareNum i liftIO $ requestObscure st case r of - RetrieveSuccess (Share _n o) -> return $ Result o + RetrieveSuccess (Share _n o) -> return o RetrieveFailure _ -> throwError err404 -putObject :: ServerState -> StorableObjectIdent -> Maybe ProofOfWork -> StorableObject -> Handler (ProofOfWorkRequirement StoreResult) -putObject st i _pow o = do +putObject :: ServerState -> StorableObjectIdent -> Maybe ProofOfWork -> StorableObject -> Handler (POWGuarded StoreResult) +putObject st i pow o = rateLimit (rateLimiter st) pow i $ do if validObjectsize o then do r <- liftIO $ storeShare (serverStorage st) i (Share dummyShareNum o) liftIO $ requestObscure st - return $ Result r - else return $ Result $ StoreFailure "invalid object size" + return r + else return $ StoreFailure "invalid object size" validObjectsize :: StorableObject -> Bool validObjectsize o = any (sz ==) knownObjectSizes where sz = B.length (fromStorableObject o) -countObjects :: ServerState -> Maybe ProofOfWork -> Handler (ProofOfWorkRequirement CountResult) -countObjects st _pow = liftIO $ Result <$> countShares (serverStorage st) +countObjects :: ServerState -> Handler CountResult +countObjects = liftIO . countShares . serverStorage -- | 1 is a dummy value; the server does not know the actual share numbers. dummyShareNum :: ShareNum |