feat: login conflict (#1127)
Some checks failed
Build / build (20) (push) Successful in 40s
Build / build (22) (push) Has been cancelled
Build Docker image / docker (push) Has been cancelled
Build / build (18) (push) Has been cancelled

Closes #1076

Reviewed-on: #1127
This commit is contained in:
Sainan 2025-03-09 07:40:37 -07:00
parent 3da02385f9
commit f6513420be
6 changed files with 31 additions and 17 deletions

View File

@ -61,10 +61,19 @@ export const loginController: RequestHandler = async (request, response) => {
return; return;
} }
if (account.Nonce == 0 || loginRequest.ClientType != "webui") { if (loginRequest.ClientType == "webui") {
if (!account.Nonce) {
account.ClientType = "webui";
account.Nonce = nonce;
}
} else {
if (account.Nonce && account.ClientType != "webui" && !account.Dropped && !loginRequest.kick) {
response.status(400).json({ error: "nonce still set" });
return;
}
account.ClientType = loginRequest.ClientType;
account.Nonce = nonce; account.Nonce = nonce;
}
if (loginRequest.ClientType != "webui") {
account.CountryCode = loginRequest.lang.toUpperCase(); account.CountryCode = loginRequest.lang.toUpperCase();
} }
await account.save(); await account.save();

View File

@ -0,0 +1,9 @@
import { getAccountForRequest } from "@/src/services/loginService";
import { RequestHandler } from "express";
export const ircDroppedController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req);
account.Dropped = true;
await account.save();
res.end();
};

View File

@ -20,6 +20,7 @@ const databaseAccountSchema = new Schema<IDatabaseAccountJson>(
ConsentNeeded: { type: Boolean, required: true }, ConsentNeeded: { type: Boolean, required: true },
TrackedSettings: { type: [String], default: [] }, TrackedSettings: { type: [String], default: [] },
Nonce: { type: Number, default: 0 }, Nonce: { type: Number, default: 0 },
Dropped: Boolean,
LastLoginDay: { type: Number }, LastLoginDay: { type: Number },
LatestEventMessageDate: { type: Date, default: 0 } LatestEventMessageDate: { type: Date, default: 0 }
}, },

View File

@ -7,6 +7,7 @@ import { popArchonCrystalUpgradeController } from "@/src/controllers/custom/popA
import { deleteAccountController } from "@/src/controllers/custom/deleteAccountController"; import { deleteAccountController } from "@/src/controllers/custom/deleteAccountController";
import { getNameController } from "@/src/controllers/custom/getNameController"; import { getNameController } from "@/src/controllers/custom/getNameController";
import { renameAccountController } from "@/src/controllers/custom/renameAccountController"; import { renameAccountController } from "@/src/controllers/custom/renameAccountController";
import { ircDroppedController } from "@/src/controllers/custom/ircDroppedController";
import { createAccountController } from "@/src/controllers/custom/createAccountController"; import { createAccountController } from "@/src/controllers/custom/createAccountController";
import { createMessageController } from "@/src/controllers/custom/createMessageController"; import { createMessageController } from "@/src/controllers/custom/createMessageController";
@ -28,6 +29,7 @@ customRouter.get("/popArchonCrystalUpgrade", popArchonCrystalUpgradeController);
customRouter.get("/deleteAccount", deleteAccountController); customRouter.get("/deleteAccount", deleteAccountController);
customRouter.get("/getName", getNameController); customRouter.get("/getName", getNameController);
customRouter.get("/renameAccount", renameAccountController); customRouter.get("/renameAccount", renameAccountController);
customRouter.get("/ircDropped", ircDroppedController);
customRouter.post("/createAccount", createAccountController); customRouter.post("/createAccount", createAccountController);
customRouter.post("/createMessage", createMessageController); customRouter.post("/createMessage", createMessageController);

View File

@ -82,21 +82,12 @@ export const getAccountForRequest = async (req: Request): Promise<TAccountDocume
}; };
export const getAccountIdForRequest = async (req: Request): Promise<string> => { export const getAccountIdForRequest = async (req: Request): Promise<string> => {
if (!req.query.accountId) { const account = await getAccountForRequest(req);
throw new Error("Request is missing accountId parameter"); if (account.Dropped && req.query.ct) {
account.Dropped = undefined;
await account.save();
} }
if (!req.query.nonce || parseInt(req.query.nonce as string) === 0) { return account._id.toString();
throw new Error("Request is missing nonce parameter");
}
if (
!(await Account.exists({
_id: req.query.accountId,
Nonce: req.query.nonce
}))
) {
throw new Error("Invalid accountId-nonce pair");
}
return req.query.accountId as string;
}; };
export const isAdministrator = (account: TAccountDocument): boolean => { export const isAdministrator = (account: TAccountDocument): boolean => {

View File

@ -14,6 +14,7 @@ export interface IAccountAndLoginResponseCommons {
export interface IDatabaseAccount extends IAccountAndLoginResponseCommons { export interface IDatabaseAccount extends IAccountAndLoginResponseCommons {
email: string; email: string;
password: string; password: string;
Dropped?: boolean;
LastLoginDay?: number; LastLoginDay?: number;
LatestEventMessageDate: Date; LatestEventMessageDate: Date;
} }
@ -32,6 +33,7 @@ export interface ILoginRequest {
date: number; date: number;
ClientType: string; ClientType: string;
PS: string; PS: string;
kick?: boolean;
} }
export interface ILoginResponse extends IAccountAndLoginResponseCommons { export interface ILoginResponse extends IAccountAndLoginResponseCommons {