From a14a799ccab66d84968bb324694127a0287ec3d8 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Fri, 25 Oct 2024 21:53:07 +0400 Subject: [PATCH] ntf: smp to ntf push plan wip --- rfcs/2024-09-25-ios-notifications-2.md | 10 +++++++++- src/Simplex/Messaging/Agent.hs | 3 +++ src/Simplex/Messaging/Agent/Client.hs | 1 + src/Simplex/Messaging/Notifications/Server.hs | 5 +++++ src/Simplex/Messaging/Protocol.hs | 15 +++++++++++++-- src/Simplex/Messaging/Server.hs | 9 +++++++++ 6 files changed, 40 insertions(+), 3 deletions(-) diff --git a/rfcs/2024-09-25-ios-notifications-2.md b/rfcs/2024-09-25-ios-notifications-2.md index 79416b83f..c8a02cd18 100644 --- a/rfcs/2024-09-25-ios-notifications-2.md +++ b/rfcs/2024-09-25-ios-notifications-2.md @@ -46,4 +46,12 @@ NKEY :: NtfPublicAuthKey -> RcvNtfPublicDhKey -> Maybe NtfServerRequest -> Comma -- NotifierID is passed in entity ID field of the transmission ``` -2. Notification server will need to support an additional command to receive "proxied" subscription commands, `SFWD`, that would include `NtfServerRequest`. This command can include both `SNEW` and `SDEL` commands. +Instead of client generating keys for request, SMP server could generate them itself before forwarding request to notifications server. + +2. SMP server has to differentiate legacy queues and queues using new notifications protocol, for example by saving notifications server on queue record. + +For sending notifications, subscriptions mechanism could be replaced with direct push to notifications protocol. + +3. Notification server will need to support an additional command to receive "proxied" subscription commands, `SFWD`, that would include `NtfServerRequest`. This command can include both `SNEW` and `SDEL` commands. + +Notifications server has to process NMSG in form of forwarded request from SMP server (in addition to processing it in subscriptions loop). Notifications "subscription" record in that case would be used only for bookkeeping, for example, finding token (not for making subscriptions to SMP server via NSUB). diff --git a/src/Simplex/Messaging/Agent.hs b/src/Simplex/Messaging/Agent.hs index dc6f4ad17..f07643fea 100644 --- a/src/Simplex/Messaging/Agent.hs +++ b/src/Simplex/Messaging/Agent.hs @@ -771,10 +771,12 @@ newRcvConnSrv c userId connId enableNtfs cMode clientData pqInitKeys subMode srv _ -> pure () AgentConfig {smpClientVRange, smpAgentVRange, e2eEncryptVRange} <- asks config let sndSecure = case cMode of SCMInvitation -> True; SCMContact -> False + -- [ntf] enableNtfs to newRcvQueue (rq, qUri, tSess, sessId) <- newRcvQueue c userId connId srvWithAuth smpClientVRange subMode sndSecure `catchAgentError` \e -> liftIO (print e) >> throwE e atomically $ incSMPServerStat c userId srv connCreated rq' <- withStore c $ \db -> updateNewConnRcv db connId rq lift . when (subMode == SMSubscribe) $ addNewQueueSubscription c rq' tSess sessId + -- [ntf] don't create subscription in client when enableNtfs $ do ns <- asks ntfSupervisor atomically $ sendNtfSubCommand ns (NSCCreate, [connId]) @@ -2083,6 +2085,7 @@ sendNtfConnCommands c cmd = do connIds <- liftIO $ S.toList <$> getSubscriptions c rs <- lift $ withStoreBatch' c (\db -> map (getConnData db) connIds) let (connIds', cErrs) = enabledNtfConns (zip connIds rs) + -- [ntf] send NKEY to smp servers instead of creating via smp supervisor forM_ (L.nonEmpty connIds') $ \connIds'' -> atomically $ writeTBQueue (ntfSubQ ns) (cmd, connIds'') unless (null cErrs) $ atomically $ writeTBQueue (subQ c) ("", "", AEvt SAENone $ ERRS cErrs) diff --git a/src/Simplex/Messaging/Agent/Client.hs b/src/Simplex/Messaging/Agent/Client.hs index 212f0b13a..1b7c74dcb 100644 --- a/src/Simplex/Messaging/Agent/Client.hs +++ b/src/Simplex/Messaging/Agent/Client.hs @@ -1339,6 +1339,7 @@ newRcvQueue c userId connId (ProtoServerWithAuth srv auth) vRange subMode sender (e2eDhKey, e2ePrivKey) <- atomically $ C.generateKeyPair g logServer "-->" c srv NoEntity "NEW" tSess <- mkTransportSession c userId srv connId + -- [ntf] generate notifier id (if enableNtfs), other data from token (sessId, QIK {rcvId, sndId, rcvPublicDhKey, sndSecure}) <- withClient c tSess $ \(SMPConnectedClient smp _) -> (sessionId $ thParams smp,) <$> createSMPQueue smp rKeys dhKey auth subMode senderCanSecure diff --git a/src/Simplex/Messaging/Notifications/Server.hs b/src/Simplex/Messaging/Notifications/Server.hs index 81094e1a7..b0933ab9a 100644 --- a/src/Simplex/Messaging/Notifications/Server.hs +++ b/src/Simplex/Messaging/Notifications/Server.hs @@ -676,6 +676,11 @@ client NtfServerClient {rcvQ, sndQ} NtfSubscriber {newSubQ, smpAgent = ca} NtfPu intervalNotifier delay = forever $ do liftIO $ threadDelay' delay atomically $ writeTBQueue pushQ (tkn, PNCheckMessages) + -- [ntf] should process forwarded commands + -- SNEW, SDEL + -- should process pushed messages (outside of subscription mechanism) - NMSG + -- - find token by notifier id sent by smp server + -- - push last ntfs to apns for token (PNMessageData - NMSG data, notifier id) NtfReqNew corrId (ANE SSubscription newSub) -> do logDebug "SNEW - new subscription" st <- asks store diff --git a/src/Simplex/Messaging/Protocol.hs b/src/Simplex/Messaging/Protocol.hs index 3c5ba11cb..acb05b3e7 100644 --- a/src/Simplex/Messaging/Protocol.hs +++ b/src/Simplex/Messaging/Protocol.hs @@ -393,10 +393,10 @@ data Command (p :: Party) where -- v6 of SMP servers only support signature algorithm for command authorization. -- v7 of SMP servers additionally support additional layer of authenticated encryption. -- RcvPublicAuthKey is defined as C.APublicKey - it can be either signature or DH public keys. - NEW :: RcvPublicAuthKey -> RcvPublicDhKey -> Maybe BasicAuth -> SubscriptionMode -> SenderCanSecure -> Command Recipient + NEW :: RcvPublicAuthKey -> RcvPublicDhKey -> Maybe BasicAuth -> SubscriptionMode -> SenderCanSecure -> Maybe NtfRequest -> Command Recipient SUB :: Command Recipient KEY :: SndPublicAuthKey -> Command Recipient - NKEY :: NtfPublicAuthKey -> RcvNtfPublicDhKey -> Command Recipient + NKEY :: NtfPublicAuthKey -> RcvNtfPublicDhKey -> Maybe NtfServerRequest -> Command Recipient NDEL :: Command Recipient GET :: Command Recipient -- ACK v1 has to be supported for encoding/decoding @@ -427,6 +427,17 @@ data Command (p :: Party) where deriving instance Show (Command p) +-- [ntf] +-- why does client need to include pass into commands? +-- client doesn't have to pass them to ntf server, so smp server could generate them itself. +-- does ntf server even need NtfPublicAuthKey it if it won't be making subscription? - only RcvNtfPublicDhKey for ecryption? +data NtfRequest = NtfRequest NotifierId NtfPublicAuthKey RcvNtfPublicDhKey NtfServerRequest + +data NtfServerRequest = NtfServerRequest NtfServer EncSingedNtfCmd + +-- EncSingedNtfCmd should contain device token +type EncSingedNtfCmd = ByteString + data SubscriptionMode = SMSubscribe | SMOnlyCreate deriving (Eq, Show) diff --git a/src/Simplex/Messaging/Server.hs b/src/Simplex/Messaging/Server.hs index 29de4ff6d..79357a5ec 100644 --- a/src/Simplex/Messaging/Server.hs +++ b/src/Simplex/Messaging/Server.hs @@ -263,6 +263,7 @@ smpServer started cfg@ServerConfig {transports, transportConfig = tCfg} attachHT stats <- asks serverStats liftIO $ forever $ do threadDelay ntfInt + -- [ntf] in addition to subscribed ntf clients (legacy), should push itself for queues with ntf server saved readTVarIO ntfSubClients >>= mapM_ (deliverNtfs ns stats) where deliverNtfs ns stats Client {clientId, ntfSubscriptions, sndQ, connected} = @@ -1221,6 +1222,14 @@ client thParams' clnt@Client {clientId, subscriptions, ntfSubscriptions, rcvQ, s incStat $ qSecured stats liftIO $ either ERR (const OK) <$> secureQueue st rId sKey + -- [ntf] + -- take notifier id (Maybe for backwards compatibility). + -- if id is passed: + -- - response to client would be OK + -- - if it already exists, response would be AUTH / duplicate error? + -- - forward notifier id, EncSingedNtfCmd and dhKey for encryption negotiation to ntf server to create "subscription" record. + -- smp server should differentiate on queue record whether it expects ntf subscriptions or + -- it should push notifications to ntf server itself. - store ntf server on queue record. addQueueNotifier_ :: QueueStore -> NtfPublicAuthKey -> RcvNtfPublicDhKey -> M (Transmission BrokerMsg) addQueueNotifier_ st notifierKey dhKey = time "NKEY" $ do (rcvPublicDhKey, privDhKey) <- atomically . C.generateKeyPair =<< asks random