feat(xep): Guard against random data in the SASL2 result

This commit is contained in:
PapaTutuWawa 2023-04-01 00:51:51 +02:00
parent 30482c86f0
commit af8bc606d6
2 changed files with 18 additions and 18 deletions

View File

@ -6,18 +6,6 @@ import 'package:moxxmpp/src/negotiators/sasl/negotiator.dart';
import 'package:moxxmpp/src/stringxml.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.
abstract class Sasl2FeatureNegotiator extends XmppFeatureNegotiatorBase {
Sasl2FeatureNegotiator(
@ -30,10 +18,14 @@ abstract class Sasl2FeatureNegotiator extends XmppFeatureNegotiatorBase {
/// 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
/// 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);
/// Called by the SASL2 negotiator when the SASL2 negotiations are done. [response]
/// 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);
}
@ -148,6 +140,18 @@ class Sasl2Negotiator extends XmppFeatureNegotiatorBase {
_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
bool matchesFeature(List<XMLNode> features) {
// Only do SASL2 when the socket is secure
@ -182,7 +186,7 @@ class Sasl2Negotiator extends XmppFeatureNegotiatorBase {
// Collect additional data by interested negotiators
final children = List<XMLNode>.empty(growable: true);
for (final negotiator in _featureNegotiators) {
if (isInliningPossible(_sasl2Data!, negotiator.negotiatingXmlns)) {
if (_isInliningPossible(negotiator.negotiatingXmlns)) {
children.addAll(
await negotiator.onSasl2FeaturesReceived(_sasl2Data!),
);
@ -214,7 +218,7 @@ class Sasl2Negotiator extends XmppFeatureNegotiatorBase {
// Tell the dependent negotiators about the result
// TODO(Unknown): This can be written in a better way
for (final negotiator in _featureNegotiators) {
if (isInliningPossible(_sasl2Data!, negotiator.negotiatingXmlns)) {
if (_isInliningPossible(negotiator.negotiatingXmlns)) {
final result = await negotiator.onSasl2Success(nonza);
if (!result.isType<bool>()) {
return Result(result.get<NegotiatorError>());

View File

@ -25,10 +25,6 @@ class ExampleNegotiator extends Sasl2FeatureNegotiator {
@override
Future<List<XMLNode>> onSasl2FeaturesReceived(XMLNode nonza) async {
if (!isInliningPossible(nonza, 'invalid:example:dont:use')) {
return [];
}
return [
XMLNode.xmlns(
tag: 'test-data-request',