Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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: 1 addition & 1 deletion deploy/services-demo/conf/nginz/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ http {
proxy_pass http://brig;
}

location /register {
location ~* (/v[0-9]+)?/register {
include common_response_no_zauth.conf;
proxy_pass http://brig;
}
Expand Down
23 changes: 19 additions & 4 deletions libs/wire-api/src/Wire/API/Routes/Version.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ where
import Control.Lens ((?~))
import Data.Aeson (FromJSON, ToJSON (..))
import qualified Data.Aeson as Aeson
import Data.Attoparsec.ByteString.Char8
import Data.ByteString.Builder
import Data.ByteString.Conversion
import Data.Domain
import Data.Schema
import qualified Data.Swagger as S
Expand All @@ -47,12 +50,24 @@ data Version = V0 | V1
deriving stock (Eq, Ord, Bounded, Enum, Show)
deriving (FromJSON, ToJSON) via (Schema Version)

versionNumber :: Version -> Integer
versionNumber V0 = 0
versionNumber V1 = 1

instance ToSchema Version where
schema =
enum @Integer "Version" . mconcat $
[ element 0 V0,
element 1 V1
]
enum @Integer "Version" $
foldMap
(\v -> element (versionNumber v) v)
[minBound .. maxBound]

instance FromByteString Version where
parser =
maybe (fail "Unsupported version") pure
=<< fmap mkVersion decimal

instance ToByteString Version where
builder = integerDec . versionNumber

readVersionNumber :: Text -> Maybe Integer
readVersionNumber v = do
Expand Down
11 changes: 10 additions & 1 deletion libs/wire-api/src/Wire/API/Routes/Version/Wai.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

module Wire.API.Routes.Version.Wai where

import Data.ByteString.Conversion
import qualified Data.Text.Lazy as LText
import Imports
import qualified Network.HTTP.Types as HTTP
Expand Down Expand Up @@ -44,4 +45,12 @@ parseVersion req = do
[] -> Nothing
(x : xs) -> pure (x, xs)
n <- readVersionNumber version
pure (rewriteRequestPure (\(_, q) _ -> (pinfo, q)) req, n)
let req' =
rewriteRequestPure
(\(_, q) _ -> (pinfo, q))
req
{ requestHeaders =
requestHeaders req
<> [("Wire-API-Version", toByteString' n)]
}
pure (req', n)
9 changes: 5 additions & 4 deletions services/brig/src/Brig/API/Public.hs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ sitemap = do
-- - UserActivated event to created user, if it is a team invitation or user has an SSO ID
-- - UserIdentityUpdated event to created user, if email code or phone code is provided
post "/register" (continue createUserH) $
accept "application" "json"
opt (header "Wire-API-Version")
.&. accept "application" "json"
.&. jsonRequest @Public.NewUserPublic
document "POST" "register" $ do
Doc.summary "Register a new user."
Expand Down Expand Up @@ -669,10 +670,10 @@ getClientPrekeys :: UserId -> ClientId -> (Handler r) [Public.PrekeyId]
getClientPrekeys usr clt = lift (API.lookupPrekeyIds usr clt)

-- docs/reference/user/registration.md {#RefRegistration}
createUserH :: JSON ::: JsonRequest Public.NewUserPublic -> (Handler r) Response
createUserH (_ ::: req) = do
createUserH :: Maybe Version ::: JSON ::: JsonRequest Public.NewUserPublic -> (Handler r) Response
createUserH (v ::: _ ::: req) = do
CreateUserResponse cok loc prof <- createUser =<< parseJsonBody req
lift . Auth.setResponseCookie cok
lift . Auth.setResponseCookie v cok
. setStatus status201
. addHeader "Location" (toByteString' loc)
$ json prof
Expand Down
39 changes: 24 additions & 15 deletions services/brig/src/Brig/User/API/Auth.hs
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,16 @@ import qualified Network.Wai.Utilities.Response as WaiResp
import Network.Wai.Utilities.Swagger (document)
import qualified Network.Wai.Utilities.Swagger as Doc
import Wire.API.ErrorDescription
import Wire.API.Routes.Version
import qualified Wire.API.User as Public
import Wire.API.User.Auth as Public
import Wire.Swagger as Doc (pendingLoginError)

routesPublic :: Routes Doc.ApiBuilder (Handler r) ()
routesPublic = do
post "/access" (continue renewH) $
accept "application" "json"
opt (header "Wire-API-Version")
.&. accept "application" "json"
.&. tokenRequest
document "POST" "newAccessToken" $ do
Doc.summary "Obtain an access tokens for a cookie."
Expand Down Expand Up @@ -101,7 +103,8 @@ routesPublic = do
Doc.errorResponse' loginCodePending Doc.pendingLoginError

post "/login" (continue loginH) $
jsonRequest @Public.Login
opt (header "Wire-API-Version")
.&. jsonRequest @Public.Login
.&. def False (query "persist")
.&. accept "application" "json"
document "POST" "login" $ do
Expand Down Expand Up @@ -190,7 +193,8 @@ routesInternal = do
.&. accept "application" "json"

post "/i/sso-login" (continue ssoLoginH) $
jsonRequest @SsoLogin
opt (header "Wire-API-Version")
.&. jsonRequest @SsoLogin
.&. def False (query "persist")
.&. accept "application" "json"

Expand Down Expand Up @@ -231,18 +235,18 @@ reAuthUser :: UserId -> ReAuthUser -> (Handler r) ()
reAuthUser uid body = do
User.reauthenticate uid (reAuthPassword body) !>> reauthError

loginH :: JsonRequest Public.Login ::: Bool ::: JSON -> (Handler r) Response
loginH (req ::: persist ::: _) = do
lift . tokenResponse =<< flip login persist =<< parseJsonBody req
loginH :: Maybe Version ::: JsonRequest Public.Login ::: Bool ::: JSON -> (Handler r) Response
loginH (v ::: req ::: persist ::: _) = do
lift . tokenResponse v =<< flip login persist =<< parseJsonBody req

login :: Public.Login -> Bool -> (Handler r) (Auth.Access ZAuth.User)
login l persist = do
let typ = if persist then PersistentCookie else SessionCookie
Auth.login l typ !>> loginError

ssoLoginH :: JsonRequest SsoLogin ::: Bool ::: JSON -> (Handler r) Response
ssoLoginH (req ::: persist ::: _) = do
lift . tokenResponse =<< flip ssoLogin persist =<< parseJsonBody req
ssoLoginH :: Maybe Version ::: JsonRequest SsoLogin ::: Bool ::: JSON -> (Handler r) Response
ssoLoginH (v ::: req ::: persist ::: _) = do
lift . tokenResponse v =<< flip ssoLogin persist =<< parseJsonBody req

ssoLogin :: SsoLogin -> Bool -> (Handler r) (Auth.Access ZAuth.User)
ssoLogin l persist = do
Expand All @@ -251,7 +255,7 @@ ssoLogin l persist = do

legalHoldLoginH :: JsonRequest LegalHoldLogin ::: JSON -> (Handler r) Response
legalHoldLoginH (req ::: _) = do
lift . tokenResponse =<< legalHoldLogin =<< parseJsonBody req
lift . tokenResponse Nothing =<< legalHoldLogin =<< parseJsonBody req

legalHoldLogin :: LegalHoldLogin -> (Handler r) (Auth.Access ZAuth.LegalHoldUser)
legalHoldLogin l = do
Expand Down Expand Up @@ -320,8 +324,13 @@ rmCookies :: UserId -> Public.RemoveCookies -> (Handler r) ()
rmCookies uid (Public.RemoveCookies pw lls ids) = do
Auth.revokeAccess uid pw ids lls !>> authError

renewH :: JSON ::: Maybe (Either (List1 ZAuth.UserToken) (List1 ZAuth.LegalHoldUserToken)) ::: Maybe (Either ZAuth.AccessToken ZAuth.LegalHoldAccessToken) -> (Handler r) Response
renewH (_ ::: ut ::: at) = lift . either tokenResponse tokenResponse =<< renew ut at
renewH ::
Maybe Version
::: JSON
::: Maybe (Either (List1 ZAuth.UserToken) (List1 ZAuth.LegalHoldUserToken))
::: Maybe (Either ZAuth.AccessToken ZAuth.LegalHoldAccessToken) ->
(Handler r) Response
renewH (v ::: _ ::: ut ::: at) = lift . either (tokenResponse v) (tokenResponse v) =<< renew ut at

-- | renew access for either:
-- * a user with user token and optional access token, or
Expand Down Expand Up @@ -406,9 +415,9 @@ tokenRequest = opt (userToken ||| legalHoldUserToken) .&. opt (accessToken ||| l
)
Just t -> return t

tokenResponse :: ZAuth.UserTokenLike u => Auth.Access u -> (AppIO r) Response
tokenResponse (Auth.Access t Nothing) = pure $ json t
tokenResponse (Auth.Access t (Just c)) = Auth.setResponseCookie c (json t)
tokenResponse :: ZAuth.UserTokenLike u => Maybe Version -> Auth.Access u -> (AppIO r) Response
tokenResponse _ (Auth.Access t Nothing) = pure $ json t
tokenResponse v (Auth.Access t (Just c)) = Auth.setResponseCookie v c (json t)

-- | Internal utilities: These functions are nearly copies verbatim from the original
-- project: https://gitlab.com/twittner/wai-predicates/-/blob/develop/src/Network/Wai/Predicate.hs#L106-112
Expand Down
8 changes: 6 additions & 2 deletions services/brig/src/Brig/User/Auth/Cookie.hs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import Network.Wai.Utilities.Response (addHeader)
import System.Logger.Class (field, msg, val, (~~))
import qualified System.Logger.Class as Log
import qualified Web.Cookie as WebCookie
import Wire.API.Routes.Version

--------------------------------------------------------------------------------
-- Basic Cookie Management
Expand Down Expand Up @@ -222,19 +223,22 @@ newCookieLimited u typ label = do

setResponseCookie ::
(Monad m, MonadReader Env m, ZAuth.UserTokenLike u) =>
Maybe Version ->
Cookie (ZAuth.Token u) ->
Response ->
m Response
setResponseCookie c r = do
setResponseCookie mv c r = do
s <- view settings
let hdr = toByteString' (WebCookie.renderSetCookie (cookie s))
return (addHeader "Set-Cookie" hdr r)
where
versionPrefix :: ByteString
versionPrefix = foldMap (("/v" <>) . toByteString') mv
cookie s =
WebCookie.def
{ WebCookie.setCookieName = "zuid",
WebCookie.setCookieValue = toByteString' (cookieValue c),
WebCookie.setCookiePath = Just "/access",
WebCookie.setCookiePath = Just (versionPrefix <> "/access"),
WebCookie.setCookieExpires =
if cookieType c == PersistentCookie
then Just (cookieExpires c)
Expand Down