Skip to content

Commit

Permalink
Merge pull request #3884 from wireapp/release_2024-02-13_09_30
Browse files Browse the repository at this point in the history
Release 2024-02-13 - (expected chart version 4.41.0)
  • Loading branch information
elland authored Feb 13, 2024
2 parents 97b2245 + 8c3af6a commit cc5f08b
Show file tree
Hide file tree
Showing 23 changed files with 137 additions and 23 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# [2024-02-13] (Chart Release 4.41.0)

# [2024-02-12] (Chart Release 4.40.0)

## Release notes
Expand Down
3 changes: 3 additions & 0 deletions libs/gundeck-types/src/Gundeck/Types/Push/V2.hs
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,17 @@ newtype ApsLocKey = ApsLocKey {fromLocKey :: Text}

data ApsPreference
= ApsStdPreference
| ApsVoIPPreference
deriving (Eq, Show, Generic)
deriving (Arbitrary) via GenericUniform ApsPreference

instance ToJSON ApsPreference where
toJSON ApsVoIPPreference = "voip"
toJSON ApsStdPreference = "std"

instance FromJSON ApsPreference where
parseJSON = withText "ApsPreference" $ \case
"voip" -> pure ApsVoIPPreference
"std" -> pure ApsStdPreference
x -> fail $ "Invalid preference: " ++ show x

Expand Down
8 changes: 7 additions & 1 deletion libs/wire-api/src/Wire/API/Push/V2/Token.hs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ data Transport
= GCM
| APNS
| APNSSandbox
| APNSVoIP
| APNSVoIPSandbox
deriving stock (Eq, Ord, Show, Bounded, Enum, Generic)
deriving (Arbitrary) via (GenericUniform Transport)
deriving (A.ToJSON, A.FromJSON, S.ToSchema) via (Schema Transport)
Expand All @@ -125,7 +127,9 @@ instance ToSchema Transport where
mconcat
[ element "GCM" GCM,
element "APNS" APNS,
element "APNS_SANDBOX" APNSSandbox
element "APNS_SANDBOX" APNSSandbox,
element "APNS_VOIP" APNSVoIP,
element "APNS_VOIP_SANDBOX" APNSVoIPSandbox
]

instance FromByteString Transport where
Expand All @@ -134,6 +138,8 @@ instance FromByteString Transport where
"GCM" -> pure GCM
"APNS" -> pure APNS
"APNS_SANDBOX" -> pure APNSSandbox
"APNS_VOIP" -> pure APNSVoIP
"APNS_VOIP_SANDBOX" -> pure APNSVoIPSandbox
x -> fail $ "Invalid push transport: " <> show x

newtype Token = Token
Expand Down
6 changes: 6 additions & 0 deletions libs/wire-api/test/golden/Test/Wire/API/Golden/Generated.hs
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,12 @@ tests =
),
( Test.Wire.API.Golden.Generated.Push_2eToken_2eTransport_user.testObject_Push_2eToken_2eTransport_user_3,
"testObject_Push_2eToken_2eTransport_user_3.json"
),
( Test.Wire.API.Golden.Generated.Push_2eToken_2eTransport_user.testObject_Push_2eToken_2eTransport_user_4,
"testObject_Push_2eToken_2eTransport_user_4.json"
),
( Test.Wire.API.Golden.Generated.Push_2eToken_2eTransport_user.testObject_Push_2eToken_2eTransport_user_5,
"testObject_Push_2eToken_2eTransport_user_5.json"
)
],
testGroup "Golden: Token_user" $
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

module Test.Wire.API.Golden.Generated.Push_2eToken_2eTransport_user where

import Wire.API.Push.Token (Transport (APNS, APNSSandbox, GCM))
import Wire.API.Push.Token (Transport (APNS, APNSSandbox, APNSVoIP, APNSVoIPSandbox, GCM))
import Wire.API.Push.Token qualified as Push.Token (Transport)

testObject_Push_2eToken_2eTransport_user_1 :: Push.Token.Transport
Expand All @@ -28,3 +28,9 @@ testObject_Push_2eToken_2eTransport_user_2 = APNS

