Compare commits
2 Commits
308f7d93f5
...
e1e492832e
Author | SHA1 | Date | |
---|---|---|---|
e1e492832e | |||
1950394f7d |
2
.gitlint
2
.gitlint
@ -7,7 +7,7 @@ line-length=72
|
|||||||
[title-trailing-punctuation]
|
[title-trailing-punctuation]
|
||||||
[title-hard-tab]
|
[title-hard-tab]
|
||||||
[title-match-regex]
|
[title-match-regex]
|
||||||
regex=^((feat|fix|chore|refactor|docs|release|test)\((meta|tests|style|docs|xep|core)+(,(meta|tests|style|docs|xep|core))*\)|release): [A-Z0-9].*$
|
regex=^((feat|fix|chore|refactor|docs|release|test)\((meta|tests|style|docs|xep|core|example)+(,(meta|tests|style|docs|xep|core|example))*\)|release): [A-Z0-9].*$
|
||||||
|
|
||||||
|
|
||||||
[body-trailing-whitespace]
|
[body-trailing-whitespace]
|
||||||
|
@ -11,5 +11,3 @@ analyzer:
|
|||||||
exclude:
|
exclude:
|
||||||
- "**/*.g.dart"
|
- "**/*.g.dart"
|
||||||
- "**/*.freezed.dart"
|
- "**/*.freezed.dart"
|
||||||
- "test/"
|
|
||||||
- "integration_test/"
|
|
||||||
|
@ -167,7 +167,7 @@ class XmppConnection {
|
|||||||
|
|
||||||
/// Completers for certain actions
|
/// Completers for certain actions
|
||||||
// ignore: use_late_for_private_fields_and_variables
|
// ignore: use_late_for_private_fields_and_variables
|
||||||
Completer<Result<bool, XmppConnectionError>>? _connectionCompleter;
|
Completer<Result<bool, XmppError>>? _connectionCompleter;
|
||||||
|
|
||||||
/// Negotiators
|
/// Negotiators
|
||||||
final Map<String, XmppFeatureNegotiatorBase> _featureNegotiators = {};
|
final Map<String, XmppFeatureNegotiatorBase> _featureNegotiators = {};
|
||||||
@ -896,7 +896,8 @@ class XmppConnection {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
_log.severe(
|
_log.severe(
|
||||||
'No negotiator could be picked while negotiations are not done');
|
'No negotiator could be picked while negotiations are not done',
|
||||||
|
);
|
||||||
await _resetIsConnectionRunning();
|
await _resetIsConnectionRunning();
|
||||||
await handleError(NoAuthenticatorAvailableError());
|
await handleError(NoAuthenticatorAvailableError());
|
||||||
return;
|
return;
|
||||||
@ -1132,7 +1133,7 @@ class XmppConnection {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result<bool, XmppConnectionError>> _connectImpl({
|
Future<Result<bool, XmppError>> _connectImpl({
|
||||||
String? lastResource,
|
String? lastResource,
|
||||||
bool waitForConnection = false,
|
bool waitForConnection = false,
|
||||||
bool shouldReconnect = true,
|
bool shouldReconnect = true,
|
||||||
@ -1222,7 +1223,7 @@ class XmppConnection {
|
|||||||
///
|
///
|
||||||
/// [enableReconnectOnSuccess] indicates that automatic reconnection is to be
|
/// [enableReconnectOnSuccess] indicates that automatic reconnection is to be
|
||||||
/// enabled once the connection has been successfully established.
|
/// enabled once the connection has been successfully established.
|
||||||
Future<Result<bool, XmppConnectionError>> connect({
|
Future<Result<bool, XmppError>> connect({
|
||||||
String? lastResource,
|
String? lastResource,
|
||||||
bool? shouldReconnect,
|
bool? shouldReconnect,
|
||||||
bool waitForConnection = false,
|
bool waitForConnection = false,
|
||||||
|
@ -4,13 +4,28 @@ import 'package:test/test.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
test('Test the async queue', () async {
|
test('Test the async queue', () async {
|
||||||
final queue = AsyncQueue();
|
final queue = AsyncQueue();
|
||||||
int future1Finish = 0;
|
var future1Finish = 0;
|
||||||
int future2Finish = 0;
|
var future2Finish = 0;
|
||||||
int future3Finish = 0;
|
var future3Finish = 0;
|
||||||
|
|
||||||
await queue.addJob(() => Future<void>.delayed(const Duration(seconds: 3), () => future1Finish = DateTime.now().millisecondsSinceEpoch));
|
await queue.addJob(
|
||||||
await queue.addJob(() => Future<void>.delayed(const Duration(seconds: 3), () => future2Finish = DateTime.now().millisecondsSinceEpoch));
|
() => Future<void>.delayed(
|
||||||
await queue.addJob(() => Future<void>.delayed(const Duration(seconds: 3), () => future3Finish = DateTime.now().millisecondsSinceEpoch));
|
const Duration(seconds: 3),
|
||||||
|
() => future1Finish = DateTime.now().millisecondsSinceEpoch,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await queue.addJob(
|
||||||
|
() => Future<void>.delayed(
|
||||||
|
const Duration(seconds: 3),
|
||||||
|
() => future2Finish = DateTime.now().millisecondsSinceEpoch,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await queue.addJob(
|
||||||
|
() => Future<void>.delayed(
|
||||||
|
const Duration(seconds: 3),
|
||||||
|
() => future3Finish = DateTime.now().millisecondsSinceEpoch,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
await Future<void>.delayed(const Duration(seconds: 12));
|
await Future<void>.delayed(const Duration(seconds: 12));
|
||||||
|
|
||||||
|
@ -3,28 +3,38 @@ import 'package:moxxmpp/src/awaiter.dart';
|
|||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
final bareJid = JID('moxxmpp', 'server3.example', '');
|
const bareJid = JID('moxxmpp', 'server3.example', '');
|
||||||
|
|
||||||
test('Test awaiting an awaited stanza with a from attribute', () async {
|
test('Test awaiting an awaited stanza with a from attribute', () async {
|
||||||
final awaiter = StanzaAwaiter();
|
final awaiter = StanzaAwaiter();
|
||||||
|
|
||||||
// "Send" a stanza
|
// "Send" a stanza
|
||||||
final future = await awaiter.addPending('user1@server.example', 'abc123', 'iq');
|
final future = await awaiter.addPending(
|
||||||
|
'user1@server.example',
|
||||||
|
'abc123',
|
||||||
|
'iq',
|
||||||
|
);
|
||||||
|
|
||||||
// Receive the wrong answer
|
// Receive the wrong answer
|
||||||
final result1 = await awaiter.onData(
|
final result1 = await awaiter.onData(
|
||||||
XMLNode.fromString('<iq from="user3@server.example" id="abc123" type="result" />'),
|
XMLNode.fromString(
|
||||||
|
'<iq from="user3@server.example" id="abc123" type="result" />',
|
||||||
|
),
|
||||||
bareJid,
|
bareJid,
|
||||||
);
|
);
|
||||||
expect(result1, false);
|
expect(result1, false);
|
||||||
final result2 = await awaiter.onData(
|
final result2 = await awaiter.onData(
|
||||||
XMLNode.fromString('<iq from="user1@server.example" id="lol" type="result" />'),
|
XMLNode.fromString(
|
||||||
|
'<iq from="user1@server.example" id="lol" type="result" />',
|
||||||
|
),
|
||||||
bareJid,
|
bareJid,
|
||||||
);
|
);
|
||||||
expect(result2, false);
|
expect(result2, false);
|
||||||
|
|
||||||
// Receive the correct answer
|
// Receive the correct answer
|
||||||
final stanza = XMLNode.fromString('<iq from="user1@server.example" id="abc123" type="result" />');
|
final stanza = XMLNode.fromString(
|
||||||
|
'<iq from="user1@server.example" id="abc123" type="result" />',
|
||||||
|
);
|
||||||
final result3 = await awaiter.onData(
|
final result3 = await awaiter.onData(
|
||||||
stanza,
|
stanza,
|
||||||
bareJid,
|
bareJid,
|
||||||
@ -45,7 +55,7 @@ void main() {
|
|||||||
bareJid,
|
bareJid,
|
||||||
);
|
);
|
||||||
expect(result1, false);
|
expect(result1, false);
|
||||||
|
|
||||||
// Receive the correct answer
|
// Receive the correct answer
|
||||||
final stanza = XMLNode.fromString('<iq id="abc123" type="result" />');
|
final stanza = XMLNode.fromString('<iq id="abc123" type="result" />');
|
||||||
final result2 = await awaiter.onData(
|
final result2 = await awaiter.onData(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:moxxmpp/moxxmpp.dart';
|
import 'package:moxxmpp/moxxmpp.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Parse a full JID', () {
|
test('Parse a full JID', () {
|
||||||
final jid = JID.fromString('test@server/abc');
|
final jid = JID.fromString('test@server/abc');
|
||||||
@ -29,23 +30,41 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Equality', () {
|
test('Equality', () {
|
||||||
expect(JID.fromString('hallo@welt/abc') == JID('hallo', 'welt', 'abc'), true);
|
expect(
|
||||||
expect(JID.fromString('hallo@welt') == JID('hallo', 'welt', 'a'), false);
|
JID.fromString('hallo@welt/abc') == const JID('hallo', 'welt', 'abc'),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
JID.fromString('hallo@welt') == const JID('hallo', 'welt', 'a'),
|
||||||
|
false,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Dot suffix at domain part', () {
|
test('Dot suffix at domain part', () {
|
||||||
expect(JID.fromString('hallo@welt.example.') == JID('hallo', 'welt.example', ''), true);
|
expect(
|
||||||
expect(JID.fromString('hallo@welt.example./test') == JID('hallo', 'welt.example', 'test'), true);
|
JID.fromString('hallo@welt.example.') ==
|
||||||
|
const JID('hallo', 'welt.example', ''),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
JID.fromString('hallo@welt.example./test') ==
|
||||||
|
const JID('hallo', 'welt.example', 'test'),
|
||||||
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Parse resource with a slash', () {
|
test('Parse resource with a slash', () {
|
||||||
expect(JID.fromString('hallo@welt.example./test/welt') == JID('hallo', 'welt.example', 'test/welt'), true);
|
expect(
|
||||||
|
JID.fromString('hallo@welt.example./test/welt') ==
|
||||||
|
const JID('hallo', 'welt.example', 'test/welt'),
|
||||||
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('bareCompare', () {
|
test('bareCompare', () {
|
||||||
final jid1 = JID('hallo', 'welt', 'lol');
|
const jid1 = JID('hallo', 'welt', 'lol');
|
||||||
final jid2 = JID('hallo', 'welt', '');
|
const jid2 = JID('hallo', 'welt', '');
|
||||||
final jid3 = JID('hallo', 'earth', 'true');
|
const jid3 = JID('hallo', 'earth', 'true');
|
||||||
|
|
||||||
expect(jid1.bareCompare(jid2), true);
|
expect(jid1.bareCompare(jid2), true);
|
||||||
expect(jid2.bareCompare(jid1), true);
|
expect(jid2.bareCompare(jid1), true);
|
||||||
|
@ -9,24 +9,32 @@ const exampleXmlns2 = 'im:moxxmpp:example2';
|
|||||||
const exampleNamespace2 = 'im.moxxmpp.test.example2';
|
const exampleNamespace2 = 'im.moxxmpp.test.example2';
|
||||||
|
|
||||||
class StubNegotiator1 extends XmppFeatureNegotiatorBase {
|
class StubNegotiator1 extends XmppFeatureNegotiatorBase {
|
||||||
StubNegotiator1() : called = false, super(1, false, exampleXmlns1, exampleNamespace1);
|
StubNegotiator1()
|
||||||
|
: called = false,
|
||||||
|
super(1, false, exampleXmlns1, exampleNamespace1);
|
||||||
|
|
||||||
bool called;
|
bool called;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<NegotiatorState, NegotiatorError>> negotiate(XMLNode nonza) async {
|
Future<Result<NegotiatorState, NegotiatorError>> negotiate(
|
||||||
|
XMLNode nonza,
|
||||||
|
) async {
|
||||||
called = true;
|
called = true;
|
||||||
return const Result(NegotiatorState.done);
|
return const Result(NegotiatorState.done);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StubNegotiator2 extends XmppFeatureNegotiatorBase {
|
class StubNegotiator2 extends XmppFeatureNegotiatorBase {
|
||||||
StubNegotiator2() : called = false, super(10, false, exampleXmlns2, exampleNamespace2);
|
StubNegotiator2()
|
||||||
|
: called = false,
|
||||||
|
super(10, false, exampleXmlns2, exampleNamespace2);
|
||||||
|
|
||||||
bool called;
|
bool called;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<NegotiatorState, NegotiatorError>> negotiate(XMLNode nonza) async {
|
Future<Result<NegotiatorState, NegotiatorError>> negotiate(
|
||||||
|
XMLNode nonza,
|
||||||
|
) async {
|
||||||
called = true;
|
called = true;
|
||||||
return const Result(NegotiatorState.done);
|
return const Result(NegotiatorState.done);
|
||||||
}
|
}
|
||||||
@ -53,12 +61,13 @@ void main() {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final connection = XmppConnection(
|
final connection = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
stubSocket,
|
stubSocket,
|
||||||
)..registerFeatureNegotiators([
|
)
|
||||||
|
..registerFeatureNegotiators([
|
||||||
StubNegotiator1(),
|
StubNegotiator1(),
|
||||||
StubNegotiator2(),
|
StubNegotiator2(),
|
||||||
])
|
])
|
||||||
@ -85,11 +94,13 @@ void main() {
|
|||||||
expect(connection.getNextNegotiator(features)?.id, exampleNamespace2);
|
expect(connection.getNextNegotiator(features)?.id, exampleNamespace2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test negotiating features with no stream restarts', () async {
|
test('Test negotiating features with no stream restarts', () async {
|
||||||
await connection.connect();
|
await connection.connect();
|
||||||
await Future.delayed(const Duration(seconds: 3), () {
|
await Future.delayed(const Duration(seconds: 3), () {
|
||||||
final negotiator1 = connection.getNegotiatorById<StubNegotiator1>(exampleNamespace1);
|
final negotiator1 =
|
||||||
final negotiator2 = connection.getNegotiatorById<StubNegotiator2>(exampleNamespace2);
|
connection.getNegotiatorById<StubNegotiator1>(exampleNamespace1);
|
||||||
|
final negotiator2 =
|
||||||
|
connection.getNegotiatorById<StubNegotiator2>(exampleNamespace2);
|
||||||
expect(negotiator1?.called, true);
|
expect(negotiator1?.called, true);
|
||||||
expect(negotiator2?.called, true);
|
expect(negotiator2?.called, true);
|
||||||
});
|
});
|
||||||
|
@ -3,12 +3,11 @@ import 'package:test/test.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Test receiving a roster push', () async {
|
test('Test receiving a roster push', () async {
|
||||||
final rs = TestingRosterStateManager(null, []);
|
final rs = TestingRosterStateManager(null, [])..register((_) {});
|
||||||
rs.register((_) {});
|
|
||||||
|
|
||||||
await rs.handleRosterPush(
|
await rs.handleRosterPush(
|
||||||
RosterPushResult(
|
RosterPushResult(
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser@server.example',
|
jid: 'testuser@server.example',
|
||||||
subscription: 'both',
|
subscription: 'both',
|
||||||
),
|
),
|
||||||
@ -17,7 +16,10 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
rs.getRosterItems().indexWhere((item) => item.jid == 'testuser@server.example') != -1,
|
rs
|
||||||
|
.getRosterItems()
|
||||||
|
.indexWhere((item) => item.jid == 'testuser@server.example') !=
|
||||||
|
-1,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
expect(rs.loadCount, 1);
|
expect(rs.loadCount, 1);
|
||||||
@ -26,7 +28,7 @@ void main() {
|
|||||||
// Receive another roster push
|
// Receive another roster push
|
||||||
await rs.handleRosterPush(
|
await rs.handleRosterPush(
|
||||||
RosterPushResult(
|
RosterPushResult(
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser2@server2.example',
|
jid: 'testuser2@server2.example',
|
||||||
subscription: 'to',
|
subscription: 'to',
|
||||||
),
|
),
|
||||||
@ -35,16 +37,19 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
rs.getRosterItems().indexWhere((item) => item.jid == 'testuser2@server2.example') != -1,
|
rs
|
||||||
|
.getRosterItems()
|
||||||
|
.indexWhere((item) => item.jid == 'testuser2@server2.example') !=
|
||||||
|
-1,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
expect(rs.loadCount, 1);
|
expect(rs.loadCount, 1);
|
||||||
expect(rs.getRosterItems().length, 2);
|
expect(rs.getRosterItems().length, 2);
|
||||||
|
|
||||||
// Remove one of the items
|
// Remove one of the items
|
||||||
await rs.handleRosterPush(
|
await rs.handleRosterPush(
|
||||||
RosterPushResult(
|
RosterPushResult(
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser2@server2.example',
|
jid: 'testuser2@server2.example',
|
||||||
subscription: 'remove',
|
subscription: 'remove',
|
||||||
),
|
),
|
||||||
@ -53,34 +58,39 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
rs.getRosterItems().indexWhere((item) => item.jid == 'testuser2@server2.example') == -1,
|
rs
|
||||||
|
.getRosterItems()
|
||||||
|
.indexWhere((item) => item.jid == 'testuser2@server2.example') ==
|
||||||
|
-1,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
rs.getRosterItems().indexWhere((item) => item.jid == 'testuser@server.example') != 1,
|
rs
|
||||||
|
.getRosterItems()
|
||||||
|
.indexWhere((item) => item.jid == 'testuser@server.example') !=
|
||||||
|
1,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
expect(rs.loadCount, 1);
|
expect(rs.loadCount, 1);
|
||||||
expect(rs.getRosterItems().length, 1);
|
expect(rs.getRosterItems().length, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a roster fetch', () async {
|
test('Test a roster fetch', () async {
|
||||||
final rs = TestingRosterStateManager(null, []);
|
final rs = TestingRosterStateManager(null, [])..register((_) {});
|
||||||
rs.register((_) {});
|
|
||||||
|
|
||||||
// Fetch the roster
|
// Fetch the roster
|
||||||
await rs.handleRosterFetch(
|
await rs.handleRosterFetch(
|
||||||
RosterRequestResult(
|
RosterRequestResult(
|
||||||
[
|
[
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser@server.example',
|
jid: 'testuser@server.example',
|
||||||
subscription: 'both',
|
subscription: 'both',
|
||||||
),
|
),
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser2@server2.example',
|
jid: 'testuser2@server2.example',
|
||||||
subscription: 'to',
|
subscription: 'to',
|
||||||
),
|
),
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser3@server3.example',
|
jid: 'testuser3@server3.example',
|
||||||
subscription: 'from',
|
subscription: 'from',
|
||||||
),
|
),
|
||||||
@ -91,48 +101,66 @@ void main() {
|
|||||||
|
|
||||||
expect(rs.loadCount, 1);
|
expect(rs.loadCount, 1);
|
||||||
expect(rs.getRosterItems().length, 3);
|
expect(rs.getRosterItems().length, 3);
|
||||||
expect(rs.getRosterItems().indexWhere((item) => item.jid == 'testuser@server.example') != -1, true);
|
expect(
|
||||||
expect(rs.getRosterItems().indexWhere((item) => item.jid == 'testuser2@server2.example') != -1, true);
|
rs
|
||||||
expect(rs.getRosterItems().indexWhere((item) => item.jid == 'testuser3@server3.example') != -1, true);
|
.getRosterItems()
|
||||||
|
.indexWhere((item) => item.jid == 'testuser@server.example') !=
|
||||||
|
-1,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
rs
|
||||||
|
.getRosterItems()
|
||||||
|
.indexWhere((item) => item.jid == 'testuser2@server2.example') !=
|
||||||
|
-1,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
rs
|
||||||
|
.getRosterItems()
|
||||||
|
.indexWhere((item) => item.jid == 'testuser3@server3.example') !=
|
||||||
|
-1,
|
||||||
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a roster fetch if we already have a roster', () async {
|
test('Test a roster fetch if we already have a roster', () async {
|
||||||
XmppEvent? event;
|
XmppEvent? event;
|
||||||
final rs = TestingRosterStateManager('aaaaa', [
|
final rs = TestingRosterStateManager('aaaaa', [
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser@server.example',
|
jid: 'testuser@server.example',
|
||||||
subscription: 'both',
|
subscription: 'both',
|
||||||
),
|
),
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser2@server2.example',
|
jid: 'testuser2@server2.example',
|
||||||
subscription: 'to',
|
subscription: 'to',
|
||||||
),
|
),
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser3@server3.example',
|
jid: 'testuser3@server3.example',
|
||||||
subscription: 'from',
|
subscription: 'from',
|
||||||
),
|
),
|
||||||
]);
|
])
|
||||||
rs.register((_event) {
|
..register((e) {
|
||||||
event = _event;
|
event = e;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fetch the roster
|
// Fetch the roster
|
||||||
await rs.handleRosterFetch(
|
await rs.handleRosterFetch(
|
||||||
RosterRequestResult(
|
RosterRequestResult(
|
||||||
[
|
[
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser@server.example',
|
jid: 'testuser@server.example',
|
||||||
subscription: 'both',
|
subscription: 'both',
|
||||||
),
|
),
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser2@server2.example',
|
jid: 'testuser2@server2.example',
|
||||||
subscription: 'to',
|
subscription: 'to',
|
||||||
),
|
),
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser3@server3.example',
|
jid: 'testuser3@server3.example',
|
||||||
subscription: 'both',
|
subscription: 'both',
|
||||||
),
|
),
|
||||||
XmppRosterItem(
|
const XmppRosterItem(
|
||||||
jid: 'testuser4@server4.example',
|
jid: 'testuser4@server4.example',
|
||||||
subscription: 'both',
|
subscription: 'both',
|
||||||
),
|
),
|
||||||
@ -142,7 +170,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(event is RosterUpdatedEvent, true);
|
expect(event is RosterUpdatedEvent, true);
|
||||||
final updateEvent = event as RosterUpdatedEvent;
|
final updateEvent = event! as RosterUpdatedEvent;
|
||||||
|
|
||||||
expect(updateEvent.added.length, 1);
|
expect(updateEvent.added.length, 1);
|
||||||
expect(updateEvent.added.first.jid, 'testuser4@server4.example');
|
expect(updateEvent.added.first.jid, 'testuser4@server4.example');
|
||||||
|
@ -1,27 +1,30 @@
|
|||||||
import 'package:moxxmpp/src/negotiators/sasl/kv.dart';
|
import 'package:moxxmpp/src/negotiators/sasl/kv.dart';
|
||||||
import 'package:moxxmpp/moxxmpp.dart';
|
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Test the Key-Value parser', () {
|
test('Test the Key-Value parser', () {
|
||||||
final result1 = parseKeyValue('n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL');
|
final result1 = parseKeyValue('n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL');
|
||||||
expect(result1.length, 2);
|
expect(result1.length, 2);
|
||||||
expect(result1['n']!, 'user');
|
expect(result1['n'], 'user');
|
||||||
expect(result1['r']!, 'fyko+d2lbbFgONRv9qkxdawL');
|
expect(result1['r'], 'fyko+d2lbbFgONRv9qkxdawL');
|
||||||
|
|
||||||
final result2 = parseKeyValue('r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096');
|
final result2 = parseKeyValue(
|
||||||
expect(result2.length, 3);
|
'r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096',
|
||||||
expect(result2['r']!, 'fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j');
|
);
|
||||||
expect(result2['s']!, 'QSXCR+Q6sek8bf92');
|
expect(result2.length, 3);
|
||||||
expect(result2['i']!, '4096');
|
expect(result2['r'], 'fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j');
|
||||||
|
expect(result2['s'], 'QSXCR+Q6sek8bf92');
|
||||||
|
expect(result2['i'], '4096');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Test the Key-Value parser with '=' as a value", () {
|
test("Test the Key-Value parser with '=' as a value", () {
|
||||||
final result = parseKeyValue('c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=,o=123');
|
final result = parseKeyValue(
|
||||||
expect(result.length, 4);
|
'c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=,o=123',
|
||||||
expect(result['c']!, 'biws');
|
);
|
||||||
expect(result['r']!, 'fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j');
|
expect(result.length, 4);
|
||||||
expect(result['p']!, 'v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=');
|
expect(result['c'], 'biws');
|
||||||
expect(result['o']!, '123');
|
expect(result['r'], 'fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j');
|
||||||
|
expect(result['p'], 'v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=');
|
||||||
|
expect(result['o'], '123');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -38,11 +38,19 @@ final scramSha256StreamFeatures = XMLNode(
|
|||||||
void main() {
|
void main() {
|
||||||
final fakeSocket = StubTCPSocket([]);
|
final fakeSocket = StubTCPSocket([]);
|
||||||
test('Test SASL SCRAM-SHA-1', () async {
|
test('Test SASL SCRAM-SHA-1', () async {
|
||||||
final negotiator = SaslScramNegotiator(0, 'n=user,r=fyko+d2lbbFgONRv9qkxdawL', 'fyko+d2lbbFgONRv9qkxdawL', ScramHashType.sha1);
|
final negotiator = SaslScramNegotiator(
|
||||||
negotiator.register(
|
0,
|
||||||
|
'n=user,r=fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
'fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
ScramHashType.sha1,
|
||||||
|
)..register(
|
||||||
NegotiatorAttributes(
|
NegotiatorAttributes(
|
||||||
(XMLNode _, {String? redact}) {},
|
(XMLNode _, {String? redact}) {},
|
||||||
() => ConnectionSettings(jid: JID.fromString('user@server'), password: 'pencil', useDirectTLS: true),
|
() => ConnectionSettings(
|
||||||
|
jid: JID.fromString('user@server'),
|
||||||
|
password: 'pencil',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
(_) async {},
|
(_) async {},
|
||||||
getNegotiatorNullStub,
|
getNegotiatorNullStub,
|
||||||
getManagerNullStub,
|
getManagerNullStub,
|
||||||
@ -52,61 +60,90 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
HEX.encode(await negotiator.calculateSaltedPassword('QSXCR+Q6sek8bf92', 4096)),
|
HEX.encode(
|
||||||
'1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d',
|
await negotiator.calculateSaltedPassword('QSXCR+Q6sek8bf92', 4096),
|
||||||
);
|
),
|
||||||
expect(
|
'1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d',
|
||||||
HEX.encode(
|
);
|
||||||
await negotiator.calculateClientKey(HEX.decode('1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d')),
|
expect(
|
||||||
|
HEX.encode(
|
||||||
|
await negotiator.calculateClientKey(
|
||||||
|
HEX.decode('1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d'),
|
||||||
),
|
),
|
||||||
'e234c47bf6c36696dd6d852b99aaa2ba26555728',
|
),
|
||||||
);
|
'e234c47bf6c36696dd6d852b99aaa2ba26555728',
|
||||||
const authMessage = 'n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j';
|
);
|
||||||
expect(
|
const authMessage =
|
||||||
HEX.encode(
|
'n=user,r=fyko+d2lbbFgONRv9qkxdawL,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096,c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j';
|
||||||
await negotiator.calculateClientSignature(authMessage, HEX.decode('e9d94660c39d65c38fbad91c358f14da0eef2bd6')),
|
expect(
|
||||||
|
HEX.encode(
|
||||||
|
await negotiator.calculateClientSignature(
|
||||||
|
authMessage,
|
||||||
|
HEX.decode('e9d94660c39d65c38fbad91c358f14da0eef2bd6'),
|
||||||
),
|
),
|
||||||
'5d7138c486b0bfabdf49e3e2da8bd6e5c79db613',
|
),
|
||||||
);
|
'5d7138c486b0bfabdf49e3e2da8bd6e5c79db613',
|
||||||
expect(
|
);
|
||||||
HEX.encode(
|
expect(
|
||||||
negotiator.calculateClientProof(HEX.decode('e234c47bf6c36696dd6d852b99aaa2ba26555728'), HEX.decode('5d7138c486b0bfabdf49e3e2da8bd6e5c79db613')),
|
HEX.encode(
|
||||||
|
negotiator.calculateClientProof(
|
||||||
|
HEX.decode('e234c47bf6c36696dd6d852b99aaa2ba26555728'),
|
||||||
|
HEX.decode('5d7138c486b0bfabdf49e3e2da8bd6e5c79db613'),
|
||||||
),
|
),
|
||||||
'bf45fcbf7073d93d022466c94321745fe1c8e13b',
|
),
|
||||||
);
|
'bf45fcbf7073d93d022466c94321745fe1c8e13b',
|
||||||
expect(
|
);
|
||||||
HEX.encode(
|
expect(
|
||||||
await negotiator.calculateServerSignature(authMessage, HEX.decode('0fe09258b3ac852ba502cc62ba903eaacdbf7d31')),
|
HEX.encode(
|
||||||
|
await negotiator.calculateServerSignature(
|
||||||
|
authMessage,
|
||||||
|
HEX.decode('0fe09258b3ac852ba502cc62ba903eaacdbf7d31'),
|
||||||
),
|
),
|
||||||
'ae617da6a57c4bbb2e0286568dae1d251905b0a4',
|
),
|
||||||
);
|
'ae617da6a57c4bbb2e0286568dae1d251905b0a4',
|
||||||
expect(
|
);
|
||||||
HEX.encode(
|
expect(
|
||||||
await negotiator.calculateServerKey(HEX.decode('1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d')),
|
HEX.encode(
|
||||||
|
await negotiator.calculateServerKey(
|
||||||
|
HEX.decode('1d96ee3a529b5a5f9e47c01f229a2cb8a6e15f7d'),
|
||||||
),
|
),
|
||||||
'0fe09258b3ac852ba502cc62ba903eaacdbf7d31',
|
),
|
||||||
);
|
'0fe09258b3ac852ba502cc62ba903eaacdbf7d31',
|
||||||
expect(
|
);
|
||||||
HEX.encode(
|
expect(
|
||||||
negotiator.calculateClientProof(
|
HEX.encode(
|
||||||
HEX.decode('e234c47bf6c36696dd6d852b99aaa2ba26555728'),
|
negotiator.calculateClientProof(
|
||||||
HEX.decode('5d7138c486b0bfabdf49e3e2da8bd6e5c79db613'),
|
HEX.decode('e234c47bf6c36696dd6d852b99aaa2ba26555728'),
|
||||||
),
|
HEX.decode('5d7138c486b0bfabdf49e3e2da8bd6e5c79db613'),
|
||||||
),
|
),
|
||||||
'bf45fcbf7073d93d022466c94321745fe1c8e13b',
|
),
|
||||||
);
|
'bf45fcbf7073d93d022466c94321745fe1c8e13b',
|
||||||
|
);
|
||||||
|
|
||||||
expect(await negotiator.calculateChallengeResponse('cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng=='), 'c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=');
|
expect(
|
||||||
|
await negotiator.calculateChallengeResponse(
|
||||||
|
'cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==',
|
||||||
|
),
|
||||||
|
'c=biws,r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts=',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test SASL SCRAM-SHA-256', () async {
|
test('Test SASL SCRAM-SHA-256', () async {
|
||||||
String? lastMessage;
|
String? lastMessage;
|
||||||
final negotiator = SaslScramNegotiator(0, 'n=user,r=rOprNGfwEbeRWgbNEkqO', 'rOprNGfwEbeRWgbNEkqO', ScramHashType.sha256);
|
final negotiator = SaslScramNegotiator(
|
||||||
negotiator.register(
|
0,
|
||||||
|
'n=user,r=rOprNGfwEbeRWgbNEkqO',
|
||||||
|
'rOprNGfwEbeRWgbNEkqO',
|
||||||
|
ScramHashType.sha256,
|
||||||
|
)..register(
|
||||||
NegotiatorAttributes(
|
NegotiatorAttributes(
|
||||||
(XMLNode n, {String? redact}) => lastMessage = n.innerText(),
|
(XMLNode n, {String? redact}) => lastMessage = n.innerText(),
|
||||||
() => ConnectionSettings(jid: JID.fromString('user@server'), password: 'pencil', useDirectTLS: true),
|
() => ConnectionSettings(
|
||||||
|
jid: JID.fromString('user@server'),
|
||||||
|
password: 'pencil',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
(_) async {},
|
(_) async {},
|
||||||
getNegotiatorNullStub,
|
getNegotiatorNullStub,
|
||||||
getManagerNullStub,
|
getManagerNullStub,
|
||||||
@ -116,29 +153,45 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
await negotiator.negotiate(scramSha256StreamFeatures);
|
await negotiator.negotiate(scramSha256StreamFeatures);
|
||||||
expect(
|
expect(
|
||||||
utf8.decode(base64Decode(lastMessage!)),
|
utf8.decode(base64Decode(lastMessage!)),
|
||||||
'n,,n=user,r=rOprNGfwEbeRWgbNEkqO',
|
'n,,n=user,r=rOprNGfwEbeRWgbNEkqO',
|
||||||
);
|
);
|
||||||
|
|
||||||
await negotiator.negotiate(XMLNode.fromString("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1yT3ByTkdmd0ViZVJXZ2JORWtxTyVodllEcFdVYTJSYVRDQWZ1eEZJbGopaE5sRiRrMCxzPVcyMlphSjBTTlk3c29Fc1VFamI2Z1E9PSxpPTQwOTY=</challenge>"));
|
|
||||||
expect(
|
|
||||||
utf8.decode(base64Decode(lastMessage!)),
|
|
||||||
'c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF\$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=',
|
|
||||||
);
|
|
||||||
|
|
||||||
final result = await negotiator.negotiate(XMLNode.fromString("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj02cnJpVFJCaTIzV3BSUi93dHVwK21NaFVaVW4vZEI1bkxUSlJzamw5NUc0PQ==</success>"));
|
await negotiator.negotiate(
|
||||||
|
XMLNode.fromString(
|
||||||
|
"<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1yT3ByTkdmd0ViZVJXZ2JORWtxTyVodllEcFdVYTJSYVRDQWZ1eEZJbGopaE5sRiRrMCxzPVcyMlphSjBTTlk3c29Fc1VFamI2Z1E9PSxpPTQwOTY=</challenge>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
utf8.decode(base64Decode(lastMessage!)),
|
||||||
|
r'c=biws,r=rOprNGfwEbeRWgbNEkqO%hvYDpWUa2RaTCAfuxFIlj)hNlF$k0,p=dHzbZapWIk4jUhN+Ute9ytag9zjfMHgsqmmiz7AndVQ=',
|
||||||
|
);
|
||||||
|
|
||||||
expect(result.get<NegotiatorState>(), NegotiatorState.done);
|
final result = await negotiator.negotiate(
|
||||||
|
XMLNode.fromString(
|
||||||
|
"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj02cnJpVFJCaTIzV3BSUi93dHVwK21NaFVaVW4vZEI1bkxUSlJzamw5NUc0PQ==</success>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.get<NegotiatorState>(), NegotiatorState.done);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a positive server signature check', () async {
|
test('Test a positive server signature check', () async {
|
||||||
final negotiator = SaslScramNegotiator(0, 'n=user,r=fyko+d2lbbFgONRv9qkxdawL', 'fyko+d2lbbFgONRv9qkxdawL', ScramHashType.sha1);
|
final negotiator = SaslScramNegotiator(
|
||||||
negotiator.register(
|
0,
|
||||||
|
'n=user,r=fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
'fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
ScramHashType.sha1,
|
||||||
|
)..register(
|
||||||
NegotiatorAttributes(
|
NegotiatorAttributes(
|
||||||
(XMLNode _, {String? redact}) {},
|
(XMLNode _, {String? redact}) {},
|
||||||
() => ConnectionSettings(jid: JID.fromString('user@server'), password: 'pencil', useDirectTLS: true),
|
() => ConnectionSettings(
|
||||||
|
jid: JID.fromString('user@server'),
|
||||||
|
password: 'pencil',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
(_) async {},
|
(_) async {},
|
||||||
getNegotiatorNullStub,
|
getNegotiatorNullStub,
|
||||||
getManagerNullStub,
|
getManagerNullStub,
|
||||||
@ -148,19 +201,35 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
await negotiator.negotiate(scramSha1StreamFeatures);
|
await negotiator.negotiate(scramSha1StreamFeatures);
|
||||||
await negotiator.negotiate(XMLNode.fromString("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>"));
|
await negotiator.negotiate(
|
||||||
final result = await negotiator.negotiate(XMLNode.fromString("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1ybUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>"));
|
XMLNode.fromString(
|
||||||
|
"<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final result = await negotiator.negotiate(
|
||||||
|
XMLNode.fromString(
|
||||||
|
"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1ybUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
expect(result.get<NegotiatorState>(), NegotiatorState.done);
|
expect(result.get<NegotiatorState>(), NegotiatorState.done);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a negative server signature check', () async {
|
test('Test a negative server signature check', () async {
|
||||||
final negotiator = SaslScramNegotiator(0, 'n=user,r=fyko+d2lbbFgONRv9qkxdawL', 'fyko+d2lbbFgONRv9qkxdawL', ScramHashType.sha1);
|
final negotiator = SaslScramNegotiator(
|
||||||
negotiator.register(
|
0,
|
||||||
|
'n=user,r=fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
'fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
ScramHashType.sha1,
|
||||||
|
)..register(
|
||||||
NegotiatorAttributes(
|
NegotiatorAttributes(
|
||||||
(XMLNode _, {String? redact}) {},
|
(XMLNode _, {String? redact}) {},
|
||||||
() => ConnectionSettings(jid: JID.fromString('user@server'), password: 'pencil', useDirectTLS: true),
|
() => ConnectionSettings(
|
||||||
|
jid: JID.fromString('user@server'),
|
||||||
|
password: 'pencil',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
(_) async {},
|
(_) async {},
|
||||||
getNegotiatorNullStub,
|
getNegotiatorNullStub,
|
||||||
getManagerNullStub,
|
getManagerNullStub,
|
||||||
@ -170,23 +239,38 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
var result;
|
var result = await negotiator.negotiate(scramSha1StreamFeatures);
|
||||||
result = await negotiator.negotiate(scramSha1StreamFeatures);
|
expect(result.isType<NegotiatorState>(), true);
|
||||||
expect(result.isType<NegotiatorState>(), true);
|
|
||||||
|
|
||||||
result = await negotiator.negotiate(XMLNode.fromString("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>"));
|
result = await negotiator.negotiate(
|
||||||
expect(result.isType<NegotiatorState>(), true);
|
XMLNode.fromString(
|
||||||
|
"<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(result.isType<NegotiatorState>(), true);
|
||||||
|
|
||||||
result = await negotiator.negotiate(XMLNode.fromString("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1zbUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>"));
|
result = await negotiator.negotiate(
|
||||||
expect(result.isType<NegotiatorError>(), true);
|
XMLNode.fromString(
|
||||||
|
"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1zbUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(result.isType<NegotiatorError>(), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a resetting the SCRAM negotiator', () async {
|
test('Test a resetting the SCRAM negotiator', () async {
|
||||||
final negotiator = SaslScramNegotiator(0, 'n=user,r=fyko+d2lbbFgONRv9qkxdawL', 'fyko+d2lbbFgONRv9qkxdawL', ScramHashType.sha1);
|
final negotiator = SaslScramNegotiator(
|
||||||
negotiator.register(
|
0,
|
||||||
|
'n=user,r=fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
'fyko+d2lbbFgONRv9qkxdawL',
|
||||||
|
ScramHashType.sha1,
|
||||||
|
)..register(
|
||||||
NegotiatorAttributes(
|
NegotiatorAttributes(
|
||||||
(XMLNode _, {String? redact}) {},
|
(XMLNode _, {String? redact}) {},
|
||||||
() => ConnectionSettings(jid: JID.fromString('user@server'), password: 'pencil', useDirectTLS: true),
|
() => ConnectionSettings(
|
||||||
|
jid: JID.fromString('user@server'),
|
||||||
|
password: 'pencil',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
(_) async {},
|
(_) async {},
|
||||||
getNegotiatorNullStub,
|
getNegotiatorNullStub,
|
||||||
getManagerNullStub,
|
getManagerNullStub,
|
||||||
@ -196,16 +280,32 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
await negotiator.negotiate(scramSha1StreamFeatures);
|
await negotiator.negotiate(scramSha1StreamFeatures);
|
||||||
await negotiator.negotiate(XMLNode.fromString("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>"));
|
await negotiator.negotiate(
|
||||||
final result1 = await negotiator.negotiate(XMLNode.fromString("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1ybUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>"));
|
XMLNode.fromString(
|
||||||
expect(result1.get<NegotiatorState>(), NegotiatorState.done);
|
"<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final result1 = await negotiator.negotiate(
|
||||||
|
XMLNode.fromString(
|
||||||
|
"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1ybUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(result1.get<NegotiatorState>(), NegotiatorState.done);
|
||||||
|
|
||||||
// Reset and try again
|
// Reset and try again
|
||||||
negotiator.reset();
|
negotiator.reset();
|
||||||
await negotiator.negotiate(scramSha1StreamFeatures);
|
await negotiator.negotiate(scramSha1StreamFeatures);
|
||||||
await negotiator.negotiate(XMLNode.fromString("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>"));
|
await negotiator.negotiate(
|
||||||
final result2 = await negotiator.negotiate(XMLNode.fromString("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1ybUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>"));
|
XMLNode.fromString(
|
||||||
expect(result2.get<NegotiatorState>(), NegotiatorState.done);
|
"<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cj1meWtvK2QybGJiRmdPTlJ2OXFreGRhd0wzcmZjTkhZSlkxWlZ2V1ZzN2oscz1RU1hDUitRNnNlazhiZjkyLGk9NDA5Ng==</challenge>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final result2 = await negotiator.negotiate(
|
||||||
|
XMLNode.fromString(
|
||||||
|
"<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>dj1ybUY5cHFWOFM3c3VBb1pXamE0ZEpSa0ZzS1E9</success>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(result2.get<NegotiatorState>(), NegotiatorState.done);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,89 +1,151 @@
|
|||||||
import 'package:moxxmpp/moxxmpp.dart';
|
import 'package:moxxmpp/moxxmpp.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
final stanza1 = Stanza.iq(children: [
|
final stanza1 = Stanza.iq(
|
||||||
XMLNode.xmlns(tag: 'tag', xmlns: 'owo')
|
children: [XMLNode.xmlns(tag: 'tag', xmlns: 'owo')],
|
||||||
],);
|
);
|
||||||
final stanza2 = Stanza.message(children: [
|
final stanza2 = Stanza.message(
|
||||||
XMLNode.xmlns(tag: 'some-other-tag', xmlns: 'owo')
|
children: [XMLNode.xmlns(tag: 'some-other-tag', xmlns: 'owo')],
|
||||||
],);
|
);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('match all', () {
|
test('match all', () {
|
||||||
final handler = StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true, false, null, stanza));
|
final handler = StanzaHandler(
|
||||||
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
expect(handler.matches(Stanza.iq()), true);
|
expect(handler.matches(Stanza.iq()), true);
|
||||||
expect(handler.matches(Stanza.message()), true);
|
expect(handler.matches(Stanza.message()), true);
|
||||||
expect(handler.matches(Stanza.presence()), true);
|
expect(handler.matches(Stanza.presence()), true);
|
||||||
expect(handler.matches(stanza1), true);
|
expect(handler.matches(stanza1), true);
|
||||||
expect(handler.matches(stanza2), true);
|
expect(handler.matches(stanza2), true);
|
||||||
});
|
});
|
||||||
test('xmlns matching', () {
|
test('xmlns matching', () {
|
||||||
final handler = StanzaHandler(
|
final handler = StanzaHandler(
|
||||||
callback: (stanza, _) async => StanzaHandlerData(true, false, null, stanza),
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
tagXmlns: 'owo',
|
true,
|
||||||
);
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
tagXmlns: 'owo',
|
||||||
|
);
|
||||||
|
|
||||||
expect(handler.matches(Stanza.iq()), false);
|
expect(handler.matches(Stanza.iq()), false);
|
||||||
expect(handler.matches(Stanza.message()), false);
|
expect(handler.matches(Stanza.message()), false);
|
||||||
expect(handler.matches(Stanza.presence()), false);
|
expect(handler.matches(Stanza.presence()), false);
|
||||||
expect(handler.matches(stanza1), true);
|
expect(handler.matches(stanza1), true);
|
||||||
expect(handler.matches(stanza2), true);
|
expect(handler.matches(stanza2), true);
|
||||||
});
|
});
|
||||||
test('stanzaTag matching', () {
|
test('stanzaTag matching', () {
|
||||||
var run = false;
|
var run = false;
|
||||||
final handler = StanzaHandler(callback: (stanza, _) async {
|
final handler = StanzaHandler(
|
||||||
run = true;
|
callback: (stanza, _) async {
|
||||||
return StanzaHandlerData(true, false, null, stanza);
|
run = true;
|
||||||
}, stanzaTag: 'iq',);
|
return StanzaHandlerData(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
stanzaTag: 'iq',
|
||||||
|
);
|
||||||
|
|
||||||
expect(handler.matches(Stanza.iq()), true);
|
expect(handler.matches(Stanza.iq()), true);
|
||||||
expect(handler.matches(Stanza.message()), false);
|
expect(handler.matches(Stanza.message()), false);
|
||||||
expect(handler.matches(Stanza.presence()), false);
|
expect(handler.matches(Stanza.presence()), false);
|
||||||
expect(handler.matches(stanza1), true);
|
expect(handler.matches(stanza1), true);
|
||||||
expect(handler.matches(stanza2), false);
|
expect(handler.matches(stanza2), false);
|
||||||
|
|
||||||
handler.callback(stanza2, StanzaHandlerData(false, false, null, stanza2));
|
handler.callback(
|
||||||
expect(run, true);
|
stanza2,
|
||||||
|
StanzaHandlerData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
expect(run, true);
|
||||||
});
|
});
|
||||||
test('tagName matching', () {
|
test('tagName matching', () {
|
||||||
final handler = StanzaHandler(
|
final handler = StanzaHandler(
|
||||||
callback: (stanza, _) async => StanzaHandlerData(true, false, null, stanza),
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
tagName: 'tag',
|
true,
|
||||||
);
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
tagName: 'tag',
|
||||||
|
);
|
||||||
|
|
||||||
expect(handler.matches(Stanza.iq()), false);
|
expect(handler.matches(Stanza.iq()), false);
|
||||||
expect(handler.matches(Stanza.message()), false);
|
expect(handler.matches(Stanza.message()), false);
|
||||||
expect(handler.matches(Stanza.presence()), false);
|
expect(handler.matches(Stanza.presence()), false);
|
||||||
expect(handler.matches(stanza1), true);
|
expect(handler.matches(stanza1), true);
|
||||||
expect(handler.matches(stanza2), false);
|
expect(handler.matches(stanza2), false);
|
||||||
});
|
});
|
||||||
test('combined matching', () {
|
test('combined matching', () {
|
||||||
final handler = StanzaHandler(
|
final handler = StanzaHandler(
|
||||||
callback: (stanza, _) async => StanzaHandlerData(true, false, null, stanza),
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
tagName: 'tag',
|
true,
|
||||||
stanzaTag: 'iq',
|
false,
|
||||||
tagXmlns: 'owo',
|
null,
|
||||||
);
|
stanza,
|
||||||
|
),
|
||||||
|
tagName: 'tag',
|
||||||
|
stanzaTag: 'iq',
|
||||||
|
tagXmlns: 'owo',
|
||||||
|
);
|
||||||
|
|
||||||
expect(handler.matches(Stanza.iq()), false);
|
expect(handler.matches(Stanza.iq()), false);
|
||||||
expect(handler.matches(Stanza.message()), false);
|
expect(handler.matches(Stanza.message()), false);
|
||||||
expect(handler.matches(Stanza.presence()), false);
|
expect(handler.matches(Stanza.presence()), false);
|
||||||
expect(handler.matches(stanza1), true);
|
expect(handler.matches(stanza1), true);
|
||||||
expect(handler.matches(stanza2), false);
|
expect(handler.matches(stanza2), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('sorting', () {
|
test('sorting', () {
|
||||||
final handlerList = [
|
final handlerList = [
|
||||||
StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true, false, null, stanza), tagName: '1', priority: 100),
|
StanzaHandler(
|
||||||
StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true, false, null, stanza), tagName: '2'),
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
StanzaHandler(callback: (stanza, _) async => StanzaHandlerData(true, false, null, stanza), tagName: '3', priority: 50)
|
true,
|
||||||
];
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
tagName: '1',
|
||||||
|
priority: 100,
|
||||||
|
),
|
||||||
|
StanzaHandler(
|
||||||
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
tagName: '2',
|
||||||
|
),
|
||||||
|
StanzaHandler(
|
||||||
|
callback: (stanza, _) async => StanzaHandlerData(
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
tagName: '3',
|
||||||
|
priority: 50,
|
||||||
|
)
|
||||||
|
]..sort(stanzaHandlerSortComparator);
|
||||||
|
|
||||||
handlerList.sort(stanzaHandlerSortComparator);
|
expect(handlerList[0].tagName, '1');
|
||||||
|
expect(handlerList[1].tagName, '3');
|
||||||
expect(handlerList[0].tagName, '1');
|
expect(handlerList[2].tagName, '2');
|
||||||
expect(handlerList[1].tagName, '3');
|
|
||||||
expect(handlerList[2].tagName, '2');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,33 +5,79 @@ import 'helpers/xml.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Test stringxml', () {
|
test('Test stringxml', () {
|
||||||
final child = XMLNode(tag: 'uwu', attributes: { 'strength': 10 });
|
final child = XMLNode(tag: 'uwu', attributes: {'strength': 10});
|
||||||
final stanza = XMLNode.xmlns(tag: 'uwu-meter', xmlns: 'uwu', children: [ child ]);
|
final stanza =
|
||||||
expect(XMLNode(tag: 'iq', attributes: {'xmlns': 'uwu'}).toXml(), "<iq xmlns='uwu' />");
|
XMLNode.xmlns(tag: 'uwu-meter', xmlns: 'uwu', children: [child]);
|
||||||
expect(XMLNode.xmlns(tag: 'iq', xmlns: 'uwu', attributes: {'how': 'uwu'}).toXml(), "<iq xmlns='uwu' how='uwu' />");
|
expect(
|
||||||
expect(stanza.toXml(), "<uwu-meter xmlns='uwu'><uwu strength=10 /></uwu-meter>");
|
XMLNode(tag: 'iq', attributes: {'xmlns': 'uwu'}).toXml(),
|
||||||
|
"<iq xmlns='uwu' />",
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
XMLNode.xmlns(tag: 'iq', xmlns: 'uwu', attributes: {'how': 'uwu'})
|
||||||
|
.toXml(),
|
||||||
|
"<iq xmlns='uwu' how='uwu' />",
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
stanza.toXml(),
|
||||||
|
"<uwu-meter xmlns='uwu'><uwu strength=10 /></uwu-meter>",
|
||||||
|
);
|
||||||
|
|
||||||
expect(StreamHeaderNonza('uwu.server').toXml(), "<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='uwu.server' xml:lang='en'>");
|
expect(
|
||||||
|
StreamHeaderNonza('uwu.server').toXml(),
|
||||||
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='uwu.server' xml:lang='en'>",
|
||||||
|
);
|
||||||
|
|
||||||
expect(XMLNode(tag: 'text', attributes: {}, text: 'hallo').toXml(), '<text>hallo</text>');
|
expect(
|
||||||
expect(XMLNode(tag: 'text', attributes: { 'world': 'no' }, text: 'hallo').toXml(), "<text world='no'>hallo</text>");
|
XMLNode(tag: 'text', attributes: {}, text: 'hallo').toXml(),
|
||||||
expect(XMLNode(tag: 'text', attributes: {}, text: 'hallo').toXml(), '<text>hallo</text>');
|
'<text>hallo</text>',
|
||||||
expect(XMLNode(tag: 'text', attributes: {}, text: 'test').innerText(), 'test');
|
);
|
||||||
|
expect(
|
||||||
|
XMLNode(tag: 'text', attributes: {'world': 'no'}, text: 'hallo').toXml(),
|
||||||
|
"<text world='no'>hallo</text>",
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
XMLNode(tag: 'text', attributes: {}, text: 'hallo').toXml(),
|
||||||
|
'<text>hallo</text>',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
XMLNode(tag: 'text', attributes: {}, text: 'test').innerText(),
|
||||||
|
'test',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test XmlElement', () {
|
test('Test XmlElement', () {
|
||||||
expect(XMLNode.fromXmlElement(XmlDocument.parse("<root owo='uwu' />").firstElementChild!).toXml(), "<root owo='uwu' />");
|
expect(
|
||||||
|
XMLNode.fromXmlElement(
|
||||||
|
XmlDocument.parse("<root owo='uwu' />").firstElementChild!,
|
||||||
|
).toXml(),
|
||||||
|
"<root owo='uwu' />",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test the find functions', () {
|
test('Test the find functions', () {
|
||||||
final node1 = XMLNode.fromString('<message><a xmlns="a" /><body>Hallo</body></message>');
|
final node1 = XMLNode.fromString(
|
||||||
|
'<message><a xmlns="a" /><body>Hallo</body></message>',
|
||||||
|
);
|
||||||
|
|
||||||
expect(compareXMLNodes(node1.firstTag('body')!, XMLNode.fromString('<body>Hallo</body>')), true);
|
expect(
|
||||||
expect(compareXMLNodes(node1.firstTagByXmlns('a')!, XMLNode.fromString('<a xmlns="a" />')), true);
|
compareXMLNodes(
|
||||||
|
node1.firstTag('body')!,
|
||||||
|
XMLNode.fromString('<body>Hallo</body>'),
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
compareXMLNodes(
|
||||||
|
node1.firstTagByXmlns('a')!,
|
||||||
|
XMLNode.fromString('<a xmlns="a" />'),
|
||||||
|
),
|
||||||
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test compareXMLNodes', () {
|
test('Test compareXMLNodes', () {
|
||||||
final node1 = XMLNode.fromString('''
|
final node1 = XMLNode.fromString(
|
||||||
|
'''
|
||||||
<iq type='set' id='0327c373-2e34-46bd-ab7f-1274a6f7095f' to='pubsub.server.example.org' from='testuser@example.org/MU29eEZn' xmlns='jabber:client'>
|
<iq type='set' id='0327c373-2e34-46bd-ab7f-1274a6f7095f' to='pubsub.server.example.org' from='testuser@example.org/MU29eEZn' xmlns='jabber:client'>
|
||||||
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||||
<publish node='princely_musings'>
|
<publish node='princely_musings'>
|
||||||
@ -75,6 +121,12 @@ void main() {
|
|||||||
</iq>
|
</iq>
|
||||||
''');
|
''');
|
||||||
|
|
||||||
expect(compareXMLNodes(node1, node2, ignoreId: true), false);
|
expect(
|
||||||
|
compareXMLNodes(
|
||||||
|
node1,
|
||||||
|
node2,
|
||||||
|
),
|
||||||
|
false,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,29 @@
|
|||||||
import 'package:test/test.dart';
|
|
||||||
import 'package:moxxmpp/src/util/wait.dart';
|
import 'package:moxxmpp/src/util/wait.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Test adding and resolving', () async {
|
test('Test adding and resolving', () async {
|
||||||
// ID -> Milliseconds since epoch
|
// ID -> Milliseconds since epoch
|
||||||
final tracker = WaitForTracker<int, int>();
|
final tracker = WaitForTracker<int, int>();
|
||||||
|
|
||||||
int r2 = 0;
|
var r2 = 0;
|
||||||
int r3 = 0;
|
var r3 = 0;
|
||||||
|
|
||||||
// Queue some jobs
|
// Queue some jobs
|
||||||
final r1 = await tracker.waitFor(0);
|
final r1 = await tracker.waitFor(0);
|
||||||
expect(r1, null);
|
expect(r1, null);
|
||||||
|
|
||||||
tracker
|
// ignore: unawaited_futures
|
||||||
.waitFor(0)
|
tracker.waitFor(0).then((result) async {
|
||||||
.then((result) async {
|
expect(result != null, true);
|
||||||
expect(result != null, true);
|
r2 = await result!;
|
||||||
r2 = await result!;
|
});
|
||||||
});
|
|
||||||
tracker
|
// ignore: unawaited_futures
|
||||||
.waitFor(0)
|
tracker.waitFor(0).then((result) async {
|
||||||
.then((result) async {
|
expect(result != null, true);
|
||||||
expect(result != null, true);
|
r3 = await result!;
|
||||||
r3 = await result!;
|
});
|
||||||
});
|
|
||||||
|
|
||||||
final c = await tracker.waitFor(1);
|
final c = await tracker.waitFor(1);
|
||||||
expect(c, null);
|
expect(c, null);
|
||||||
|
@ -3,11 +3,15 @@ import 'package:test/test.dart';
|
|||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Parsing', () {
|
test('Parsing', () {
|
||||||
const testData = "<x xmlns='jabber:x:data' type='result'><field var='FORM_TYPE' type='hidden'><value>urn:xmpp:dataforms:softwareinfo</value></field><field var='ip_version' type='text-multi' ><value>ipv4</value><value>ipv6</value></field><field var='os'><value>Mac</value></field><field var='os_version'><value>10.5.1</value></field><field var='software'><value>Psi</value></field><field var='software_version'><value>0.11</value></field></x>";
|
const testData =
|
||||||
|
"<x xmlns='jabber:x:data' type='result'><field var='FORM_TYPE' type='hidden'><value>urn:xmpp:dataforms:softwareinfo</value></field><field var='ip_version' type='text-multi' ><value>ipv4</value><value>ipv6</value></field><field var='os'><value>Mac</value></field><field var='os_version'><value>10.5.1</value></field><field var='software'><value>Psi</value></field><field var='software_version'><value>0.11</value></field></x>";
|
||||||
|
|
||||||
final form = parseDataForm(XMLNode.fromString(testData));
|
final form = parseDataForm(XMLNode.fromString(testData));
|
||||||
expect(form.getFieldByVar('FORM_TYPE')?.values.first, 'urn:xmpp:dataforms:softwareinfo');
|
expect(
|
||||||
expect(form.getFieldByVar('ip_version')?.values, [ 'ipv4', 'ipv6' ]);
|
form.getFieldByVar('FORM_TYPE')?.values.first,
|
||||||
|
'urn:xmpp:dataforms:softwareinfo',
|
||||||
|
);
|
||||||
|
expect(form.getFieldByVar('ip_version')?.values, ['ipv4', 'ipv6']);
|
||||||
expect(form.getFieldByVar('os')?.values.first, 'Mac');
|
expect(form.getFieldByVar('os')?.values.first, 'Mac');
|
||||||
expect(form.getFieldByVar('os_version')?.values.first, '10.5.1');
|
expect(form.getFieldByVar('os_version')?.values.first, '10.5.1');
|
||||||
expect(form.getFieldByVar('software')?.values.first, 'Psi');
|
expect(form.getFieldByVar('software')?.values.first, 'Psi');
|
||||||
|
@ -28,7 +28,7 @@ void main() {
|
|||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />'
|
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
@ -64,54 +64,55 @@ void main() {
|
|||||||
"<iq type='get' id='ec325efc-9924-4c48-93f8-ed34a2b0e5fc' to='romeo@montague.lit/orchard' from='polynomdivision@test.server/MU29eEZn' xmlns='jabber:client'><query xmlns='http://jabber.org/protocol/disco#info' /></iq>",
|
"<iq type='get' id='ec325efc-9924-4c48-93f8-ed34a2b0e5fc' to='romeo@montague.lit/orchard' from='polynomdivision@test.server/MU29eEZn' xmlns='jabber:client'><query xmlns='http://jabber.org/protocol/disco#info' /></iq>",
|
||||||
'',
|
'',
|
||||||
ignoreId: true,
|
ignoreId: true,
|
||||||
adjustId: false,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
final XmppConnection conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
)..setConnectionSettings(
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
),
|
||||||
conn.registerManagers([
|
);
|
||||||
|
await conn.registerManagers([
|
||||||
PresenceManager(),
|
PresenceManager(),
|
||||||
RosterManager(TestingRosterStateManager(null, [])),
|
RosterManager(TestingRosterStateManager(null, [])),
|
||||||
DiscoManager([]),
|
DiscoManager([]),
|
||||||
PingManager(),
|
PingManager(),
|
||||||
EntityCapabilitiesManager('http://moxxmpp.example'),
|
EntityCapabilitiesManager('http://moxxmpp.example'),
|
||||||
]);
|
]);
|
||||||
conn.registerFeatureNegotiators(
|
conn.registerFeatureNegotiators([
|
||||||
[
|
SaslPlainNegotiator(),
|
||||||
SaslPlainNegotiator(),
|
SaslScramNegotiator(10, '', '', ScramHashType.sha512),
|
||||||
SaslScramNegotiator(10, '', '', ScramHashType.sha512),
|
ResourceBindingNegotiator(),
|
||||||
ResourceBindingNegotiator(),
|
]);
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
final disco = conn.getManagerById<DiscoManager>(discoManager)!;
|
final disco = conn.getManagerById<DiscoManager>(discoManager)!;
|
||||||
|
|
||||||
await conn.connect();
|
await conn.connect();
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
await Future<void>.delayed(const Duration(seconds: 3));
|
||||||
|
|
||||||
final jid = JID.fromString('romeo@montague.lit/orchard');
|
final jid = JID.fromString('romeo@montague.lit/orchard');
|
||||||
final result1 = disco.discoInfoQuery(jid.toString());
|
final result1 = disco.discoInfoQuery(jid.toString());
|
||||||
final result2 = disco.discoInfoQuery(jid.toString());
|
final result2 = disco.discoInfoQuery(jid.toString());
|
||||||
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future<void>.delayed(const Duration(seconds: 1));
|
||||||
expect(
|
expect(
|
||||||
disco.infoTracker.getRunningTasks(DiscoCacheKey(jid.toString(), null)).length,
|
disco.infoTracker
|
||||||
|
.getRunningTasks(DiscoCacheKey(jid.toString(), null))
|
||||||
|
.length,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
fakeSocket.injectRawXml("<iq type='result' id='${fakeSocket.lastId!}' from='romeo@montague.lit/orchard' to='polynomdivision@test.server/MU29eEZn' xmlns='jabber:client'><query xmlns='http://jabber.org/protocol/disco#info' /></iq>");
|
fakeSocket.injectRawXml(
|
||||||
|
"<iq type='result' id='${fakeSocket.lastId!}' from='romeo@montague.lit/orchard' to='polynomdivision@test.server/MU29eEZn' xmlns='jabber:client'><query xmlns='http://jabber.org/protocol/disco#info' /></iq>",
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
);
|
||||||
|
|
||||||
|
await Future<void>.delayed(const Duration(seconds: 2));
|
||||||
|
|
||||||
expect(fakeSocket.getState(), 6);
|
expect(fakeSocket.getState(), 6);
|
||||||
expect(await result1, await result2);
|
expect(await result1, await result2);
|
||||||
expect(disco.infoTracker.hasTasksRunning(), false);
|
expect(disco.infoTracker.hasTasksRunning(), false);
|
||||||
|
@ -11,16 +11,18 @@ class StubbedDiscoManager extends DiscoManager {
|
|||||||
final bool _itemError;
|
final bool _itemError;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<DiscoError, DiscoInfo>> discoInfoQuery(String entity, { String? node, bool shouldEncrypt = true }) async {
|
Future<Result<DiscoError, DiscoInfo>> discoInfoQuery(
|
||||||
|
String entity, {
|
||||||
|
String? node,
|
||||||
|
bool shouldEncrypt = true,
|
||||||
|
}) async {
|
||||||
final result = DiscoInfo.fromQuery(
|
final result = DiscoInfo.fromQuery(
|
||||||
XMLNode.fromString(
|
XMLNode.fromString('''
|
||||||
'''
|
|
||||||
<query xmlns='http://jabber.org/protocol/disco#info'>
|
<query xmlns='http://jabber.org/protocol/disco#info'>
|
||||||
<identity category='pubsub' type='service' />
|
<identity category='pubsub' type='service' />
|
||||||
<feature var="http://jabber.org/protocol/pubsub" />
|
<feature var="http://jabber.org/protocol/pubsub" />
|
||||||
<feature var="http://jabber.org/protocol/pubsub#multi-items" />
|
<feature var="http://jabber.org/protocol/pubsub#multi-items" />
|
||||||
</query>'''
|
</query>'''),
|
||||||
),
|
|
||||||
JID.fromString('pubsub.server.example.org'),
|
JID.fromString('pubsub.server.example.org'),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -28,7 +30,11 @@ class StubbedDiscoManager extends DiscoManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Result<DiscoError, List<DiscoItem>>> discoItemsQuery(String entity, {String? node, bool shouldEncrypt = true}) async {
|
Future<Result<DiscoError, List<DiscoItem>>> discoItemsQuery(
|
||||||
|
String entity, {
|
||||||
|
String? node,
|
||||||
|
bool shouldEncrypt = true,
|
||||||
|
}) async {
|
||||||
if (_itemError) {
|
if (_itemError) {
|
||||||
return Result(
|
return Result(
|
||||||
UnknownDiscoError(),
|
UnknownDiscoError(),
|
||||||
@ -39,13 +45,15 @@ class StubbedDiscoManager extends DiscoManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
test('Test pre-processing with pubsub#max_items when the server does not support it (1/2)', () async {
|
test(
|
||||||
|
'Test pre-processing with pubsub#max_items when the server does not support it (1/2)',
|
||||||
|
() async {
|
||||||
final manager = PubSubManager();
|
final manager = PubSubManager();
|
||||||
final TestingManagerHolder tm = TestingManagerHolder();
|
final tm = TestingManagerHolder();
|
||||||
await tm.register(StubbedDiscoManager(false));
|
await tm.register(StubbedDiscoManager(false));
|
||||||
await tm.register(manager);
|
await tm.register(manager);
|
||||||
|
|
||||||
@ -58,9 +66,11 @@ void main() {
|
|||||||
expect(result.maxItems, '1');
|
expect(result.maxItems, '1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test pre-processing with pubsub#max_items when the server does not support it (2/2)', () async {
|
test(
|
||||||
|
'Test pre-processing with pubsub#max_items when the server does not support it (2/2)',
|
||||||
|
() async {
|
||||||
final manager = PubSubManager();
|
final manager = PubSubManager();
|
||||||
final TestingManagerHolder tm = TestingManagerHolder();
|
final tm = TestingManagerHolder();
|
||||||
await tm.register(StubbedDiscoManager(true));
|
await tm.register(StubbedDiscoManager(true));
|
||||||
await tm.register(manager);
|
await tm.register(manager);
|
||||||
|
|
||||||
@ -73,7 +83,9 @@ void main() {
|
|||||||
expect(result.maxItems, '1');
|
expect(result.maxItems, '1');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test publishing with pubsub#max_items when the server does not support it', () async {
|
test(
|
||||||
|
'Test publishing with pubsub#max_items when the server does not support it',
|
||||||
|
() async {
|
||||||
final socket = StubTCPSocket.authenticated(
|
final socket = StubTCPSocket.authenticated(
|
||||||
TestingManagerHolder.settings,
|
TestingManagerHolder.settings,
|
||||||
[
|
[
|
||||||
@ -158,24 +170,26 @@ void main() {
|
|||||||
RosterManager(TestingRosterStateManager(null, [])),
|
RosterManager(TestingRosterStateManager(null, [])),
|
||||||
PingManager(),
|
PingManager(),
|
||||||
]);
|
]);
|
||||||
connection..registerFeatureNegotiators([
|
connection
|
||||||
SaslPlainNegotiator(),
|
..registerFeatureNegotiators([
|
||||||
ResourceBindingNegotiator(),
|
SaslPlainNegotiator(),
|
||||||
])
|
ResourceBindingNegotiator(),
|
||||||
..setConnectionSettings(TestingManagerHolder.settings);
|
])
|
||||||
|
..setConnectionSettings(TestingManagerHolder.settings);
|
||||||
await connection.connect(
|
await connection.connect(
|
||||||
waitUntilLogin: true,
|
waitUntilLogin: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
final item = XMLNode(tag: "test-item");
|
final item = XMLNode(tag: 'test-item');
|
||||||
final result = await connection.getManagerById<PubSubManager>(pubsubManager)!.publish(
|
final result =
|
||||||
'pubsub.server.example.org',
|
await connection.getManagerById<PubSubManager>(pubsubManager)!.publish(
|
||||||
'princely_musings',
|
'pubsub.server.example.org',
|
||||||
item,
|
'princely_musings',
|
||||||
id: 'current',
|
item,
|
||||||
options: const PubSubPublishOptions(maxItems: 'max'),
|
id: 'current',
|
||||||
);
|
options: const PubSubPublishOptions(maxItems: 'max'),
|
||||||
|
);
|
||||||
|
|
||||||
expect(result.isType<bool>(), true);
|
expect(result.isType<bool>(), true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,20 +5,20 @@ import 'package:test/test.dart';
|
|||||||
void main() {
|
void main() {
|
||||||
test('Test XEP example', () async {
|
test('Test XEP example', () async {
|
||||||
final data = DiscoInfo(
|
final data = DiscoInfo(
|
||||||
[
|
const [
|
||||||
'http://jabber.org/protocol/caps',
|
'http://jabber.org/protocol/caps',
|
||||||
'http://jabber.org/protocol/disco#info',
|
'http://jabber.org/protocol/disco#info',
|
||||||
'http://jabber.org/protocol/disco#items',
|
'http://jabber.org/protocol/disco#items',
|
||||||
'http://jabber.org/protocol/muc'
|
'http://jabber.org/protocol/muc'
|
||||||
],
|
],
|
||||||
[
|
const [
|
||||||
Identity(
|
Identity(
|
||||||
category: 'client',
|
category: 'client',
|
||||||
type: 'pc',
|
type: 'pc',
|
||||||
name: 'Exodus 0.9.1',
|
name: 'Exodus 0.9.1',
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[],
|
const [],
|
||||||
null,
|
null,
|
||||||
JID.fromString('some@user.local/test'),
|
JID.fromString('some@user.local/test'),
|
||||||
);
|
);
|
||||||
@ -28,29 +28,30 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Test complex generation example', () async {
|
test('Test complex generation example', () async {
|
||||||
const extDiscoDataString = "<x xmlns='jabber:x:data' type='result'><field var='FORM_TYPE' type='hidden'><value>urn:xmpp:dataforms:softwareinfo</value></field><field var='ip_version' type='text-multi' ><value>ipv4</value><value>ipv6</value></field><field var='os'><value>Mac</value></field><field var='os_version'><value>10.5.1</value></field><field var='software'><value>Psi</value></field><field var='software_version'><value>0.11</value></field></x>";
|
const extDiscoDataString =
|
||||||
|
"<x xmlns='jabber:x:data' type='result'><field var='FORM_TYPE' type='hidden'><value>urn:xmpp:dataforms:softwareinfo</value></field><field var='ip_version' type='text-multi' ><value>ipv4</value><value>ipv6</value></field><field var='os'><value>Mac</value></field><field var='os_version'><value>10.5.1</value></field><field var='software'><value>Psi</value></field><field var='software_version'><value>0.11</value></field></x>";
|
||||||
final data = DiscoInfo(
|
final data = DiscoInfo(
|
||||||
[
|
const [
|
||||||
'http://jabber.org/protocol/caps',
|
'http://jabber.org/protocol/caps',
|
||||||
'http://jabber.org/protocol/disco#info',
|
'http://jabber.org/protocol/disco#info',
|
||||||
'http://jabber.org/protocol/disco#items',
|
'http://jabber.org/protocol/disco#items',
|
||||||
'http://jabber.org/protocol/muc'
|
'http://jabber.org/protocol/muc'
|
||||||
],
|
],
|
||||||
[
|
const [
|
||||||
const Identity(
|
Identity(
|
||||||
category: 'client',
|
category: 'client',
|
||||||
type: 'pc',
|
type: 'pc',
|
||||||
name: 'Psi 0.11',
|
name: 'Psi 0.11',
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
),
|
),
|
||||||
const Identity(
|
Identity(
|
||||||
category: 'client',
|
category: 'client',
|
||||||
type: 'pc',
|
type: 'pc',
|
||||||
name: 'Ψ 0.11',
|
name: 'Ψ 0.11',
|
||||||
lang: 'el',
|
lang: 'el',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
[ parseDataForm(XMLNode.fromString(extDiscoDataString)) ],
|
[parseDataForm(XMLNode.fromString(extDiscoDataString))],
|
||||||
null,
|
null,
|
||||||
JID.fromString('some@user.local/test'),
|
JID.fromString('some@user.local/test'),
|
||||||
);
|
);
|
||||||
@ -58,9 +59,9 @@ void main() {
|
|||||||
final hash = await calculateCapabilityHash(data, Sha1());
|
final hash = await calculateCapabilityHash(data, Sha1());
|
||||||
expect(hash, 'q07IKJEyjvHSyhy//CH0CxmKi8w=');
|
expect(hash, 'q07IKJEyjvHSyhy//CH0CxmKi8w=');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test Gajim capability hash computation', () async {
|
test('Test Gajim capability hash computation', () async {
|
||||||
// TODO: This one fails
|
// TODO(Unknown): This one fails
|
||||||
/*
|
/*
|
||||||
final data = DiscoInfo(
|
final data = DiscoInfo(
|
||||||
features: [
|
features: [
|
||||||
@ -120,7 +121,7 @@ void main() {
|
|||||||
|
|
||||||
test('Test Conversations hash computation', () async {
|
test('Test Conversations hash computation', () async {
|
||||||
final data = DiscoInfo(
|
final data = DiscoInfo(
|
||||||
[
|
const [
|
||||||
'eu.siacs.conversations.axolotl.devicelist+notify',
|
'eu.siacs.conversations.axolotl.devicelist+notify',
|
||||||
'http://jabber.org/protocol/caps',
|
'http://jabber.org/protocol/caps',
|
||||||
'http://jabber.org/protocol/chatstates',
|
'http://jabber.org/protocol/chatstates',
|
||||||
@ -152,14 +153,14 @@ void main() {
|
|||||||
'urn:xmpp:receipts',
|
'urn:xmpp:receipts',
|
||||||
'urn:xmpp:time'
|
'urn:xmpp:time'
|
||||||
],
|
],
|
||||||
[
|
const [
|
||||||
Identity(
|
Identity(
|
||||||
category: 'client',
|
category: 'client',
|
||||||
type: 'phone',
|
type: 'phone',
|
||||||
name: 'Conversations',
|
name: 'Conversations',
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
[],
|
const [],
|
||||||
null,
|
null,
|
||||||
JID.fromString('user@server.local/test'),
|
JID.fromString('user@server.local/test'),
|
||||||
);
|
);
|
||||||
|
@ -3,21 +3,54 @@ import 'package:test/test.dart';
|
|||||||
import '../helpers/logging.dart';
|
import '../helpers/logging.dart';
|
||||||
import '../helpers/xmpp.dart';
|
import '../helpers/xmpp.dart';
|
||||||
|
|
||||||
Future<void> runIncomingStanzaHandlers(StreamManagementManager man, Stanza stanza) async {
|
Future<void> runIncomingStanzaHandlers(
|
||||||
|
StreamManagementManager man,
|
||||||
|
Stanza stanza,
|
||||||
|
) async {
|
||||||
for (final handler in man.getIncomingPreStanzaHandlers()) {
|
for (final handler in man.getIncomingPreStanzaHandlers()) {
|
||||||
if (handler.matches(stanza)) await handler.callback(stanza, StanzaHandlerData(false, false, null, stanza));
|
if (handler.matches(stanza)) {
|
||||||
|
await handler.callback(
|
||||||
|
stanza,
|
||||||
|
StanzaHandlerData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> runOutgoingStanzaHandlers(StreamManagementManager man, Stanza stanza) async {
|
Future<void> runOutgoingStanzaHandlers(
|
||||||
|
StreamManagementManager man,
|
||||||
|
Stanza stanza,
|
||||||
|
) async {
|
||||||
for (final handler in man.getOutgoingPostStanzaHandlers()) {
|
for (final handler in man.getOutgoingPostStanzaHandlers()) {
|
||||||
if (handler.matches(stanza)) await handler.callback(stanza, StanzaHandlerData(false, false, null, stanza));
|
if (handler.matches(stanza)) {
|
||||||
|
await handler.callback(
|
||||||
|
stanza,
|
||||||
|
StanzaHandlerData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XmppManagerAttributes mkAttributes(void Function(Stanza) callback) {
|
XmppManagerAttributes mkAttributes(void Function(Stanza) callback) {
|
||||||
return XmppManagerAttributes(
|
return XmppManagerAttributes(
|
||||||
sendStanza: (stanza, { StanzaFromType addFrom = StanzaFromType.full, bool addId = true, bool awaitable = true, bool encrypted = false, bool forceEncryption = false, }) async {
|
sendStanza: (
|
||||||
|
stanza, {
|
||||||
|
StanzaFromType addFrom = StanzaFromType.full,
|
||||||
|
bool addId = true,
|
||||||
|
bool awaitable = true,
|
||||||
|
bool encrypted = false,
|
||||||
|
bool forceEncryption = false,
|
||||||
|
}) async {
|
||||||
callback(stanza);
|
callback(stanza);
|
||||||
|
|
||||||
return Stanza.message();
|
return Stanza.message();
|
||||||
@ -33,12 +66,22 @@ XmppManagerAttributes mkAttributes(void Function(Stanza) callback) {
|
|||||||
isFeatureSupported: (_) => false,
|
isFeatureSupported: (_) => false,
|
||||||
getFullJID: () => JID.fromString('hallo@example.server/uwu'),
|
getFullJID: () => JID.fromString('hallo@example.server/uwu'),
|
||||||
getSocket: () => StubTCPSocket([]),
|
getSocket: () => StubTCPSocket([]),
|
||||||
getConnection: () => XmppConnection(TestingReconnectionPolicy(), AlwaysConnectedConnectivityManager(), StubTCPSocket([])),
|
getConnection: () => XmppConnection(
|
||||||
|
TestingReconnectionPolicy(),
|
||||||
|
AlwaysConnectedConnectivityManager(),
|
||||||
|
StubTCPSocket([]),
|
||||||
|
),
|
||||||
getNegotiatorById: getNegotiatorNullStub,
|
getNegotiatorById: getNegotiatorNullStub,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLNode mkAck(int h) => XMLNode.xmlns(tag: 'a', xmlns: 'urn:xmpp:sm:3', attributes: { 'h': h.toString() });
|
XMLNode mkAck(int h) => XMLNode.xmlns(
|
||||||
|
tag: 'a',
|
||||||
|
xmlns: 'urn:xmpp:sm:3',
|
||||||
|
attributes: {
|
||||||
|
'h': h.toString(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
initLogger();
|
initLogger();
|
||||||
@ -50,8 +93,7 @@ void main() {
|
|||||||
|
|
||||||
test('Test stream with SM enablement', () async {
|
test('Test stream with SM enablement', () async {
|
||||||
final attributes = mkAttributes((_) {});
|
final attributes = mkAttributes((_) {});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
|
|
||||||
// [...]
|
// [...]
|
||||||
// <enable /> // <enabled />
|
// <enable /> // <enabled />
|
||||||
@ -77,10 +119,10 @@ void main() {
|
|||||||
group('Acking', () {
|
group('Acking', () {
|
||||||
test('Test completely clearing the queue', () async {
|
test('Test completely clearing the queue', () async {
|
||||||
final attributes = mkAttributes((_) {});
|
final attributes = mkAttributes((_) {});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
|
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
await manager
|
||||||
|
.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
||||||
|
|
||||||
// Send a stanza 5 times
|
// Send a stanza 5 times
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
@ -93,11 +135,12 @@ void main() {
|
|||||||
});
|
});
|
||||||
test('Test partially clearing the queue', () async {
|
test('Test partially clearing the queue', () async {
|
||||||
final attributes = mkAttributes((_) {});
|
final attributes = mkAttributes((_) {});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
|
await manager.onXmppEvent(
|
||||||
|
StreamManagementEnabledEvent(resource: 'hallo'),
|
||||||
|
);
|
||||||
|
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
|
||||||
|
|
||||||
// Send a stanza 5 times
|
// Send a stanza 5 times
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
await runOutgoingStanzaHandlers(manager, stanza);
|
await runOutgoingStanzaHandlers(manager, stanza);
|
||||||
@ -109,11 +152,12 @@ void main() {
|
|||||||
});
|
});
|
||||||
test('Send an ack with h > c2s', () async {
|
test('Send an ack with h > c2s', () async {
|
||||||
final attributes = mkAttributes((_) {});
|
final attributes = mkAttributes((_) {});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
|
await manager.onXmppEvent(
|
||||||
|
StreamManagementEnabledEvent(resource: 'hallo'),
|
||||||
|
);
|
||||||
|
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
|
||||||
|
|
||||||
// Send a stanza 5 times
|
// Send a stanza 5 times
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
await runOutgoingStanzaHandlers(manager, stanza);
|
await runOutgoingStanzaHandlers(manager, stanza);
|
||||||
@ -126,11 +170,12 @@ void main() {
|
|||||||
});
|
});
|
||||||
test('Send an ack with h < c2s', () async {
|
test('Send an ack with h < c2s', () async {
|
||||||
final attributes = mkAttributes((_) {});
|
final attributes = mkAttributes((_) {});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
|
await manager.onXmppEvent(
|
||||||
|
StreamManagementEnabledEvent(resource: 'hallo'),
|
||||||
|
);
|
||||||
|
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
|
||||||
|
|
||||||
// Send a stanza 5 times
|
// Send a stanza 5 times
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
await runOutgoingStanzaHandlers(manager, stanza);
|
await runOutgoingStanzaHandlers(manager, stanza);
|
||||||
@ -146,9 +191,10 @@ void main() {
|
|||||||
group('Counting acks', () {
|
group('Counting acks', () {
|
||||||
test('Sending all pending acks at once', () async {
|
test('Sending all pending acks at once', () async {
|
||||||
final attributes = mkAttributes((_) {});
|
final attributes = mkAttributes((_) {});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
await manager.onXmppEvent(
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
StreamManagementEnabledEvent(resource: 'hallo'),
|
||||||
|
);
|
||||||
|
|
||||||
// Send a stanza 5 times
|
// Send a stanza 5 times
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
@ -162,9 +208,10 @@ void main() {
|
|||||||
});
|
});
|
||||||
test('Sending partial pending acks at once', () async {
|
test('Sending partial pending acks at once', () async {
|
||||||
final attributes = mkAttributes((_) {});
|
final attributes = mkAttributes((_) {});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
await manager.onXmppEvent(
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
StreamManagementEnabledEvent(resource: 'hallo'),
|
||||||
|
);
|
||||||
|
|
||||||
// Send a stanza 5 times
|
// Send a stanza 5 times
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
@ -177,12 +224,12 @@ void main() {
|
|||||||
expect(await manager.getPendingAcks(), 2);
|
expect(await manager.getPendingAcks(), 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test counting incoming stanzas for which handlers end early', () async {
|
test('Test counting incoming stanzas for which handlers end early',
|
||||||
final fakeSocket = StubTCPSocket(
|
() async {
|
||||||
[
|
final fakeSocket = StubTCPSocket([
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -194,14 +241,14 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />'
|
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -219,31 +266,31 @@ void main() {
|
|||||||
<sm xmlns="urn:xmpp:sm:3"/>
|
<sm xmlns="urn:xmpp:sm:3"/>
|
||||||
</stream:features>
|
</stream:features>
|
||||||
''',
|
''',
|
||||||
),
|
),
|
||||||
StanzaExpectation(
|
StanzaExpectation(
|
||||||
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
||||||
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
||||||
ignoreId: true,
|
ignoreId: true,
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
||||||
'<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />',
|
'<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />',
|
||||||
),
|
),
|
||||||
]
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
final XmppConnection conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
)..setConnectionSettings(
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
),
|
||||||
|
);
|
||||||
final sm = StreamManagementManager();
|
final sm = StreamManagementManager();
|
||||||
conn.registerManagers([
|
await conn.registerManagers([
|
||||||
PresenceManager(),
|
PresenceManager(),
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
DiscoManager([]),
|
DiscoManager([]),
|
||||||
@ -252,20 +299,21 @@ void main() {
|
|||||||
CarbonsManager()..forceEnable(),
|
CarbonsManager()..forceEnable(),
|
||||||
EntityCapabilitiesManager('http://moxxmpp.example'),
|
EntityCapabilitiesManager('http://moxxmpp.example'),
|
||||||
]);
|
]);
|
||||||
conn.registerFeatureNegotiators(
|
conn.registerFeatureNegotiators([
|
||||||
[
|
SaslPlainNegotiator(),
|
||||||
SaslPlainNegotiator(),
|
ResourceBindingNegotiator(),
|
||||||
ResourceBindingNegotiator(),
|
StreamManagementNegotiator(),
|
||||||
StreamManagementNegotiator(),
|
]);
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
await conn.connect();
|
await conn.connect(
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
waitUntilLogin: true,
|
||||||
expect(fakeSocket.getState(), 6);
|
);
|
||||||
|
expect(fakeSocket.getState(), 5);
|
||||||
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
||||||
expect(
|
expect(
|
||||||
conn.getManagerById<StreamManagementManager>(smManager)!.isStreamManagementEnabled(),
|
conn
|
||||||
|
.getManagerById<StreamManagementManager>(smManager)!
|
||||||
|
.isStreamManagementEnabled(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -289,16 +337,15 @@ void main() {
|
|||||||
</message>
|
</message>
|
||||||
''');
|
''');
|
||||||
|
|
||||||
await Future.delayed(const Duration(seconds: 2));
|
await Future<void>.delayed(const Duration(seconds: 2));
|
||||||
expect(sm.state.s2c, 1);
|
expect(sm.state.s2c, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test counting incoming stanzas that are awaited', () async {
|
test('Test counting incoming stanzas that are awaited', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket([
|
||||||
[
|
StringExpectation(
|
||||||
StringExpectation(
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
'''
|
||||||
'''
|
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -310,14 +357,14 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />'
|
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -335,63 +382,64 @@ void main() {
|
|||||||
<sm xmlns="urn:xmpp:sm:3"/>
|
<sm xmlns="urn:xmpp:sm:3"/>
|
||||||
</stream:features>
|
</stream:features>
|
||||||
''',
|
''',
|
||||||
),
|
),
|
||||||
StanzaExpectation(
|
StanzaExpectation(
|
||||||
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
||||||
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
||||||
ignoreId: true,
|
ignoreId: true,
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
||||||
'<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />',
|
'<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
// StringExpectation(
|
||||||
"<presence xmlns='jabber:client' from='polynomdivision@test.server/MU29eEZn'><show>chat</show><c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://moxxmpp.example' ver='3QvQ2RAy45XBDhArjxy/vEWMl+E=' /></presence>",
|
// "<presence xmlns='jabber:client' from='polynomdivision@test.server/MU29eEZn'><show>chat</show></presence>",
|
||||||
'<iq type="result" />',
|
// '<iq type="result" />',
|
||||||
),
|
// ),
|
||||||
StanzaExpectation(
|
StanzaExpectation(
|
||||||
"<iq to='user@example.com' type='get' id='a' xmlns='jabber:client' />",
|
"<iq to='user@example.com' type='get' id='a' xmlns='jabber:client' />",
|
||||||
"<iq from='user@example.com' type='result' id='a' />",
|
"<iq from='user@example.com' type='result' id='a' />",
|
||||||
ignoreId: true,
|
ignoreId: true,
|
||||||
adjustId: true,
|
adjustId: true,
|
||||||
),
|
),
|
||||||
]
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
final XmppConnection conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
)..setConnectionSettings(
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
),
|
||||||
|
);
|
||||||
final sm = StreamManagementManager();
|
final sm = StreamManagementManager();
|
||||||
conn.registerManagers([
|
await conn.registerManagers([
|
||||||
PresenceManager(),
|
PresenceManager(),
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
DiscoManager([]),
|
DiscoManager([]),
|
||||||
PingManager(),
|
PingManager(),
|
||||||
sm,
|
sm,
|
||||||
CarbonsManager()..forceEnable(),
|
CarbonsManager()..forceEnable(),
|
||||||
EntityCapabilitiesManager('http://moxxmpp.example'),
|
//EntityCapabilitiesManager('http://moxxmpp.example'),
|
||||||
|
]);
|
||||||
|
conn.registerFeatureNegotiators([
|
||||||
|
SaslPlainNegotiator(),
|
||||||
|
ResourceBindingNegotiator(),
|
||||||
|
StreamManagementNegotiator(),
|
||||||
]);
|
]);
|
||||||
conn.registerFeatureNegotiators(
|
|
||||||
[
|
|
||||||
SaslPlainNegotiator(),
|
|
||||||
ResourceBindingNegotiator(),
|
|
||||||
StreamManagementNegotiator(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
await conn.connect();
|
await conn.connect(
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
waitUntilLogin: true,
|
||||||
expect(fakeSocket.getState(), 6);
|
);
|
||||||
|
expect(fakeSocket.getState(), 5);
|
||||||
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
||||||
expect(
|
expect(
|
||||||
conn.getManagerById<StreamManagementManager>(smManager)!.isStreamManagementEnabled(),
|
conn
|
||||||
|
.getManagerById<StreamManagementManager>(smManager)!
|
||||||
|
.isStreamManagementEnabled(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -404,7 +452,7 @@ void main() {
|
|||||||
addFrom: StanzaFromType.none,
|
addFrom: StanzaFromType.none,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(sm.state.s2c, 2);
|
expect(sm.state.s2c, /*2*/ 1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -412,12 +460,13 @@ void main() {
|
|||||||
test('Stanza retransmission', () async {
|
test('Stanza retransmission', () async {
|
||||||
var stanzaCount = 0;
|
var stanzaCount = 0;
|
||||||
final attributes = mkAttributes((_) {
|
final attributes = mkAttributes((_) {
|
||||||
stanzaCount++;
|
stanzaCount++;
|
||||||
});
|
});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
|
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
await manager.onXmppEvent(
|
||||||
|
StreamManagementEnabledEvent(resource: 'hallo'),
|
||||||
|
);
|
||||||
|
|
||||||
// Send 5 stanzas
|
// Send 5 stanzas
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
@ -438,21 +487,22 @@ void main() {
|
|||||||
test('Resumption with prior state', () async {
|
test('Resumption with prior state', () async {
|
||||||
var stanzaCount = 0;
|
var stanzaCount = 0;
|
||||||
final attributes = mkAttributes((_) {
|
final attributes = mkAttributes((_) {
|
||||||
stanzaCount++;
|
stanzaCount++;
|
||||||
});
|
});
|
||||||
final manager = StreamManagementManager();
|
final manager = StreamManagementManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
|
|
||||||
// [ ... ]
|
// [ ... ]
|
||||||
await manager.onXmppEvent(StreamManagementEnabledEvent(resource: 'hallo'));
|
await manager.onXmppEvent(
|
||||||
manager.setState(manager.state.copyWith(c2s: 150, s2c: 70));
|
StreamManagementEnabledEvent(resource: 'hallo'),
|
||||||
|
);
|
||||||
|
await manager.setState(manager.state.copyWith(c2s: 150, s2c: 70));
|
||||||
|
|
||||||
// Send some stanzas but don't ack them
|
// Send some stanzas but don't ack them
|
||||||
for (var i = 0; i < 5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
await runOutgoingStanzaHandlers(manager, stanza);
|
await runOutgoingStanzaHandlers(manager, stanza);
|
||||||
}
|
}
|
||||||
expect(manager.getUnackedStanzas().length, 5);
|
expect(manager.getUnackedStanzas().length, 5);
|
||||||
|
|
||||||
// Lose connection
|
// Lose connection
|
||||||
// [ Reconnect ]
|
// [ Reconnect ]
|
||||||
await manager.onXmppEvent(StreamResumedEvent(h: 150));
|
await manager.onXmppEvent(StreamResumedEvent(h: 150));
|
||||||
@ -463,11 +513,10 @@ void main() {
|
|||||||
|
|
||||||
group('Test the negotiator', () {
|
group('Test the negotiator', () {
|
||||||
test('Test successful stream enablement', () async {
|
test('Test successful stream enablement', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket([
|
||||||
[
|
StringExpectation(
|
||||||
StringExpectation(
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
'''
|
||||||
'''
|
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -479,14 +528,14 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />'
|
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -504,61 +553,61 @@ void main() {
|
|||||||
<sm xmlns="urn:xmpp:sm:3"/>
|
<sm xmlns="urn:xmpp:sm:3"/>
|
||||||
</stream:features>
|
</stream:features>
|
||||||
''',
|
''',
|
||||||
),
|
),
|
||||||
StanzaExpectation(
|
StanzaExpectation(
|
||||||
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
||||||
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
||||||
ignoreId: true
|
ignoreId: true,
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
||||||
'<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />'
|
'<enabled xmlns="urn:xmpp:sm:3" id="some-long-sm-id" resume="true" />',
|
||||||
)
|
)
|
||||||
]
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
final XmppConnection conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
)..setConnectionSettings(
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
),
|
||||||
conn.registerManagers([
|
);
|
||||||
PresenceManager(),
|
await conn.registerManagers([
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
PresenceManager(),
|
||||||
DiscoManager([]),
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
PingManager(),
|
DiscoManager([]),
|
||||||
StreamManagementManager(),
|
PingManager(),
|
||||||
|
StreamManagementManager(),
|
||||||
]);
|
]);
|
||||||
conn.registerFeatureNegotiators(
|
conn.registerFeatureNegotiators([
|
||||||
[
|
SaslPlainNegotiator(),
|
||||||
SaslPlainNegotiator(),
|
ResourceBindingNegotiator(),
|
||||||
ResourceBindingNegotiator(),
|
StreamManagementNegotiator(),
|
||||||
StreamManagementNegotiator(),
|
]);
|
||||||
]
|
|
||||||
|
await conn.connect(
|
||||||
|
waitUntilLogin: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
await conn.connect();
|
expect(fakeSocket.getState(), 5);
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
|
||||||
|
|
||||||
expect(fakeSocket.getState(), 6);
|
|
||||||
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
||||||
expect(
|
expect(
|
||||||
conn.getManagerById<StreamManagementManager>(smManager)!.isStreamManagementEnabled(),
|
conn
|
||||||
|
.getManagerById<StreamManagementManager>(smManager)!
|
||||||
|
.isStreamManagementEnabled(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a failed stream resumption', () async {
|
test('Test a failed stream resumption', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket([
|
||||||
[
|
StringExpectation(
|
||||||
StringExpectation(
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
'''
|
||||||
'''
|
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -570,14 +619,14 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />'
|
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -595,74 +644,71 @@ void main() {
|
|||||||
<sm xmlns="urn:xmpp:sm:3"/>
|
<sm xmlns="urn:xmpp:sm:3"/>
|
||||||
</stream:features>
|
</stream:features>
|
||||||
''',
|
''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<resume xmlns='urn:xmpp:sm:3' previd='id-1' h='10' />",
|
"<resume xmlns='urn:xmpp:sm:3' previd='id-1' h='10' />",
|
||||||
"<failed xmlns='urn:xmpp:sm:3' h='another-sequence-number'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></failed>",
|
"<failed xmlns='urn:xmpp:sm:3' h='another-sequence-number'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></failed>",
|
||||||
),
|
),
|
||||||
StanzaExpectation(
|
StanzaExpectation(
|
||||||
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
||||||
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
||||||
ignoreId: true
|
ignoreId: true,
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
||||||
'<enabled xmlns="urn:xmpp:sm:3" id="id-2" resume="true" />'
|
'<enabled xmlns="urn:xmpp:sm:3" id="id-2" resume="true" />',
|
||||||
)
|
)
|
||||||
]
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
final XmppConnection conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
)..setConnectionSettings(
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
|
||||||
conn.registerManagers([
|
|
||||||
PresenceManager(),
|
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
|
||||||
DiscoManager([]),
|
|
||||||
PingManager(),
|
|
||||||
StreamManagementManager(),
|
|
||||||
]);
|
|
||||||
conn.registerFeatureNegotiators(
|
|
||||||
[
|
|
||||||
SaslPlainNegotiator(),
|
|
||||||
ResourceBindingNegotiator(),
|
|
||||||
StreamManagementNegotiator(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
conn.getManagerById<StreamManagementManager>(smManager)!
|
|
||||||
.setState(
|
|
||||||
StreamManagementState(
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
streamResumptionId: 'id-1',
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
await conn.registerManagers([
|
||||||
|
PresenceManager(),
|
||||||
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
|
DiscoManager([]),
|
||||||
|
PingManager(),
|
||||||
|
StreamManagementManager(),
|
||||||
|
]);
|
||||||
|
conn.registerFeatureNegotiators([
|
||||||
|
SaslPlainNegotiator(),
|
||||||
|
ResourceBindingNegotiator(),
|
||||||
|
StreamManagementNegotiator(),
|
||||||
|
]);
|
||||||
|
await conn.getManagerById<StreamManagementManager>(smManager)!.setState(
|
||||||
|
StreamManagementState(
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
streamResumptionId: 'id-1',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
await conn.connect();
|
await conn.connect(
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
waitUntilLogin: true,
|
||||||
expect(fakeSocket.getState(), 7);
|
);
|
||||||
|
expect(fakeSocket.getState(), 6);
|
||||||
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
||||||
expect(
|
expect(
|
||||||
conn
|
conn
|
||||||
.getManagerById<StreamManagementManager>(smManager)!
|
.getManagerById<StreamManagementManager>(smManager)!
|
||||||
.isStreamManagementEnabled(),
|
.isStreamManagementEnabled(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a successful stream resumption', () async {
|
test('Test a successful stream resumption', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket([
|
||||||
[
|
StringExpectation(
|
||||||
StringExpectation(
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
'''
|
||||||
'''
|
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -674,14 +720,14 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />'
|
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -699,55 +745,53 @@ void main() {
|
|||||||
<sm xmlns="urn:xmpp:sm:3"/>
|
<sm xmlns="urn:xmpp:sm:3"/>
|
||||||
</stream:features>
|
</stream:features>
|
||||||
''',
|
''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<resume xmlns='urn:xmpp:sm:3' previd='id-1' h='10' />",
|
"<resume xmlns='urn:xmpp:sm:3' previd='id-1' h='10' />",
|
||||||
"<resumed xmlns='urn:xmpp:sm:3' h='id-1' h='12' />",
|
"<resumed xmlns='urn:xmpp:sm:3' h='id-1' h='12' />",
|
||||||
),
|
),
|
||||||
]
|
]);
|
||||||
);
|
|
||||||
|
|
||||||
final XmppConnection conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
)..setConnectionSettings(
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
|
||||||
conn.registerManagers([
|
|
||||||
PresenceManager(),
|
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
|
||||||
DiscoManager([]),
|
|
||||||
PingManager(),
|
|
||||||
StreamManagementManager(),
|
|
||||||
]);
|
|
||||||
conn.registerFeatureNegotiators(
|
|
||||||
[
|
|
||||||
SaslPlainNegotiator(),
|
|
||||||
ResourceBindingNegotiator(),
|
|
||||||
StreamManagementNegotiator(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
conn.getManagerById<StreamManagementManager>(smManager)!
|
|
||||||
.setState(
|
|
||||||
StreamManagementState(
|
|
||||||
10,
|
|
||||||
10,
|
|
||||||
streamResumptionId: 'id-1',
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
await conn.registerManagers([
|
||||||
|
PresenceManager(),
|
||||||
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
|
DiscoManager([]),
|
||||||
|
PingManager(),
|
||||||
|
StreamManagementManager(),
|
||||||
|
]);
|
||||||
|
conn.registerFeatureNegotiators([
|
||||||
|
SaslPlainNegotiator(),
|
||||||
|
ResourceBindingNegotiator(),
|
||||||
|
StreamManagementNegotiator(),
|
||||||
|
]);
|
||||||
|
await conn.getManagerById<StreamManagementManager>(smManager)!.setState(
|
||||||
|
StreamManagementState(
|
||||||
|
10,
|
||||||
|
10,
|
||||||
|
streamResumptionId: 'id-1',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
await conn.connect(lastResource: 'abc123');
|
await conn.connect(
|
||||||
await Future.delayed(const Duration(seconds: 3), () async {
|
lastResource: 'abc123',
|
||||||
expect(fakeSocket.getState(), 5);
|
waitUntilLogin: true,
|
||||||
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
);
|
||||||
final sm = conn.getManagerById<StreamManagementManager>(smManager)!;
|
expect(fakeSocket.getState(), 4);
|
||||||
expect(sm.isStreamManagementEnabled(), true);
|
expect(await conn.getConnectionState(), XmppConnectionState.connected);
|
||||||
expect(sm.streamResumed, true);
|
final sm = conn.getManagerById<StreamManagementManager>(smManager)!;
|
||||||
});
|
expect(sm.isStreamManagementEnabled(), true);
|
||||||
|
expect(sm.streamResumed, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,21 @@ import 'package:test/test.dart';
|
|||||||
import '../helpers/xmpp.dart';
|
import '../helpers/xmpp.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test("Test if we're vulnerable against CVE-2020-26547 style vulnerabilities", () async {
|
test("Test if we're vulnerable against CVE-2020-26547 style vulnerabilities",
|
||||||
|
() async {
|
||||||
final attributes = XmppManagerAttributes(
|
final attributes = XmppManagerAttributes(
|
||||||
sendStanza: (stanza, { StanzaFromType addFrom = StanzaFromType.full, bool addId = true, bool retransmitted = false, bool awaitable = true, bool encrypted = false, bool forceEncryption = false, }) async {
|
sendStanza: (
|
||||||
|
stanza, {
|
||||||
|
StanzaFromType addFrom = StanzaFromType.full,
|
||||||
|
bool addId = true,
|
||||||
|
bool retransmitted = false,
|
||||||
|
bool awaitable = true,
|
||||||
|
bool encrypted = false,
|
||||||
|
bool forceEncryption = false,
|
||||||
|
}) async {
|
||||||
// ignore: avoid_print
|
// ignore: avoid_print
|
||||||
print('==> ${stanza.toXml()}');
|
print('==> ${stanza.toXml()}');
|
||||||
return XMLNode(tag: 'iq', attributes: { 'type': 'result' });
|
return XMLNode(tag: 'iq', attributes: {'type': 'result'});
|
||||||
},
|
},
|
||||||
sendNonza: (nonza) {},
|
sendNonza: (nonza) {},
|
||||||
sendEvent: (event) {},
|
sendEvent: (event) {},
|
||||||
@ -21,15 +30,27 @@ void main() {
|
|||||||
isFeatureSupported: (_) => false,
|
isFeatureSupported: (_) => false,
|
||||||
getFullJID: () => JID.fromString('bob@xmpp.example/uwu'),
|
getFullJID: () => JID.fromString('bob@xmpp.example/uwu'),
|
||||||
getSocket: () => StubTCPSocket([]),
|
getSocket: () => StubTCPSocket([]),
|
||||||
getConnection: () => XmppConnection(TestingReconnectionPolicy(), AlwaysConnectedConnectivityManager(), StubTCPSocket([])),
|
getConnection: () => XmppConnection(
|
||||||
|
TestingReconnectionPolicy(),
|
||||||
|
AlwaysConnectedConnectivityManager(),
|
||||||
|
StubTCPSocket([]),
|
||||||
|
),
|
||||||
getNegotiatorById: getNegotiatorNullStub,
|
getNegotiatorById: getNegotiatorNullStub,
|
||||||
);
|
);
|
||||||
final manager = CarbonsManager();
|
final manager = CarbonsManager()..register(attributes);
|
||||||
manager.register(attributes);
|
|
||||||
await manager.enableCarbons();
|
await manager.enableCarbons();
|
||||||
|
|
||||||
expect(manager.isCarbonValid(JID.fromString('mallory@evil.example')), false);
|
expect(
|
||||||
expect(manager.isCarbonValid(JID.fromString('bob@xmpp.example')), true);
|
manager.isCarbonValid(JID.fromString('mallory@evil.example')),
|
||||||
expect(manager.isCarbonValid(JID.fromString('bob@xmpp.example/abc')), false);
|
false,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
manager.isCarbonValid(JID.fromString('bob@xmpp.example')),
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
manager.isCarbonValid(JID.fromString('bob@xmpp.example/abc')),
|
||||||
|
false,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ class MockedCSINegotiator extends CSINegotiator {
|
|||||||
MockedCSINegotiator(this._isSupported);
|
MockedCSINegotiator(this._isSupported);
|
||||||
|
|
||||||
final bool _isSupported;
|
final bool _isSupported;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isSupported => _isSupported;
|
bool get isSupported => _isSupported;
|
||||||
}
|
}
|
||||||
@ -31,58 +31,86 @@ void main() {
|
|||||||
group('Test the XEP-0352 implementation', () {
|
group('Test the XEP-0352 implementation', () {
|
||||||
test('Test setting the CSI state when CSI is unsupported', () {
|
test('Test setting the CSI state when CSI is unsupported', () {
|
||||||
var nonzaSent = false;
|
var nonzaSent = false;
|
||||||
final csi = CSIManager();
|
CSIManager()
|
||||||
csi.register(
|
..register(
|
||||||
XmppManagerAttributes(
|
XmppManagerAttributes(
|
||||||
sendStanza: (_, { StanzaFromType addFrom = StanzaFromType.full, bool addId = true, bool retransmitted = false, bool awaitable = true, bool encrypted = false, bool forceEncryption = false, }) async => XMLNode(tag: 'hallo'),
|
sendStanza: (
|
||||||
sendEvent: (event) {},
|
_, {
|
||||||
sendNonza: (nonza) {
|
StanzaFromType addFrom = StanzaFromType.full,
|
||||||
nonzaSent = true;
|
bool addId = true,
|
||||||
},
|
bool retransmitted = false,
|
||||||
getConnectionSettings: () => ConnectionSettings(
|
bool awaitable = true,
|
||||||
jid: JID.fromString('some.user@example.server'),
|
bool encrypted = false,
|
||||||
password: 'password',
|
bool forceEncryption = false,
|
||||||
useDirectTLS: true,
|
}) async =>
|
||||||
|
XMLNode(tag: 'hallo'),
|
||||||
|
sendEvent: (event) {},
|
||||||
|
sendNonza: (nonza) {
|
||||||
|
nonzaSent = true;
|
||||||
|
},
|
||||||
|
getConnectionSettings: () => ConnectionSettings(
|
||||||
|
jid: JID.fromString('some.user@example.server'),
|
||||||
|
password: 'password',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
|
getManagerById: getManagerNullStub,
|
||||||
|
getNegotiatorById: getUnsupportedCSINegotiator,
|
||||||
|
isFeatureSupported: (_) => false,
|
||||||
|
getFullJID: () => JID.fromString('some.user@example.server/aaaaa'),
|
||||||
|
getSocket: () => StubTCPSocket([]),
|
||||||
|
getConnection: () => XmppConnection(
|
||||||
|
TestingReconnectionPolicy(),
|
||||||
|
AlwaysConnectedConnectivityManager(),
|
||||||
|
StubTCPSocket([]),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
getManagerById: getManagerNullStub,
|
)
|
||||||
getNegotiatorById: getUnsupportedCSINegotiator,
|
..setActive()
|
||||||
isFeatureSupported: (_) => false,
|
..setInactive();
|
||||||
getFullJID: () => JID.fromString('some.user@example.server/aaaaa'),
|
|
||||||
getSocket: () => StubTCPSocket([]),
|
|
||||||
getConnection: () => XmppConnection(TestingReconnectionPolicy(), AlwaysConnectedConnectivityManager(), StubTCPSocket([])),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
csi.setActive();
|
|
||||||
csi.setInactive();
|
|
||||||
|
|
||||||
expect(nonzaSent, false, reason: 'Expected that no nonza is sent');
|
expect(nonzaSent, false, reason: 'Expected that no nonza is sent');
|
||||||
});
|
});
|
||||||
test('Test setting the CSI state when CSI is supported', () {
|
test('Test setting the CSI state when CSI is supported', () {
|
||||||
final csi = CSIManager();
|
CSIManager()
|
||||||
csi.register(
|
..register(
|
||||||
XmppManagerAttributes(
|
XmppManagerAttributes(
|
||||||
sendStanza: (_, { StanzaFromType addFrom = StanzaFromType.full, bool addId = true, bool retransmitted = false, bool awaitable = true, bool encrypted = false, bool forceEncryption = false, }) async => XMLNode(tag: 'hallo'),
|
sendStanza: (
|
||||||
sendEvent: (event) {},
|
_, {
|
||||||
sendNonza: (nonza) {
|
StanzaFromType addFrom = StanzaFromType.full,
|
||||||
expect(nonza.attributes['xmlns'] == csiXmlns, true, reason: "Expected only nonzas with XMLNS '$csiXmlns'");
|
bool addId = true,
|
||||||
},
|
bool retransmitted = false,
|
||||||
getConnectionSettings: () => ConnectionSettings(
|
bool awaitable = true,
|
||||||
jid: JID.fromString('some.user@example.server'),
|
bool encrypted = false,
|
||||||
password: 'password',
|
bool forceEncryption = false,
|
||||||
useDirectTLS: true,
|
}) async =>
|
||||||
|
XMLNode(tag: 'hallo'),
|
||||||
|
sendEvent: (event) {},
|
||||||
|
sendNonza: (nonza) {
|
||||||
|
expect(
|
||||||
|
nonza.attributes['xmlns'] == csiXmlns,
|
||||||
|
true,
|
||||||
|
reason: "Expected only nonzas with XMLNS '$csiXmlns'",
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getConnectionSettings: () => ConnectionSettings(
|
||||||
|
jid: JID.fromString('some.user@example.server'),
|
||||||
|
password: 'password',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
|
getManagerById: getManagerNullStub,
|
||||||
|
getNegotiatorById: getSupportedCSINegotiator,
|
||||||
|
isFeatureSupported: (_) => false,
|
||||||
|
getFullJID: () => JID.fromString('some.user@example.server/aaaaa'),
|
||||||
|
getSocket: () => StubTCPSocket([]),
|
||||||
|
getConnection: () => XmppConnection(
|
||||||
|
TestingReconnectionPolicy(),
|
||||||
|
AlwaysConnectedConnectivityManager(),
|
||||||
|
StubTCPSocket([]),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
getManagerById: getManagerNullStub,
|
)
|
||||||
getNegotiatorById: getSupportedCSINegotiator,
|
..setActive()
|
||||||
isFeatureSupported: (_) => false,
|
..setInactive();
|
||||||
getFullJID: () => JID.fromString('some.user@example.server/aaaaa'),
|
|
||||||
getSocket: () => StubTCPSocket([]),
|
|
||||||
getConnection: () => XmppConnection(TestingReconnectionPolicy(), AlwaysConnectedConnectivityManager(), StubTCPSocket([])),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
csi.setActive();
|
|
||||||
csi.setInactive();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -29,26 +29,20 @@ void main() {
|
|||||||
'Cookie': 'foo=bar; user=romeo',
|
'Cookie': 'foo=bar; user=romeo',
|
||||||
'X-Tracking': 'Base64String=='
|
'X-Tracking': 'Base64String=='
|
||||||
};
|
};
|
||||||
expect(
|
expect(prepareHeaders(headers), {
|
||||||
prepareHeaders(headers),
|
'Authorization': 'Basic Base64String==',
|
||||||
{
|
'Cookie': 'foo=bar; user=romeo',
|
||||||
'Authorization': 'Basic Base64String==',
|
});
|
||||||
'Cookie': 'foo=bar; user=romeo',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
test('remove newlines', () {
|
test('remove newlines', () {
|
||||||
final headers = {
|
final headers = {
|
||||||
'Authorization': '\n\nBasic Base64String==\n\n',
|
'Authorization': '\n\nBasic Base64String==\n\n',
|
||||||
'\nCookie\r\n': 'foo=bar; user=romeo',
|
'\nCookie\r\n': 'foo=bar; user=romeo',
|
||||||
};
|
};
|
||||||
expect(
|
expect(prepareHeaders(headers), {
|
||||||
prepareHeaders(headers),
|
'Authorization': 'Basic Base64String==',
|
||||||
{
|
'Cookie': 'foo=bar; user=romeo',
|
||||||
'Authorization': 'Basic Base64String==',
|
});
|
||||||
'Cookie': 'foo=bar; user=romeo',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,13 @@ void main() {
|
|||||||
'''),
|
'''),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(sfs.metadata.hashes['sha3-256'], '2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=');
|
expect(
|
||||||
expect(sfs.metadata.hashes['id-blake2b256'], '2AfMGH8O7UNPTvUVAM9aK13mpCY=');
|
sfs.metadata.hashes['sha3-256'],
|
||||||
|
'2XarmwTlNxDAMkvymloX3S5+VbylNrJt/l5QyPa+YoU=',
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
sfs.metadata.hashes['id-blake2b256'],
|
||||||
|
'2AfMGH8O7UNPTvUVAM9aK13mpCY=',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:test/test.dart';
|
|
||||||
import 'package:moxxmpp/moxxmpp.dart';
|
import 'package:moxxmpp/moxxmpp.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Test parsing a large sticker pack', () {
|
test('Test parsing a large sticker pack', () {
|
||||||
|
@ -10,15 +10,18 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Test building a multiline quote', () {
|
test('Test building a multiline quote', () {
|
||||||
final quote = QuoteData.fromBodies('Hallo Welt\nHallo Erde', 'How are you?');
|
final quote = QuoteData.fromBodies(
|
||||||
|
'Hallo Welt\nHallo Erde',
|
||||||
|
'How are you?',
|
||||||
|
);
|
||||||
|
|
||||||
expect(quote.body, '> Hallo Welt\n> Hallo Erde\nHow are you?');
|
expect(quote.body, '> Hallo Welt\n> Hallo Erde\nHow are you?');
|
||||||
expect(quote.fallbackLength, 26);
|
expect(quote.fallbackLength, 26);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Applying a singleline quote', () {
|
test('Applying a singleline quote', () {
|
||||||
final body = '> Hallo Welt\nHello right back!';
|
const body = '> Hallo Welt\nHello right back!';
|
||||||
final reply = ReplyData(
|
const reply = ReplyData(
|
||||||
to: '',
|
to: '',
|
||||||
id: '',
|
id: '',
|
||||||
start: 0,
|
start: 0,
|
||||||
@ -30,8 +33,8 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Applying a multiline quote', () {
|
test('Applying a multiline quote', () {
|
||||||
final body = "> Hallo Welt\n> How are you?\nI'm fine.\nThank you!";
|
const body = "> Hallo Welt\n> How are you?\nI'm fine.\nThank you!";
|
||||||
final reply = ReplyData(
|
const reply = ReplyData(
|
||||||
to: '',
|
to: '',
|
||||||
id: '',
|
id: '',
|
||||||
start: 0,
|
start: 0,
|
||||||
|
@ -10,22 +10,20 @@ void main() {
|
|||||||
final buffer = XmlStreamBuffer();
|
final buffer = XmlStreamBuffer();
|
||||||
final controller = StreamController<String>();
|
final controller = StreamController<String>();
|
||||||
|
|
||||||
controller
|
unawaited(
|
||||||
.stream
|
controller.stream.transform(buffer).forEach((node) {
|
||||||
.transform(buffer)
|
|
||||||
.forEach((node) {
|
|
||||||
if (node.tag == 'childa') {
|
if (node.tag == 'childa') {
|
||||||
childa = true;
|
childa = true;
|
||||||
} else if (node.tag == 'childb') {
|
} else if (node.tag == 'childb') {
|
||||||
childb = true;
|
childb = true;
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
controller.add('<childa /><childb />');
|
controller.add('<childa /><childb />');
|
||||||
|
|
||||||
await Future.delayed(const Duration(seconds: 2), () {
|
await Future<void>.delayed(const Duration(seconds: 2));
|
||||||
expect(childa, true);
|
expect(childa, true);
|
||||||
expect(childb, true);
|
expect(childb, true);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
test('Test broken up Xml data', () async {
|
test('Test broken up Xml data', () async {
|
||||||
var childa = false;
|
var childa = false;
|
||||||
@ -34,23 +32,22 @@ void main() {
|
|||||||
final buffer = XmlStreamBuffer();
|
final buffer = XmlStreamBuffer();
|
||||||
final controller = StreamController<String>();
|
final controller = StreamController<String>();
|
||||||
|
|
||||||
controller
|
unawaited(
|
||||||
.stream
|
controller.stream.transform(buffer).forEach((node) {
|
||||||
.transform(buffer)
|
|
||||||
.forEach((node) {
|
|
||||||
if (node.tag == 'childa') {
|
if (node.tag == 'childa') {
|
||||||
childa = true;
|
childa = true;
|
||||||
} else if (node.tag == 'childb') {
|
} else if (node.tag == 'childb') {
|
||||||
childb = true;
|
childb = true;
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
controller.add('<childa');
|
);
|
||||||
controller.add(' /><childb />');
|
controller
|
||||||
|
..add('<childa')
|
||||||
|
..add(' /><childb />');
|
||||||
|
|
||||||
await Future.delayed(const Duration(seconds: 2), () {
|
await Future<void>.delayed(const Duration(seconds: 2));
|
||||||
expect(childa, true);
|
expect(childa, true);
|
||||||
expect(childb, true);
|
expect(childb, true);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test closing the stream', () async {
|
test('Test closing the stream', () async {
|
||||||
@ -60,23 +57,22 @@ void main() {
|
|||||||
final buffer = XmlStreamBuffer();
|
final buffer = XmlStreamBuffer();
|
||||||
final controller = StreamController<String>();
|
final controller = StreamController<String>();
|
||||||
|
|
||||||
controller
|
unawaited(
|
||||||
.stream
|
controller.stream.transform(buffer).forEach((node) {
|
||||||
.transform(buffer)
|
|
||||||
.forEach((node) {
|
|
||||||
if (node.tag == 'childa') {
|
if (node.tag == 'childa') {
|
||||||
childa = true;
|
childa = true;
|
||||||
} else if (node.tag == 'childb') {
|
} else if (node.tag == 'childb') {
|
||||||
childb = true;
|
childb = true;
|
||||||
}
|
}
|
||||||
});
|
}),
|
||||||
controller.add('<childa');
|
);
|
||||||
controller.add(' /><childb />');
|
controller
|
||||||
controller.add('</stream:stream>');
|
..add('<childa')
|
||||||
|
..add(' /><childb />')
|
||||||
|
..add('</stream:stream>');
|
||||||
|
|
||||||
await Future.delayed(const Duration(seconds: 2), () {
|
await Future<void>.delayed(const Duration(seconds: 2));
|
||||||
expect(childa, true);
|
expect(childa, true);
|
||||||
expect(childb, true);
|
expect(childb, true);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -5,32 +5,61 @@ import 'helpers/logging.dart';
|
|||||||
import 'helpers/xmpp.dart';
|
import 'helpers/xmpp.dart';
|
||||||
|
|
||||||
/// Returns true if the roster manager triggeres an event for a given stanza
|
/// Returns true if the roster manager triggeres an event for a given stanza
|
||||||
Future<bool> testRosterManager(String bareJid, String resource, String stanzaString) async {
|
Future<bool> testRosterManager(
|
||||||
|
String bareJid,
|
||||||
|
String resource,
|
||||||
|
String stanzaString,
|
||||||
|
) async {
|
||||||
var eventTriggered = false;
|
var eventTriggered = false;
|
||||||
final roster = RosterManager(TestingRosterStateManager('', []));
|
final roster = RosterManager(TestingRosterStateManager('', []))
|
||||||
roster.register(XmppManagerAttributes(
|
..register(
|
||||||
sendStanza: (_, { StanzaFromType addFrom = StanzaFromType.full, bool addId = true, bool retransmitted = false, bool awaitable = true, bool encrypted = false, bool forceEncryption = false, }) async => XMLNode(tag: 'hallo'),
|
XmppManagerAttributes(
|
||||||
sendEvent: (event) {
|
sendStanza: (
|
||||||
eventTriggered = true;
|
_, {
|
||||||
},
|
StanzaFromType addFrom = StanzaFromType.full,
|
||||||
sendNonza: (_) {},
|
bool addId = true,
|
||||||
getConnectionSettings: () => ConnectionSettings(
|
bool retransmitted = false,
|
||||||
jid: JID.fromString(bareJid),
|
bool awaitable = true,
|
||||||
password: 'password',
|
bool encrypted = false,
|
||||||
useDirectTLS: true,
|
bool forceEncryption = false,
|
||||||
|
}) async =>
|
||||||
|
XMLNode(tag: 'hallo'),
|
||||||
|
sendEvent: (event) {
|
||||||
|
eventTriggered = true;
|
||||||
|
},
|
||||||
|
sendNonza: (_) {},
|
||||||
|
getConnectionSettings: () => ConnectionSettings(
|
||||||
|
jid: JID.fromString(bareJid),
|
||||||
|
password: 'password',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
|
getManagerById: getManagerNullStub,
|
||||||
|
getNegotiatorById: getNegotiatorNullStub,
|
||||||
|
isFeatureSupported: (_) => false,
|
||||||
|
getFullJID: () => JID.fromString('$bareJid/$resource'),
|
||||||
|
getSocket: () => StubTCPSocket([]),
|
||||||
|
getConnection: () => XmppConnection(
|
||||||
|
TestingReconnectionPolicy(),
|
||||||
|
AlwaysConnectedConnectivityManager(),
|
||||||
|
StubTCPSocket([]),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
getManagerById: getManagerNullStub,
|
);
|
||||||
getNegotiatorById: getNegotiatorNullStub,
|
|
||||||
isFeatureSupported: (_) => false,
|
|
||||||
getFullJID: () => JID.fromString('$bareJid/$resource'),
|
|
||||||
getSocket: () => StubTCPSocket([]),
|
|
||||||
getConnection: () => XmppConnection(TestingReconnectionPolicy(), AlwaysConnectedConnectivityManager(), StubTCPSocket([])),
|
|
||||||
),);
|
|
||||||
|
|
||||||
final stanza = Stanza.fromXMLNode(XMLNode.fromString(stanzaString));
|
final stanza = Stanza.fromXMLNode(XMLNode.fromString(stanzaString));
|
||||||
for (final handler in roster.getIncomingStanzaHandlers()) {
|
for (final handler in roster.getIncomingStanzaHandlers()) {
|
||||||
if (handler.matches(stanza)) await handler.callback(stanza, StanzaHandlerData(false, false, null, stanza));
|
if (handler.matches(stanza)) {
|
||||||
}
|
await handler.callback(
|
||||||
|
stanza,
|
||||||
|
StanzaHandlerData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
stanza,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return eventTriggered;
|
return eventTriggered;
|
||||||
}
|
}
|
||||||
@ -39,11 +68,11 @@ void main() {
|
|||||||
initLogger();
|
initLogger();
|
||||||
|
|
||||||
test('Test a successful login attempt with no SM', () async {
|
test('Test a successful login attempt with no SM', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket(
|
||||||
[
|
[
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -55,14 +84,14 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />'
|
'<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl" />',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -80,82 +109,57 @@ void main() {
|
|||||||
<sm xmlns="urn:xmpp:sm:3"/>
|
<sm xmlns="urn:xmpp:sm:3"/>
|
||||||
</stream:features>
|
</stream:features>
|
||||||
''',
|
''',
|
||||||
),
|
),
|
||||||
StanzaExpectation(
|
StanzaExpectation(
|
||||||
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
'<iq xmlns="jabber:client" type="set" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></iq>',
|
||||||
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
'<iq xmlns="jabber:client" type="result" id="a"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>polynomdivision@test.server/MU29eEZn</jid></bind></iq>',
|
||||||
ignoreId: true,
|
ignoreId: true,
|
||||||
),
|
),
|
||||||
/*
|
StanzaExpectation(
|
||||||
Expectation(
|
"<enable xmlns='urn:xmpp:sm:3' resume='true' />",
|
||||||
XMLNode.xmlns(
|
"<enabled xmlns='urn:xmpp:sm:3' id='some-long-sm-id' resume='true'/>",
|
||||||
tag: 'presence',
|
),
|
||||||
xmlns: 'jabber:client',
|
],
|
||||||
attributes: { 'from': 'polynomdivision@test.server/MU29eEZn' },
|
);
|
||||||
children: [
|
// TODO(Unknown): This test is broken since we query the server and enable carbons
|
||||||
XMLNode(
|
final conn = XmppConnection(
|
||||||
tag: 'show',
|
TestingReconnectionPolicy(),
|
||||||
text: 'chat',
|
AlwaysConnectedConnectivityManager(),
|
||||||
),
|
fakeSocket,
|
||||||
XMLNode.xmlns(
|
)..setConnectionSettings(
|
||||||
tag: 'c',
|
ConnectionSettings(
|
||||||
xmlns: 'http://jabber.org/protocol/caps',
|
|
||||||
attributes: {
|
|
||||||
// TODO: Somehow make the test ignore this attribute
|
|
||||||
'ver': 'QRTBC5cg/oYd+UOTYazSQR4zb/I=',
|
|
||||||
'node': 'http://moxxmpp.example',
|
|
||||||
'hash': 'sha-1'
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
XMLNode(
|
|
||||||
tag: 'presence',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
*/
|
|
||||||
],
|
|
||||||
);
|
|
||||||
// TODO: This test is broken since we query the server and enable carbons
|
|
||||||
final XmppConnection conn = XmppConnection(
|
|
||||||
TestingReconnectionPolicy(),
|
|
||||||
AlwaysConnectedConnectivityManager(),
|
|
||||||
fakeSocket,
|
|
||||||
);
|
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
),
|
||||||
conn.registerManagers([
|
|
||||||
PresenceManager(),
|
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
|
||||||
DiscoManager([]),
|
|
||||||
PingManager(),
|
|
||||||
StreamManagementManager(),
|
|
||||||
EntityCapabilitiesManager('http://moxxmpp.example'),
|
|
||||||
]);
|
|
||||||
conn.registerFeatureNegotiators(
|
|
||||||
[
|
|
||||||
SaslPlainNegotiator(),
|
|
||||||
SaslScramNegotiator(10, '', '', ScramHashType.sha512),
|
|
||||||
ResourceBindingNegotiator(),
|
|
||||||
StreamManagementNegotiator(),
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
await conn.registerManagers([
|
||||||
|
PresenceManager(),
|
||||||
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
|
DiscoManager([]),
|
||||||
|
PingManager(),
|
||||||
|
StreamManagementManager(),
|
||||||
|
EntityCapabilitiesManager('http://moxxmpp.example'),
|
||||||
|
]);
|
||||||
|
conn.registerFeatureNegotiators([
|
||||||
|
SaslPlainNegotiator(),
|
||||||
|
SaslScramNegotiator(10, '', '', ScramHashType.sha512),
|
||||||
|
ResourceBindingNegotiator(),
|
||||||
|
StreamManagementNegotiator(),
|
||||||
|
]);
|
||||||
|
|
||||||
await conn.connect();
|
await conn.connect(
|
||||||
await Future.delayed(const Duration(seconds: 3), () {
|
waitUntilLogin: true,
|
||||||
expect(fakeSocket.getState(), /*6*/ 5);
|
);
|
||||||
});
|
expect(fakeSocket.getState(), /*6*/ 5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test a failed SASL auth', () async {
|
test('Test a failed SASL auth', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket(
|
||||||
[
|
[
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -167,111 +171,55 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
'<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized /></failure>'
|
'<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized /></failure>',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
var receivedEvent = false;
|
var receivedEvent = false;
|
||||||
final XmppConnection conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
)..setConnectionSettings(
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
|
||||||
password: 'aaaa',
|
|
||||||
useDirectTLS: true,
|
|
||||||
),);
|
|
||||||
conn.registerManagers([
|
|
||||||
PresenceManager(),
|
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
|
||||||
DiscoManager([]),
|
|
||||||
PingManager(),
|
|
||||||
EntityCapabilitiesManager('http://moxxmpp.example'),
|
|
||||||
]);
|
|
||||||
conn.registerFeatureNegotiators([
|
|
||||||
SaslPlainNegotiator()
|
|
||||||
]);
|
|
||||||
|
|
||||||
conn.asBroadcastStream().listen((event) {
|
|
||||||
if (event is AuthenticationFailedEvent && event.saslError == 'not-authorized') {
|
|
||||||
receivedEvent = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await conn.connect();
|
|
||||||
await Future.delayed(const Duration(seconds: 3), () {
|
|
||||||
expect(receivedEvent, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test('Test another failed SASL auth', () async {
|
|
||||||
final fakeSocket = StubTCPSocket(
|
|
||||||
[
|
|
||||||
StringExpectation(
|
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
|
||||||
'''
|
|
||||||
<stream:stream
|
|
||||||
xmlns="jabber:client"
|
|
||||||
version="1.0"
|
|
||||||
xmlns:stream="http://etherx.jabber.org/streams"
|
|
||||||
from="test.server"
|
|
||||||
xml:lang="en">
|
|
||||||
<stream:features xmlns="http://etherx.jabber.org/streams">
|
|
||||||
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
|
|
||||||
<mechanism>PLAIN</mechanism>
|
|
||||||
</mechanisms>
|
|
||||||
</stream:features>''',
|
|
||||||
),
|
|
||||||
StringExpectation(
|
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
|
||||||
'<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism-too-weak /></failure>',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
var receivedEvent = false;
|
|
||||||
final XmppConnection conn = XmppConnection(
|
|
||||||
TestingReconnectionPolicy(),
|
|
||||||
AlwaysConnectedConnectivityManager(),
|
|
||||||
fakeSocket,
|
|
||||||
);
|
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
password: 'aaaa',
|
password: 'aaaa',
|
||||||
useDirectTLS: true,
|
useDirectTLS: true,
|
||||||
),);
|
),
|
||||||
conn.registerManagers([
|
);
|
||||||
PresenceManager(),
|
await conn.registerManagers([
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
PresenceManager(),
|
||||||
DiscoManager([]),
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
PingManager(),
|
DiscoManager([]),
|
||||||
EntityCapabilitiesManager('http://moxxmpp.example'),
|
PingManager(),
|
||||||
]);
|
EntityCapabilitiesManager('http://moxxmpp.example'),
|
||||||
conn.registerFeatureNegotiators([
|
]);
|
||||||
SaslPlainNegotiator()
|
conn.registerFeatureNegotiators([
|
||||||
]);
|
SaslPlainNegotiator(),
|
||||||
|
]);
|
||||||
|
|
||||||
conn.asBroadcastStream().listen((event) {
|
conn.asBroadcastStream().listen((event) {
|
||||||
if (event is AuthenticationFailedEvent && event.saslError == 'mechanism-too-weak') {
|
if (event is AuthenticationFailedEvent &&
|
||||||
receivedEvent = true;
|
event.saslError == 'not-authorized') {
|
||||||
}
|
receivedEvent = true;
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await conn.connect();
|
await conn.connect(
|
||||||
await Future.delayed(const Duration(seconds: 3), () {
|
waitUntilLogin: true,
|
||||||
expect(receivedEvent, true);
|
);
|
||||||
});
|
expect(receivedEvent, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
/*test('Test choosing SCRAM-SHA-1', () async {
|
test('Test another failed SASL auth', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket(
|
||||||
play: [
|
[
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='test.server' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -281,92 +229,162 @@ void main() {
|
|||||||
<stream:features xmlns="http://etherx.jabber.org/streams">
|
<stream:features xmlns="http://etherx.jabber.org/streams">
|
||||||
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
|
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
|
||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
<mechanism>SCRAM-SHA-1</mechanism>
|
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
// TODO(Unknown): This test is currently broken
|
StringExpectation(
|
||||||
StringExpectation(
|
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
||||||
"<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='SCRAM-SHA-1'>AHBvbHlub21kaXZpc2lvbgBhYWFh</auth>",
|
'<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism-too-weak /></failure>',
|
||||||
"..."
|
),
|
||||||
)
|
],
|
||||||
],
|
);
|
||||||
|
var receivedEvent = false;
|
||||||
|
final conn = XmppConnection(
|
||||||
|
TestingReconnectionPolicy(),
|
||||||
|
AlwaysConnectedConnectivityManager(),
|
||||||
|
fakeSocket,
|
||||||
|
)..setConnectionSettings(
|
||||||
|
ConnectionSettings(
|
||||||
|
jid: JID.fromString('polynomdivision@test.server'),
|
||||||
|
password: 'aaaa',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
final XmppConnection conn = XmppConnection(TestingReconnectionPolicy(), fakeSocket);
|
await conn.registerManagers([
|
||||||
conn.setConnectionSettings(ConnectionSettings(
|
PresenceManager(),
|
||||||
jid: JID.fromString('polynomdivision@test.server'),
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
password: 'aaaa',
|
DiscoManager([]),
|
||||||
useDirectTLS: true,
|
PingManager(),
|
||||||
),);
|
EntityCapabilitiesManager('http://moxxmpp.example'),
|
||||||
conn.registerManagers([
|
]);
|
||||||
PresenceManager('http://moxxmpp.example'),
|
conn.registerFeatureNegotiators([SaslPlainNegotiator()]);
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
|
||||||
DiscoManager(),
|
|
||||||
PingManager(),
|
|
||||||
]);
|
|
||||||
conn.registerFeatureNegotiators([
|
|
||||||
SaslPlainNegotiator(),
|
|
||||||
SaslScramNegotiator(10, '', '', ScramHashType.sha1),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await conn.connect();
|
conn.asBroadcastStream().listen((event) {
|
||||||
await Future.delayed(const Duration(seconds: 3), () {
|
if (event is AuthenticationFailedEvent &&
|
||||||
expect(fakeSocket.getState(), 2);
|
event.saslError == 'mechanism-too-weak') {
|
||||||
});
|
receivedEvent = true;
|
||||||
});*/
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await conn.connect(
|
||||||
|
waitUntilLogin: true,
|
||||||
|
);
|
||||||
|
expect(receivedEvent, true);
|
||||||
|
});
|
||||||
|
|
||||||
group('Test roster pushes', () {
|
group('Test roster pushes', () {
|
||||||
test('Test for a CVE-2015-8688 style vulnerability', () async {
|
test('Test for a CVE-2015-8688 style vulnerability', () async {
|
||||||
var eventTriggered = false;
|
var eventTriggered = false;
|
||||||
final roster = RosterManager(TestingRosterStateManager('', []));
|
final roster = RosterManager(TestingRosterStateManager('', []))
|
||||||
roster.register(XmppManagerAttributes(
|
..register(
|
||||||
sendStanza: (_, { StanzaFromType addFrom = StanzaFromType.full, bool addId = true, bool retransmitted = false, bool awaitable = true, bool encrypted = false, bool forceEncryption = false, }) async => XMLNode(tag: 'hallo'),
|
XmppManagerAttributes(
|
||||||
sendEvent: (event) {
|
sendStanza: (
|
||||||
eventTriggered = true;
|
_, {
|
||||||
},
|
StanzaFromType addFrom = StanzaFromType.full,
|
||||||
sendNonza: (_) {},
|
bool addId = true,
|
||||||
getConnectionSettings: () => ConnectionSettings(
|
bool retransmitted = false,
|
||||||
jid: JID.fromString('some.user@example.server'),
|
bool awaitable = true,
|
||||||
password: 'password',
|
bool encrypted = false,
|
||||||
useDirectTLS: true,
|
bool forceEncryption = false,
|
||||||
),
|
}) async =>
|
||||||
getManagerById: getManagerNullStub,
|
XMLNode(tag: 'hallo'),
|
||||||
getNegotiatorById: getNegotiatorNullStub,
|
sendEvent: (event) {
|
||||||
isFeatureSupported: (_) => false,
|
eventTriggered = true;
|
||||||
getFullJID: () => JID.fromString('some.user@example.server/aaaaa'),
|
},
|
||||||
getSocket: () => StubTCPSocket([]),
|
sendNonza: (_) {},
|
||||||
getConnection: () => XmppConnection(TestingReconnectionPolicy(), AlwaysConnectedConnectivityManager(), StubTCPSocket([])),
|
getConnectionSettings: () => ConnectionSettings(
|
||||||
),);
|
jid: JID.fromString('some.user@example.server'),
|
||||||
|
password: 'password',
|
||||||
|
useDirectTLS: true,
|
||||||
|
),
|
||||||
|
getManagerById: getManagerNullStub,
|
||||||
|
getNegotiatorById: getNegotiatorNullStub,
|
||||||
|
isFeatureSupported: (_) => false,
|
||||||
|
getFullJID: () => JID.fromString('some.user@example.server/aaaaa'),
|
||||||
|
getSocket: () => StubTCPSocket([]),
|
||||||
|
getConnection: () => XmppConnection(
|
||||||
|
TestingReconnectionPolicy(),
|
||||||
|
AlwaysConnectedConnectivityManager(),
|
||||||
|
StubTCPSocket([]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
// NOTE: Based on https://gultsch.de/gajim_roster_push_and_message_interception.html
|
// NOTE: Based on https://gultsch.de/gajim_roster_push_and_message_interception.html
|
||||||
// NOTE: Added a from attribute as a server would add it itself.
|
// NOTE: Added a from attribute as a server would add it itself.
|
||||||
final maliciousStanza = Stanza.fromXMLNode(XMLNode.fromString("<iq type=\"set\" from=\"eve@siacs.eu/bbbbb\" to=\"some.user@example.server/aaaaa\"><query xmlns='jabber:iq:roster'><item subscription=\"both\" jid=\"eve@siacs.eu\" name=\"Bob\" /></query></iq>"));
|
final maliciousStanza = Stanza.fromXMLNode(
|
||||||
|
XMLNode.fromString(
|
||||||
|
"<iq type=\"set\" from=\"eve@siacs.eu/bbbbb\" to=\"some.user@example.server/aaaaa\"><query xmlns='jabber:iq:roster'><item subscription=\"both\" jid=\"eve@siacs.eu\" name=\"Bob\" /></query></iq>",
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
for (final handler in roster.getIncomingStanzaHandlers()) {
|
for (final handler in roster.getIncomingStanzaHandlers()) {
|
||||||
if (handler.matches(maliciousStanza)) await handler.callback(maliciousStanza, StanzaHandlerData(false, false, null, maliciousStanza));
|
if (handler.matches(maliciousStanza)) {
|
||||||
}
|
await handler.callback(
|
||||||
|
maliciousStanza,
|
||||||
|
StanzaHandlerData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
maliciousStanza,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
expect(eventTriggered, false, reason: 'Was able to inject a malicious roster push');
|
expect(
|
||||||
});
|
eventTriggered,
|
||||||
test('The manager should accept pushes from our bare jid', () async {
|
false,
|
||||||
final result = await testRosterManager('test.user@server.example', 'aaaaa', "<iq from='test.user@server.example' type='result' id='82c2aa1e-cac3-4f62-9e1f-bbe6b057daf3' to='test.user@server.example/aaaaa' xmlns='jabber:client'><query ver='64' xmlns='jabber:iq:roster'><item jid='some.other.user@server.example' subscription='to' /></query></iq>");
|
reason: 'Was able to inject a malicious roster push',
|
||||||
expect(result, true, reason: 'Roster pushes from our bare JID should be accepted');
|
);
|
||||||
});
|
});
|
||||||
test('The manager should accept pushes from a jid that, if the resource is stripped, is our bare jid', () async {
|
test('The manager should accept pushes from our bare jid', () async {
|
||||||
final result1 = await testRosterManager('test.user@server.example', 'aaaaa', "<iq from='test.user@server.example/aaaaa' type='result' id='82c2aa1e-cac3-4f62-9e1f-bbe6b057daf3' to='test.user@server.example/aaaaa' xmlns='jabber:client'><query ver='64' xmlns='jabber:iq:roster'><item jid='some.other.user@server.example' subscription='to' /></query></iq>");
|
final result = await testRosterManager(
|
||||||
expect(result1, true, reason: 'Roster pushes should be accepted if the bare JIDs are the same');
|
'test.user@server.example',
|
||||||
|
'aaaaa',
|
||||||
|
"<iq from='test.user@server.example' type='result' id='82c2aa1e-cac3-4f62-9e1f-bbe6b057daf3' to='test.user@server.example/aaaaa' xmlns='jabber:client'><query ver='64' xmlns='jabber:iq:roster'><item jid='some.other.user@server.example' subscription='to' /></query></iq>",
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
result,
|
||||||
|
true,
|
||||||
|
reason: 'Roster pushes from our bare JID should be accepted',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test(
|
||||||
|
'The manager should accept pushes from a jid that, if the resource is stripped, is our bare jid',
|
||||||
|
() async {
|
||||||
|
final result1 = await testRosterManager(
|
||||||
|
'test.user@server.example',
|
||||||
|
'aaaaa',
|
||||||
|
"<iq from='test.user@server.example/aaaaa' type='result' id='82c2aa1e-cac3-4f62-9e1f-bbe6b057daf3' to='test.user@server.example/aaaaa' xmlns='jabber:client'><query ver='64' xmlns='jabber:iq:roster'><item jid='some.other.user@server.example' subscription='to' /></query></iq>",
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
result1,
|
||||||
|
true,
|
||||||
|
reason:
|
||||||
|
'Roster pushes should be accepted if the bare JIDs are the same',
|
||||||
|
);
|
||||||
|
|
||||||
final result2 = await testRosterManager('test.user@server.example', 'aaaaa', "<iq from='test.user@server.example/bbbbb' type='result' id='82c2aa1e-cac3-4f62-9e1f-bbe6b057daf3' to='test.user@server.example/aaaaa' xmlns='jabber:client'><query ver='64' xmlns='jabber:iq:roster'><item jid='some.other.user@server.example' subscription='to' /></query></iq>");
|
final result2 = await testRosterManager(
|
||||||
expect(result2, true, reason: 'Roster pushes should be accepted if the bare JIDs are the same');
|
'test.user@server.example',
|
||||||
});
|
'aaaaa',
|
||||||
|
"<iq from='test.user@server.example/bbbbb' type='result' id='82c2aa1e-cac3-4f62-9e1f-bbe6b057daf3' to='test.user@server.example/aaaaa' xmlns='jabber:client'><query ver='64' xmlns='jabber:iq:roster'><item jid='some.other.user@server.example' subscription='to' /></query></iq>",
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
result2,
|
||||||
|
true,
|
||||||
|
reason:
|
||||||
|
'Roster pushes should be accepted if the bare JIDs are the same',
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Test failing due to the server only allowing SASL PLAIN', () async {
|
test('Test failing due to the server only allowing SASL PLAIN', () async {
|
||||||
final fakeSocket = StubTCPSocket(
|
final fakeSocket = StubTCPSocket(
|
||||||
[
|
[
|
||||||
StringExpectation(
|
StringExpectation(
|
||||||
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='example.org' xml:lang='en'>",
|
"<stream:stream xmlns='jabber:client' version='1.0' xmlns:stream='http://etherx.jabber.org/streams' to='example.org' xml:lang='en'>",
|
||||||
'''
|
'''
|
||||||
<stream:stream
|
<stream:stream
|
||||||
xmlns="jabber:client"
|
xmlns="jabber:client"
|
||||||
version="1.0"
|
version="1.0"
|
||||||
@ -378,28 +396,27 @@ void main() {
|
|||||||
<mechanism>PLAIN</mechanism>
|
<mechanism>PLAIN</mechanism>
|
||||||
</mechanisms>
|
</mechanisms>
|
||||||
</stream:features>''',
|
</stream:features>''',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
final conn = XmppConnection(
|
final conn = XmppConnection(
|
||||||
TestingReconnectionPolicy(),
|
TestingReconnectionPolicy(),
|
||||||
AlwaysConnectedConnectivityManager(),
|
AlwaysConnectedConnectivityManager(),
|
||||||
fakeSocket,
|
fakeSocket,
|
||||||
);
|
);
|
||||||
conn.registerManagers([
|
await conn.registerManagers([
|
||||||
PresenceManager(),
|
PresenceManager(),
|
||||||
RosterManager(TestingRosterStateManager('', [])),
|
RosterManager(TestingRosterStateManager('', [])),
|
||||||
DiscoManager([]),
|
DiscoManager([]),
|
||||||
PingManager(),
|
PingManager(),
|
||||||
]);
|
]);
|
||||||
conn.registerFeatureNegotiators(
|
conn
|
||||||
[
|
..registerFeatureNegotiators([
|
||||||
// SaslPlainNegotiator(),
|
// SaslPlainNegotiator(),
|
||||||
ResourceBindingNegotiator(),
|
ResourceBindingNegotiator(),
|
||||||
]
|
])
|
||||||
);
|
..setConnectionSettings(
|
||||||
conn.setConnectionSettings(
|
|
||||||
ConnectionSettings(
|
ConnectionSettings(
|
||||||
jid: JID.fromString('testuser@example.org'),
|
jid: JID.fromString('testuser@example.org'),
|
||||||
password: 'abc123',
|
password: 'abc123',
|
||||||
@ -407,10 +424,13 @@ void main() {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final result = await conn.connect(
|
final result = await conn.connect(
|
||||||
waitUntilLogin: true,
|
waitUntilLogin: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.isType<NoMatchingAuthenticationMechanismAvailableError>(), true);
|
expect(
|
||||||
|
result.isType<NoMatchingAuthenticationMechanismAvailableError>(),
|
||||||
|
true,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user