Messaging: WIP MailFetcher, MailSession
This commit is contained in:
322
Messaging/Mail/MailSession.vb
Normal file
322
Messaging/Mail/MailSession.vb
Normal file
@@ -0,0 +1,322 @@
|
||||
Imports System.Net.Security
|
||||
Imports DigitalData.Modules.Base
|
||||
Imports DigitalData.Modules.Logging
|
||||
Imports Limilabs.Client
|
||||
Imports Limilabs.Client.IMAP
|
||||
Imports Limilabs.Client.SMTP
|
||||
Imports Microsoft.Identity.Client
|
||||
|
||||
Namespace Mail
|
||||
Public Class MailSession
|
||||
Inherits BaseClass
|
||||
|
||||
Public ReadOnly Client As ClientBase
|
||||
Public ReadOnly OAuth2 As OAuth2
|
||||
|
||||
Public Const AUTH_SSL = "SSL"
|
||||
Public Const AUTH_STARTTLS = "STARTTLS"
|
||||
Public Const AUTH_SSLTLS = "SSL/TLS"
|
||||
Public Const AUTH_NONE = "NONE"
|
||||
Public Const AUTH_OAUTH2 = "OAUTH2"
|
||||
|
||||
Private Const SMTP_IGNORED_ERRORS As SslPolicyErrors =
|
||||
SslPolicyErrors.RemoteCertificateChainErrors Or ' self-signed
|
||||
SslPolicyErrors.RemoteCertificateNameMismatch ' name mismatch
|
||||
|
||||
Private _Session As SessionInfo
|
||||
|
||||
Public ReadOnly Property Session As SessionInfo
|
||||
Get
|
||||
Return _Session
|
||||
End Get
|
||||
End Property
|
||||
|
||||
Public Sub New(pLogConfig As LogConfig, pClient As ClientBase)
|
||||
MyBase.New(pLogConfig)
|
||||
Client = pClient
|
||||
End Sub
|
||||
|
||||
Public Class SessionInfo
|
||||
Public Server As String
|
||||
Public Port As Integer
|
||||
Public User As String
|
||||
Public Password As String
|
||||
Public AuthType As String
|
||||
|
||||
Public ClientId As String
|
||||
Public TenantId As String
|
||||
Public ClientSecret As String
|
||||
|
||||
Public [Error] As Exception
|
||||
Public Connected As Boolean = False
|
||||
End Class
|
||||
|
||||
Public Class MailSessionOptions
|
||||
Public Property EnableDefault As Boolean = True
|
||||
Public Property EnableTls1_1 As Boolean = False
|
||||
Public Property EnableTls1_2 As Boolean = False
|
||||
|
||||
' Not available in .NET 4.6.2
|
||||
'Public Property EnableTls1_3 As Boolean = False
|
||||
End Class
|
||||
|
||||
''' <summary>
|
||||
''' Start a connection with the specified server and return the session info.
|
||||
''' </summary>
|
||||
''' <param name="pServer"></param>
|
||||
''' <param name="pPort"></param>
|
||||
''' <param name="pUser"></param>
|
||||
''' <param name="pPassword"></param>
|
||||
''' <param name="pAuthType"></param>
|
||||
''' <returns></returns>
|
||||
Public Function ConnectToServer(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSessionOptions) As SessionInfo
|
||||
Dim oSession = New SessionInfo With {
|
||||
.Server = pServer,
|
||||
.Port = pPort,
|
||||
.User = pUser,
|
||||
.Password = pPassword,
|
||||
.AuthType = pAuthType
|
||||
}
|
||||
|
||||
Logger.Debug("Connecting to Server..")
|
||||
Logger.Debug("Server: [{0}]", oSession.Server)
|
||||
Logger.Debug("Port: [{0}]", oSession.Port)
|
||||
Logger.Debug("User: [{0}]", oSession.User)
|
||||
Logger.Debug("AuthType: [{0}]", oSession.AuthType)
|
||||
|
||||
_Session = oSession
|
||||
|
||||
Logger.Debug("Initializing Connection with Auth type [{0}].", oSession.AuthType)
|
||||
|
||||
Return ConnectToServer(oSession, pOptions)
|
||||
End Function
|
||||
|
||||
Private Function ConnectToServer(pSession As SessionInfo, pOptions As MailSessionOptions) As SessionInfo
|
||||
AddHandler Client.ServerCertificateValidate, AddressOf Session_ServerCertificateValidate
|
||||
|
||||
If pOptions.EnableDefault Then
|
||||
Logger.Debug("Enabling Default TLS Version")
|
||||
Client.SSLConfiguration.EnabledSslProtocols = Security.Authentication.SslProtocols.Default
|
||||
Else
|
||||
Logger.Debug("Disabling Default TLS Version")
|
||||
Client.SSLConfiguration.EnabledSslProtocols = Security.Authentication.SslProtocols.None
|
||||
End If
|
||||
|
||||
' Set TLS Version manually if requested
|
||||
If pOptions.EnableTls1_1 Then
|
||||
Logger.Debug("Enabling TLS Version 1.1")
|
||||
Client.SSLConfiguration.EnabledSslProtocols = Client.SSLConfiguration.EnabledSslProtocols Or Security.Authentication.SslProtocols.Tls11
|
||||
End If
|
||||
|
||||
If pOptions.EnableTls1_2 Then
|
||||
Logger.Debug("Enabling TLS Version 1.2")
|
||||
Client.SSLConfiguration.EnabledSslProtocols = Client.SSLConfiguration.EnabledSslProtocols Or Security.Authentication.SslProtocols.Tls12
|
||||
End If
|
||||
|
||||
' This is not available in .NET 4.6.2, only in .NET 4.7/4.8
|
||||
'If pOptions.EnableTls1_3 Then
|
||||
' Logger.Debug("Enabling TLS Version 1.3")
|
||||
' oSession.SSLConfiguration.EnabledSslProtocols = oSession.SSLConfiguration.EnabledSslProtocols Or Security.Authentication.SslProtocols.Tls13
|
||||
'End If
|
||||
|
||||
Logger.Debug("Enabled Encryption Protocols: [{0}]", Client.SSLConfiguration.EnabledSslProtocols)
|
||||
|
||||
If pSession.AuthType = AUTH_OAUTH2 Then
|
||||
Try
|
||||
If TypeOf Client Is Imap Then
|
||||
Dim oClient As Imap = Client
|
||||
oClient.ConnectSSL(pSession.Server)
|
||||
Else
|
||||
Throw New ApplicationException("Only OAuth2 for IMAP is not yet supported!")
|
||||
End If
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Error while connecting with Auth type OAuth2!")
|
||||
Logger.Error(ex)
|
||||
|
||||
Session.Error = ex
|
||||
Return Session
|
||||
End Try
|
||||
|
||||
ElseIf pSession.AuthType = AUTH_SSL Then
|
||||
Try
|
||||
If pSession.Port = 465 Then
|
||||
Logger.Debug("Connecting with [ConnectSSL] on [{0}/{1}]", pSession.Server, pSession.Port)
|
||||
Client.ConnectSSL(pSession.Server, pSession.Port)
|
||||
Else
|
||||
Logger.Debug("Connecting with [Connect] on [{0}/{1}]", pSession.Server, pSession.Port)
|
||||
Client.Connect(pSession.Server, pSession.Port)
|
||||
End If
|
||||
Logger.Info("Connection Successful!")
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Error while connecting with Auth type SSL!")
|
||||
Logger.Error(ex)
|
||||
|
||||
Session.Error = ex
|
||||
Return Session
|
||||
End Try
|
||||
|
||||
ElseIf Session.AuthType = AUTH_SSLTLS Or Session.AuthType = AUTH_STARTTLS Then
|
||||
|
||||
Try
|
||||
Logger.Debug("Connecting with [Connect] on [{0}/{1}]", pSession.Server, pSession.Port)
|
||||
Client.Connect(pSession.Server, pSession.Port)
|
||||
Logger.Info("Connection Successful!")
|
||||
|
||||
Dim oSupportsSTARTTLS As Boolean = SupportsSTARTTLS(Client)
|
||||
Logger.Debug("Server supports STARTTLS: [{0}]", oSupportsSTARTTLS)
|
||||
|
||||
If oSupportsSTARTTLS Then
|
||||
DoSTARTTLS(Client)
|
||||
Logger.Info("STARTTLS Successful!")
|
||||
Else
|
||||
Logger.Debug("Server does not support STARTTLS. Enabling TLS1.2 instead.")
|
||||
Client.SSLConfiguration.EnabledSslProtocols = Security.Authentication.SslProtocols.Tls12
|
||||
End If
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Error while connecting with Auth type STARTTLS!")
|
||||
Logger.Error(ex)
|
||||
|
||||
pSession.Error = ex
|
||||
Return pSession
|
||||
End Try
|
||||
|
||||
Else
|
||||
Try
|
||||
Logger.Debug("Unknown Auth type. Using PLAINTEXT connection.")
|
||||
Client.Connect(pSession.Server, pSession.Port, useSSL:=False)
|
||||
Logger.Info("Connection Successful!")
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Error while connecting with Auth type PLAINTEXT!")
|
||||
Logger.Error(ex)
|
||||
|
||||
pSession.Error = ex
|
||||
Return pSession
|
||||
End Try
|
||||
|
||||
End If
|
||||
|
||||
Try
|
||||
If pSession.User <> String.Empty Then
|
||||
Logger.Info("Logging in with user [{0}] and Auth Type [{1}]", pSession.User, pSession.AuthType)
|
||||
|
||||
If pSession.AuthType = AUTH_OAUTH2 Then
|
||||
' SessionInfo.Password will be the access token that was obtained
|
||||
' in the OAuth2 flow before
|
||||
DoUseBestLogin_OAuth2(Client, pSession.User, pSession.Password)
|
||||
Else
|
||||
DoUseBestLogin_BasicAuth(Client, pSession.User, pSession.Password)
|
||||
End If
|
||||
|
||||
End If
|
||||
Catch ex As Exception
|
||||
Logger.Warn("Error while connecting with Auth type [{0}]!", pSession.AuthType)
|
||||
Logger.Error(ex)
|
||||
|
||||
pSession.Error = ex
|
||||
Return pSession
|
||||
End Try
|
||||
|
||||
pSession.Connected = True
|
||||
|
||||
Return pSession
|
||||
End Function
|
||||
|
||||
Public Function DisconnectFromServer() As Boolean
|
||||
Try
|
||||
If Client IsNot Nothing Then
|
||||
Logger.Debug("Closing connection to Server [{0}].", Session.Server)
|
||||
DoClose(Client)
|
||||
Session.Connected = False
|
||||
Logger.Info("Connection to Server [{0}] closed.", Session.Server)
|
||||
Else
|
||||
Logger.Debug("No connection currently open. Exiting.")
|
||||
End If
|
||||
|
||||
Return True
|
||||
|
||||
Catch ex As Exception
|
||||
Logger.Error(ex)
|
||||
Return False
|
||||
|
||||
End Try
|
||||
End Function
|
||||
|
||||
Public Async Function TestLogin(pServer As String, pPort As Integer, pUser As String, pPassword As String, pAuthType As String, pOptions As MailSessionOptions) As Task(Of Boolean)
|
||||
Dim oInfo = Await ConnectToServer(pServer, pPort, pUser, pPassword, pAuthType, pOptions)
|
||||
If oInfo.Connected Then
|
||||
If DisconnectFromServer() Then
|
||||
Return True
|
||||
Else
|
||||
Logger.Warn("Login Test failed while disconnecting.")
|
||||
Return False
|
||||
End If
|
||||
Else
|
||||
Logger.Warn("Login Test Failed while connecting.")
|
||||
Return False
|
||||
End If
|
||||
End Function
|
||||
|
||||
|
||||
Private Function SupportsSTARTTLS(pClient As ClientBase)
|
||||
If TypeOf pClient Is Smtp Then
|
||||
Return DirectCast(pClient, Smtp).SupportedExtensions.Contains(SmtpExtension.StartTLS)
|
||||
ElseIf TypeOf pClient Is Imap Then
|
||||
Return DirectCast(pClient, Imap).SupportedExtensions.Contains(ImapExtension.StartTLS)
|
||||
Else
|
||||
Logger.Error("Unknown session type: [{0}]", pClient.GetType.ToString)
|
||||
Return False
|
||||
End If
|
||||
End Function
|
||||
|
||||
Private Sub DoClose(pClient As ClientBase)
|
||||
If TypeOf pClient Is Smtp Then
|
||||
DirectCast(pClient, Smtp).Close()
|
||||
ElseIf TypeOf pClient Is Imap Then
|
||||
DirectCast(pClient, Imap).Close()
|
||||
Else
|
||||
Logger.Error("Unknown session type: [{0}]", pClient.GetType.ToString)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub DoUseBestLogin_BasicAuth(pClient As ClientBase, pUserName As String, pPassword As String)
|
||||
If TypeOf pClient Is Smtp Then
|
||||
DirectCast(pClient, Smtp).UseBestLogin(pUserName, pPassword)
|
||||
ElseIf TypeOf pClient Is Imap Then
|
||||
DirectCast(pClient, Imap).UseBestLogin(pUserName, pPassword)
|
||||
Else
|
||||
Logger.Error("Unknown session type: [{0}]", pClient.GetType.ToString)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub DoUseBestLogin_OAuth2(pClient As ClientBase, pUserName As String, pAccessToken As String)
|
||||
If TypeOf pClient Is Imap Then
|
||||
DirectCast(pClient, Imap).LoginOAUTH2(pUserName, pAccessToken)
|
||||
Else
|
||||
Logger.Error("Unknown session type: [{0}]", pClient.GetType.ToString)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub DoSTARTTLS(pClient As ClientBase)
|
||||
If TypeOf pClient Is Smtp Then
|
||||
DirectCast(pClient, Smtp).StartTLS()
|
||||
ElseIf TypeOf pClient Is Imap Then
|
||||
DirectCast(pClient, Imap).StartTLS()
|
||||
Else
|
||||
Logger.Error("Unknown session type: [{0}]", pClient.GetType.ToString)
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Private Sub Session_ServerCertificateValidate(sender As Object, e As ServerCertificateValidateEventArgs)
|
||||
' i dont know why it works but it does
|
||||
If (e.SslPolicyErrors And Not SMTP_IGNORED_ERRORS) = SslPolicyErrors.None Then
|
||||
e.IsValid = True
|
||||
Else
|
||||
e.IsValid = False
|
||||
End If
|
||||
End Sub
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
Reference in New Issue
Block a user