testObject_Push_2eToken_2eTransport_user_3 :: Push.Token.Transport
testObject_Push_2eToken_2eTransport_user_3 = APNSSandbox

testObject_Push_2eToken_2eTransport_user_4 :: Push.Token.Transport
testObject_Push_2eToken_2eTransport_user_4 = APNSVoIP

testObject_Push_2eToken_2eTransport_user_5 :: Push.Token.Transport
testObject_Push_2eToken_2eTransport_user_5 = APNSVoIPSandbox
4 changes: 4 additions & 0 deletions libs/wire-api/test/golden/Test/Wire/API/Golden/Manual.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import Test.Wire.API.Golden.Manual.QualifiedUserClientPrekeyMap
import Test.Wire.API.Golden.Manual.SearchResultContact
import Test.Wire.API.Golden.Manual.SubConversation
import Test.Wire.API.Golden.Manual.TeamSize
import Test.Wire.API.Golden.Manual.Token
import Test.Wire.API.Golden.Manual.UserClientPrekeyMap
import Test.Wire.API.Golden.Manual.UserIdList
import Test.Wire.API.Golden.Runner
Expand Down Expand Up @@ -143,6 +144,9 @@ tests =
testGroup "GroupId" $
testObjects
[(testObject_GroupId_1, "testObject_GroupId_1.json")],
testGroup "PushToken" $
testObjects
[(testObject_Token_1, "testObject_Token_1.json")],
testGroup "TeamSize" $
testObjects
[ (testObject_TeamSize_1, "testObject_TeamSize_1.json"),
Expand Down
29 changes: 29 additions & 0 deletions libs/wire-api/test/golden/Test/Wire/API/Golden/Manual/Token.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
-- This file is part of the Wire Server implementation.
--
-- Copyright (C) 2022 Wire Swiss GmbH <[email protected]>
--
-- This program is free software: you can redistribute it and/or modify it under
-- the terms of the GNU Affero General Public License as published by the Free
-- Software Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- This program is distributed in the hope that it will be useful, but WITHOUT
-- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
-- details.
--
-- 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 Test.Wire.API.Golden.Manual.Token where

import Data.Id
import Wire.API.Push.V2.Token

testObject_Token_1 :: PushToken
testObject_Token_1 =
pushToken
APNSVoIPSandbox
(AppName {appNameText = "j{\110746\SOH_\1084873M"})
(Token {tokenText = "K"})
(ClientId {clientToWord64 = 6})
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"APNS_VOIP"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"APNS_VOIP_SANDBOX"
6 changes: 6 additions & 0 deletions libs/wire-api/test/golden/testObject_Token_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"app": "j{𛂚\u0001_􈷉M",
"client": "6",
"token": "K",
"transport": "APNS_VOIP_SANDBOX"
}
2 changes: 1 addition & 1 deletion libs/wire-api/test/unit/Test/Wire/API/MLS.hs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ spawn cp minput = do
in snd <$> concurrently writeInput readOutput
case (mout, ex) of
(Just out, ExitSuccess) -> pure out
_ -> assertFailure $ "Failed spawning process\n" <> show mout <> "\n" <> show ex
_ -> assertFailure "Failed spawning process"

