owltide/server/api/auth/account.post.ts
Hornwitser f69381c44c
Some checks failed
/ build (push) Failing after 28s
/ deploy (push) Has been skipped
Set verbatimModuleSyntax for server code
The nuxi typecheck command complains about type only imports that are
not declared as such, but the VsCode environment does not.  There's
probably a missmatch somewhere in the configuration for Nuxt that I'm
not going to dig into.  Workaround this issue for now by setting the
option in the tsconfig.json file for the server.
2025-07-09 18:10:42 +02:00

96 lines
2.6 KiB
TypeScript

/*
SPDX-FileCopyrightText: © 2025 Hornwitser <code@hornwitser.no>
SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { readUsers, writeUsers, nextUserId, type ServerUser, readAuthenticationMethods, nextAuthenticationMethodId, writeAuthenticationMethods } from "~/server/database";
import { broadcastEvent } from "~/server/streams";
import type { ApiSession } from "~/shared/types/api";
export default defineEventHandler(async (event): Promise<ApiSession> => {
let session = await getServerSession(event, false);
if (session?.accountId !== undefined) {
throw createError({
status: 409,
message: "Cannot create account while logged in to an account."
});
}
const body = await readBody(event);
const name = body?.name;
const users = await readUsers();
let user: ServerUser;
if (typeof name === "string") {
if (name === "") {
throw createError({
status: 400,
message: "Name cannot be blank",
});
}
if (users.some(user => user.name && user.name.toLowerCase() === name.toLowerCase())) {
throw createError({
status: 409,
message: "User already exists",
});
}
const firstUser = users.every(user => user.type === "anonymous");
user = {
id: await nextUserId(),
updatedAt: new Date().toISOString(),
type: firstUser ? "admin" : "regular",
name,
};
} else if (name === undefined) {
user = {
id: await nextUserId(),
updatedAt: new Date().toISOString(),
type: "anonymous",
};
} else {
throw createError({
status: 400,
message: "Invalid name",
});
}
if (user.type !== "anonymous") {
if (!session?.authenticationProvider) {
throw createError({
statusCode: 409,
statusMessage: "Conflict",
message: "User account need an authentication method associated with it.",
});
}
const authMethods = await readAuthenticationMethods();
const method = authMethods.find(method => (
method.provider === session.authenticationProvider
&& method.slug === session.authenticationSlug
));
if (method) {
throw createError({
statusCode: 409,
statusMessage: "Conflict",
message: "A user is already associated with the authentication method",
});
}
authMethods.push({
id: await nextAuthenticationMethodId(),
userId: user.id,
provider: session.authenticationProvider,
slug: session.authenticationSlug!,
name: session.authenticationName!,
})
await writeAuthenticationMethods(authMethods);
}
users.push(user);
await writeUsers(users);
await broadcastEvent({
type: "user-update",
data: user,
});
const newSession = await setServerSession(event, user);
return await serverSessionToApi(event, newSession);
})