44{-# LANGUAGE LambdaCase #-}
55{-# LANGUAGE KindSignatures #-}
66{-# LANGUAGE NamedFieldPuns #-}
7+ {-# LANGUAGE OverloadedLists #-}
78{-# LANGUAGE OverloadedStrings #-}
89
910module Simplex.Messaging.Notifications.Server.Env where
1011
1112import Control.Concurrent (ThreadId )
13+ import Control.Monad.Except
14+ import Control.Monad.Trans.Except
1215import Crypto.Random
1316import Data.Int (Int64 )
1417import Data.List.NonEmpty (NonEmpty )
@@ -19,7 +22,7 @@ import qualified Data.X509.Validation as XV
1922import Network.Socket
2023import qualified Network.TLS as TLS
2124import Numeric.Natural
22- import Simplex.Messaging.Client (ProtocolClientConfig (.. ))
25+ import Simplex.Messaging.Client (ProtocolClientError (.. ), SMPClientError )
2326import Simplex.Messaging.Client.Agent
2427import qualified Simplex.Messaging.Crypto as C
2528import Simplex.Messaging.Notifications.Protocol
@@ -28,16 +31,17 @@ import Simplex.Messaging.Notifications.Server.Stats
2831import Simplex.Messaging.Notifications.Server.Store.Postgres
2932import Simplex.Messaging.Notifications.Server.Store.Types
3033import Simplex.Messaging.Notifications.Transport (NTFVersion , VersionRangeNTF )
31- import Simplex.Messaging.Protocol (BasicAuth , CorrId , Party (.. ), SMPServer , SParty (.. ), Transmission )
34+ import Simplex.Messaging.Protocol (BasicAuth , CorrId , Party (.. ), SMPServer , SParty (.. ), ServiceId , Transmission )
3235import Simplex.Messaging.Server.Env.STM (StartOptions (.. ))
3336import Simplex.Messaging.Server.Expiration
3437import Simplex.Messaging.Server.QueueStore.Postgres.Config (PostgresStoreCfg (.. ))
3538import Simplex.Messaging.Session
3639import Simplex.Messaging.TMap (TMap )
3740import qualified Simplex.Messaging.TMap as TM
3841import Simplex.Messaging.Transport (ASrvTransport , SMPServiceRole (.. ), ServiceCredentials (.. ), THandleParams , TransportPeer (.. ))
42+ import Simplex.Messaging.Transport.Credentials (genCredentials , tlsCredentials )
3943import Simplex.Messaging.Transport.Server (AddHTTP , ServerCredentials , TransportServerConfig , loadFingerprint , loadServerCredential )
40- import System.Exit ( exitFailure )
44+ import Simplex.Messaging.Util ( liftEitherWith )
4145import System.Mem.Weak (Weak )
4246import UnliftIO.STM
4347
@@ -95,20 +99,35 @@ newNtfServerEnv config@NtfServerConfig {pushQSize, smpAgentCfg, apnsConfig, dbSt
9599 random <- C. newRandom
96100 store <- newNtfDbStore dbStoreConfig
97101 tlsServerCreds <- loadServerCredential ntfCredentials
98- serviceCertHash@ (XV. Fingerprint fp) <- loadFingerprint ntfCredentials
99- smpAgentCfg' <-
100- if useServiceCreds
101- then do
102- serviceSignKey <- case C. x509ToPrivate' $ snd tlsServerCreds of
103- Right pk -> pure pk
104- Left e -> putStrLn (" Server has no valid key: " <> show e) >> exitFailure
105- let service = ServiceCredentials {serviceRole = SRNotifier , serviceCreds = tlsServerCreds, serviceCertHash, serviceSignKey}
106- pure smpAgentCfg {smpCfg = (smpCfg smpAgentCfg) {serviceCredentials = Just service}}
107- else pure smpAgentCfg
108- subscriber <- newNtfSubscriber smpAgentCfg' random
102+ XV. Fingerprint fp <- loadFingerprint ntfCredentials
103+ let dbService = if useServiceCreds then Just $ mkDbService random store else Nothing
104+ subscriber <- newNtfSubscriber smpAgentCfg dbService random
109105 pushServer <- newNtfPushServer pushQSize apnsConfig
110106 serverStats <- newNtfServerStats =<< getCurrentTime
111107 pure NtfEnv {config, subscriber, pushServer, store, random, tlsServerCreds, serverIdentity = C. KeyHash fp, serverStats}
108+ where
109+ mkDbService g store =
110+ DBService
111+ { getCredentials = getCredentials g store,
112+ updateServiceId = updateServiceId store
113+ }
114+ getCredentials :: TVar ChaChaDRG -> NtfPostgresStore -> SMPServer -> IO (Either SMPClientError ServiceCredentials )
115+ getCredentials g st srv = runExceptT $ do
116+ ExceptT (withClientDB " " st $ \ db -> getNtfServiceCredentials db srv >>= mapM (mkServiceCreds db)) >>= \ case
117+ Just (C. KeyHash kh, serviceCreds) -> do
118+ serviceSignKey <- liftEitherWith PCEIOError $ C. x509ToPrivate' $ snd serviceCreds
119+ pure ServiceCredentials {serviceRole = SRNotifier , serviceCreds, serviceCertHash = XV. Fingerprint kh, serviceSignKey}
120+ Nothing -> throwE PCEServiceUnavailable -- this error cannot happen, as clients never connect to unknown servers
121+ where
122+ mkServiceCreds db = \ case
123+ (_, Just tlsCreds) -> pure tlsCreds
124+ (srvId, Nothing ) -> do
125+ cred <- genCredentials g Nothing (25 , 24 * 999999 ) " simplex"
126+ let tlsCreds = tlsCredentials [cred]
127+ setNtfServiceCredentials db srvId tlsCreds
128+ pure tlsCreds
129+ updateServiceId :: NtfPostgresStore -> SMPServer -> Maybe ServiceId -> IO (Either SMPClientError () )
130+ updateServiceId st srv serviceId_ = withClientDB " " st $ \ db -> updateNtfServiceId db srv serviceId_
112131
113132data NtfSubscriber = NtfSubscriber
114133 { smpSubscribers :: TMap SMPServer SMPSubscriberVar ,
@@ -118,11 +137,11 @@ data NtfSubscriber = NtfSubscriber
118137
119138type SMPSubscriberVar = SessionVar SMPSubscriber
120139
121- newNtfSubscriber :: SMPClientAgentConfig -> TVar ChaChaDRG -> IO NtfSubscriber
122- newNtfSubscriber smpAgentCfg random = do
140+ newNtfSubscriber :: SMPClientAgentConfig -> Maybe DBService -> TVar ChaChaDRG -> IO NtfSubscriber
141+ newNtfSubscriber smpAgentCfg dbService random = do
123142 smpSubscribers <- TM. emptyIO
124143 subscriberSeq <- newTVarIO 0
125- smpAgent <- newSMPClientAgent SNotifierService smpAgentCfg random
144+ smpAgent <- newSMPClientAgent SNotifierService smpAgentCfg dbService random
126145 pure NtfSubscriber {smpSubscribers, subscriberSeq, smpAgent}
127146
128147data SMPSubscriber = SMPSubscriber
0 commit comments