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
|
# NixOS
|
||||||
.direnv
|
.direnv
|
||||||
.envrc
|
.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!**
|
- **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.
|
- 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
|
## Contributing
|
||||||
|
|
||||||
Due to issues with `protobuf`, `omemo_dart` reimplements the Protobuf encoding for the required
|
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
|
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
|
When submitting a PR, please run the linter using `dart analyze` and make sure that all
|
||||||
tests still pass using `dart test`.
|
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;
|
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 _skipMessageKeys(header.pn!);
|
||||||
await _dhRatchet(header);
|
await _dhRatchet(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
await _skipMessageKeys(header.n!);
|
await _skipMessageKeys(header.n!);
|
||||||
final newCkr = await kdfCk(ckr!, kdfCkNextChainKey);
|
final newCkr = await kdfCk(ckr!, kdfCkNextChainKey);
|
||||||
final mk = await kdfCk(ckr!, kdfCkNextMessageKey);
|
final mk = await kdfCk(ckr!, kdfCkNextMessageKey);
|
||||||
|
|||||||
@@ -386,13 +386,22 @@ class OmemoSessionManager {
|
|||||||
_eventStreamController.add(DeviceModifiedEvent(_device));
|
_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
|
@visibleForTesting
|
||||||
OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
|
OmemoDoubleRatchet getRatchet(String jid, int deviceId) => _ratchetMap[RatchetMapKey(jid, deviceId)]!;
|
||||||
|
|
||||||
@visibleForTesting
|
|
||||||
Map<String, List<int>> getDeviceMap() => _deviceMap;
|
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
Map<RatchetMapKey, OmemoDoubleRatchet> getRatchetMap() => _ratchetMap;
|
Map<RatchetMapKey, OmemoDoubleRatchet> getRatchetMap() => _ratchetMap;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
name: omemo_dart
|
name: omemo_dart
|
||||||
description: An XMPP library independent OMEMO library
|
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:
|
environment:
|
||||||
sdk: '>=2.17.0 <3.0.0'
|
sdk: '>=2.17.0 <3.0.0'
|
||||||
@@ -9,6 +11,7 @@ dependencies:
|
|||||||
collection: ^1.16.0
|
collection: ^1.16.0
|
||||||
cryptography: ^2.0.5
|
cryptography: ^2.0.5
|
||||||
hex: ^0.2.0
|
hex: ^0.2.0
|
||||||
|
meta: ^1.8.0
|
||||||
pinenacl: ^0.5.1
|
pinenacl: ^0.5.1
|
||||||
synchronized: ^3.0.0+2
|
synchronized: ^3.0.0+2
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ void main() {
|
|||||||
test('Test using OMEMO sessions with only one device per user', () async {
|
test('Test using OMEMO sessions with only one device per user', () async {
|
||||||
const aliceJid = 'alice@server.example';
|
const aliceJid = 'alice@server.example';
|
||||||
const bobJid = 'bob@other.server.example';
|
const bobJid = 'bob@other.server.example';
|
||||||
|
|
||||||
// Alice and Bob generate their sessions
|
// Alice and Bob generate their sessions
|
||||||
var deviceModified = false;
|
var deviceModified = false;
|
||||||
var ratchetModified = 0;
|
var ratchetModified = 0;
|
||||||
@@ -367,4 +366,60 @@ void main() {
|
|||||||
// untrusted device.
|
// untrusted device.
|
||||||
expect(aliceMessage.encryptedKeys.length, 1);
|
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 oldDevice = await oldSession.getDevice();
|
||||||
final newDevice = await newSession.getDevice();
|
final newDevice = await newSession.getDevice();
|
||||||
expect(await oldDevice.equals(newDevice), true);
|
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);
|
expect(oldSession.getRatchetMap().length, newSession.getRatchetMap().length);
|
||||||
for (final session in oldSession.getRatchetMap().entries) {
|
for (final session in oldSession.getRatchetMap().entries) {
|
||||||
|
|||||||
Reference in New Issue
Block a user