send method
Future<void>
send(
- MessagePayloadModel payload, {
- required List<
String> recipients, - List<
File> files = const [],
Implementation
Future<void> send(
MessagePayloadModel payload, {
required List<String> recipients,
List<File> files = const [],
}) async {
final currentPeer = await _db.peers.current.get();
if (currentPeer == null) {
throw StateError('Missing current peer');
}
final secretKey = await _encryption.createSecretKey();
final secretKeyBytes = await secretKey.extractBytes();
final encryptedPayload = await _encryption.encryptSecret(
secretKey,
jsonEncode(payload.toJson()),
);
final requestedPeerKeys = {...recipients, currentPeer.key};
final knownPeers = await _db.peers.ids(requestedPeerKeys.toList()).get();
final revokedPeerKeys = knownPeers
.where((peer) => peer.isRevoked)
.map((peer) => peer.key)
.toSet();
final peerKeys = requestedPeerKeys
.where((peerKey) => !revokedPeerKeys.contains(peerKey))
.toList();
final devices = await _db.devices.peers(peerKeys).get();
final activeDevices = devices.where((device) => !device.isRevoked);
final recipientKeys = activeDevices.map((d) => d.signingKey).toList();
final keyIndex = {
for (final d in activeDevices) d.signingKey: d.encryptionKey,
};
final secretKeyIndex = <String, String>{};
for (final recipientKey in recipientKeys) {
final encryptionKey = keyIndex[recipientKey];
if (encryptionKey == null) {
_logger.log('Missing device encryption key for $recipientKey');
continue;
}
secretKeyIndex[recipientKey] = base64Encode(
await _encryption.encryptSharedSecret(secretKeyBytes, encryptionKey),
);
}
final attachments = <NetworkMediaModel>[];
for (final file in files) {
final bytes = await file.readAsBytes();
final encryptedBytes = await _encryption.encryptSecretBytes(
secretKey,
bytes,
);
final hash = sha256.convert(encryptedBytes).toString();
await MediaStorage.instance.put(hash, Uint8List.fromList(encryptedBytes));
attachments.add(
NetworkMediaModel(
hash: hash,
mime: detectMimeType(file.path, headerBytes: bytes),
size: encryptedBytes.length,
name: file.uri.pathSegments.last,
),
);
}
final body = MessageEventBodyModel(
peers: peerKeys,
keys: secretKeyIndex,
payload: encryptedPayload,
encryptionKey: Encryption.instance.publicKey,
attachments: attachments,
);
final event = await _client.events.publish(body);
final onlineDevices = await _db.devices.online.get();
await Future.wait(
onlineDevices
.where((device) => peerKeys.contains(device.peerKey))
.map(
(device) => _client.events.relayDevice(device.signingKey, event),
),
);
await _createReceipt(event, MessageReceiptStatus.sent);
}