Use standard webpush when available

This commit is contained in:
sim 2025-01-14 16:04:27 +01:00
parent 376653cb3f
commit 00e90e5f21
4 changed files with 52 additions and 13 deletions

View file

@ -163,7 +163,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
PushNotificationReceiver.this.notify(context, PushNotification.fromNotification(context, account, notification), account.getID(), notification); 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); NotificationManager nm=context.getSystemService(NotificationManager.class);
AccountSession session=AccountSessionManager.get(accountID); AccountSession session=AccountSessionManager.get(accountID);
Account self=session.self; Account self=session.self;

View file

@ -5,16 +5,20 @@ import android.util.Log;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.joinmastodon.android.api.MastodonAPIController; 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.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse; import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.PushNotification;
import org.unifiedpush.android.connector.FailedReason; import org.unifiedpush.android.connector.FailedReason;
import org.unifiedpush.android.connector.MessagingReceiver; 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.PushEndpoint;
import org.unifiedpush.android.connector.data.PushMessage; import org.unifiedpush.android.connector.data.PushMessage;
import java.util.List; import java.util.List;
import java.util.function.Function;
import kotlin.text.Charsets; import kotlin.text.Charsets;
import me.grishka.appkit.api.Callback; 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 // Called when a new endpoint be used for sending push messages
Log.d(TAG, "onNewEndpoint: New Endpoint " + endpoint.getUrl() + " for "+ instance); Log.d(TAG, "onNewEndpoint: New Endpoint " + endpoint.getUrl() + " for "+ instance);
AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance); AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance);
if (account != null) if (account != null) {
account.getPushSubscriptionManager().registerAccountForPush(null, endpoint.getUrl()); 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 @Override
@ -65,19 +76,38 @@ public class UnifiedPushNotificationReceiver extends MessagingReceiver{
if (account == null) if (account == null)
return; return;
//this is stupid if (message.getDecrypted()) {
// Mastodon stores the info to decrypt the message in the HTTP headers, which are not accessible in UnifiedPush, // If the mastodon server supports the standard webpush, we can directly use the content
// thus it is not possible to decrypt them. SO we need to re-request them from the server and transform them later on Log.d(TAG, "Push message correctly decrypted");
// The official uses fcm and moves the headers to extra data, see PushNotification pn = MastodonAPIController.gson.fromJson(new String(message.getContent(), Charsets.UTF_8), PushNotification.class);
// https://github.com/mastodon/webpush-fcm-relay/blob/cac95b28d5364b0204f629283141ac3fb749e0c5/webpush-fcm-relay.go#L116 new GetNotificationByID(pn.notificationId)
// https://github.com/tuskyapp/Tusky/pull/2303#issue-1112080540 .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<Notification, Runnable> callback) {
account.getCacheController().getNotifications(null, 1, false, false, true, new Callback<>(){ account.getCacheController().getNotifications(null, 1, false, false, true, new Callback<>(){
@Override @Override
public void onSuccess(PaginatedResponse<List<Notification>> result){ public void onSuccess(PaginatedResponse<List<Notification>> result){
result.items result.items
.stream() .stream()
.findFirst() .findFirst()
.ifPresent(value->MastodonAPIController.runInBackground(()->new PushNotificationReceiver().notifyUnifiedPush(context, account, value))); .ifPresent(value->MastodonAPIController.runInBackground(callback.apply(value)));
} }
@Override @Override

View file

@ -169,9 +169,16 @@ public class PushSubscriptionManager{
if (endpoint.startsWith("https://app.joinmastodon.org/relay-to/fcm/")) if (endpoint.startsWith("https://app.joinmastodon.org/relay-to/fcm/"))
newEndpoint += pushAccountID; newEndpoint += pushAccountID;
new RegisterForPushNotifications(newEndpoint, registerAccountForPush(subscription, newEndpoint, encodedPublicKey, encodedAuthKey);
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.Alerts.ofAll() : subscription.alerts,
subscription==null ? PushSubscription.Policy.ALL : subscription.policy) subscription==null ? PushSubscription.Policy.ALL : subscription.policy)
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){

View file

@ -27,6 +27,8 @@ public class RegisterForPushNotifications extends MastodonAPIRequest<PushSubscri
private static class Subscription{ private static class Subscription{
public String endpoint; public String endpoint;
// Use standard push notifications if available
public Boolean standard = true;
public Keys keys=new Keys(); public Keys keys=new Keys();
} }