From 551066ed9a255bd47c1c5789ec1998fda64bd5aa Mon Sep 17 00:00:00 2001 From: vnugent Date: Thu, 12 Jan 2023 17:47:40 -0500 Subject: Large project reorder and consolidation --- .../.gitattributes | 63 ---- .../.gitignore | 352 ------------------ .../readme.md | 0 .../src/AccountValidations.cs | 132 ------- .../src/EmailSystemConfig.cs | 153 -------- .../src/Endpoints/RegRequestMessage.cs | 40 --- .../src/Endpoints/RegistrationEntpoint.cs | 392 --------------------- .../src/RegistrationContext.cs | 39 -- .../src/RegistrationEntryPoint.cs | 66 ---- .../src/TokenRevocation/RevokedToken.cs | 43 --- .../src/TokenRevocation/RevokedTokenStore.cs | 101 ------ ...Plugins.Essentials.Accounts.Registration.csproj | 54 --- 12 files changed, 1435 deletions(-) delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/.gitattributes delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/.gitignore delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/readme.md delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/AccountValidations.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegRequestMessage.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationContext.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationEntryPoint.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedToken.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedTokenStore.cs delete mode 100644 VNLib.Plugins.Essentials.Accounts.Registration/src/VNLib.Plugins.Essentials.Accounts.Registration.csproj (limited to 'VNLib.Plugins.Essentials.Accounts.Registration') diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/.gitattributes b/VNLib.Plugins.Essentials.Accounts.Registration/.gitattributes deleted file mode 100644 index 1ff0c42..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/.gitattributes +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/.gitignore b/VNLib.Plugins.Essentials.Accounts.Registration/.gitignore deleted file mode 100644 index f17dcd9..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/.gitignore +++ /dev/null @@ -1,352 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -.json diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/readme.md b/VNLib.Plugins.Essentials.Accounts.Registration/readme.md deleted file mode 100644 index e69de29..0000000 diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/AccountValidations.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/AccountValidations.cs deleted file mode 100644 index b84728b..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/AccountValidations.cs +++ /dev/null @@ -1,132 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: AccountValidations.cs -* -* AccountValidations.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using FluentValidation; - -using VNLib.Plugins.Essentials.Accounts.Registration.Endpoints; -using VNLib.Plugins.Extensions.Validation; - -namespace VNLib.Plugins.Essentials.Accounts.Registration -{ - internal static class AccountValidations - { - /// - /// Central password requirement validator - /// - public static IValidator PasswordValidator { get; } = GetPassVal(); - - public static IValidator AccountDataValidator { get; } = GetAcVal(); - - /// - /// A validator used to validate new registration request messages - /// - public static IValidator RegRequestValidator { get; } = GetRequestValidator(); - - static IValidator GetPassVal() - { - InlineValidator passVal = new(); - - passVal.RuleFor(static password => password) - .NotEmpty() - .Length(min: 8, max: 100) - .Password() - .WithMessage(errorMessage: "Password does not meet minium requirements"); - - return passVal; - } - - static IValidator GetAcVal() - { - InlineValidator adv = new (); - - //Validate city - - adv.RuleFor(t => t.City) - .MaximumLength(35) - .AlphaOnly() - .When(t => t.City?.Length > 0); - - adv.RuleFor(t => t.Company) - .MaximumLength(50) - .SpecialCharacters() - .When(t => t.Company?.Length > 0); - - //Require a first and last names to be set together - adv.When(t => t.First?.Length > 0 || t.Last?.Length > 0, () => - { - adv.RuleFor(t => t.First) - .Length(1, 35) - .AlphaOnly(); - adv.RuleFor(t => t.Last) - .Length(1, 35) - .AlphaOnly(); - }); - - adv.RuleFor(t => t.PhoneNumber) - .PhoneNumber() - .When(t => t.PhoneNumber?.Length > 0) - .OverridePropertyName("Phone"); - - //State must be 2 characters for us states if set - adv.RuleFor(t => t.State) - .Length(2) - .When(t => t.State?.Length > 0); - - adv.RuleFor(t => t.Street) - .AlphaNumericOnly() - .MaximumLength(50) - .When(t => t.Street?.Length > 0); - - //Allow empty zip codes, but if one is defined, is must be less than 7 characters - adv.RuleFor(t => t.Zip) - .NumericOnly() - .MaximumLength(7) - .When(t => t.Zip?.Length > 0); - - return adv; - } - - static IValidator GetRequestValidator() - { - InlineValidator reqVal = new(); - - reqVal.RuleFor(static s => s.ClientId) - .NotEmpty() - .AlphaNumericOnly() - .Length(1, 100); - - //Convert to universal time before validating - reqVal.RuleFor(static s => s.Timestamp.ToUniversalTime()) - .Must(t => t > DateTimeOffset.UtcNow.AddSeconds(-60) && t < DateTimeOffset.UtcNow.AddSeconds(60)); - - reqVal.RuleFor(static s => s.UserName) - .NotEmpty() - .EmailAddress() - .IllegalCharacters() - .Length(5, 50); - - return reqVal; - } - } -} diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs deleted file mode 100644 index 238ae37..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/EmailSystemConfig.cs +++ /dev/null @@ -1,153 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: EmailSystemConfig.cs -* -* EmailSystemConfig.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Text; -using System.Text.Json; - -using RestSharp; - -using Emails.Transactional.Client; - -using VNLib.Utils.Extensions; -using VNLib.Net.Rest.Client; -using VNLib.Net.Rest.Client.OAuth2; -using VNLib.Plugins.Extensions.Loading; - -namespace VNLib.Plugins.Essentials.Accounts.Registration -{ - /// - /// An extended configuration - /// object that contains a pool for making - /// transactions - /// - internal sealed class EmailSystemConfig : TransactionalEmailConfig - { - public const string REG_TEMPLATE_NAME = "Registration"; - - public EmailSystemConfig(PluginBase pbase) - { - IReadOnlyDictionary conf = pbase.GetConfig("email"); - EmailFromName = conf["from_name"].GetString() ?? throw new KeyNotFoundException(""); - EmailFromAddress = conf["from_address"].GetString() ?? throw new KeyNotFoundException(""); - Uri baseServerPath = new(conf["base_url"].GetString()!, UriKind.RelativeOrAbsolute); - Uri tokenServerBase = new(conf["token_server_url"].GetString()!, UriKind.RelativeOrAbsolute); - Uri transactionEndpoint = new(conf["transaction_path"].GetString()!, UriKind.RelativeOrAbsolute); - //Load templates - Dictionary templates = conf["templates"].EnumerateObject().ToDictionary(jp => jp.Name, jp => jp.Value.GetString()!); - //Init base config - WithTemplates(templates) - .WithUrl(transactionEndpoint); - //Load credentials - string authEndpoint = conf["token_path"].GetString() ?? throw new KeyNotFoundException(); - int maxClients = conf["max_clients"].GetInt32(); - - - //Load oauth secrets from vault - Task oauth2ClientID = pbase.TryGetSecretAsync("oauth2_client_id"); - Task oauth2Password = pbase.TryGetSecretAsync("oauth2_client_secret"); - - //Lazy cred loaded, tasks should be loaded before this method will ever get called - Credential lazyCredentialGet() - { - //Load the results - SecretResult cliendId = oauth2ClientID.Result ?? throw new KeyNotFoundException("Missing required oauth2 client id"); - SecretResult password = oauth2Password.Result ?? throw new KeyNotFoundException("Missing required oauth2 client secret"); - - //Creat credential - return Credential.Create(cliendId.Result, password.Result); - } - - - //Init client creation options - RestClientOptions poolOptions = new() - { - AllowMultipleDefaultParametersWithSameName = true, - AutomaticDecompression = System.Net.DecompressionMethods.All, - PreAuthenticate = true, - Encoding = Encoding.UTF8, - MaxTimeout = conf["request_timeout_ms"].GetInt32(), - UserAgent = "Essentials.EmailRegistation", - FollowRedirects = false, - BaseUrl = baseServerPath - }; - //Options for auth token endpoint - RestClientOptions oAuth2ClientOptions = new() - { - AllowMultipleDefaultParametersWithSameName = true, - AutomaticDecompression = System.Net.DecompressionMethods.All, - PreAuthenticate = false, - Encoding = Encoding.UTF8, - MaxTimeout = conf["request_timeout_ms"].GetInt32(), - UserAgent = "Essentials.EmailRegistation", - FollowRedirects = false, - BaseUrl = baseServerPath - }; - - //Init Oauth authenticator - OAuth2Authenticator authenticator = new(oAuth2ClientOptions, lazyCredentialGet, authEndpoint); - //Store pool - RestClientPool = new(maxClients, poolOptions, authenticator:authenticator); - - void Cleanup() - { - authenticator.Dispose(); - RestClientPool.Dispose(); - oauth2ClientID.Dispose(); - oauth2Password.Dispose(); - } - - //register password cleanup - _ = pbase.UnloadToken.RegisterUnobserved(Cleanup); - } - - /// - /// A shared for renting configuraed - /// - /// - public RestClientPool RestClientPool { get; } - /// - /// A global from email address name - /// - public string EmailFromName { get; } - /// - /// A global from email address - /// - public string EmailFromAddress { get; } - - /// - /// Prepares a new registration email transaction request - /// - /// The prepared object - public EmailTransactionRequest GetRegistrationMessage() - { - EmailTransactionRequest req = GetTemplateRequest(REG_TEMPLATE_NAME); - req.FromAddress = EmailFromAddress; - req.FromName = EmailFromName; - //set reg subject - req.Subject = "One more step to register"; - return req; - } - } -} \ No newline at end of file diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegRequestMessage.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegRequestMessage.cs deleted file mode 100644 index 0683067..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegRequestMessage.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: RegRequestMessage.cs -* -* RegRequestMessage.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System.Text.Json.Serialization; - -namespace VNLib.Plugins.Essentials.Accounts.Registration.Endpoints -{ - internal class RegRequestMessage - { - [JsonPropertyName("localtime")] - public DateTimeOffset Timestamp { get; set; } - - [JsonPropertyName("username")] - public string? UserName { get; set; } - - [JsonPropertyName("clientid")] - public string? ClientId { get; set; } - } -} \ No newline at end of file diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs deleted file mode 100644 index 74f2aa1..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/Endpoints/RegistrationEntpoint.cs +++ /dev/null @@ -1,392 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: RegistrationEntpoint.cs -* -* RegistrationEntpoint.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.Net; -using System.Text.Json; -using System.Threading.Tasks; -using System.Security.Cryptography; - -using FluentValidation; - -using Emails.Transactional.Client; -using Emails.Transactional.Client.Exceptions; - -using VNLib.Hashing; -using VNLib.Utils.Memory; -using VNLib.Utils.Logging; -using VNLib.Utils.Extensions; -using VNLib.Hashing.IdentityUtility; -using VNLib.Net.Rest.Client; -using VNLib.Net.Rest.Client.OAuth2; -using VNLib.Plugins.Essentials.Users; -using VNLib.Plugins.Essentials.Endpoints; -using VNLib.Plugins.Essentials.Extensions; -using VNLib.Plugins.Extensions.Loading; -using VNLib.Plugins.Extensions.Loading.Sql; -using VNLib.Plugins.Extensions.Loading.Events; -using VNLib.Plugins.Extensions.Loading.Users; -using VNLib.Plugins.Extensions.Validation; -using VNLib.Plugins.Essentials.Accounts.Registration.TokenRevocation; -using static VNLib.Plugins.Essentials.Accounts.AccountManager; - - -namespace VNLib.Plugins.Essentials.Accounts.Registration.Endpoints -{ - - [ConfigurationName("registration")] - internal sealed class RegistrationEntpoint : UnprotectedWebEndpoint, IIntervalScheduleable - { - /// - /// Generates a CNG random buffer to use as a nonce - /// - private static string EntropyNonce => RandomHash.GetRandomHex(16); - - const string FAILED_AUTH_ERR = "Your registration does not exist, you should try to regisiter again."; - const string REG_ERR_MESSAGE = "Please check your email inbox."; - - private HMAC SigAlg => new HMACSHA256(RegSignatureKey.Result); - - private readonly IUserManager Users; - private readonly IValidator RegJwtValdidator; - private readonly PasswordHashing Passwords; - private readonly RevokedTokenStore RevokedTokens; - private readonly EmailSystemConfig Emails; - private readonly Task RegSignatureKey; - private readonly TimeSpan RegExpiresSec; - - /// - /// Creates back-end functionality for a "registration" or "sign-up" page that integrates with the plugin - /// - /// The path identifier - /// - public RegistrationEntpoint(PluginBase plugin, IReadOnlyDictionary config) - { - string? path = config["path"].GetString(); - - InitPathAndLog(path, plugin.Log); - - RegExpiresSec = config["reg_expires_sec"].GetTimeSpan(TimeParseType.Seconds); - - //Init reg jwt validator - RegJwtValdidator = GetJwtValidator(); - - Passwords = plugin.GetPasswords(); - Users = plugin.GetUserManager(); - RevokedTokens = new(plugin.GetContextOptions()); - Emails = new(plugin); - - //Begin the async op to get the signature key from the vault - RegSignatureKey = plugin.TryGetSecretAsync("reg_sig_key").ContinueWith((ts) => { - - using SecretResult? sr = ts.Result ?? throw new KeyNotFoundException("Missing required key 'reg_sig_key' in 'registration' configuration"); - return ts.Result.GetFromBase64(); - - }, TaskScheduler.Default); - - //Register timeout for cleanup - plugin.ScheduleInterval(this, TimeSpan.FromSeconds(60)); - } - - private static IValidator GetJwtValidator() - { - InlineValidator val = new(); - - val.RuleFor(static s => s) - .NotEmpty() - //Must contain 2 periods for jwt limitation - .Must(static s => s.Count(s => s == '.') == 2) - //Guard length - .Length(20, 500) - .IllegalCharacters(); - return val; - } - - - protected override async ValueTask PostAsync(HttpEntity entity) - { - ValErrWebMessage webm = new(); - //Get the json request data from client - using JsonDocument? request = await entity.GetJsonFromFileAsync(); - - if(webm.Assert(request != null, "No request data present")) - { - entity.CloseResponseJson(HttpStatusCode.BadRequest, webm); - return VfReturnType.VirtualSkip; - } - - //Get the jwt string from client - string? regJwt = request.RootElement.GetPropString("token"); - using PrivateString? password = (PrivateString?)request.RootElement.GetPropString("password"); - - //validate inputs - { - if (webm.Assert(regJwt != null, FAILED_AUTH_ERR)) - { - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - - if (webm.Assert(password != null, "You must specify a password.")) - { - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - //validate new password - if(!AccountValidations.PasswordValidator.Validate((string)password, webm)) - { - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - //Validate jwt - if (webm.Assert(RegJwtValdidator.Validate(regJwt).IsValid, FAILED_AUTH_ERR)) - { - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - } - - //Verify jwt has not been revoked - if(await RevokedTokens.IsRevokedAsync(regJwt, entity.EventCancellation)) - { - webm.Result = FAILED_AUTH_ERR; - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - - string emailAddress; - try - { - //get jwt - using JsonWebToken jwt = JsonWebToken.Parse(regJwt); - //verify signature - using (HMAC hmac = SigAlg) - { - bool verified = jwt.Verify(hmac); - - if (webm.Assert(verified, FAILED_AUTH_ERR)) - { - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - } - - //recover iat and email address - using JsonDocument reg = jwt.GetPayload(); - emailAddress = reg.RootElement.GetPropString("email")!; - DateTimeOffset iat = DateTimeOffset.FromUnixTimeSeconds(reg.RootElement.GetProperty("iat").GetInt64()); - - //Verify IAT against expiration at second resolution - if (webm.Assert(iat.Add(RegExpiresSec) > DateTimeOffset.UtcNow, FAILED_AUTH_ERR)) - { - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - } - catch (FormatException fe) - { - Log.Debug(fe); - webm.Result = FAILED_AUTH_ERR; - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - - - //Always hash the new password, even if failed - using PrivateString passHash = Passwords.Hash(password); - - try - { - //Generate userid from email - string uid = GetRandomUserId(); - - //Create the new user - using IUser user = await Users.CreateUserAsync(uid, emailAddress, MINIMUM_LEVEL, passHash, entity.EventCancellation); - - //Set active status - user.Status = UserStatus.Active; - //set local account origin - user.SetAccountOrigin(LOCAL_ACCOUNT_ORIGIN); - - //set user verification - await user.ReleaseAsync(); - - //Revoke token now complete - _ = RevokedTokens.RevokeAsync(regJwt, CancellationToken.None).ConfigureAwait(false); - - webm.Result = "Successfully created your new account. You may now log in"; - webm.Success = true; - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - //Capture creation failed, this may be a replay - catch (UserExistsException) - { - } - catch(UserCreationFailedException) - { - } - - webm.Result = FAILED_AUTH_ERR; - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - - - private static readonly IReadOnlyDictionary JWT_HEADER = new Dictionary() - { - { "typ", "JWT" }, - { "alg", "HS256" } - }; - - protected override async ValueTask PutAsync(HttpEntity entity) - { - ValErrWebMessage webm = new(); - - //Get the request - RegRequestMessage? request = await entity.GetJsonFromFileAsync(); - if (webm.Assert(request != null, "Request is invalid")) - { - entity.CloseResponseJson(HttpStatusCode.BadRequest, webm); - return VfReturnType.VirtualSkip; - } - - //Validate the request - if (!AccountValidations.RegRequestValidator.Validate(request, webm)) - { - entity.CloseResponseJson(HttpStatusCode.UnprocessableEntity, webm); - return VfReturnType.VirtualSkip; - } - - //Create psudo contant time delay - Task delay = Task.Delay(200); - - //See if a user account already exists - using (IUser? user = await Users.GetUserFromEmailAsync(request.UserName!, entity.EventCancellation)) - { - if (user != null) - { - goto Exit; - } - } - - //Get exact timestamp - DateTimeOffset timeStamp = DateTimeOffset.UtcNow; - - //generate random nonce for entropy - string entropy = EntropyNonce; - - //Init client jwt - string jwtData; - using (JsonWebToken emailJwt = new()) - { - - emailJwt.WriteHeader(JWT_HEADER); - - //Init new claim stack, include the same iat time, nonce for entropy, and descriptor storage id - emailJwt.InitPayloadClaim(3) - .AddClaim("iat", timeStamp.ToUnixTimeSeconds()) - .AddClaim("n", entropy) - .AddClaim("email", request.UserName) - .CommitClaims(); - - //sign the jwt - using (HMAC hmac = SigAlg) - { - emailJwt.Sign(hmac); - } - //Compile to encoded string - jwtData = emailJwt.Compile(); - } - - string regUrl = $"https://{entity.Server.RequestUri.Authority}{Path}?t={jwtData}"; - - //Send email to user in background task and do not await it - _ = SendRegEmailAsync(request.UserName!, regUrl).ConfigureAwait(false); - - Exit: - //await sort of constant time delay - await delay; - - //Notify user - webm.Result = REG_ERR_MESSAGE; - webm.Success = true; - - entity.CloseResponse(webm); - return VfReturnType.VirtualSkip; - } - - - private async Task SendRegEmailAsync(string emailAddress, string url) - { - try - { - //Get a new registration template - EmailTransactionRequest emailTemplate = Emails.GetRegistrationMessage(); - //Add the user's to address - emailTemplate.AddToAddress(emailAddress); - emailTemplate.AddVariable("username", emailAddress); - //Set the security code variable string - emailTemplate.AddVariable("reg_url", url); - emailTemplate.AddVariable("date", DateTimeOffset.UtcNow.ToString("f")); - - //Get a new client contract - using ClientContract client = Emails.RestClientPool.Lease(); - //Send the email - TransactionResult result = await client.Resource.SendEmailAsync(emailTemplate); - if (!result.Success) - { - Log.Debug("Registration email failed to send, SMTP status code: {smtp}", result.SmtpStatus); - } - else - { - Log.Verbose("Registration email sent to user. Status {smtp}", result.SmtpStatus); - } - } - catch (ValidationFailedException vf) - { - //This should only occur if there is a bug in our reigration code that allowed an invalid value pass - Log.Debug(vf, "Registration email failed to send to user because data validation failed"); - } - catch (InvalidAuthorizationException iae) - { - Log.Warn(iae, "Registration email failed to send due to an authentication error"); - } - catch (OAuth2AuthenticationException o2e) - { - Log.Warn(o2e, "Registration email failed to send due to an authentication error"); - } - catch (Exception ex) - { - Log.Error(ex); - } - } - - async Task IIntervalScheduleable.OnIntervalAsync(ILogProvider log, CancellationToken cancellationToken) - { - //Cleanup tokens - await RevokedTokens.CleanTableAsync(RegExpiresSec, cancellationToken); - } - } -} \ No newline at end of file diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationContext.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationContext.cs deleted file mode 100644 index 611e30e..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationContext.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: RevocationContext.cs -* -* RevocationContext.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using Microsoft.EntityFrameworkCore; - -using VNLib.Plugins.Extensions.Data; -using VNLib.Plugins.Essentials.Accounts.Registration.TokenRevocation; - -namespace VNLib.Plugins.Essentials.Accounts.Registration -{ - internal class RegistrationContext : TransactionalDbContext - { - public DbSet RevokedRegistrationTokens { get; set; } - - public RegistrationContext(DbContextOptions options) : base(options) - {} - } -} \ No newline at end of file diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationEntryPoint.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationEntryPoint.cs deleted file mode 100644 index c24e7e0..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/RegistrationEntryPoint.cs +++ /dev/null @@ -1,66 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: RegistrationEntryPoint.cs -* -* RegistrationEntryPoint.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using VNLib.Utils.Logging; - -using VNLib.Plugins.Extensions.Loading; -using VNLib.Plugins.Extensions.Loading.Sql; -using VNLib.Plugins.Extensions.Loading.Routing; -using VNLib.Plugins.Essentials.Accounts.Registration.Endpoints; - -namespace VNLib.Plugins.Essentials.Accounts.Registration -{ - public sealed class RegistrationEntryPoint : PluginBase - { - public override string PluginName => "Essentials.EmailRegistration"; - - protected override void OnLoad() - { - try - { - //Route reg endpoint - this.Route(); - - Log.Information("Plugin loaded"); - } - catch(KeyNotFoundException kne) - { - Log.Error("Missing required configuration variables: {ex}", kne.Message); - } - } - - protected override void OnUnLoad() - { - Log.Information("Plugin unloaded"); - } - - protected override void ProcessHostCommand(string cmd) - { - if (!this.IsDebug()) - { - return; - } - } - } -} \ No newline at end of file diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedToken.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedToken.cs deleted file mode 100644 index c2b7715..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedToken.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: RevokedToken.cs -* -* RevokedToken.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System; -using System.ComponentModel.DataAnnotations; - -namespace VNLib.Plugins.Essentials.Accounts.Registration.TokenRevocation -{ - - internal class RevokedToken - { - /// - /// The time the token was revoked. - /// - public DateTime Created { get; set; } - /// - /// The token that was revoked. - /// - [Key] - public string? Token { get; set; } - } -} \ No newline at end of file diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedTokenStore.cs b/VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedTokenStore.cs deleted file mode 100644 index 89f4bd6..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/TokenRevocation/RevokedTokenStore.cs +++ /dev/null @@ -1,101 +0,0 @@ -/* -* Copyright (c) 2022 Vaughn Nugent -* -* Library: VNLib -* Package: VNLib.Plugins.Essentials.Accounts.Registration -* File: RevokedTokenStore.cs -* -* RevokedTokenStore.cs is part of VNLib.Plugins.Essentials.Accounts.Registration which is part of the larger -* VNLib collection of libraries and utilities. -* -* VNLib.Plugins.Essentials.Accounts.Registration is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License as -* published by the Free Software Foundation, either version 3 of the -* License, or (at your option) any later version. -* -* VNLib.Plugins.Essentials.Accounts.Registration is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see https://www.gnu.org/licenses/. -*/ - -using System.Collections; - -using Microsoft.EntityFrameworkCore; - -using VNLib.Utils; - -namespace VNLib.Plugins.Essentials.Accounts.Registration.TokenRevocation -{ - internal class RevokedTokenStore - { - private readonly DbContextOptions Options; - - public RevokedTokenStore(DbContextOptions options) - { - Options = options; - } - - public async Task IsRevokedAsync(string token, CancellationToken cancellation) - { - await using RegistrationContext context = new (Options); - await context.OpenTransactionAsync(cancellation); - - //Select any that match tokens - bool any = await (from t in context.RevokedRegistrationTokens - where t.Token == token - select t).AnyAsync(cancellation); - - await context.CommitTransactionAsync(cancellation); - return any; - } - - public async Task RevokeAsync(string token, CancellationToken cancellation) - { - await using RegistrationContext context = new (Options); - await context.OpenTransactionAsync(cancellation); - - //Add to table - context.RevokedRegistrationTokens.Add(new RevokedToken() - { - Created = DateTime.UtcNow, - Token = token - }); - - //Save changes and commit transaction - await context.SaveChangesAsync(cancellation); - await context.CommitTransactionAsync(cancellation); - } - - /// - /// Removes expired records from the store - /// - /// The time a token is valid for - /// A token that cancels the async operation - /// The number of records evicted from the store - public async Task CleanTableAsync(TimeSpan validFor, CancellationToken cancellation) - { - DateTime expiredBefore = DateTime.UtcNow.Subtract(validFor); - - await using RegistrationContext context = new (Options); - await context.OpenTransactionAsync(cancellation); - - //Select any that match tokens - RevokedToken[] expired = await context.RevokedRegistrationTokens.Where(t => t.Created < expiredBefore) - .Select(static t => t) - .ToArrayAsync(cancellation); - - - context.RevokedRegistrationTokens.RemoveRange(expired); - - ERRNO count =await context.SaveChangesAsync(cancellation); - - await context.CommitTransactionAsync(cancellation); - - return count; - } - } -} \ No newline at end of file diff --git a/VNLib.Plugins.Essentials.Accounts.Registration/src/VNLib.Plugins.Essentials.Accounts.Registration.csproj b/VNLib.Plugins.Essentials.Accounts.Registration/src/VNLib.Plugins.Essentials.Accounts.Registration.csproj deleted file mode 100644 index 8b2264e..0000000 --- a/VNLib.Plugins.Essentials.Accounts.Registration/src/VNLib.Plugins.Essentials.Accounts.Registration.csproj +++ /dev/null @@ -1,54 +0,0 @@ - - - - net6.0 - enable - enable - False - VNLib.Plugins.Essentials.Accounts.Registration - Vaughn Nugent - Copyright © 2022 Vaughn Nugent - https://www.vaughnnugent.com/resources - False - False - 1.0.0.1 - Essentials.EmailRegistration - False - True - \\vaughnnugent.com\Internal\Folder Redirection\vman\Documents\Programming\Software\StrongNameingKey.snk - - - - - - true - latest-all - - - False - - - False - - - - - - - - - - - - - - - PreserveNewest - - - - - - - - -- cgit