removed redirect feature

This commit is contained in:
fuomag9
2026-02-13 22:53:11 +01:00
parent 78309e8435
commit 7e4df5e50b
11 changed files with 11 additions and 886 deletions

View File

@@ -8,8 +8,7 @@ import { syncInstances } from "./instance-sync";
import {
accessListEntries,
certificates,
proxyHosts,
redirectHosts
proxyHosts
} from "./db/schema";
const CERTS_DIR = process.env.CERTS_DIRECTORY || join(process.cwd(), "data", "certs");
@@ -144,16 +143,6 @@ type LoadBalancerRouteConfig = {
} | null;
};
type RedirectHostRow = {
id: number;
name: string;
domains: string;
destination: string;
status_code: number;
preserve_query: number;
enabled: number;
};
type AccessListEntryRow = {
access_list_id: number;
username: string;
@@ -688,30 +677,6 @@ function buildProxyRoutes(
return routes;
}
function buildRedirectRoutes(rows: RedirectHostRow[]): CaddyHttpRoute[] {
return rows
.filter((row) => Boolean(row.enabled))
.map((row) => {
const domains = parseJson<string[]>(row.domains, []);
const preserveQuery = Boolean(row.preserve_query);
const location = preserveQuery ? `${row.destination}{uri}` : row.destination;
return {
match: [{ host: domains }],
handle: [
{
handler: "static_response",
status_code: row.status_code,
headers: {
Location: [location],
"Strict-Transport-Security": ["max-age=63072000"]
}
}
],
terminal: true
};
});
}
function buildTlsConnectionPolicies(
usage: Map<number, CertificateUsage>,
managedCertificatesWithAutomation: Set<number>,
@@ -907,7 +872,7 @@ async function buildTlsAutomation(
}
async function buildCaddyDocument() {
const [proxyHostRecords, redirectHostRecords, certRows, accessListEntryRecords] = await Promise.all([
const [proxyHostRecords, certRows, accessListEntryRecords] = await Promise.all([
db
.select({
id: proxyHosts.id,
@@ -926,17 +891,6 @@ async function buildCaddyDocument() {
enabled: proxyHosts.enabled
})
.from(proxyHosts),
db
.select({
id: redirectHosts.id,
name: redirectHosts.name,
domains: redirectHosts.domains,
destination: redirectHosts.destination,
statusCode: redirectHosts.statusCode,
preserveQuery: redirectHosts.preserveQuery,
enabled: redirectHosts.enabled
})
.from(redirectHosts),
db
.select({
id: certificates.id,
@@ -975,16 +929,6 @@ async function buildCaddyDocument() {
enabled: h.enabled ? 1 : 0
}));
const redirectHostRows: RedirectHostRow[] = redirectHostRecords.map((h) => ({
id: h.id,
name: h.name,
domains: h.domains,
destination: h.destination,
status_code: h.statusCode,
preserve_query: h.preserveQuery ? 1 : 0,
enabled: h.enabled ? 1 : 0
}));
const certRowsMapped: CertificateRow[] = certRows.map((c: typeof certRows[0]) => ({
id: c.id,
name: c.name,
@@ -1023,8 +967,7 @@ async function buildCaddyDocument() {
);
const httpRoutes: CaddyHttpRoute[] = [
...buildProxyRoutes(proxyHostRows, accessMap, readyCertificates, autoManagedDomains),
...buildRedirectRoutes(redirectHostRows)
...buildProxyRoutes(proxyHostRows, accessMap, readyCertificates, autoManagedDomains)
];
const hasTls = tlsConnectionPolicies.length > 0;

View File

@@ -150,19 +150,6 @@ export const proxyHosts = sqliteTable("proxy_hosts", {
.default(false)
});
export const redirectHosts = sqliteTable("redirect_hosts", {
id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(),
domains: text("domains").notNull(),
destination: text("destination").notNull(),
statusCode: integer("status_code").notNull().default(302),
preserveQuery: integer("preserve_query", { mode: "boolean" }).notNull().default(true),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
createdBy: integer("created_by").references(() => users.id, { onDelete: "set null" }),
createdAt: text("created_at").notNull(),
updatedAt: text("updated_at").notNull()
});
export const apiTokens = sqliteTable(
"api_tokens",
{

View File

@@ -1,5 +1,5 @@
import db, { nowIso } from "./db";
import { accessListEntries, accessLists, certificates, proxyHosts, redirectHosts } from "./db/schema";
import { accessListEntries, accessLists, certificates, proxyHosts } from "./db/schema";
import { getSetting, setSetting } from "./settings";
import { recordInstanceSyncResult, updateInstance } from "./models/instances";
import { decryptSecret, encryptSecret, isEncryptedSecret } from "./secret";
@@ -23,7 +23,6 @@ export type SyncPayload = {
accessLists: Array<typeof accessLists.$inferSelect>;
accessListEntries: Array<typeof accessListEntries.$inferSelect>;
proxyHosts: Array<typeof proxyHosts.$inferSelect>;
redirectHosts: Array<typeof redirectHosts.$inferSelect>;
};
};
@@ -229,12 +228,11 @@ export async function clearSyncedSetting(key: string): Promise<void> {
}
export async function buildSyncPayload(): Promise<SyncPayload> {
const [certRows, accessListRows, accessEntryRows, proxyRows, redirectRows] = await Promise.all([
const [certRows, accessListRows, accessEntryRows, proxyRows] = await Promise.all([
db.select().from(certificates),
db.select().from(accessLists),
db.select().from(accessListEntries),
db.select().from(proxyHosts),
db.select().from(redirectHosts)
db.select().from(proxyHosts)
]);
const settings = {
@@ -256,11 +254,6 @@ export async function buildSyncPayload(): Promise<SyncPayload> {
createdBy: null
}));
const sanitizedRedirects = redirectRows.map((row) => ({
...row,
createdBy: null
}));
const sanitizedProxyHosts = proxyRows.map((row) => ({
...row,
ownerUserId: null
@@ -273,8 +266,7 @@ export async function buildSyncPayload(): Promise<SyncPayload> {
certificates: sanitizedCertificates,
accessLists: sanitizedAccessLists,
accessListEntries: accessEntryRows,
proxyHosts: sanitizedProxyHosts,
redirectHosts: sanitizedRedirects
proxyHosts: sanitizedProxyHosts
}
};
}
@@ -407,7 +399,6 @@ export async function applySyncPayload(payload: SyncPayload) {
// better-sqlite3 is synchronous, so transaction callback must be synchronous
db.transaction((tx) => {
tx.delete(proxyHosts).run();
tx.delete(redirectHosts).run();
tx.delete(accessListEntries).run();
tx.delete(accessLists).run();
tx.delete(certificates).run();
@@ -424,8 +415,5 @@ export async function applySyncPayload(payload: SyncPayload) {
if (payload.data.proxyHosts.length > 0) {
tx.insert(proxyHosts).values(payload.data.proxyHosts).run();
}
if (payload.data.redirectHosts.length > 0) {
tx.insert(redirectHosts).values(payload.data.redirectHosts).run();
}
});
}

View File

@@ -1,139 +0,0 @@
import db, { nowIso, toIso } from "../db";
import { logAuditEvent } from "../audit";
import { applyCaddyConfig } from "../caddy";
import { redirectHosts } from "../db/schema";
import { desc, eq } from "drizzle-orm";
export type RedirectHost = {
id: number;
name: string;
domains: string[];
destination: string;
status_code: number;
preserve_query: boolean;
enabled: boolean;
created_at: string;
updated_at: string;
};
export type RedirectHostInput = {
name: string;
domains: string[];
destination: string;
status_code?: number;
preserve_query?: boolean;
enabled?: boolean;
};
type RedirectHostRow = typeof redirectHosts.$inferSelect;
function parseDbRecord(record: RedirectHostRow): RedirectHost {
return {
id: record.id,
name: record.name,
domains: JSON.parse(record.domains),
destination: record.destination,
status_code: record.statusCode,
preserve_query: record.preserveQuery,
enabled: record.enabled,
created_at: toIso(record.createdAt)!,
updated_at: toIso(record.updatedAt)!
};
}
export async function listRedirectHosts(): Promise<RedirectHost[]> {
const records = await db.select().from(redirectHosts).orderBy(desc(redirectHosts.createdAt));
return records.map(parseDbRecord);
}
export async function getRedirectHost(id: number): Promise<RedirectHost | null> {
const record = await db.query.redirectHosts.findFirst({
where: (table, { eq }) => eq(table.id, id)
});
return record ? parseDbRecord(record) : null;
}
export async function createRedirectHost(input: RedirectHostInput, actorUserId: number) {
if (!input.domains || input.domains.length === 0) {
throw new Error("At least one domain is required");
}
const now = nowIso();
const [record] = await db
.insert(redirectHosts)
.values({
name: input.name.trim(),
domains: JSON.stringify(Array.from(new Set(input.domains.map((d) => d.trim().toLowerCase())))),
destination: input.destination.trim(),
statusCode: input.status_code ?? 302,
preserveQuery: input.preserve_query ?? true,
enabled: input.enabled ?? true,
createdAt: now,
updatedAt: now,
createdBy: actorUserId
})
.returning();
if (!record) {
throw new Error("Failed to create redirect host");
}
logAuditEvent({
userId: actorUserId,
action: "create",
entityType: "redirect_host",
entityId: record.id,
summary: `Created redirect ${input.name}`
});
await applyCaddyConfig();
return (await getRedirectHost(record.id))!;
}
export async function updateRedirectHost(id: number, input: Partial<RedirectHostInput>, actorUserId: number) {
const existing = await getRedirectHost(id);
if (!existing) {
throw new Error("Redirect host not found");
}
const now = nowIso();
await db
.update(redirectHosts)
.set({
name: input.name ?? existing.name,
domains: input.domains ? JSON.stringify(Array.from(new Set(input.domains))) : JSON.stringify(existing.domains),
destination: input.destination ?? existing.destination,
statusCode: input.status_code ?? existing.status_code,
preserveQuery: input.preserve_query ?? existing.preserve_query,
enabled: input.enabled ?? existing.enabled,
updatedAt: now
})
.where(eq(redirectHosts.id, id));
logAuditEvent({
userId: actorUserId,
action: "update",
entityType: "redirect_host",
entityId: id,
summary: `Updated redirect ${input.name ?? existing.name}`
});
await applyCaddyConfig();
return (await getRedirectHost(id))!;
}
export async function deleteRedirectHost(id: number, actorUserId: number) {
const existing = await getRedirectHost(id);
if (!existing) {
throw new Error("Redirect host not found");
}
await db.delete(redirectHosts).where(eq(redirectHosts.id, id));
logAuditEvent({
userId: actorUserId,
action: "delete",
entityType: "redirect_host",
entityId: id,
summary: `Deleted redirect ${existing.name}`
});
await applyCaddyConfig();
}