From 00e90e5f21a53a8ab2122548d327d55f41068c15 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 14 Jan 2025 16:04:27 +0100 Subject: [PATCH] Use standard webpush when available --- .../android/PushNotificationReceiver.java | 2 +- .../UnifiedPushNotificationReceiver.java | 48 +++++++++++++++---- .../android/api/PushSubscriptionManager.java | 13 +++-- .../RegisterForPushNotifications.java | 2 + 4 files changed, 52 insertions(+), 13 deletions(-) diff --git a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java index b26ba5fa7..49e402f4d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java @@ -163,7 +163,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{ PushNotificationReceiver.this.notify(context, PushNotification.fromNotification(context, account, notification), account.getID(), notification); } - private void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){ + void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){ NotificationManager nm=context.getSystemService(NotificationManager.class); AccountSession session=AccountSessionManager.get(accountID); Account self=session.self; diff --git a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java index dd648d7ea..7e2b452ed 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java +++ b/mastodon/src/main/java/org/joinmastodon/android/UnifiedPushNotificationReceiver.java @@ -5,16 +5,20 @@ import android.util.Log; import org.jetbrains.annotations.NotNull; import org.joinmastodon.android.api.MastodonAPIController; +import org.joinmastodon.android.api.requests.notifications.GetNotificationByID; import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.PaginatedResponse; +import org.joinmastodon.android.model.PushNotification; import org.unifiedpush.android.connector.FailedReason; import org.unifiedpush.android.connector.MessagingReceiver; +import org.unifiedpush.android.connector.data.PublicKeySet; import org.unifiedpush.android.connector.data.PushEndpoint; import org.unifiedpush.android.connector.data.PushMessage; import java.util.List; +import java.util.function.Function; import kotlin.text.Charsets; import me.grishka.appkit.api.Callback; @@ -32,8 +36,15 @@ public class UnifiedPushNotificationReceiver extends MessagingReceiver{ // Called when a new endpoint be used for sending push messages Log.d(TAG, "onNewEndpoint: New Endpoint " + endpoint.getUrl() + " for "+ instance); AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance); - if (account != null) - account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl()); + if (account != null) { + PublicKeySet ks = endpoint.getPubKeySet(); + if (ks != null){ + account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl(), ks.getPubKey(), ks.getAuth()); + } else { + // ks should never be null on new endpoint + account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl()); + } + } } @Override @@ -65,19 +76,38 @@ public class UnifiedPushNotificationReceiver extends MessagingReceiver{ if (account == null) return; - //this is stupid - // Mastodon stores the info to decrypt the message in the HTTP headers, which are not accessible in UnifiedPush, - // thus it is not possible to decrypt them. SO we need to re-request them from the server and transform them later on - // The official uses fcm and moves the headers to extra data, see - // https://github.com/mastodon/webpush-fcm-relay/blob/cac95b28d5364b0204f629283141ac3fb749e0c5/webpush-fcm-relay.go#L116 - // https://github.com/tuskyapp/Tusky/pull/2303#issue-1112080540 + if (message.getDecrypted()) { + // If the mastodon server supports the standard webpush, we can directly use the content + Log.d(TAG, "Push message correctly decrypted"); + PushNotification pn = MastodonAPIController.gson.fromJson(new String(message.getContent(), Charsets.UTF_8), PushNotification.class); + new GetNotificationByID(pn.notificationId) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(org.joinmastodon.android.model.Notification result){ + MastodonAPIController.runInBackground(()->new PushNotificationReceiver().notify(context, pn, instance, result)); + } + + @Override + public void onError(ErrorResponse error){ + MastodonAPIController.runInBackground(()-> new PushNotificationReceiver().notify(context, pn, instance, null)); + } + }) + .exec(instance); + } else { + // else, we have to sync with the server + Log.d(TAG, "Server doesn't support standard webpush, fetching one notification"); + fetchOneNotification(context, account, (notif) -> () -> new PushNotificationReceiver().notifyUnifiedPush(context, account, notif)); + } + } + + private void fetchOneNotification(@NotNull Context context, @NotNull AccountSession account, @NotNull Function callback) { account.getCacheController().getNotifications(null, 1, false, false, true, new Callback<>(){ @Override public void onSuccess(PaginatedResponse> result){ result.items .stream() .findFirst() - .ifPresent(value->MastodonAPIController.runInBackground(()->new PushNotificationReceiver().notifyUnifiedPush(context, account, value))); + .ifPresent(value->MastodonAPIController.runInBackground(callback.apply(value))); } @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java b/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java index 046c55531..0e757910b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/PushSubscriptionManager.java @@ -169,9 +169,16 @@ public class PushSubscriptionManager{ if (endpoint.startsWith("https://app.joinmastodon.org/relay-to/fcm/")) newEndpoint += pushAccountID; - new RegisterForPushNotifications(newEndpoint, - encodedPublicKey, - encodedAuthKey, + registerAccountForPush(subscription, newEndpoint, encodedPublicKey, encodedAuthKey); + }); + } + + public void registerAccountForPush(PushSubscription subscription, String endpoint, String p256dh, String auth){ + MastodonAPIController.runInBackground(()->{ + Log.d(TAG, "registerAccountForPush: started for "+accountID); + new RegisterForPushNotifications(endpoint, + p256dh, + auth, subscription==null ? PushSubscription.Alerts.ofAll() : subscription.alerts, subscription==null ? PushSubscription.Policy.ALL : subscription.policy) .setCallback(new Callback<>(){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java index fb6cabcd9..18bd02884 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/RegisterForPushNotifications.java @@ -27,6 +27,8 @@ public class RegisterForPushNotifications extends MastodonAPIRequest