aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/routes/auth.test.ts106
-rw-r--r--src/server/routes/auth.ts23
-rw-r--r--src/server/scripts/add-user.ts48
3 files changed, 49 insertions, 128 deletions
diff --git a/src/server/routes/auth.test.ts b/src/server/routes/auth.test.ts
index 3ba504e..5bf9f86 100644
--- a/src/server/routes/auth.test.ts
+++ b/src/server/routes/auth.test.ts
@@ -3,7 +3,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
import { errorHandler } from "../middleware/index.js";
import type {
RefreshTokenRepository,
- UserPublic,
UserRepository,
} from "../repositories/index.js";
import { createAuthRouter } from "./auth.js";
@@ -32,18 +31,6 @@ function createMockRefreshTokenRepo(): RefreshTokenRepository {
};
}
-interface RegisterResponse {
- user?: {
- id: string;
- username: string;
- createdAt: string;
- };
- error?: {
- code: string;
- message: string;
- };
-}
-
interface LoginResponse {
accessToken?: string;
refreshToken?: string;
@@ -57,99 +44,6 @@ interface LoginResponse {
};
}
-describe("POST /register", () => {
- let app: Hono;
- let mockUserRepo: ReturnType<typeof createMockUserRepo>;
- let mockRefreshTokenRepo: ReturnType<typeof createMockRefreshTokenRepo>;
-
- beforeEach(() => {
- vi.clearAllMocks();
- mockUserRepo = createMockUserRepo();
- mockRefreshTokenRepo = createMockRefreshTokenRepo();
- const auth = createAuthRouter({
- userRepo: mockUserRepo,
- refreshTokenRepo: mockRefreshTokenRepo,
- });
- app = new Hono();
- app.onError(errorHandler);
- app.route("/api/auth", auth);
- });
-
- it("creates a new user with valid credentials", async () => {
- vi.mocked(mockUserRepo.existsByUsername).mockResolvedValue(false);
- vi.mocked(mockUserRepo.create).mockResolvedValue({
- id: "test-uuid-123",
- username: "testuser",
- createdAt: new Date("2024-01-01T00:00:00Z"),
- } as UserPublic);
-
- const res = await app.request("/api/auth/register", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- username: "testuser",
- password: "securepassword12345",
- }),
- });
-
- expect(res.status).toBe(201);
- const body = (await res.json()) as RegisterResponse;
- expect(body.user).toEqual({
- id: "test-uuid-123",
- username: "testuser",
- createdAt: "2024-01-01T00:00:00.000Z",
- });
- expect(mockUserRepo.existsByUsername).toHaveBeenCalledWith("testuser");
- expect(mockUserRepo.create).toHaveBeenCalledWith({
- username: "testuser",
- passwordHash: "hashed_securepassword12345",
- });
- });
-
- it("returns 400 for invalid username", async () => {
- const res = await app.request("/api/auth/register", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- username: "",
- password: "securepassword12345",
- }),
- });
-
- expect(res.status).toBe(400);
- });
-
- it("returns 400 for password too short", async () => {
- const res = await app.request("/api/auth/register", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- username: "testuser",
- password: "tooshort123456",
- }),
- });
-
- expect(res.status).toBe(400);
- });
-
- it("returns 409 for existing username", async () => {
- vi.mocked(mockUserRepo.existsByUsername).mockResolvedValue(true);
-
- const res = await app.request("/api/auth/register", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- username: "existinguser",
- password: "securepassword12345",
- }),
- });
-
- expect(res.status).toBe(409);
- const body = (await res.json()) as RegisterResponse;
- expect(body.error?.code).toBe("USERNAME_EXISTS");
- });
-});
-
describe("POST /login", () => {
let app: Hono;
let mockUserRepo: ReturnType<typeof createMockUserRepo>;
diff --git a/src/server/routes/auth.ts b/src/server/routes/auth.ts
index 144bbae..06c88a6 100644
--- a/src/server/routes/auth.ts
+++ b/src/server/routes/auth.ts
@@ -10,11 +10,7 @@ import {
type UserRepository,
userRepository,
} from "../repositories/index.js";
-import {
- createUserSchema,
- loginSchema,
- refreshTokenSchema,
-} from "../schemas/index.js";
+import { loginSchema, refreshTokenSchema } from "../schemas/index.js";
function getJwtSecret(): string {
const secret = process.env.JWT_SECRET;
@@ -43,23 +39,6 @@ export function createAuthRouter(deps: AuthDependencies) {
const { userRepo, refreshTokenRepo } = deps;
return new Hono()
- .post("/register", zValidator("json", createUserSchema), async (c) => {
- const { username, password } = c.req.valid("json");
-
- // Check if username already exists
- const exists = await userRepo.existsByUsername(username);
- if (exists) {
- throw Errors.conflict("Username already exists", "USERNAME_EXISTS");
- }
-
- // Hash password with Argon2
- const passwordHash = await argon2.hash(password);
-
- // Create user
- const newUser = await userRepo.create({ username, passwordHash });
-
- return c.json({ user: newUser }, 201);
- })
.post("/login", zValidator("json", loginSchema), async (c) => {
const { username, password } = c.req.valid("json");
diff --git a/src/server/scripts/add-user.ts b/src/server/scripts/add-user.ts
new file mode 100644
index 0000000..5fcccac
--- /dev/null
+++ b/src/server/scripts/add-user.ts
@@ -0,0 +1,48 @@
+import * as readline from "node:readline/promises";
+import * as argon2 from "argon2";
+import { userRepository } from "../repositories/index.js";
+
+async function main() {
+ const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
+
+ const username = await rl.question("Username: ");
+ const password = await rl.question("Password: ");
+ rl.close();
+
+ if (!username || !password) {
+ console.error("Error: Username and password are required");
+ process.exit(1);
+ }
+
+ if (password.length < 8) {
+ console.error("Error: Password must be at least 8 characters");
+ process.exit(1);
+ }
+
+ // Check if username already exists
+ const exists = await userRepository.existsByUsername(username);
+ if (exists) {
+ console.error(`Error: Username "${username}" already exists`);
+ process.exit(1);
+ }
+
+ // Hash password with Argon2
+ const passwordHash = await argon2.hash(password);
+
+ // Create user
+ const newUser = await userRepository.create({ username, passwordHash });
+
+ console.log(`User created successfully:`);
+ console.log(` ID: ${newUser.id}`);
+ console.log(` Username: ${newUser.username}`);
+
+ process.exit(0);
+}
+
+main().catch((error) => {
+ console.error("Error:", error.message);
+ process.exit(1);
+});