Skip to content

Commit

Permalink
add option to register onBadCertificate callback
Browse files Browse the repository at this point in the history
Resolves #167
  • Loading branch information
robert-virkus committed Jul 13, 2021
1 parent 07012c8 commit cc76eb2
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 32 deletions.
11 changes: 8 additions & 3 deletions lib/imap/imap_client.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:collection/collection.dart' show IterableExtension;
import 'package:enough_mail/enough_mail.dart';
Expand Down Expand Up @@ -195,16 +196,20 @@ class ImapClient extends ClientBase {
/// Set [isLogEnabled] to `true` for getting log outputs on the standard output.
/// Optionally specify a [logName] that is given out at logs to differentiate between different imap clients.
/// Set the [connectionTimeout] in case the connection connection should timeout automatically after the given time.
/// [onBadCertificate] is an optional handler for unverifiable certificates. The handler receives the [X509Certificate], and can inspect it and decide (or let the user decide) whether to accept the connection or not. The handler should return true to continue the [SecureSocket] connection.
ImapClient({
EventBus? bus,
bool isLogEnabled = false,
String? logName,
Duration? connectionTimeout,
bool Function(X509Certificate)? onBadCertificate,
}) : _eventBus = bus ?? EventBus(),
super(
isLogEnabled: isLogEnabled,
logName: logName,
connectionTimeout: connectionTimeout) {
isLogEnabled: isLogEnabled,
logName: logName,
connectionTimeout: connectionTimeout,
onBadCertificate: onBadCertificate,
) {
_imapResponseReader = ImapResponseReader(onServerResponse);
}

Expand Down
65 changes: 44 additions & 21 deletions lib/mail/mail_client.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';

import 'package:collection/collection.dart' show IterableExtension;
import 'package:enough_mail/enough_mail.dart';
Expand Down Expand Up @@ -107,22 +108,27 @@ class MailClient {
/// Specify the account settings with [account].
/// Set [isLogEnabled] to true to debug connection issues.
/// Specify the optional [downloadSizeLimit] in bytes to only download messages automatically that are this size or lower.
MailClient(MailAccount account,
{bool isLogEnabled = false,
int? downloadSizeLimit,
EventBus? eventBus,
String? logName})
: _eventBus = eventBus ?? EventBus(),
/// [onBadCertificate] is an optional handler for unverifiable certificates. The handler receives the [X509Certificate], and can inspect it and decide (or let the user decide) whether to accept the connection or not. The handler should return true to continue the [SecureSocket] connection.
MailClient(
MailAccount account, {
bool isLogEnabled = false,
int? downloadSizeLimit,
EventBus? eventBus,
String? logName,
bool Function(X509Certificate)? onBadCertificate,
}) : _eventBus = eventBus ?? EventBus(),
_account = account,
_isLogEnabled = isLogEnabled,
_downloadSizeLimit = downloadSizeLimit {
final config = _account.incoming!;
if (config.serverConfig!.type == ServerType.imap) {
_incomingMailClient = _IncomingImapClient(
_downloadSizeLimit, _eventBus, _isLogEnabled, logName, config, this);
_downloadSizeLimit, _eventBus, _isLogEnabled, logName, config, this,
onBadCertificate: onBadCertificate);
} else if (config.serverConfig!.type == ServerType.pop) {
_incomingMailClient = _IncomingPopClient(
_downloadSizeLimit, _eventBus, _isLogEnabled, logName, config, this);
_downloadSizeLimit, _eventBus, _isLogEnabled, logName, config, this,
onBadCertificate: onBadCertificate);
} else {
throw StateError(
'Unsupported incoming server type [${config.serverConfig!.typeName}].');
Expand All @@ -133,12 +139,14 @@ class MailClient {
'Warning: unknown outgoing server type ${outgoingConfig.serverConfig!.typeName}.');
}
_outgoingMailClient = _OutgoingSmtpClient(
this,
_account.outgoingClientDomain,
_eventBus,
_isLogEnabled,
'SMTP-$logName',
outgoingConfig);
this,
_account.outgoingClientDomain,
_eventBus,
_isLogEnabled,
'SMTP-$logName',
outgoingConfig,
onBadCertificate: onBadCertificate,
);
}

/// Adds the specified mail event [filter].
Expand Down Expand Up @@ -1116,9 +1124,14 @@ class _IncomingImapClient extends _IncomingMailClient {
bool isLogEnabled,
String? logName,
MailServerConfig config,
MailClient mailClient)
MailClient mailClient,
{bool Function(X509Certificate)? onBadCertificate})
: _imapClient = ImapClient(
bus: eventBus, isLogEnabled: isLogEnabled, logName: logName),
bus: eventBus,
isLogEnabled: isLogEnabled,
logName: logName,
onBadCertificate: onBadCertificate,
),
super(downloadSizeLimit, config, mailClient) {
eventBus.on<ImapEvent>().listen(_onImapEvent);
}
Expand Down Expand Up @@ -2091,9 +2104,13 @@ class _IncomingPopClient extends _IncomingMailClient {
bool isLogEnabled,
String? logName,
MailServerConfig config,
MailClient mailClient)
MailClient mailClient,
{bool Function(X509Certificate)? onBadCertificate})
: _popClient = PopClient(
bus: eventBus, isLogEnabled: isLogEnabled, logName: logName),
bus: eventBus,
isLogEnabled: isLogEnabled,
logName: logName,
onBadCertificate: onBadCertificate),
super(downloadSizeLimit, config, mailClient);

