diff options
author | vnugent <public@vaughnnugent.com> | 2024-03-21 14:33:21 -0400 |
---|---|---|
committer | vnugent <public@vaughnnugent.com> | 2024-03-21 14:33:21 -0400 |
commit | f8aea6453ddb2d56c1ce2ecb6a9e67d1af523c2e (patch) | |
tree | b62d6086e93b8da32a1b5caa2c0981a1c1ed2518 | |
parent | cc29bed99dc9e151315cce75e50d55dca306b532 (diff) |
feat: Add optional svg base64 icons for social OAuth2 connections
9 files changed, 61 insertions, 19 deletions
diff --git a/lib/vnlib.browser/src/social/index.ts b/lib/vnlib.browser/src/social/index.ts index dac3cc9..7d80687 100644 --- a/lib/vnlib.browser/src/social/index.ts +++ b/lib/vnlib.browser/src/social/index.ts @@ -55,6 +55,7 @@ export interface SocialOAuthPortal { readonly id: string; readonly login: string; readonly logout?: string; + readonly icon?: string; } /** @@ -67,6 +68,10 @@ export interface OAuthMethod { */ readonly id: string; /** + * Optional bas64encoded icon image url for the method + */ + readonly icon?: string; + /** * Determines if the current flow is active for this method */ isActiveLogin(): boolean @@ -90,6 +95,10 @@ export interface SocialOauthMethod { */ readonly id: string /** + * Optional bas64encoded icon image url for the method + */ + readonly icon?: string + /** * The endpoint to submit the authentication request to */ loginUrl(): string @@ -214,7 +223,8 @@ export const fromSocialConnections = <T extends SocialOauthMethod>(methods: T[], return map(methods, method => { return{ id: method.id, - + icon: method.icon, + async beginLoginFlow() { //Prepare the login claim` const claim = await prepareLogin() @@ -314,6 +324,7 @@ export const fromSocialPortals = (portals: SocialOAuthPortal[]): SocialOauthMeth return map(portals, p => { return { id: p.id, + icon: p.icon, loginUrl : () => p.login, //Get the logout data from the server getLogoutData: () => ({ url: p.logout!, args: {}}), diff --git a/plugins/VNLib.Plugins.Essentials.Accounts/README.md b/plugins/VNLib.Plugins.Essentials.Accounts/README.md index 13f2dad..3caedb2 100644 --- a/plugins/VNLib.Plugins.Essentials.Accounts/README.md +++ b/plugins/VNLib.Plugins.Essentials.Accounts/README.md @@ -2,7 +2,7 @@ *An Essentials web plugin that provides endpoints for authenticating, registering, resetting, local user accounts including multi-factor authentication using TOTP (for now).* ### Dependency notice -This library uses some external dependencies: VaultSharp, Serilog, libargon2, and FluentValidation. +This library uses some external dependencies: Serilog, libargon2, and FluentValidation. ## Builds Debug build w/ symbols & xml docs, release builds, NuGet packages, and individually packaged source code are available on my website (link below). diff --git a/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs b/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs index 318f3ce..219239e 100644 --- a/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs +++ b/plugins/VNLib.Plugins.Essentials.Accounts/src/AccountsEntryPoint.cs @@ -92,7 +92,7 @@ namespace VNLib.Plugins.Essentials.Accounts this.ExportService<IAccountSecurityProvider>(securityProvider); //Also add the middleware array - this.ExportService(new IHttpMiddleware[] { securityProvider }); + this.ExportService<IHttpMiddleware[]>([ securityProvider ]); Log.Information("Configuring the account security provider service"); } diff --git a/plugins/VNLib.Plugins.Essentials.Accounts/src/SecurityProvider/AccountSecProvider.cs b/plugins/VNLib.Plugins.Essentials.Accounts/src/SecurityProvider/AccountSecProvider.cs index 8770930..3088ada 100644 --- a/plugins/VNLib.Plugins.Essentials.Accounts/src/SecurityProvider/AccountSecProvider.cs +++ b/plugins/VNLib.Plugins.Essentials.Accounts/src/SecurityProvider/AccountSecProvider.cs @@ -637,7 +637,7 @@ namespace VNLib.Plugins.Essentials.Accounts.SecurityProvider string base32SigningKey = VnEncoding.ToBase32String(signingKey, false); //Zero signing key now were done using it - MemoryUtil.InitializeBlock(signingKey.AsSpan()); + MemoryUtil.InitializeBlock(signingKey); //Compile the jwt for the cookie value string jwtValue = jwt.Compile(); diff --git a/plugins/VNLib.Plugins.Essentials.Auth.Social/src/PortalsEndpoint.cs b/plugins/VNLib.Plugins.Essentials.Auth.Social/src/PortalsEndpoint.cs index 4e5f867..177988f 100644 --- a/plugins/VNLib.Plugins.Essentials.Auth.Social/src/PortalsEndpoint.cs +++ b/plugins/VNLib.Plugins.Essentials.Auth.Social/src/PortalsEndpoint.cs @@ -23,44 +23,63 @@ */ using System; +using System.Net; using System.Linq; +using System.Text.Json; using System.Collections.Generic; +using VNLib.Utils.IO; +using VNLib.Net.Http; using VNLib.Plugins.Essentials.Endpoints; using VNLib.Plugins.Extensions.Loading; - namespace VNLib.Plugins.Essentials.Auth.Social { [ConfigurationName("portals")] - internal sealed class PortalsEndpoint : UnprotectedWebEndpoint + internal sealed class PortalsEndpoint : UnprotectedWebEndpoint, IDisposable { - private PortalDefJson[] _portals; + private readonly VnMemoryStream _portals; public PortalsEndpoint(PluginBase plugin, IConfigScope config) { string path = config.GetRequiredProperty("path", p => p.GetString()!); InitPathAndLog(path, plugin.Log); - //Empty array by default - _portals = []; + _portals = new VnMemoryStream(); } public void SetPortals(IEnumerable<SocialOAuthPortal> portals) { //Convert to json - _portals = portals.Select(p => new PortalDefJson + PortalDefJson[] jsn = portals.Select(p => new PortalDefJson { id = p.PortalId, login = p.LoginEndpoint.Path, logout = p.LogoutEndpoint?.Path, + icon = p.Base64Icon }).ToArray(); + + //Serialize portals array to memory stream + JsonSerializer.Serialize(_portals, jsn); + + //Set memory stream to readonly so shallow copy can be returned + _ = VnMemoryStream.CreateReadonly(_portals); } protected override VfReturnType Get(HttpEntity entity) { - //return portals array as json - return VirtualOkJson(entity, _portals); + //return portals array, pre-serialized + return VirtualClose( + entity, + HttpStatusCode.OK, + ContentType.Json, + _portals!.GetReadonlyShallowCopy() + ); + } + + void IDisposable.Dispose() + { + _portals?.Dispose(); } private sealed class PortalDefJson @@ -70,6 +89,8 @@ namespace VNLib.Plugins.Essentials.Auth.Social public string? login { get; set; } public string? logout { get; set; } + + public string? icon { get; set; } } } }
\ No newline at end of file diff --git a/plugins/VNLib.Plugins.Essentials.Auth.Social/src/SocialOAuthPortal.cs b/plugins/VNLib.Plugins.Essentials.Auth.Social/src/SocialOAuthPortal.cs index 3fe6ddf..db5ed6e 100644 --- a/plugins/VNLib.Plugins.Essentials.Auth.Social/src/SocialOAuthPortal.cs +++ b/plugins/VNLib.Plugins.Essentials.Auth.Social/src/SocialOAuthPortal.cs @@ -30,5 +30,6 @@ namespace VNLib.Plugins.Essentials.Auth.Social /// <param name="PortalId"> The unique identifier for the portal </param> /// <param name="LoginEndpoint"> Required login endpoint to advertise to the client </param> /// <param name="LogoutEndpoint"> Optional logout endpoint to advertise to the client </param> - public record SocialOAuthPortal(string PortalId, IEndpoint LoginEndpoint, IEndpoint? LogoutEndpoint); + /// <param name="Base64Icon">Optional base64 image icon src for the client to load and display</param> + public record SocialOAuthPortal(string PortalId, IEndpoint LoginEndpoint, IEndpoint? LogoutEndpoint, string? Base64Icon); }
\ No newline at end of file diff --git a/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs b/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs index 2fcc477..a698806 100644 --- a/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs +++ b/plugins/providers/VNLib.Plugins.Essentials.Auth.Auth0/src/Auth0Portal.cs @@ -33,7 +33,7 @@ namespace VNLib.Plugins.Essentials.Auth.Auth0 [ServiceExport] [ConfigurationName(ConfigKey)] - public sealed class Auth0Portal(PluginBase plugin) : IOAuthProvider + public sealed class Auth0Portal(PluginBase plugin, IConfigScope config) : IOAuthProvider { internal const string ConfigKey = "auth0"; @@ -43,12 +43,15 @@ namespace VNLib.Plugins.Essentials.Auth.Auth0 ///<inheritdoc/> public SocialOAuthPortal[] GetPortals() { + string? base64IconData = config.GetValueOrDefault("icon", p => p.GetString()!, null); + //Return the Auth0 portal return [ new SocialOAuthPortal( ConfigKey, _loginEndpoint, - _logoutEndpoint + _logoutEndpoint, + base64IconData ) ]; diff --git a/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs b/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs index ed3940f..01bfe8d 100644 --- a/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs +++ b/plugins/providers/VNLib.Plugins.Essentials.Auth.Discord/src/DiscordPortal.cs @@ -35,7 +35,7 @@ namespace VNLib.Plugins.Essentials.Auth.Discord [ServiceExport] [ConfigurationName(ConfigKey)] - public sealed class DiscordPortal(PluginBase plugin) : IOAuthProvider + public sealed class DiscordPortal(PluginBase plugin, IConfigScope config) : IOAuthProvider { internal const string ConfigKey = "discord"; @@ -44,12 +44,15 @@ namespace VNLib.Plugins.Essentials.Auth.Discord ///<inheritdoc/> public SocialOAuthPortal[] GetPortals() { + string? base64IconData = config.GetValueOrDefault("icon", p => p.GetString()!, null); + //Return the Discord portal return [ new SocialOAuthPortal( ConfigKey, _loginEndpoint, - null + null, + base64IconData ) ]; diff --git a/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs b/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs index 946531d..c438bfe 100644 --- a/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs +++ b/plugins/providers/VNLib.Plugins.Essentials.Auth.Github/src/GithubPortal.cs @@ -33,7 +33,7 @@ namespace VNLib.Plugins.Essentials.Auth.Github [ServiceExport] [ConfigurationName(ConfigKey)] - public sealed class GithubPortal(PluginBase plugin) : IOAuthProvider + public sealed class GithubPortal(PluginBase plugin, IConfigScope config) : IOAuthProvider { internal const string ConfigKey = "github"; @@ -42,12 +42,15 @@ namespace VNLib.Plugins.Essentials.Auth.Github ///<inheritdoc/> public SocialOAuthPortal[] GetPortals() { + string? base64IconData = config.GetValueOrDefault("icon", p => p.GetString()!, null); + //Return the github portal return [ new SocialOAuthPortal( ConfigKey, _loginEndpoint, - null + null, + base64IconData ) ]; |