Skip to content
This repository was archived by the owner on Feb 6, 2024. It is now read-only.

Commit 7c84a9a

Browse files
committed
Run auth checks on some APIs
Verify the identity of the user on * PUT users * DELETE users * GET decks * GET decks/<deck-id> * POST decks * PUT decks/<deck-id>
1 parent 13b6fcf commit 7c84a9a

File tree

2 files changed

+111
-19
lines changed

2 files changed

+111
-19
lines changed

infra/handler/app/Test.hs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,25 @@ main = do
2020
manager' <- newManager defaultManagerSettings
2121

2222
let clientEnv = mkClientEnv manager' (BaseUrl Http "localhost" 8080 "")
23+
let someFirebaseId = FirebaseId "the-uid" -- from ./token
24+
let someUserId = UserId someFirebaseId
25+
let someDeck = Deck
26+
{ deckSlides = []
27+
, deckDeckname = Deckname "foo"
28+
, deckOwnerId = someUserId
29+
, deckAttributes = HMS.empty
30+
}
2331

2432
runClientM usersGet' clientEnv >>= \case
2533
Left err -> error $ "Expected users, got error: " <> show err
2634
Right [] -> pure ()
2735
Right decks -> error $ "Expected 0 users, got: " <> show decks
2836

29-
runClientM (decksGet' b Nothing) clientEnv >>= \case
37+
runClientM (decksGet' b (Just someUserId)) clientEnv >>= \case
3038
Left err -> error $ "Expected decks, got error: " <> show err
3139
Right [] -> pure ()
3240
Right decks -> error $ "Expected 0 decks, got: " <> show decks
3341

34-
let someFirebaseId = FirebaseId "the-uid" -- from ./token
35-
let someUserId = UserId someFirebaseId
36-
37-
let someDeck = Deck { deckSlides = [] , deckDeckname = Deckname "foo", deckOwnerId = someUserId, deckAttributes = HMS.empty }
38-
3942
deckId <- runClientM (decksPost' b someDeck) clientEnv >>= \case
4043
Left err -> error $ "Expected new deck, got error: " <> show err
4144
Right (Item deckId _) -> pure deckId
@@ -52,7 +55,7 @@ main = do
5255
Left err -> error $ "Expected updated deck, got error: " <> show err
5356
Right {} -> pure ()
5457

55-
runClientM (decksGet' b Nothing) clientEnv >>= \case
58+
runClientM (decksGet' b (Just someUserId)) clientEnv >>= \case
5659
Left err -> error $ "Expected decks, got error: " <> show err
5760
Right decks ->
5861
if decks == [Item deckId newDeck] then pure () else (error $ "Expected updated decks, got: " <> show decks)
@@ -96,7 +99,7 @@ main = do
9699
Left err -> error $ "Expected deck delete, got error: " <> show err
97100
Right {} -> pure ()
98101

99-
runClientM (decksGet' b Nothing) clientEnv >>= \case
102+
runClientM (decksGet' b (Just someUserId)) clientEnv >>= \case
100103
Left err -> error $ "Expected no decks, got error: " <> show err
101104
Right decks ->
102105
if decks == [] then pure () else (error $ "Expected no decks, got: " <> show decks)

infra/handler/src/DeckGo/Handler.hs

Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,17 @@ usersPost env fuid user = do
382382
pure $ Item userId user
383383

384384
usersPut :: Aws.Env -> Firebase.UserId -> UserId -> User -> Servant.Handler (Item UserId User)
385-
usersPut env _ userId user = do
385+
usersPut env fuid userId user = do
386+
387+
when (Firebase.unUserId fuid /= unFirebaseId (unUserId userId)) $ do
388+
liftIO $ putStrLn $ unwords
389+
[ "User is trying to update another user:", show (fuid, userId, user) ]
390+
Servant.throwError Servant.err404
391+
392+
when (Firebase.unUserId fuid /= unFirebaseId (userFirebaseId user)) $ do
393+
liftIO $ putStrLn $ unwords
394+
[ "Client used the wrong user ID on user", show (fuid, userId, user) ]
395+
Servant.throwError Servant.err400
386396

387397
res <- runAWS env $ Aws.send $ DynamoDB.updateItem "Users" &
388398
DynamoDB.uiUpdateExpression .~
@@ -401,7 +411,10 @@ usersPut env _ userId user = do
401411
pure $ Item userId user
402412

403413
usersDelete :: Aws.Env -> Firebase.UserId -> UserId -> Servant.Handler ()
404-
usersDelete env _ userId = do
414+
usersDelete env fuid userId = do
415+
416+
when (Firebase.unUserId fuid /= unFirebaseId (unUserId userId)) $ do
417+
Servant.throwError Servant.err403
405418

406419
res <- runAWS env $ Aws.send $ DynamoDB.deleteItem "Users" &
407420
DynamoDB.diKey .~ HMS.singleton "UserFirebaseId"
@@ -416,15 +429,24 @@ usersDelete env _ userId = do
416429
-- DECKS
417430

418431
decksGet :: Aws.Env -> Firebase.UserId -> Maybe UserId -> Servant.Handler [Item DeckId Deck]
419-
decksGet env _uid mUserId = do
432+
decksGet env fuid mUserId = do
433+
434+
userId <- case mUserId of
435+
Nothing -> do
436+
liftIO $ putStrLn $ unwords
437+
[ "No user specified when GETting decks:", show fuid ]
438+
Servant.throwError Servant.err400
439+
Just userId -> pure userId
440+
441+
when (Firebase.unUserId fuid /= unFirebaseId (unUserId userId)) $ do
442+
liftIO $ putStrLn $ unwords
443+
[ "Client asking for decks as another user", show (fuid, userId) ]
444+
Servant.throwError Servant.err403
420445

421-
let updateReq = case mUserId of
422-
Nothing -> id
423-
Just userId -> \req -> req &
446+
res <- runAWS env $ Aws.send $ DynamoDB.scan "Decks" &
424447
DynamoDB.sFilterExpression .~ Just "DeckOwnerId = :o" &
425448
DynamoDB.sExpressionAttributeValues .~ HMS.singleton ":o" (userIdToAttributeValue userId)
426449

427-
res <- runAWS env $ Aws.send $ updateReq $ DynamoDB.scan "Decks"
428450
case res of
429451
Right scanResponse ->
430452
case sequence $ scanResponse ^. DynamoDB.srsItems <&> itemToDeck of
@@ -437,10 +459,12 @@ decksGet env _uid mUserId = do
437459
Servant.throwError Servant.err500
438460

439461
decksGetDeckId :: Aws.Env -> Firebase.UserId -> DeckId -> Servant.Handler (Item DeckId Deck)
440-
decksGetDeckId env _ deckId = do
462+
decksGetDeckId env fuid deckId = do
463+
441464
res <- runAWS env $ Aws.send $ DynamoDB.getItem "Decks" &
442465
DynamoDB.giKey .~ HMS.singleton "DeckId" (deckIdToAttributeValue deckId)
443-
case res of
466+
467+
deck@Item{itemContent} <- case res of
444468
Right getItemResponse -> do
445469
case getItemResponse ^. DynamoDB.girsResponseStatus of
446470
200 -> pure ()
@@ -462,8 +486,24 @@ decksGetDeckId env _ deckId = do
462486
liftIO $ print e
463487
Servant.throwError Servant.err500
464488

489+
let ownerId = deckOwnerId itemContent
490+
491+
when (Firebase.unUserId fuid /= unFirebaseId (unUserId ownerId)) $ do
492+
liftIO $ putStrLn $ unwords $
493+
[ "Deck was found", show deck, "but requester is not the owner", show fuid ]
494+
Servant.throwError Servant.err404
495+
496+
pure deck
497+
465498
decksPost :: Aws.Env -> Firebase.UserId -> Deck -> Servant.Handler (Item DeckId Deck)
466-
decksPost env _ deck = do
499+
decksPost env fuid deck = do
500+
501+
let ownerId = deckOwnerId deck
502+
503+
when (Firebase.unUserId fuid /= unFirebaseId (unUserId ownerId)) $ do
504+
liftIO $ putStrLn $ unwords $
505+
[ "Deck was POSTed", show deck, "but requester is not the owner", show fuid ]
506+
Servant.throwError Servant.err400
467507

468508
deckId <- liftIO $ DeckId <$> newId
469509

@@ -479,7 +519,18 @@ decksPost env _ deck = do
479519
pure $ Item deckId deck
480520

481521
decksPut :: Aws.Env -> Firebase.UserId -> DeckId -> Deck -> Servant.Handler (Item DeckId Deck)
482-
decksPut env _ deckId deck = do
522+
decksPut env fuid deckId deck = do
523+
524+
getDeck env deckId >>= \case
525+
Nothing -> do
526+
liftIO $ putStrLn $ unwords
527+
[ "Trying to PUT", show deckId, "but deck doesn't exist." ]
528+
Servant.throwError Servant.err404
529+
Just Deck{deckOwnerId} -> do
530+
when (Firebase.unUserId fuid /= unFirebaseId (unUserId deckOwnerId)) $ do
531+
liftIO $ putStrLn $ unwords $
532+
[ "Deck was PUTed", show deck, "but requester is not the owner", show fuid ]
533+
Servant.throwError Servant.err404
483534

484535
res <- runAWS env $ Aws.send $ DynamoDB.updateItem "Decks" &
485536
DynamoDB.uiUpdateExpression .~ Just "SET DeckSlides = :s, DeckName = :n, DeckOwnerId = :o, DeckAttributes = :a" &
@@ -509,6 +560,44 @@ decksDelete env _ deckId = do
509560
liftIO $ print e
510561
Servant.throwError Servant.err500
511562

563+
-- | Reads a Deck from the database.
564+
--
565+
-- If the deck is not found, returns Nothing
566+
-- If the deck can't be parsed, throws a 500.
567+
-- If the response status is not 200, throws a 500.
568+
getDeck :: Aws.Env -> DeckId -> Servant.Handler (Maybe Deck)
569+
getDeck env deckId = do
570+
571+
res <- runAWS env $ Aws.send $ DynamoDB.getItem "Decks" &
572+
DynamoDB.giKey .~ HMS.singleton "DeckId" (deckIdToAttributeValue deckId)
573+
574+
mItem <- case res of
575+
Right r -> do
576+
case
577+
( r ^. DynamoDB.girsResponseStatus
578+
, itemToDeck (r ^. DynamoDB.girsItem )) of
579+
(200, Just deck) -> pure $ Just deck
580+
(200, Nothing) -> do
581+
liftIO $ putStrLn $ "Could not parse response: " <> show r
582+
Servant.throwError Servant.err500
583+
(404, _) -> pure Nothing
584+
s -> do
585+
liftIO $
586+
putStrLn $ "Unkown response status: " <> show s <>
587+
" in response " <> show r
588+
Servant.throwError Servant.err500
589+
Left e -> do
590+
liftIO $ print e
591+
Servant.throwError Servant.err500
592+
593+
case mItem of
594+
Just Item{itemId = deckId', itemContent = deck} -> do
595+
when (deckId' /= deckId) $ do
596+
liftIO $ putStrLn $ "Mismatched deck IDs " <> show (deckId, deckId')
597+
Servant.throwError Servant.err500
598+
pure $ Just deck
599+
Nothing -> pure Nothing
600+
512601
-- SLIDES
513602

514603
slidesGet :: Aws.Env -> Firebase.UserId -> Servant.Handler [Item SlideId Slide]

0 commit comments

Comments
 (0)