Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libs/galley-types/src/Galley/Types/Teams.hs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ data HiddenPerm
-- efficient this end-point is. better not let all team members
-- play with it unless we have to.
DownloadTeamMembersCsv
| ChangeTeamMemberProfiles
deriving (Eq, Ord, Show)

-- | See Note [hidden team roles]
Expand Down Expand Up @@ -367,6 +368,7 @@ roleHiddenPermissions role = HiddenPermissions p p
ChangeTeamFeature TeamFeatureFileSharing,
ChangeTeamFeature TeamFeatureClassifiedDomains {- the features not listed here can only be changed in stern -},
ChangeTeamFeature TeamFeatureSelfDeletingMessages,
ChangeTeamMemberProfiles,
ReadIdp,
CreateUpdateDeleteIdp,
CreateReadDeleteScimToken,
Expand Down
9 changes: 9 additions & 0 deletions libs/wire-api/src/Wire/API/Routes/Public/Brig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ data Api routes = Api
:> "self"
:> ReqBody '[JSON] DeleteUser
:> MultiVerb 'DELETE '[JSON] DeleteSelfResponses (Maybe Timeout),
updateUserEmailValidation ::
routes
:- Summary "Resend email address validation email."
:> Description "If the user has a pending email validation, the validation email will be resent."
:> ZUser
:> "users"
:> CaptureUserId "uid"
Comment thread
fisx marked this conversation as resolved.
:> "email"
:> Put '[JSON] (),
getHandleInfoUnqualified ::
routes
:- Summary "(deprecated, use /search/contacts) Get information on a user handle"
Expand Down
3 changes: 3 additions & 0 deletions services/brig/src/Brig/API/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ newPasswordMustDiffer = Wai.mkError status409 "password-must-differ" "For provid
notFound :: LText -> Wai.Error
notFound = Wai.mkError status404 "not-found"

conflict :: LText -> Wai.Error
conflict = Wai.mkError status409 "conflict"

Comment thread
battermann marked this conversation as resolved.
Outdated
invalidAccountStatus :: Wai.Error
invalidAccountStatus = Wai.mkError status400 "invalid-status" "The specified account status cannot be set."

Expand Down
28 changes: 28 additions & 0 deletions services/brig/src/Brig/API/Public.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import Brig.App
import qualified Brig.Calling.API as Calling
import qualified Brig.Data.Connection as Data
import qualified Brig.Data.User as Data
import qualified Brig.IO.Intra as Intra
import Brig.Options hiding (internalEvents, sesQueue)
import qualified Brig.Provider.API as Provider
import qualified Brig.Team.API as Team
Expand Down Expand Up @@ -80,6 +81,7 @@ import qualified Data.Text.Ascii as Ascii
import Data.Text.Encoding (decodeLatin1)
import Data.Text.Lazy (pack)
import qualified Data.ZAuth.Token as ZAuth
import Galley.Types.Teams (HiddenPerm (..), hasPermission)
import Imports hiding (head)
import Network.HTTP.Types.Status
import Network.Wai (Response, lazyRequestBody)
Expand Down Expand Up @@ -251,6 +253,7 @@ servantSitemap =
BrigAPI.getUserQualified = getUser,
BrigAPI.getSelf = getSelf,
BrigAPI.deleteSelf = deleteUser,
BrigAPI.updateUserEmailValidation = updateUserEmailValidation,
BrigAPI.getHandleInfoUnqualified = getHandleInfoUnqualifiedH,
BrigAPI.getUserByHandleQualified = Handle.getHandleInfo,
BrigAPI.listUsersByUnqualifiedIdsOrHandles = listUsersByUnqualifiedIdsOrHandles,
Expand Down Expand Up @@ -1193,6 +1196,31 @@ verifyDeleteUserH (r ::: _) = do
API.verifyDeleteUser body !>> deleteUserError
return (setStatus status200 empty)

