Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for push notifications in GotoSocial 0.18 #3150

Open
VyrCossont opened this issue Jan 23, 2025 · 9 comments
Open

Support for push notifications in GotoSocial 0.18 #3150

VyrCossont opened this issue Jan 23, 2025 · 9 comments
Labels
c: fediverse Related to non-Mastodon servers

Comments

@VyrCossont
Copy link

VyrCossont commented Jan 23, 2025

I'm the GotoSocial developer implementing Web Push notifications for the upcoming GtS 0.18 release and wanted to give you a heads up. Right now Elk properly displays that GtS doesn't support them yet:

Image

But we'll be adding them with superseriousbusiness/gotosocial#3587 fairly soon. They work almost identically to Mastodon's, with the following caveats:

  • We have a few additional notification types for GotoSocial interaction policies: pending.favourite, pending.reply, and pending.reblog
  • policy for controlling who you get PNs from is not yet implemented: you can set it to anything but GtS will ignore it and always return policy: "all" (this may change before we ship 0.18)

Please let me know if you have questions.

@VyrCossont VyrCossont added the s: pending triage Pending Triage label Jan 23, 2025
@shuuji3 shuuji3 added c: fediverse Related to non-Mastodon servers and removed s: pending triage Pending Triage labels Jan 24, 2025
@shuuji3
Copy link
Member

shuuji3 commented Jan 24, 2025

Thanks for sharing the update. 😃 I'm still unfamiliar with how push notification works in Mastodon but I checked some related codes.

Message

In the current implementation, the second paragraph (It seems that your server does not...) is shown when currentUser object has vapidKey value. If the new version has the same property, it will be hidden. Otherwise, we'll need to adjust the feature detection.

ref.

New notification type

We have a few additional notification types for GotoSocial interaction policies: pending.favourite, pending.reply, and pending.reblog

Current Canary Elk won't show notifications with unknown types in Notification tab (https://main.elk.zone/notifications), and just print out warnings to the console: https://github.com/elk-zone/elk/blob/main/components/notification/NotificationCard.vue#L34
Once Goto Social updates, we could add those types with new strings if needed.

@VyrCossont
Copy link
Author

Do you happen to know where the VAPID key is coming from?

VAPID public keys are per instance, but Mastodon used to also send them when app credentials were created; this was deprecated in Mastodon 4.3.0 and may stop working someday.

Since Mastodon 4.3.0, it's now available from the v2 instance API. You can see that in the GtS version of my own push-notification-enabled GtS server here: https://princess.industries/api/v2/instance

Finally, it's available on Web Push subscription objects, but that's probably not relevant to this case, since you'd need to create a subscription to get it that way, and this check happens before that.

Let me confirm that we're providing it all three ways in GtS and get back to you.

@userquin
Copy link
Member

userquin commented Jan 24, 2025

can you check the error in devtools? the server key is requested when the user signs-in:

? client.value.v1.push.subscription.fetch().catch(() => Promise.resolve(undefined))

Here the api: https://docs.joinmastodon.org/methods/push/#get

And the vapid_key logic here:

