basic register
This commit is contained in:
21
login.html
21
login.html
@@ -3,17 +3,24 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>LOGIN</h1>
|
||||
|
||||
<p>
|
||||
<a href="/">Game</a>
|
||||
<div id="login">
|
||||
</p>
|
||||
|
||||
<form id="login">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" name="email" id="email" /><br />
|
||||
<input required type="email" name="email" id="email" />
|
||||
(required)<br />
|
||||
<label for="password">Password</label>
|
||||
<input type="password" name="password" id="password" /><br />
|
||||
<button id="login-button">Login</button>
|
||||
</div>
|
||||
<div>
|
||||
<input required type="password" name="password" id="password" />
|
||||
(required)<br />
|
||||
<button type="submit" id="login-button">Login</button>
|
||||
</form>
|
||||
|
||||
<p>
|
||||
<a href="/register">Register?</a>
|
||||
</div>
|
||||
</p>
|
||||
|
||||
<script type="module" src="/src/login.ts"></script>
|
||||
</body>
|
||||
|
||||
@@ -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")
|
||||
);
|
||||
@@ -10,6 +10,6 @@ datasource db {
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
name String?
|
||||
password String
|
||||
first_login Boolean
|
||||
}
|
||||
|
||||
@@ -3,18 +3,31 @@
|
||||
<html>
|
||||
<body>
|
||||
<h1>REGISTER</h1>
|
||||
<a href="/">Game</a>
|
||||
<div id="login">
|
||||
<label for="email">Email</label>
|
||||
<input type="email" name="user" id="email" /><br />
|
||||
<label for="password">Password</label>
|
||||
<input type="password" name="password" id="password" /><br />
|
||||
<button id="login-button">Register</button>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/login">Login?</a>
|
||||
</div>
|
||||
|
||||
<script type="module" src="/src/login.ts"></script>
|
||||
<p>
|
||||
<a href="/">Game</a>
|
||||
</p>
|
||||
|
||||
<form id="register">
|
||||
<label for="email">Email</label>
|
||||
<input required type="email" name="user" id="email" />
|
||||
(required)<br />
|
||||
<label for="password">Password</label>
|
||||
<input
|
||||
required
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
pattern=".{8,}"
|
||||
/>
|
||||
(required, min 8 chars)<br />
|
||||
<button type="submit" id="login-button">Register</button>
|
||||
</form>
|
||||
|
||||
<p>
|
||||
<a href="/login">Login?</a>
|
||||
</p>
|
||||
|
||||
<script type="module" src="/src/register.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
108
server.ts
108
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<string> = [];
|
||||
|
||||
// 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!");
|
||||
},
|
||||
|
||||
11
src/auth/messages.ts
Normal file
11
src/auth/messages.ts
Normal file
@@ -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",
|
||||
};
|
||||
17
src/login.ts
17
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);
|
||||
});
|
||||
|
||||
25
src/register.ts
Normal file
25
src/register.ts
Normal file
@@ -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());
|
||||
});
|
||||
@@ -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;
|
||||
|
||||
@@ -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<string> | undefined;
|
||||
}
|
||||
|
||||
4
src/utilities/email.ts
Normal file
4
src/utilities/email.ts
Normal file
@@ -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);
|
||||
};
|
||||
13
src/utilities/password.ts
Normal file
13
src/utilities/password.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const hashPassword = async (password: string): Promise<string> => {
|
||||
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;
|
||||
};
|
||||
Reference in New Issue
Block a user