Skip to content

Commit

Permalink
v6.0.0-beta.7
Browse files Browse the repository at this point in the history
  • Loading branch information
trueai-org committed Nov 19, 2024
1 parent 43c6487 commit 3228d9d
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 1 deletion.
53 changes: 53 additions & 0 deletions src/Midjourney.Captcha.API/Controllers/TwoFAController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Microsoft.AspNetCore.Mvc;
using Midjourney.Infrastructure.Services;

namespace Midjourney.Captcha.API.Controllers
{
/// <summary>
/// 2FA
/// </summary>
[ApiController]
[Route("/")]
public class TwoFAController : Controller
{
[HttpGet("{secret}")]
public IActionResult GetOtp(string secret)
{
if (string.IsNullOrEmpty(secret))
{
return BadRequest("Missing secret parameter");
}

var loadTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var otp = TwoFAHelper.GenerateOtp(secret, loadTime);

var remainingTime = TwoFAHelper.CalculateRemainingTime(loadTime);

var htmlContent = $@"
<html>
<head>
<title>2FA Auth</title>
<script>
const loadTime = {loadTime};
const remainingTime = {remainingTime};
if (remainingTime <= 0) {{
location.reload();
}} else {{
setTimeout(() => {{
location.reload();
}}, remainingTime * 1000);
}}
</script>
</head>
<body>
<pre>{{
""token"": ""{otp}""
}}</pre>
</body>
</html>
";
return Content(htmlContent, "text/html");
}
}
}
3 changes: 3 additions & 0 deletions src/Midjourney.Captcha.API/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ public void Configure(IApplicationBuilder app, IHostEnvironment env)
app.UseSwaggerUI();
}

app.UseDefaultFiles(); // 启用默认文件(index.html)
app.UseStaticFiles(); // 配置提供静态文件

app.UseCors(builder =>
{
builder.AllowAnyMethod().AllowAnyHeader().SetIsOriginAllowed(origin => true).AllowCredentials();
Expand Down
Binary file added src/Midjourney.Captcha.API/wwwroot/favicon.ico
Binary file not shown.
2 changes: 1 addition & 1 deletion src/Midjourney.Infrastructure/GlobalConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class GlobalConfiguration
/// <summary>
/// 版本号
/// </summary>
public static string Version { get; set; } = "v6.0.0-beta.6";
public static string Version { get; set; } = "v6.0.0-beta.7";

/// <summary>
/// 全局配置项
Expand Down
77 changes: 77 additions & 0 deletions src/Midjourney.Infrastructure/Services/TwoFAHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System.Globalization;
using System.Security.Cryptography;
using System.Text;

namespace Midjourney.Infrastructure.Services
{
/// <summary>
/// 2fa 验证帮助类
/// https://github.com/wuzf/2fa/blob/main/worker.js
/// </summary>
public class TwoFAHelper
{
public static string GenerateOtp(string secret)
{
var loadTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var otp = GenerateOtp(secret, loadTime);
return otp;
}

public static string GenerateOtp(string secret, long loadTime)
{
const int timeStep = 30;

var counter = loadTime / timeStep;
var counterBytes = BitConverter.GetBytes(counter);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(counterBytes);
}

var key = Base32Decode(secret);

using var hmac = new HMACSHA1(key);
var hash = hmac.ComputeHash(counterBytes);

var offset = hash[^1] & 0xF;
var binaryCode = ((hash[offset] & 0x7F) << 24) |
((hash[offset + 1] & 0xFF) << 16) |
((hash[offset + 2] & 0xFF) << 8) |
(hash[offset + 3] & 0xFF);

var otp = (binaryCode % 1_000_000).ToString("D6", CultureInfo.InvariantCulture);
return otp;
}

private static byte[] Base32Decode(string base32)
{
const string alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
base32 = base32.ToUpperInvariant();

var bits = new StringBuilder();
foreach (var c in base32)
{
var index = alphabet.IndexOf(c);
if (index < 0) throw new ArgumentException("Invalid Base32 character.");
bits.Append(Convert.ToString(index, 2).PadLeft(5, '0'));
}

var byteList = new List<byte>();
for (int i = 0; i + 8 <= bits.Length; i += 8)
{
byteList.Add(Convert.ToByte(bits.ToString(i, 8), 2));
}

return byteList.ToArray();
}

public static int CalculateRemainingTime(long loadTime)
{
const int timeStep = 30;
var epochTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var currentCounter = epochTime / timeStep;
var expirationTime = (currentCounter + 1) * timeStep;
return (int)(expirationTime - loadTime);
}
}
}

0 comments on commit 3228d9d

Please sign in to comment.