cli :: String -> FilePath -> [String] -> CreateProcess
cli store tmp args =
Expand Down
1 change: 1 addition & 0 deletions libs/wire-api/wire-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ test-suite wire-api-golden-tests
Test.Wire.API.Golden.Manual.SearchResultContact
Test.Wire.API.Golden.Manual.SubConversation
Test.Wire.API.Golden.Manual.TeamSize
Test.Wire.API.Golden.Manual.Token
Test.Wire.API.Golden.Manual.UserClientPrekeyMap
Test.Wire.API.Golden.Manual.UserIdList
Test.Wire.API.Golden.Protobuf
Expand Down
4 changes: 3 additions & 1 deletion services/brig/docs/swagger-v3.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"enum": [
"GCM",
"APNS",
"APNS_SANDBOX"
"APNS_SANDBOX",
"APNS_VOIP",
"APNS_VOIP_SANDBOX"
],
"type": "string"
},
Expand Down
4 changes: 3 additions & 1 deletion services/brig/docs/swagger-v4.json
Original file line number Diff line number Diff line change
Expand Up @@ -4828,7 +4828,9 @@
"enum": [
"GCM",
"APNS",
"APNS_SANDBOX"
"APNS_SANDBOX",
"APNS_VOIP",
"APNS_VOIP_SANDBOX"
],
"type": "string"
},
Expand Down
9 changes: 5 additions & 4 deletions services/brig/src/Brig/Provider/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import Data.Range
import Data.Set qualified as Set
import Data.Text.Ascii qualified as Ascii
import Data.Text.Encoding qualified as Text
import Data.Text.Lazy qualified as Text
import GHC.TypeNats
import Imports
import Network.HTTP.Types.Status
Expand Down Expand Up @@ -705,7 +706,7 @@ addBot zuid zcon cid add = do
-- implicitly in the next line.
pure $ FutureWork @'UnprotectedBot undefined
wrapClientE (User.addClient (botUserId bid) bcl newClt maxPermClients (Just $ Set.singleton Public.ClientSupportsLegalholdImplicitConsent))
!>> const (StdError badGateway) -- MalformedPrekeys
!>> const (StdError $ badGatewayWith "MalformedPrekeys")