@override
Expand Down Expand Up @@ -2353,9 +2370,15 @@ class _OutgoingSmtpClient extends _OutgoingMailClient {
final MailServerConfig _mailConfig;

_OutgoingSmtpClient(this.mailClient, outgoingClientDomain, EventBus? eventBus,
bool isLogEnabled, String logName, MailServerConfig mailConfig)
: _smtpClient = SmtpClient(outgoingClientDomain,
bus: eventBus, isLogEnabled: isLogEnabled, logName: logName),
bool isLogEnabled, String logName, MailServerConfig mailConfig,
{bool Function(X509Certificate)? onBadCertificate})
: _smtpClient = SmtpClient(
outgoingClientDomain,
bus: eventBus,
isLogEnabled: isLogEnabled,
logName: logName,
onBadCertificate: onBadCertificate,
),
_mailConfig = mailConfig;

Future<void> _connectOutgoingIfRequired() async {
Expand Down
11 changes: 8 additions & 3 deletions lib/pop/pop_client.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:enough_mail/enough_mail.dart';
Expand Down Expand Up @@ -43,16 +44,20 @@ class PopClient extends ClientBase {
/// Set [isLogEnabled] to `true` to see log output.
/// Set the [logName] for adding the name to each log entry.
/// Set the [connectionTimeout] in case the connection connection should timeout automatically after the given time.
/// [onBadCertificate] is an optional handler for unverifiable certificates. The handler receives the [X509Certificate], and can inspect it and decide (or let the user decide) whether to accept the connection or not. The handler should return true to continue the [SecureSocket] connection.
PopClient({
EventBus? bus,
bool isLogEnabled = false,
String? logName,
Duration? connectionTimeout,
bool Function(X509Certificate)? onBadCertificate,
}) : _eventBus = bus ?? EventBus(),
super(
isLogEnabled: isLogEnabled,
logName: logName,
connectionTimeout: connectionTimeout);
isLogEnabled: isLogEnabled,
logName: logName,
connectionTimeout: connectionTimeout,
onBadCertificate: onBadCertificate,
);

@override
void onConnectionEstablished(
Expand Down
11 changes: 8 additions & 3 deletions lib/smtp/smtp_client.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:io';
import 'dart:typed_data';
import 'package:enough_mail/mail_address.dart';
import 'package:enough_mail/mime_data.dart';
Expand Down Expand Up @@ -104,18 +105,22 @@ class SmtpClient extends ClientBase {
/// Set [isLogEnabled] to `true` to see log output.
/// Set the [logName] for adding the name to each log entry.
/// Set the [connectionTimeout] in case the connection connection should timeout automatically after the given time.
/// [onBadCertificate] is an optional handler for unverifiable certificates. The handler receives the [X509Certificate], and can inspect it and decide (or let the user decide) whether to accept the connection or not. The handler should return true to continue the [SecureSocket] connection.
SmtpClient(
String clientDomain, {
EventBus? bus,
bool isLogEnabled = false,
String? logName,
Duration? connectionTimeout,
bool Function(X509Certificate)? onBadCertificate,
}) : _eventBus = bus ?? EventBus(),
_clientDomain = clientDomain,
super(
isLogEnabled: isLogEnabled,
logName: logName,
connectionTimeout: connectionTimeout);
isLogEnabled: isLogEnabled,
logName: logName,
connectionTimeout: connectionTimeout,
onBadCertificate: onBadCertificate,
);

@override
void onConnectionEstablished(
Expand Down
17 changes: 15 additions & 2 deletions lib/src/util/client_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ abstract class ClientBase {

bool _isConnected = false;

/// [onBadCertificate] is an optional handler for unverifiable certificates. The handler receives the [X509Certificate], and can inspect it and decide (or let the user decide) whether to accept the connection or not. The handler should return true to continue the [SecureSocket] connection.
final bool Function(X509Certificate)? onBadCertificate;

void onDataReceived(Uint8List data);
void onConnectionEstablished(
ConnectionInfo connectionInfo, String serverGreeting);
Expand All @@ -39,7 +42,13 @@ abstract class ClientBase {
/// Set [isLogEnabled] to `true` to see log output.
/// Set the [logName] for adding the name to each log entry.
/// Set the [connectionTimeout] in case the connection connection should timeout automatically after the given time.
ClientBase({this.isLogEnabled = false, this.logName, this.connectionTimeout});
/// [onBadCertificate] is an optional handler for unverifiable certificates. The handler receives the [X509Certificate], and can inspect it and decide (or let the user decide) whether to accept the connection or not. The handler should return true to continue the [SecureSocket] connection.
ClientBase({
this.isLogEnabled = false,
this.logName,
this.connectionTimeout,
this.onBadCertificate,
});

/// Connects to the specified server.
///
Expand All @@ -50,7 +59,11 @@ abstract class ClientBase {
initial: initialApp);
connectionInfo = ConnectionInfo(host, port, isSecure);
final socket = isSecure
? await SecureSocket.connect(host, port)
? await SecureSocket.connect(
host,
port,
onBadCertificate: onBadCertificate,
)
: await Socket.connect(host, port);
_greetingsCompleter = Completer<ConnectionInfo>();
_isServerGreetingDone = false;
Expand Down

0 comments on commit cc76eb2

Please sign in to comment.