intial setting and auth intergrated
This commit is contained in:
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -60,7 +60,8 @@
|
|||||||
"opendock",
|
"opendock",
|
||||||
"opendocks",
|
"opendocks",
|
||||||
"ppoo",
|
"ppoo",
|
||||||
"prodlabels"
|
"prodlabels",
|
||||||
|
"trycatch"
|
||||||
],
|
],
|
||||||
"gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db",
|
"gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db",
|
||||||
"gitea.instanceURL": "https://git.tuffraid.net",
|
"gitea.instanceURL": "https://git.tuffraid.net",
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ const signin = z.union([
|
|||||||
const r = Router();
|
const r = Router();
|
||||||
|
|
||||||
r.post("/", async (req, res) => {
|
r.post("/", async (req, res) => {
|
||||||
let login: unknown;
|
let login: unknown | any;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const validated = signin.parse(req.body);
|
const validated = signin.parse(req.body);
|
||||||
if ("email" in validated) {
|
if ("email" in validated) {
|
||||||
@@ -92,6 +93,15 @@ r.post("/", async (req, res) => {
|
|||||||
password: validated.password,
|
password: validated.password,
|
||||||
},
|
},
|
||||||
headers: fromNodeHeaders(req.headers),
|
headers: fromNodeHeaders(req.headers),
|
||||||
|
asResponse: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
login.headers.forEach((value: string, key: string) => {
|
||||||
|
if (key.toLowerCase() === "set-cookie") {
|
||||||
|
res.append("set-cookie", value);
|
||||||
|
} else {
|
||||||
|
res.setHeader(key, value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,27 +2,55 @@ import { fromNodeHeaders } from "better-auth/node";
|
|||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Request, Response } from "express";
|
||||||
import { auth } from "../utils/auth.utils.js";
|
import { auth } from "../utils/auth.utils.js";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace Express {
|
||||||
|
interface Request {
|
||||||
|
user?: {
|
||||||
|
id: string;
|
||||||
|
email?: string;
|
||||||
|
roles?: string | null | undefined; //Record<string, string[]>;
|
||||||
|
username?: string | null | undefined;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function toWebHeaders(nodeHeaders: Request["headers"]): Headers {
|
||||||
|
// const h = new Headers();
|
||||||
|
// for (const [key, value] of Object.entries(nodeHeaders)) {
|
||||||
|
// if (Array.isArray(value)) {
|
||||||
|
// value.forEach((v) => h.append(key, v));
|
||||||
|
// } else if (value !== undefined) {
|
||||||
|
// h.set(key, value);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return h;
|
||||||
|
// }
|
||||||
|
|
||||||
export const requireAuth = async (
|
export const requireAuth = async (
|
||||||
req: Request,
|
req: Request,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction,
|
next: NextFunction,
|
||||||
) => {
|
) => {
|
||||||
// TODO: add the real auth stuff in later.
|
|
||||||
try {
|
try {
|
||||||
const session = await auth.api.getSession({
|
const session = await auth.api.getSession({
|
||||||
headers: fromNodeHeaders(req.headers),
|
headers: fromNodeHeaders(req.headers),
|
||||||
|
//query: { disableCookieCache: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!session) {
|
if (!session) {
|
||||||
//return res.status(401).json({ error: "Unauthorized" });
|
return res.status(401).json({ error: "Unauthorized" });
|
||||||
console.info("not auth of course");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach session to request for later use
|
//console.log(session);
|
||||||
(req as any).session = session;
|
|
||||||
console.info(
|
req.user = {
|
||||||
"Just passing the middleware and reminder that we need to add the real stuff in.",
|
id: session.user.id,
|
||||||
);
|
email: session.user.email,
|
||||||
|
roles: session.user.role,
|
||||||
|
username: session.user.username,
|
||||||
|
};
|
||||||
|
|
||||||
next();
|
next();
|
||||||
} catch {
|
} catch {
|
||||||
return res.status(401).json({ error: "Unauthorized" });
|
return res.status(401).json({ error: "Unauthorized" });
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export const prodQuery = async (queryToRun: string, name: string) => {
|
|||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: `Query results for: ${name}`,
|
message: `Query results for: ${name}`,
|
||||||
data: result.recordset,
|
data: result.recordset ?? [],
|
||||||
};
|
};
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
const err = error as SqlError;
|
const err = error as SqlError;
|
||||||
|
|||||||
44
backend/system/settings.route.ts
Normal file
44
backend/system/settings.route.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { type Response, Router } from "express";
|
||||||
|
import { db } from "../db/db.controller.js";
|
||||||
|
import { settings } from "../db/schema/settings.schema.js";
|
||||||
|
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
|
// export const updateSetting = async (setting: Setting) => {
|
||||||
|
// // TODO: when the setting is a feature setting we will need to have it run each kill switch on the crons well just stop them and during a reset it just wont start them
|
||||||
|
// // TODO: when the setting is a system we will need to force an app restart
|
||||||
|
// // TODO: when the setting is standard we don't do anything.
|
||||||
|
// };
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
r.get("/", async (_, res: Response) => {
|
||||||
|
const { data: sName, error: sError } = await tryCatch(
|
||||||
|
db.select().from(settings),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sError) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "system",
|
||||||
|
subModule: "settings",
|
||||||
|
message: `There was an error getting the settings `,
|
||||||
|
data: [sError],
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "system",
|
||||||
|
subModule: "settings",
|
||||||
|
message: `All current settings`,
|
||||||
|
data: sName ?? [],
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
0
backend/system/settingsBase.controller.ts
Normal file
0
backend/system/settingsBase.controller.ts
Normal file
@@ -1,7 +0,0 @@
|
|||||||
import type { Setting } from "../db/schema/settings.schema.js";
|
|
||||||
|
|
||||||
export const updateSetting = async (setting: Setting) => {
|
|
||||||
// TODO: when the setting is a feature setting we will need to have it run each kill switch on the crons well just stop them and during a reset it just wont start them
|
|
||||||
// TODO: when the setting is a system we will need to force an app restart
|
|
||||||
// TODO: when the setting is standard we don't do anything.
|
|
||||||
};
|
|
||||||
93
backend/system/settingsUpdate.route.ts
Normal file
93
backend/system/settingsUpdate.route.ts
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
import { eq, sql } from "drizzle-orm";
|
||||||
|
import { type Request, type Response, Router } from "express";
|
||||||
|
import { db } from "../db/db.controller.js";
|
||||||
|
import { settings } from "../db/schema/settings.schema.js";
|
||||||
|
|
||||||
|
import { apiReturn } from "../utils/returnHelper.utils.js";
|
||||||
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
||||||
|
|
||||||
|
// export const updateSetting = async (setting: Setting) => {
|
||||||
|
// // TODO: when the setting is a feature setting we will need to have it run each kill switch on the crons well just stop them and during a reset it just wont start them
|
||||||
|
// // TODO: when the setting is a system we will need to force an app restart
|
||||||
|
// // TODO: when the setting is standard we don't do anything.
|
||||||
|
// };
|
||||||
|
|
||||||
|
const r = Router();
|
||||||
|
|
||||||
|
r.patch("/:name", async (req: Request, res: Response) => {
|
||||||
|
const { name } = req.params;
|
||||||
|
const updates: Record<string, unknown | null> = {};
|
||||||
|
// lets see if we even have a setting name
|
||||||
|
|
||||||
|
const { data: sName, error: sError } = await tryCatch(
|
||||||
|
db
|
||||||
|
.select()
|
||||||
|
.from(settings)
|
||||||
|
.where(eq(settings.name, name ?? "")),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sError) {
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: false,
|
||||||
|
level: "error",
|
||||||
|
module: "system",
|
||||||
|
subModule: "settings",
|
||||||
|
message: `There was an error checking the name of the setting`,
|
||||||
|
data: [sError],
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (sName?.length === 0) {
|
||||||
|
// return apiReturn(res, {
|
||||||
|
// success: false,
|
||||||
|
// level: "error",
|
||||||
|
// module: "system",
|
||||||
|
// subModule: "settings",
|
||||||
|
// message: `The setting "${name}" dose not appear to be a valid setting please check the name and try again. `,
|
||||||
|
// data: [],
|
||||||
|
// status: 400,
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// manage the actual setting. we will still do an upsert just in case we strangely get past everything
|
||||||
|
|
||||||
|
if (req.body?.value !== undefined) {
|
||||||
|
updates.value = req.body.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.body?.description !== undefined) {
|
||||||
|
updates.description = req.body.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.body?.moduleName !== undefined) {
|
||||||
|
updates.moduleName = req.body.moduleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.body?.active !== undefined) {
|
||||||
|
updates.active = req.body.active === "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.body?.roles !== undefined) {
|
||||||
|
updates.roles = req.body.roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.body?.settingType !== undefined) {
|
||||||
|
updates.settingType = req.body.settingType;
|
||||||
|
}
|
||||||
|
|
||||||
|
updates.upd_user = req.user?.username || "lst_user";
|
||||||
|
updates.upd_date = sql`NOW()`;
|
||||||
|
|
||||||
|
return apiReturn(res, {
|
||||||
|
success: true,
|
||||||
|
level: "info",
|
||||||
|
module: "system",
|
||||||
|
subModule: "settings",
|
||||||
|
message: `Setting "${name}" Was just updated. `,
|
||||||
|
data: [updates],
|
||||||
|
status: 400,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
export default r;
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
|
import { requireAuth } from "backend/middleware/auth.middleware.js";
|
||||||
import type { Express } from "express";
|
import type { Express } from "express";
|
||||||
|
import getSettings from "./settings.route.js";
|
||||||
|
import updSetting from "./settingsUpdate.route.js";
|
||||||
import stats from "./stats.route.js";
|
import stats from "./stats.route.js";
|
||||||
|
|
||||||
export const setupSystemRoutes = (baseUrl: string, app: Express) => {
|
export const setupSystemRoutes = (baseUrl: string, app: Express) => {
|
||||||
//stats will be like this as we dont need to change this
|
//stats will be like this as we dont need to change this
|
||||||
app.use(`${baseUrl}/api/stats`, stats);
|
app.use(`${baseUrl}/api/stats`, stats);
|
||||||
|
app.use(`${baseUrl}/api/settings`, getSettings);
|
||||||
|
app.use(`${baseUrl}/api/settings`, requireAuth, updSetting);
|
||||||
|
|
||||||
// all other system should be under /api/system/*
|
// all other system should be under /api/system/*
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import {
|
|||||||
admin,
|
admin,
|
||||||
apiKey,
|
apiKey,
|
||||||
createAuthMiddleware,
|
createAuthMiddleware,
|
||||||
customSession,
|
//customSession,
|
||||||
jwt,
|
jwt,
|
||||||
lastLoginMethod,
|
lastLoginMethod,
|
||||||
username,
|
username,
|
||||||
} from "better-auth/plugins";
|
} from "better-auth/plugins";
|
||||||
import { eq } from "drizzle-orm";
|
//import { eq } from "drizzle-orm";
|
||||||
import { db } from "../db/db.controller.js";
|
import { db } from "../db/db.controller.js";
|
||||||
import * as rawSchema from "../db/schema/auth.schema.js";
|
import * as rawSchema from "../db/schema/auth.schema.js";
|
||||||
import { allowedOrigins } from "./cors.utils.js";
|
import { allowedOrigins } from "./cors.utils.js";
|
||||||
@@ -31,20 +31,15 @@ export const auth = betterAuth({
|
|||||||
provider: "pg",
|
provider: "pg",
|
||||||
schema,
|
schema,
|
||||||
}),
|
}),
|
||||||
user: {
|
// user: {
|
||||||
additionalFields: {
|
// additionalFields: {
|
||||||
role: {
|
// role: {
|
||||||
type: "string",
|
// type: "string",
|
||||||
required: false,
|
// //required: false,
|
||||||
input: false,
|
// input: false,
|
||||||
},
|
// },
|
||||||
lastLogin: {
|
// },
|
||||||
type: "date",
|
// },
|
||||||
required: true,
|
|
||||||
input: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: [
|
plugins: [
|
||||||
jwt({ jwt: { expirationTime: "1h" } }),
|
jwt({ jwt: { expirationTime: "1h" } }),
|
||||||
apiKey(),
|
apiKey(),
|
||||||
@@ -53,26 +48,27 @@ export const auth = betterAuth({
|
|||||||
username({
|
username({
|
||||||
minUsernameLength: 5,
|
minUsernameLength: 5,
|
||||||
usernameValidator: (username) => {
|
usernameValidator: (username) => {
|
||||||
if (username === "admin") {
|
if (username === "admin" || username === "root") {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
customSession(async ({ user, session }) => {
|
|
||||||
const roles = await db
|
// customSession(async ({ user, session }) => {
|
||||||
.select({ roles: rawSchema.user.role })
|
// const roles = await db
|
||||||
.from(rawSchema.user)
|
// .select({ roles: rawSchema.user.role })
|
||||||
.where(eq(rawSchema.user.id, session.id));
|
// .from(rawSchema.user)
|
||||||
return {
|
// .where(eq(rawSchema.user.id, session.id));
|
||||||
roles,
|
// return {
|
||||||
user: {
|
// roles,
|
||||||
...user,
|
// user: {
|
||||||
//newField: "newField",
|
// ...user,
|
||||||
},
|
// //newField: "newField",
|
||||||
session,
|
// },
|
||||||
};
|
// session,
|
||||||
}),
|
// };
|
||||||
|
// }),
|
||||||
],
|
],
|
||||||
trustedOrigins: allowedOrigins,
|
trustedOrigins: allowedOrigins,
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { Response } from "express";
|
import type { Response } from "express";
|
||||||
import { createLogger } from "../logger/logger.controller.js";
|
import { createLogger } from "../logger/logger.controller.js";
|
||||||
|
|
||||||
interface Data {
|
interface Data<T = unknown[]> {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
module: "system" | "ocp" | "routes" | "datamart" | "utils" | "opendock";
|
module: "system" | "ocp" | "routes" | "datamart" | "utils" | "opendock";
|
||||||
subModule:
|
subModule:
|
||||||
@@ -14,10 +14,11 @@ interface Data {
|
|||||||
| "auth"
|
| "auth"
|
||||||
| "datamart"
|
| "datamart"
|
||||||
| "jobs"
|
| "jobs"
|
||||||
| "apt";
|
| "apt"
|
||||||
|
| "settings";
|
||||||
level: "info" | "error" | "debug" | "fatal";
|
level: "info" | "error" | "debug" | "fatal";
|
||||||
message: string;
|
message: string;
|
||||||
data?: unknown[];
|
data?: T;
|
||||||
notify?: boolean;
|
notify?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
33
brunoApi/auth/Login.bru
Normal file
33
brunoApi/auth/Login.bru
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
meta {
|
||||||
|
name: Login
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
url: {{url}}/lst/api/authentication/login
|
||||||
|
body: json
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
"username": "matthes01",
|
||||||
|
"password": "nova0511"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
script:post-response {
|
||||||
|
// // grab the raw Set-Cookie header
|
||||||
|
// const cookies = res.headers["set-cookie"];
|
||||||
|
|
||||||
|
// const sessionCookie = cookies[0].split(";")[0];
|
||||||
|
|
||||||
|
// // Save it as an environment variable
|
||||||
|
// bru.setEnvVar("session_cookie", sessionCookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
8
brunoApi/auth/folder.bru
Normal file
8
brunoApi/auth/folder.bru
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
meta {
|
||||||
|
name: auth
|
||||||
|
seq: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
auth {
|
||||||
|
mode: inherit
|
||||||
|
}
|
||||||
0
brunoApi/collection.bru
Normal file
0
brunoApi/collection.bru
Normal file
@@ -1,3 +1,4 @@
|
|||||||
vars {
|
vars {
|
||||||
url: http://localhost:3000
|
url: http://localhost:3000
|
||||||
|
~session_cookie:
|
||||||
}
|
}
|
||||||
|
|||||||
16
brunoApi/system/Get Settings.bru
Normal file
16
brunoApi/system/Get Settings.bru
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
meta {
|
||||||
|
name: Get Settings
|
||||||
|
type: http
|
||||||
|
seq: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{url}}/lst/api/settings
|
||||||
|
body: none
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
23
brunoApi/system/updateSetting.bru
Normal file
23
brunoApi/system/updateSetting.bru
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
meta {
|
||||||
|
name: updateSetting
|
||||||
|
type: http
|
||||||
|
seq: 2
|
||||||
|
}
|
||||||
|
|
||||||
|
patch {
|
||||||
|
url: {{url}}/lst/api/settings/something
|
||||||
|
body: json
|
||||||
|
auth: inherit
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
{
|
||||||
|
"value" : "true",
|
||||||
|
"active": "false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
settings {
|
||||||
|
encodeUrl: true
|
||||||
|
timeout: 0
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user