From 63067869d8c1da029e96ef9c843fa4387ef57d36 Mon Sep 17 00:00:00 2001 From: FriendlyNamazu Date: Sat, 30 Aug 2025 18:56:18 +0200 Subject: [PATCH] remove lodestone verification also remove relinking as there's nothing to relink with --- .../Discord/MareWizardModule.Register.cs | 62 ++-- .../Discord/MareWizardModule.Relink.cs | 281 ------------------ .../Discord/MareWizardModule.cs | 2 - 3 files changed, 45 insertions(+), 300 deletions(-) delete mode 100644 MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Relink.cs diff --git a/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Register.cs b/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Register.cs index 72411c2..7115d0e 100644 --- a/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Register.cs +++ b/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Register.cs @@ -21,16 +21,44 @@ public partial class MareWizardModule _logger.LogInformation("{method}:{userId}", nameof(ComponentRegister), Context.Interaction.User.Id); EmbedBuilder eb = new(); - 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 - + "- 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."); + // eb.WithColor(Color.Blue); + // eb.WithTitle("Start Registration"); + // eb.WithDescription("Here you can start the registration process with the Namazu Sync 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 + // + "- 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("πŸŒ’")); + + var registerSuccess = false; + + eb.WithColor(Color.Green); + using var db = await GetDbContext().ConfigureAwait(false); + string lodestoneAuth = await GenerateLodestoneAuth(Context.User.Id, null, db).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 + + $"**{key}**" + + Environment.NewLine + Environment.NewLine + + "Enter this key in Namazu Sync 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 + + " __NOTE: Secret keys are considered legacy. Using the suggested OAuth2 authentication, you do not need to use this Secret Key.__" + + Environment.NewLine + + "You should connect as soon as possible to not get caught by the automatic cleanup process." + + Environment.NewLine + + "Have fun." + ); ComponentBuilder cb = new(); AddHome(cb); - cb.WithButton("Start Registration", "wizard-register-start", ButtonStyle.Primary, emote: new Emoji("πŸŒ’")); + if (registerSuccess) { + await _botServices.AddRegisteredRoleAsync(Context.Interaction.User).ConfigureAwait(false); + } + await ModifyInteraction(eb, cb).ConfigureAwait(false); } @@ -133,14 +161,14 @@ public partial class MareWizardModule 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.__**" + + $"**{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." + + "Enter this key in Namazu Sync 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 + + " __NOTE: Secret keys are considered legacy. Using the suggested OAuth2 authentication, you do not need to use this Secret Key.__" + + Environment.NewLine + "You should connect as soon as possible to not get caught by the automatic cleanup process." + Environment.NewLine + "Have fun."); @@ -159,9 +187,9 @@ public partial class MareWizardModule + 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:" + + "## You __need__ to enter following the code this bot provided onto your lodestone in the character profile:" + Environment.NewLine + Environment.NewLine - + "**`" + verificationCode + "`**"); + + "**" + verificationCode + "**"); cb.WithButton("Cancel", "wizard-register", emote: new Emoji("❌")); cb.WithButton("Retry", "wizard-register-verify:" + verificationCode, ButtonStyle.Primary, emote: new Emoji("πŸ”")); } @@ -209,11 +237,11 @@ public partial class MareWizardModule + Environment.NewLine + "__NOTE: If the link does not lead you to your character edit profile page, you need to log in and set up your privacy settings!__" + Environment.NewLine + Environment.NewLine - + $"**`{lodestoneAuth}`**" + + $"**{lodestoneAuth}**" + Environment.NewLine + Environment.NewLine - + $"**! THIS IS NOT THE KEY YOU HAVE TO ENTER IN MARE !**" + + $"**! THIS IS NOT THE KEY YOU HAVE TO ENTER IN NAMAZU !**" + Environment.NewLine + Environment.NewLine - + "Once added and saved, use the button below to Verify and finish registration and receive a secret key to use for Mare Synchronos." + + "Once added and saved, use the button below to Verify and finish registration and receive a secret key to use for Namazu Sync." + Environment.NewLine + "__You can delete the entry from your profile after verification.__" + Environment.NewLine + Environment.NewLine diff --git a/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Relink.cs b/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Relink.cs deleted file mode 100644 index 52e9bcc..0000000 --- a/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.Relink.cs +++ /dev/null @@ -1,281 +0,0 @@ -ο»Ώusing Discord.Interactions; -using Discord; -using MareSynchronosShared.Data; -using MareSynchronosShared.Utils; -using MareSynchronosShared.Models; -using Microsoft.EntityFrameworkCore; - -namespace MareSynchronosServices.Discord; - -public partial class MareWizardModule -{ - [ComponentInteraction("wizard-relink")] - public async Task ComponentRelink() - { - if (!(await ValidateInteraction().ConfigureAwait(false))) return; - - _logger.LogInformation("{method}:{userId}", nameof(ComponentRelink), Context.Interaction.User.Id); - - EmbedBuilder eb = new(); - eb.WithTitle("Relink"); - eb.WithColor(Color.Blue); - eb.WithDescription("Use this in case you already have a registered Mare account, but lost access to your previous Discord account." + Environment.NewLine + Environment.NewLine - + "- Have your original registered Lodestone URL ready (i.e. https://eu.finalfantasyxiv.com/lodestone/character/XXXXXXXXX)" + Environment.NewLine - + " - The relink process 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"); - ComponentBuilder cb = new(); - AddHome(cb); - cb.WithButton("Start Relink", "wizard-relink-start", ButtonStyle.Primary, emote: new Emoji("πŸ”—")); - await ModifyInteraction(eb, cb).ConfigureAwait(false); - } - - [ComponentInteraction("wizard-relink-start")] - public async Task ComponentRelinkStart() - { - if (!(await ValidateInteraction().ConfigureAwait(false))) return; - - _logger.LogInformation("{method}:{userId}", nameof(ComponentRelinkStart), Context.Interaction.User.Id); - - using var db = await GetDbContext().ConfigureAwait(false); - db.LodeStoneAuth.RemoveRange(db.LodeStoneAuth.Where(u => u.DiscordId == Context.User.Id)); - _botServices.DiscordVerifiedUsers.TryRemove(Context.User.Id, out _); - _botServices.DiscordRelinkLodestoneMapping.TryRemove(Context.User.Id, out _); - await db.SaveChangesAsync().ConfigureAwait(false); - - await RespondWithModalAsync("wizard-relink-lodestone-modal").ConfigureAwait(false); - } - - [ModalInteraction("wizard-relink-lodestone-modal")] - public async Task ModalRelink(LodestoneModal lodestoneModal) - { - if (!(await ValidateInteraction().ConfigureAwait(false))) return; - - _logger.LogInformation("{method}:{userId}:{url}", nameof(ModalRelink), Context.Interaction.User.Id, lodestoneModal.LodestoneUrl); - - EmbedBuilder eb = new(); - eb.WithColor(Color.Purple); - var result = await HandleRelinkModalAsync(eb, lodestoneModal).ConfigureAwait(false); - ComponentBuilder cb = new(); - cb.WithButton("Cancel", "wizard-relink", ButtonStyle.Secondary, emote: new Emoji("❌")); - if (result.Success) cb.WithButton("Verify", "wizard-relink-verify:" + result.LodestoneAuth + "," + result.UID, ButtonStyle.Primary, emote: new Emoji("βœ…")); - else cb.WithButton("Try again", "wizard-relink-start", ButtonStyle.Primary, emote: new Emoji("πŸ”")); - await ModifyModalInteraction(eb, cb).ConfigureAwait(false); - } - - [ComponentInteraction("wizard-relink-verify:*,*")] - public async Task ComponentRelinkVerify(string verificationCode, string uid) - { - if (!(await ValidateInteraction().ConfigureAwait(false))) return; - - _logger.LogInformation("{method}:{userId}:{uid}:{verificationCode}", nameof(ComponentRelinkVerify), Context.Interaction.User.Id, uid, verificationCode); - - - _botServices.VerificationQueue.Enqueue(new KeyValuePair>(Context.User.Id, - (services) => HandleVerifyRelinkAsync(Context.User.Id, verificationCode, services))); - EmbedBuilder eb = new(); - ComponentBuilder cb = new(); - eb.WithColor(Color.Purple); - cb.WithButton("Cancel", "wizard-relink", ButtonStyle.Secondary, emote: new Emoji("❌")); - cb.WithButton("Check", "wizard-relink-verify-check:" + verificationCode + "," + uid, ButtonStyle.Primary, emote: new Emoji("❓")); - eb.WithTitle("Relink Verification Pending"); - eb.WithDescription("Please wait until the bot verifies your registration." + Environment.NewLine - + "Press \"Check\" to check if the verification has been already processed" + Environment.NewLine + Environment.NewLine - + "__This will not advance automatically, you need to press \"Check\".__"); - await ModifyInteraction(eb, cb).ConfigureAwait(false); - } - - [ComponentInteraction("wizard-relink-verify-check:*,*")] - public async Task ComponentRelinkVerifyCheck(string verificationCode, string uid) - { - if (!(await ValidateInteraction().ConfigureAwait(false))) return; - - _logger.LogInformation("{method}:{userId}:{uid}:{verificationCode}", nameof(ComponentRelinkVerifyCheck), Context.Interaction.User.Id, uid, verificationCode); - - 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 relinkSuccess = false; - if (!verificationRan) - { - if (stillEnqueued) - { - eb.WithColor(Color.Gold); - eb.WithTitle("Your relink verification is still pending"); - eb.WithDescription("Please try again and click Check in a few seconds"); - cb.WithButton("Cancel", "wizard-relink", ButtonStyle.Secondary, emote: new Emoji("❌")); - cb.WithButton("Check", "wizard-relink-verify-check:" + verificationCode + "," + uid, ButtonStyle.Primary, emote: new Emoji("❓")); - } - else - { - eb.WithColor(Color.Red); - eb.WithTitle("Something went wrong"); - eb.WithDescription("Your relink verification was processed but did not arrive properly. Please try to start the relink process from the start."); - cb.WithButton("Restart", "wizard-relink", ButtonStyle.Primary, emote: new Emoji("πŸ”")); - } - } - else - { - if (verified) - { - eb.WithColor(Color.Green); - using var db = await GetDbContext().ConfigureAwait(false); - var (_, key) = await HandleRelinkUser(db, uid).ConfigureAwait(false); - eb.WithTitle($"Relink successful, your UID is again: {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 - + $"||**`{key}`**||" - + Environment.NewLine + Environment.NewLine - + "Enter this key in Mare Synchronos and hit save to connect to the service." - + Environment.NewLine + Environment.NewLine - + "NOTE: If you are using OAuth2, you do not require to use this secret key." - + Environment.NewLine - + "Have fun."); - AddHome(cb); - - relinkSuccess = true; - } - else - { - eb.WithColor(Color.Gold); - eb.WithTitle("Failed to verify relink"); - eb.WithDescription("The bot was not able to find the required verification code on your Lodestone profile." + Environment.NewLine + Environment.NewLine - + "Please restart your relink process, make sure to save your profile _twice_ for it to be properly saved." + 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 - + "The code the bot is looking for is" + Environment.NewLine + Environment.NewLine - + "**`" + verificationCode + "`**"); - cb.WithButton("Cancel", "wizard-relink", emote: new Emoji("❌")); - cb.WithButton("Retry", "wizard-relink-verify:" + verificationCode + "," + uid, ButtonStyle.Primary, emote: new Emoji("πŸ”")); - } - } - - await ModifyInteraction(eb, cb).ConfigureAwait(false); - if (relinkSuccess) - await _botServices.AddRegisteredRoleAsync(Context.Interaction.User).ConfigureAwait(false); - } - - private async Task<(bool Success, string LodestoneAuth, string UID)> HandleRelinkModalAsync(EmbedBuilder embed, LodestoneModal arg) - { - ulong userId = Context.User.Id; - - var lodestoneId = ParseCharacterIdFromLodestoneUrl(arg.LodestoneUrl); - if (lodestoneId == null) - { - embed.WithTitle("Invalid Lodestone URL"); - embed.WithDescription("The lodestone URL was not valid. It should have following format:" + Environment.NewLine - + "https://eu.finalfantasyxiv.com/lodestone/character/YOUR_LODESTONE_ID/"); - return (false, string.Empty, string.Empty); - } - // check if userid is already in db - var hashedLodestoneId = StringUtils.Sha256String(lodestoneId.ToString()); - - using var db = await GetDbContext().ConfigureAwait(false); - - // check if discord id or lodestone id is banned - if (db.BannedRegistrations.Any(a => a.DiscordIdOrLodestoneAuth == hashedLodestoneId)) - { - embed.WithTitle("Illegal operation"); - embed.WithDescription("Your account is banned"); - return (false, string.Empty, string.Empty); - } - - if (!db.LodeStoneAuth.Any(a => a.HashedLodestoneId == hashedLodestoneId)) - { - // character already in db - embed.WithTitle("Impossible operation"); - embed.WithDescription("This lodestone character does not exist in the database."); - return (false, string.Empty, string.Empty); - } - - var expectedUser = await db.LodeStoneAuth.Include(u => u.User).SingleAsync(u => u.HashedLodestoneId == hashedLodestoneId).ConfigureAwait(false); - - string lodestoneAuth = await GenerateLodestoneAuth(Context.User.Id, hashedLodestoneId, db).ConfigureAwait(false); - // check if lodestone id is already in db - embed.WithTitle("Authorize your character for relinking"); - embed.WithDescription("Add following key to your character profile at https://na.finalfantasyxiv.com/lodestone/my/setting/profile/" - + Environment.NewLine + Environment.NewLine - + $"**`{lodestoneAuth}`**" - + Environment.NewLine + Environment.NewLine - + $"**! THIS IS NOT THE KEY YOU HAVE TO ENTER IN MARE !**" - + Environment.NewLine - + "__You can delete the entry from your profile after verification.__" - + Environment.NewLine + Environment.NewLine - + "The verification will expire in approximately 15 minutes. If you fail to verify the relink will be invalidated and you have to relink again."); - _botServices.DiscordRelinkLodestoneMapping[Context.User.Id] = lodestoneId.ToString(); - - return (true, lodestoneAuth, expectedUser.User.UID); - } - - private async Task HandleVerifyRelinkAsync(ulong userid, string authString, DiscordBotServices services) - { - using var req = new HttpClient(); - - services.DiscordVerifiedUsers.Remove(userid, out _); - if (services.DiscordRelinkLodestoneMapping.ContainsKey(userid)) - { - var randomServer = services.LodestoneServers[random.Next(services.LodestoneServers.Length)]; - var url = $"https://{randomServer}.finalfantasyxiv.com/lodestone/character/{services.DiscordRelinkLodestoneMapping[userid]}"; - _logger.LogInformation("Verifying {userid} with URL {url}", userid, url); - using var response = await req.GetAsync(url).ConfigureAwait(false); - if (response.IsSuccessStatusCode || response.StatusCode == System.Net.HttpStatusCode.Forbidden) - { - var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - if (content.Contains(authString)) - { - services.DiscordVerifiedUsers[userid] = true; - _logger.LogInformation("Relink: Verified {userid} from lodestone {lodestone}", userid, services.DiscordRelinkLodestoneMapping[userid]); - await _botServices.LogToChannel($"<@{userid}> RELINK VERIFY: Success.").ConfigureAwait(false); - services.DiscordRelinkLodestoneMapping.TryRemove(userid, out _); - } - else - { - services.DiscordVerifiedUsers[userid] = false; - _logger.LogInformation("Relink: Could not verify {userid} from lodestone {lodestone}, did not find authString: {authString}, status code was: {code}", - userid, services.DiscordRelinkLodestoneMapping[userid], authString, response.StatusCode); - await _botServices.LogToChannel($"<@{userid}> RELINK VERIFY: Failed: No Authstring ({authString}). (<{url}>)").ConfigureAwait(false); - } - } - else - { - _logger.LogWarning("Could not verify {userid}, HttpStatusCode: {code}", userid, response.StatusCode); - await _botServices.LogToChannel($"<@{userid}> RELINK VERIFY: Failed: HttpStatusCode {response.StatusCode}. (<{url}>)").ConfigureAwait(false); - } - } - } - - private async Task<(string, string)> HandleRelinkUser(MareDbContext db, string uid) - { - var oldLodestoneAuth = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(u => u.User.UID == uid && u.DiscordId != Context.User.Id).ConfigureAwait(false); - var newLodestoneAuth = await db.LodeStoneAuth.Include(u => u.User).SingleOrDefaultAsync(u => u.DiscordId == Context.User.Id).ConfigureAwait(false); - - var user = oldLodestoneAuth.User; - - var computedHash = StringUtils.Sha256String(StringUtils.GenerateRandomString(64) + DateTime.UtcNow.ToString()); - var auth = new Auth() - { - HashedKey = StringUtils.Sha256String(computedHash), - User = user, - }; - - var previousAuth = await db.Auth.SingleOrDefaultAsync(u => u.UserUID == user.UID).ConfigureAwait(false); - if (previousAuth != null) - { - db.Remove(previousAuth); - } - - newLodestoneAuth.LodestoneAuthString = null; - newLodestoneAuth.StartedAt = null; - newLodestoneAuth.User = user; - db.Update(newLodestoneAuth); - db.Remove(oldLodestoneAuth); - await db.Auth.AddAsync(auth).ConfigureAwait(false); - - _botServices.Logger.LogInformation("User relinked: {userUID}", user.UID); - - await db.SaveChangesAsync().ConfigureAwait(false); - - await _botServices.LogToChannel($"{Context.User.Mention} RELINK COMPLETE: => {user.UID}").ConfigureAwait(false); - - return (user.UID, computedHash); - } -} diff --git a/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.cs b/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.cs index 15425f2..e10770e 100644 --- a/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.cs +++ b/MareSynchronosServer/MareSynchronosServices/Discord/MareWizardModule.cs @@ -160,7 +160,6 @@ public partial class MareWizardModule : InteractionModuleBase + (!hasAccount ? string.Empty : ("- Check your account status press \"ℹ️ User Info\"" + Environment.NewLine)) + (hasAccount ? string.Empty : ("- Register a new Namazu 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 : ("- 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))) @@ -171,7 +170,6 @@ public partial class MareWizardModule : InteractionModuleBase if (!hasAccount) { cb.WithButton("Register", "wizard-register", ButtonStyle.Primary, new Emoji("πŸŒ’")); - cb.WithButton("Relink", "wizard-relink", ButtonStyle.Secondary, new Emoji("πŸ”—")); } else {