?????????????????????????????????? SQL? Co-authored-by: Cursor <cursoragent@cursor.com>
133 lines
5.4 KiB
C#
133 lines
5.4 KiB
C#
using System.Net;
|
|
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using FluentAssertions;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.DependencyInjection.Extensions;
|
|
using Moq;
|
|
using Oms.Domain.SystemAggregate.Consts;
|
|
using Oms.Domain.SystemAggregate.Entities;
|
|
using Oms.Domain.SystemAggregate.Repositories;
|
|
using SimpleAdmin.Api.IntegrationTests.Support;
|
|
using SimpleAdmin.Api.WeChat.Options;
|
|
|
|
namespace SimpleAdmin.Api.IntegrationTests;
|
|
|
|
public class WeChatRouteIntegrationTests
|
|
{
|
|
[Fact]
|
|
public async Task WeChatLegacyVerification_ShouldRegisterGetAndPostMethods()
|
|
{
|
|
await using var host = await SimpleAdminApiTestHost.CreateAsync(configureServices: ConfigureWeChatFallback);
|
|
|
|
var methods = host.GetHttpMethods("apiwechat/verification");
|
|
methods.Should().BeEquivalentTo(["GET", "POST"]);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task WeChatRoutes_ShouldBeRegisteredOnAuthService()
|
|
{
|
|
await using var host = await SimpleAdminApiTestHost.CreateAsync(configureServices: ConfigureWeChatFallback);
|
|
|
|
host.RoutePatterns.Should().Contain("apiwechat/verification");
|
|
host.RoutePatterns.Should().Contain("wechat/mp/{appId}");
|
|
host.RoutePatterns.Should().Contain("wechat/mp/login-qrcode");
|
|
host.RoutePatterns.Should().Contain("wechat/mp/follow-qrcode");
|
|
host.RoutePatterns.Should().Contain("wechat/oauth/user-info");
|
|
host.RoutePatterns.Should().Contain("wechat/customer/register");
|
|
host.RoutePatterns.Should().Contain("wechat/customer/bind");
|
|
host.RoutePatterns.Should().Contain("rbac/auth/wx-login/status");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task WeChatValidateLegacy_ShouldReturnEchostrWhenSignatureValid()
|
|
{
|
|
await using var host = await SimpleAdminApiTestHost.CreateAsync(configureServices: services =>
|
|
{
|
|
ConfigureWeChatFallback(services);
|
|
services.PostConfigure<WeChatMpOptions>(options => options.Token = "test-token");
|
|
});
|
|
|
|
const string timestamp = "1400000000";
|
|
const string nonce = "nonce";
|
|
const string echostr = "hello-wechat";
|
|
var signature = SignWeChat("test-token", timestamp, nonce);
|
|
|
|
var response = await host.Client.GetAsync(
|
|
$"/apiwechat/verification?signature={signature}×tamp={timestamp}&nonce={nonce}&echostr={echostr}");
|
|
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
(await response.Content.ReadAsStringAsync()).Should().Be(echostr);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task WeChatValidateLegacy_ShouldReturnEchostrAsPlainTextWithoutJsonWrapper()
|
|
{
|
|
await using var host = await SimpleAdminApiTestHost.CreateAsync(configureServices: services =>
|
|
{
|
|
ConfigureWeChatFallback(services);
|
|
services.PostConfigure<WeChatMpOptions>(options => options.Token = "test-token");
|
|
});
|
|
|
|
const string timestamp = "1400000000";
|
|
const string nonce = "nonce";
|
|
const string echostr = "5938472619053847261";
|
|
var signature = SignWeChat("test-token", timestamp, nonce);
|
|
|
|
var response = await host.Client.GetAsync(
|
|
$"/apiwechat/verification?signature={signature}×tamp={timestamp}&nonce={nonce}&echostr={echostr}");
|
|
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
response.Content.Headers.ContentType?.MediaType.Should().Be("text/plain");
|
|
var body = await response.Content.ReadAsStringAsync();
|
|
body.Should().Be(echostr);
|
|
body.Should().NotStartWith("{");
|
|
}
|
|
|
|
[Fact]
|
|
public async Task WeChatValidateLegacy_WithProductionToken_ShouldReturnEchostr()
|
|
{
|
|
const string token = "c6ca74013df823c0e1da0feaaaf8bf66";
|
|
const string timestamp = "1714037059";
|
|
const string nonce = "486452656";
|
|
const string echostr = "5938472619053847261";
|
|
var signature = SignWeChat(token, timestamp, nonce);
|
|
|
|
await using var host = await SimpleAdminApiTestHost.CreateAsync(configureServices: services =>
|
|
{
|
|
ConfigureWeChatFallback(services);
|
|
services.PostConfigure<WeChatMpOptions>(options => options.Token = token);
|
|
});
|
|
|
|
var response = await host.Client.GetAsync(
|
|
$"/apiwechat/verification?signature={signature}×tamp={timestamp}&nonce={nonce}&echostr={echostr}");
|
|
|
|
response.StatusCode.Should().Be(HttpStatusCode.OK);
|
|
response.Content.Headers.ContentType?.MediaType.Should().Be("text/plain");
|
|
(await response.Content.ReadAsStringAsync()).Should().Be(echostr);
|
|
}
|
|
|
|
private static void ConfigureWeChatFallback(IServiceCollection services)
|
|
{
|
|
services.PostConfigure<WeChatMpOptions>(options =>
|
|
{
|
|
options.Token = "test-token";
|
|
options.AppId = "wx-test";
|
|
});
|
|
|
|
var repository = new Mock<ISystemOtherConfigRepository>();
|
|
repository
|
|
.Setup(x => x.GetByConfigCodeAsync(SystemOtherConfigCodes.WeChatMp, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((SystemOtherConfig?)null);
|
|
services.RemoveAll<ISystemOtherConfigRepository>();
|
|
services.AddSingleton(repository.Object);
|
|
}
|
|
|
|
private static string SignWeChat(string token, string timestamp, string nonce)
|
|
{
|
|
var parts = new[] { token, timestamp, nonce }.OrderBy(x => x, StringComparer.Ordinal).ToArray();
|
|
var hash = SHA1.HashData(Encoding.UTF8.GetBytes(string.Concat(parts)));
|
|
return Convert.ToHexString(hash).ToLowerInvariant();
|
|
}
|
|
}
|