.then(({ registration, subscription }): Promise<mastodon.v1.WebPushSubscription | undefined> => {
if (subscription) {
const currentServerKey = (new Uint8Array(subscription.options.applicationServerKey!)).toString()
const subscriptionServerKey = urlBase64ToUint8Array(vapidKey).toString()
// If the VAPID public key did not change and the endpoint corresponds
// to the endpoint saved in the backend, the subscription is valid
// If push subscription is not there, we need to create it: it is fetched on login
if (subscriptionServerKey === currentServerKey && subscription.endpoint === serverEndpoint && (!force && user.pushSubscription)) {
return Promise.resolve(user.pushSubscription)
}
else if (user.pushSubscription) {
// if we have a subscription, but it is not valid or forcing renew, we need to remove it
// we need to prevent removing push notification data
return unsubscribeFromBackend(false, false)
.catch(removePushNotificationDataOnError)
.then(() => subscribe(registration, vapidKey))
.then(subscription => sendSubscriptionToBackend(subscription, notificationData, policy))
}
}

and the creation here:

async function sendSubscriptionToBackend(
subscription: PushSubscription,
data: CreatePushNotification,
policy: mastodon.v1.WebPushSubscriptionPolicy,
): Promise<mastodon.v1.WebPushSubscription> {
const { endpoint, keys } = subscription.toJSON()
return await useMastoClient().v1.push.subscription.create({
policy,
subscription: {
endpoint: endpoint!,
keys: {
p256dh: keys!.p256dh!,
auth: keys!.auth!,
},
},
data,
})
}

Do you have enabled another account with psuh notifications enabled? do you have permissions blocked (push notification requires you to enable browser push notifications when asked)?

@VyrCossont
Copy link
Author

VyrCossont commented Jan 25, 2025

I don't have permissions blocked, and I don't have another account with push notifications enabled (I'm aware that a given site can only have one push subscription at a time).

As far as errors, both Mastodon and GtS 404 when /api/v1/push/subscription is called, but this is expected because no push subscription exists when you've just logged in for the first time.

I think we're running into #2562 here: elk.zone has old OAuth app credentials for my production and test servers, and those credentials don't have an associated VAPID key. If you can delete your stored app credentials for princess.industries and haruko.org, we can test that theory. Unfortunately, I don't have any more instances I can use for testing this theory, but I did manage to break logging into haruko.org entirely by deleting credentials for Elk before I saw that bug.

@VyrCossont
Copy link
Author

I believe there are at least two possible fixes aside from directly addressing #2562; one is to do a one-time invalidation of the app token for every GtS instance, and the other is to use the VAPID key in /api/v2/instance for detecting Web Push support, instead of the VAPID key returned when app credentials are created.

@shuuji3
Copy link
Member

shuuji3 commented Feb 4, 2025

Thanks for the suggestions. I'm going to take a closer look at this issue this week and try to understand how push notifications work.

I was able to set up GoToSocial server on my Raspberry Pi with docker-compose (https://dev-000.gotosocial.shuuji3.xyz/@shuuji3) so that I can check how they interact with the local Elk dev server. Can I use snapshot tag image for testing this? I assume it includes the latest PR for a push notification (superseriousbusiness/gotosocial#3721).

I think the first step I can try is to implement the second option, using /api/v2/instance's configurations.vapid.secret_key to detect availability for push notification.

#2562 was also a long-standing issue and I understand we need to fix it at some point. After implementing that, I'll try TTL cache package (like https://www.npmjs.com/package/@isaacs/ttlcache) or something to prevent permanent lockout from Elk.

@shuuji3
Copy link
Member

shuuji3 commented Feb 4, 2025

Another idea for testing: maybe you can create a PR (with a trivial edit) against this repository just for testing. Elk repository will create a new deploy preview using Netlify similar to the production build, and it issues a new domain for each PR.

For example, the creation of this PR #3183 triggered the new deploy preview with this URL: https://deploy-preview-3183--elk-zone.netlify.app/.

It should have a clean database for each Elk server so the old OAuth app credentials don't exist there. If you think it works for you, please feel free to create any number of PR 🙂

@VyrCossont
Copy link
Author

@shuuji3 that's correct, the snapshot Docker release should be updated every time we merge to main.

@shuuji3
Copy link
Member

shuuji3 commented Feb 7, 2025

Probably #3193 will (partially) solve the app token issue. It prioritizes using vapid_key from /api/v2/instance and also updates the key name for server storage, meaning it will invalidate the existing server cache (but this invalidation is still only one-time).

I tested the snapshot version of GoToSocial (0.17.4-SNAPSHOT+git-00bd0f7) with the PR deploy preview (https://deploy-preview-3193--elk-zone.netlify.app/) and the push notification seems to work as expected.

Screenshot of elk's push notification setting page. there is enable button

Screenshot of the same page, push notification enabled, showing notification config items

Screenshot of push notification popup on desktop


the other is to use the VAPID key in /api/v2/instance for detecting Web Push support, instead of the VAPID key returned when app credentials are created.

Note that although #3193 changed to use /api/v2/instance if available, I didn't change the existing web push support detection logic. (Some other servers doesn't support /api/v2/instance yet so couldn't rely on this solely.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: fediverse Related to non-Mastodon servers
Projects
None yet
Development

No branches or pull requests

3 participants