From 4b93f0c7f724e96667245bad8cd0658101fbdec6 Mon Sep 17 00:00:00 2001
From: Matteo Rosati
Date: Mon, 26 Jan 2026 00:36:05 +0100
Subject: [PATCH] basic register
---
login.html | 23 ++--
.../migration.sql | 3 +-
prisma/schema.prisma | 8 +-
register.html | 37 ++++--
server.ts | 108 ++++++++++++++++--
src/auth/messages.ts | 11 ++
src/login.ts | 17 ++-
src/register.ts | 25 ++++
src/services/database-service.ts | 2 +-
src/types/types.ts | 10 ++
src/utilities/email.ts | 4 +
src/utilities/password.ts | 13 +++
12 files changed, 217 insertions(+), 44 deletions(-)
rename prisma/migrations/{20260125085125_init => 20260125230748_init}/migration.sql (76%)
create mode 100644 src/auth/messages.ts
create mode 100644 src/register.ts
create mode 100644 src/utilities/email.ts
create mode 100644 src/utilities/password.ts
diff --git a/login.html b/login.html
index ff3d510..039b7ed 100644
--- a/login.html
+++ b/login.html
@@ -3,17 +3,24 @@
LOGIN
- Game
-
-
+
diff --git a/prisma/migrations/20260125085125_init/migration.sql b/prisma/migrations/20260125230748_init/migration.sql
similarity index 76%
rename from prisma/migrations/20260125085125_init/migration.sql
rename to prisma/migrations/20260125230748_init/migration.sql
index b6a8924..ed6acf8 100644
--- a/prisma/migrations/20260125085125_init/migration.sql
+++ b/prisma/migrations/20260125230748_init/migration.sql
@@ -2,7 +2,8 @@
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"email" TEXT NOT NULL,
- "name" TEXT,
+ "password" TEXT NOT NULL,
+ "first_login" BOOLEAN NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 44bd9a8..8b92553 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -8,8 +8,8 @@ datasource db {
}
model User {
- id Int @id @default(autoincrement())
- email String @unique
- name String?
- password String
+ id Int @id @default(autoincrement())
+ email String @unique
+ password String
+ first_login Boolean
}
diff --git a/register.html b/register.html
index 7a595bc..882a243 100644
--- a/register.html
+++ b/register.html
@@ -3,18 +3,31 @@
REGISTER
- Game
-
-
-
-
-
-
-
-
-
+
+ Game
+
+
+
+
+
+ Login?
+
+
+
diff --git a/server.ts b/server.ts
index 1885679..6001e51 100644
--- a/server.ts
+++ b/server.ts
@@ -1,31 +1,115 @@
import { Hono } from "hono";
+import { cors } from "hono/cors";
import { upgradeWebSocket, websocket } from "hono/bun";
import { DatabaseService } from "@/services/database-service";
+import { RegisterRequest, RegisterResponse } from "@/types/types";
+import { MESSAGES } from "@/auth/messages";
+import { validateEmail } from "@/utilities/email";
+import { Prisma } from "@/orm/generated/prisma/client";
+import { hashPassword } from "@/utilities/password";
const app = new Hono();
+app.use(
+ "/api/v1/*",
+ cors({
+ origin: "*",
+ allowHeaders: ["X-Custom-Header", "Upgrade-Insecure-Requests"],
+ allowMethods: ["POST", "GET", "OPTIONS"],
+ exposeHeaders: ["Content-Length", "X-Kuma-Revision"],
+ maxAge: 600,
+ credentials: true,
+ }),
+);
+
app.get("/", async (c) => {
- const database = new DatabaseService();
- await database.getClient().user.create({
- data: {
- email: "rosati5.matteo@gmail.com",
- name: "Matteo",
- },
- });
-
- const users = await database.getClient().user.findMany();
-
return c.json({
message: "ok",
- users: users,
});
});
+app.post("/api/v1/register", async (c) => {
+ let body: RegisterRequest | undefined;
+ let errors = false;
+ let messages: Array = [];
+
+ // Get the request body and handle malformed payload
+ try {
+ body = (await c.req.json()) as RegisterRequest;
+ } catch (error) {
+ console.error(`Received invalid payload: ${error}`);
+ return c.json({
+ status: "error",
+ messages: [MESSAGES.INVALID_REQUEST],
+ } as RegisterResponse);
+ }
+
+ // //////////////////
+ // Request validation
+ if (!body.email) {
+ errors = true;
+ messages.push(MESSAGES.MISSING_EMAIL);
+ }
+
+ if (!validateEmail(body.email)) {
+ errors = true;
+ messages.push(MESSAGES.INVALID_EMAIL);
+ }
+
+ if (!body.password) {
+ errors = true;
+ messages.push(MESSAGES.MISSING_PASSWORD);
+ }
+ // End: Request validation
+ // ///////////////////////
+
+ if (errors) {
+ return c.json({
+ status: "error",
+ messages: messages,
+ } as RegisterResponse);
+ }
+
+ // Database
+ const database = new DatabaseService();
+
+ try {
+ // Sala la password
+ body.password = await hashPassword(body.password);
+
+ await database.getClient().user.create({
+ data: {
+ ...body,
+ first_login: true,
+ },
+ });
+ } catch (e) {
+ if (
+ e instanceof Prisma.PrismaClientKnownRequestError &&
+ e.code === "P2002"
+ ) {
+ return c.json({
+ status: "error",
+ messages: [MESSAGES.USER_ALREADY_EXISTS],
+ } as RegisterResponse);
+ }
+
+ return c.json({
+ status: "error",
+ messages: [MESSAGES.UNKNOWN_DATABASE_ERROR],
+ } as RegisterResponse);
+ }
+
+ return c.json({
+ status: "success",
+ } as RegisterResponse);
+});
+
app.get(
"/ws",
upgradeWebSocket((c) => {
return {
- onOpen(event, ws) {
+ onOpen(e, ws) {
console.log("Server: Connection opened");
ws.send("Hello!");
},
diff --git a/src/auth/messages.ts b/src/auth/messages.ts
new file mode 100644
index 0000000..39f58e0
--- /dev/null
+++ b/src/auth/messages.ts
@@ -0,0 +1,11 @@
+export const MESSAGES = {
+ MISSING_EMAIL: "The e-mail address is missing",
+ INVALID_EMAIL: "The e-mail address is invalid",
+ MISSING_PASSWORD: "The password is missing",
+ WRONG_PASSWORD: "Wrong password",
+ USER_NOT_FOUND: "User not found",
+ USER_CREATED: "The user has been created",
+ USER_ALREADY_EXISTS: "This user already exists",
+ INVALID_REQUEST: "Invalid request",
+ UNKNOWN_DATABASE_ERROR: "Il database ha dato un errore sconosciuto",
+};
diff --git a/src/login.ts b/src/login.ts
index 4fcd0fb..08e8a24 100644
--- a/src/login.ts
+++ b/src/login.ts
@@ -1,14 +1,19 @@
// STYLES
-// import "modern-normalize/modern-normalize.css";
-// import "@fontsource-variable/jetbrains-mono";
+import "modern-normalize/modern-normalize.css";
+import "@fontsource-variable/jetbrains-mono";
import "@/main.css";
-// import "@maptiler/sdk/dist/maptiler-sdk.css";
// LIBRARIES
-// import $ from "jquery";
+import $ from "jquery";
// import { FilterSpecification, Map, config } from "@maptiler/sdk";
// import { createIcons, Locate, LocateFixed } from "lucide";
-// import area from "@turf/area";
-// import { polygon } from "@turf/helpers";
console.log("login");
+
+$("#login").on("submit", (e) => {
+ e.preventDefault();
+ const email = $("#email").val();
+ const password = $("#password").val();
+
+ console.log(email, password);
+});
diff --git a/src/register.ts b/src/register.ts
new file mode 100644
index 0000000..06e7d97
--- /dev/null
+++ b/src/register.ts
@@ -0,0 +1,25 @@
+// STYLES
+import "modern-normalize/modern-normalize.css";
+import "@fontsource-variable/jetbrains-mono";
+import "@/main.css";
+
+// LIBRARIES
+import $ from "jquery";
+
+const API_SERVER = import.meta.env.VITE_API_SERVER!;
+
+$("#register").on("submit", async (e) => {
+ e.preventDefault();
+ const email = $("#email");
+ const password = $("#password");
+
+ const response = await fetch(`${API_SERVER}/api/v1/register`, {
+ method: "POST",
+ body: JSON.stringify({
+ email: email.val(),
+ password: password.val(),
+ }),
+ });
+
+ console.log(await response.json());
+});
diff --git a/src/services/database-service.ts b/src/services/database-service.ts
index af763d8..69ca7ee 100644
--- a/src/services/database-service.ts
+++ b/src/services/database-service.ts
@@ -1,5 +1,5 @@
import { PrismaPg } from "@prisma/adapter-pg";
-import { PrismaClient } from "@/orm/generated/prisma";
+import { PrismaClient } from "@/orm/generated/prisma/client";
export class DatabaseService {
private prisma: PrismaClient;
diff --git a/src/types/types.ts b/src/types/types.ts
index 1b99c22..f7a407a 100644
--- a/src/types/types.ts
+++ b/src/types/types.ts
@@ -92,3 +92,13 @@ export interface SelectedFeature {
id: number;
area: number;
}
+
+export interface RegisterRequest {
+ email: string;
+ password: string;
+}
+
+export interface RegisterResponse {
+ status: "success" | "error";
+ messages: Array | undefined;
+}
diff --git a/src/utilities/email.ts b/src/utilities/email.ts
new file mode 100644
index 0000000..3b3f375
--- /dev/null
+++ b/src/utilities/email.ts
@@ -0,0 +1,4 @@
+export const validateEmail = (email: string): boolean => {
+ const emailRegex: RegExp = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
+ return emailRegex.test(email);
+};
diff --git a/src/utilities/password.ts b/src/utilities/password.ts
new file mode 100644
index 0000000..753e5ad
--- /dev/null
+++ b/src/utilities/password.ts
@@ -0,0 +1,13 @@
+export const hashPassword = async (password: string): Promise => {
+ const PASSWORD_SALT = Bun.env.PASSWORD_SALT!;
+ const saltedPassword = PASSWORD_SALT + password;
+ const encoder = new TextEncoder();
+ const data = encoder.encode(saltedPassword);
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
+ const hashHex = hashArray
+ .map((b) => b.toString(16).padStart(2, "0"))
+ .join("");
+
+ return hashHex;
+};