requestify cross-signing endpoints
This commit is contained in:
parent
e1679d59be
commit
b4e83caa89
|
@ -117,34 +117,23 @@ class CrossSigning {
|
|||
Future<void> sign(List<SignableKey> keys) async {
|
||||
Uint8List selfSigningKey;
|
||||
Uint8List userSigningKey;
|
||||
final signatures = <String, dynamic>{};
|
||||
var signedKey = false;
|
||||
final signedKeys = <MatrixSignableKey>[];
|
||||
final addSignature =
|
||||
(SignableKey key, SignableKey signedWith, String signature) {
|
||||
if (key == null || signedWith == null || signature == null) {
|
||||
return;
|
||||
}
|
||||
if (!signatures.containsKey(key.userId)) {
|
||||
signatures[key.userId] = <String, dynamic>{};
|
||||
final signedKey = signedKeys.firstWhere(
|
||||
(k) => k.userId == key.userId && k.identifier == key.identifier,
|
||||
orElse: () => null) ??
|
||||
key.cloneForSigning();
|
||||
signedKey.signatures ??= <String, Map<String, String>>{};
|
||||
if (!signedKey.signatures.containsKey(signedWith.userId)) {
|
||||
signedKey.signatures[signedWith.userId] = <String, String>{};
|
||||
}
|
||||
if (!signatures[key.userId].containsKey(key.identifier)) {
|
||||
signatures[key.userId][key.identifier] =
|
||||
Map<String, dynamic>.from(key.toJson());
|
||||
// we don't need to send all old signatures, so let's just remove them
|
||||
signatures[key.userId][key.identifier].remove('signatures');
|
||||
}
|
||||
if (!signatures[key.userId][key.identifier].containsKey('signatures')) {
|
||||
signatures[key.userId][key.identifier]
|
||||
['signatures'] = <String, dynamic>{};
|
||||
}
|
||||
if (!signatures[key.userId][key.identifier]['signatures']
|
||||
.containsKey(signedWith.userId)) {
|
||||
signatures[key.userId][key.identifier]['signatures']
|
||||
[signedWith.userId] = <String, dynamic>{};
|
||||
}
|
||||
signatures[key.userId][key.identifier]['signatures'][signedWith.userId]
|
||||
signedKey.signatures[signedWith.userId]
|
||||
['ed25519:${signedWith.identifier}'] = signature;
|
||||
signedKey = true;
|
||||
signedKeys.add(signedKey);
|
||||
};
|
||||
for (final key in keys) {
|
||||
if (key.userId == client.userID) {
|
||||
|
@ -182,13 +171,9 @@ class CrossSigning {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (signedKey) {
|
||||
if (signedKeys.isNotEmpty) {
|
||||
// post our new keys!
|
||||
await client.jsonRequest(
|
||||
type: RequestType.POST,
|
||||
action: '/client/r0/keys/signatures/upload',
|
||||
data: signatures,
|
||||
);
|
||||
await client.api.uploadKeySignatures(signedKeys);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ export 'package:famedlysdk/matrix_api/model/third_party_location.dart';
|
|||
export 'package:famedlysdk/matrix_api/model/third_party_user.dart';
|
||||
export 'package:famedlysdk/matrix_api/model/timeline_history_response.dart';
|
||||
export 'package:famedlysdk/matrix_api/model/turn_server_credentials.dart';
|
||||
export 'package:famedlysdk/matrix_api/model/upload_key_signatures_response.dart';
|
||||
export 'package:famedlysdk/matrix_api/model/user_search_result.dart';
|
||||
export 'package:famedlysdk/matrix_api/model/well_known_informations.dart';
|
||||
export 'package:famedlysdk/matrix_api/model/who_is_info.dart';
|
||||
|
|
|
@ -54,6 +54,7 @@ import 'model/tag.dart';
|
|||
import 'model/third_party_identifier.dart';
|
||||
import 'model/third_party_user.dart';
|
||||
import 'model/turn_server_credentials.dart';
|
||||
import 'model/upload_key_signatures_response.dart';
|
||||
import 'model/well_known_informations.dart';
|
||||
import 'model/who_is_info.dart';
|
||||
|
||||
|
@ -1503,6 +1504,55 @@ class MatrixApi {
|
|||
return DeviceListsUpdate.fromJson(response);
|
||||
}
|
||||
|
||||
/// Uploads your own cross-signing keys.
|
||||
/// https://12682-24998719-gh.circle-artifacts.com/0/scripts/gen/client_server/unstable.html#post-matrix-client-r0-keys-device-signing-upload
|
||||
Future<void> uploadDeviceSigningKeys({
|
||||
MatrixCrossSigningKey masterKey,
|
||||
MatrixCrossSigningKey selfSigningKey,
|
||||
MatrixCrossSigningKey userSigningKey,
|
||||
}) async {
|
||||
await request(
|
||||
RequestType.POST,
|
||||
'/client/r0/keys/device_signing/upload',
|
||||
data: {
|
||||
'master_key': masterKey.toJson(),
|
||||
'self_signing_key': selfSigningKey.toJson(),
|
||||
'user_signing_key': userSigningKey.toJson(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Uploads new signatures of keys
|
||||
/// https://12682-24998719-gh.circle-artifacts.com/0/scripts/gen/client_server/unstable.html#post-matrix-client-r0-keys-signatures-upload
|
||||
Future<UploadKeySignaturesResponse> uploadKeySignatures(
|
||||
List<MatrixSignableKey> keys) async {
|
||||
final payload = <String, dynamic>{};
|
||||
for (final key in keys) {
|
||||
if (key.identifier == null ||
|
||||
key.signatures == null ||
|
||||
key.signatures.isEmpty) {
|
||||
continue;
|
||||
}
|
||||
if (!payload.containsKey(key.userId)) {
|
||||
payload[key.userId] = <String, dynamic>{};
|
||||
}
|
||||
if (payload[key.userId].containsKey(key.identifier)) {
|
||||
// we need to merge signature objects
|
||||
payload[key.userId][key.identifier]['signatures']
|
||||
.addAll(key.signatures);
|
||||
} else {
|
||||
// we can just add signatures
|
||||
payload[key.userId][key.identifier] = key.toJson();
|
||||
}
|
||||
}
|
||||
final response = await request(
|
||||
RequestType.POST,
|
||||
'/client/r0/keys/signatures/upload',
|
||||
data: payload,
|
||||
);
|
||||
return UploadKeySignaturesResponse.fromJson(response);
|
||||
}
|
||||
|
||||
/// Gets all currently active pushers for the authenticated user.
|
||||
/// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushers
|
||||
Future<List<Pusher>> requestPushers() async {
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
|
||||
class MatrixSignableKey {
|
||||
String userId;
|
||||
String identifier;
|
||||
Map<String, String> keys;
|
||||
Map<String, Map<String, String>> signatures;
|
||||
Map<String, dynamic> unsigned;
|
||||
|
||||
MatrixSignableKey(this.userId, this.keys, this.signatures, {this.unsigned});
|
||||
MatrixSignableKey(this.userId, this.identifier, this.keys, this.signatures,
|
||||
{this.unsigned});
|
||||
|
||||
// This object is used for signing so we need the raw json too
|
||||
Map<String, dynamic> _json;
|
||||
|
@ -31,9 +33,10 @@ class MatrixSignableKey {
|
|||
_json = json;
|
||||
userId = json['user_id'];
|
||||
keys = Map<String, String>.from(json['keys']);
|
||||
signatures = json['signatures'] is Map ? Map<String, Map<String, String>>.from(
|
||||
(json['signatures'] as Map)
|
||||
.map((k, v) => MapEntry(k, Map<String, String>.from(v)))) : null;
|
||||
signatures = json['signatures'] is Map
|
||||
? Map<String, Map<String, String>>.from((json['signatures'] as Map)
|
||||
.map((k, v) => MapEntry(k, Map<String, String>.from(v))))
|
||||
: null;
|
||||
unsigned = json['unsigned'] is Map
|
||||
? Map<String, dynamic>.from(json['unsigned'])
|
||||
: null;
|
||||
|
@ -56,7 +59,7 @@ class MatrixSignableKey {
|
|||
|
||||
class MatrixCrossSigningKey extends MatrixSignableKey {
|
||||
List<String> usage;
|
||||
String get publicKey => keys?.values?.first;
|
||||
String get publicKey => identifier;
|
||||
|
||||
MatrixCrossSigningKey(
|
||||
String userId,
|
||||
|
@ -64,12 +67,13 @@ class MatrixCrossSigningKey extends MatrixSignableKey {
|
|||
Map<String, String> keys,
|
||||
Map<String, Map<String, String>> signatures, {
|
||||
Map<String, dynamic> unsigned,
|
||||
}) : super(userId, keys, signatures, unsigned: unsigned);
|
||||
}) : super(userId, keys?.values?.first, keys, signatures, unsigned: unsigned);
|
||||
|
||||
@override
|
||||
MatrixCrossSigningKey.fromJson(Map<String, dynamic> json)
|
||||
: super.fromJson(json) {
|
||||
usage = List<String>.from(json['usage']);
|
||||
identifier = keys?.values?.first;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -81,23 +85,23 @@ class MatrixCrossSigningKey extends MatrixSignableKey {
|
|||
}
|
||||
|
||||
class MatrixDeviceKeys extends MatrixSignableKey {
|
||||
String deviceId;
|
||||
String get deviceId => identifier;
|
||||
List<String> algorithms;
|
||||
String get deviceDisplayName =>
|
||||
unsigned != null ? unsigned['device_display_name'] : null;
|
||||
|
||||
MatrixDeviceKeys(
|
||||
String userId,
|
||||
this.deviceId,
|
||||
String deviceId,
|
||||
this.algorithms,
|
||||
Map<String, String> keys,
|
||||
Map<String, Map<String, String>> signatures, {
|
||||
Map<String, dynamic> unsigned,
|
||||
}) : super(userId, keys, signatures, unsigned: unsigned);
|
||||
}) : super(userId, deviceId, keys, signatures, unsigned: unsigned);
|
||||
|
||||
@override
|
||||
MatrixDeviceKeys.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
|
||||
deviceId = json['device_id'];
|
||||
identifier = json['device_id'];
|
||||
algorithms = json['algorithms'].cast<String>();
|
||||
}
|
||||
|
||||
|
|
55
lib/matrix_api/model/upload_key_signatures_response.dart
Normal file
55
lib/matrix_api/model/upload_key_signatures_response.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Famedly Matrix SDK
|
||||
* Copyright (C) 2020 Famedly GmbH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import 'matrix_exception.dart';
|
||||
|
||||
class UploadKeySignaturesResponse {
|
||||
Map<String, Map<String, MatrixException>> failures;
|
||||
|
||||
UploadKeySignaturesResponse.fromJson(Map<String, dynamic> json) {
|
||||
failures = json['failures'] != null
|
||||
? (json['failures'] as Map).map(
|
||||
(k, v) => MapEntry(
|
||||
k,
|
||||
(v as Map).map((k, v) => MapEntry(
|
||||
k,
|
||||
MatrixException.fromJson(v),
|
||||
)),
|
||||
),
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final data = <String, dynamic>{};
|
||||
if (failures != null) {
|
||||
data['failures'] = failures.map(
|
||||
(k, v) => MapEntry(
|
||||
k,
|
||||
v.map(
|
||||
(k, v) => MapEntry(
|
||||
k,
|
||||
v.raw,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -100,7 +100,6 @@ class DeviceKeysList {
|
|||
|
||||
abstract class SignableKey extends MatrixSignableKey {
|
||||
Client client;
|
||||
String identifier;
|
||||
Map<String, dynamic> validSignatures;
|
||||
bool _verified;
|
||||
bool blocked;
|
||||
|
@ -123,6 +122,13 @@ abstract class SignableKey extends MatrixSignableKey {
|
|||
blocked = false;
|
||||
}
|
||||
|
||||
MatrixSignableKey cloneForSigning() {
|
||||
final newKey =
|
||||
MatrixSignableKey.fromJson(Map<String, dynamic>.from(toJson()));
|
||||
newKey.signatures.clear();
|
||||
return newKey;
|
||||
}
|
||||
|
||||
String get signingContent {
|
||||
final data = Map<String, dynamic>.from(super.toJson());
|
||||
// some old data might have the custom verified and blocked keys
|
||||
|
|
Loading…
Reference in a new issue