diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..a83b330
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,41 @@
+name: Build and Publish
+
+on:
+ workflow_dispatch: # Allow running the workflow manually from the GitHub UI
+ push:
+ paths:
+ - 'Src/**'
+ - '.github/workflows/**'
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Setup .NET 8.0
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+ - name: Restore dependencies
+ working-directory: ./Src
+ run: dotnet restore
+ - name: Build
+ working-directory: ./Src
+ run: dotnet build --configuration Release --no-restore
+ - name: Test
+ working-directory: ./Src
+ run: |
+ dotnet test --configuration Release --no-restore --no-build --verbosity normal
+ #- name: Create NuGet packages
+ # run: |
+ # dotnet pack --configuration Release --output $GITHUB_WORKSPACE/out Src/SmtpServer/SmtpServer.csproj
+ #- name: Push NuGet packages
+ # run: |
+ # dotnet nuget push $GITHUB_WORKSPACE/out/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.NUGET_TOKEN}} --skip-duplicate --no-symbols
\ No newline at end of file
diff --git a/Examples/SampleApp/SampleApp.csproj b/Examples/SampleApp/SampleApp.csproj
index f84b784..77cfe22 100644
--- a/Examples/SampleApp/SampleApp.csproj
+++ b/Examples/SampleApp/SampleApp.csproj
@@ -2,7 +2,7 @@
Exe
- net5.0
+ net8.0
@@ -15,7 +15,7 @@
-
+
diff --git a/Examples/WorkerService/WorkerService.csproj b/Examples/WorkerService/WorkerService.csproj
index e5dfbb7..4aeeed1 100644
--- a/Examples/WorkerService/WorkerService.csproj
+++ b/Examples/WorkerService/WorkerService.csproj
@@ -1,12 +1,12 @@
- net5.0
+ net8.0
dotnet-WorkerService-1397719A-187C-45F4-8DB3-2427A449DD89
-
+
diff --git a/Src/SmtpServer.Benchmarks/SmtpServer.Benchmarks.csproj b/Src/SmtpServer.Benchmarks/SmtpServer.Benchmarks.csproj
index 3a94f4b..7dd835a 100644
--- a/Src/SmtpServer.Benchmarks/SmtpServer.Benchmarks.csproj
+++ b/Src/SmtpServer.Benchmarks/SmtpServer.Benchmarks.csproj
@@ -2,7 +2,7 @@
Exe
- net5.0
+ net8.0
@@ -20,7 +20,7 @@
-
+
diff --git a/Src/SmtpServer.Tests/MailClient.cs b/Src/SmtpServer.Tests/MailClient.cs
index b1ee5b9..89653f5 100644
--- a/Src/SmtpServer.Tests/MailClient.cs
+++ b/Src/SmtpServer.Tests/MailClient.cs
@@ -1,8 +1,8 @@
-using System.Threading;
-using MailKit.Net.Smtp;
+using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using MimeKit.Text;
+using System.Threading;
namespace SmtpServer.Tests
{
@@ -49,7 +49,8 @@ public static MimeMessage Message(
public static SmtpClientEx Client(string host = "localhost", int port = 9025, SecureSocketOptions options = SecureSocketOptions.Auto)
{
var client = new SmtpClientEx();
-
+ client.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
+
client.Connected += (sender, args) =>
{
diff --git a/Src/SmtpServer.Tests/SmtpServer.Tests.csproj b/Src/SmtpServer.Tests/SmtpServer.Tests.csproj
index 6e8b39f..38bb095 100644
--- a/Src/SmtpServer.Tests/SmtpServer.Tests.csproj
+++ b/Src/SmtpServer.Tests/SmtpServer.Tests.csproj
@@ -1,14 +1,14 @@
- net5.0
+ net8.0
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Src/SmtpServer.Tests/SmtpServerTests.cs b/Src/SmtpServer.Tests/SmtpServerTests.cs
index ff7a60f..1c62dc7 100644
--- a/Src/SmtpServer.Tests/SmtpServerTests.cs
+++ b/Src/SmtpServer.Tests/SmtpServerTests.cs
@@ -1,20 +1,21 @@
-using System;
+using MailKit;
+using SmtpServer.Authentication;
+using SmtpServer.ComponentModel;
+using SmtpServer.Mail;
+using SmtpServer.Net;
+using SmtpServer.Protocol;
+using SmtpServer.Storage;
+using SmtpServer.Tests.Mocks;
+using System;
using System.IO;
using System.Net;
-using System.Net.Security;
using System.Security.Authentication;
+using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
-using MailKit;
-using SmtpServer.Mail;
-using SmtpServer.Tests.Mocks;
using Xunit;
-using SmtpServer.Authentication;
-using SmtpServer.ComponentModel;
-using SmtpServer.Net;
-using SmtpServer.Protocol;
-using SmtpServer.Storage;
using SmtpResponse = SmtpServer.Protocol.SmtpResponse;
namespace SmtpServer.Tests
@@ -51,6 +52,8 @@ public void CanReceiveMessage()
[InlineData("שלום שלום שלום", "windows-1255")]
public void CanReceiveUnicodeMimeMessage(string text, string charset)
{
+ Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
+
using (CreateServer())
{
// act
@@ -245,59 +248,49 @@ public void DoesNotSecureTheSessionWhenCertificateIsEmpty()
[Fact]
public void SecuresTheSessionWhenCertificateIsSupplied()
{
- ServicePointManager.ServerCertificateValidationCallback = IgnoreCertificateValidationFailureForTestingOnly;
+ using var disposable = CreateServer(options => options.Certificate(CreateCertificate()));
- using (var disposable = CreateServer(options => options.Certificate(CreateCertificate())))
- {
- var isSecure = false;
- var sessionCreatedHandler = new EventHandler(
- delegate (object sender, SessionEventArgs args)
+ var isSecure = false;
+ var sessionCreatedHandler = new EventHandler(
+ delegate (object sender, SessionEventArgs args)
+ {
+ args.Context.CommandExecuted += (_, commandArgs) =>
{
- args.Context.CommandExecuted += (_, commandArgs) =>
- {
- isSecure = commandArgs.Context.Pipe.IsSecure;
- };
- });
+ isSecure = commandArgs.Context.Pipe.IsSecure;
+ };
+ });
- disposable.Server.SessionCreated += sessionCreatedHandler;
-
- MailClient.Send();
+ disposable.Server.SessionCreated += sessionCreatedHandler;
- disposable.Server.SessionCreated -= sessionCreatedHandler;
-
- Assert.True(isSecure);
- }
+ MailClient.Send();
- ServicePointManager.ServerCertificateValidationCallback = null;
+ disposable.Server.SessionCreated -= sessionCreatedHandler;
+
+ Assert.True(isSecure);
}
[Fact]
public void SecuresTheSessionByDefault()
{
- ServicePointManager.ServerCertificateValidationCallback = IgnoreCertificateValidationFailureForTestingOnly;
+ using var disposable = CreateServer(endpoint => endpoint.IsSecure(true).Certificate(CreateCertificate()));
- using (var disposable = CreateServer(endpoint => endpoint.IsSecure(true).Certificate(CreateCertificate())))
- {
- var isSecure = false;
- var sessionCreatedHandler = new EventHandler(
- delegate (object sender, SessionEventArgs args)
+ var isSecure = false;
+ var sessionCreatedHandler = new EventHandler(
+ delegate (object sender, SessionEventArgs args)
+ {
+ args.Context.CommandExecuted += (_, commandArgs) =>
{
- args.Context.CommandExecuted += (_, commandArgs) =>
- {
- isSecure = commandArgs.Context.Pipe.IsSecure;
- };
- });
+ isSecure = commandArgs.Context.Pipe.IsSecure;
+ };
+ });
- disposable.Server.SessionCreated += sessionCreatedHandler;
-
- MailClient.NoOp(MailKit.Security.SecureSocketOptions.SslOnConnect);
+ disposable.Server.SessionCreated += sessionCreatedHandler;
- disposable.Server.SessionCreated -= sessionCreatedHandler;
-
- Assert.True(isSecure);
- }
+ MailClient.NoOp(MailKit.Security.SecureSocketOptions.SslOnConnect);
- ServicePointManager.ServerCertificateValidationCallback = null;
+ disposable.Server.SessionCreated -= sessionCreatedHandler;
+
+ Assert.True(isSecure);
}
[Fact]
@@ -305,35 +298,30 @@ public void ServerCanBeSecuredAndAuthenticated()
{
var userAuthenticator = new DelegatingUserAuthenticator((user, password) => true);
- ServicePointManager.ServerCertificateValidationCallback = IgnoreCertificateValidationFailureForTestingOnly;
-
- using (var disposable = CreateServer(
+ using var disposable = CreateServer(
endpoint => endpoint.AllowUnsecureAuthentication(true).Certificate(CreateCertificate()).SupportedSslProtocols(SslProtocols.Tls12),
- services => services.Add(userAuthenticator)))
- {
- var isSecure = false;
- ISessionContext sessionContext = null;
- var sessionCreatedHandler = new EventHandler(
- delegate (object sender, SessionEventArgs args)
- {
- sessionContext = args.Context;
- sessionContext.CommandExecuted += (_, commandArgs) =>
- {
- isSecure = commandArgs.Context.Pipe.IsSecure;
- };
- });
+ services => services.Add(userAuthenticator));
- disposable.Server.SessionCreated += sessionCreatedHandler;
+ var isSecure = false;
+ ISessionContext sessionContext = null;
+ var sessionCreatedHandler = new EventHandler(
+ delegate (object sender, SessionEventArgs args)
+ {
+ sessionContext = args.Context;
+ sessionContext.CommandExecuted += (_, commandArgs) =>
+ {
+ isSecure = commandArgs.Context.Pipe.IsSecure;
+ };
+ });
- MailClient.Send(user: "user", password: "password");
+ disposable.Server.SessionCreated += sessionCreatedHandler;
- disposable.Server.SessionCreated -= sessionCreatedHandler;
+ MailClient.Send(user: "user", password: "password");
- Assert.True(isSecure);
- Assert.True(sessionContext.Authentication.IsAuthenticated);
- }
+ disposable.Server.SessionCreated -= sessionCreatedHandler;
- ServicePointManager.ServerCertificateValidationCallback = null;
+ Assert.True(isSecure);
+ Assert.True(sessionContext.Authentication.IsAuthenticated);
}
[Fact]
@@ -356,17 +344,38 @@ public void EndpointListenerWillRaiseEndPointEvents()
Assert.True(stopped);
}
- public static bool IgnoreCertificateValidationFailureForTestingOnly(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
+ public static X509Certificate2 CreateSelfSignedCertificate(string subjectName)
{
- return true;
+ var validityPeriodInYears = 1;
+
+ using RSA rsa = RSA.Create(2048); // 2048-Bit Key
+
+ var certificateRequest = new CertificateRequest(
+ $"CN={subjectName}", // Common Name (CN)
+ rsa,
+ HashAlgorithmName.SHA256, // Hash-Algorithmus
+ RSASignaturePadding.Pkcs1 // Padding Schema
+ );
+
+ certificateRequest.CertificateExtensions.Add(
+ new X509SubjectKeyIdentifierExtension(certificateRequest.PublicKey, false)
+ );
+
+ certificateRequest.CertificateExtensions.Add(
+ new X509BasicConstraintsExtension(true, false, 0, true)
+ );
+
+ DateTimeOffset notBefore = DateTimeOffset.UtcNow;
+ DateTimeOffset notAfter = notBefore.AddYears(validityPeriodInYears);
+
+ X509Certificate2 certificate = certificateRequest.CreateSelfSigned(notBefore, notAfter);
+
+ return new X509Certificate2(certificate.Export(X509ContentType.Pfx));
}
public static X509Certificate2 CreateCertificate()
{
- var certificate = File.ReadAllBytes(@"C:\Users\caino\Dropbox\Documents\Cain\Programming\SmtpServer\SmtpServer.pfx");
- var password = File.ReadAllText(@"C:\Users\caino\Dropbox\Documents\Cain\Programming\SmtpServer\SmtpServerPassword.txt");
-
- return new X509Certificate2(certificate, password);
+ return CreateSelfSignedCertificate("localhost");
}
///