From 0e6fac928640972aea815aea41a0340b856ca41e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 18 Nov 2021 16:11:50 -0500 Subject: [PATCH] Web Push fixes --- .../actions/push_notifications/registerer.js | 14 ++++++-------- app/soapbox/features/ui/index.js | 17 ++++++++++++++--- .../__tests__/push_notifications-test.js | 12 ++++++------ app/soapbox/reducers/push_notifications.js | 12 ++++++------ app/soapbox/utils/auth.js | 5 +++++ 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/app/soapbox/actions/push_notifications/registerer.js b/app/soapbox/actions/push_notifications/registerer.js index 156641c2b..2dca31fe8 100644 --- a/app/soapbox/actions/push_notifications/registerer.js +++ b/app/soapbox/actions/push_notifications/registerer.js @@ -2,6 +2,7 @@ import { decode as decodeBase64 } from '../../utils/base64'; import { pushNotificationsSetting } from '../../settings'; import { setBrowserSupport, setSubscription, clearSubscription } from './setter'; import { createPushSubsription, updatePushSubscription } from 'soapbox/actions/push_subscriptions'; +import { getVapidKey } from 'soapbox/utils/auth'; // Taken from https://www.npmjs.com/package/web-push const urlBase64ToUint8Array = (base64String) => { @@ -13,11 +14,6 @@ const urlBase64ToUint8Array = (base64String) => { return decodeBase64(base64); }; -const getVapidKey = getState => { - const state = getState(); - return state.getIn(['auth', 'app', 'vapid_key']) || state.getIn(['instance', 'pleroma', 'vapid_public_key']); -}; - const getRegistration = () => navigator.serviceWorker.ready; const getPushSubscription = (registration) => @@ -27,7 +23,7 @@ const getPushSubscription = (registration) => const subscribe = (registration, getState) => registration.pushManager.subscribe({ userVisibleOnly: true, - applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState)), + applicationServerKey: urlBase64ToUint8Array(getVapidKey(getState())), }); const unsubscribe = ({ registration, subscription }) => @@ -35,7 +31,8 @@ const unsubscribe = ({ registration, subscription }) => const sendSubscriptionToBackend = (subscription, me) => { return (dispatch, getState) => { - const params = { subscription }; + const alerts = getState().getIn(['push_notifications', 'alerts']).toJS(); + const params = { subscription, data: { alerts } }; if (me) { const data = pushNotificationsSetting.get(me); @@ -54,7 +51,7 @@ const supportsPushNotifications = ('serviceWorker' in navigator && 'PushManager' export function register() { return (dispatch, getState) => { const me = getState().get('me'); - const vapidKey = getVapidKey(getState); + const vapidKey = getVapidKey(getState()); dispatch(setBrowserSupport(supportsPushNotifications)); @@ -105,6 +102,7 @@ export function register() { } }) .catch(error => { + console.error(error); if (error.code === 20 && error.name === 'AbortError') { console.warn('Your browser supports Web Push Notifications, but does not seem to implement the VAPID protocol.'); } else if (error.code === 5 && error.name === 'InvalidCharacterError') { diff --git a/app/soapbox/features/ui/index.js b/app/soapbox/features/ui/index.js index 4256988b6..1076b481c 100644 --- a/app/soapbox/features/ui/index.js +++ b/app/soapbox/features/ui/index.js @@ -44,6 +44,7 @@ import { getFeatures } from 'soapbox/utils/features'; import { fetchCustomEmojis } from 'soapbox/actions/custom_emojis'; import ThumbNavigation from 'soapbox/components/thumb_navigation'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; +import { getVapidKey } from 'soapbox/utils/auth'; import { Status, @@ -135,6 +136,7 @@ const mapStateToProps = state => { const account = state.getIn(['accounts', me]); const instance = state.get('instance'); const soapbox = getSoapboxConfig(state); + const vapidKey = getVapidKey(state); return { dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null, @@ -144,6 +146,7 @@ const mapStateToProps = state => { account, features: getFeatures(instance), soapbox, + vapidKey, }; }; @@ -357,6 +360,7 @@ class UI extends React.PureComponent { account: PropTypes.object, features: PropTypes.object.isRequired, soapbox: ImmutablePropTypes.map.isRequired, + vapidKey: PropTypes.string, }; state = { @@ -466,7 +470,7 @@ class UI extends React.PureComponent { }); componentDidMount() { - const { account, features, dispatch } = this.props; + const { account, features, vapidKey, dispatch } = this.props; if (!account) return; window.addEventListener('resize', this.handleResize, { passive: true }); @@ -515,17 +519,24 @@ class UI extends React.PureComponent { dispatch(fetchCustomEmojis()); this.connectStreaming(); - dispatch(registerPushNotifications()); + + if (vapidKey) { + dispatch(registerPushNotifications()); + } } componentDidUpdate(prevProps) { this.connectStreaming(); - const { dispatch, account, features } = this.props; + const { dispatch, account, features, vapidKey } = this.props; if (features.chats && account && !prevProps.features.chats) { dispatch(fetchChats()); } + + if (vapidKey && !prevProps.vapidKey) { + dispatch(registerPushNotifications()); + } } componentWillUnmount() { diff --git a/app/soapbox/reducers/__tests__/push_notifications-test.js b/app/soapbox/reducers/__tests__/push_notifications-test.js index 97e75df54..8a7b63925 100644 --- a/app/soapbox/reducers/__tests__/push_notifications-test.js +++ b/app/soapbox/reducers/__tests__/push_notifications-test.js @@ -6,12 +6,12 @@ describe('push_notifications reducer', () => { expect(reducer(undefined, {})).toEqual(ImmutableMap({ subscription: null, alerts: new ImmutableMap({ - follow: false, - follow_request: false, - favourite: false, - reblog: false, - mention: false, - poll: false, + follow: true, + follow_request: true, + favourite: true, + reblog: true, + mention: true, + poll: true, }), isSubscribed: false, browserSupport: false, diff --git a/app/soapbox/reducers/push_notifications.js b/app/soapbox/reducers/push_notifications.js index e72952934..a1cc31699 100644 --- a/app/soapbox/reducers/push_notifications.js +++ b/app/soapbox/reducers/push_notifications.js @@ -4,12 +4,12 @@ import { Map as ImmutableMap } from 'immutable'; const initialState = ImmutableMap({ subscription: null, alerts: new ImmutableMap({ - follow: false, - follow_request: false, - favourite: false, - reblog: false, - mention: false, - poll: false, + follow: true, + follow_request: true, + favourite: true, + reblog: true, + mention: true, + poll: true, }), isSubscribed: false, browserSupport: false, diff --git a/app/soapbox/utils/auth.js b/app/soapbox/utils/auth.js index c697578a1..0d0c6c321 100644 --- a/app/soapbox/utils/auth.js +++ b/app/soapbox/utils/auth.js @@ -57,3 +57,8 @@ export const getAuthUserUrl = state => { me, ]).find(isURL); }; + +/** Get the VAPID public key. */ +export const getVapidKey = state => { + return state.getIn(['auth', 'app', 'vapid_key']) || state.getIn(['instance', 'pleroma', 'vapid_public_key']); +};