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
1 change: 1 addition & 0 deletions cassandra-schema.cql
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ CREATE TABLE galley_test.conversation_codes (
key ascii,
scope int,
conversation uuid,
password blob,
value ascii,
PRIMARY KEY (key, scope)
) WITH CLUSTERING ORDER BY (scope ASC)
Expand Down
1 change: 1 addition & 0 deletions changelog.d/2-features/pr-3149
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Optional password for guest links
4 changes: 4 additions & 0 deletions libs/wire-api/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
, hex
, hostname-validate
, hscim
, HsOpenSSL
, hspec
, hspec-wai
, http-api-data
Expand Down Expand Up @@ -73,6 +74,7 @@
, saml2-web-sso
, schema-profunctor
, scientific
, scrypt
, servant
, servant-client
, servant-client-core
Expand Down Expand Up @@ -150,6 +152,7 @@ mkDerivation {
hashable
hostname-validate
hscim
HsOpenSSL
http-api-data
http-media
http-types
Expand All @@ -175,6 +178,7 @@ mkDerivation {
saml2-web-sso
schema-profunctor
scientific
scrypt
servant
servant-client
servant-client-core
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Brig.Budget
module Wire.API.Budget
( Budget (..),
BudgetKey (..),
Budgeted (..),
Expand Down
4 changes: 3 additions & 1 deletion libs/wire-api/src/Wire/API/Conversation.hs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ conversationSchema v =
-- link about the conversation.
data ConversationCoverView = ConversationCoverView
{ cnvCoverConvId :: ConvId,
cnvCoverName :: Maybe Text
cnvCoverName :: Maybe Text,
cnvCoverHasPassword :: Bool
}
deriving stock (Eq, Show, Generic)
deriving (Arbitrary) via (GenericUniform ConversationCoverView)
Expand All @@ -299,6 +300,7 @@ instance ToSchema ConversationCoverView where
$ ConversationCoverView
<$> cnvCoverConvId .= field "id" schema
<*> cnvCoverName .= optField "name" (maybeWithDefault A.Null schema)
<*> cnvCoverHasPassword .= field "has_password" schema

data ConversationList a = ConversationList
{ convList :: [a],
Expand Down
46 changes: 41 additions & 5 deletions libs/wire-api/src/Wire/API/Conversation/Code.hs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ module Wire.API.Conversation.Code
( -- * ConversationCode
ConversationCode (..),
mkConversationCode,
CreateConversationCodeRequest (..),
JoinConversationByCode (..),

-- * re-exports
Code.Key (..),
Expand All @@ -34,17 +36,49 @@ import Data.Aeson (FromJSON, ToJSON)
import Data.ByteString.Conversion (toByteString')
-- FUTUREWORK: move content of Data.Code here?
import Data.Code as Code
import Data.Misc (HttpsUrl (HttpsUrl))
import Data.Misc
import Data.Schema
import qualified Data.Swagger as S
import Imports
import qualified URI.ByteString as URI
import Wire.Arbitrary (Arbitrary, GenericUniform (..))

newtype CreateConversationCodeRequest = CreateConversationCodeRequest
{ cccrPassword :: Maybe PlainTextPassword8
}
deriving stock (Eq, Show, Generic)
deriving (Arbitrary) via (GenericUniform CreateConversationCodeRequest)
deriving (FromJSON, ToJSON, S.ToSchema) via Schema CreateConversationCodeRequest

instance ToSchema CreateConversationCodeRequest where
schema =
objectWithDocModifier
"CreateConversationCodeRequest"
(description ?~ "Optional request body for creating a conversation code with a password")
$ CreateConversationCodeRequest <$> cccrPassword .= maybe_ (optField "password" schema)

data JoinConversationByCode = JoinConversationByCode
{ jcbcCode :: ConversationCode,
jcbcPassword :: Maybe PlainTextPassword8
}
deriving stock (Eq, Show, Generic)
deriving (Arbitrary) via (GenericUniform JoinConversationByCode)
deriving (FromJSON, ToJSON, S.ToSchema) via Schema JoinConversationByCode

instance ToSchema JoinConversationByCode where
schema =
objectWithDocModifier
"JoinConversationByCode"
(description ?~ "Request body for joining a conversation by code")
$ JoinConversationByCode
<$> jcbcCode .= fieldWithDocModifier "code" (description ?~ "Conversation code") schema
<*> jcbcPassword .= maybe_ (optField "password" schema)

data ConversationCode = ConversationCode
{ conversationKey :: Code.Key,
conversationCode :: Code.Value,
conversationUri :: Maybe HttpsUrl
conversationUri :: Maybe HttpsUrl,
conversationHasPassword :: Maybe Bool
}
deriving stock (Eq, Show, Generic)
deriving (Arbitrary) via (GenericUniform ConversationCode)
Expand Down Expand Up @@ -73,13 +107,15 @@ instance ToSchema ConversationCode where
(description ?~ "Full URI (containing key/code) to join a conversation")
schema
)
<*> conversationHasPassword .= maybe_ (optField "has_password" schema)

mkConversationCode :: Code.Key -> Code.Value -> HttpsUrl -> ConversationCode
mkConversationCode k v (HttpsUrl prefix) =
mkConversationCode :: Code.Key -> Code.Value -> Bool -> HttpsUrl -> ConversationCode
mkConversationCode k v hasPw (HttpsUrl prefix) =
ConversationCode
{ conversationKey = k,
conversationCode = v,
conversationUri = Just (HttpsUrl link)
conversationUri = Just (HttpsUrl link),
conversationHasPassword = Just hasPw
}
where
q = [("key", toByteString' k), ("code", toByteString' v)]
Expand Down
3 changes: 3 additions & 0 deletions libs/wire-api/src/Wire/API/Error/Galley.hs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ data GalleyError
| ConvMemberNotFound
| GuestLinksDisabled
| CodeNotFound
| InvalidConversationPassword
| InvalidPermissions
| InvalidTeamStatusUpdate
| AccessDenied
Expand Down Expand Up @@ -235,6 +236,8 @@ type instance MapError 'GuestLinksDisabled = 'StaticError 409 "guest-links-disab

type instance MapError 'CodeNotFound = 'StaticError 404 "no-conversation-code" "Conversation code not found"

type instance MapError 'InvalidConversationPassword = 'StaticError 403 "invalid-conversation-password" "Invalid conversation password"

type instance MapError 'InvalidPermissions = 'StaticError 403 "invalid-permissions" "The specified permissions are invalid"

type instance MapError 'InvalidTeamStatusUpdate = 'StaticError 403 "invalid-team-status-update" "Cannot use this endpoint to update the team to the given status."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
-- You should have received a copy of the GNU Affero General Public License along
-- with this program. If not, see <https://www.gnu.org/licenses/>.

module Brig.Password
module Wire.API.Password
( Password,
genPassword,
mkSafePassword,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Imports hiding (head)
import Servant hiding (WithStatus)
import Servant.Swagger.Internal.Orphans ()
import Wire.API.Conversation
import Wire.API.Conversation.Code
import Wire.API.Conversation.Role
import Wire.API.Conversation.Typing
import Wire.API.Error
Expand Down Expand Up @@ -316,6 +317,7 @@ type ConversationAPI =
"get-conversation-by-reusable-code"
( Summary "Get limited conversation information by key/code pair"
:> CanThrow 'CodeNotFound
:> CanThrow 'InvalidConversationPassword
:> CanThrow 'ConvNotFound
:> CanThrow 'ConvAccessDenied
:> CanThrow 'GuestLinksDisabled
Expand Down Expand Up @@ -548,14 +550,16 @@ type ConversationAPI =
-- This endpoint can lead to the following events being sent:
-- - MemberJoin event to members
:<|> Named
"join-conversation-by-code-unqualified"
"join-conversation-by-code-unqualified@v3"
( Summary
"Join a conversation using a reusable code.\
\If the guest links team feature is disabled, this will fail with 409 GuestLinksDisabled.\
\Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/code-check` which responds with 404 CodeNotFound if guest links are disabled."
:> Until 'V4
:> MakesFederatedCall 'Galley "on-conversation-updated"
:> MakesFederatedCall 'Galley "on-new-remote-conversation"
:> CanThrow 'CodeNotFound
:> CanThrow 'InvalidConversationPassword
:> CanThrow 'ConvAccessDenied
:> CanThrow 'ConvNotFound
:> CanThrow 'GuestLinksDisabled
Expand All @@ -569,6 +573,32 @@ type ConversationAPI =
:> ReqBody '[Servant.JSON] ConversationCode
:> MultiVerb 'POST '[Servant.JSON] ConvJoinResponses (UpdateResult Event)
)
-- This endpoint can lead to the following events being sent:
-- - MemberJoin event to members
:<|> Named
"join-conversation-by-code-unqualified"
( Summary
"Join a conversation using a reusable code.\
\If the guest links team feature is disabled, this will fail with 409 GuestLinksDisabled.\
\Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/code-check` which responds with 404 CodeNotFound if guest links are disabled."
:> From 'V4
:> MakesFederatedCall 'Galley "on-conversation-updated"
:> MakesFederatedCall 'Galley "on-new-remote-conversation"
:> CanThrow 'CodeNotFound
:> CanThrow 'InvalidConversationPassword
:> CanThrow 'ConvAccessDenied
:> CanThrow 'ConvNotFound
:> CanThrow 'GuestLinksDisabled
:> CanThrow 'InvalidOperation
:> CanThrow 'NotATeamMember
:> CanThrow 'TooManyMembers
:> ZLocalUser
:> ZConn
:> "conversations"
:> "join"
:> ReqBody '[Servant.JSON] JoinConversationByCode
:> MultiVerb 'POST '[Servant.JSON] ConvJoinResponses (UpdateResult Event)
)
:<|> Named
"code-check"
( Summary
Expand All @@ -577,6 +607,7 @@ type ConversationAPI =
\Note that this is currently inconsistent (for backwards compatibility reasons) with `POST /conversations/join` which responds with 409 GuestLinksDisabled if guest links are disabled."
:> CanThrow 'CodeNotFound
:> CanThrow 'ConvNotFound
:> CanThrow 'InvalidConversationPassword
:> "conversations"
:> "code-check"
:> ReqBody '[Servant.JSON] ConversationCode
Expand All @@ -588,9 +619,27 @@ type ConversationAPI =
)
-- this endpoint can lead to the following events being sent:
-- - ConvCodeUpdate event to members, if code didn't exist before
:<|> Named
"create-conversation-code-unqualified@v3"
( Summary "Create or recreate a conversation code"
:> Until 'V4
:> DescriptionOAuthScope 'WriteConversationsCode
:> CanThrow 'ConvAccessDenied
:> CanThrow 'ConvNotFound
:> CanThrow 'GuestLinksDisabled
:> ZUser
:> ZOptConn
:> "conversations"
:> Capture' '[Description "Conversation ID"] "cnv" ConvId
:> "code"
:> CreateConversationCodeVerb
)
-- this endpoint can lead to the following events being sent:
-- - ConvCodeUpdate event to members, if code didn't exist before
:<|> Named
"create-conversation-code-unqualified"
( Summary "Create or recreate a conversation code"
:> From 'V4
:> DescriptionOAuthScope 'WriteConversationsCode
:> CanThrow 'ConvAccessDenied
:> CanThrow 'ConvNotFound
Expand All @@ -600,6 +649,7 @@ type ConversationAPI =
:> "conversations"
:> Capture' '[Description "Conversation ID"] "cnv" ConvId
:> "code"
:> ReqBody '[JSON] CreateConversationCodeRequest
:> CreateConversationCodeVerb
)
:<|> Named
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ testObject_ConversationCode_user_1 =
uriQuery = Query {queryPairs = []},
uriFragment = Nothing
}
)
),
conversationHasPassword = Nothing
}

testObject_ConversationCode_user_2 :: ConversationCode
testObject_ConversationCode_user_2 =
ConversationCode
{ conversationKey = Key {asciiKey = unsafeRange (fromRight undefined (validate "NEN=eLUWHXclTp=_2Nap"))},
conversationCode = Value {asciiValue = unsafeRange (fromRight undefined (validate "lLz-9vR8ENum0kI-xWJs"))},
conversationUri = Nothing
conversationUri = Nothing,
conversationHasPassword = Nothing
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ testObject_Event_conversation_3 =
( ConversationCode
{ conversationKey = Key {asciiKey = unsafeRange "CRdONS7988O2QdyndJs1"},
conversationCode = Value {asciiValue = unsafeRange "7d6713"},
conversationUri = Just $ HttpsUrl (URI {uriScheme = Scheme {schemeBS = "https"}, uriAuthority = Just (Authority {authorityUserInfo = Nothing, authorityHost = Host {hostBS = "example.com"}, authorityPort = Nothing}), uriPath = "", uriQuery = Query {queryPairs = []}, uriFragment = Nothing})
conversationUri = Just $ HttpsUrl (URI {uriScheme = Scheme {schemeBS = "https"}, uriAuthority = Just (Authority {authorityUserInfo = Nothing, authorityHost = Host {hostBS = "example.com"}, authorityPort = Nothing}), uriPath = "", uriQuery = Query {queryPairs = []}, uriFragment = Nothing}),
conversationHasPassword = Nothing
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ testObject_Event_user_14 =
ConversationCode
{ conversationKey = Key {asciiKey = unsafeRange (fromRight undefined (validate "NEN=eLUWHXclTp=_2Nap"))},
conversationCode = Value {asciiValue = unsafeRange (fromRight undefined (validate "lLz-9vR8ENum0kI-xWJs"))},
conversationUri = Nothing
conversationUri = Nothing,
conversationHasPassword = Nothing
}

testObject_Event_user_15 :: Event
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,18 @@ testObject_ConversationCoverView_1 =
ConversationCoverView
(Id (fromJust (UUID.fromString "00000018-0000-0020-0000-000e00000002")))
Nothing
False

testObject_ConversationCoverView_2 :: ConversationCoverView
testObject_ConversationCoverView_2 =
ConversationCoverView
(Id (fromJust (UUID.fromString "00000018-0000-0020-0000-000e00000002")))
(Just "conversation name")
False

testObject_ConversationCoverView_3 :: ConversationCoverView
testObject_ConversationCoverView_3 =
ConversationCoverView
(Id (fromJust (UUID.fromString "00000018-0000-0020-0000-000e00000002")))
(Just "")
True
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"id": "00000018-0000-0020-0000-000e00000002",
"name": null
"name": null,
"has_password": false
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"id": "00000018-0000-0020-0000-000e00000002",
"name": "conversation name"
"name": "conversation name",
"has_password": false
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"id": "00000018-0000-0020-0000-000e00000002",
"name": ""
"name": "",
"has_password": true
}
2 changes: 2 additions & 0 deletions libs/wire-api/test/unit/Test/Wire/API/Roundtrip/Aeson.hs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ tests =
testRoundTrip @Conversation.Bot.RemoveBotResponse,
testRoundTrip @Conversation.Bot.UpdateBotPrekeys,
testRoundTrip @Conversation.Code.ConversationCode,
testRoundTrip @Conversation.Code.JoinConversationByCode,
testRoundTrip @Conversation.Code.CreateConversationCodeRequest,
testRoundTrip @Conversation.Member.MemberUpdate,
testRoundTrip @Conversation.Member.MutedStatus,
testRoundTrip @Conversation.Member.Member,
Expand Down
Loading