updateUserEmailValidation :: UserId -> UserId -> Handler ()
updateUserEmailValidation zuserId emailOwnerId = do
maybeZuserTeamId <- lift $ Data.lookupUserTeam zuserId
Comment thread
battermann marked this conversation as resolved.
whenM (isNothing <$> runMaybeT (checkPerm maybeZuserTeamId)) $
throwStd insufficientTeamPermissions
maybeEmailOwnerTeamId <- lift $ Data.lookupUserTeam emailOwnerId
checkSameTeam maybeZuserTeamId maybeEmailOwnerTeamId
maybeEmail <- lift $ Data.lookupUserUnverifiedEmail emailOwnerId
case maybeEmail of
Just email -> void $ API.changeSelfEmail emailOwnerId email API.AllowSCIMUpdates
Nothing -> throwStd $ conflict "the user doesn't have a pending email validation"
where
checkSameTeam :: Maybe TeamId -> Maybe TeamId -> Handler ()
checkSameTeam (Just zuserTeamId) maybeEmailOwnerTeamId =
when (Just zuserTeamId /= maybeEmailOwnerTeamId) $ throwStd insufficientTeamPermissions
checkSameTeam Nothing _ = throwStd insufficientTeamPermissions

checkPerm :: Maybe TeamId -> MaybeT Handler ()
checkPerm maybeTeamId = do
teamId <- hoistMaybe maybeTeamId
teamMember <- MaybeT $ lift $ Intra.getTeamMember zuserId teamId
if teamMember `hasPermission` ChangeTeamMemberProfiles
then pure ()
else throwStd insufficientTeamPermissions

-- activation

data ActivationRespWithStatus
Expand Down
5 changes: 2 additions & 3 deletions services/brig/src/Brig/API/User.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1232,9 +1232,8 @@ getEmailForProfile profileOwner EmailVisibleIfOnTeam' =
then userEmail profileOwner
else Nothing
getEmailForProfile profileOwner (EmailVisibleIfOnSameTeam' (Just (viewerTeamId, viewerTeamMember))) =
if ( Just viewerTeamId == userTeam profileOwner
&& Team.hasPermission viewerTeamMember Team.ViewSameTeamEmails
)
if Just viewerTeamId == userTeam profileOwner
&& Team.hasPermission viewerTeamMember Team.ViewSameTeamEmails
then userEmail profileOwner
else Nothing
getEmailForProfile _ (EmailVisibleIfOnSameTeam' Nothing) = Nothing
Expand Down
13 changes: 12 additions & 1 deletion services/brig/src/Brig/Data/User.hs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module Brig.Data.User
lookupServiceUsers,
lookupServiceUsersForTeam,
lookupFeatureConferenceCalling,
lookupUserUnverifiedEmail,

-- * Updates
updateUser,
Expand Down Expand Up @@ -89,6 +90,7 @@ import Data.Misc (PlainTextPassword (..))
import Data.Qualified
import Data.Range (fromRange)
import Data.Time (addUTCTime)
import Data.UUID (UUID)
import Data.UUID.V4
import Galley.Types.Bot
import Imports
Expand Down Expand Up @@ -404,9 +406,18 @@ lookupRichInfoMultiUsers users = do
-- successful login.
lookupUserTeam :: UserId -> AppIO (Maybe TeamId)
lookupUserTeam u =
join . fmap runIdentity
(runIdentity =<<)
<$> retry x1 (query1 teamSelect (params LocalQuorum (Identity u)))

lookupUserUnverifiedEmail :: MonadClient m => UserId -> m (Maybe Email)
lookupUserUnverifiedEmail userId =
(runIdentity =<<) <$> retry x1 (query1 cql (params LocalQuorum (Identity $ toUUID userId)))
where
cql :: PrepQuery R (Identity UUID) (Identity (Maybe Email))
Comment thread
battermann marked this conversation as resolved.
Outdated
cql =
"SELECT email \
\FROM vcodes WHERE account = ?"
Comment thread
battermann marked this conversation as resolved.
Outdated

lookupAuth :: (MonadClient m) => UserId -> m (Maybe (Maybe Password, AccountStatus))
lookupAuth u = fmap f <$> retry x1 (query1 authSelect (params LocalQuorum (Identity u)))
where
Expand Down