-- Add the bot to the conversation
ev <- lift $ RPC.addBotMember zuid zcon cid bid (clientId clt) pid sid
Expand Down Expand Up @@ -917,8 +918,8 @@ maybeInvalidUser = maybe (throwStd (errorToWai @'E.InvalidUser)) pure
rangeChecked :: (KnownNat n, KnownNat m, Within a n m, Monad monad) => a -> (ExceptT Error monad) (Range n m a)
rangeChecked = either (throwStd . invalidRange . fromString) pure . checkedEither

badGateway :: Wai.Error
badGateway = Wai.mkError status502 "bad-gateway" "The upstream service returned an invalid response."
badGatewayWith :: String -> Wai.Error
badGatewayWith str = Wai.mkError status502 "bad-gateway" ("The upstream service returned an invalid response: " <> Text.pack str)

tooManyBots :: Wai.Error
tooManyBots = Wai.mkError status409 "too-many-bots" "Maximum number of bots for the service reached."
Expand All @@ -927,7 +928,7 @@ serviceNotWhitelisted :: Wai.Error
serviceNotWhitelisted = Wai.mkError status403 "service-not-whitelisted" "The desired service is not on the whitelist of allowed services for this team."

serviceError :: RPC.ServiceError -> Wai.Error
serviceError RPC.ServiceUnavailable = badGateway
serviceError (RPC.ServiceUnavailableWith str) = badGatewayWith str
serviceError RPC.ServiceBotConflict = tooManyBots

randServiceToken :: MonadIO m => m Public.ServiceToken
Expand Down
6 changes: 3 additions & 3 deletions services/brig/src/Brig/Provider/RPC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import Wire.Rpc
-- External RPC

data ServiceError
= ServiceUnavailable
= ServiceUnavailableWith String
| ServiceBotConflict

-- | Request a new bot to be created by an external service.
Expand All @@ -86,7 +86,7 @@ createBot scon new = do
case Bilge.statusCode rs of
201 -> decodeBytes "External" (responseBody rs)
409 -> throwE ServiceBotConflict
_ -> lift (extLogError scon rs) >> throwE ServiceUnavailable
_ -> lift (extLogError scon rs) >> throwE (ServiceUnavailableWith $ show rs)
where
-- we can't use 'responseJsonEither' instead, because we have a @Response ByteString@
-- here, not a @Response (Maybe ByteString)@.
Expand All @@ -97,7 +97,7 @@ createBot scon new = do
extReq scon ["bots"]
. method POST
. Bilge.json new
onExc ex = lift (extLogError scon ex) >> throwE ServiceUnavailable
onExc ex = lift (extLogError scon ex) >> throwE (ServiceUnavailableWith $ displayException ex)

extReq :: ServiceConn -> [ByteString] -> Request -> Request
extReq scon ps =
Expand Down
19 changes: 14 additions & 5 deletions services/gundeck/src/Gundeck/Aws.hs
Original file line number Diff line number Diff line change
Expand Up @@ -369,12 +369,17 @@ newtype Attributes = Attributes

-- Note [VoIP TTLs]
-- ~~~~~~~~~~~~~~~~
-- For GCM, APNS and APNS_SANDBOX, SNS treats the TTL "0"
-- The TTL message attributes for APNS_VOIP and APNS_VOIP_SANDBOX are not
-- documented but appear to work. The reason might be that TTLs were
-- introduced before support for VoIP notifications. There is a catch,
-- however. For GCM, APNS and APNS_SANDBOX, SNS treats the TTL "0"
-- specially, i.e. it forwards it to the provider where it has a special
-- meaning. Which means if the TTL is lower than the "dwell time" in SNS,
-- the notification is never sent to the provider. So we must specify a
-- reasonably large TTL for transient VoIP notifications, so that they are
-- not discarded already by SNS.
-- meaning. That does not appear to be the case for APNS_VOIP and
-- APNS_VOIP_SANDBOX, for which the TTL is interpreted normally, which means
-- if the TTL is lower than the "dwell time" in SNS, the notification is
-- never sent to the provider. So we must specify a reasonably large TTL
-- for transient VoIP notifications, so that they are not discarded
-- already by SNS.
--
-- cf. http://docs.aws.amazon.com/sns/latest/dg/sns-ttl.html

Expand All @@ -390,9 +395,13 @@ timeToLive t s = Attributes (Endo (ttlAttr s))
ttlNow GCM = "0"
ttlNow APNS = "0"
ttlNow APNSSandbox = "0"
ttlNow APNSVoIP = "15" -- See note [VoIP TTLs]
ttlNow APNSVoIPSandbox = "15" -- See note [VoIP TTLs]
ttlKey GCM = "AWS.SNS.MOBILE.GCM.TTL"
ttlKey APNS = "AWS.SNS.MOBILE.APNS.TTL"
ttlKey APNSSandbox = "AWS.SNS.MOBILE.APNS_SANDBOX.TTL"
ttlKey APNSVoIP = "AWS.SNS.MOBILE.APNS_VOIP.TTL"
ttlKey APNSVoIPSandbox = "AWS.SNS.MOBILE.APNS_VOIP_SANDBOX.TTL"

publish :: EndpointArn -> LT.Text -> Attributes -> Amazon (Either PublishError ())
publish arn txt attrs = do
Expand Down
4 changes: 4 additions & 0 deletions services/gundeck/src/Gundeck/Aws/Arn.hs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ arnTransportText :: Transport -> Text
arnTransportText GCM = "GCM"
arnTransportText APNS = "APNS"
arnTransportText APNSSandbox = "APNS_SANDBOX"
arnTransportText APNSVoIP = "APNS_VOIP"
arnTransportText APNSVoIPSandbox = "APNS_VOIP_SANDBOX"

-- Parsers --------------------------------------------------------------------

Expand All @@ -157,5 +159,7 @@ endpointTopicParser = do
transportParser :: Parser Transport
transportParser =
string "GCM" $> GCM
<|> string "APNS_VOIP_SANDBOX" $> APNSVoIPSandbox
<|> string "APNS_VOIP" $> APNSVoIP
<|> string "APNS_SANDBOX" $> APNSSandbox
<|> string "APNS" $> APNS
4 changes: 4 additions & 0 deletions services/gundeck/src/Gundeck/Instances.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@ instance Cql Transport where
toCql GCM = CqlInt 0
toCql APNS = CqlInt 1
toCql APNSSandbox = CqlInt 2
toCql APNSVoIP = CqlInt 3
toCql APNSVoIPSandbox = CqlInt 4

fromCql (CqlInt i) = case i of
0 -> pure GCM
1 -> pure APNS
2 -> pure APNSSandbox
3 -> pure APNSVoIP
4 -> pure APNSVoIPSandbox
n -> Left $ "unexpected transport: " ++ show n
fromCql _ = Left "transport: int expected"

Expand Down
23 changes: 19 additions & 4 deletions services/gundeck/src/Gundeck/Push.hs
Original file line number Diff line number Diff line change
Expand Up @@ -374,16 +374,31 @@ nativeTargets psh rcps' alreadySent =
null (psh ^. pushConnections)
|| a ^. addrConn `elem` psh ^. pushConnections
-- Apply transport preference in case of alternative transports for the
-- same client. If no explicit preference is given, the default preference depends on the priority.
-- same client (currently only APNS vs APNS VoIP). If no explicit
-- preference is given, the default preference depends on the priority.
preference as =
let pref = psh ^. pushNativeAps >>= view apsPreference
in filter (pick (fromMaybe defPreference pref)) as
where
pick pr a = case a ^. addrTransport of
GCM -> True
APNS -> pr == ApsStdPreference
APNSSandbox -> pr == ApsStdPreference
defPreference = ApsStdPreference
APNS -> pr == ApsStdPreference || notAny a APNSVoIP
APNSSandbox -> pr == ApsStdPreference || notAny a APNSVoIPSandbox
APNSVoIP -> pr == ApsVoIPPreference || notAny a APNS
APNSVoIPSandbox -> pr == ApsVoIPPreference || notAny a APNSSandbox
notAny a t =
not
( any
( \a' ->
addrEqualClient a a'
&& a ^. addrApp == a' ^. addrApp
&& a' ^. addrTransport == t
)
as
)
defPreference = case psh ^. pushNativePriority of
LowPriority -> ApsStdPreference
HighPriority -> ApsVoIPPreference
check :: Either SomeException [a] -> m [a]
check (Left e) = mntgtLogErr e >> pure []
check (Right r) = pure r
Expand Down
9 changes: 9 additions & 0 deletions services/gundeck/src/Gundeck/Push/Native/Serialise.hs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ renderText t prio x = case t of
GCM -> trim "GCM" (jsonString gcmJson)
APNS -> trim "APNS" (jsonString stdApnsJson)
APNSSandbox -> trim "APNS_SANDBOX" (jsonString stdApnsJson)
APNSVoIP -> trim "APNS_VOIP" (jsonString voipApnsJson)
APNSVoIPSandbox -> trim "APNS_VOIP_SANDBOX" (jsonString voipApnsJson)
where
gcmJson =
object
Expand All @@ -65,6 +67,11 @@ renderText t prio x = case t of
[ "aps" .= apsDict,
"data" .= x
]
voipApnsJson =
object
[ "aps" .= object [],
"data" .= x
]
-- https://developer.apple.com/documentation/usernotifications/modifying_content_in_newly_delivered_notifications
-- Must contain `mutable-content: 1` and include an alert dictionary with title, subtitle, or body information.
-- Since we have no useful data here, we send a default payload that gets overridden by the client
Expand All @@ -87,6 +94,8 @@ maxPayloadSize :: Transport -> Int64
maxPayloadSize GCM = 4096
maxPayloadSize APNS = 4096
maxPayloadSize APNSSandbox = 4096
maxPayloadSize APNSVoIP = 5120
maxPayloadSize APNSVoIPSandbox = 5120

gcmPriority :: Priority -> Text
gcmPriority LowPriority = "normal"
Expand Down
5 changes: 3 additions & 2 deletions services/gundeck/test/integration/API.hs
Original file line number Diff line number Diff line change
Expand Up @@ -838,8 +838,9 @@ testSharePushToken = do
gcmTok <- Token . T.decodeUtf8 . toByteString' <$> randomId
apsTok <- Token . T.decodeUtf8 . B16.encode <$> randomBytes 32
let tok1 = pushToken GCM "test" gcmTok
let tok2 = pushToken APNS "com.wire.int.ent" apsTok
forM_ [tok1, tok2] $ \tk -> do
let tok2 = pushToken APNSVoIP "com.wire.dev.ent" apsTok
let tok3 = pushToken APNS "com.wire.int.ent" apsTok
forM_ [tok1, tok2, tok3] $ \tk -> do
u1 <- randomUser
u2 <- randomUser
c1 <- randomClientId
Expand Down
Loading

0 comments on commit cc5f08b

Please sign in to comment.