more reliable UP deregistration with proper cross-platform support

This commit is contained in:
Henry Hiles 2026-09-10 14:14:10 -04:00
commit 06720238b8
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
4 changed files with 70 additions and 27 deletions

View file

@ -4,6 +4,7 @@ import "package:nexus/controllers/shared_prefs.dart";
class KeyController(final String key) extends Notifier<String?> {
static const String spaceKey = "space";
static const String roomKey = "room";
static const String pushKeyKey = "pushKey";
@override
String? build() =>

View file

@ -0,0 +1,30 @@
import "dart:convert";
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:nexus/controllers/key.dart";
class PushKeyController(final String instance) extends Notifier<String?> {
@override
String? build() => json.decode(
ref.watch(KeyController.provider(KeyController.pushKeyKey)) ?? "{}",
)[instance];
Future<void> set(String? value) async {
final provider = KeyController.provider(KeyController.pushKeyKey);
final notifier = ref.watch(provider.notifier);
final prefs = IMap(json.decode(ref.watch(provider) ?? "{}"));
state = value;
notifier.set(
json.encode(
prefs.add(instance, value).where((_, value) => value != null),
),
);
}
static final provider =
NotifierProvider.family<PushKeyController, String?, String>(
PushKeyController.new,
);
}

View file

@ -1,10 +1,12 @@
import "dart:convert";
import "dart:io";
import "package:flutter/foundation.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:intl/intl.dart";
import "package:nexus/controllers/key.dart";
import "package:nexus/controllers/notifications.dart";
import "package:nexus/controllers/push_key.dart";
import "package:nexus/controllers/rooms.dart";
import "package:nexus/main.dart";
import "package:nexus/controllers/client.dart";
@ -26,7 +28,11 @@ class UnifiedPushController extends AsyncNotifier<bool> {
storage: UnifiedPushStorageSharedPreferences(),
background: isInBackground,
),
onNewEndpoint: (endpoint, instance) => client.registerPusher(
onNewEndpoint: (endpoint, instance) async {
final pushKey = endpoint.pubKeySet!.pubKey;
ref.watch(PushKeyController.provider(instance).notifier).set(pushKey);
await client.registerPusher(
.new(
appDisplayName: "Nexus",
appId: "nexus.federated.nexus",
@ -38,9 +44,10 @@ class UnifiedPushController extends AsyncNotifier<bool> {
"Nexus on ${toBeginningOfSentenceCase(Platform.operatingSystem)}",
kind: .webPush,
lang: "en",
pushKey: endpoint.pubKeySet!.pubKey,
),
pushKey: pushKey,
),
);
},
onMessage: (message, instance) async {
if (message.decrypted == false) {
throw Exception(
@ -88,7 +95,12 @@ class UnifiedPushController extends AsyncNotifier<bool> {
if (isInBackground) exit(0);
},
onRegistrationFailed: (error, instance) => throw error,
onUnregistered: (instance) => ref.invalidateSelf(),
onUnregistered: (instance) async {
await ref
.watch(PushKeyController.provider(instance).notifier)
.set(null);
ref.invalidateSelf();
},
);
if (registered) {
@ -128,17 +140,17 @@ class UnifiedPushController extends AsyncNotifier<bool> {
Future<void> deregister() async {
final clientState = ref.watch(ClientStateController.provider);
final key = await UnifiedPushStorageSharedPreferences().keys.get(
clientState!.deviceId!,
);
if (key == null) return;
final key = ref.watch(PushKeyController.provider(clientState!.deviceId!));
if (key != null) {
await ref
.watch(ClientController.provider.notifier)
.deregisterPusher(
.new(appId: "nexus.federated.nexus", pushKey: key.split("=").first),
.deregisterPusher(.new(appId: "nexus.federated.nexus", pushKey: key));
} else {
debugPrint(
"No matching pushKey found. Skipping deregistration from homeserver.",
);
}
await UnifiedPush.unregister(clientState.deviceId!);
ref.invalidateSelf();

View file

@ -11,7 +11,7 @@ class UnifiedPushAllowedController extends AsyncNotifier<String?> {
return "No valid distributors found. Try installing ${Platform.isLinux
? "KUnifiedPush"
: Platform.isAndroid
? "FCM or NTFY"
? "Google Play Services or NTFY"
: "NTFY"}.";
}