Merge branch 'fosrl:main' into webauth

This commit is contained in:
Marvin
2025-09-22 12:36:06 +02:00
committed by GitHub
16 changed files with 221 additions and 107 deletions

View File

@@ -138,12 +138,8 @@ export async function updateProxyResources(
? true
: resourceData.ssl;
let headers = "";
for (const header of resourceData.headers || []) {
headers += `${header.name}: ${header.value},`;
}
// if there are headers, remove the trailing comma
if (headers.endsWith(",")) {
headers = headers.slice(0, -1);
if (resourceData.headers) {
headers = JSON.stringify(resourceData.headers);
}
if (existingResource) {
@@ -169,7 +165,7 @@ export async function updateProxyResources(
.update(resources)
.set({
name: resourceData.name || "Unnamed Resource",
protocol: protocol || "http",
protocol: protocol || "tcp",
http: http,
proxyPort: http ? null : resourceData["proxy-port"],
fullDomain: http ? resourceData["full-domain"] : null,
@@ -461,7 +457,7 @@ export async function updateProxyResources(
orgId,
niceId: resourceNiceId,
name: resourceData.name || "Unnamed Resource",
protocol: resourceData.protocol || "http",
protocol: protocol || "tcp",
http: http,
proxyPort: http ? null : resourceData["proxy-port"],
fullDomain: http ? resourceData["full-domain"] : null,

View File

@@ -2,7 +2,7 @@ import path from "path";
import { fileURLToPath } from "url";
// This is a placeholder value replaced by the build process
export const APP_VERSION = "1.10.1";
export const APP_VERSION = "1.10.2";
export const __FILENAME = fileURLToPath(import.meta.url);
export const __DIRNAME = path.dirname(__FILENAME);

View File

@@ -15,7 +15,7 @@ export async function addTargets(
}:${target.port}`;
});
sendToClient(newtId, {
await sendToClient(newtId, {
type: `newt/${protocol}/add`,
data: {
targets: payloadTargets

View File

@@ -319,26 +319,6 @@ async function createRawResource(
const { name, http, protocol, proxyPort } = parsedBody.data;
// if http is false check to see if there is already a resource with the same port and protocol
const existingResource = await db
.select()
.from(resources)
.where(
and(
eq(resources.protocol, protocol),
eq(resources.proxyPort, proxyPort!)
)
);
if (existingResource.length > 0) {
return next(
createHttpError(
HttpCode.CONFLICT,
"Resource with that protocol and port already exists"
)
);
}
let resource: Resource | undefined;
const niceId = await getUniqueResourceName(orgId);

View File

@@ -42,7 +42,9 @@ async function query(resourceId?: number, niceId?: string, orgId?: string) {
}
}
export type GetResourceResponse = NonNullable<Awaited<ReturnType<typeof query>>>;
export type GetResourceResponse = Omit<NonNullable<Awaited<ReturnType<typeof query>>>, 'headers'> & {
headers: { name: string; value: string }[] | null;
};
registry.registerPath({
method: "get",
@@ -99,7 +101,10 @@ export async function getResource(
}
return response<GetResourceResponse>(res, {
data: resource,
data: {
...resource,
headers: resource.headers ? JSON.parse(resource.headers) : resource.headers
},
success: true,
error: false,
message: "Resource retrieved successfully",

View File

@@ -47,7 +47,7 @@ const updateHttpResourceBodySchema = z
tlsServerName: z.string().nullable().optional(),
setHostHeader: z.string().nullable().optional(),
skipToIdpId: z.number().int().positive().nullable().optional(),
headers: z.string().nullable().optional()
headers: z.array(z.object({ name: z.string(), value: z.string() })).optional(),
})
.strict()
.refine((data) => Object.keys(data).length > 0, {
@@ -85,18 +85,6 @@ const updateHttpResourceBodySchema = z
message:
"Invalid custom Host Header value. Use domain name format, or save empty to unset custom Host Header."
}
)
.refine(
(data) => {
if (data.headers) {
return validateHeaders(data.headers);
}
return true;
},
{
message:
"Invalid headers format. Use comma-separated format: 'Header-Name: value, Another-Header: another-value'. Header values cannot contain colons."
}
);
export type UpdateResourceResponse = Resource;
@@ -292,9 +280,14 @@ async function updateHttpResource(
updateData.subdomain = finalSubdomain;
}
let headers = null;
if (updateData.headers) {
headers = JSON.stringify(updateData.headers);
}
const updatedResource = await db
.update(resources)
.set({ ...updateData })
.set({ ...updateData, headers })
.where(eq(resources.resourceId, resource.resourceId))
.returning();
@@ -342,31 +335,6 @@ async function updateRawResource(
const updateData = parsedBody.data;
if (updateData.proxyPort) {
const proxyPort = updateData.proxyPort;
const existingResource = await db
.select()
.from(resources)
.where(
and(
eq(resources.protocol, resource.protocol),
eq(resources.proxyPort, proxyPort!)
)
);
if (
existingResource.length > 0 &&
existingResource[0].resourceId !== resource.resourceId
) {
return next(
createHttpError(
HttpCode.CONFLICT,
"Resource with that protocol and port already exists"
)
);
}
}
const updatedResource = await db
.update(resources)
.set(updateData)

View File

@@ -306,17 +306,25 @@ export async function getTraefikConfig(
...additionalMiddlewares
];
if (resource.headers && resource.headers.length > 0) {
if (resource.headers || resource.setHostHeader) {
// if there are headers, parse them into an object
const headersObj: { [key: string]: string } = {};
const headersArr = resource.headers.split(",");
for (const header of headersArr) {
const [key, value] = header
.split(":")
.map((s: string) => s.trim());
if (key && value) {
headersObj[key] = value;
if (resource.headers) {
let headersArr: { name: string; value: string }[] = [];
try {
headersArr = JSON.parse(resource.headers) as {
name: string;
value: string;
}[];
} catch (e) {
logger.warn(
`Failed to parse headers for resource ${resource.resourceId}: ${e}`
);
}
headersArr.forEach((header) => {
headersObj[header.name] = header.value;
});
}
if (resource.setHostHeader) {

View File

@@ -10,6 +10,7 @@ import m2 from "./scriptsPg/1.7.0";
import m3 from "./scriptsPg/1.8.0";
import m4 from "./scriptsPg/1.9.0";
import m5 from "./scriptsPg/1.10.0";
import m6 from "./scriptsPg/1.10.2";
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
// EXCEPT FOR THE DATABASE AND THE SCHEMA
@@ -21,6 +22,7 @@ const migrations = [
{ version: "1.8.0", run: m3 },
{ version: "1.9.0", run: m4 },
{ version: "1.10.0", run: m5 },
{ version: "1.10.2", run: m6 },
// Add new migrations here as they are created
] as {
version: string;

View File

@@ -28,6 +28,7 @@ import m23 from "./scriptsSqlite/1.8.0";
import m24 from "./scriptsSqlite/1.9.0";
import m25 from "./scriptsSqlite/1.10.0";
import m26 from "./scriptsSqlite/1.10.1";
import m27 from "./scriptsSqlite/1.10.2";
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
// EXCEPT FOR THE DATABASE AND THE SCHEMA
@@ -55,6 +56,7 @@ const migrations = [
{ version: "1.9.0", run: m24 },
{ version: "1.10.0", run: m25 },
{ version: "1.10.1", run: m26 },
{ version: "1.10.2", run: m27 },
// Add new migrations here as they are created
] as const;

View File

@@ -0,0 +1,47 @@
import { db } from "@server/db/pg/driver";
import { sql } from "drizzle-orm";
import { __DIRNAME, APP_PATH } from "@server/lib/consts";
const version = "1.10.2";
export default async function migration() {
console.log(`Running setup script ${version}...`);
try {
const resources = await db.execute(sql`
SELECT * FROM "resources"
`);
await db.execute(sql`BEGIN`);
for (const resource of resources.rows) {
const headers = resource.headers as string | null;
if (headers && headers !== "") {
// lets convert it to json
// fist split at commas
const headersArray = headers
.split(",")
.map((header: string) => {
const [name, ...valueParts] = header.split(":");
const value = valueParts.join(":").trim();
return { name: name.trim(), value };
});
await db.execute(sql`
UPDATE "resources" SET "headers" = ${JSON.stringify(headersArray)} WHERE "resourceId" = ${resource.resourceId}
`);
console.log(
`Updated resource ${resource.resourceId} headers to JSON format`
);
}
}
await db.execute(sql`COMMIT`);
console.log(`Migrated database`);
} catch (e) {
await db.execute(sql`ROLLBACK`);
console.log("Failed to migrate db:", e);
throw e;
}
}

View File

@@ -66,4 +66,4 @@ DROP TABLE "targets_old";`);
console.log("Failed to migrate db:", e);
throw e;
}
}
}

View File

@@ -0,0 +1,54 @@
import { APP_PATH } from "@server/lib/consts";
import Database from "better-sqlite3";
import path from "path";
const version = "1.10.2";
export default async function migration() {
console.log(`Running setup script ${version}...`);
const location = path.join(APP_PATH, "db", "db.sqlite");
const db = new Database(location);
const resources = db.prepare("SELECT * FROM resources").all() as Array<{
resourceId: number;
headers: string | null;
}>;
try {
db.pragma("foreign_keys = OFF");
db.transaction(() => {
for (const resource of resources) {
const headers = resource.headers;
if (headers && headers !== "") {
// lets convert it to json
// fist split at commas
const headersArray = headers
.split(",")
.map((header: string) => {
const [name, ...valueParts] = header.split(":");
const value = valueParts.join(":").trim();
return { name: name.trim(), value };
});
db.prepare(
`
UPDATE "resources" SET "headers" = ? WHERE "resourceId" = ?`
).run(JSON.stringify(headersArray), resource.resourceId);
console.log(
`Updated resource ${resource.resourceId} headers to JSON format`
);
}
}
})();
db.pragma("foreign_keys = ON");
console.log(`Migrated database`);
} catch (e) {
console.log("Failed to migrate db:", e);
throw e;
}
}