Browse Source

Merge pull request #959 from nextcloud/refactor/push_notification

refactor(neon,nextcloud): cleanup PushNotification decryption
pull/979/head
Nikolas Rimikis 1 year ago committed by GitHub
parent
commit
cf13862630
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/neon/neon/lib/src/blocs/push_notifications.dart
  2. 49
      packages/neon/neon/lib/src/models/push_notification.dart
  3. 19
      packages/neon/neon/lib/src/utils/push_utils.dart

2
packages/neon/neon/lib/src/blocs/push_notifications.dart

@ -60,7 +60,7 @@ class PushNotificationsBloc extends Bloc implements PushNotificationsBlocEvents,
Future<void> _setupUnifiedPush() async {
// We just use a single RSA keypair for all accounts
final keypair = await PushUtils.loadRSAKeypair();
final keypair = PushUtils.loadRSAKeypair();
await UnifiedPush.initialize(
onNewEndpoint: (final endpoint, final instance) async {

49
packages/neon/neon/lib/src/models/push_notification.dart

@ -1,13 +1,26 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:meta/meta.dart';
import 'package:nextcloud/notifications.dart' show DecryptedSubject;
import 'package:nextcloud/notifications.dart' as notifications;
part 'push_notification.g.dart';
/// The json key for [PushNotification.accountID].
const String _accountIDKey = 'accountID';
/// The json key for [PushNotification.priority].
const String _priorityKey = 'priority';
/// The json key for [PushNotification.type].
const String _typeKey = 'type';
/// The json key for [PushNotification.subject].
const String _subjectKey = 'subject';
/// Data for a push notification.
@JsonSerializable()
@immutable
@internal
class PushNotification {
/// Creates a new push notification.
const PushNotification({
required this.accountID,
required this.priority,
@ -15,14 +28,44 @@ class PushNotification {
required this.subject,
});
/// Creates a new PushNotification object from the given [json] data.
///
/// Use [PushNotification.fromEncrypted] when you the [subject] is still encrypted.
factory PushNotification.fromJson(final Map<String, dynamic> json) => _$PushNotificationFromJson(json);
/// Creates a new PushNotification object from the given [json] data containing an encrypted [subject].
///
/// Use [PushNotification.fromJson] when the [subject] is not encrypted.
factory PushNotification.fromEncrypted(
final Map<String, dynamic> json,
final notifications.RSAPrivateKey privateKey,
) {
final subject = notifications.decryptPushNotificationSubject(privateKey, json[_subjectKey] as String);
return PushNotification(
accountID: json[_accountIDKey] as String,
priority: json[_priorityKey] as String,
type: json[_typeKey] as String,
subject: subject,
);
}
/// Parses this object into a json like map.
Map<String, dynamic> toJson() => _$PushNotificationToJson(this);
/// The account associated to this notification.
@JsonKey(name: _accountIDKey)
final String accountID;
/// The priority of the notification.
@JsonKey(name: _priorityKey)
final String priority;
/// The type of the notification.
@JsonKey(name: _typeKey)
final String type;
final DecryptedSubject subject;
/// The subject of this notification.
@JsonKey(name: _subjectKey)
final notifications.DecryptedSubject subject;
}

19
packages/neon/neon/lib/src/utils/push_utils.dart

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:ui';
@ -23,17 +24,17 @@ import 'package:nextcloud/notifications.dart' as notifications;
class PushUtils {
const PushUtils._();
static Future<notifications.RSAKeypair> loadRSAKeypair() async {
static notifications.RSAKeypair loadRSAKeypair() {
const storage = AppStorage(StorageKeys.notifications);
const keyDevicePrivateKey = 'device-private-key';
late notifications.RSAKeypair keypair;
if (!storage.containsKey(keyDevicePrivateKey) || (storage.getString(keyDevicePrivateKey)?.isEmpty ?? true)) {
final notifications.RSAKeypair keypair;
if (!storage.containsKey(keyDevicePrivateKey) || (storage.getString(keyDevicePrivateKey)!.isEmpty)) {
debugPrint('Generating RSA keys for push notifications');
// The key size has to be 2048, other sizes are not accepted by Nextcloud (at the moment at least)
// ignore: avoid_redundant_argument_values
keypair = notifications.RSAKeypair.fromRandom(keySize: 2048);
await storage.setString(keyDevicePrivateKey, keypair.privateKey.toPEM());
unawaited(storage.setString(keyDevicePrivateKey, keypair.privateKey.toPEM()));
} else {
keypair = notifications.RSAKeypair(notifications.RSAPrivateKey.fromPEM(storage.getString(keyDevicePrivateKey)!));
}
@ -74,16 +75,10 @@ class PushUtils {
);
await NeonStorage.init();
final keypair = await loadRSAKeypair();
final keypair = loadRSAKeypair();
for (final message in Uri(query: utf8.decode(messages)).queryParameters.values) {
final data = json.decode(message) as Map<String, dynamic>;
final pushNotification = PushNotification(
accountID: instance,
priority: data['priority']! as String,
type: data['type']! as String,
subject: notifications.decryptPushNotificationSubject(keypair.privateKey, data['subject']! as String),
);
final pushNotification = PushNotification.fromEncrypted(data, keypair.privateKey);
if (pushNotification.subject.delete ?? false) {
await localNotificationsPlugin.cancel(_getNotificationID(instance, pushNotification));

Loading…
Cancel
Save