Skip to content

Commit

Permalink
[stash]
Browse files Browse the repository at this point in the history
  • Loading branch information
fisx committed Jun 17, 2024
1 parent 24587f3 commit 1e1db5c
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 19 deletions.
20 changes: 12 additions & 8 deletions libs/wire-subsystems/src/Wire/MiniBackend.hs
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,15 @@ data MiniBackend = MkMiniBackend
-- invariant: for each key, the user.id and the key are the same
users :: [StoredUser],
userPassword :: Map UserId Password,
userKeys :: Map UserKey UserId,
passwordResetCodes :: Map PasswordResetKey (PasswordResetCode, UserId)
}

instance Default MiniBackend where
def =
MkMiniBackend
{ users = mempty,
userKeys = mempty,
passwordResetCodes = mempty,
userPassword = mempty
userPassword = mempty,
passwordResetCodes = mempty
}

-- | represents an entire federated, stateful world of backends
Expand Down Expand Up @@ -426,7 +424,7 @@ staticCodeStore ::
InterpreterFor CodeStore r
staticCodeStore = interpret \case
MkPasswordResetKey uid ->
pure . PasswordResetKey . encodeBase64Url $ toByteString' uid
pure . PasswordResetKey . encodeBase64Url $ toByteString' uid -- TODO(fisx): understand how this work on develop first, then write tests, *then* port it!
GenerateEmailCode ->
pure . PasswordResetCode . encodeBase64Url $ "email-code"
GeneratePhoneCode -> (error "deprecated")
Expand Down Expand Up @@ -518,12 +516,18 @@ miniEventInterpreter = interpret \case
GenerateUserEvent uid _mconn e -> modify (MkMiniEvent uid e :)

staticUserKeyStoreInterpreter ::
Member (State MiniBackend) r =>
(HasCallStack, Member (State MiniBackend) r) =>
InterpreterFor UserKeyStore r
staticUserKeyStoreInterpreter = interpret $ \case
LookupKey key -> do
keys <- gets (.userKeys)
pure $ M.lookup key keys
usrs <- gets (.users)
let matchinUsrs = case key of
UserEmailKey eml -> listToMaybe $ filter ((== eml) . (.email)) usrs
UserPhoneKey phn -> listToMaybe $ filter ((== phn) . (.phone)) usrs
pure case matchingUsrs of
[usr] -> usr.id
[] -> Nothing
bad@(_:_:_) -> error (show bad)
InsertKey uid key ->
modify $ \b -> b {userKeys = M.insert key uid (userKeys b)}
DeleteKey key ->
Expand Down
4 changes: 2 additions & 2 deletions libs/wire-subsystems/src/Wire/UserSubsystem.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ data UserSubsystemError
| UserSubsystemHandleExists
| UserSubsystemInvalidHandle
| UserSubsystemProfileNotFound
| UserSubsystemInvalidPasswordResetKey
| UserSubsystemInvalidPasswordResetKey Text
| UserSubsystemPasswordResetInProgress
| UserSubSystemInvalidPasswordResetCode
| UserSubsystemResetPasswordMustDiffer
Expand All @@ -44,7 +44,7 @@ userSubsystemErrorToWai =
UserSubsystemHandleExists -> dynError @(MapError E.HandleExists)
UserSubsystemInvalidHandle -> dynError @(MapError E.InvalidHandle)
UserSubsystemHandleManagedByScim -> dynError @(MapError E.HandleManagedByScim)
UserSubsystemInvalidPasswordResetKey -> dynError @(MapError E.InvalidPasswordResetKey)
UserSubsystemInvalidPasswordResetKey _ -> dynError @(MapError E.InvalidPasswordResetKey)
UserSubsystemPasswordResetInProgress -> dynError @(MapError E.PasswordResetInProgress)
UserSubSystemInvalidPasswordResetCode -> dynError @(MapError E.InvalidPasswordResetCode)
UserSubsystemResetPasswordMustDiffer -> dynError @(MapError E.ResetPasswordMustDiffer)
Expand Down
9 changes: 5 additions & 4 deletions libs/wire-subsystems/src/Wire/UserSubsystem/Interpreter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,11 @@ passwordResetInitImpl ::
Sem r (UserId, PasswordResetPair)
passwordResetInitImpl target = do
let key = either UKS.userEmailKey UKS.userPhoneKey target
user <- UKS.lookupKey key >>= maybe (throw UserSubsystemInvalidPasswordResetKey) pure
user <- UKS.lookupKey key >>= maybe (throw (UserSubsystemInvalidPasswordResetKey "init_lookup")) pure
Log.debug $ field "user" (toByteString user) . field "action" (val "User.beginPasswordReset")
status <- US.lookupStatus user
unless (status == Just Active) $
throw UserSubsystemInvalidPasswordResetKey
throw (UserSubsystemInvalidPasswordResetKey "init_inactive")
code <- PWS.lookupPasswordResetCode user
when (isJust code) $
throw UserSubsystemPasswordResetInProgress
Expand Down Expand Up @@ -536,6 +536,7 @@ checkNewIsDifferent uid pw = do
| (verifyPassword pw currpw) -> throw UserSubsystemResetPasswordMustDiffer
_ -> pure ()

