mirror of
https://github.com/kmc7468/arkvault.git
synced 2026-02-04 08:06:56 +00:00
강제 로그인 기능 추가
This commit is contained in:
@@ -46,17 +46,32 @@ export const refreshSession = async (
|
||||
return { userId: session.user_id, clientId: session.client_id };
|
||||
};
|
||||
|
||||
export const upgradeSession = async (sessionId: string, clientId: number) => {
|
||||
export const upgradeSession = async (
|
||||
userId: number,
|
||||
sessionId: string,
|
||||
clientId: number,
|
||||
force: boolean,
|
||||
) => {
|
||||
try {
|
||||
const res = await db
|
||||
.updateTable("session")
|
||||
.set({ client_id: clientId })
|
||||
.where("id", "=", sessionId)
|
||||
.where("client_id", "is", null)
|
||||
.executeTakeFirst();
|
||||
if (res.numUpdatedRows === 0n) {
|
||||
throw new IntegrityError("Session not found");
|
||||
}
|
||||
await db.transaction().execute(async (trx) => {
|
||||
if (force) {
|
||||
await trx
|
||||
.deleteFrom("session")
|
||||
.where("id", "!=", sessionId)
|
||||
.where("user_id", "=", userId)
|
||||
.where("client_id", "=", clientId)
|
||||
.execute();
|
||||
}
|
||||
const res = await trx
|
||||
.updateTable("session")
|
||||
.set({ client_id: clientId })
|
||||
.where("id", "=", sessionId)
|
||||
.where("client_id", "is", null)
|
||||
.executeTakeFirst();
|
||||
if (res.numUpdatedRows === 0n) {
|
||||
throw new IntegrityError("Session not found");
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
if (e instanceof pg.DatabaseError && e.code === "23505") {
|
||||
throw new IntegrityError("Session already exists");
|
||||
|
||||
@@ -4,28 +4,29 @@ export const passwordChangeRequest = z.object({
|
||||
oldPassword: z.string().trim().nonempty(),
|
||||
newPassword: z.string().trim().nonempty(),
|
||||
});
|
||||
export type PasswordChangeRequest = z.infer<typeof passwordChangeRequest>;
|
||||
export type PasswordChangeRequest = z.input<typeof passwordChangeRequest>;
|
||||
|
||||
export const loginRequest = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().trim().nonempty(),
|
||||
});
|
||||
export type LoginRequest = z.infer<typeof loginRequest>;
|
||||
export type LoginRequest = z.input<typeof loginRequest>;
|
||||
|
||||
export const sessionUpgradeRequest = z.object({
|
||||
encPubKey: z.string().base64().nonempty(),
|
||||
sigPubKey: z.string().base64().nonempty(),
|
||||
});
|
||||
export type SessionUpgradeRequest = z.infer<typeof sessionUpgradeRequest>;
|
||||
export type SessionUpgradeRequest = z.input<typeof sessionUpgradeRequest>;
|
||||
|
||||
export const sessionUpgradeResponse = z.object({
|
||||
id: z.number().int().positive(),
|
||||
challenge: z.string().base64().nonempty(),
|
||||
});
|
||||
export type SessionUpgradeResponse = z.infer<typeof sessionUpgradeResponse>;
|
||||
export type SessionUpgradeResponse = z.output<typeof sessionUpgradeResponse>;
|
||||
|
||||
export const sessionUpgradeVerifyRequest = z.object({
|
||||
id: z.number().int().positive(),
|
||||
answerSig: z.string().base64().nonempty(),
|
||||
force: z.boolean().default(false),
|
||||
});
|
||||
export type SessionUpgradeVerifyRequest = z.infer<typeof sessionUpgradeVerifyRequest>;
|
||||
export type SessionUpgradeVerifyRequest = z.input<typeof sessionUpgradeVerifyRequest>;
|
||||
|
||||
@@ -15,12 +15,12 @@ export const categoryInfoResponse = z.object({
|
||||
.optional(),
|
||||
subCategories: z.number().int().positive().array(),
|
||||
});
|
||||
export type CategoryInfoResponse = z.infer<typeof categoryInfoResponse>;
|
||||
export type CategoryInfoResponse = z.output<typeof categoryInfoResponse>;
|
||||
|
||||
export const categoryFileAddRequest = z.object({
|
||||
file: z.number().int().positive(),
|
||||
});
|
||||
export type CategoryFileAddRequest = z.infer<typeof categoryFileAddRequest>;
|
||||
export type CategoryFileAddRequest = z.input<typeof categoryFileAddRequest>;
|
||||
|
||||
export const categoryFileListResponse = z.object({
|
||||
files: z.array(
|
||||
@@ -30,19 +30,19 @@ export const categoryFileListResponse = z.object({
|
||||
}),
|
||||
),
|
||||
});
|
||||
export type CategoryFileListResponse = z.infer<typeof categoryFileListResponse>;
|
||||
export type CategoryFileListResponse = z.output<typeof categoryFileListResponse>;
|
||||
|
||||
export const categoryFileRemoveRequest = z.object({
|
||||
file: z.number().int().positive(),
|
||||
});
|
||||
export type CategoryFileRemoveRequest = z.infer<typeof categoryFileRemoveRequest>;
|
||||
export type CategoryFileRemoveRequest = z.input<typeof categoryFileRemoveRequest>;
|
||||
|
||||
export const categoryRenameRequest = z.object({
|
||||
dekVersion: z.string().datetime(),
|
||||
name: z.string().base64().nonempty(),
|
||||
nameIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type CategoryRenameRequest = z.infer<typeof categoryRenameRequest>;
|
||||
export type CategoryRenameRequest = z.input<typeof categoryRenameRequest>;
|
||||
|
||||
export const categoryCreateRequest = z.object({
|
||||
parent: categoryIdSchema,
|
||||
@@ -52,4 +52,4 @@ export const categoryCreateRequest = z.object({
|
||||
name: z.string().base64().nonempty(),
|
||||
nameIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type CategoryCreateRequest = z.infer<typeof categoryCreateRequest>;
|
||||
export type CategoryCreateRequest = z.input<typeof categoryCreateRequest>;
|
||||
|
||||
@@ -8,29 +8,29 @@ export const clientListResponse = z.object({
|
||||
}),
|
||||
),
|
||||
});
|
||||
export type ClientListResponse = z.infer<typeof clientListResponse>;
|
||||
export type ClientListResponse = z.output<typeof clientListResponse>;
|
||||
|
||||
export const clientRegisterRequest = z.object({
|
||||
encPubKey: z.string().base64().nonempty(),
|
||||
sigPubKey: z.string().base64().nonempty(),
|
||||
});
|
||||
export type ClientRegisterRequest = z.infer<typeof clientRegisterRequest>;
|
||||
export type ClientRegisterRequest = z.input<typeof clientRegisterRequest>;
|
||||
|
||||
export const clientRegisterResponse = z.object({
|
||||
id: z.number().int().positive(),
|
||||
challenge: z.string().base64().nonempty(),
|
||||
});
|
||||
export type ClientRegisterResponse = z.infer<typeof clientRegisterResponse>;
|
||||
export type ClientRegisterResponse = z.output<typeof clientRegisterResponse>;
|
||||
|
||||
export const clientRegisterVerifyRequest = z.object({
|
||||
id: z.number().int().positive(),
|
||||
answerSig: z.string().base64().nonempty(),
|
||||
});
|
||||
export type ClientRegisterVerifyRequest = z.infer<typeof clientRegisterVerifyRequest>;
|
||||
export type ClientRegisterVerifyRequest = z.input<typeof clientRegisterVerifyRequest>;
|
||||
|
||||
export const clientStatusResponse = z.object({
|
||||
id: z.number().int().positive(),
|
||||
state: z.enum(["pending", "active"]),
|
||||
isInitialMekNeeded: z.boolean(),
|
||||
});
|
||||
export type ClientStatusResponse = z.infer<typeof clientStatusResponse>;
|
||||
export type ClientStatusResponse = z.output<typeof clientStatusResponse>;
|
||||
|
||||
@@ -16,19 +16,19 @@ export const directoryInfoResponse = z.object({
|
||||
subDirectories: z.number().int().positive().array(),
|
||||
files: z.number().int().positive().array(),
|
||||
});
|
||||
export type DirectoryInfoResponse = z.infer<typeof directoryInfoResponse>;
|
||||
export type DirectoryInfoResponse = z.output<typeof directoryInfoResponse>;
|
||||
|
||||
export const directoryDeleteResponse = z.object({
|
||||
deletedFiles: z.number().int().positive().array(),
|
||||
});
|
||||
export type DirectoryDeleteResponse = z.infer<typeof directoryDeleteResponse>;
|
||||
export type DirectoryDeleteResponse = z.output<typeof directoryDeleteResponse>;
|
||||
|
||||
export const directoryRenameRequest = z.object({
|
||||
dekVersion: z.string().datetime(),
|
||||
name: z.string().base64().nonempty(),
|
||||
nameIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type DirectoryRenameRequest = z.infer<typeof directoryRenameRequest>;
|
||||
export type DirectoryRenameRequest = z.input<typeof directoryRenameRequest>;
|
||||
|
||||
export const directoryCreateRequest = z.object({
|
||||
parent: directoryIdSchema,
|
||||
@@ -38,4 +38,4 @@ export const directoryCreateRequest = z.object({
|
||||
name: z.string().base64().nonempty(),
|
||||
nameIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type DirectoryCreateRequest = z.infer<typeof directoryCreateRequest>;
|
||||
export type DirectoryCreateRequest = z.input<typeof directoryCreateRequest>;
|
||||
|
||||
@@ -21,42 +21,42 @@ export const fileInfoResponse = z.object({
|
||||
lastModifiedAtIv: z.string().base64().nonempty(),
|
||||
categories: z.number().int().positive().array(),
|
||||
});
|
||||
export type FileInfoResponse = z.infer<typeof fileInfoResponse>;
|
||||
export type FileInfoResponse = z.output<typeof fileInfoResponse>;
|
||||
|
||||
export const fileRenameRequest = z.object({
|
||||
dekVersion: z.string().datetime(),
|
||||
name: z.string().base64().nonempty(),
|
||||
nameIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type FileRenameRequest = z.infer<typeof fileRenameRequest>;
|
||||
export type FileRenameRequest = z.input<typeof fileRenameRequest>;
|
||||
|
||||
export const fileThumbnailInfoResponse = z.object({
|
||||
updatedAt: z.string().datetime(),
|
||||
contentIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type FileThumbnailInfoResponse = z.infer<typeof fileThumbnailInfoResponse>;
|
||||
export type FileThumbnailInfoResponse = z.output<typeof fileThumbnailInfoResponse>;
|
||||
|
||||
export const fileThumbnailUploadRequest = z.object({
|
||||
dekVersion: z.string().datetime(),
|
||||
contentIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type FileThumbnailUploadRequest = z.infer<typeof fileThumbnailUploadRequest>;
|
||||
export type FileThumbnailUploadRequest = z.input<typeof fileThumbnailUploadRequest>;
|
||||
|
||||
export const duplicateFileScanRequest = z.object({
|
||||
hskVersion: z.number().int().positive(),
|
||||
contentHmac: z.string().base64().nonempty(),
|
||||
});
|
||||
export type DuplicateFileScanRequest = z.infer<typeof duplicateFileScanRequest>;
|
||||
export type DuplicateFileScanRequest = z.input<typeof duplicateFileScanRequest>;
|
||||
|
||||
export const duplicateFileScanResponse = z.object({
|
||||
files: z.number().int().positive().array(),
|
||||
});
|
||||
export type DuplicateFileScanResponse = z.infer<typeof duplicateFileScanResponse>;
|
||||
export type DuplicateFileScanResponse = z.output<typeof duplicateFileScanResponse>;
|
||||
|
||||
export const missingThumbnailFileScanResponse = z.object({
|
||||
files: z.number().int().positive().array(),
|
||||
});
|
||||
export type MissingThumbnailFileScanResponse = z.infer<typeof missingThumbnailFileScanResponse>;
|
||||
export type MissingThumbnailFileScanResponse = z.output<typeof missingThumbnailFileScanResponse>;
|
||||
|
||||
export const fileUploadRequest = z.object({
|
||||
parent: directoryIdSchema,
|
||||
@@ -78,9 +78,9 @@ export const fileUploadRequest = z.object({
|
||||
lastModifiedAt: z.string().base64().nonempty(),
|
||||
lastModifiedAtIv: z.string().base64().nonempty(),
|
||||
});
|
||||
export type FileUploadRequest = z.infer<typeof fileUploadRequest>;
|
||||
export type FileUploadRequest = z.input<typeof fileUploadRequest>;
|
||||
|
||||
export const fileUploadResponse = z.object({
|
||||
file: z.number().int().positive(),
|
||||
});
|
||||
export type FileUploadResponse = z.infer<typeof fileUploadResponse>;
|
||||
export type FileUploadResponse = z.output<typeof fileUploadResponse>;
|
||||
|
||||
@@ -10,10 +10,10 @@ export const hmacSecretListResponse = z.object({
|
||||
}),
|
||||
),
|
||||
});
|
||||
export type HmacSecretListResponse = z.infer<typeof hmacSecretListResponse>;
|
||||
export type HmacSecretListResponse = z.output<typeof hmacSecretListResponse>;
|
||||
|
||||
export const initialHmacSecretRegisterRequest = z.object({
|
||||
mekVersion: z.number().int().positive(),
|
||||
hsk: z.string().base64().nonempty(),
|
||||
});
|
||||
export type InitialHmacSecretRegisterRequest = z.infer<typeof initialHmacSecretRegisterRequest>;
|
||||
export type InitialHmacSecretRegisterRequest = z.input<typeof initialHmacSecretRegisterRequest>;
|
||||
|
||||
@@ -10,10 +10,10 @@ export const masterKeyListResponse = z.object({
|
||||
}),
|
||||
),
|
||||
});
|
||||
export type MasterKeyListResponse = z.infer<typeof masterKeyListResponse>;
|
||||
export type MasterKeyListResponse = z.output<typeof masterKeyListResponse>;
|
||||
|
||||
export const initialMasterKeyRegisterRequest = z.object({
|
||||
mek: z.string().base64().nonempty(),
|
||||
mekSig: z.string().base64().nonempty(),
|
||||
});
|
||||
export type InitialMasterKeyRegisterRequest = z.infer<typeof initialMasterKeyRegisterRequest>;
|
||||
export type InitialMasterKeyRegisterRequest = z.input<typeof initialMasterKeyRegisterRequest>;
|
||||
|
||||
@@ -4,9 +4,9 @@ export const userInfoResponse = z.object({
|
||||
email: z.string().email(),
|
||||
nickname: z.string().nonempty(),
|
||||
});
|
||||
export type UserInfoResponse = z.infer<typeof userInfoResponse>;
|
||||
export type UserInfoResponse = z.output<typeof userInfoResponse>;
|
||||
|
||||
export const nicknameChangeRequest = z.object({
|
||||
newNickname: z.string().trim().min(2).max(8),
|
||||
});
|
||||
export type NicknameChangeRequest = z.infer<typeof nicknameChangeRequest>;
|
||||
export type NicknameChangeRequest = z.input<typeof nicknameChangeRequest>;
|
||||
|
||||
@@ -87,9 +87,11 @@ export const createSessionUpgradeChallenge = async (
|
||||
|
||||
export const verifySessionUpgradeChallenge = async (
|
||||
sessionId: string,
|
||||
userId: number,
|
||||
ip: string,
|
||||
challengeId: number,
|
||||
answerSig: string,
|
||||
force: boolean,
|
||||
) => {
|
||||
const challenge = await consumeSessionUpgradeChallenge(challengeId, sessionId, ip);
|
||||
if (!challenge) {
|
||||
@@ -106,13 +108,13 @@ export const verifySessionUpgradeChallenge = async (
|
||||
}
|
||||
|
||||
try {
|
||||
await upgradeSession(sessionId, client.id);
|
||||
await upgradeSession(userId, sessionId, client.id, force);
|
||||
} catch (e) {
|
||||
if (e instanceof IntegrityError) {
|
||||
if (e.message === "Session not found") {
|
||||
error(500, "Invalid challenge answer");
|
||||
} else if (e.message === "Session already exists") {
|
||||
error(403, "Already logged in");
|
||||
} else if (!force && e.message === "Session already exists") {
|
||||
error(409, "Already logged in");
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
|
||||
Reference in New Issue
Block a user