Compare commits
13 Commits
5bec3b4587
...
v0.1.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 44ab31aebb | |||
| e4f1d7d4b0 | |||
| 7600804aa1 | |||
| a4589b6e09 | |||
| d0986a4608 | |||
| 683a76cc80 | |||
| dad707f71d | |||
| 419be8af4d | |||
| fafc4f2320 | |||
| fc842fe000 | |||
| e3de50e0c7 | |||
| 234c2088b9 | |||
| ad3f1d4579 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,3 +12,6 @@ pubspec.lock
|
||||
# NixOS
|
||||
.direnv
|
||||
.envrc
|
||||
|
||||
# Protobuf build artifacts
|
||||
lib/protobuf/*.dart
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,3 +1,11 @@
|
||||
## 1.0.0
|
||||
## 0.1.0
|
||||
|
||||
- Initial version.
|
||||
- Initial version
|
||||
- Implement the Double Ratchet, X3DH and OMEMO specific bits
|
||||
- Add a Blind-Trust-Before-Verification TrustManager
|
||||
- Supported OMEMO version: 0.8.3
|
||||
|
||||
## 0.1.3
|
||||
|
||||
- Fix bug with the Double Ratchet causing only the initial message to be decryptable
|
||||
- Expose `getDeviceMap` as a developer usable function
|
||||
|
||||
23
README.md
23
README.md
@@ -18,11 +18,32 @@ the stanza format of your preferred XMPP library yourself.
|
||||
- **Please note that this library has not been audited for its security! Use at your own risk!**
|
||||
- This library is not tested with other implementations of OMEMO 0.8.3 as I do not know of any client implementing spec compliant OMEMO 0.8.3. It does, however, work with itself.
|
||||
|
||||
## Usage
|
||||
|
||||
Include `omemo_dart` in your `pubspec.yaml` like this:
|
||||
|
||||
```yaml
|
||||
# [...]
|
||||
|
||||
dependencies:
|
||||
omemo_dart:
|
||||
hosted: https://git.polynom.me/api/packages/PapaTutuWawa/pub
|
||||
version: ^0.1.0
|
||||
# [...]
|
||||
|
||||
# [...]
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Due to issues with `protobuf`, `omemo_dart` reimplements the Protobuf encoding for the required
|
||||
OMEMO messages. As such, `protobuf` is only a dependency for testing that the serialisation and
|
||||
deserialisation of the custom implementation.
|
||||
deserialisation of the custom implementation. In order to run tests, you need the Protbuf
|
||||
compiler. After that, making sure that
|
||||
the [Dart Protobuf compiler addon](https://pub.dev/packages/protoc_plugin) and the
|
||||
Protobuf compiler itself is in your PATH,
|
||||
run `protoc -I=./protobuf/ --dart_out=lib/protobuf/ ./protobuf/schema.proto` in the
|
||||
repository's root to generate the real Protobuf bindings.
|
||||
|
||||
When submitting a PR, please run the linter using `dart analyze` and make sure that all
|
||||
tests still pass using `dart test`.
|
||||
|
||||
0
lib/protobuf/.gitkeep
Normal file
0
lib/protobuf/.gitkeep
Normal file
@@ -1,263 +0,0 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: schema.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,constant_identifier_names,directives_ordering,library_prefixes,non_constant_identifier_names,prefer_final_fields,return_of_invalid_type,unnecessary_const,unnecessary_import,unnecessary_this,unused_import,unused_shown_name
|
||||
|
||||
import 'dart:core' as $core;
|
||||
|
||||
import 'package:protobuf/protobuf.dart' as $pb;
|
||||
|
||||
class OMEMOMessage extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'OMEMOMessage', createEmptyInstance: create)
|
||||
..a<$core.int>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'n', $pb.PbFieldType.QU3)
|
||||
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pn', $pb.PbFieldType.QU3)
|
||||
..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'dhPub', $pb.PbFieldType.QY)
|
||||
..a<$core.List<$core.int>>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ciphertext', $pb.PbFieldType.OY)
|
||||
;
|
||||
|
||||
OMEMOMessage._() : super();
|
||||
factory OMEMOMessage({
|
||||
$core.int? n,
|
||||
$core.int? pn,
|
||||
$core.List<$core.int>? dhPub,
|
||||
$core.List<$core.int>? ciphertext,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (n != null) {
|
||||
_result.n = n;
|
||||
}
|
||||
if (pn != null) {
|
||||
_result.pn = pn;
|
||||
}
|
||||
if (dhPub != null) {
|
||||
_result.dhPub = dhPub;
|
||||
}
|
||||
if (ciphertext != null) {
|
||||
_result.ciphertext = ciphertext;
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
factory OMEMOMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory OMEMOMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
OMEMOMessage clone() => OMEMOMessage()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
OMEMOMessage copyWith(void Function(OMEMOMessage) updates) => super.copyWith((message) => updates(message as OMEMOMessage)) as OMEMOMessage; // ignore: deprecated_member_use
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static OMEMOMessage create() => OMEMOMessage._();
|
||||
OMEMOMessage createEmptyInstance() => create();
|
||||
static $pb.PbList<OMEMOMessage> createRepeated() => $pb.PbList<OMEMOMessage>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static OMEMOMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<OMEMOMessage>(create);
|
||||
static OMEMOMessage? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.int get n => $_getIZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set n($core.int v) { $_setUnsignedInt32(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasN() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearN() => clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.int get pn => $_getIZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set pn($core.int v) { $_setUnsignedInt32(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasPn() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearPn() => clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.List<$core.int> get dhPub => $_getN(2);
|
||||
@$pb.TagNumber(3)
|
||||
set dhPub($core.List<$core.int> v) { $_setBytes(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasDhPub() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearDhPub() => clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.List<$core.int> get ciphertext => $_getN(3);
|
||||
@$pb.TagNumber(4)
|
||||
set ciphertext($core.List<$core.int> v) { $_setBytes(3, v); }
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasCiphertext() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearCiphertext() => clearField(4);
|
||||
}
|
||||
|
||||
class OMEMOAuthenticatedMessage extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'OMEMOAuthenticatedMessage', createEmptyInstance: create)
|
||||
..a<$core.List<$core.int>>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'mac', $pb.PbFieldType.QY)
|
||||
..a<$core.List<$core.int>>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'message', $pb.PbFieldType.QY)
|
||||
;
|
||||
|
||||
OMEMOAuthenticatedMessage._() : super();
|
||||
factory OMEMOAuthenticatedMessage({
|
||||
$core.List<$core.int>? mac,
|
||||
$core.List<$core.int>? message,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (mac != null) {
|
||||
_result.mac = mac;
|
||||
}
|
||||
if (message != null) {
|
||||
_result.message = message;
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
factory OMEMOAuthenticatedMessage.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory OMEMOAuthenticatedMessage.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
OMEMOAuthenticatedMessage clone() => OMEMOAuthenticatedMessage()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
OMEMOAuthenticatedMessage copyWith(void Function(OMEMOAuthenticatedMessage) updates) => super.copyWith((message) => updates(message as OMEMOAuthenticatedMessage)) as OMEMOAuthenticatedMessage; // ignore: deprecated_member_use
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static OMEMOAuthenticatedMessage create() => OMEMOAuthenticatedMessage._();
|
||||
OMEMOAuthenticatedMessage createEmptyInstance() => create();
|
||||
static $pb.PbList<OMEMOAuthenticatedMessage> createRepeated() => $pb.PbList<OMEMOAuthenticatedMessage>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static OMEMOAuthenticatedMessage getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<OMEMOAuthenticatedMessage>(create);
|
||||
static OMEMOAuthenticatedMessage? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.List<$core.int> get mac => $_getN(0);
|
||||
@$pb.TagNumber(1)
|
||||
set mac($core.List<$core.int> v) { $_setBytes(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasMac() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearMac() => clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.List<$core.int> get message => $_getN(1);
|
||||
@$pb.TagNumber(2)
|
||||
set message($core.List<$core.int> v) { $_setBytes(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasMessage() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearMessage() => clearField(2);
|
||||
}
|
||||
|
||||
class OMEMOKeyExchange extends $pb.GeneratedMessage {
|
||||
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'OMEMOKeyExchange', createEmptyInstance: create)
|
||||
..a<$core.int>(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'pkId', $pb.PbFieldType.QU3)
|
||||
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'spkId', $pb.PbFieldType.QU3)
|
||||
..a<$core.List<$core.int>>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ik', $pb.PbFieldType.QY)
|
||||
..a<$core.List<$core.int>>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ek', $pb.PbFieldType.QY)
|
||||
..aQM<OMEMOAuthenticatedMessage>(5, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'message', subBuilder: OMEMOAuthenticatedMessage.create)
|
||||
;
|
||||
|
||||
OMEMOKeyExchange._() : super();
|
||||
factory OMEMOKeyExchange({
|
||||
$core.int? pkId,
|
||||
$core.int? spkId,
|
||||
$core.List<$core.int>? ik,
|
||||
$core.List<$core.int>? ek,
|
||||
OMEMOAuthenticatedMessage? message,
|
||||
}) {
|
||||
final _result = create();
|
||||
if (pkId != null) {
|
||||
_result.pkId = pkId;
|
||||
}
|
||||
if (spkId != null) {
|
||||
_result.spkId = spkId;
|
||||
}
|
||||
if (ik != null) {
|
||||
_result.ik = ik;
|
||||
}
|
||||
if (ek != null) {
|
||||
_result.ek = ek;
|
||||
}
|
||||
if (message != null) {
|
||||
_result.message = message;
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
factory OMEMOKeyExchange.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
|
||||
factory OMEMOKeyExchange.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
|
||||
'Will be removed in next major version')
|
||||
OMEMOKeyExchange clone() => OMEMOKeyExchange()..mergeFromMessage(this);
|
||||
@$core.Deprecated(
|
||||
'Using this can add significant overhead to your binary. '
|
||||
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
|
||||
'Will be removed in next major version')
|
||||
OMEMOKeyExchange copyWith(void Function(OMEMOKeyExchange) updates) => super.copyWith((message) => updates(message as OMEMOKeyExchange)) as OMEMOKeyExchange; // ignore: deprecated_member_use
|
||||
$pb.BuilderInfo get info_ => _i;
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static OMEMOKeyExchange create() => OMEMOKeyExchange._();
|
||||
OMEMOKeyExchange createEmptyInstance() => create();
|
||||
static $pb.PbList<OMEMOKeyExchange> createRepeated() => $pb.PbList<OMEMOKeyExchange>();
|
||||
@$core.pragma('dart2js:noInline')
|
||||
static OMEMOKeyExchange getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<OMEMOKeyExchange>(create);
|
||||
static OMEMOKeyExchange? _defaultInstance;
|
||||
|
||||
@$pb.TagNumber(1)
|
||||
$core.int get pkId => $_getIZ(0);
|
||||
@$pb.TagNumber(1)
|
||||
set pkId($core.int v) { $_setUnsignedInt32(0, v); }
|
||||
@$pb.TagNumber(1)
|
||||
$core.bool hasPkId() => $_has(0);
|
||||
@$pb.TagNumber(1)
|
||||
void clearPkId() => clearField(1);
|
||||
|
||||
@$pb.TagNumber(2)
|
||||
$core.int get spkId => $_getIZ(1);
|
||||
@$pb.TagNumber(2)
|
||||
set spkId($core.int v) { $_setUnsignedInt32(1, v); }
|
||||
@$pb.TagNumber(2)
|
||||
$core.bool hasSpkId() => $_has(1);
|
||||
@$pb.TagNumber(2)
|
||||
void clearSpkId() => clearField(2);
|
||||
|
||||
@$pb.TagNumber(3)
|
||||
$core.List<$core.int> get ik => $_getN(2);
|
||||
@$pb.TagNumber(3)
|
||||
set ik($core.List<$core.int> v) { $_setBytes(2, v); }
|
||||
@$pb.TagNumber(3)
|
||||
$core.bool hasIk() => $_has(2);
|
||||
@$pb.TagNumber(3)
|
||||
void clearIk() => clearField(3);
|
||||
|
||||
@$pb.TagNumber(4)
|
||||
$core.List<$core.int> get ek => $_getN(3);
|
||||
@$pb.TagNumber(4)
|
||||
set ek($core.List<$core.int> v) { $_setBytes(3, v); }
|
||||
@$pb.TagNumber(4)
|
||||
$core.bool hasEk() => $_has(3);
|
||||
@$pb.TagNumber(4)
|
||||
void clearEk() => clearField(4);
|
||||
|
||||
@$pb.TagNumber(5)
|
||||
OMEMOAuthenticatedMessage get message => $_getN(4);
|
||||
@$pb.TagNumber(5)
|
||||
set message(OMEMOAuthenticatedMessage v) { setField(5, v); }
|
||||
@$pb.TagNumber(5)
|
||||
$core.bool hasMessage() => $_has(4);
|
||||
@$pb.TagNumber(5)
|
||||
void clearMessage() => clearField(5);
|
||||
@$pb.TagNumber(5)
|
||||
OMEMOAuthenticatedMessage ensureMessage() => $_ensure(4);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: schema.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,constant_identifier_names,directives_ordering,library_prefixes,non_constant_identifier_names,prefer_final_fields,return_of_invalid_type,unnecessary_const,unnecessary_import,unnecessary_this,unused_import,unused_shown_name
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: schema.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,constant_identifier_names,deprecated_member_use_from_same_package,directives_ordering,library_prefixes,non_constant_identifier_names,prefer_final_fields,return_of_invalid_type,unnecessary_const,unnecessary_import,unnecessary_this,unused_import,unused_shown_name
|
||||
|
||||
import 'dart:core' as $core;
|
||||
import 'dart:convert' as $convert;
|
||||
import 'dart:typed_data' as $typed_data;
|
||||
@$core.Deprecated('Use oMEMOMessageDescriptor instead')
|
||||
const OMEMOMessage$json = const {
|
||||
'1': 'OMEMOMessage',
|
||||
'2': const [
|
||||
const {'1': 'n', '3': 1, '4': 2, '5': 13, '10': 'n'},
|
||||
const {'1': 'pn', '3': 2, '4': 2, '5': 13, '10': 'pn'},
|
||||
const {'1': 'dh_pub', '3': 3, '4': 2, '5': 12, '10': 'dhPub'},
|
||||
const {'1': 'ciphertext', '3': 4, '4': 1, '5': 12, '10': 'ciphertext'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `OMEMOMessage`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List oMEMOMessageDescriptor = $convert.base64Decode('CgxPTUVNT01lc3NhZ2USDAoBbhgBIAIoDVIBbhIOCgJwbhgCIAIoDVICcG4SFQoGZGhfcHViGAMgAigMUgVkaFB1YhIeCgpjaXBoZXJ0ZXh0GAQgASgMUgpjaXBoZXJ0ZXh0');
|
||||
@$core.Deprecated('Use oMEMOAuthenticatedMessageDescriptor instead')
|
||||
const OMEMOAuthenticatedMessage$json = const {
|
||||
'1': 'OMEMOAuthenticatedMessage',
|
||||
'2': const [
|
||||
const {'1': 'mac', '3': 1, '4': 2, '5': 12, '10': 'mac'},
|
||||
const {'1': 'message', '3': 2, '4': 2, '5': 12, '10': 'message'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `OMEMOAuthenticatedMessage`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List oMEMOAuthenticatedMessageDescriptor = $convert.base64Decode('ChlPTUVNT0F1dGhlbnRpY2F0ZWRNZXNzYWdlEhAKA21hYxgBIAIoDFIDbWFjEhgKB21lc3NhZ2UYAiACKAxSB21lc3NhZ2U=');
|
||||
@$core.Deprecated('Use oMEMOKeyExchangeDescriptor instead')
|
||||
const OMEMOKeyExchange$json = const {
|
||||
'1': 'OMEMOKeyExchange',
|
||||
'2': const [
|
||||
const {'1': 'pk_id', '3': 1, '4': 2, '5': 13, '10': 'pkId'},
|
||||
const {'1': 'spk_id', '3': 2, '4': 2, '5': 13, '10': 'spkId'},
|
||||
const {'1': 'ik', '3': 3, '4': 2, '5': 12, '10': 'ik'},
|
||||
const {'1': 'ek', '3': 4, '4': 2, '5': 12, '10': 'ek'},
|
||||
const {'1': 'message', '3': 5, '4': 2, '5': 11, '6': '.OMEMOAuthenticatedMessage', '10': 'message'},
|
||||
],
|
||||
};
|
||||
|
||||
/// Descriptor for `OMEMOKeyExchange`. Decode as a `google.protobuf.DescriptorProto`.
|
||||
final $typed_data.Uint8List oMEMOKeyExchangeDescriptor = $convert.base64Decode('ChBPTUVNT0tleUV4Y2hhbmdlEhMKBXBrX2lkGAEgAigNUgRwa0lkEhUKBnNwa19pZBgCIAIoDVIFc3BrSWQSDgoCaWsYAyACKAxSAmlrEg4KAmVrGAQgAigMUgJlaxI0CgdtZXNzYWdlGAUgAigLMhouT01FTU9BdXRoZW50aWNhdGVkTWVzc2FnZVIHbWVzc2FnZQ==');
|
||||
@@ -1,9 +0,0 @@
|
||||
///
|
||||
// Generated code. Do not modify.
|
||||
// source: schema.proto
|
||||
//
|
||||
// @dart = 2.12
|
||||
// ignore_for_file: annotate_overrides,camel_case_types,constant_identifier_names,deprecated_member_use_from_same_package,directives_ordering,library_prefixes,non_constant_identifier_names,prefer_final_fields,return_of_invalid_type,unnecessary_const,unnecessary_import,unnecessary_this,unused_import,unused_shown_name
|
||||
|
||||
export 'schema.pb.dart';
|
||||
|
||||
@@ -293,11 +293,15 @@ class OmemoDoubleRatchet {
|
||||
return plaintext;
|
||||
}
|
||||
|
||||
if (header.dhPub != await dhr?.getBytes()) {
|
||||
final dhPubMatches = listsEqual(
|
||||
header.dhPub ?? <int>[],
|
||||
await dhr?.getBytes() ?? <int>[],
|
||||
);
|
||||
if (!dhPubMatches) {
|
||||
await _skipMessageKeys(header.pn!);
|
||||
await _dhRatchet(header);
|
||||
}
|
||||
|
||||
|
||||
await _skipMessageKeys(header.n!);
|
||||
final newCkr = await kdfCk(ckr!, kdfCkNextChainKey);
|
||||
final mk = await kdfCk(ckr!, kdfCkNextMessageKey);
|
||||
|
||||
@@ -386,13 +386,22 @@ class OmemoSessionManager {
|
||||
_eventStreamController.add(DeviceModifiedEvent(_device));
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the device map, i.e. the mapping of bare Jid to its device identifiers
|
||||
/// we have built sessions with.
|
||||
Future<Map<String, List<int>>> getDeviceMap() async {
|
||||
Map<String, List<int>>? map;
|
||||
|
||||
await _lock.synchronized(() async {
|
||||
map = _deviceMap;
|
||||
});
|
||||
|
||||
return map!;
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
|
||||
|
||||
@visibleForTesting
|
||||
Map<String, List<int>> getDeviceMap() => _deviceMap;
|
||||
|
||||
@visibleForTesting
|
||||
Map<RatchetMapKey, OmemoDoubleRatchet> getRatchetMap() => _ratchetMap;
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
name: omemo_dart
|
||||
description: An XMPP library independent OMEMO library
|
||||
version: 0.1.0
|
||||
version: 0.1.3
|
||||
homepage: https://github.com/PapaTutuWawa/omemo_dart
|
||||
publish_to: https://git.polynom.me/api/packages/PapaTutuWawa/pub
|
||||
|
||||
environment:
|
||||
sdk: '>=2.17.0 <3.0.0'
|
||||
@@ -9,6 +11,7 @@ dependencies:
|
||||
collection: ^1.16.0
|
||||
cryptography: ^2.0.5
|
||||
hex: ^0.2.0
|
||||
meta: ^1.8.0
|
||||
pinenacl: ^0.5.1
|
||||
synchronized: ^3.0.0+2
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ void main() {
|
||||
test('Test using OMEMO sessions with only one device per user', () async {
|
||||
const aliceJid = 'alice@server.example';
|
||||
const bobJid = 'bob@other.server.example';
|
||||
|
||||
// Alice and Bob generate their sessions
|
||||
var deviceModified = false;
|
||||
var ratchetModified = 0;
|
||||
@@ -367,4 +366,60 @@ void main() {
|
||||
// untrusted device.
|
||||
expect(aliceMessage.encryptedKeys.length, 1);
|
||||
});
|
||||
|
||||
test('Test by sending multiple messages back and forth', () async {
|
||||
const aliceJid = 'alice@server.example';
|
||||
const bobJid = 'bob@other.server.example';
|
||||
// Alice and Bob generate their sessions
|
||||
final aliceSession = await OmemoSessionManager.generateNewIdentity(
|
||||
aliceJid,
|
||||
AlwaysTrustingTrustManager(),
|
||||
opkAmount: 1,
|
||||
);
|
||||
final bobSession = await OmemoSessionManager.generateNewIdentity(
|
||||
bobJid,
|
||||
AlwaysTrustingTrustManager(),
|
||||
opkAmount: 1,
|
||||
);
|
||||
|
||||
// Alice encrypts a message for Bob
|
||||
final aliceMessage = await aliceSession.encryptToJid(
|
||||
bobJid,
|
||||
'Hello Bob!',
|
||||
newSessions: [
|
||||
await (await bobSession.getDevice()).toBundle(),
|
||||
],
|
||||
);
|
||||
|
||||
// Alice sends the message to Bob
|
||||
// ...
|
||||
|
||||
await bobSession.decryptMessage(
|
||||
aliceMessage.ciphertext,
|
||||
aliceJid,
|
||||
(await aliceSession.getDevice()).id,
|
||||
aliceMessage.encryptedKeys,
|
||||
);
|
||||
|
||||
for (var i = 0; i < 100; i++) {
|
||||
final messageText = 'Test Message #$i';
|
||||
// Bob responds to Alice
|
||||
final bobResponseMessage = await bobSession.encryptToJid(
|
||||
aliceJid,
|
||||
messageText,
|
||||
);
|
||||
|
||||
// Bob sends the message to Alice
|
||||
// ...
|
||||
|
||||
// Alice decrypts it
|
||||
final aliceReceivedMessage = await aliceSession.decryptMessage(
|
||||
bobResponseMessage.ciphertext,
|
||||
bobJid,
|
||||
(await bobSession.getDevice()).id,
|
||||
bobResponseMessage.encryptedKeys,
|
||||
);
|
||||
expect(messageText, aliceReceivedMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ void main() {
|
||||
final oldDevice = await oldSession.getDevice();
|
||||
final newDevice = await newSession.getDevice();
|
||||
expect(await oldDevice.equals(newDevice), true);
|
||||
expect(oldSession.getDeviceMap(), newSession.getDeviceMap());
|
||||
expect(await oldSession.getDeviceMap(), await newSession.getDeviceMap());
|
||||
|
||||
expect(oldSession.getRatchetMap().length, newSession.getRatchetMap().length);
|
||||
for (final session in oldSession.getRatchetMap().entries) {
|
||||
|
||||
Reference in New Issue
Block a user