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