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 {
|
Future<void> sign(List<SignableKey> keys) async {
|
||||||
Uint8List selfSigningKey;
|
Uint8List selfSigningKey;
|
||||||
Uint8List userSigningKey;
|
Uint8List userSigningKey;
|
||||||
final signatures = <String, dynamic>{};
|
final signedKeys = <MatrixSignableKey>[];
|
||||||
var signedKey = false;
|
|
||||||
final addSignature =
|
final addSignature =
|
||||||
(SignableKey key, SignableKey signedWith, String signature) {
|
(SignableKey key, SignableKey signedWith, String signature) {
|
||||||
if (key == null || signedWith == null || signature == null) {
|
if (key == null || signedWith == null || signature == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!signatures.containsKey(key.userId)) {
|
final signedKey = signedKeys.firstWhere(
|
||||||
signatures[key.userId] = <String, dynamic>{};
|
(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)) {
|
signedKey.signatures[signedWith.userId]
|
||||||
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]
|
|
||||||
['ed25519:${signedWith.identifier}'] = signature;
|
['ed25519:${signedWith.identifier}'] = signature;
|
||||||
signedKey = true;
|
signedKeys.add(signedKey);
|
||||||
};
|
};
|
||||||
for (final key in keys) {
|
for (final key in keys) {
|
||||||
if (key.userId == client.userID) {
|
if (key.userId == client.userID) {
|
||||||
|
@ -182,13 +171,9 @@ class CrossSigning {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (signedKey) {
|
if (signedKeys.isNotEmpty) {
|
||||||
// post our new keys!
|
// post our new keys!
|
||||||
await client.jsonRequest(
|
await client.api.uploadKeySignatures(signedKeys);
|
||||||
type: RequestType.POST,
|
|
||||||
action: '/client/r0/keys/signatures/upload',
|
|
||||||
data: signatures,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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/third_party_user.dart';
|
||||||
export 'package:famedlysdk/matrix_api/model/timeline_history_response.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/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/user_search_result.dart';
|
||||||
export 'package:famedlysdk/matrix_api/model/well_known_informations.dart';
|
export 'package:famedlysdk/matrix_api/model/well_known_informations.dart';
|
||||||
export 'package:famedlysdk/matrix_api/model/who_is_info.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_identifier.dart';
|
||||||
import 'model/third_party_user.dart';
|
import 'model/third_party_user.dart';
|
||||||
import 'model/turn_server_credentials.dart';
|
import 'model/turn_server_credentials.dart';
|
||||||
|
import 'model/upload_key_signatures_response.dart';
|
||||||
import 'model/well_known_informations.dart';
|
import 'model/well_known_informations.dart';
|
||||||
import 'model/who_is_info.dart';
|
import 'model/who_is_info.dart';
|
||||||
|
|
||||||
|
@ -1503,6 +1504,55 @@ class MatrixApi {
|
||||||
return DeviceListsUpdate.fromJson(response);
|
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.
|
/// Gets all currently active pushers for the authenticated user.
|
||||||
/// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushers
|
/// https://matrix.org/docs/spec/client_server/r0.6.1#get-matrix-client-r0-pushers
|
||||||
Future<List<Pusher>> requestPushers() async {
|
Future<List<Pusher>> requestPushers() async {
|
||||||
|
|
|
@ -18,11 +18,13 @@
|
||||||
|
|
||||||
class MatrixSignableKey {
|
class MatrixSignableKey {
|
||||||
String userId;
|
String userId;
|
||||||
|
String identifier;
|
||||||
Map<String, String> keys;
|
Map<String, String> keys;
|
||||||
Map<String, Map<String, String>> signatures;
|
Map<String, Map<String, String>> signatures;
|
||||||
Map<String, dynamic> unsigned;
|
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
|
// This object is used for signing so we need the raw json too
|
||||||
Map<String, dynamic> _json;
|
Map<String, dynamic> _json;
|
||||||
|
@ -31,9 +33,10 @@ class MatrixSignableKey {
|
||||||
_json = json;
|
_json = json;
|
||||||
userId = json['user_id'];
|
userId = json['user_id'];
|
||||||
keys = Map<String, String>.from(json['keys']);
|
keys = Map<String, String>.from(json['keys']);
|
||||||
signatures = json['signatures'] is Map ? Map<String, Map<String, String>>.from(
|
signatures = json['signatures'] is Map
|
||||||
(json['signatures'] as Map)
|
? Map<String, Map<String, String>>.from((json['signatures'] as Map)
|
||||||
.map((k, v) => MapEntry(k, Map<String, String>.from(v)))) : null;
|
.map((k, v) => MapEntry(k, Map<String, String>.from(v))))
|
||||||
|
: null;
|
||||||
unsigned = json['unsigned'] is Map
|
unsigned = json['unsigned'] is Map
|
||||||
? Map<String, dynamic>.from(json['unsigned'])
|
? Map<String, dynamic>.from(json['unsigned'])
|
||||||
: null;
|
: null;
|
||||||
|
@ -56,7 +59,7 @@ class MatrixSignableKey {
|
||||||
|
|
||||||
class MatrixCrossSigningKey extends MatrixSignableKey {
|
class MatrixCrossSigningKey extends MatrixSignableKey {
|
||||||
List<String> usage;
|
List<String> usage;
|
||||||
String get publicKey => keys?.values?.first;
|
String get publicKey => identifier;
|
||||||
|
|
||||||
MatrixCrossSigningKey(
|
MatrixCrossSigningKey(
|
||||||
String userId,
|
String userId,
|
||||||
|
@ -64,12 +67,13 @@ class MatrixCrossSigningKey extends MatrixSignableKey {
|
||||||
Map<String, String> keys,
|
Map<String, String> keys,
|
||||||
Map<String, Map<String, String>> signatures, {
|
Map<String, Map<String, String>> signatures, {
|
||||||
Map<String, dynamic> unsigned,
|
Map<String, dynamic> unsigned,
|
||||||
}) : super(userId, keys, signatures, unsigned: unsigned);
|
}) : super(userId, keys?.values?.first, keys, signatures, unsigned: unsigned);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MatrixCrossSigningKey.fromJson(Map<String, dynamic> json)
|
MatrixCrossSigningKey.fromJson(Map<String, dynamic> json)
|
||||||
: super.fromJson(json) {
|
: super.fromJson(json) {
|
||||||
usage = List<String>.from(json['usage']);
|
usage = List<String>.from(json['usage']);
|
||||||
|
identifier = keys?.values?.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -81,23 +85,23 @@ class MatrixCrossSigningKey extends MatrixSignableKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MatrixDeviceKeys extends MatrixSignableKey {
|
class MatrixDeviceKeys extends MatrixSignableKey {
|
||||||
String deviceId;
|
String get deviceId => identifier;
|
||||||
List<String> algorithms;
|
List<String> algorithms;
|
||||||
String get deviceDisplayName =>
|
String get deviceDisplayName =>
|
||||||
unsigned != null ? unsigned['device_display_name'] : null;
|
unsigned != null ? unsigned['device_display_name'] : null;
|
||||||
|
|
||||||
MatrixDeviceKeys(
|
MatrixDeviceKeys(
|
||||||
String userId,
|
String userId,
|
||||||
this.deviceId,
|
String deviceId,
|
||||||
this.algorithms,
|
this.algorithms,
|
||||||
Map<String, String> keys,
|
Map<String, String> keys,
|
||||||
Map<String, Map<String, String>> signatures, {
|
Map<String, Map<String, String>> signatures, {
|
||||||
Map<String, dynamic> unsigned,
|
Map<String, dynamic> unsigned,
|
||||||
}) : super(userId, keys, signatures, unsigned: unsigned);
|
}) : super(userId, deviceId, keys, signatures, unsigned: unsigned);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
MatrixDeviceKeys.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
|
MatrixDeviceKeys.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
|
||||||
deviceId = json['device_id'];
|
identifier = json['device_id'];
|
||||||
algorithms = json['algorithms'].cast<String>();
|
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 {
|
abstract class SignableKey extends MatrixSignableKey {
|
||||||
Client client;
|
Client client;
|
||||||
String identifier;
|
|
||||||
Map<String, dynamic> validSignatures;
|
Map<String, dynamic> validSignatures;
|
||||||
bool _verified;
|
bool _verified;
|
||||||
bool blocked;
|
bool blocked;
|
||||||
|
@ -123,6 +122,13 @@ abstract class SignableKey extends MatrixSignableKey {
|
||||||
blocked = false;
|
blocked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MatrixSignableKey cloneForSigning() {
|
||||||
|
final newKey =
|
||||||
|
MatrixSignableKey.fromJson(Map<String, dynamic>.from(toJson()));
|
||||||
|
newKey.signatures.clear();
|
||||||
|
return newKey;
|
||||||
|
}
|
||||||
|
|
||||||
String get signingContent {
|
String get signingContent {
|
||||||
final data = Map<String, dynamic>.from(super.toJson());
|
final data = Map<String, dynamic>.from(super.toJson());
|
||||||
// some old data might have the custom verified and blocked keys
|
// some old data might have the custom verified and blocked keys
|
||||||
|
|
Loading…
Reference in a new issue