feat(xep): Guard against random data in the SASL2 result
This commit is contained in:
parent
30482c86f0
commit
af8bc606d6
@ -6,18 +6,6 @@ import 'package:moxxmpp/src/negotiators/sasl/negotiator.dart';
|
|||||||
import 'package:moxxmpp/src/stringxml.dart';
|
import 'package:moxxmpp/src/stringxml.dart';
|
||||||
import 'package:moxxmpp/src/types/result.dart';
|
import 'package:moxxmpp/src/types/result.dart';
|
||||||
|
|
||||||
bool isInliningPossible(XMLNode nonza, String xmlns) {
|
|
||||||
assert(nonza.tag == 'authentication', 'Ensure we use the correct nonza');
|
|
||||||
assert(nonza.xmlns == sasl2Xmlns, 'Ensure we use the correct nonza');
|
|
||||||
final inline = nonza.firstTag('inline');
|
|
||||||
if (inline == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return inline.children.firstWhereOrNull((child) => child.xmlns == xmlns) !=
|
|
||||||
null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A special type of [XmppFeatureNegotiatorBase] that is aware of SASL2.
|
/// A special type of [XmppFeatureNegotiatorBase] that is aware of SASL2.
|
||||||
abstract class Sasl2FeatureNegotiator extends XmppFeatureNegotiatorBase {
|
abstract class Sasl2FeatureNegotiator extends XmppFeatureNegotiatorBase {
|
||||||
Sasl2FeatureNegotiator(
|
Sasl2FeatureNegotiator(
|
||||||
@ -30,10 +18,14 @@ abstract class Sasl2FeatureNegotiator extends XmppFeatureNegotiatorBase {
|
|||||||
/// Called by the SASL2 negotiator when we received the SASL2 stream features
|
/// Called by the SASL2 negotiator when we received the SASL2 stream features
|
||||||
/// [sasl2Features]. The return value is a list of XML elements that should be
|
/// [sasl2Features]. The return value is a list of XML elements that should be
|
||||||
/// added to the SASL2 <authenticate /> nonza.
|
/// added to the SASL2 <authenticate /> nonza.
|
||||||
|
/// This method is only called when the <inline /> element contains an item with
|
||||||
|
/// xmlns equal to [negotiatingXmlns].
|
||||||
Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode sasl2Features);
|
Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode sasl2Features);
|
||||||
|
|
||||||
/// Called by the SASL2 negotiator when the SASL2 negotiations are done. [response]
|
/// Called by the SASL2 negotiator when the SASL2 negotiations are done. [response]
|
||||||
/// is the entire response nonza.
|
/// is the entire response nonza.
|
||||||
|
/// This method is only called when the previous <inline /> element contains an
|
||||||
|
/// item with xmlns equal to [negotiatingXmlns].
|
||||||
Future<Result<bool, NegotiatorError>> onSasl2Success(XMLNode response);
|
Future<Result<bool, NegotiatorError>> onSasl2Success(XMLNode response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +140,18 @@ class Sasl2Negotiator extends XmppFeatureNegotiatorBase {
|
|||||||
_featureNegotiators.add(negotiator);
|
_featureNegotiators.add(negotiator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true, if an item with xmlns of [xmlns] is contained inside [_sasl2Data]'s
|
||||||
|
/// <inline /> block. If not, returns false.
|
||||||
|
bool _isInliningPossible(String xmlns) {
|
||||||
|
final inline = _sasl2Data!.firstTag('inline');
|
||||||
|
if (inline == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inline.children.firstWhereOrNull((child) => child.xmlns == xmlns) !=
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool matchesFeature(List<XMLNode> features) {
|
bool matchesFeature(List<XMLNode> features) {
|
||||||
// Only do SASL2 when the socket is secure
|
// Only do SASL2 when the socket is secure
|
||||||
@ -182,7 +186,7 @@ class Sasl2Negotiator extends XmppFeatureNegotiatorBase {
|
|||||||
// Collect additional data by interested negotiators
|
// Collect additional data by interested negotiators
|
||||||
final children = List<XMLNode>.empty(growable: true);
|
final children = List<XMLNode>.empty(growable: true);
|
||||||
for (final negotiator in _featureNegotiators) {
|
for (final negotiator in _featureNegotiators) {
|
||||||
if (isInliningPossible(_sasl2Data!, negotiator.negotiatingXmlns)) {
|
if (_isInliningPossible(negotiator.negotiatingXmlns)) {
|
||||||
children.addAll(
|
children.addAll(
|
||||||
await negotiator.onSasl2FeaturesReceived(_sasl2Data!),
|
await negotiator.onSasl2FeaturesReceived(_sasl2Data!),
|
||||||
);
|
);
|
||||||
@ -214,7 +218,7 @@ class Sasl2Negotiator extends XmppFeatureNegotiatorBase {
|
|||||||
// Tell the dependent negotiators about the result
|
// Tell the dependent negotiators about the result
|
||||||
// TODO(Unknown): This can be written in a better way
|
// TODO(Unknown): This can be written in a better way
|
||||||
for (final negotiator in _featureNegotiators) {
|
for (final negotiator in _featureNegotiators) {
|
||||||
if (isInliningPossible(_sasl2Data!, negotiator.negotiatingXmlns)) {
|
if (_isInliningPossible(negotiator.negotiatingXmlns)) {
|
||||||
final result = await negotiator.onSasl2Success(nonza);
|
final result = await negotiator.onSasl2Success(nonza);
|
||||||
if (!result.isType<bool>()) {
|
if (!result.isType<bool>()) {
|
||||||
return Result(result.get<NegotiatorError>());
|
return Result(result.get<NegotiatorError>());
|
||||||
|
@ -25,10 +25,6 @@ class ExampleNegotiator extends Sasl2FeatureNegotiator {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode nonza) async {
|
Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode nonza) async {
|
||||||
if (!isInliningPossible(nonza, 'invalid:example:dont:use')) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
XMLNode.xmlns(
|
XMLNode.xmlns(
|
||||||
tag: 'test-data-request',
|
tag: 'test-data-request',
|
||||||
|
Loading…
Reference in New Issue
Block a user