mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-28 21:58:15 +02:00
rename auth and start work separating config
This commit is contained in:
parent
d447de9e8a
commit
b199595100
15 changed files with 153 additions and 120 deletions
|
@ -12,12 +12,12 @@ import { eq } from "drizzle-orm";
|
|||
import config from "@server/config";
|
||||
import type { RandomReader } from "@oslojs/crypto/random";
|
||||
import { generateRandomString } from "@oslojs/crypto/random";
|
||||
import { extractBaseDomain } from "@server/utils/extractBaseDomain";
|
||||
|
||||
export const SESSION_COOKIE_NAME = config.server.session_cookie_name;
|
||||
export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
|
||||
export const SECURE_COOKIES = config.server.secure_cookies;
|
||||
export const COOKIE_DOMAIN =
|
||||
"." + new URL(config.app.base_url).hostname.split(".").slice(-2).join(".");
|
||||
export const COOKIE_DOMAIN = "." + extractBaseDomain(config.app.base_url);
|
||||
|
||||
export function generateSessionToken(): string {
|
||||
const bytes = new Uint8Array(20);
|
||||
|
|
|
@ -9,12 +9,12 @@ import { Newt, newts, newtSessions, NewtSession } from "@server/db/schema";
|
|||
import db from "@server/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import config from "@server/config";
|
||||
import { extractBaseDomain } from "@server/utils/extractBaseDomain";
|
||||
|
||||
export const SESSION_COOKIE_NAME = "session";
|
||||
export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
|
||||
export const SECURE_COOKIES = config.server.secure_cookies;
|
||||
export const COOKIE_DOMAIN =
|
||||
"." + new URL(config.app.base_url).hostname.split(".").slice(-2).join(".");
|
||||
export const COOKIE_DOMAIN = "." + extractBaseDomain(config.app.base_url);
|
||||
|
||||
export async function createNewtSession(
|
||||
token: string,
|
||||
|
|
|
@ -8,12 +8,12 @@ import {
|
|||
import db from "@server/db";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import config from "@server/config";
|
||||
import { extractBaseDomain } from "@server/utils/extractBaseDomain";
|
||||
|
||||
export const SESSION_COOKIE_NAME = "resource_session";
|
||||
export const SESSION_COOKIE_EXPIRES = 1000 * 60 * 60 * 24 * 30;
|
||||
export const SECURE_COOKIES = config.server.secure_cookies;
|
||||
export const COOKIE_DOMAIN =
|
||||
"." + new URL(config.app.base_url).hostname.split(".").slice(-2).join(".");
|
||||
export const COOKIE_DOMAIN = "." + extractBaseDomain(config.app.base_url);
|
||||
|
||||
export async function createResourceSession(opts: {
|
||||
token: string;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import yaml from "js-yaml";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { z } from "zod";
|
||||
import { fromError } from "zod-validation-error";
|
||||
|
||||
export const __FILENAME = fileURLToPath(import.meta.url);
|
||||
export const __DIRNAME = path.dirname(__FILENAME);
|
||||
|
@ -79,7 +79,18 @@ const environmentSchema = z.object({
|
|||
.optional()
|
||||
});
|
||||
|
||||
export function getConfig() {
|
||||
export class Config {
|
||||
private rawConfig!: z.infer<typeof environmentSchema>;
|
||||
|
||||
constructor() {
|
||||
this.loadConfig();
|
||||
}
|
||||
|
||||
public getRawConfig() {
|
||||
return this.rawConfig;
|
||||
}
|
||||
|
||||
public loadConfig() {
|
||||
const loadConfig = (configPath: string) => {
|
||||
try {
|
||||
const yamlContent = fs.readFileSync(configPath, "utf8");
|
||||
|
@ -105,19 +116,28 @@ export function getConfig() {
|
|||
environment = loadConfig(configFilePath2);
|
||||
}
|
||||
if (!environment) {
|
||||
const exampleConfigPath = path.join(__DIRNAME, "config.example.yml");
|
||||
const exampleConfigPath = path.join(
|
||||
__DIRNAME,
|
||||
"config.example.yml"
|
||||
);
|
||||
if (fs.existsSync(exampleConfigPath)) {
|
||||
try {
|
||||
const exampleConfigContent = fs.readFileSync(
|
||||
exampleConfigPath,
|
||||
"utf8"
|
||||
);
|
||||
fs.writeFileSync(configFilePath1, exampleConfigContent, "utf8");
|
||||
fs.writeFileSync(
|
||||
configFilePath1,
|
||||
exampleConfigContent,
|
||||
"utf8"
|
||||
);
|
||||
environment = loadConfig(configFilePath1);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
throw new Error(
|
||||
`Error creating configuration file from example: ${error.message}`
|
||||
`Error creating configuration file from example: ${
|
||||
error.message
|
||||
}`
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
|
@ -174,7 +194,10 @@ export function getConfig() {
|
|||
? "true"
|
||||
: "false";
|
||||
|
||||
return parsedConfig.data;
|
||||
this.rawConfig = parsedConfig.data;
|
||||
}
|
||||
}
|
||||
|
||||
export default getConfig();
|
||||
export const config = new Config();
|
||||
|
||||
export default config;
|
||||
|
|
|
@ -6,7 +6,7 @@ import logger from "@server/logger";
|
|||
export async function sendEmail(
|
||||
template: ReactElement,
|
||||
opts: {
|
||||
name: string | undefined;
|
||||
name?: string;
|
||||
from: string | undefined;
|
||||
to: string | undefined;
|
||||
subject: string;
|
||||
|
|
|
@ -11,6 +11,7 @@ import { createAdminRole } from "@server/setup/ensureActions";
|
|||
import config from "@server/config";
|
||||
import { fromError } from "zod-validation-error";
|
||||
import { defaultRoleAllowedActions } from "../role";
|
||||
import { extractBaseDomain } from "@server/utils/extractBaseDomain";
|
||||
|
||||
const createOrgSchema = z
|
||||
.object({
|
||||
|
@ -83,7 +84,7 @@ export async function createOrg(
|
|||
|
||||
await db.transaction(async (trx) => {
|
||||
// create a url from config.app.base_url and get the hostname
|
||||
const domain = new URL(config.app.base_url).hostname;
|
||||
const domain = extractBaseDomain(config.app.base_url);
|
||||
|
||||
const newOrg = await trx
|
||||
.insert(orgs)
|
||||
|
|
|
@ -53,8 +53,6 @@ export async function createResource(
|
|||
|
||||
let { name, subdomain } = parsedBody.data;
|
||||
|
||||
subdomain = subdomain.toLowerCase(); // always to lower case
|
||||
|
||||
// Validate request params
|
||||
const parsedParams = createResourceParamsSchema.safeParse(req.params);
|
||||
if (!parsedParams.success) {
|
||||
|
|
|
@ -41,8 +41,6 @@ export async function traefikConfigProvider(
|
|||
const badgerMiddlewareName = "badger";
|
||||
const redirectMiddlewareName = "redirect-to-https";
|
||||
|
||||
// const baseDomain = new URL(config.app.base_url).hostname;
|
||||
|
||||
const http: any = {
|
||||
routers: {},
|
||||
services: {},
|
||||
|
|
|
@ -3,10 +3,11 @@ import { orgs } from "../db/schema";
|
|||
import config from "@server/config";
|
||||
import { ne } from "drizzle-orm";
|
||||
import logger from "@server/logger";
|
||||
import { extractBaseDomain } from "@server/utils/extractBaseDomain";
|
||||
|
||||
export async function copyInConfig() {
|
||||
// create a url from config.app.base_url and get the hostname
|
||||
const domain = new URL(config.app.base_url).hostname;
|
||||
const domain = extractBaseDomain(config.app.base_url);
|
||||
|
||||
// update the domain on all of the orgs where the domain is not equal to the new domain
|
||||
// TODO: eventually each org could have a unique domain that we do not want to overwrite, so this will be unnecessary
|
||||
|
|
|
@ -1,18 +1,23 @@
|
|||
import { ensureActions } from "./ensureActions";
|
||||
import { copyInConfig } from "./copyInConfig";
|
||||
import logger from "@server/logger";
|
||||
import { runMigrations } from "./migrations";
|
||||
import { setupServerAdmin } from "./setupServerAdmin";
|
||||
import { loadConfig } from "@server/config";
|
||||
|
||||
export async function runSetupFunctions() {
|
||||
try {
|
||||
logger.info(`Setup for version ${process.env.APP_VERSION}`);
|
||||
await runMigrations(); // run the migrations
|
||||
|
||||
console.log("Migrations completed successfully.")
|
||||
|
||||
// ANYTHING BEFORE THIS LINE CANNOT USE THE CONFIG
|
||||
loadConfig();
|
||||
|
||||
await copyInConfig(); // copy in the config to the db as needed
|
||||
await setupServerAdmin();
|
||||
await ensureActions(); // make sure all of the actions are in the db and the roles
|
||||
} catch (error) {
|
||||
logger.error("Error running setup functions", error);
|
||||
console.error("Error running setup functions:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import logger from "@server/logger";
|
||||
import { __DIRNAME } from "@server/config";
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import db, { exists } from "@server/db";
|
||||
|
@ -8,12 +7,12 @@ import { versionMigrations } from "@server/db/schema";
|
|||
import { desc } from "drizzle-orm";
|
||||
|
||||
// Import all migrations explicitly
|
||||
import migration100beta1 from "./scripts/1.0.0-beta1";
|
||||
import m1 from "./scripts/1.0.0-beta1";
|
||||
// Add new migration imports here as they are created
|
||||
|
||||
// Define the migration list with versions and their corresponding functions
|
||||
const migrations = [
|
||||
{ version: "1.0.0-beta.1", run: migration100beta1 }
|
||||
{ version: "1.0.0-beta.1", run: m1 }
|
||||
// Add new migrations here as they are created
|
||||
] as const;
|
||||
|
||||
|
@ -23,21 +22,21 @@ export async function runMigrations() {
|
|||
}
|
||||
|
||||
if (process.env.ENVIRONMENT !== "prod") {
|
||||
logger.info("Skipping migrations in non-prod environment");
|
||||
console.info("Skipping migrations in non-prod environment");
|
||||
return;
|
||||
}
|
||||
|
||||
if (exists) {
|
||||
await executeScripts();
|
||||
} else {
|
||||
logger.info("Running migrations...");
|
||||
console.info("Running migrations...");
|
||||
try {
|
||||
migrate(db, {
|
||||
migrationsFolder: path.join(__DIRNAME, "init") // put here during the docker build
|
||||
});
|
||||
logger.info("Migrations completed successfully.");
|
||||
console.info("Migrations completed successfully.");
|
||||
} catch (error) {
|
||||
logger.error("Error running migrations:", error);
|
||||
console.error("Error running migrations:", error);
|
||||
}
|
||||
|
||||
// insert process.env.APP_VERSION into the versionMigrations table
|
||||
|
@ -61,7 +60,7 @@ async function executeScripts() {
|
|||
.limit(1);
|
||||
|
||||
const startVersion = lastExecuted[0]?.version ?? "0.0.0";
|
||||
logger.info(`Starting migrations from version ${startVersion}`);
|
||||
console.info(`Starting migrations from version ${startVersion}`);
|
||||
|
||||
// Filter and sort migrations
|
||||
const pendingMigrations = migrations
|
||||
|
@ -70,7 +69,7 @@ async function executeScripts() {
|
|||
|
||||
// Run migrations in order
|
||||
for (const migration of pendingMigrations) {
|
||||
logger.info(`Running migration ${migration.version}`);
|
||||
console.info(`Running migration ${migration.version}`);
|
||||
|
||||
try {
|
||||
await migration.run();
|
||||
|
@ -84,11 +83,11 @@ async function executeScripts() {
|
|||
})
|
||||
.execute();
|
||||
|
||||
logger.info(
|
||||
console.info(
|
||||
`Successfully completed migration ${migration.version}`
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
console.error(
|
||||
`Failed to run migration ${migration.version}:`,
|
||||
error
|
||||
);
|
||||
|
@ -96,9 +95,9 @@ async function executeScripts() {
|
|||
}
|
||||
}
|
||||
|
||||
logger.info("All migrations completed successfully");
|
||||
console.info("All migrations completed successfully");
|
||||
} catch (error) {
|
||||
logger.error("Migration process failed:", error);
|
||||
console.error("Migration process failed:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import logger from "@server/logger";
|
||||
|
||||
export default async function migration100beta1() {
|
||||
export default async function migration() {
|
||||
logger.info("Running setup script 1.0.0-beta.1");
|
||||
// SQL operations would go here in ts format
|
||||
logger.info("Done...");
|
||||
|
|
11
server/utils/extractBaseDomain.ts
Normal file
11
server/utils/extractBaseDomain.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
export function extractBaseDomain(url: string): string {
|
||||
const newUrl = new URL(url);
|
||||
const hostname = newUrl.hostname;
|
||||
const parts = hostname.split(".");
|
||||
|
||||
if (parts.length <= 2) {
|
||||
return parts.join(".");
|
||||
}
|
||||
|
||||
return parts.slice(1).join(".");
|
||||
}
|
|
@ -398,7 +398,7 @@ export default function ResourceAuthenticationPage() {
|
|||
onCheckedChange={(val) => setSsoEnabled(val)}
|
||||
/>
|
||||
<Label htmlFor="sso-toggle">
|
||||
Allow Unified Login
|
||||
Use Platform SSO
|
||||
</Label>
|
||||
</div>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
|
|
|
@ -44,7 +44,6 @@ export default async function InvitePage(props: {
|
|||
await authCookieHeader()
|
||||
)
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
error = formatAxiosError(e);
|
||||
});
|
||||
|
||||
|
@ -68,8 +67,6 @@ export default async function InvitePage(props: {
|
|||
|
||||
const type = cardType();
|
||||
|
||||
console.log("card type is", type, error)
|
||||
|
||||
if (!user && type === "user_does_not_exist") {
|
||||
redirect(`/auth/signup?redirect=/invite?token=${params.token}`);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue