2 Commits
v3.1 ... v3.1.2

Author SHA1 Message Date
41c3904e85 Upgrade e-mail config 2023-07-09 23:08:10 -04:00
5d431b81c7 Add canonical domain support 2023-07-08 18:20:48 -04:00
5 changed files with 53 additions and 14 deletions

View File

@@ -14,6 +14,7 @@ RUN dotnet restore
COPY . ./ COPY . ./
WORKDIR /jjj/JobsJobsJobs/Application WORKDIR /jjj/JobsJobsJobs/Application
RUN dotnet publish -c Release -r linux-x64 RUN dotnet publish -c Release -r linux-x64
RUN rm bin/Release/net7.0/linux-x64/publish/appsettings.*.json
FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine as final FROM mcr.microsoft.com/dotnet/aspnet:7.0-alpine as final
WORKDIR /app WORKDIR /app

View File

@@ -3,6 +3,7 @@ module JobsJobsJobs.App
open System open System
open System.Text open System.Text
open BitBadger.AspNetCore.CanonicalDomains
open Giraffe open Giraffe
open Giraffe.EndpointRouting open Giraffe.EndpointRouting
open JobsJobsJobs.Common.Data open JobsJobsJobs.Common.Data
@@ -58,6 +59,9 @@ let main args =
opts.Cookie.HttpOnly <- true opts.Cookie.HttpOnly <- true
opts.Cookie.IsEssential <- true) opts.Cookie.IsEssential <- true)
let emailCfg = cfg.GetSection "Email"
if (emailCfg.GetChildren >> Seq.isEmpty >> not) () then ConfigurationBinder.Bind(emailCfg, Email.options)
let app = builder.Build () let app = builder.Build ()
// Unify the endpoints from all features // Unify the endpoints from all features
@@ -71,6 +75,7 @@ let main args =
] ]
let _ = app.UseForwardedHeaders () let _ = app.UseForwardedHeaders ()
let _ = app.UseCanonicalDomains ()
let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict)) let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict))
let _ = app.UseStaticFiles () let _ = app.UseStaticFiles ()
let _ = app.UseRouting () let _ = app.UseRouting ()

View File

@@ -29,4 +29,8 @@
<PackageReference Update="FSharp.Core" Version="7.0.300" /> <PackageReference Update="FSharp.Core" Version="7.0.300" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="BitBadger.AspNetCore.CanonicalDomains" Version="1.0.0" />
</ItemGroup>
</Project> </Project>

View File

@@ -3,17 +3,41 @@ module JobsJobsJobs.Email
open System.Net open System.Net
open JobsJobsJobs.Domain open JobsJobsJobs.Domain
open MailKit.Net.Smtp open MailKit.Net.Smtp
open MailKit.Security
open MimeKit open MimeKit
/// Options to use when sending e-mail
type EmailOptions() =
/// The hostname of the SMTP server
member val SmtpHost : string = "localhost" with get, set
/// The port over which SMTP communication should occur
member val Port : int = 25 with get, set
/// Whether to use SSL when communicating with the SMTP server
member val UseSsl : bool = false with get, set
/// The authentication to use with the SMTP server
member val Authentication : string = "" with get, set
/// The e-mail address from which messages should be sent
member val FromAddress : string = "nobody@noagendacareers.com" with get, set
/// The name from which messages should be sent
member val FromName : string = "Jobs, Jobs, Jobs" with get, set
/// The options for the SMTP server
let mutable options = EmailOptions ()
/// Private functions for sending e-mail /// Private functions for sending e-mail
[<AutoOpen>] [<AutoOpen>]
module private Helpers = module private Helpers =
/// Create an SMTP client /// Create an SMTP client
let smtpClient () = backgroundTask { let createClient () = backgroundTask {
let client = new SmtpClient () let client = new SmtpClient ()
do! client.ConnectAsync ("localhost", 25, SecureSocketOptions.None) do! client.ConnectAsync (options.SmtpHost, options.Port, options.UseSsl)
do! client.AuthenticateAsync (options.FromAddress, options.Authentication)
return client return client
} }
@@ -24,13 +48,19 @@ module private Helpers =
msg.To.Add (MailboxAddress (Citizen.name citizen, citizen.Email)) msg.To.Add (MailboxAddress (Citizen.name citizen, citizen.Email))
msg.Subject <- subject msg.Subject <- subject
msg msg
/// Send a message
let sendMessage msg = backgroundTask {
use! client = createClient ()
let! result = client.SendAsync msg
do! client.DisconnectAsync true
return result
}
/// Send an account confirmation e-mail /// Send an account confirmation e-mail
let sendAccountConfirmation citizen security = backgroundTask { let sendAccountConfirmation citizen security = backgroundTask {
let token = WebUtility.UrlEncode security.Token.Value let token = WebUtility.UrlEncode security.Token.Value
use! client = smtpClient () use msg = createMessage citizen "Account Confirmation Request"
use msg = createMessage citizen "Account Confirmation Request"
let text = let text =
[ $"ITM, {Citizen.name citizen}!" [ $"ITM, {Citizen.name citizen}!"
@@ -57,14 +87,13 @@ let sendAccountConfirmation citizen security = backgroundTask {
use msgText = new TextPart (Text = text) use msgText = new TextPart (Text = text)
msg.Body <- msgText msg.Body <- msgText
return! client.SendAsync msg return! sendMessage msg
} }
/// Send a password reset link /// Send a password reset link
let sendPasswordReset citizen security = backgroundTask { let sendPasswordReset citizen security = backgroundTask {
let token = WebUtility.UrlEncode security.Token.Value let token = WebUtility.UrlEncode security.Token.Value
use! client = smtpClient () use msg = createMessage citizen "Reset Password for Jobs, Jobs, Jobs"
use msg = createMessage citizen "Reset Password for Jobs, Jobs, Jobs"
let text = let text =
[ $"ITM, {Citizen.name citizen}!" [ $"ITM, {Citizen.name citizen}!"
@@ -90,5 +119,5 @@ let sendPasswordReset citizen security = backgroundTask {
use msgText = new TextPart (Text = text) use msgText = new TextPart (Text = text)
msg.Body <- msgText msg.Body <- msgText
return! client.SendAsync msg return! sendMessage msg
} }

View File

@@ -4,7 +4,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
<GenerateDocumentationFile>false</GenerateDocumentationFile> <GenerateDocumentationFile>false</GenerateDocumentationFile>
<AssemblyVersion>3.1.0.0</AssemblyVersion> <AssemblyVersion>3.1.2.0</AssemblyVersion>
<FileVersion>3.1.0.0</FileVersion> <FileVersion>3.1.2.0</FileVersion>
</PropertyGroup> </PropertyGroup>
</Project> </Project>