diff --git a/moxxmpp/LICENSE b/moxxmpp/LICENSE new file mode 100644 index 0000000..dc6a3cd --- /dev/null +++ b/moxxmpp/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Alexander "PapaTutuWawa" + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/moxxmpp/README.md b/moxxmpp/README.md index a16e658..583f2a7 100644 --- a/moxxmpp/README.md +++ b/moxxmpp/README.md @@ -4,4 +4,4 @@ A pure-Dart XMPP library written for Moxxy. ## License -See `../LICENSE`. +See `./LICENSE`. diff --git a/moxxmpp/lib/src/socket.dart b/moxxmpp/lib/src/socket.dart index c16416a..0de7f34 100644 --- a/moxxmpp/lib/src/socket.dart +++ b/moxxmpp/lib/src/socket.dart @@ -1,10 +1,3 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'package:logging/logging.dart'; -//import 'package:moxdns/moxdns.dart'; -//import 'package:moxxmpp/src/rfcs/rfc_2782.dart'; - // NOTE: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids const xmppClientALPNId = 'xmpp-client'; @@ -61,283 +54,3 @@ abstract class BaseSocketWrapper { /// to the XmppConnection. void prepareDisconnect() {} } - -/// TCP socket implementation for XmppConnection -/*class TCPSocketWrapper extends BaseSocketWrapper { - - TCPSocketWrapper(this._logData) - : _log = Logger('TCPSocketWrapper'), - _dataStream = StreamController.broadcast(), - _eventStream = StreamController.broadcast(), - _secure = false, - _ignoreSocketClosure = false; - Socket? _socket; - bool _ignoreSocketClosure; - final StreamController _dataStream; - final StreamController _eventStream; - StreamSubscription? _socketSubscription; - - final Logger _log; - final bool _logData; - - bool _secure; - - @override - bool isSecure() => _secure; - - @override - bool whitespacePingAllowed() => true; - - @override - bool managesKeepalives() => false; - - /// Allow the socket to be destroyed by cancelling internal subscriptions. - void destroy() { - _socketSubscription?.cancel(); - } - - bool _onBadCertificate(dynamic certificate, String domain) { - _log.fine('Bad certificate: ${certificate.toString()}'); - //final isExpired = certificate.endValidity.isAfter(DateTime.now()); - // TODO(Unknown): Either validate the certificate ourselves or use a platform native - // hostname verifier (or Dart adds it themselves) - return false; - } - - Future _xep368Connect(String domain) async { - // TODO(Unknown): Maybe do DNSSEC one day - final results = await MoxdnsPlugin.srvQuery('_xmpps-client._tcp.$domain', false); - if (results.isEmpty) { - return false; - } - - results.sort(srvRecordSortComparator); - for (final srv in results) { - try { - _log.finest('Attempting secure connection to ${srv.target}:${srv.port}...'); - _ignoreSocketClosure = true; - _socket = await SecureSocket.connect( - srv.target, - srv.port, - timeout: const Duration(seconds: 5), - supportedProtocols: const [ xmppClientALPNId ], - onBadCertificate: (cert) => _onBadCertificate(cert, domain), - ); - - _ignoreSocketClosure = false; - _secure = true; - _log.finest('Success!'); - return true; - } on SocketException catch(e) { - _log.finest('Failure! $e'); - _ignoreSocketClosure = false; - } - } - - return false; - } - - Future _rfc6120Connect(String domain) async { - // TODO(Unknown): Maybe do DNSSEC one day - final results = await MoxdnsPlugin.srvQuery('_xmpp-client._tcp.$domain', false); - results.sort(srvRecordSortComparator); - - for (final srv in results) { - try { - _log.finest('Attempting connection to ${srv.target}:${srv.port}...'); - _ignoreSocketClosure = true; - _socket = await Socket.connect( - srv.target, - srv.port, - timeout: const Duration(seconds: 5), - ); - - _ignoreSocketClosure = false; - _log.finest('Success!'); - return true; - } on SocketException catch(e) { - _log.finest('Failure! $e'); - _ignoreSocketClosure = false; - continue; - } - } - - return _rfc6120FallbackConnect(domain); - } - - /// Connect to [host] with port [port] and returns true if the connection - /// was successfully established. Does not setup the streams as this has - /// to be done by the caller. - Future _hostPortConnect(String host, int port) async { - try { - _log.finest('Attempting fallback connection to $host:$port...'); - _ignoreSocketClosure = true; - _socket = await Socket.connect( - host, - port, - timeout: const Duration(seconds: 5), - ); - _log.finest('Success!'); - return true; - } on SocketException catch(e) { - _log.finest('Failure! $e'); - _ignoreSocketClosure = false; - return false; - } - } - - /// Connect to [domain] using the default C2S port of XMPP. Returns - /// true if the connection was successful. Does not setup the streams - /// as [_rfc6120FallbackConnect] should only be called from - /// [_rfc6120Connect], which already sets the streams up on a successful - /// connection. - Future _rfc6120FallbackConnect(String domain) async { - return _hostPortConnect(domain, 5222); - } - - @override - Future secure(String domain) async { - if (_secure) { - _log.warning('Connection is already marked as secure. Doing nothing'); - return true; - } - - if (_socket == null) { - _log.severe('Failed to secure socket since _socket is null'); - return false; - } - - _ignoreSocketClosure = true; - - try { - _socket = await SecureSocket.secure( - _socket!, - supportedProtocols: const [ xmppClientALPNId ], - onBadCertificate: (cert) => _onBadCertificate(cert, domain), - ); - - _secure = true; - _ignoreSocketClosure = false; - _setupStreams(); - return true; - } on SocketException { - _ignoreSocketClosure = false; - return false; - } - } - - void _setupStreams() { - if (_socket == null) { - _log.severe('Failed to setup streams as _socket is null'); - return; - } - - _socketSubscription = _socket!.listen( - (List event) { - final data = utf8.decode(event); - if (_logData) { - _log.finest('<== $data'); - } - _dataStream.add(data); - }, - onError: (Object error) { - _log.severe(error.toString()); - _eventStream.add(XmppSocketErrorEvent(error)); - }, - ); - // ignore: implicit_dynamic_parameter - _socket!.done.then((_) { - if (!_ignoreSocketClosure) { - _eventStream.add(XmppSocketClosureEvent()); - } - }); - } - - @override - Future connect(String domain, { String? host, int? port }) async { - _ignoreSocketClosure = false; - _secure = false; - - // Connection order: - // 1. host:port, if given - // 2. XEP-0368 - // 3. RFC 6120 - // 4. RFC 6120 fallback - - if (host != null && port != null) { - _log.finest('Specific host and port given'); - if (await _hostPortConnect(host, port)) { - _setupStreams(); - return true; - } - } - - if (await _xep368Connect(domain)) { - _setupStreams(); - return true; - } - - // NOTE: _rfc6120Connect already attempts the fallback - if (await _rfc6120Connect(domain)) { - _setupStreams(); - return true; - } - - return false; - } - - @override - void close() { - if (_socketSubscription != null) { - _log.finest('Closing socket subscription'); - _socketSubscription!.cancel(); - } - - if (_socket == null) { - _log.warning('Failed to close socket since _socket is null'); - return; - } - - _ignoreSocketClosure = true; - try { - _socket!.close(); - } catch(e) { - _log.warning('Closing socket threw exception: $e'); - } - _ignoreSocketClosure = false; - } - - @override - Stream getDataStream() => _dataStream.stream.asBroadcastStream(); - - @override - Stream getEventStream() => _eventStream.stream.asBroadcastStream(); - - @override - void write(Object? data, { String? redact }) { - if (_socket == null) { - _log.severe('Failed to write to socket as _socket is null'); - return; - } - - if (data != null && data is String && _logData) { - if (redact != null) { - _log.finest('**> $redact'); - } else { - _log.finest('==> $data'); - } - } - - try { - _socket!.write(data); - } on SocketException catch (e) { - _log.severe(e); - _eventStream.add(XmppSocketErrorEvent(e)); - } - } - - @override - void prepareDisconnect() { - _ignoreSocketClosure = true; - } -}*/ diff --git a/moxxmpp/pubspec.yaml b/moxxmpp/pubspec.yaml index f285050..b75c250 100644 --- a/moxxmpp/pubspec.yaml +++ b/moxxmpp/pubspec.yaml @@ -2,35 +2,32 @@ name: moxxmpp description: A pure-Dart XMPP library version: 0.1.0 homepage: https://codeberg.org/moxxy/moxxmpp +publish_to: https://git.polynom.me/api/packages/Moxxy/pub environment: sdk: '>=2.18.0 <3.0.0' dependencies: cryptography: 2.0.5 + freezed: ^2.1.0+1 + freezed_annotation: 2.1.0 hex: 0.2.0 + json_serializable: ^6.3.1 logging: 1.0.2 + meta: ^1.7.0 moxlib: hosted: https://git.polynom.me/api/packages/Moxxy/pub version: 0.1.5 omemo_dart: hosted: https://git.polynom.me/api/packages/PapaTutuWawa/pub - version: 0.3.1 + version: 0.3.2 random_string: 2.3.1 saslprep: 1.0.2 + synchronized: 3.0.0+2 uuid: 3.0.5 xml: ^6.1.0 dev_dependencies: build_runner: ^2.1.11 - freezed: ^2.1.0+1 - json_serializable: ^6.3.1 - meta: ^1.7.0 test: ^1.16.0 very_good_analysis: ^3.0.1 - -dependency_overrides: - omemo_dart: - git: - url: https://codeberg.org/PapaTutuWawa/omemo_dart.git - rev: c68471349ab1b347ec9ad54651265710842c50b7