@@ -16,14 +16,8 @@ import Control.Monad
1616import Control.Monad.Except
1717import Control.Monad.IO.Class
1818import Control.Monad.Trans.Except
19- import Crypto.Hash.Algorithms (SHA256 (.. ))
2019import qualified Crypto.PubKey.ECC.ECDSA as EC
21- import qualified Crypto.PubKey.ECC.Types as ECT
2220import Crypto.Random (ChaChaDRG )
23- import qualified Crypto.Store.PKCS8 as PK
24- import Data.ASN1.BinaryEncoding (DER (.. ))
25- import Data.ASN1.Encoding
26- import Data.ASN1.Types
2721import Data.Aeson (ToJSON , (.=) )
2822import qualified Data.Aeson as J
2923import qualified Data.Aeson.Encoding as JE
@@ -32,18 +26,15 @@ import Data.Bifunctor (first)
3226import qualified Data.ByteString.Base64.URL as U
3327import Data.ByteString.Builder (lazyByteString )
3428import Data.ByteString.Char8 (ByteString )
35- import qualified Data.ByteString.Lazy.Char8 as LB
3629import qualified Data.CaseInsensitive as CI
3730import Data.Int (Int64 )
3831import Data.List (find )
39- import Data.List.NonEmpty (NonEmpty (.. ))
4032import Data.Map.Strict (Map )
4133import Data.Maybe (isNothing )
4234import Data.Text (Text )
4335import qualified Data.Text as T
4436import Data.Text.Encoding (encodeUtf8 )
4537import Data.Time.Clock.System
46- import qualified Data.X509 as X
4738import qualified Data.X509.CertificateStore as XS
4839import Network.HPACK.Token as HT
4940import Network.HTTP.Types (Status )
@@ -53,6 +44,7 @@ import qualified Network.HTTP2.Client as H
5344import Network.Socket (HostName , ServiceName )
5445import qualified Simplex.Messaging.Crypto as C
5546import Simplex.Messaging.Notifications.Protocol
47+ import Simplex.Messaging.Notifications.Server.Push
5648import Simplex.Messaging.Notifications.Server.Push.APNS.Internal
5749import Simplex.Messaging.Notifications.Server.Store.Types (NtfTknRec (.. ))
5850import Simplex.Messaging.Parsers (defaultJSON )
@@ -62,55 +54,6 @@ import Simplex.Messaging.Util (safeDecodeUtf8, tshow)
6254import System.Environment (getEnv )
6355import UnliftIO.STM
6456
65- data JWTHeader = JWTHeader
66- { alg :: Text , -- key algorithm, ES256 for APNS
67- kid :: Text -- key ID
68- }
69- deriving (Show )
70-
71- data JWTClaims = JWTClaims
72- { iss :: Text , -- issuer, team ID for APNS
73- iat :: Int64 -- issue time, seconds from epoch
74- }
75- deriving (Show )
76-
77- data JWTToken = JWTToken JWTHeader JWTClaims
78- deriving (Show )
79-
80- mkJWTToken :: JWTHeader -> Text -> IO JWTToken
81- mkJWTToken hdr iss = do
82- iat <- systemSeconds <$> getSystemTime
83- pure $ JWTToken hdr JWTClaims {iss, iat}
84-
85- type SignedJWTToken = ByteString
86-
87- $ (JQ. deriveToJSON defaultJSON ''JWTHeader)
88-
89- $ (JQ. deriveToJSON defaultJSON ''JWTClaims)
90-
91- signedJWTToken :: EC. PrivateKey -> JWTToken -> IO SignedJWTToken
92- signedJWTToken pk (JWTToken hdr claims) = do
93- let hc = jwtEncode hdr <> " ." <> jwtEncode claims
94- sig <- EC. sign pk SHA256 hc
95- pure $ hc <> " ." <> serialize sig
96- where
97- jwtEncode :: ToJSON a => a -> ByteString
98- jwtEncode = U. encodeUnpadded . LB. toStrict . J. encode
99- serialize sig = U. encodeUnpadded $ encodeASN1' DER [Start Sequence , IntVal (EC. sign_r sig), IntVal (EC. sign_s sig), End Sequence ]
100-
101- readECPrivateKey :: FilePath -> IO EC. PrivateKey
102- readECPrivateKey f = do
103- -- this pattern match is specific to APNS key type, it may need to be extended for other push providers
104- [PK. Unprotected (X. PrivKeyEC X. PrivKeyEC_Named {privkeyEC_name, privkeyEC_priv})] <- PK. readKeyFile f
105- pure EC. PrivateKey {private_curve = ECT. getCurveByName privkeyEC_name, private_d = privkeyEC_priv}
106-
107- data PushNotification
108- = PNVerification NtfRegCode
109- | PNMessage (NonEmpty PNMessageData )
110- | -- | PNAlert Text
111- PNCheckMessages
112- deriving (Show )
113-
11457data APNSNotification = APNSNotification { aps :: APNSNotificationBody , notificationData :: Maybe J. Value}
11558 deriving (Show )
11659
0 commit comments