removed redirect feature
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user