diff --git a/keyserver/package.json b/keyserver/package.json --- a/keyserver/package.json +++ b/keyserver/package.json @@ -78,7 +78,8 @@ "tcomb": "^3.2.29", "twin-bcrypt": "^2.1.1", "uuid": "^3.3.3", - "web": "0.0.1" + "web": "0.0.1", + "web-push": "^3.5.0" }, "optionalDependencies": { "bufferutil": "^4.0.5", diff --git a/keyserver/src/push/providers.js b/keyserver/src/push/providers.js --- a/keyserver/src/push/providers.js +++ b/keyserver/src/push/providers.js @@ -5,6 +5,7 @@ import fcmAdmin from 'firebase-admin'; import type { FirebaseApp } from 'firebase-admin'; import invariant from 'invariant'; +import webpush from 'web-push'; import { importJSON } from '../utils/import-json.js'; @@ -80,6 +81,26 @@ return codeVersion && codeVersion >= 87 ? 'app.comm' : 'org.squadcal.app'; } +type WebPushConfig = { +publicKey: string, +privateKey: string }; +let cachedWebPushConfig: ?WebPushConfig = null; +async function getWebPushConfig(): Promise { + if (cachedWebPushConfig) { + return cachedWebPushConfig; + } + cachedWebPushConfig = await importJSON({ + folder: 'secrets', + name: 'web_push_config', + }); + if (cachedWebPushConfig) { + webpush.setVapidDetails( + 'mailto:support@comm.app', + cachedWebPushConfig.publicKey, + cachedWebPushConfig.privateKey, + ); + } + return cachedWebPushConfig; +} + export { getAPNPushProfileForCodeVersion, getFCMPushProfileForCodeVersion, @@ -88,4 +109,5 @@ endFirebase, endAPNs, getAPNsNotificationTopic, + getWebPushConfig, }; diff --git a/keyserver/src/responders/website-responders.js b/keyserver/src/responders/website-responders.js --- a/keyserver/src/responders/website-responders.js +++ b/keyserver/src/responders/website-responders.js @@ -40,6 +40,7 @@ fetchCurrentUserInfo, fetchKnownUserInfos, } from '../fetchers/user-fetchers.js'; +import { getWebPushConfig } from '../push/providers.js'; import { setNewSession } from '../session/cookies.js'; import { Viewer } from '../session/viewer.js'; import { streamJSON, waitForStream } from '../utils/json-stream.js'; @@ -304,6 +305,17 @@ return hasNotAcknowledgedPolicies ? 0 : initialTime; })(); + const pushApiPublicKeyPromise = (async () => { + const pushConfig = await getWebPushConfig(); + if (!pushConfig) { + if (process.env.NODE_ENV !== 'development') { + console.warn('keyserver/secrets/web_push_config.json should exist'); + } + return null; + } + return pushConfig.publicKey; + })(); + const { jsURL, fontsURL, cssInclude } = await assetInfoPromise; // prettier-ignore @@ -392,6 +404,7 @@ primaryIdentityKeys: null, notificationIdentityKeys: null, }, + pushApiPublicKey: pushApiPublicKeyPromise, _persist: null, }); const jsonStream = streamJSON(res, initialReduxState); diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js --- a/lib/types/redux-types.js +++ b/lib/types/redux-types.js @@ -122,6 +122,7 @@ deviceToken?: void, cookie?: void, cryptoStore: CryptoStore, + pushApiPublicKey: ?string, ... }; export type AppState = NativeAppState | WebAppState; diff --git a/web/redux/redux-setup.js b/web/redux/redux-setup.js --- a/web/redux/redux-setup.js +++ b/web/redux/redux-setup.js @@ -89,6 +89,7 @@ windowActive: boolean, userPolicies: UserPolicies, cryptoStore: CryptoStore, + pushApiPublicKey: ?string, _persist: ?PersistState, }; diff --git a/yarn.lock b/yarn.lock --- a/yarn.lock +++ b/yarn.lock @@ -6708,6 +6708,16 @@ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= +asn1.js@^5.3.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + asn1@~0.2.3: version "0.2.6" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" @@ -7434,7 +7444,7 @@ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== -bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: +bn.js@^4.0.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== @@ -13075,6 +13085,13 @@ quick-lru "^5.1.1" resolve-alpn "^1.0.0" +http_ece@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/http_ece/-/http_ece-1.1.0.tgz#74780c6eb32d8ddfe9e36a83abcd81fe0cd4fb75" + integrity sha512-bptAfCDdPJxOs5zYSe7Y3lpr772s1G346R4Td5LgRUeCwIGpCGDUTJxRrhTNcAXbx37spge0kWEIH7QAYWNTlA== + dependencies: + urlsafe-base64 "~1.0.0" + https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" @@ -23144,6 +23161,11 @@ punycode "1.3.2" querystring "0.2.0" +urlsafe-base64@^1.0.0, urlsafe-base64@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/urlsafe-base64/-/urlsafe-base64-1.0.0.tgz#23f89069a6c62f46cf3a1d3b00169cefb90be0c6" + integrity sha512-RtuPeMy7c1UrHwproMZN9gN6kiZ0SvJwRaEzwZY0j9MypEkFqyBaKv176jvlPtg58Zh36bOkS0NFABXMHvvGCA== + use-callback-ref@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" @@ -23530,6 +23552,18 @@ dependencies: defaults "^1.0.3" +web-push@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/web-push/-/web-push-3.5.0.tgz#4576533746052eda3bd50414b54a1b0a21eeaeae" + integrity sha512-JC0V9hzKTqlDYJ+LTZUXtW7B175qwwaqzbbMSWDxHWxZvd3xY0C2rcotMGDavub2nAAFw+sXTsqR65/KY2A5AQ== + dependencies: + asn1.js "^5.3.0" + http_ece "1.1.0" + https-proxy-agent "^5.0.0" + jws "^4.0.0" + minimist "^1.2.5" + urlsafe-base64 "^1.0.0" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"