refactor(lst): register added in
This commit is contained in:
@@ -6,7 +6,8 @@ import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
//routes
|
||||
import auth from "./services/auth/authService";
|
||||
import scalar from "./route/scalar";
|
||||
import scalar from "./services/general/route/scalar";
|
||||
import apiHits from "./services/general/route/apitHits";
|
||||
// services
|
||||
import {ocmeService} from "./services/ocme/ocmeServer";
|
||||
|
||||
@@ -38,10 +39,10 @@ app.all("/ocme/*", async (c) => {
|
||||
return ocmeService(c);
|
||||
});
|
||||
|
||||
const routes = [scalar, auth] as const;
|
||||
const routes = [scalar, auth, apiHits] as const;
|
||||
|
||||
routes.forEach((route) => {
|
||||
app.route("/", route);
|
||||
app.route("/api/", route);
|
||||
});
|
||||
|
||||
//app.basePath("/api/auth").route("/login", login).route("/session", session).route("/register", register);
|
||||
|
||||
39
server/src/globalUtils/apitHits.ts
Normal file
39
server/src/globalUtils/apitHits.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import {z, ZodError} from "zod";
|
||||
import {Context} from "hono";
|
||||
// Define the request body schema
|
||||
const requestSchema = z.object({
|
||||
ip: z.string().optional(),
|
||||
endpoint: z.string(),
|
||||
action: z.string().optional(),
|
||||
stats: z.string().optional(),
|
||||
});
|
||||
|
||||
type ApiHitData = z.infer<typeof requestSchema>;
|
||||
|
||||
export const apiHit = async (
|
||||
c: Context,
|
||||
data: unknown
|
||||
): Promise<{success: boolean; data?: ApiHitData; errors?: any[]}> => {
|
||||
// console.log(data);
|
||||
try {
|
||||
// Extract IP from request headers or connection info
|
||||
const forwarded = c.req.header("host");
|
||||
|
||||
//console.log(forwarded);
|
||||
// Validate the data
|
||||
const validatedData = requestSchema.parse(data);
|
||||
|
||||
// Proceed with the validated data
|
||||
// console.log("Validated Data:", validatedData);
|
||||
return {success: true, data: validatedData};
|
||||
} catch (error) {
|
||||
// Explicitly check if the error is an instance of ZodError
|
||||
if (error instanceof ZodError) {
|
||||
// console.log({success: false, errors: error.errors});
|
||||
return {success: false, errors: error.errors};
|
||||
}
|
||||
|
||||
// Catch other unexpected errors
|
||||
return {success: false, errors: [{message: "An unknown error occurred"}]};
|
||||
}
|
||||
};
|
||||
@@ -5,8 +5,8 @@ import register from "./routes/register";
|
||||
import session from "./routes/session";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
app.route("api/auth/login", login);
|
||||
app.route("api/auth//register", register);
|
||||
app.route("api/auth/session", session);
|
||||
app.route("auth/login", login);
|
||||
app.route("auth/register", register);
|
||||
app.route("auth/session", session);
|
||||
|
||||
export default app;
|
||||
|
||||
@@ -5,38 +5,38 @@ const app = new OpenAPIHono();
|
||||
|
||||
const UserSchema = z
|
||||
.object({
|
||||
username: z.string().min(3).openapi({example: "smith002"}),
|
||||
username: z.string().optional().openapi({example: "smith002"}),
|
||||
//email: z.string().optional().openapi({example: "s.smith@example.com"}),
|
||||
password: z.string().openapi({example: "password123"}),
|
||||
})
|
||||
.openapi("User");
|
||||
|
||||
// Define the response schema for the login endpoint
|
||||
const LoginResponseSchema = z
|
||||
.object({
|
||||
message: z.string().openapi({example: "Login successful"}),
|
||||
user: z.object({
|
||||
username: z.string().openapi({example: "smith002"}),
|
||||
// Add other user fields as needed
|
||||
}),
|
||||
})
|
||||
.openapi("LoginResponse");
|
||||
|
||||
const route = createRoute({
|
||||
tags: ["Auth"],
|
||||
summary: "Login as user",
|
||||
description: "Login as a user to get a JWT token",
|
||||
method: "post",
|
||||
path: "/",
|
||||
request: {body: {content: {"application/json": {schema: UserSchema}}}},
|
||||
request: {
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {schema: UserSchema},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: LoginResponseSchema,
|
||||
schema: z.object({
|
||||
success: z.boolean().openapi({example: true}),
|
||||
message: z.string().openapi({example: "Logged in"}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Login successful",
|
||||
description: "Response message",
|
||||
},
|
||||
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
@@ -52,37 +52,38 @@ const route = createRoute({
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
message: z.string().openapi({example: "Invalid credentials"}),
|
||||
success: z.boolean().openapi({example: false}),
|
||||
message: z.string().openapi({example: "Username and password required"}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Unauthorized",
|
||||
description: "Bad request",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
app.openapi(route, async (c) => {
|
||||
let body: {username: string; password: string};
|
||||
const {username, password, email} = await c.req.json();
|
||||
|
||||
console.log(`Trying to login`);
|
||||
try {
|
||||
body = await c.req.json();
|
||||
} catch (error) {
|
||||
return c.json({success: false, message: "Username and password required"}, 400);
|
||||
if (!username || !password || !email) {
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
message: "Username and password are required",
|
||||
},
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
if (!body?.username || !body?.password) {
|
||||
return c.json({success: false, message: "Username and password required"}, 400);
|
||||
}
|
||||
try {
|
||||
const {token, user} = login(body.username, body.password);
|
||||
const {token, user} = login(username.toLowerCase(), password);
|
||||
|
||||
// Set the JWT as an HTTP-only cookie
|
||||
// c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Path=/; SameSite=None; Max-Age=3600`);
|
||||
//c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
|
||||
|
||||
return c.json({message: "Login successful", data: {token, user}});
|
||||
return c.json({success: true, message: "Login successful", user, token}, 200);
|
||||
} catch (err) {
|
||||
return c.json({message: err instanceof Error ? err.message : "Invalid credentials"}, 401);
|
||||
return c.json({success: false, message: "Incorrect Credentials"}, 401);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,14 +1,31 @@
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {db} from "../../../../database/dbClient";
|
||||
import {users} from "../../../../database/schema/users";
|
||||
import {apiHit} from "../../../globalUtils/apitHits";
|
||||
import {createPassword} from "../utils/createPassword";
|
||||
import {eq} from "drizzle-orm";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
const UserSchema = z
|
||||
.object({
|
||||
id: z.string().openapi({example: "123"}),
|
||||
name: z.string().min(3).openapi({example: "John Doe"}),
|
||||
age: z.number().openapi({example: 42}),
|
||||
})
|
||||
.openapi("User");
|
||||
const UserSchema = z.object({
|
||||
username: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9_]{3,30}$/)
|
||||
.openapi({example: "smith034"}),
|
||||
email: z.string().email().openapi({example: "smith@example.com"}),
|
||||
password: z
|
||||
.string()
|
||||
.min(6, {message: "Passwords must be longer than 3 characters"})
|
||||
.regex(/[A-Z]/, {message: "Password must contain at least one uppercase letter"})
|
||||
.regex(/[\W_]/, {message: "Password must contain at least one special character"})
|
||||
.openapi({example: "Password1!"}),
|
||||
});
|
||||
|
||||
type User = z.infer<typeof UserSchema>;
|
||||
|
||||
const responseSchema = z.object({
|
||||
message: z.string().optional().openapi({example: "User Created"}),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
@@ -16,17 +33,88 @@ app.openapi(
|
||||
summary: "Register a new user",
|
||||
method: "post",
|
||||
path: "/",
|
||||
request: {params: UserSchema},
|
||||
request: {
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {schema: UserSchema},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {"application/json": {schema: UserSchema}},
|
||||
content: {"application/json": {schema: responseSchema}},
|
||||
description: "Retrieve the user",
|
||||
},
|
||||
400: {
|
||||
content: {
|
||||
"application/json": {
|
||||
schema: z.object({
|
||||
success: z.boolean().openapi({example: false}),
|
||||
message: z.string().openapi({example: "Invalid credentials passed"}),
|
||||
}),
|
||||
},
|
||||
},
|
||||
description: "Retrieve the user",
|
||||
},
|
||||
},
|
||||
}),
|
||||
(c) => {
|
||||
const {id} = c.req.valid("param");
|
||||
return c.json({id, age: 20, name: "Ultra-man"});
|
||||
async (c) => {
|
||||
// apit hit
|
||||
apiHit(c, {endpoint: "api/auth/register"});
|
||||
let {username, email, password} = await c.req.json();
|
||||
|
||||
if (!username || !email || !password) {
|
||||
return c.json({success: false, message: "Credentials missing"}, 400);
|
||||
}
|
||||
|
||||
// some usernames that should be ignored
|
||||
const badActors = ["admin", "root"];
|
||||
if (badActors.includes(username)) {
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
message: `${username} is not a valid name to be registerd please try again`,
|
||||
},
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
// make sure the user dose not already exist in the system
|
||||
const userCheck = await db.select().from(users).where(eq(users.username, username));
|
||||
|
||||
if (userCheck.length === 1) {
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
|
||||
},
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
// make sure we only send over a username that is all lowercase
|
||||
username = username.toLowerCase();
|
||||
|
||||
// get the good kinda password
|
||||
password = await createPassword(password);
|
||||
|
||||
try {
|
||||
const user = await db
|
||||
.insert(users)
|
||||
.values({username, email, password})
|
||||
.returning({user: users.username, email: users.email});
|
||||
|
||||
return c.json({message: "User Registered", user}, 200);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return c.json(
|
||||
{
|
||||
success: false,
|
||||
message: `${username} already exists please login or reset password, if you feel this is an error please contact your admin.`,
|
||||
},
|
||||
400
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import bcrypt from "bcrypt";
|
||||
|
||||
export const passwordUpdate = (password: string) => {
|
||||
export const createPassword = async (password: string) => {
|
||||
// encypt password
|
||||
let pass: string = process.env.SECRET;
|
||||
let salt: string = process.env.SALTING;
|
||||
let pass: string | undefined = process.env.SECRET;
|
||||
let salt: string | undefined = process.env.SALTING;
|
||||
|
||||
if (!pass || !salt) {
|
||||
pass = "error";
|
||||
} else {
|
||||
pass = bcrypt.hashSync(process.env.SECRET + password, parseInt(process.env.SALTING));
|
||||
pass = bcrypt.hashSync(process.env.SECRET + password, parseInt(salt));
|
||||
|
||||
pass = btoa(pass);
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import {OpenAPIHono} from "@hono/zod-openapi";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
// the doc endpoint
|
||||
app.doc("/api", {
|
||||
app.doc("/", {
|
||||
openapi: "3.0.0",
|
||||
info: {
|
||||
version: "1.0.0",
|
||||
53
server/src/services/general/route/apitHits.ts
Normal file
53
server/src/services/general/route/apitHits.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi";
|
||||
import {apiHit} from "../../../globalUtils/apitHits";
|
||||
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
// Define the request body schema
|
||||
const requestSchema = z.object({
|
||||
ip: z.string().optional(),
|
||||
endpoint: z.string().optional(),
|
||||
action: z.string().optional(),
|
||||
stats: z.string().optional(),
|
||||
});
|
||||
|
||||
// Define the response schema
|
||||
const responseSchema = z.object({
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
app.openapi(
|
||||
createRoute({
|
||||
tags: ["api"],
|
||||
summary: "Tracks the API posts and how often",
|
||||
method: "post",
|
||||
path: "/hits",
|
||||
request: {
|
||||
body: {
|
||||
content: {
|
||||
"application/json": {schema: requestSchema},
|
||||
},
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
200: {
|
||||
content: {
|
||||
"application/json": {schema: responseSchema},
|
||||
},
|
||||
description: "Response message",
|
||||
},
|
||||
},
|
||||
}),
|
||||
async (c) => {
|
||||
const data = await c.req.json();
|
||||
|
||||
apiHit(data);
|
||||
|
||||
// Return response with the received data
|
||||
return c.json({
|
||||
message: `Received name: ${data.name}, arrayData: ${data.arrayData}`,
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
export default app;
|
||||
@@ -4,7 +4,7 @@ import {apiReference} from "@scalar/hono-api-reference";
|
||||
const app = new OpenAPIHono();
|
||||
|
||||
app.get(
|
||||
"/api/docs",
|
||||
"/docs",
|
||||
apiReference({
|
||||
theme: "kepler",
|
||||
layout: "classic",
|
||||
@@ -56,7 +56,7 @@ app.get(
|
||||
description: "Production",
|
||||
},
|
||||
{
|
||||
url: "http://localhost:4000",
|
||||
url: "http://localhost:3000",
|
||||
description: "dev server",
|
||||
},
|
||||
],
|
||||
Reference in New Issue
Block a user