-- TODO: refactor this function? or at least rename it!
mkPasswordResetKey' ::
(Member (Error UserSubsystemError) r, Member UserKeyStore r, Member CodeStore r) =>
PasswordResetIdentity ->
Expand All @@ -545,8 +546,8 @@ mkPasswordResetKey' ident = case ident of
PasswordResetEmailIdentity e -> do
lookupKey (userEmailKey e)
>>= traverse mkPasswordResetKey
>>= maybe (throw UserSubsystemInvalidPasswordResetKey) pure
>>= maybe (throw (UserSubsystemInvalidPasswordResetKey "complete_email")) pure
PasswordResetPhoneIdentity p ->
lookupKey (userPhoneKey p)
>>= traverse mkPasswordResetKey
>>= maybe (throw UserSubsystemInvalidPasswordResetKey) pure
>>= maybe (throw (UserSubsystemInvalidPasswordResetKey "complete_phone")) pure
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Wire.API.Team.Feature
import Wire.API.Team.Member
import Wire.API.Team.Permission
import Wire.API.User hiding (DeleteUser)
import Wire.API.User.Password (PasswordResetIdentity (PasswordResetIdentityKey))
import Wire.API.User.Password (PasswordResetIdentity (..))
import Wire.API.UserEvent
import Wire.MiniBackend
import Wire.StoredUser as SU
Expand Down Expand Up @@ -454,16 +454,21 @@ spec = describe "UserSubsystem.Interpreter" do
else newSupportedProtocols
in actualSupportedProtocols === expectedSupportedProtocols

describe "password reset" do
focus $ describe "password reset" do
it "happy path" do
user :: StoredUser <- generate arbitrary
user :: StoredUser <-
generate arbitrary <&> \u ->
u
{ email = parseEmail "a29c950a-2a51-11ef-bc05-ebc0f6d21339@example.com"
{- TODO(fisx): generate random uuids here for different test runs. -}
}
config :: UserSubsystemConfig <- generate arbitrary
let localBackend = def {users = [user]}
password = plainTextPassword8Unsafe "newsecret"
(actualState, ()) =
runNoFederationStackState localBackend Nothing config do
(_, (key, code)) <- passwordResetInit (Left $ fromMaybe (error "no email") user.email)
passwordResetComplete (PasswordResetIdentityKey key) code password
(_, (_, code)) <- passwordResetInit (Left $ fromMaybe (error "no email") user.email)
passwordResetComplete (PasswordResetEmailIdentity (fromJust user.email)) code password
Just actualPassword = Map.lookup user.id actualState.userPassword
verifyPassword password actualPassword `shouldBe` True

Expand Down

0 comments on commit 1e1db5c

Please sign in to comment.