Support pin,pass,whitelist correctly on login

This commit is contained in:
Owen
2026-06-01 21:32:07 -07:00
parent 8a57d8dd9c
commit b6d688f15e
12 changed files with 547 additions and 395 deletions
+10 -1
View File
@@ -19,6 +19,9 @@ export async function createResourceSession(opts: {
userSessionId?: string | null; userSessionId?: string | null;
whitelistId?: number | null; whitelistId?: number | null;
accessTokenId?: string | null; accessTokenId?: string | null;
policyPasswordId?: number | null;
policyPincodeId?: number | null;
policyWhitelistId?: number | null;
doNotExtend?: boolean; doNotExtend?: boolean;
expiresAt?: number | null; expiresAt?: number | null;
sessionLength?: number | null; sessionLength?: number | null;
@@ -28,7 +31,10 @@ export async function createResourceSession(opts: {
!opts.pincodeId && !opts.pincodeId &&
!opts.whitelistId && !opts.whitelistId &&
!opts.accessTokenId && !opts.accessTokenId &&
!opts.userSessionId !opts.userSessionId &&
!opts.policyPasswordId &&
!opts.policyPincodeId &&
!opts.policyWhitelistId
) { ) {
throw new Error("Auth method must be provided"); throw new Error("Auth method must be provided");
} }
@@ -49,6 +55,9 @@ export async function createResourceSession(opts: {
whitelistId: opts.whitelistId || null, whitelistId: opts.whitelistId || null,
doNotExtend: opts.doNotExtend || false, doNotExtend: opts.doNotExtend || false,
accessTokenId: opts.accessTokenId || null, accessTokenId: opts.accessTokenId || null,
policyPasswordId: opts.policyPasswordId || null,
policyPincodeId: opts.policyPincodeId || null,
policyWhitelistId: opts.policyWhitelistId || null,
isRequestToken: opts.isRequestToken || false, isRequestToken: opts.isRequestToken || false,
userSessionId: opts.userSessionId || null, userSessionId: opts.userSessionId || null,
issuedAt: new Date().getTime() issuedAt: new Date().getTime()
+18
View File
@@ -820,6 +820,24 @@ export const resourceSessions = pgTable("resourceSessions", {
onDelete: "cascade" onDelete: "cascade"
} }
), ),
policyPasswordId: integer("policyPasswordId").references(
() => resourcePolicyPassword.passwordId,
{
onDelete: "cascade"
}
),
policyPincodeId: integer("policyPincodeId").references(
() => resourcePolicyPincode.pincodeId,
{
onDelete: "cascade"
}
),
policyWhitelistId: integer("policyWhitelistId").references(
() => resourcePolicyWhiteList.whitelistId,
{
onDelete: "cascade"
}
),
issuedAt: bigint("issuedAt", { mode: "number" }) issuedAt: bigint("issuedAt", { mode: "number" })
}); });
+18
View File
@@ -1148,6 +1148,24 @@ export const resourceSessions = sqliteTable("resourceSessions", {
onDelete: "cascade" onDelete: "cascade"
} }
), ),
policyPasswordId: integer("policyPasswordId").references(
() => resourcePolicyPassword.passwordId,
{
onDelete: "cascade"
}
),
policyPincodeId: integer("policyPincodeId").references(
() => resourcePolicyPincode.pincodeId,
{
onDelete: "cascade"
}
),
policyWhitelistId: integer("policyWhitelistId").references(
() => resourcePolicyWhiteList.whitelistId,
{
onDelete: "cascade"
}
),
issuedAt: integer("issuedAt") issuedAt: integer("issuedAt")
}); });
+2 -1
View File
@@ -520,7 +520,8 @@ export class TraefikConfigManager {
build != "oss", // generate the login pages on the cloud and hybrid, build != "oss", // generate the login pages on the cloud and hybrid,
build == "saas" build == "saas"
? false ? false
: config.getRawConfig().traefik.allow_raw_resources // dont allow raw resources on saas otherwise use config : config.getRawConfig().traefik.allow_raw_resources, // dont allow raw resources on saas otherwise use config
build != "oss" // generate browser gateway targets on cloud and enterprise
); );
const domains = new Set<string>(); const domains = new Set<string>();
+59 -42
View File
@@ -85,7 +85,8 @@ export async function getTraefikConfig(
filterOutNamespaceDomains = false, filterOutNamespaceDomains = false,
generateLoginPageRouters = false, generateLoginPageRouters = false,
allowRawResources = true, allowRawResources = true,
allowMaintenancePage = true allowMaintenancePage = true,
allowBrowserGatewayResources = true
): Promise<any> { ): Promise<any> {
// Get resources with their targets and sites in a single optimized query // Get resources with their targets and sites in a single optimized query
// Start from sites on this exit node, then join to targets and resources // Start from sites on this exit node, then join to targets and resources
@@ -276,6 +277,39 @@ export async function getTraefikConfig(
}); });
}); });
// Group browser gateway targets by resource
type BrowserGatewayResourceEntry = {
resourceId: number;
name: string;
fullDomain: string | null;
ssl: boolean | null;
subdomain: string | null;
domainId: string | null;
enabled: boolean | null;
wildcard: boolean | null;
domainCertResolver: string | null;
preferWildcardCert: boolean | null;
maintenanceModeEnabled: boolean | null;
maintenanceModeType: string | null;
maintenanceTitle: string | null;
maintenanceMessage: string | null;
maintenanceEstimatedTime: string | null;
targets: {
browserGatewayTargetId: number;
bgType: string;
siteId: number;
siteType: string;
siteOnline: boolean | null;
subnet: string | null;
siteExitNodeId: number | null;
}[];
};
const browserGatewayResourcesMap = new Map<
number,
BrowserGatewayResourceEntry
>();
if (allowBrowserGatewayResources) {
// Query browser gateway targets for this exit node // Query browser gateway targets for this exit node
const browserGatewayRows = await db const browserGatewayRows = await db
.select({ .select({
@@ -298,7 +332,8 @@ export async function getTraefikConfig(
maintenanceMessage: resources.maintenanceMessage, maintenanceMessage: resources.maintenanceMessage,
maintenanceEstimatedTime: resources.maintenanceEstimatedTime, maintenanceEstimatedTime: resources.maintenanceEstimatedTime,
// Browser gateway target fields // Browser gateway target fields
browserGatewayTargetId: browserGatewayTarget.browserGatewayTargetId, browserGatewayTargetId:
browserGatewayTarget.browserGatewayTargetId,
bgType: browserGatewayTarget.type, bgType: browserGatewayTarget.type,
// Site fields // Site fields
siteId: sites.siteId, siteId: sites.siteId,
@@ -334,38 +369,6 @@ export async function getTraefikConfig(
) )
); );
// Group browser gateway targets by resource
type BrowserGatewayResourceEntry = {
resourceId: number;
name: string;
fullDomain: string | null;
ssl: boolean | null;
subdomain: string | null;
domainId: string | null;
enabled: boolean | null;
wildcard: boolean | null;
domainCertResolver: string | null;
preferWildcardCert: boolean | null;
maintenanceModeEnabled: boolean | null;
maintenanceModeType: string | null;
maintenanceTitle: string | null;
maintenanceMessage: string | null;
maintenanceEstimatedTime: string | null;
targets: {
browserGatewayTargetId: number;
bgType: string;
siteId: number;
siteType: string;
siteOnline: boolean | null;
subnet: string | null;
siteExitNodeId: number | null;
}[];
};
const browserGatewayResourcesMap = new Map<
number,
BrowserGatewayResourceEntry
>();
for (const row of browserGatewayRows) { for (const row of browserGatewayRows) {
if (filterOutNamespaceDomains && row.domainNamespaceId) { if (filterOutNamespaceDomains && row.domainNamespaceId) {
continue; continue;
@@ -400,6 +403,7 @@ export async function getTraefikConfig(
siteExitNodeId: row.siteExitNodeId siteExitNodeId: row.siteExitNodeId
}); });
} }
}
let siteResourcesWithFullDomain: { let siteResourcesWithFullDomain: {
siteResourceId: number; siteResourceId: number;
@@ -1055,6 +1059,7 @@ export async function getTraefikConfig(
} }
} }
if (allowBrowserGatewayResources) {
// Generate Traefik config for browser gateway resources // Generate Traefik config for browser gateway resources
const browserGatewayPort = 39999; const browserGatewayPort = 39999;
for (const [, bgResource] of browserGatewayResourcesMap.entries()) { for (const [, bgResource] of browserGatewayResourcesMap.entries()) {
@@ -1123,7 +1128,9 @@ export async function getTraefikConfig(
if (bgResource.ssl) { if (bgResource.ssl) {
const redirectRouterName = `bg-r${bgResource.resourceId}-redirect`; const redirectRouterName = `bg-r${bgResource.resourceId}-redirect`;
config_output.http.routers![redirectRouterName] = { config_output.http.routers![redirectRouterName] = {
entryPoints: [config.getRawConfig().traefik.http_entrypoint], entryPoints: [
config.getRawConfig().traefik.http_entrypoint
],
middlewares: [redirectHttpsMiddlewareName], middlewares: [redirectHttpsMiddlewareName],
service: bgUiServiceName, service: bgUiServiceName,
rule: hostRule, rule: hostRule,
@@ -1158,15 +1165,19 @@ export async function getTraefikConfig(
const maintenanceHost = const maintenanceHost =
config.getRawConfig().server.internal_hostname; config.getRawConfig().server.internal_hostname;
if (!config_output.http.services) config_output.http.services = {}; if (!config_output.http.services)
config_output.http.services = {};
if (!config_output.http.middlewares) if (!config_output.http.middlewares)
config_output.http.middlewares = {}; config_output.http.middlewares = {};
if (!config_output.http.routers) config_output.http.routers = {}; if (!config_output.http.routers)
config_output.http.routers = {};
config_output.http.services![bgMaintenanceServiceName] = { config_output.http.services![bgMaintenanceServiceName] = {
loadBalancer: { loadBalancer: {
servers: [ servers: [
{ url: `http://${maintenanceHost}:${maintenancePort}` } {
url: `http://${maintenanceHost}:${maintenancePort}`
}
], ],
passHostHeader: true passHostHeader: true
} }
@@ -1190,7 +1201,9 @@ export async function getTraefikConfig(
...(bgResource.ssl ? { tls } : {}) ...(bgResource.ssl ? { tls } : {})
}; };
config_output.http.routers![`${bgMaintenanceRouterName}-assets`] = { config_output.http.routers![
`${bgMaintenanceRouterName}-assets`
] = {
entryPoints: [ entryPoints: [
bgResource.ssl ? entrypointHttps : entrypointHttp bgResource.ssl ? entrypointHttps : entrypointHttp
], ],
@@ -1225,7 +1238,9 @@ export async function getTraefikConfig(
.map((t) => ({ .map((t) => ({
url: `http://${t.subnet!.split("/")[0]}:${browserGatewayPort}` url: `http://${t.subnet!.split("/")[0]}:${browserGatewayPort}`
})) }))
.filter((v, i, a) => a.findIndex((u) => u.url === v.url) === i); .filter(
(v, i, a) => a.findIndex((u) => u.url === v.url) === i
);
config_output.http.routers![bgRouterName] = { config_output.http.routers![bgRouterName] = {
entryPoints: [ entryPoints: [
@@ -1292,8 +1307,9 @@ export async function getTraefikConfig(
}; };
// Catch-all router rewrites everything on the domain to /{primaryType} // Catch-all router rewrites everything on the domain to /{primaryType}
config_output.http.routers![`bg-r${bgResource.resourceId}-ui-router`] = config_output.http.routers![
{ `bg-r${bgResource.resourceId}-ui-router`
] = {
entryPoints: [entrypoint], entryPoints: [entrypoint],
middlewares: [...routerMiddlewares, uiRewriteMiddlewareName], middlewares: [...routerMiddlewares, uiRewriteMiddlewareName],
service: bgUiServiceName, service: bgUiServiceName,
@@ -1302,6 +1318,7 @@ export async function getTraefikConfig(
...(bgResource.ssl ? { tls } : {}) ...(bgResource.ssl ? { tls } : {})
}; };
} }
}
// Add Traefik routes for siteResource aliases (HTTP mode + SSL) so that // Add Traefik routes for siteResource aliases (HTTP mode + SSL) so that
// Traefik generates TLS certificates for those domains even when no // Traefik generates TLS certificates for those domains even when no
+2 -1
View File
@@ -270,7 +270,8 @@ hybridRouter.get(
true, // But don't allow domain namespace resources true, // But don't allow domain namespace resources
false, // Dont include login pages, false, // Dont include login pages,
true, // allow raw resources true, // allow raw resources
false // dont generate maintenance page false, // dont generate maintenance page
false // dont generate browser gateway targets
); );
return response(res, { return response(res, {
+17 -7
View File
@@ -1,7 +1,7 @@
import { verify } from "@node-rs/argon2"; import { verify } from "@node-rs/argon2";
import { generateSessionToken } from "@server/auth/sessions/app"; import { generateSessionToken } from "@server/auth/sessions/app";
import { db } from "@server/db"; import { db } from "@server/db";
import { orgs, resourcePassword, resources } from "@server/db"; import { orgs, resourcePassword, resourcePolicies, resourcePolicyPassword, resources } from "@server/db";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import response from "@server/lib/response"; import response from "@server/lib/response";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
@@ -61,17 +61,29 @@ export async function authWithPassword(
const [result] = await db const [result] = await db
.select() .select()
.from(resources) .from(resources)
.leftJoin(orgs, eq(orgs.orgId, resources.orgId))
.leftJoin(
resourcePolicies,
eq(resourcePolicies.resourcePolicyId, resources.resourcePolicyId)
)
.leftJoin(
resourcePolicyPassword,
eq(resourcePolicyPassword.resourcePolicyId, resourcePolicies.resourcePolicyId)
)
.leftJoin( .leftJoin(
resourcePassword, resourcePassword,
eq(resourcePassword.resourceId, resources.resourceId) eq(resourcePassword.resourceId, resources.resourceId)
) )
.leftJoin(orgs, eq(orgs.orgId, resources.orgId))
.where(eq(resources.resourceId, resourceId)) .where(eq(resources.resourceId, resourceId))
.limit(1); .limit(1);
const resource = result?.resources; const resource = result?.resources;
const org = result?.orgs; const org = result?.orgs;
const definedPassword = result?.resourcePassword;
// Policy password takes precedence over resource-level password
const policyPassword = result?.resourcePolicyPassword ?? null;
const definedPassword = policyPassword ?? result?.resourcePassword ?? null;
const isPolicyPassword = !!policyPassword;
if (!org) { if (!org) {
return next( return next(
@@ -89,11 +101,8 @@ export async function authWithPassword(
return next( return next(
createHttpError( createHttpError(
HttpCode.UNAUTHORIZED, HttpCode.UNAUTHORIZED,
createHttpError(
HttpCode.BAD_REQUEST,
"Resource has no password protection" "Resource has no password protection"
) )
)
); );
} }
@@ -126,7 +135,8 @@ export async function authWithPassword(
await createResourceSession({ await createResourceSession({
resourceId, resourceId,
token, token,
passwordId: definedPassword.passwordId, passwordId: isPolicyPassword ? null : definedPassword.passwordId,
policyPasswordId: isPolicyPassword ? definedPassword.passwordId : null,
isRequestToken: true, isRequestToken: true,
expiresAt: Date.now() + 1000 * 30, // 30 seconds expiresAt: Date.now() + 1000 * 30, // 30 seconds
sessionLength: 1000 * 30, sessionLength: 1000 * 30,
+17 -4
View File
@@ -1,6 +1,6 @@
import { generateSessionToken } from "@server/auth/sessions/app"; import { generateSessionToken } from "@server/auth/sessions/app";
import { db } from "@server/db"; import { db } from "@server/db";
import { orgs, resourcePincode, resources } from "@server/db"; import { orgs, resourcePincode, resourcePolicies, resourcePolicyPincode, resources } from "@server/db";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import response from "@server/lib/response"; import response from "@server/lib/response";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
@@ -60,17 +60,29 @@ export async function authWithPincode(
const [result] = await db const [result] = await db
.select() .select()
.from(resources) .from(resources)
.leftJoin(orgs, eq(orgs.orgId, resources.orgId))
.leftJoin(
resourcePolicies,
eq(resourcePolicies.resourcePolicyId, resources.resourcePolicyId)
)
.leftJoin(
resourcePolicyPincode,
eq(resourcePolicyPincode.resourcePolicyId, resourcePolicies.resourcePolicyId)
)
.leftJoin( .leftJoin(
resourcePincode, resourcePincode,
eq(resourcePincode.resourceId, resources.resourceId) eq(resourcePincode.resourceId, resources.resourceId)
) )
.leftJoin(orgs, eq(orgs.orgId, resources.orgId))
.where(eq(resources.resourceId, resourceId)) .where(eq(resources.resourceId, resourceId))
.limit(1); .limit(1);
const resource = result?.resources; const resource = result?.resources;
const org = result?.orgs; const org = result?.orgs;
const definedPincode = result?.resourcePincode;
// Policy pincode takes precedence over resource-level pincode
const policyPincode = result?.resourcePolicyPincode ?? null;
const definedPincode = policyPincode ?? result?.resourcePincode ?? null;
const isPolicyPincode = !!policyPincode;
if (!org) { if (!org) {
return next( return next(
@@ -125,7 +137,8 @@ export async function authWithPincode(
await createResourceSession({ await createResourceSession({
resourceId, resourceId,
token, token,
pincodeId: definedPincode.pincodeId, pincodeId: isPolicyPincode ? null : definedPincode.pincodeId,
policyPincodeId: isPolicyPincode ? definedPincode.pincodeId : null,
isRequestToken: true, isRequestToken: true,
expiresAt: Date.now() + 1000 * 30, // 30 seconds expiresAt: Date.now() + 1000 * 30, // 30 seconds
sessionLength: 1000 * 30, sessionLength: 1000 * 30,
+73 -42
View File
@@ -1,6 +1,6 @@
import { generateSessionToken } from "@server/auth/sessions/app"; import { generateSessionToken } from "@server/auth/sessions/app";
import { db } from "@server/db"; import { db } from "@server/db";
import { orgs, resourceOtp, resources, resourceWhitelist } from "@server/db"; import { orgs, resourceOtp, resources, resourceWhitelist, resourcePolicyWhiteList } from "@server/db";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import response from "@server/lib/response"; import response from "@server/lib/response";
import { eq, and } from "drizzle-orm"; import { eq, and } from "drizzle-orm";
@@ -59,7 +59,67 @@ export async function authWithWhitelist(
const { email, otp } = parsedBody.data; const { email, otp } = parsedBody.data;
try { try {
const [result] = await db // Fetch resource and org first
const [resourceResult] = await db
.select()
.from(resources)
.leftJoin(orgs, eq(orgs.orgId, resources.orgId))
.where(eq(resources.resourceId, resourceId))
.limit(1);
const resource = resourceResult?.resources;
const org = resourceResult?.orgs;
if (!resource) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Resource does not exist")
);
}
if (!org) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Resource does not exist")
);
}
const wildcard = "*@" + email.split("@")[1];
// Check policy whitelist first (policy takes precedence over resource whitelist)
let policyWhitelistEntry: { whitelistId: number; email: string } | null = null;
if (resource.resourcePolicyId) {
const [exact] = await db
.select()
.from(resourcePolicyWhiteList)
.where(
and(
eq(resourcePolicyWhiteList.resourcePolicyId, resource.resourcePolicyId),
eq(resourcePolicyWhiteList.email, email)
)
)
.limit(1);
if (exact) {
policyWhitelistEntry = exact;
} else {
logger.debug("Checking for wildcard email in policy: " + wildcard);
const [wildcardMatch] = await db
.select()
.from(resourcePolicyWhiteList)
.where(
and(
eq(resourcePolicyWhiteList.resourcePolicyId, resource.resourcePolicyId),
eq(resourcePolicyWhiteList.email, wildcard)
)
)
.limit(1);
if (wildcardMatch) policyWhitelistEntry = wildcardMatch;
}
}
// Fall back to resource whitelist if not found in policy
let resourceWhitelistEntry: { whitelistId: number; email: string } | null = null;
if (!policyWhitelistEntry) {
const [exact] = await db
.select() .select()
.from(resourceWhitelist) .from(resourceWhitelist)
.where( .where(
@@ -68,24 +128,13 @@ export async function authWithWhitelist(
eq(resourceWhitelist.email, email) eq(resourceWhitelist.email, email)
) )
) )
.leftJoin(
resources,
eq(resources.resourceId, resourceWhitelist.resourceId)
)
.leftJoin(orgs, eq(orgs.orgId, resources.orgId))
.limit(1); .limit(1);
let resource = result?.resources; if (exact) {
let org = result?.orgs; resourceWhitelistEntry = exact;
let whitelistedEmail = result?.resourceWhitelist; } else {
if (!whitelistedEmail) {
// if email is not found, check for wildcard email
const wildcard = "*@" + email.split("@")[1];
logger.debug("Checking for wildcard email: " + wildcard); logger.debug("Checking for wildcard email: " + wildcard);
const [wildcardMatch] = await db
const [result] = await db
.select() .select()
.from(resourceWhitelist) .from(resourceWhitelist)
.where( .where(
@@ -94,18 +143,14 @@ export async function authWithWhitelist(
eq(resourceWhitelist.email, wildcard) eq(resourceWhitelist.email, wildcard)
) )
) )
.leftJoin(
resources,
eq(resources.resourceId, resourceWhitelist.resourceId)
)
.leftJoin(orgs, eq(orgs.orgId, resources.orgId))
.limit(1); .limit(1);
if (wildcardMatch) resourceWhitelistEntry = wildcardMatch;
}
}
resource = result?.resources; const isPolicyWhitelist = !!policyWhitelistEntry;
org = result?.orgs; const whitelistedEmail = policyWhitelistEntry ?? resourceWhitelistEntry;
whitelistedEmail = result?.resourceWhitelist;
// if wildcard is still not found, return unauthorized
if (!whitelistedEmail) { if (!whitelistedEmail) {
if (config.getRawConfig().app.log_failed_attempts) { if (config.getRawConfig().app.log_failed_attempts) {
logger.info( logger.info(
@@ -113,7 +158,6 @@ export async function authWithWhitelist(
); );
} }
if (org && resource) {
logAccessAudit({ logAccessAudit({
orgId: org.orgId, orgId: org.orgId,
resourceId: resource.resourceId, resourceId: resource.resourceId,
@@ -123,7 +167,6 @@ export async function authWithWhitelist(
userAgent: req.headers["user-agent"], userAgent: req.headers["user-agent"],
requestIp: req.ip requestIp: req.ip
}); });
}
return next( return next(
createHttpError( createHttpError(
@@ -135,19 +178,6 @@ export async function authWithWhitelist(
) )
); );
} }
}
if (!org) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Resource does not exist")
);
}
if (!resource) {
return next(
createHttpError(HttpCode.BAD_REQUEST, "Resource does not exist")
);
}
if (otp && email) { if (otp && email) {
const isValidCode = await isValidOtp( const isValidCode = await isValidOtp(
@@ -211,7 +241,8 @@ export async function authWithWhitelist(
await createResourceSession({ await createResourceSession({
resourceId, resourceId,
token, token,
whitelistId: whitelistedEmail.whitelistId, whitelistId: isPolicyWhitelist ? null : whitelistedEmail.whitelistId,
policyWhitelistId: isPolicyWhitelist ? whitelistedEmail.whitelistId : null,
isRequestToken: true, isRequestToken: true,
expiresAt: Date.now() + 1000 * 30, // 30 seconds expiresAt: Date.now() + 1000 * 30, // 30 seconds
sessionLength: 1000 * 30, sessionLength: 1000 * 30,
@@ -22,7 +22,8 @@ export async function traefikConfigProvider(
config.getRawConfig().traefik.site_types, config.getRawConfig().traefik.site_types,
build == "oss", // filter out the namespace domains in open source build == "oss", // filter out the namespace domains in open source
build != "oss", // generate the login pages on the cloud and and enterprise, build != "oss", // generate the login pages on the cloud and and enterprise,
config.getRawConfig().traefik.allow_raw_resources config.getRawConfig().traefik.allow_raw_resources,
build != "oss" // generate browser gateway resources on cloud and enterprise
); );
if (traefikConfig?.http?.middlewares) { if (traefikConfig?.http?.middlewares) {
+18
View File
@@ -583,6 +583,24 @@ export default async function migration() {
DELETE FROM "resourceWhitelist" DELETE FROM "resourceWhitelist"
WHERE "resourceId" = ${resource.resourceId} WHERE "resourceId" = ${resource.resourceId}
`); `);
await db.execute(sql`
ALTER TABLE "resourceSessions" ADD COLUMN "policyPasswordId" integer;
`);
await db.execute(sql`
ALTER TABLE "resourceSessions" ADD COLUMN "policyPincodeId" integer;
`);
await db.execute(sql`
ALTER TABLE "resourceSessions" ADD COLUMN "policyWhitelistId" integer;
`);
await db.execute(sql`
ALTER TABLE "resourceSessions" ADD CONSTRAINT "resourceSessions_policyPasswordId_resourcePolicyPassword_passwordId_fk" FOREIGN KEY ("policyPasswordId") REFERENCES "public"."resourcePolicyPassword"("passwordId") ON DELETE cascade ON UPDATE no action;
`);
await db.execute(sql`
ALTER TABLE "resourceSessions" ADD CONSTRAINT "resourceSessions_policyPincodeId_resourcePolicyPincode_pincodeId_fk" FOREIGN KEY ("policyPincodeId") REFERENCES "public"."resourcePolicyPincode"("pincodeId") ON DELETE cascade ON UPDATE no action;
`);
await db.execute(sql`
ALTER TABLE "resourceSessions" ADD CONSTRAINT "resourceSessions_policyWhitelistId_resourcePolicyWhitelist_id_fk" FOREIGN KEY ("policyWhitelistId") REFERENCES "public"."resourcePolicyWhitelist"("id") ON DELETE cascade ON UPDATE no action;
`);
} }
await db.execute(sql`COMMIT`); await db.execute(sql`COMMIT`);
+15
View File
@@ -337,6 +337,21 @@ export default async function migration() {
ALTER TABLE 'sites' ADD 'autoUpdateOverrideOrg' integer DEFAULT false NOT NULL; ALTER TABLE 'sites' ADD 'autoUpdateOverrideOrg' integer DEFAULT false NOT NULL;
` `
).run(); ).run();
db.prepare(
`
ALTER TABLE 'resourceSessions' ADD 'policyPasswordId' integer REFERENCES resourcePolicyPassword(passwordId);
`
).run();
db.prepare(
`
ALTER TABLE 'resourceSessions' ADD 'policyPincodeId' integer REFERENCES resourcePolicyPincode(pincodeId);
`
).run();
db.prepare(
`
ALTER TABLE 'resourceSessions' ADD 'policyWhitelistId' integer REFERENCES resourcePolicyWhitelist(id);
`
).run();
})(); })();
const existingResources = db const existingResources = db