mirror of
https://github.com/Caraxi/mare.server.git
synced 2025-12-12 15:07:23 +01:00
a
This commit is contained in:
parent
616b96981d
commit
bc1c884562
26 changed files with 209 additions and 498 deletions
|
|
@ -28,10 +28,10 @@ services:
|
|||
image: darkarchon/mare-synchronos-server:latest
|
||||
restart: on-failure
|
||||
ports:
|
||||
- 6000:6000/tcp
|
||||
- 6050:6050/tcp
|
||||
- 6300:6300/tcp
|
||||
- 6350:6350/tcp
|
||||
environment:
|
||||
MareSynchronos__CdnFullUrl: "${DEV_MARE_CDNURL}"
|
||||
MareSynchronos__CdnFullUrl: "http://127.0.0.1:6200/marecache"
|
||||
MareSynchronos__XIVAPIKey: "${DEV_MARE_XIVAPIKEY}"
|
||||
DOTNET_USE_POLLING_FILE_WATCHER: 1
|
||||
volumes:
|
||||
|
|
@ -42,34 +42,34 @@ services:
|
|||
postgres:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl --fail http://localhost:6000/health || exit 1"]
|
||||
test: ["CMD-SHELL", "curl --fail http://localhost:6300/health || exit 1"]
|
||||
retries: 60
|
||||
start_period: 10s
|
||||
timeout: 1s
|
||||
|
||||
mare-auth:
|
||||
image: darkarchon/mare-synchronos-authservice:latest
|
||||
restart: on-failure
|
||||
environment:
|
||||
DOTNET_USE_POLLING_FILE_WATCHER: 1
|
||||
volumes:
|
||||
- ../config/standalone/authservice-standalone.json:/opt/MareSynchronosAuthService/appsettings.json
|
||||
- ../log/authservice-standalone/:/opt/MareSynchronosAuthService/logs/:rw
|
||||
- postgres_socket:/var/run/postgresql/:rw
|
||||
depends_on:
|
||||
mare-server:
|
||||
condition: service_healthy
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
#
|
||||
# mare-auth:
|
||||
# image: darkarchon/mare-synchronos-authservice:latest
|
||||
# restart: on-failure
|
||||
# environment:
|
||||
# DOTNET_USE_POLLING_FILE_WATCHER: 1
|
||||
# volumes:
|
||||
# - ../config/standalone/authservice-standalone.json:/opt/MareSynchronosAuthService/appsettings.json
|
||||
# - ../log/authservice-standalone/:/opt/MareSynchronosAuthService/logs/:rw
|
||||
# - postgres_socket:/var/run/postgresql/:rw
|
||||
# depends_on:
|
||||
# mare-server:
|
||||
# condition: service_healthy
|
||||
# postgres:
|
||||
# condition: service_healthy
|
||||
|
||||
mare-services:
|
||||
image: darkarchon/mare-synchronos-services:latest
|
||||
restart: on-failure
|
||||
environment:
|
||||
MareSynchronos__DiscordBotToken: "${DEV_MARE_DISCORDTOKEN}"
|
||||
MareSynchronos__DiscordChannelForMessages: "${DEV_MARE_DISCORDCHANNEL}"
|
||||
MareSynchronos__DiscordChannelForReports: "${DEV_MARE_DISCORDCHANNEL}"
|
||||
MareSynchronos__DiscordChannelForCommands: "${DEV_MARE_DISCORDCHANNEL}"
|
||||
MareSynchronos__DiscordChannelForMessages: "926997505848254507"
|
||||
MareSynchronos__DiscordChannelForReports: "926997505848254507"
|
||||
MareSynchronos__DiscordChannelForCommands: "926997505848254507"
|
||||
DOTNET_USE_POLLING_FILE_WATCHER: 1
|
||||
volumes:
|
||||
- ../config/standalone/services-standalone.json:/opt/MareSynchronosServices/appsettings.json
|
||||
|
|
@ -87,13 +87,13 @@ services:
|
|||
- 6200:6200/tcp
|
||||
restart: on-failure
|
||||
environment:
|
||||
MareSynchronos__CdnFullUrl: "${DEV_MARE_CDNURL}"
|
||||
MareSynchronos__CdnFullUrl: "http://127.0.0.1:6200/marecache"
|
||||
DOTNET_USE_POLLING_FILE_WATCHER: 1
|
||||
volumes:
|
||||
- ../config/standalone/files-standalone.json:/opt/MareSynchronosStaticFilesServer/appsettings.json
|
||||
- ../log/files-standalone/:/opt/MareSynchronosStaticFilesServer/logs/:rw
|
||||
- postgres_socket:/var/run/postgresql/:rw
|
||||
- ../data/files-standalone/:/marecache/:rw
|
||||
- D:\mareserverfiles\:/marecache/:rw
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@
|
|||
"Default": "Warning",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information",
|
||||
"MareSynchronosStaticFilesServer": "Debug",
|
||||
"MareSynchronosShared": "Debug",
|
||||
"MareSynchronosStaticFilesServer": "Trace",
|
||||
"MareSynchronosShared": "Trace",
|
||||
"System.IO": "Information",
|
||||
},
|
||||
"File": {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information",
|
||||
"Microsoft.EntityFramework": "Warning",
|
||||
"MareSynchronosServer": "Debug",
|
||||
"MareSynchronosServer": "Trace",
|
||||
"MareSynchronosShared": "Debug",
|
||||
"System.IO": "Information",
|
||||
"MareSynchronosServer.Services.SystemInfoService": "Warning"
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
"MareSynchronos": {
|
||||
"DbContextPoolSize": 512,
|
||||
"ShardName": "Main",
|
||||
"MetricsPort": 6050,
|
||||
"MetricsPort": 6350,
|
||||
"MainServerAddress": "",
|
||||
"FailedAuthForTempBan": 5,
|
||||
"TempBanDurationInMinutes": 5,
|
||||
|
|
@ -38,20 +38,20 @@
|
|||
""
|
||||
],
|
||||
"RedisConnectionString": "redis,password=secretredispassword",
|
||||
"CdnFullUrl": "http://localhost:6200",
|
||||
"CdnFullUrl": "http://localhost:6200/marecache",
|
||||
"MaxExistingGroupsByUser": 6,
|
||||
"MaxJoinedGroupsByUser": 10,
|
||||
"MaxGroupUserCount": 100,
|
||||
"PurgeUnusedAccounts": false,
|
||||
"PurgeUnusedAccountsPeriodInDays": 14,
|
||||
"ExpectedClientVersion": "0.9.0",
|
||||
"ExpectedClientVersion": "0.11.22",
|
||||
"XIVAPIKey": ""
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
"Endpoints": {
|
||||
"Http": {
|
||||
"Url": "http://+:6000"
|
||||
"Url": "http://+:6300"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -29,14 +29,14 @@
|
|||
"ShardName": "Services",
|
||||
"MetricsPort": 6150,
|
||||
"CdnFullUrl": "http://localhost:6200/",
|
||||
"MainServerAddress": "http://mare-server:6000/",
|
||||
"MainServerAddress": "http://mare-server:6300/",
|
||||
"MainServerGrpcAddress": "http://mare-server:6005/",
|
||||
"DiscordBotToken": "",
|
||||
"DiscordChannelForMessages": "",
|
||||
"DiscordChannelForCommands": "",
|
||||
"Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring",
|
||||
"RedisConnectionString": "redis,password=secretredispassword",
|
||||
"VanityRoles": {"984484868241096724":"Main Developer", "1012008556259725398":"Patreon Subscriber"}
|
||||
"VanityRoles": {"1097028541666836500":"Main Developer", "1012008556259725398":"Patreon Subscriber"}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Kestrel": {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
@echo off
|
||||
docker compose -f compose\mare-standalone.yml -p standalone up
|
||||
docker compose -f compose\mare-standalone.yml -p standalone up -d
|
||||
10
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/.gitignore
generated
vendored
Normal file
10
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/modules.xml
|
||||
/.idea.MareSynchronosServer.iml
|
||||
/projectSettingsUpdater.xml
|
||||
/contentModel.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
4
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/encodings.xml
generated
Normal file
4
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/encodings.xml
generated
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
8
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/indexLayout.xml
generated
Normal file
8
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/indexLayout.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
7
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/vcs.xml
generated
Normal file
7
MareSynchronosServer/.idea/.idea.MareSynchronosServer/.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/../MareAPI" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
|
@ -19,4 +19,9 @@
|
|||
<ProjectReference Include="..\MareSynchronosShared\MareSynchronosShared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controllers\" />
|
||||
<Folder Include="Services\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,143 +0,0 @@
|
|||
using MareSynchronosShared;
|
||||
using MareSynchronosShared.Services;
|
||||
using MareSynchronosShared.Utils.Configuration;
|
||||
using MaxMind.GeoIP2;
|
||||
|
||||
namespace MareSynchronosAuthService.Services;
|
||||
|
||||
public class GeoIPService : IHostedService
|
||||
{
|
||||
private readonly ILogger<GeoIPService> _logger;
|
||||
private readonly IConfigurationService<AuthServiceConfiguration> _mareConfiguration;
|
||||
private bool _useGeoIP = false;
|
||||
private string _cityFile = string.Empty;
|
||||
private DatabaseReader? _dbReader;
|
||||
private DateTime _dbLastWriteTime = DateTime.MinValue;
|
||||
private CancellationTokenSource _fileWriteTimeCheckCts = new();
|
||||
private bool _processingReload = false;
|
||||
|
||||
public GeoIPService(ILogger<GeoIPService> logger,
|
||||
IConfigurationService<AuthServiceConfiguration> mareConfiguration)
|
||||
{
|
||||
_logger = logger;
|
||||
_mareConfiguration = mareConfiguration;
|
||||
}
|
||||
|
||||
public async Task<string> GetCountryFromIP(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
if (!_useGeoIP)
|
||||
{
|
||||
return "*";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ip = httpContextAccessor.GetIpAddress();
|
||||
|
||||
using CancellationTokenSource waitCts = new();
|
||||
waitCts.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
while (_processingReload) await Task.Delay(100, waitCts.Token).ConfigureAwait(false);
|
||||
|
||||
if (_dbReader!.TryCity(ip, out var response))
|
||||
{
|
||||
string? continent = response?.Continent.Code;
|
||||
if (!string.IsNullOrEmpty(continent) &&
|
||||
string.Equals(continent, "NA", StringComparison.Ordinal)
|
||||
&& response?.Location.Longitude != null)
|
||||
{
|
||||
if (response.Location.Longitude < -102)
|
||||
{
|
||||
continent = "NA-W";
|
||||
}
|
||||
else
|
||||
{
|
||||
continent = "NA-E";
|
||||
}
|
||||
}
|
||||
|
||||
return continent ?? "*";
|
||||
}
|
||||
|
||||
return "*";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Error handling Geo IP country in request");
|
||||
return "*";
|
||||
}
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("GeoIP module starting update task");
|
||||
|
||||
var token = _fileWriteTimeCheckCts.Token;
|
||||
_ = PeriodicReloadTask(token);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task PeriodicReloadTask(CancellationToken token)
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
_processingReload = true;
|
||||
|
||||
var useGeoIP = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.UseGeoIP), false);
|
||||
var cityFile = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.GeoIPDbCityFile), string.Empty);
|
||||
DateTime lastWriteTime = DateTime.MinValue;
|
||||
if (File.Exists(cityFile))
|
||||
{
|
||||
lastWriteTime = new FileInfo(cityFile).LastWriteTimeUtc;
|
||||
}
|
||||
|
||||
if (useGeoIP && (!string.Equals(cityFile, _cityFile, StringComparison.OrdinalIgnoreCase) || lastWriteTime > _dbLastWriteTime))
|
||||
{
|
||||
_cityFile = cityFile;
|
||||
if (!File.Exists(_cityFile)) throw new FileNotFoundException($"Could not open GeoIP City Database, path does not exist: {_cityFile}");
|
||||
_dbReader?.Dispose();
|
||||
_dbReader = null;
|
||||
_dbReader = new DatabaseReader(_cityFile);
|
||||
_dbLastWriteTime = lastWriteTime;
|
||||
|
||||
_ = _dbReader.City("8.8.8.8").Continent;
|
||||
|
||||
_logger.LogInformation($"Loaded GeoIP city file from {_cityFile}");
|
||||
|
||||
if (_useGeoIP != useGeoIP)
|
||||
{
|
||||
_logger.LogInformation("GeoIP module is now enabled");
|
||||
_useGeoIP = useGeoIP;
|
||||
}
|
||||
}
|
||||
|
||||
if (_useGeoIP != useGeoIP && !useGeoIP)
|
||||
{
|
||||
_logger.LogInformation("GeoIP module is now disabled");
|
||||
_useGeoIP = useGeoIP;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogWarning(e, "Error during periodic GeoIP module reload task, disabling GeoIP");
|
||||
_useGeoIP = false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_processingReload = false;
|
||||
}
|
||||
|
||||
await Task.Delay(TimeSpan.FromMinutes(1)).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_fileWriteTimeCheckCts.Cancel();
|
||||
_fileWriteTimeCheckCts.Dispose();
|
||||
_dbReader?.Dispose();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,8 +7,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosServer", "Mar
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronos.API", "..\MareAPI\MareSynchronosAPI\MareSynchronos.API.csproj", "{326BFB1B-5571-47A6-8513-1FFDB32D53B0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosServerTest", "MareSynchronosServerTest\MareSynchronosServerTest.csproj", "{25A82A2A-35C2-4EE0-A0E8-DFDD77978DDA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosShared", "MareSynchronosShared\MareSynchronosShared.csproj", "{67B1461D-E215-4BA8-A64D-E1836724D5E6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MareSynchronosStaticFilesServer", "MareSynchronosStaticFilesServer\MareSynchronosStaticFilesServer.csproj", "{3C7F43BB-FE4C-48BC-BF42-D24E70E8FCB7}"
|
||||
|
|
@ -36,10 +34,6 @@ Global
|
|||
{326BFB1B-5571-47A6-8513-1FFDB32D53B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{326BFB1B-5571-47A6-8513-1FFDB32D53B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{326BFB1B-5571-47A6-8513-1FFDB32D53B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{25A82A2A-35C2-4EE0-A0E8-DFDD77978DDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{25A82A2A-35C2-4EE0-A0E8-DFDD77978DDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{25A82A2A-35C2-4EE0-A0E8-DFDD77978DDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{25A82A2A-35C2-4EE0-A0E8-DFDD77978DDA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{67B1461D-E215-4BA8-A64D-E1836724D5E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{67B1461D-E215-4BA8-A64D-E1836724D5E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{67B1461D-E215-4BA8-A64D-E1836724D5E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
namespace MareSynchronosAuthService.Authentication;
|
||||
namespace MareSynchronosServer.Authentication;
|
||||
|
||||
public record SecretKeyAuthReply(bool Success, string? Uid, string? PrimaryUid, string? Alias, bool TempBan, bool Permaban, bool MarkedForBan);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace MareSynchronosAuthService.Authentication;
|
||||
namespace MareSynchronosServer.Authentication;
|
||||
|
||||
internal record SecretKeyFailedAuthorization
|
||||
{
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using MareSynchronosAuthService.Authentication;
|
||||
using MareSynchronosAuthService.Services;
|
||||
using MareSynchronosAuthService.Services;
|
||||
using MareSynchronosShared.Data;
|
||||
using MareSynchronosShared.Models;
|
||||
using MareSynchronosShared.Services;
|
||||
|
|
@ -13,6 +12,7 @@ using System.Globalization;
|
|||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using MareSynchronosServer.Authentication;
|
||||
|
||||
namespace MareSynchronosAuthService.Controllers;
|
||||
|
||||
|
|
@ -24,18 +24,16 @@ public abstract class AuthControllerBase : Controller
|
|||
protected readonly IDbContextFactory<MareDbContext> MareDbContextFactory;
|
||||
protected readonly SecretKeyAuthenticatorService SecretKeyAuthenticatorService;
|
||||
private readonly IDatabase _redis;
|
||||
private readonly GeoIPService _geoIPProvider;
|
||||
|
||||
protected AuthControllerBase(ILogger logger,
|
||||
IHttpContextAccessor accessor, IDbContextFactory<MareDbContext> mareDbContextFactory,
|
||||
SecretKeyAuthenticatorService secretKeyAuthenticatorService,
|
||||
IConfigurationService<AuthServiceConfiguration> configuration,
|
||||
IDatabase redisDb, GeoIPService geoIPProvider)
|
||||
IDatabase redisDb)
|
||||
{
|
||||
Logger = logger;
|
||||
HttpAccessor = accessor;
|
||||
_redis = redisDb;
|
||||
_geoIPProvider = geoIPProvider;
|
||||
MareDbContextFactory = mareDbContextFactory;
|
||||
SecretKeyAuthenticatorService = secretKeyAuthenticatorService;
|
||||
Configuration = configuration;
|
||||
|
|
@ -106,7 +104,6 @@ public abstract class AuthControllerBase : Controller
|
|||
new Claim(MareClaimTypes.CharaIdent, charaIdent),
|
||||
new Claim(MareClaimTypes.Alias, alias),
|
||||
new Claim(MareClaimTypes.Expires, DateTime.UtcNow.AddHours(6).Ticks.ToString(CultureInfo.InvariantCulture)),
|
||||
new Claim(MareClaimTypes.Continent, await _geoIPProvider.GetCountryFromIP(HttpAccessor))
|
||||
});
|
||||
|
||||
return Content(token.RawData);
|
||||
|
|
@ -20,6 +20,8 @@ public class ClientMessageController : Controller
|
|||
_hubContext = hubContext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Route("sendMessage")]
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> SendMessage(ClientMessage msg)
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ public class JwtController : AuthControllerBase
|
|||
IHttpContextAccessor accessor, IDbContextFactory<MareDbContext> mareDbContextFactory,
|
||||
SecretKeyAuthenticatorService secretKeyAuthenticatorService,
|
||||
IConfigurationService<AuthServiceConfiguration> configuration,
|
||||
IDatabase redisDb, GeoIPService geoIPProvider)
|
||||
IDatabase redisDb)
|
||||
: base(logger, accessor, mareDbContextFactory, secretKeyAuthenticatorService,
|
||||
configuration, redisDb, geoIPProvider)
|
||||
configuration, redisDb)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -29,9 +29,9 @@ public class OAuthController : AuthControllerBase
|
|||
IHttpContextAccessor accessor, IDbContextFactory<MareDbContext> mareDbContext,
|
||||
SecretKeyAuthenticatorService secretKeyAuthenticatorService,
|
||||
IConfigurationService<AuthServiceConfiguration> configuration,
|
||||
IDatabase redisDb, GeoIPService geoIPProvider)
|
||||
IDatabase redisDb)
|
||||
: base(logger, accessor, mareDbContext, secretKeyAuthenticatorService,
|
||||
configuration, redisDb, geoIPProvider)
|
||||
configuration, redisDb)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +25,7 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="5.2.0" />
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.184">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using System.Collections.Concurrent;
|
||||
using MareSynchronosAuthService.Authentication;
|
||||
using MareSynchronosServer.Authentication;
|
||||
using MareSynchronosShared.Data;
|
||||
using MareSynchronosShared.Metrics;
|
||||
using MareSynchronosShared.Models;
|
||||
|
|
@ -18,6 +18,8 @@ using StackExchange.Redis.Extensions.Core.Configuration;
|
|||
using System.Net;
|
||||
using StackExchange.Redis.Extensions.System.Text.Json;
|
||||
using MareSynchronos.API.SignalR;
|
||||
using MareSynchronosAuthService.Controllers;
|
||||
using MareSynchronosAuthService.Services;
|
||||
using MessagePack;
|
||||
using MessagePack.Resolvers;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
|
|
@ -44,8 +46,16 @@ public class Startup
|
|||
services.AddHttpContextAccessor();
|
||||
|
||||
services.AddTransient(_ => Configuration);
|
||||
|
||||
services.AddSingleton<IConfigurationService<AuthServiceConfiguration>, MareConfigurationServiceServer<AuthServiceConfiguration>>();
|
||||
var mareConfig = Configuration.GetRequiredSection("MareSynchronos");
|
||||
ConfigureRedis(services, mareConfig);
|
||||
|
||||
services.AddSingleton<SecretKeyAuthenticatorService>();
|
||||
// services.AddSingleton<GeoIPService>();
|
||||
// services.AddHostedService(provider => provider.GetRequiredService<GeoIPService>());
|
||||
services.AddSingleton<ServerTokenGenerator>();
|
||||
|
||||
services.Configure<AuthServiceConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||
|
||||
// configure metrics
|
||||
ConfigureMetrics(services);
|
||||
|
|
@ -71,7 +81,8 @@ public class Startup
|
|||
a.FeatureProviders.Remove(a.FeatureProviders.OfType<ControllerFeatureProvider>().First());
|
||||
if (mareConfig.GetValue<Uri>(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null)
|
||||
{
|
||||
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(MareServerConfigurationController), typeof(MareBaseConfigurationController), typeof(ClientMessageController)));
|
||||
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(MareServerConfigurationController), typeof(MareBaseConfigurationController), typeof(ClientMessageController), typeof(JwtController), typeof(OAuthController)));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -80,6 +91,50 @@ public class Startup
|
|||
});
|
||||
}
|
||||
|
||||
private void ConfigureRedis(IServiceCollection services, IConfigurationSection mareConfig)
|
||||
{
|
||||
// configure redis for SignalR
|
||||
var redisConnection = mareConfig.GetValue(nameof(ServerConfiguration.RedisConnectionString), string.Empty);
|
||||
var options = ConfigurationOptions.Parse(redisConnection);
|
||||
|
||||
var endpoint = options.EndPoints[0];
|
||||
string address = "";
|
||||
int port = 0;
|
||||
|
||||
if (endpoint is DnsEndPoint dnsEndPoint) { address = dnsEndPoint.Host; port = dnsEndPoint.Port; }
|
||||
if (endpoint is IPEndPoint ipEndPoint) { address = ipEndPoint.Address.ToString(); port = ipEndPoint.Port; }
|
||||
/*
|
||||
var redisConfiguration = new RedisConfiguration()
|
||||
{
|
||||
AbortOnConnectFail = true,
|
||||
KeyPrefix = "",
|
||||
Hosts = new RedisHost[]
|
||||
{
|
||||
new RedisHost(){ Host = address, Port = port },
|
||||
},
|
||||
AllowAdmin = true,
|
||||
ConnectTimeout = options.ConnectTimeout,
|
||||
Database = 0,
|
||||
Ssl = false,
|
||||
Password = options.Password,
|
||||
ServerEnumerationStrategy = new ServerEnumerationStrategy()
|
||||
{
|
||||
Mode = ServerEnumerationStrategy.ModeOptions.All,
|
||||
TargetRole = ServerEnumerationStrategy.TargetRoleOptions.Any,
|
||||
UnreachableServerAction = ServerEnumerationStrategy.UnreachableServerActionOptions.Throw,
|
||||
},
|
||||
MaxValueLength = 1024,
|
||||
PoolSize = mareConfig.GetValue(nameof(ServerConfiguration.RedisPool), 50),
|
||||
SyncTimeout = options.SyncTimeout,
|
||||
};*/
|
||||
|
||||
var muxer = ConnectionMultiplexer.Connect(options);
|
||||
var db = muxer.GetDatabase();
|
||||
services.AddSingleton<IDatabase>(db);
|
||||
|
||||
_logger.LogInformation("Setting up Redis to connect to {host}:{port}", address, port);
|
||||
}
|
||||
|
||||
private void ConfigureMareServices(IServiceCollection services, IConfigurationSection mareConfig)
|
||||
{
|
||||
bool isMainServer = mareConfig.GetValue<Uri>(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null;
|
||||
|
|
@ -90,8 +145,14 @@ public class Startup
|
|||
services.AddSingleton<ServerTokenGenerator>();
|
||||
services.AddSingleton<SystemInfoService>();
|
||||
services.AddSingleton<OnlineSyncedPairCacheService>();
|
||||
|
||||
services.Configure<AuthServiceConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
|
||||
|
||||
services.AddHostedService(provider => provider.GetService<SystemInfoService>());
|
||||
|
||||
services.AddHttpLogging(o => { });
|
||||
// configure services based on main server status
|
||||
_logger.LogWarning($"IsMainServer = {isMainServer}");
|
||||
ConfigureServicesBasedOnShardType(services, mareConfig, isMainServer);
|
||||
|
||||
services.AddSingleton(s => new MareCensus(s.GetRequiredService<ILogger<MareCensus>>()));
|
||||
|
|
@ -193,6 +254,8 @@ public class Startup
|
|||
|
||||
private static void ConfigureAuthorization(IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IAuthorizationHandler, RedisDbUserRequirementHandler>();
|
||||
services.AddTransient<IAuthorizationHandler, ExistingUserRequirementHandler>();
|
||||
services.AddTransient<IAuthorizationHandler, UserRequirementHandler>();
|
||||
services.AddTransient<IAuthorizationHandler, ValidTokenRequirementHandler>();
|
||||
services.AddTransient<IAuthorizationHandler, ValidTokenHubRequirementHandler>();
|
||||
|
|
@ -210,6 +273,8 @@ public class Startup
|
|||
};
|
||||
});
|
||||
|
||||
services.AddLogging();
|
||||
|
||||
services.AddAuthentication(o =>
|
||||
{
|
||||
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
|
|
@ -222,6 +287,13 @@ public class Startup
|
|||
options.DefaultPolicy = new AuthorizationPolicyBuilder()
|
||||
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
|
||||
.RequireAuthenticatedUser().Build();
|
||||
options.AddPolicy("OAuthToken", policy =>
|
||||
{
|
||||
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
|
||||
policy.AddRequirements(new ValidTokenRequirement());
|
||||
policy.AddRequirements(new ExistingUserRequirement());
|
||||
policy.RequireClaim(MareClaimTypes.OAuthLoginToken, "True");
|
||||
});
|
||||
options.AddPolicy("Authenticated", policy =>
|
||||
{
|
||||
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
|
||||
|
|
@ -253,6 +325,8 @@ public class Startup
|
|||
{
|
||||
services.AddDbContextPool<MareDbContext>(options =>
|
||||
{
|
||||
var defaultConnection = Configuration.GetConnectionString("DefaultConnection");
|
||||
_logger.LogDebug("Connecting to DB using: '{0}'", defaultConnection);
|
||||
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection"), builder =>
|
||||
{
|
||||
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
|
||||
|
|
@ -337,12 +411,16 @@ public class Startup
|
|||
|
||||
app.UseWebSockets();
|
||||
app.UseHttpMetrics();
|
||||
app.UseExceptionHandler("/Error");
|
||||
|
||||
var metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4980));
|
||||
metricServer.Start();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseHttpLogging();
|
||||
|
||||
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
|
|
@ -356,10 +434,11 @@ public class Startup
|
|||
endpoints.MapHealthChecks("/health").AllowAnonymous();
|
||||
endpoints.MapControllers();
|
||||
|
||||
|
||||
foreach (var source in endpoints.DataSources.SelectMany(e => e.Endpoints).Cast<RouteEndpoint>())
|
||||
{
|
||||
if (source == null) continue;
|
||||
_logger.LogInformation("Endpoint: {url} ", source.RoutePattern.RawText);
|
||||
_logger.LogWarning("Endpoint: {url} ", source.RoutePattern.RawText);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ internal class DiscordBot : IHostedService
|
|||
_botServices.UpdateGuild(guild);
|
||||
await _botServices.LogToChannel("Bot startup complete.").ConfigureAwait(false);
|
||||
_ = UpdateVanityRoles(guild, _clientConnectedCts.Token);
|
||||
_ = RemoveUsersNotInVanityRole(_clientConnectedCts.Token);
|
||||
_ = RemoveUnregisteredUsers(_clientConnectedCts.Token);
|
||||
// _ = RemoveUsersNotInVanityRole(_clientConnectedCts.Token);
|
||||
// 1_ = RemoveUnregisteredUsers(_clientConnectedCts.Token);
|
||||
}
|
||||
|
||||
private async Task UpdateVanityRoles(RestGuild guild, CancellationToken token)
|
||||
|
|
|
|||
|
|
@ -1,215 +0,0 @@
|
|||
using Discord;
|
||||
using Discord.Interactions;
|
||||
using MareSynchronosShared.Utils.Configuration;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace MareSynchronosServices.Discord;
|
||||
|
||||
public partial class MareWizardModule : InteractionModuleBase
|
||||
{
|
||||
private const int _totalAprilFoolsRoles = 200;
|
||||
private const string _persistentFileName = "april2024.json";
|
||||
|
||||
private static readonly SemaphoreSlim _fileSemaphore = new(1, 1);
|
||||
|
||||
[ComponentInteraction("wizard-fools")]
|
||||
public async Task ComponentFools()
|
||||
{
|
||||
if (!(await ValidateInteraction().ConfigureAwait(false))) return;
|
||||
|
||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentFools), Context.Interaction.User.Id);
|
||||
|
||||
EmbedBuilder eb = new();
|
||||
eb.WithTitle("WorryCoin™ and MareToken© Balance");
|
||||
eb.WithColor(Color.Gold);
|
||||
eb.WithDescription("You currently have" + Environment.NewLine + Environment.NewLine
|
||||
+ "**200000** MaTE©" + Environment.NewLine
|
||||
+ "**0** WorryCoin™" + Environment.NewLine + Environment.NewLine
|
||||
+ "You have no payment method set up. Press the button below to add a payment method.");
|
||||
ComponentBuilder cb = new();
|
||||
AddHome(cb);
|
||||
cb.WithButton("Add Payment Method", "wizard-fools-start", ButtonStyle.Primary, emote: new Emoji("💲"));
|
||||
await ModifyInteraction(eb, cb).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[ComponentInteraction("wizard-fools-start")]
|
||||
public async Task ComponentFoolsStart()
|
||||
{
|
||||
if (!(await ValidateInteraction().ConfigureAwait(false))) return;
|
||||
|
||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentFoolsStart), Context.Interaction.User.Id);
|
||||
|
||||
EmbedBuilder eb = new();
|
||||
var user = await Context.Guild.GetUserAsync(Context.User.Id).ConfigureAwait(false);
|
||||
bool userIsInPermanentVanityRole = _botServices.VanityRoles.Where(v => !v.Value.Contains('$', StringComparison.Ordinal))
|
||||
.Select(v => v.Key).Any(u => user.RoleIds.Contains(u.Id)) || !_botServices.VanityRoles.Any();
|
||||
ComponentBuilder cb = new();
|
||||
AddHome(cb);
|
||||
|
||||
var participatedUsers = await GetParticipants().ConfigureAwait(false);
|
||||
var remainingRoles = _totalAprilFoolsRoles - participatedUsers.Count(c => c.Value == true);
|
||||
|
||||
if (userIsInPermanentVanityRole)
|
||||
{
|
||||
eb.WithColor(Color.Green);
|
||||
eb.WithTitle("Happy April Fools!");
|
||||
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "__As you already have a role that gives you a permanent Vanity ID, you cannot win another one here. "
|
||||
+ "However, tell your friends as this bot will give them a chance to win one of " + _totalAprilFoolsRoles + " lifetime vanity roles.__"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "The giveaway is active until <t:" + (new DateTime(2024, 04, 01, 23, 59, 59, DateTimeKind.Utc).Subtract(DateTime.UnixEpoch).TotalSeconds) + ":f>.");
|
||||
}
|
||||
else if (participatedUsers.ContainsKey(Context.User.Id))
|
||||
{
|
||||
eb.WithColor(Color.Orange);
|
||||
eb.WithTitle("Happy April Fools!");
|
||||
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "__You already participated in the giveaway of the permanent Vanity roles and therefore cannot participate again. Better luck next time!__");
|
||||
}
|
||||
else if (remainingRoles > 0)
|
||||
{
|
||||
eb.WithColor(Color.Green);
|
||||
eb.WithTitle("Happy April Fools!");
|
||||
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "You have currently no permanent role that allows you to set a Vanity ID, however I am giving away a total of " + _totalAprilFoolsRoles + " permanent vanity roles "
|
||||
+ "(" + remainingRoles + " still remain) and you can win one using this bot!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "To win you simply have to pick one of the buttons labeled \"Win\" below this post. Which button will win is random. "
|
||||
+ "There is a 1 in 5 chance that you can win the role. __You can only participate once.__"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "The giveaway is active until <t:" + (new DateTime(2024, 04, 01, 23, 59, 59, DateTimeKind.Utc).Subtract(DateTime.UnixEpoch).TotalSeconds) + ":f>.");
|
||||
cb.WithButton("Win", "wizard-fools-win:1", ButtonStyle.Primary, new Emoji("1️⃣"));
|
||||
cb.WithButton("Win", "wizard-fools-win:2", ButtonStyle.Primary, new Emoji("2️⃣"));
|
||||
cb.WithButton("Win", "wizard-fools-win:3", ButtonStyle.Primary, new Emoji("3️⃣"));
|
||||
cb.WithButton("Win", "wizard-fools-win:4", ButtonStyle.Primary, new Emoji("4️⃣"));
|
||||
cb.WithButton("Win", "wizard-fools-win:5", ButtonStyle.Primary, new Emoji("5️⃣"));
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.WithColor(Color.Orange);
|
||||
eb.WithTitle("Happy April Fools!");
|
||||
eb.WithDescription("Thank you for participating in Mares 2024 April Fools event."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "As you might have already guessed from the post, nothing that was written there had any truth behind it."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "This entire thing was a jab at the ridiculousness of cryptocurrency, microtransactions and games featuring multiple currencies. I hope you enjoyed the announcement post!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "__I have been giving away " + _totalAprilFoolsRoles + " permanent Vanity ID roles for this server, however you are sadly too late as they ran out by now. "
|
||||
+ "Better luck next year with whatever I will come up with!__");
|
||||
}
|
||||
await ModifyInteraction(eb, cb).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[ComponentInteraction("wizard-fools-win:*")]
|
||||
public async Task ComponentFoolsWin(int number)
|
||||
{
|
||||
if (!(await ValidateInteraction().ConfigureAwait(false))) return;
|
||||
|
||||
_logger.LogInformation("{method}:{userId}", nameof(ComponentFoolsWin), Context.Interaction.User.Id);
|
||||
|
||||
var winningNumber = new Random().Next(1, 6);
|
||||
EmbedBuilder eb = new();
|
||||
ComponentBuilder cb = new();
|
||||
AddHome(cb);
|
||||
bool hasWon = winningNumber == number;
|
||||
|
||||
await WriteParticipants(Context.Interaction.User.Id, hasWon).ConfigureAwait(false);
|
||||
|
||||
if (hasWon)
|
||||
{
|
||||
eb.WithColor(Color.Gold);
|
||||
eb.WithTitle("Congratulations you are winner!");
|
||||
eb.WithDescription("You, by pure accident and sheer luck, picked the right number and have won yourself a lifetime Vanity ID role on this server!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "The role will remain as long as you remain on this server, if you happen to leave it you will not get the role back."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "Head over to Home and to the Vanity IDs section to set it up for your account!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "Once again, thank you for participating and have a great day.");
|
||||
|
||||
var user = await Context.Guild.GetUserAsync(Context.User.Id).ConfigureAwait(false);
|
||||
await user.AddRoleAsync(_mareServicesConfiguration.GetValue<ulong?>(nameof(ServicesConfiguration.DiscordRoleAprilFools2024)).Value).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.WithColor(Color.Red);
|
||||
eb.WithTitle("Fortune did not bless you");
|
||||
eb.WithDescription("You, through sheer misfortune, sadly did not pick the right number. (The winning number was " + winningNumber + ")"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "Better luck next time!"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "Once again, thank you for participating and regardless, have a great day.");
|
||||
}
|
||||
|
||||
await ModifyInteraction(eb, cb).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<Dictionary<ulong, bool>> GetParticipants()
|
||||
{
|
||||
await _fileSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_persistentFileName))
|
||||
{
|
||||
return new();
|
||||
}
|
||||
|
||||
var json = await File.ReadAllTextAsync(_persistentFileName).ConfigureAwait(false);
|
||||
return JsonSerializer.Deserialize<Dictionary<ulong, bool>>(json);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_fileSemaphore.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task WriteParticipants(ulong participant, bool win)
|
||||
{
|
||||
await _fileSemaphore.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
Dictionary<ulong, bool> participants = new();
|
||||
if (File.Exists(_persistentFileName))
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = await File.ReadAllTextAsync(_persistentFileName).ConfigureAwait(false);
|
||||
participants = JsonSerializer.Deserialize<Dictionary<ulong, bool>>(json);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// probably empty file just deal with it
|
||||
}
|
||||
}
|
||||
|
||||
participants[participant] = win;
|
||||
|
||||
await File.WriteAllTextAsync(_persistentFileName, JsonSerializer.Serialize(participants)).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_fileSemaphore.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,13 +24,14 @@ public partial class MareWizardModule
|
|||
eb.WithColor(Color.Blue);
|
||||
eb.WithTitle("Start Registration");
|
||||
eb.WithDescription("Here you can start the registration process with the Mare Synchronos server of this Discord." + Environment.NewLine + Environment.NewLine
|
||||
+ "- Have your Lodestone URL ready (i.e. https://eu.finalfantasyxiv.com/lodestone/character/XXXXXXXXX)" + Environment.NewLine
|
||||
+ " - The registration requires you to modify your Lodestone profile with a generated code for verification" + Environment.NewLine
|
||||
/*+ "- Have your Lodestone URL ready (i.e. https://eu.finalfantasyxiv.com/lodestone/character/XXXXXXXXX)" + Environment.NewLine
|
||||
+ " - The registration requires you to modify your Lodestone profile with a generated code for verification" + Environment.NewLine*/
|
||||
+ "- Do not use this on mobile because you will need to be able to copy the generated secret key" + Environment.NewLine
|
||||
+ "# Follow the bot instructions precisely. Slow down and read.");
|
||||
ComponentBuilder cb = new();
|
||||
AddHome(cb);
|
||||
cb.WithButton("Start Registration", "wizard-register-start", ButtonStyle.Primary, emote: new Emoji("🌒"));
|
||||
cb.WithButton("Register", "wizard-register-verify-check:OK", ButtonStyle.Primary, emote: new Emoji("❓"));
|
||||
// cb.WithButton("Start Registration", "wizard-register-start", ButtonStyle.Primary, emote: new Emoji("🌒"));
|
||||
await ModifyInteraction(eb, cb).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
|
@ -102,74 +103,29 @@ public partial class MareWizardModule
|
|||
|
||||
EmbedBuilder eb = new();
|
||||
ComponentBuilder cb = new();
|
||||
bool stillEnqueued = _botServices.VerificationQueue.Any(k => k.Key == Context.User.Id);
|
||||
bool verificationRan = _botServices.DiscordVerifiedUsers.TryGetValue(Context.User.Id, out bool verified);
|
||||
bool registerSuccess = false;
|
||||
if (!verificationRan)
|
||||
{
|
||||
if (stillEnqueued)
|
||||
{
|
||||
eb.WithColor(Color.Gold);
|
||||
eb.WithTitle("Your verification is still pending");
|
||||
eb.WithDescription("Please try again and click Check in a few seconds");
|
||||
cb.WithButton("Cancel", "wizard-register", ButtonStyle.Secondary, emote: new Emoji("❌"));
|
||||
cb.WithButton("Check", "wizard-register-verify-check:" + verificationCode, ButtonStyle.Primary, emote: new Emoji("❓"));
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.WithColor(Color.Red);
|
||||
eb.WithTitle("Something went wrong");
|
||||
eb.WithDescription("Your verification was processed but did not arrive properly. Please try to start the registration from the start.");
|
||||
cb.WithButton("Restart", "wizard-register", ButtonStyle.Primary, emote: new Emoji("🔁"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (verified)
|
||||
{
|
||||
|
||||
eb.WithColor(Color.Green);
|
||||
using var db = await GetDbContext().ConfigureAwait(false);
|
||||
var (uid, key) = await HandleAddUser(db).ConfigureAwait(false);
|
||||
eb.WithTitle($"Registration successful, your UID: {uid}");
|
||||
eb.WithDescription("This is your private secret key. Do not share this private secret key with anyone. **If you lose it, it is irrevocably lost.**"
|
||||
/*+ Environment.NewLine + Environment.NewLine
|
||||
+ "**__NOTE: Secret keys are considered legacy. Using the suggested OAuth2 authentication in Mare, you do not need to use this Secret Key.__**"*/
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "**__NOTE: Secret keys are considered legacy. Using the suggested OAuth2 authentication in Mare, you do not need to use this Secret Key.__**"
|
||||
+ $"**`{key}`**"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ $"||**`{key}`**||"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "If you want to continue using legacy authentication, enter this key in Mare Synchronos and hit save to connect to the service."
|
||||
+ Environment.NewLine
|
||||
/*+ "If you want to continue using legacy authentication, enter this key in Mare Synchronos and hit save to connect to the service."
|
||||
+ Environment.NewLine*/
|
||||
+ "__NOTE: The Secret Key only contains the letters ABCDEF and numbers 0 - 9.__"
|
||||
+ Environment.NewLine
|
||||
+ "You should connect as soon as possible to not get caught by the automatic cleanup process."
|
||||
+ Environment.NewLine
|
||||
//+ "You should connect as soon as possible to not get caught by the automatic cleanup process."
|
||||
//+ Environment.NewLine
|
||||
+ "Have fun.");
|
||||
AddHome(cb);
|
||||
registerSuccess = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
eb.WithColor(Color.Gold);
|
||||
eb.WithTitle("Failed to verify registration");
|
||||
eb.WithDescription("The bot was not able to find the required verification code on your Lodestone profile."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "Please restart your verification process, make sure to save your profile _twice_ for it to be properly saved."
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "If this link does not lead to your profile edit page, you __need__ to configure the privacy settings first: https://na.finalfantasyxiv.com/lodestone/my/setting/profile/"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "**Make sure your profile is set to public (All Users) for your character. The bot cannot read profiles with privacy settings set to \"logged in\" or \"private\".**"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "## You __need__ to enter following the code this bot provided onto your Lodestone in the character profile:"
|
||||
+ Environment.NewLine + Environment.NewLine
|
||||
+ "**`" + verificationCode + "`**");
|
||||
cb.WithButton("Cancel", "wizard-register", emote: new Emoji("❌"));
|
||||
cb.WithButton("Retry", "wizard-register-verify:" + verificationCode, ButtonStyle.Primary, emote: new Emoji("🔁"));
|
||||
}
|
||||
}
|
||||
|
||||
await ModifyInteraction(eb, cb).ConfigureAwait(false);
|
||||
if (registerSuccess)
|
||||
await _botServices.AddRegisteredRoleAsync(Context.Interaction.User).ConfigureAwait(false);
|
||||
|
||||
// if (registerSuccess)await _botServices.AddRegisteredRoleAsync(Context.Interaction.User).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task<(bool, string)> HandleRegisterModalAsync(EmbedBuilder embed, LodestoneModal arg)
|
||||
|
|
@ -262,7 +218,13 @@ public partial class MareWizardModule
|
|||
|
||||
private async Task<(string, string)> HandleAddUser(MareDbContext db)
|
||||
{
|
||||
_logger.LogWarning($"Adding User: {Context.User.Username}");
|
||||
var lodestoneAuth = db.LodeStoneAuth.SingleOrDefault(u => u.DiscordId == Context.User.Id);
|
||||
if (lodestoneAuth == null) {
|
||||
lodestoneAuth = new LodeStoneAuth() { DiscordId = Context.User.Id, HashedLodestoneId = $"{Context.User.Id}", User = null, LodestoneAuthString = string.Empty };
|
||||
await db.LodeStoneAuth.AddAsync(lodestoneAuth).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
var user = new User();
|
||||
|
||||
|
|
@ -294,10 +256,12 @@ public partial class MareWizardModule
|
|||
await db.Users.AddAsync(user).ConfigureAwait(false);
|
||||
await db.Auth.AddAsync(auth).ConfigureAwait(false);
|
||||
|
||||
|
||||
lodestoneAuth.StartedAt = null;
|
||||
lodestoneAuth.User = user;
|
||||
lodestoneAuth.LodestoneAuthString = null;
|
||||
|
||||
|
||||
await db.SaveChangesAsync().ConfigureAwait(false);
|
||||
|
||||
_botServices.Logger.LogInformation("User registered: {userUID}:{hashedKey}", user.UID, hashedKey);
|
||||
|
|
|
|||
|
|
@ -160,18 +160,17 @@ public partial class MareWizardModule : InteractionModuleBase
|
|||
+ (!hasAccount ? string.Empty : ("- Check your account status press \"ℹ️ User Info\"" + Environment.NewLine))
|
||||
+ (hasAccount ? string.Empty : ("- Register a new Mare Account press \"🌒 Register\"" + Environment.NewLine))
|
||||
+ (!hasAccount ? string.Empty : ("- You lost your secret key press \"🏥 Recover\"" + Environment.NewLine))
|
||||
+ (hasAccount ? string.Empty : ("- If you have changed your Discord account press \"🔗 Relink\"" + Environment.NewLine))
|
||||
// + (hasAccount ? string.Empty : ("- If you have changed your Discord account press \"🔗 Relink\"" + Environment.NewLine))
|
||||
+ (!hasAccount ? string.Empty : ("- Create a secondary UIDs press \"2️⃣ Secondary UID\"" + Environment.NewLine))
|
||||
+ (!hasAccount ? string.Empty : ("- Set a Vanity UID press \"💅 Vanity IDs\"" + Environment.NewLine))
|
||||
+ (!hasAccount ? string.Empty : (!isInAprilFoolsMode ? string.Empty : ("- Check your WorryCoin™ and MareToken© balance and add payment options" + Environment.NewLine)))
|
||||
+ (!hasAccount ? string.Empty : ("- Delete your primary or secondary accounts with \"⚠️ Delete\""))
|
||||
);
|
||||
eb.WithColor(Color.Blue);
|
||||
ComponentBuilder cb = new();
|
||||
if (!hasAccount)
|
||||
{
|
||||
cb.WithButton("Register", "wizard-register", ButtonStyle.Primary, new Emoji("🌒"));
|
||||
cb.WithButton("Relink", "wizard-relink", ButtonStyle.Secondary, new Emoji("🔗"));
|
||||
cb.WithButton("Register", "wizard-register-verify-check:OK", ButtonStyle.Primary, new Emoji("🌒"));
|
||||
// cb.WithButton("Relink", "wizard-relink", ButtonStyle.Secondary, new Emoji("🔗"));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -179,10 +178,6 @@ public partial class MareWizardModule : InteractionModuleBase
|
|||
cb.WithButton("Recover", "wizard-recover", ButtonStyle.Secondary, new Emoji("🏥"));
|
||||
cb.WithButton("Secondary UID", "wizard-secondary", ButtonStyle.Secondary, new Emoji("2️⃣"));
|
||||
cb.WithButton("Vanity IDs", "wizard-vanity", ButtonStyle.Secondary, new Emoji("💅"));
|
||||
if (isInAprilFoolsMode)
|
||||
{
|
||||
cb.WithButton("WorryCoin™ and MareToken© management", "wizard-fools", ButtonStyle.Primary, new Emoji("💲"));
|
||||
}
|
||||
cb.WithButton("Delete", "wizard-delete", ButtonStyle.Danger, new Emoji("⚠️"));
|
||||
}
|
||||
|
||||
|
|
|
|||
3
build_run.bat
Normal file
3
build_run.bat
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
docker build -t darkarchon/mare-synchronos-server:latest . -f Docker\build\Dockerfile-MareSynchronosServer --no-cache --pull --force-rm
|
||||
docker build -t darkarchon/mare-synchronos-services:latest . -f Docker\build\Dockerfile-MareSynchronosServices --no-cache --pull --force-rm
|
||||
docker compose -f Docker\run\compose\mare-standalone.yml -p standalone up -d
|
||||
Loading…
Add table
Add a link
Reference in a new issue