mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 10:38:41 +00:00
split signal functions into multiple files
This commit is contained in:
parent
9efdf26444
commit
2eb9fd2f00
11 changed files with 262 additions and 246 deletions
|
|
@ -21,14 +21,14 @@ import 'package:twonly/src/services/api/utils.dart';
|
|||
import 'package:twonly/src/services/api/media_received.dart';
|
||||
import 'package:twonly/src/services/api/media_send.dart';
|
||||
import 'package:twonly/src/services/api/server_messages.dart';
|
||||
import 'package:twonly/src/services/signal/identity.signal.dart';
|
||||
import 'package:twonly/src/services/signal/utils.signal.dart';
|
||||
import 'package:twonly/src/utils/hive.dart';
|
||||
import 'package:twonly/src/services/fcm.service.dart';
|
||||
import 'package:twonly/src/services/flame.service.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
// ignore: library_prefixes
|
||||
import 'package:twonly/src/utils/signal.dart' as SignalHelper;
|
||||
import 'package:web_socket_channel/io.dart';
|
||||
// ignore: implementation_imports
|
||||
import 'package:libsignal_protocol_dart/src/ecc/ed25519.dart';
|
||||
|
|
@ -306,7 +306,7 @@ class ApiService {
|
|||
|
||||
Future authenticate() async {
|
||||
if (isAuthenticated) return;
|
||||
if (await SignalHelper.getSignalIdentity() == null) {
|
||||
if (await getSignalIdentity() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -329,7 +329,7 @@ class ApiService {
|
|||
|
||||
final challenge = result.value.authchallenge;
|
||||
|
||||
final privKey = await SignalHelper.getPrivateKey();
|
||||
final privKey = await getSignalPrivateIdentityKey();
|
||||
if (privKey == null) return;
|
||||
final random = getRandomUint8List(32);
|
||||
final signature = sign(privKey.serialize(), challenge, random);
|
||||
|
|
@ -358,13 +358,12 @@ class ApiService {
|
|||
}
|
||||
|
||||
Future<Result> register(String username, String? inviteCode) async {
|
||||
final signalIdentity = await SignalHelper.getSignalIdentity();
|
||||
final signalIdentity = await getSignalIdentity();
|
||||
if (signalIdentity == null) {
|
||||
return Result.error(ErrorCode.InternalError);
|
||||
}
|
||||
|
||||
final signalStore =
|
||||
await SignalHelper.getSignalStoreFromIdentity(signalIdentity);
|
||||
final signalStore = await getSignalStoreFromIdentity(signalIdentity);
|
||||
|
||||
final signedPreKey = (await signalStore.loadSignedPreKeys())[0];
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,9 @@ import 'package:twonly/src/database/tables/messages_table.dart';
|
|||
import 'package:twonly/src/model/json/message.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/services/api/utils.dart';
|
||||
import 'package:twonly/src/services/signal/encryption.signal.dart';
|
||||
import 'package:twonly/src/utils/hive.dart';
|
||||
import 'package:twonly/src/services/notification.service.dart';
|
||||
// ignore: library_prefixes
|
||||
import 'package:twonly/src/utils/signal.dart' as SignalHelper;
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
|
||||
final lockSendingMessages = Mutex();
|
||||
|
|
@ -138,7 +137,7 @@ Future<(String, RetransmitMessage)?> encryptMessage(
|
|||
{PushKind? pushKind}) async {
|
||||
return await lockSendingMessages
|
||||
.protect<(String, RetransmitMessage)?>(() async {
|
||||
Uint8List? bytes = await SignalHelper.encryptMessage(msg, userId);
|
||||
Uint8List? bytes = await signalEncryptMessage(userId, msg);
|
||||
|
||||
if (bytes == null) {
|
||||
Logger("api.dart").shout("Error encryption message!");
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ import 'package:twonly/src/services/api/messages.dart';
|
|||
import 'package:twonly/src/services/api/utils.dart';
|
||||
import 'package:twonly/src/services/api/media_received.dart';
|
||||
import 'package:twonly/src/services/notification.service.dart';
|
||||
import 'package:twonly/src/services/signal/encryption.signal.dart';
|
||||
import 'package:twonly/src/services/signal/utils.signal.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
// ignore: library_prefixes
|
||||
import 'package:twonly/src/utils/signal.dart' as SignalHelper;
|
||||
|
||||
final lockHandleServerMessage = Mutex();
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ Future handleServerMessage(server.ServerToClient msg) async {
|
|||
}
|
||||
|
||||
Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
||||
MessageJson? message = await SignalHelper.getDecryptedText(fromUserId, body);
|
||||
MessageJson? message = await signalDecryptMessage(fromUserId, body);
|
||||
if (message == null) {
|
||||
Logger("server_messages")
|
||||
.info("Got invalid cipher text from $fromUserId. Deleting it.");
|
||||
|
|
@ -264,7 +264,7 @@ Future<client.Response> handleNewMessage(int fromUserId, Uint8List body) async {
|
|||
}
|
||||
|
||||
Future<client.Response> handleRequestNewPreKey() async {
|
||||
List<PreKeyRecord> localPreKeys = await SignalHelper.getPreKeys();
|
||||
List<PreKeyRecord> localPreKeys = await signalGetPreKeys();
|
||||
|
||||
List<client.Response_PreKey> prekeysList = [];
|
||||
for (int i = 0; i < localPreKeys.length; i++) {
|
||||
|
|
|
|||
64
lib/src/services/signal/encryption.signal.dart
Normal file
64
lib/src/services/signal/encryption.signal.dart
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:twonly/src/model/json/message.dart';
|
||||
import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart';
|
||||
import 'package:twonly/src/services/signal/utils.signal.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
|
||||
Future<Uint8List?> signalEncryptMessage(int target, MessageJson msg) async {
|
||||
try {
|
||||
ConnectSignalProtocolStore signalStore = (await getSignalStore())!;
|
||||
|
||||
SessionCipher session = SessionCipher.fromStore(
|
||||
signalStore, SignalProtocolAddress(target.toString(), defaultDeviceId));
|
||||
|
||||
final ciphertext = await session.encrypt(
|
||||
Uint8List.fromList(gzip.encode(utf8.encode(jsonEncode(msg.toJson())))));
|
||||
|
||||
var b = BytesBuilder();
|
||||
b.add(ciphertext.serialize());
|
||||
b.add(intToBytes(ciphertext.getType()));
|
||||
|
||||
return b.takeBytes();
|
||||
} catch (e) {
|
||||
Logger("utils/signal").shout(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<MessageJson?> signalDecryptMessage(int source, Uint8List msg) async {
|
||||
try {
|
||||
ConnectSignalProtocolStore signalStore = (await getSignalStore())!;
|
||||
|
||||
SessionCipher session = SessionCipher.fromStore(
|
||||
signalStore, SignalProtocolAddress(source.toString(), defaultDeviceId));
|
||||
|
||||
List<Uint8List>? msgs = removeLastXBytes(msg, 4);
|
||||
if (msgs == null) {
|
||||
Logger("utils/signal").shout("Message requires at least 4 bytes.");
|
||||
return null;
|
||||
}
|
||||
Uint8List body = msgs[0];
|
||||
int type = bytesToInt(msgs[1]);
|
||||
Uint8List plaintext;
|
||||
if (type == CiphertextMessage.prekeyType) {
|
||||
PreKeySignalMessage pre = PreKeySignalMessage(body);
|
||||
plaintext = await session.decrypt(pre);
|
||||
} else if (type == CiphertextMessage.whisperType) {
|
||||
SignalMessage signalMsg = SignalMessage.fromSerialized(body);
|
||||
plaintext = await session.decryptFromSignal(signalMsg);
|
||||
} else {
|
||||
Logger("utils/signal").shout("Type not known: $type");
|
||||
return null;
|
||||
}
|
||||
MessageJson dectext =
|
||||
MessageJson.fromJson(jsonDecode(utf8.decode(gzip.decode(plaintext))));
|
||||
return dectext;
|
||||
} catch (e) {
|
||||
Logger("utils/signal").shout(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
62
lib/src/services/signal/identity.signal.dart
Normal file
62
lib/src/services/signal/identity.signal.dart
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import 'dart:convert';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:twonly/src/model/json/signal_identity.dart';
|
||||
import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart';
|
||||
|
||||
const int defaultDeviceId = 1;
|
||||
|
||||
Future<ECPrivateKey?> getSignalPrivateIdentityKey() async {
|
||||
final signalIdentity = await getSignalIdentity();
|
||||
if (signalIdentity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final IdentityKeyPair identityKeyPair =
|
||||
IdentityKeyPair.fromSerialized(signalIdentity.identityKeyPairU8List);
|
||||
|
||||
return identityKeyPair.getPrivateKey();
|
||||
}
|
||||
|
||||
Future<SignalIdentity?> getSignalIdentity() async {
|
||||
try {
|
||||
final storage = FlutterSecureStorage();
|
||||
final signalIdentityJson = await storage.read(key: "signal_identity");
|
||||
if (signalIdentityJson == null) {
|
||||
return null;
|
||||
}
|
||||
return SignalIdentity.fromJson(jsonDecode(signalIdentityJson));
|
||||
} catch (e) {
|
||||
Logger("signal.dart/getSignalIdentity").shout(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future createIfNotExistsSignalIdentity() async {
|
||||
final storage = FlutterSecureStorage();
|
||||
|
||||
final signalIdentity = await storage.read(key: "signal_identity");
|
||||
if (signalIdentity != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final identityKeyPair = generateIdentityKeyPair();
|
||||
final registrationId = generateRegistrationId(true);
|
||||
|
||||
ConnectSignalProtocolStore signalStore =
|
||||
ConnectSignalProtocolStore(identityKeyPair, registrationId);
|
||||
|
||||
final signedPreKey = generateSignedPreKey(identityKeyPair, defaultDeviceId);
|
||||
|
||||
await signalStore.signedPreKeyStore
|
||||
.storeSignedPreKey(signedPreKey.id, signedPreKey);
|
||||
|
||||
final storedSignalIdentity = SignalIdentity(
|
||||
identityKeyPairU8List: identityKeyPair.serialize(),
|
||||
registrationId: registrationId,
|
||||
);
|
||||
|
||||
await storage.write(
|
||||
key: "signal_identity", value: jsonEncode(storedSignalIdentity));
|
||||
}
|
||||
92
lib/src/services/signal/session.signal.dart
Normal file
92
lib/src/services/signal/session.signal.dart
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import 'dart:typed_data';
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
|
||||
import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart';
|
||||
import 'package:twonly/src/services/signal/utils.signal.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
|
||||
const int defaultDeviceId = 1;
|
||||
|
||||
Future<bool> createNewSignalSession(Response_UserData userData) async {
|
||||
final int userId = userData.userId.toInt();
|
||||
|
||||
SignalProtocolAddress targetAddress =
|
||||
SignalProtocolAddress(userId.toString(), defaultDeviceId);
|
||||
|
||||
SignalProtocolStore? signalStore = await getSignalStore();
|
||||
if (signalStore == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SessionBuilder sessionBuilder =
|
||||
SessionBuilder.fromSignalStore(signalStore, targetAddress);
|
||||
|
||||
ECPublicKey? tempPrePublicKey;
|
||||
int? tempPreKeyId;
|
||||
if (userData.prekeys.isNotEmpty) {
|
||||
tempPrePublicKey = Curve.decodePoint(
|
||||
DjbECPublicKey(Uint8List.fromList(userData.prekeys.first.prekey))
|
||||
.serialize(),
|
||||
1);
|
||||
tempPreKeyId = userData.prekeys.first.id.toInt();
|
||||
}
|
||||
|
||||
int tempSignedPreKeyId = userData.signedPrekeyId.toInt();
|
||||
|
||||
ECPublicKey? tempSignedPreKeyPublic = Curve.decodePoint(
|
||||
DjbECPublicKey(Uint8List.fromList(userData.signedPrekey)).serialize(), 1);
|
||||
|
||||
Uint8List? tempSignedPreKeySignature =
|
||||
Uint8List.fromList(userData.signedPrekeySignature);
|
||||
|
||||
IdentityKey tempIdentityKey = IdentityKey(Curve.decodePoint(
|
||||
DjbECPublicKey(Uint8List.fromList(userData.publicIdentityKey))
|
||||
.serialize(),
|
||||
1));
|
||||
|
||||
PreKeyBundle preKeyBundle = PreKeyBundle(
|
||||
userData.userId.toInt(),
|
||||
1,
|
||||
tempPreKeyId,
|
||||
tempPrePublicKey,
|
||||
tempSignedPreKeyId,
|
||||
tempSignedPreKeyPublic,
|
||||
tempSignedPreKeySignature,
|
||||
tempIdentityKey,
|
||||
);
|
||||
|
||||
try {
|
||||
await sessionBuilder.processPreKeyBundle(preKeyBundle);
|
||||
return true;
|
||||
} catch (e) {
|
||||
Log.error("could not process pre key bundle: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Fingerprint?> generateSessionFingerPrint(int target) async {
|
||||
ConnectSignalProtocolStore? signalStore = await getSignalStore();
|
||||
UserData? user = await getUser();
|
||||
if (signalStore == null || user == null) return null;
|
||||
try {
|
||||
IdentityKey? targetIdentity = await signalStore
|
||||
.getIdentity(SignalProtocolAddress(target.toString(), defaultDeviceId));
|
||||
if (targetIdentity != null) {
|
||||
final generator = NumericFingerprintGenerator(5200);
|
||||
final localFingerprint = generator.createFor(
|
||||
1,
|
||||
Uint8List.fromList([user.userId.toInt()]),
|
||||
(await signalStore.getIdentityKeyPair()).getPublicKey(),
|
||||
Uint8List.fromList([target.toInt()]),
|
||||
targetIdentity,
|
||||
);
|
||||
|
||||
return localFingerprint;
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
29
lib/src/services/signal/utils.signal.dart
Normal file
29
lib/src/services/signal/utils.signal.dart
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
import 'package:twonly/src/model/json/signal_identity.dart';
|
||||
import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart';
|
||||
import 'package:twonly/src/services/signal/identity.signal.dart';
|
||||
|
||||
const int defaultDeviceId = 1;
|
||||
|
||||
Future<ConnectSignalProtocolStore?> getSignalStore() async {
|
||||
return await getSignalStoreFromIdentity((await getSignalIdentity())!);
|
||||
}
|
||||
|
||||
Future<ConnectSignalProtocolStore> getSignalStoreFromIdentity(
|
||||
SignalIdentity signalIdentity) async {
|
||||
final IdentityKeyPair identityKeyPair =
|
||||
IdentityKeyPair.fromSerialized(signalIdentity.identityKeyPairU8List);
|
||||
|
||||
return ConnectSignalProtocolStore(
|
||||
identityKeyPair, signalIdentity.registrationId.toInt());
|
||||
}
|
||||
|
||||
Future<List<PreKeyRecord>> signalGetPreKeys() async {
|
||||
final preKeys = generatePreKeys(0, 200);
|
||||
final signalStore = await getSignalStore();
|
||||
if (signalStore == null) return [];
|
||||
for (final p in preKeys) {
|
||||
await signalStore.preKeyStore.storePreKey(p.id, p);
|
||||
}
|
||||
return preKeys;
|
||||
}
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:twonly/src/model/json/message.dart';
|
||||
import 'package:twonly/src/model/json/signal_identity.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/model/protobuf/api/server_to_client.pb.dart';
|
||||
import 'package:twonly/src/database/signal/connect_signal_protocol_store.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
|
||||
const int defaultDeviceId = 1;
|
||||
|
||||
Future<ECPrivateKey?> getPrivateKey() async {
|
||||
final signalIdentity = await getSignalIdentity();
|
||||
if (signalIdentity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final IdentityKeyPair identityKeyPair =
|
||||
IdentityKeyPair.fromSerialized(signalIdentity.identityKeyPairU8List);
|
||||
|
||||
return identityKeyPair.getPrivateKey();
|
||||
}
|
||||
|
||||
Future<bool> addNewContact(Response_UserData userData) async {
|
||||
final int userId = userData.userId.toInt();
|
||||
|
||||
SignalProtocolAddress targetAddress =
|
||||
SignalProtocolAddress(userId.toString(), defaultDeviceId);
|
||||
|
||||
SignalProtocolStore? signalStore = await getSignalStore();
|
||||
if (signalStore == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SessionBuilder sessionBuilder =
|
||||
SessionBuilder.fromSignalStore(signalStore, targetAddress);
|
||||
|
||||
ECPublicKey? tempPrePublicKey;
|
||||
int? tempPreKeyId;
|
||||
if (userData.prekeys.isNotEmpty) {
|
||||
tempPrePublicKey = Curve.decodePoint(
|
||||
DjbECPublicKey(Uint8List.fromList(userData.prekeys.first.prekey))
|
||||
.serialize(),
|
||||
1);
|
||||
tempPreKeyId = userData.prekeys.first.id.toInt();
|
||||
}
|
||||
|
||||
int tempSignedPreKeyId = userData.signedPrekeyId.toInt();
|
||||
|
||||
ECPublicKey? tempSignedPreKeyPublic = Curve.decodePoint(
|
||||
DjbECPublicKey(Uint8List.fromList(userData.signedPrekey)).serialize(), 1);
|
||||
|
||||
Uint8List? tempSignedPreKeySignature =
|
||||
Uint8List.fromList(userData.signedPrekeySignature);
|
||||
|
||||
IdentityKey tempIdentityKey = IdentityKey(Curve.decodePoint(
|
||||
DjbECPublicKey(Uint8List.fromList(userData.publicIdentityKey))
|
||||
.serialize(),
|
||||
1));
|
||||
|
||||
PreKeyBundle preKeyBundle = PreKeyBundle(
|
||||
userData.userId.toInt(),
|
||||
1,
|
||||
tempPreKeyId,
|
||||
tempPrePublicKey,
|
||||
tempSignedPreKeyId,
|
||||
tempSignedPreKeyPublic,
|
||||
tempSignedPreKeySignature,
|
||||
tempIdentityKey,
|
||||
);
|
||||
|
||||
try {
|
||||
await sessionBuilder.processPreKeyBundle(preKeyBundle);
|
||||
return true;
|
||||
} catch (e) {
|
||||
Logger("signal_helper").shout("Error: $e");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<ConnectSignalProtocolStore?> getSignalStore() async {
|
||||
return await getSignalStoreFromIdentity((await getSignalIdentity())!);
|
||||
}
|
||||
|
||||
Future<SignalIdentity?> getSignalIdentity() async {
|
||||
try {
|
||||
final storage = FlutterSecureStorage();
|
||||
final signalIdentityJson = await storage.read(key: "signal_identity");
|
||||
if (signalIdentityJson == null) {
|
||||
return null;
|
||||
}
|
||||
return SignalIdentity.fromJson(jsonDecode(signalIdentityJson));
|
||||
} catch (e) {
|
||||
Logger("signal.dart/getSignalIdentity").shout(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<ConnectSignalProtocolStore> getSignalStoreFromIdentity(
|
||||
SignalIdentity signalIdentity) async {
|
||||
final IdentityKeyPair identityKeyPair =
|
||||
IdentityKeyPair.fromSerialized(signalIdentity.identityKeyPairU8List);
|
||||
|
||||
return ConnectSignalProtocolStore(
|
||||
identityKeyPair, signalIdentity.registrationId.toInt());
|
||||
}
|
||||
|
||||
Future<List<PreKeyRecord>> getPreKeys() async {
|
||||
final preKeys = generatePreKeys(0, 200);
|
||||
final signalStore = await getSignalStore();
|
||||
if (signalStore == null) return [];
|
||||
for (final p in preKeys) {
|
||||
await signalStore.preKeyStore.storePreKey(p.id, p);
|
||||
}
|
||||
return preKeys;
|
||||
}
|
||||
|
||||
Future createIfNotExistsSignalIdentity() async {
|
||||
final storage = FlutterSecureStorage();
|
||||
|
||||
final signalIdentity = await storage.read(key: "signal_identity");
|
||||
if (signalIdentity != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final identityKeyPair = generateIdentityKeyPair();
|
||||
final registrationId = generateRegistrationId(true);
|
||||
|
||||
ConnectSignalProtocolStore signalStore =
|
||||
ConnectSignalProtocolStore(identityKeyPair, registrationId);
|
||||
|
||||
final signedPreKey = generateSignedPreKey(identityKeyPair, defaultDeviceId);
|
||||
|
||||
await signalStore.signedPreKeyStore
|
||||
.storeSignedPreKey(signedPreKey.id, signedPreKey);
|
||||
|
||||
final storedSignalIdentity = SignalIdentity(
|
||||
identityKeyPairU8List: identityKeyPair.serialize(),
|
||||
registrationId: registrationId,
|
||||
);
|
||||
|
||||
await storage.write(
|
||||
key: "signal_identity", value: jsonEncode(storedSignalIdentity));
|
||||
}
|
||||
|
||||
Future<Fingerprint?> generateSessionFingerPrint(int target) async {
|
||||
ConnectSignalProtocolStore? signalStore = await getSignalStore();
|
||||
UserData? user = await getUser();
|
||||
if (signalStore == null || user == null) return null;
|
||||
try {
|
||||
IdentityKey? targetIdentity = await signalStore
|
||||
.getIdentity(SignalProtocolAddress(target.toString(), defaultDeviceId));
|
||||
if (targetIdentity != null) {
|
||||
final generator = NumericFingerprintGenerator(5200);
|
||||
final localFingerprint = generator.createFor(
|
||||
1,
|
||||
Uint8List.fromList([user.userId.toInt()]),
|
||||
(await signalStore.getIdentityKeyPair()).getPublicKey(),
|
||||
Uint8List.fromList([target.toInt()]),
|
||||
targetIdentity,
|
||||
);
|
||||
|
||||
return localFingerprint;
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uint8List?> encryptMessage(MessageJson msg, int target) async {
|
||||
try {
|
||||
ConnectSignalProtocolStore signalStore = (await getSignalStore())!;
|
||||
|
||||
SessionCipher session = SessionCipher.fromStore(
|
||||
signalStore, SignalProtocolAddress(target.toString(), defaultDeviceId));
|
||||
|
||||
final ciphertext = await session.encrypt(
|
||||
Uint8List.fromList(gzip.encode(utf8.encode(jsonEncode(msg.toJson())))));
|
||||
|
||||
var b = BytesBuilder();
|
||||
b.add(ciphertext.serialize());
|
||||
b.add(intToBytes(ciphertext.getType()));
|
||||
|
||||
return b.takeBytes();
|
||||
} catch (e) {
|
||||
Logger("utils/signal").shout(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<MessageJson?> getDecryptedText(int source, Uint8List msg) async {
|
||||
try {
|
||||
ConnectSignalProtocolStore signalStore = (await getSignalStore())!;
|
||||
|
||||
SessionCipher session = SessionCipher.fromStore(
|
||||
signalStore, SignalProtocolAddress(source.toString(), defaultDeviceId));
|
||||
|
||||
List<Uint8List>? msgs = removeLastXBytes(msg, 4);
|
||||
if (msgs == null) {
|
||||
Logger("utils/signal").shout("Message requires at least 4 bytes.");
|
||||
return null;
|
||||
}
|
||||
Uint8List body = msgs[0];
|
||||
int type = bytesToInt(msgs[1]);
|
||||
Uint8List plaintext;
|
||||
if (type == CiphertextMessage.prekeyType) {
|
||||
PreKeySignalMessage pre = PreKeySignalMessage(body);
|
||||
plaintext = await session.decrypt(pre);
|
||||
} else if (type == CiphertextMessage.whisperType) {
|
||||
SignalMessage signalMsg = SignalMessage.fromSerialized(body);
|
||||
plaintext = await session.decryptFromSignal(signalMsg);
|
||||
} else {
|
||||
Logger("utils/signal").shout("Type not known: $type");
|
||||
return null;
|
||||
}
|
||||
MessageJson dectext =
|
||||
MessageJson.fromJson(jsonDecode(utf8.decode(gzip.decode(plaintext))));
|
||||
return dectext;
|
||||
} catch (e) {
|
||||
Logger("utils/signal").shout(e.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ import 'package:twonly/src/views/components/initialsavatar.dart';
|
|||
import 'package:twonly/src/model/json/message.dart';
|
||||
import 'package:twonly/src/services/api/messages.dart';
|
||||
// ignore: library_prefixes
|
||||
import 'package:twonly/src/utils/signal.dart' as SignalHelper;
|
||||
import 'package:twonly/src/services/signal/utils.signal.dart' as SignalHelper;
|
||||
import 'package:twonly/src/utils/storage.dart';
|
||||
import 'package:twonly/src/views/settings/subscription/subscription_view.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:twonly/src/database/daos/contacts_dao.dart';
|
||||
import 'package:twonly/src/database/twonly_database.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/signal.dart';
|
||||
import 'package:twonly/src/services/signal/utils.signal.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class ContactVerifyView extends StatefulWidget {
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ import 'package:logging/logging.dart';
|
|||
import 'package:twonly/globals.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:twonly/src/services/signal/identity.signal.dart';
|
||||
import 'package:twonly/src/views/components/alert_dialog.dart';
|
||||
import 'package:twonly/src/model/json/userdata.dart';
|
||||
import 'package:twonly/src/utils/misc.dart';
|
||||
import 'package:twonly/src/utils/signal.dart';
|
||||
|
||||
class RegisterView extends StatefulWidget {
|
||||
const RegisterView({super.key, required this.callbackOnSuccess});
|
||||
|
|
|
|||
Loading…
Reference in a new issue