make config class and separate migrations script

This commit is contained in:
Milo Schwartz
2025-01-01 17:50:12 -05:00
parent b199595100
commit 9732098799
45 changed files with 163 additions and 156 deletions

View File

@@ -99,7 +99,7 @@ export async function disable2fa(
}),
{
to: user.email,
from: config.email?.no_reply,
from: config.getRawConfig().email?.no_reply,
subject: "Two-factor authentication disabled"
}
);

View File

@@ -127,7 +127,7 @@ export async function login(
if (
!existingUser.emailVerified &&
config.flags?.require_email_verification
config.getRawConfig().flags?.require_email_verification
) {
return response<LoginResponse>(res, {
data: { emailVerificationRequired: true },

View File

@@ -16,7 +16,7 @@ export async function requestEmailVerificationCode(
res: Response,
next: NextFunction
): Promise<any> {
if (!config.flags?.require_email_verification) {
if (!config.getRawConfig().flags?.require_email_verification) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,

View File

@@ -82,7 +82,7 @@ export async function requestPasswordReset(
});
});
const url = `${config.app.base_url}/auth/reset-password?email=${email}&token=${token}`;
const url = `${config.getRawConfig().app.base_url}/auth/reset-password?email=${email}&token=${token}`;
await sendEmail(
ResetPasswordCode({
@@ -91,7 +91,7 @@ export async function requestPasswordReset(
link: url
}),
{
from: config.email?.no_reply,
from: config.getRawConfig().email?.no_reply,
to: email,
subject: "Reset your password"
}

View File

@@ -147,7 +147,7 @@ export async function resetPassword(
});
await sendEmail(ConfirmPasswordReset({ email }), {
from: config.email?.no_reply,
from: config.getRawConfig().email?.no_reply,
to: email,
subject: "Password Reset Confirmation"
});

View File

@@ -60,7 +60,7 @@ export async function signup(
const passwordHash = await hashPassword(password);
const userId = generateId(15);
if (config.flags?.disable_signup_without_invite) {
if (config.getRawConfig().flags?.disable_signup_without_invite) {
if (!inviteToken || !inviteId) {
return next(
createHttpError(
@@ -102,7 +102,7 @@ export async function signup(
.where(eq(users.email, email));
if (existing && existing.length > 0) {
if (!config.flags?.require_email_verification) {
if (!config.getRawConfig().flags?.require_email_verification) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
@@ -163,7 +163,7 @@ export async function signup(
const cookie = serializeSessionCookie(token);
res.appendHeader("Set-Cookie", cookie);
if (config.flags?.require_email_verification) {
if (config.getRawConfig().flags?.require_email_verification) {
sendEmailVerificationCode(email, userId);
return response<SignUpResponse>(res, {

View File

@@ -28,7 +28,7 @@ export async function verifyEmail(
res: Response,
next: NextFunction
): Promise<any> {
if (!config.flags?.require_email_verification) {
if (!config.getRawConfig().flags?.require_email_verification) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,

View File

@@ -111,7 +111,7 @@ export async function verifyTotp(
}),
{
to: user.email,
from: config.email?.no_reply,
from: config.getRawConfig().email?.no_reply,
subject: "Two-factor authentication enabled"
}
);

View File

@@ -101,13 +101,13 @@ export async function verifyResourceSession(
return allowed(res);
}
const redirectUrl = `${config.app.base_url}/auth/resource/${encodeURIComponent(resource.resourceId)}?redirect=${encodeURIComponent(originalRequestURL)}`;
const redirectUrl = `${config.getRawConfig().app.base_url}/auth/resource/${encodeURIComponent(resource.resourceId)}?redirect=${encodeURIComponent(originalRequestURL)}`;
if (!sessions) {
return notAllowed(res);
}
const sessionToken = sessions[config.server.session_cookie_name];
const sessionToken = sessions[config.getRawConfig().server.session_cookie_name];
// check for unified login
if (sso && sessionToken) {
@@ -129,7 +129,7 @@ export async function verifyResourceSession(
const resourceSessionToken =
sessions[
`${config.server.resource_session_cookie_name}_${resource.resourceId}`
`${config.getRawConfig().server.resource_session_cookie_name}_${resource.resourceId}`
];
if (resourceSessionToken) {
@@ -213,7 +213,7 @@ async function isUserAllowedToAccessResource(
user: User,
resource: Resource
): Promise<boolean> {
if (config.flags?.require_email_verification && !user.emailVerified) {
if (config.getRawConfig().flags?.require_email_verification && !user.emailVerified) {
return false;
}

View File

@@ -423,11 +423,11 @@ unauthenticated.use("/auth", authRouter);
authRouter.use(
rateLimitMiddleware({
windowMin:
config.rate_limits.auth?.window_minutes ||
config.rate_limits.global.window_minutes,
config.getRawConfig().rate_limits.auth?.window_minutes ||
config.getRawConfig().rate_limits.global.window_minutes,
max:
config.rate_limits.auth?.max_requests ||
config.rate_limits.global.max_requests,
config.getRawConfig().rate_limits.auth?.max_requests ||
config.getRawConfig().rate_limits.global.max_requests,
type: "IP_AND_PATH"
})
);

View File

@@ -52,14 +52,14 @@ export async function getConfig(req: Request, res: Response, next: NextFunction)
const address = await getNextAvailableSubnet();
const listenPort = await getNextAvailablePort();
let subEndpoint = "";
if (config.gerbil.use_subdomain) {
if (config.getRawConfig().gerbil.use_subdomain) {
subEndpoint = await getUniqueExitNodeEndpointName();
}
// create a new exit node
exitNode = await db.insert(exitNodes).values({
publicKey,
endpoint: `${subEndpoint}${subEndpoint != "" ? "." : ""}${config.gerbil.base_endpoint}`,
endpoint: `${subEndpoint}${subEndpoint != "" ? "." : ""}${config.getRawConfig().gerbil.base_endpoint}`,
address,
listenPort,
reachableAt,
@@ -122,7 +122,7 @@ async function getNextAvailableSubnet(): Promise<string> {
}).from(exitNodes);
const addresses = existingAddresses.map(a => a.address);
let subnet = findNextAvailableCidr(addresses, config.gerbil.block_size, config.gerbil.subnet_group);
let subnet = findNextAvailableCidr(addresses, config.getRawConfig().gerbil.block_size, config.getRawConfig().gerbil.subnet_group);
if (!subnet) {
throw new Error('No available subnets remaining in space');
}
@@ -139,7 +139,7 @@ async function getNextAvailablePort(): Promise<number> {
}).from(exitNodes);
// Find the first available port between 1024 and 65535
let nextPort = config.gerbil.start_port;
let nextPort = config.getRawConfig().gerbil.start_port;
for (const port of existingPorts) {
if (port.listenPort > nextPort) {
break;

View File

@@ -11,7 +11,6 @@ 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({
@@ -30,7 +29,7 @@ export async function createOrg(
): Promise<any> {
try {
// should this be in a middleware?
if (config.flags?.disable_user_create_org) {
if (config.getRawConfig().flags?.disable_user_create_org) {
if (!req.user?.serverAdmin) {
return next(
createHttpError(
@@ -83,8 +82,8 @@ export async function createOrg(
let org: Org | null = null;
await db.transaction(async (trx) => {
// create a url from config.app.base_url and get the hostname
const domain = extractBaseDomain(config.app.base_url);
// create a url from config.getRawConfig().app.base_url and get the hostname
const domain = config.getBaseDomain();
const newOrg = await trx
.insert(orgs)

View File

@@ -134,7 +134,7 @@ export async function authWithAccessToken(
expiresAt: tokenItem.expiresAt,
doNotExtend: tokenItem.expiresAt ? true : false
});
const cookieName = `${config.server.resource_session_cookie_name}_${resource.resourceId}`;
const cookieName = `${config.getRawConfig().server.resource_session_cookie_name}_${resource.resourceId}`;
const cookie = serializeResourceSessionCookie(cookieName, token);
res.appendHeader("Set-Cookie", cookie);

View File

@@ -122,7 +122,7 @@ export async function authWithPassword(
token,
passwordId: definedPassword.passwordId
});
const cookieName = `${config.server.resource_session_cookie_name}_${resource.resourceId}`;
const cookieName = `${config.getRawConfig().server.resource_session_cookie_name}_${resource.resourceId}`;
const cookie = serializeResourceSessionCookie(cookieName, token);
res.appendHeader("Set-Cookie", cookie);

View File

@@ -133,7 +133,7 @@ export async function authWithPincode(
token,
pincodeId: definedPincode.pincodeId
});
const cookieName = `${config.server.resource_session_cookie_name}_${resource.resourceId}`;
const cookieName = `${config.getRawConfig().server.resource_session_cookie_name}_${resource.resourceId}`;
const cookie = serializeResourceSessionCookie(cookieName, token);
res.appendHeader("Set-Cookie", cookie);

View File

@@ -177,7 +177,7 @@ export async function authWithWhitelist(
token,
whitelistId: whitelistedEmail.whitelistId
});
const cookieName = `${config.server.resource_session_cookie_name}_${resource.resourceId}`;
const cookieName = `${config.getRawConfig().server.resource_session_cookie_name}_${resource.resourceId}`;
const cookie = serializeResourceSessionCookie(cookieName, token);
res.appendHeader("Set-Cookie", cookie);

View File

@@ -50,12 +50,12 @@ export async function traefikConfigProvider(
[badgerMiddlewareName]: {
apiBaseUrl: new URL(
"/api/v1",
`http://${config.server.internal_hostname}:${config.server.internal_port}`,
`http://${config.getRawConfig().server.internal_hostname}:${config.getRawConfig().server.internal_port}`,
).href,
resourceSessionCookieName:
config.server.resource_session_cookie_name,
config.getRawConfig().server.resource_session_cookie_name,
userSessionCookieName:
config.server.session_cookie_name,
config.getRawConfig().server.session_cookie_name,
},
},
},
@@ -95,8 +95,8 @@ export async function traefikConfigProvider(
}
const tls = {
certResolver: config.traefik.cert_resolver,
...(config.traefik.prefer_wildcard_cert
certResolver: config.getRawConfig().traefik.cert_resolver,
...(config.getRawConfig().traefik.prefer_wildcard_cert
? {
domains: [
{
@@ -110,8 +110,8 @@ export async function traefikConfigProvider(
http.routers![routerName] = {
entryPoints: [
resource.ssl
? config.traefik.https_entrypoint
: config.traefik.http_entrypoint,
? config.getRawConfig().traefik.https_entrypoint
: config.getRawConfig().traefik.http_entrypoint,
],
middlewares: [badgerMiddlewareName],
service: serviceName,
@@ -122,7 +122,7 @@ export async function traefikConfigProvider(
if (resource.ssl) {
// this is a redirect router; all it does is redirect to the https version if tls is enabled
http.routers![routerName + "-redirect"] = {
entryPoints: [config.traefik.http_entrypoint],
entryPoints: [config.getRawConfig().traefik.http_entrypoint],
middlewares: [redirectMiddlewareName],
service: serviceName,
rule: `Host(\`${fullDomain}\`)`,

View File

@@ -152,7 +152,7 @@ export async function inviteUser(
});
});
const inviteLink = `${config.app.base_url}/invite?token=${inviteId}-${token}`;
const inviteLink = `${config.getRawConfig().app.base_url}/invite?token=${inviteId}-${token}`;
if (doEmail) {
await sendEmail(
@@ -165,7 +165,7 @@ export async function inviteUser(
}),
{
to: email,
from: config.email?.no_reply,
from: config.getRawConfig().email?.no_reply,
subject: "You're invited to join a Fossorial organization"
}
);