Skip to content

Commit a2f921a

Browse files
committed
Merge branch 'master' into dev-univer-sheet
2 parents 120bac4 + 2f2961e commit a2f921a

27 files changed

Lines changed: 590 additions & 365 deletions

BootstrapBlazor.Extensions.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.UniverIcon"
182182
EndProject
183183
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.ChatBot", "src\components\BootstrapBlazor.ChatBot\BootstrapBlazor.ChatBot.csproj", "{2F37FBF4-5C1C-4493-B614-0E8361432621}"
184184
EndProject
185+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.Authenticator", "src\components\BootstrapBlazor.Authenticator\BootstrapBlazor.Authenticator.csproj", "{1FDDF0AD-7AB6-4706-A183-26C680817BB4}"
186+
EndProject
185187
Global
186188
GlobalSection(SolutionConfigurationPlatforms) = preSolution
187189
Debug|Any CPU = Debug|Any CPU
@@ -492,6 +494,10 @@ Global
492494
{2F37FBF4-5C1C-4493-B614-0E8361432621}.Debug|Any CPU.Build.0 = Debug|Any CPU
493495
{2F37FBF4-5C1C-4493-B614-0E8361432621}.Release|Any CPU.ActiveCfg = Release|Any CPU
494496
{2F37FBF4-5C1C-4493-B614-0E8361432621}.Release|Any CPU.Build.0 = Release|Any CPU
497+
{1FDDF0AD-7AB6-4706-A183-26C680817BB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
498+
{1FDDF0AD-7AB6-4706-A183-26C680817BB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
499+
{1FDDF0AD-7AB6-4706-A183-26C680817BB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
500+
{1FDDF0AD-7AB6-4706-A183-26C680817BB4}.Release|Any CPU.Build.0 = Release|Any CPU
495501
EndGlobalSection
496502
GlobalSection(SolutionProperties) = preSolution
497503
HideSolutionNode = FALSE
@@ -577,6 +583,7 @@ Global
577583
{E30AAB64-BF28-4960-89C1-1F521025F531} = {FF1089BE-C704-4374-B629-C57C08E1798F}
578584
{A657E04C-1495-439E-BC2E-1EEAB2D1B4DA} = {FF1089BE-C704-4374-B629-C57C08E1798F}
579585
{2F37FBF4-5C1C-4493-B614-0E8361432621} = {FF1089BE-C704-4374-B629-C57C08E1798F}
586+
{1FDDF0AD-7AB6-4706-A183-26C680817BB4} = {FF1089BE-C704-4374-B629-C57C08E1798F}
580587
EndGlobalSection
581588
GlobalSection(ExtensibilityGlobals) = postSolution
582589
SolutionGuid = {D5EB1960-6F30-4CE1-B375-EAE1F787D6FF}

exclusion.dic

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,4 @@ vimeo
101101
scrlang
102102
Validata
103103
Validatable
104+
Totp
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
2+
3+
<PropertyGroup>
4+
<Version>9.0.0</Version>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<PackageTags>Bootstrap Blazor WebAssembly wasm Authenticator 2FA MFA OTP TOTP HOTP</PackageTags>
9+
<Description>Bootstrap UI components extensions of Authenticator</Description>
10+
<RootNamespace>BootstrapBlazor.Components</RootNamespace>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<PackageReference Include="BootstrapBlazor" Version="9.5.12" />
15+
<PackageReference Include="Otp.NET" Version="1.4.0" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
namespace BootstrapBlazor.Components;
6+
7+
internal static class OtpExtensions
8+
{
9+
public static OtpNet.OtpHashMode ToMode(this OtpHashMode mode) => mode switch
10+
{
11+
OtpHashMode.Sha256 => OtpNet.OtpHashMode.Sha256,
12+
OtpHashMode.Sha512 => OtpNet.OtpHashMode.Sha512,
13+
_ => OtpNet.OtpHashMode.Sha1
14+
};
15+
16+
public static OtpNet.OtpType ToType(this OtpType type) => type switch
17+
{
18+
OtpType.Hotp => OtpNet.OtpType.Hotp,
19+
_ => OtpNet.OtpType.Totp
20+
};
21+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
using Microsoft.Extensions.DependencyInjection;
6+
7+
namespace BootstrapBlazor.Components;
8+
9+
/// <summary>
10+
/// BootstrapBlazor service extensions
11+
/// </summary>
12+
public static class ServiceCollectionExtension
13+
{
14+
/// <summary>
15+
/// Inject <see cref="ITotpService"/> service extension method.
16+
/// </summary>
17+
/// <param name="services"></param>
18+
/// <param name="configOptions"></param>
19+
/// <returns></returns>
20+
public static IServiceCollection AddBootstrapBlazorTotpService(this IServiceCollection services, Action<
21+
OtpOptions>? configOptions = null)
22+
{
23+
services.AddSingleton<ITotpService, DefaultTotpService>();
24+
services.Configure<OtpOptions>(options =>
25+
{
26+
configOptions?.Invoke(options);
27+
28+
options.AccountName ??= "BootstrapBlazor";
29+
options.UserName ??= "Simulator";
30+
options.IssuerName ??= options.AccountName;
31+
options.SecretKey ??= "OMM2LVLFX6QJHMYI";
32+
});
33+
return services;
34+
}
35+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
using Microsoft.Extensions.Options;
6+
using OtpNet;
7+
8+
namespace BootstrapBlazor.Components;
9+
10+
class DefaultTotpService(IOptionsMonitor<OtpOptions> optionsMonitor) : ITotpService
11+
{
12+
[NotNull]
13+
public TotpInstanceBase? Instance { get; private set; }
14+
15+
public string GenerateOtpUri(OtpOptions? options = null)
16+
{
17+
options ??= optionsMonitor.CurrentValue;
18+
var type = options.Type.ToType();
19+
var mode = options.Algorithm.ToMode();
20+
var uri = new OtpUri(type, options.SecretKey, options.UserName, options.IssuerName, mode, options.Digits, options.Period, options.Counter);
21+
return uri.ToString();
22+
}
23+
24+
public string Compute(string secretKey, int period = 30, OtpHashMode mode = OtpHashMode.Sha1, int digits = 6, DateTime? timestamp = null)
25+
{
26+
var instance = new Totp(Base32Encoding.ToBytes(secretKey), period, mode.ToMode(), digits, timeCorrection: null);
27+
Instance = new DefaultTotpInstance(instance);
28+
return timestamp == null ? instance.ComputeTotp() : instance.ComputeTotp(timestamp.Value);
29+
}
30+
31+
public int GetRemainingSeconds(DateTime? timestamp = null)
32+
{
33+
if (Instance != null)
34+
{
35+
return timestamp == null ? Instance.GetRemainingSeconds() : Instance.GetRemainingSeconds(timestamp.Value);
36+
}
37+
var instance = new Totp(Base32Encoding.ToBytes("OMM2LVLFX6QJHMYI"));
38+
return timestamp == null ? instance.RemainingSeconds() : instance.RemainingSeconds(timestamp.Value);
39+
}
40+
41+
public string GenerateSecretKey(int length = 20)
42+
{
43+
var secretKey = KeyGeneration.GenerateRandomKey(length);
44+
return Base32Encoding.ToString(secretKey);
45+
}
46+
47+
public byte[] GetSecretKeyBytes(string input)
48+
{
49+
return Base32Encoding.ToBytes(input);
50+
}
51+
52+
public bool Verify(string code, DateTime? timestamp = null)
53+
{
54+
if (Instance != null)
55+
{
56+
return timestamp == null ? Instance.Verify(code) : Instance.Verify(code, timestamp.Value);
57+
}
58+
var instance = new Totp(Base32Encoding.ToBytes("OMM2LVLFX6QJHMYI"));
59+
return timestamp == null ? instance.VerifyTotp(code, out _) : instance.VerifyTotp(timestamp.Value, code, out _);
60+
}
61+
}
62+
63+
class DefaultTotpInstance(Totp instance) : TotpInstanceBase
64+
{
65+
public override int GetRemainingSeconds(DateTime? timestamp = null)
66+
{
67+
return timestamp == null ? instance.RemainingSeconds() : instance.RemainingSeconds(timestamp.Value);
68+
}
69+
70+
public override bool Verify(string code, DateTime? timestamp = null)
71+
{
72+
return timestamp == null ? instance.VerifyTotp(code, out _) : instance.VerifyTotp(timestamp.Value, code, out _);
73+
}
74+
}

src/components/BootstrapBlazor.BarCode/BootstrapBlazor.BarCode.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>9.0.0</Version>
4+
<Version>9.0.1</Version>
55
</PropertyGroup>
66

77
<PropertyGroup>

src/components/BootstrapBlazor.BarCode/wwwroot/zxing.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/BootstrapBlazor.DockView/BootstrapBlazor.DockView.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>9.1.10</Version>
4+
<Version>9.1.11</Version>
55
</PropertyGroup>
66

77
<PropertyGroup>

src/components/BootstrapBlazor.DockView/Components/DockViewV2.razor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export async function init(id, invoke, options) {
1010
return;
1111
}
1212

13-
if(options.theme === 'dockview-theme-light') {
13+
if (options.theme === 'dockview-theme-light') {
1414
let theme = getTheme();
1515
if (theme === 'dark') {
1616
options.theme = `dockview-theme-dark`;

0 commit comments

Comments
 (0)