Skip to content

Commit ea9adf1

Browse files
epoberezkinp1gp1g
andauthored
webpush: small fixes (#1699)
* Fix compilation for client lib * Print VAPID fp * Fix VAPID signature * refactor --------- Co-authored-by: sim <git@sgougeon.fr>
1 parent 229c895 commit ea9adf1

File tree

5 files changed

+46
-32
lines changed

5 files changed

+46
-32
lines changed

simplexmq.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ library
312312
, directory ==1.3.*
313313
, filepath ==1.4.*
314314
, hourglass ==0.2.*
315+
, http-client ==0.7.*
315316
, http-types ==0.12.*
316317
, http2 >=4.2.2 && <4.3
317318
, iproute ==1.7.*
@@ -343,7 +344,6 @@ library
343344
case-insensitive ==1.2.*
344345
, hashable ==1.4.*
345346
, ini ==0.4.1
346-
, http-client ==0.7.*
347347
, http-client-tls ==0.3.6.*
348348
, optparse-applicative >=0.15 && <0.17
349349
, process ==1.6.*

src/Simplex/Messaging/Crypto.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ module Simplex.Messaging.Crypto
9595
encodePrivKey,
9696
decodePrivKey,
9797
pubKeyBytes,
98+
encodeBigInt,
9899
uncompressEncodePoint,
99100
uncompressDecodePoint,
100101
uncompressDecodePrivateNumber,

src/Simplex/Messaging/Notifications/Server/Main.hs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
module Simplex.Messaging.Notifications.Server.Main where
1212

1313
import Control.Logger.Simple (setLogLevel)
14-
import Control.Monad ( (<$!>), unless, void )
14+
import Control.Monad (unless, void, (<$!>))
1515
import qualified Data.ByteString.Char8 as B
1616
import Data.Functor (($>))
1717
import Data.Ini (lookupValue, readIniFile)
@@ -31,9 +31,10 @@ import Simplex.Messaging.Client (HostMode (..), NetworkConfig (..), ProtocolClie
3131
import Simplex.Messaging.Client.Agent (SMPClientAgentConfig (..), defaultSMPClientAgentConfig)
3232
import qualified Simplex.Messaging.Crypto as C
3333
import Simplex.Messaging.Notifications.Protocol (NtfTokenId)
34-
import Simplex.Messaging.Notifications.Server (runNtfServer, restoreServerLastNtfs)
34+
import Simplex.Messaging.Notifications.Server (restoreServerLastNtfs, runNtfServer)
3535
import Simplex.Messaging.Notifications.Server.Env (NtfServerConfig (..), defaultInactiveClientExpiration)
3636
import Simplex.Messaging.Notifications.Server.Push.APNS (defaultAPNSPushClientConfig)
37+
import Simplex.Messaging.Notifications.Server.Push.WebPush (VapidKey (..), WebPushConfig (..), mkVapid)
3738
import Simplex.Messaging.Notifications.Server.Store (newNtfSTMStore)
3839
import Simplex.Messaging.Notifications.Server.Store.Postgres (exportNtfDbStore, importNtfSTMStore, newNtfDbStore)
3940
import Simplex.Messaging.Notifications.Server.StoreLog (readWriteNtfSTMStore)
@@ -55,9 +56,8 @@ import System.Directory (createDirectoryIfMissing, doesFileExist, renameFile)
5556
import System.Exit (exitFailure)
5657
import System.FilePath (combine)
5758
import System.IO (BufferMode (..), hSetBuffering, stderr, stdout)
58-
import Text.Read (readMaybe)
5959
import System.Process (readCreateProcess, shell)
60-
import Simplex.Messaging.Notifications.Server.Push.WebPush (WebPushConfig(..), VapidKey, mkVapid)
60+
import Text.Read (readMaybe)
6161

6262
ntfServerCLI :: FilePath -> FilePath -> IO ()
6363
ntfServerCLI cfgPath logPath =
@@ -215,12 +215,13 @@ ntfServerCLI cfgPath logPath =
215215
hSetBuffering stdout LineBuffering
216216
hSetBuffering stderr LineBuffering
217217
fp <- checkSavedFingerprint cfgPath defaultX509Config
218-
vapidKey <- getVapidKey vapidKeyPath
218+
vapidKey@VapidKey {fp = vapidFp} <- getVapidKey vapidKeyPath
219219
let host = either (const "<hostnames>") T.unpack $ lookupValue "TRANSPORT" "host" ini
220220
port = T.unpack $ strictIni "TRANSPORT" "port" ini
221221
cfg@NtfServerConfig {transports} = serverConfig vapidKey
222222
srv = ProtoServerWithAuth (NtfServer [THDomainName host] (if port == "443" then "" else port) (C.KeyHash fp)) Nothing
223223
printServiceInfo serverVersion srv
224+
B.putStrLn $ "VAPID: " <> vapidFp
224225
printNtfServerConfig transports dbStoreConfig
225226
runNtfServer cfg
226227
where
@@ -360,18 +361,21 @@ cliCommandP cfgPath logPath iniFile =
360361
skipTokensP =
361362
option
362363
strParse
363-
( long "skip-tokens"
364-
<> help "Skip tokens during import"
365-
<> value S.empty
366-
)
364+
( long "skip-tokens"
365+
<> help "Skip tokens during import"
366+
<> value S.empty
367+
)
367368
initP :: Parser InitOptions
368369
initP = do
369370
enableStoreLog <-
370-
flag' False
371+
flag'
372+
False
371373
( long "disable-store-log"
372374
<> help "Disable store log for persistence (enabled by default)"
373375
)
374-
<|> flag True True
376+
<|> flag
377+
True
378+
True
375379
( long "store-log"
376380
<> short 'l'
377381
<> help "Enable store log for persistence (DEPRECATED, enabled by default)"

src/Simplex/Messaging/Notifications/Server/Push.hs

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
module Simplex.Messaging.Notifications.Server.Push where
1212

13+
import Control.Exception (Exception)
14+
import Control.Monad.Except (ExceptT)
1315
import Crypto.Hash.Algorithms (SHA256 (..))
1416
import qualified Crypto.PubKey.ECC.ECDSA as EC
1517
import qualified Crypto.PubKey.ECC.Types as ECT
@@ -28,15 +30,13 @@ import Data.List.NonEmpty (NonEmpty (..))
2830
import Data.Text (Text)
2931
import Data.Time.Clock.System
3032
import qualified Data.X509 as X
33+
import GHC.Exception (SomeException)
34+
import Network.HTTP.Types (Status)
35+
import qualified Simplex.Messaging.Crypto as C
3136
import Simplex.Messaging.Notifications.Protocol
37+
import Simplex.Messaging.Notifications.Server.Store.Types (NtfTknRec)
3238
import Simplex.Messaging.Parsers (defaultJSON)
3339
import Simplex.Messaging.Transport.HTTP2.Client (HTTP2ClientError)
34-
import qualified Simplex.Messaging.Crypto as C
35-
import Network.HTTP.Types (Status)
36-
import Control.Exception (Exception)
37-
import Simplex.Messaging.Notifications.Server.Store.Types (NtfTknRec)
38-
import Control.Monad.Except (ExceptT)
39-
import GHC.Exception (SomeException)
4040

4141
data JWTHeader = JWTHeader
4242
{ typ :: Text, -- "JWT"
@@ -46,7 +46,7 @@ data JWTHeader = JWTHeader
4646
deriving (Show)
4747

4848
mkJWTHeader :: Text -> Maybe Text -> JWTHeader
49-
mkJWTHeader alg kid = JWTHeader { typ = "JWT", alg, kid }
49+
mkJWTHeader alg kid = JWTHeader {typ = "JWT", alg, kid}
5050

5151
data JWTClaims = JWTClaims
5252
{ iss :: Maybe Text, -- issuer, team ID for APNS
@@ -65,29 +65,38 @@ mkJWTToken hdr iss = do
6565
iat <- systemSeconds <$> getSystemTime
6666
pure $ JWTToken hdr $ jwtClaims iat
6767
where
68-
jwtClaims iat = JWTClaims
69-
{ iss = Just iss,
70-
iat = Just iat,
71-
exp = Nothing,
72-
aud = Nothing,
73-
sub = Nothing
74-
}
68+
jwtClaims iat =
69+
JWTClaims
70+
{ iss = Just iss,
71+
iat = Just iat,
72+
exp = Nothing,
73+
aud = Nothing,
74+
sub = Nothing
75+
}
7576

7677
type SignedJWTToken = ByteString
7778

7879
$(JQ.deriveToJSON defaultJSON ''JWTHeader)
7980

8081
$(JQ.deriveToJSON defaultJSON ''JWTClaims)
8182

82-
signedJWTToken :: EC.PrivateKey -> JWTToken -> IO SignedJWTToken
83-
signedJWTToken pk (JWTToken hdr claims) = do
83+
signedJWTToken_ :: (EC.Signature -> ByteString) -> EC.PrivateKey -> JWTToken -> IO SignedJWTToken
84+
signedJWTToken_ serialize pk (JWTToken hdr claims) = do
8485
let hc = jwtEncode hdr <> "." <> jwtEncode claims
8586
sig <- EC.sign pk SHA256 hc
86-
pure $ hc <> "." <> serialize sig
87+
pure $ hc <> "." <> U.encodeUnpadded (serialize sig)
8788
where
8889
jwtEncode :: ToJSON a => a -> ByteString
8990
jwtEncode = U.encodeUnpadded . LB.toStrict . J.encode
90-
serialize sig = U.encodeUnpadded $ encodeASN1' DER [Start Sequence, IntVal (EC.sign_r sig), IntVal (EC.sign_s sig), End Sequence]
91+
92+
signedJWTToken :: EC.PrivateKey -> JWTToken -> IO SignedJWTToken
93+
signedJWTToken = signedJWTToken_ $ \sig ->
94+
encodeASN1' DER [Start Sequence, IntVal (EC.sign_r sig), IntVal (EC.sign_s sig), End Sequence]
95+
96+
-- | Does it work with APNS ?
97+
signedJWTTokenRaw :: EC.PrivateKey -> JWTToken -> IO SignedJWTToken
98+
signedJWTTokenRaw = signedJWTToken_ $ \sig ->
99+
C.encodeBigInt (EC.sign_r sig) <> C.encodeBigInt (EC.sign_s sig)
91100

92101
readECPrivateKey :: FilePath -> IO EC.PrivateKey
93102
readECPrivateKey f = do

src/Simplex/Messaging/Notifications/Server/Push/WebPush.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ mkVapidHeader VapidKey {key, fp} uriAuthority expire = do
125125
{ iss = Nothing,
126126
iat = Nothing,
127127
exp = Just expire,
128-
aud = Just $ T.decodeUtf8 uriAuthority,
128+
aud = Just $ T.decodeUtf8 $ "https://" <> uriAuthority,
129129
sub = Just "https://github.com/simplex-chat/simplexmq/"
130130
}
131131
jwt = JWTToken jwtHeader jwtClaims
132-
signedToken <- signedJWTToken key jwt
132+
signedToken <- signedJWTTokenRaw key jwt
133133
pure $ "vapid t=" <> signedToken <> ",k=" <> fp
134134

135135
wpPushProviderClient :: WebPushClient -> PushProviderClient

0 commit comments

Comments
 (0)