mirror of
https://github.com/fosrl/pangolin.git
synced 2026-03-08 03:36:37 +00:00
add missing path / validation
This commit is contained in:
@@ -108,13 +108,13 @@ function validatePathRewriteConfig(
|
|||||||
return { isValid: true };
|
return { isValid: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((rewritePath && !rewritePathType) || (!rewritePath && rewritePathType)) {
|
if (rewritePathType !== "stripPrefix") {
|
||||||
return {
|
if ((rewritePath && !rewritePathType) || (!rewritePath && rewritePathType)) {
|
||||||
isValid: false,
|
return { isValid: false, error: "Both rewritePath and rewritePathType must be specified together" };
|
||||||
error: "Both rewritePath and rewritePathType must be specified together"
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!rewritePath || !rewritePathType) {
|
if (!rewritePath || !rewritePathType) {
|
||||||
return { isValid: true };
|
return { isValid: true };
|
||||||
}
|
}
|
||||||
@@ -146,26 +146,12 @@ function validatePathRewriteConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate path formats for non-regex types
|
|
||||||
if (pathMatchType !== "regex" && !path.startsWith("/")) {
|
|
||||||
return {
|
|
||||||
isValid: false,
|
|
||||||
error: "Path must start with '/' for exact and prefix matching"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Additional validation for stripPrefix
|
// Additional validation for stripPrefix
|
||||||
if (rewritePathType === "stripPrefix") {
|
if (rewritePathType === "stripPrefix") {
|
||||||
if (pathMatchType !== "prefix") {
|
if (pathMatchType !== "prefix") {
|
||||||
logger.warn(`stripPrefix rewrite type is most effective with prefix path matching. Current match type: ${pathMatchType}`);
|
logger.warn(`stripPrefix rewrite type is most effective with prefix path matching. Current match type: ${pathMatchType}`);
|
||||||
}
|
}
|
||||||
// For stripPrefix, rewritePath is optional (can be empty to just strip)
|
|
||||||
if (rewritePath && !rewritePath.startsWith("/") && rewritePath !== "") {
|
|
||||||
return {
|
|
||||||
isValid: false,
|
|
||||||
error: "stripPrefix rewritePath must start with '/' or be empty"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { isValid: true };
|
return { isValid: true };
|
||||||
@@ -181,6 +167,14 @@ function createPathRewriteMiddleware(
|
|||||||
): { middlewares: { [key: string]: any }; chain?: string[] } {
|
): { middlewares: { [key: string]: any }; chain?: string[] } {
|
||||||
const middlewares: { [key: string]: any } = {};
|
const middlewares: { [key: string]: any } = {};
|
||||||
|
|
||||||
|
if (pathMatchType !== "regex" && !path.startsWith("/")) {
|
||||||
|
path = `/${path}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rewritePathType !== "regex" && rewritePath !== "" && !rewritePath.startsWith("/")) {
|
||||||
|
rewritePath = `/${rewritePath}`;
|
||||||
|
}
|
||||||
|
|
||||||
switch (rewritePathType) {
|
switch (rewritePathType) {
|
||||||
case "exact":
|
case "exact":
|
||||||
// Replace the path with the exact rewrite path
|
// Replace the path with the exact rewrite path
|
||||||
@@ -260,9 +254,9 @@ function createPathRewriteMiddleware(
|
|||||||
prefix: rewritePath
|
prefix: rewritePath
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
middlewares,
|
middlewares,
|
||||||
chain: [middlewareName, addPrefixMiddlewareName]
|
chain: [middlewareName, addPrefixMiddlewareName]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -387,7 +381,7 @@ export async function getTraefikConfig(
|
|||||||
|
|
||||||
if (!validation.isValid) {
|
if (!validation.isValid) {
|
||||||
logger.error(`Invalid path rewrite configuration for resource ${resourceId}: ${validation.error}`);
|
logger.error(`Invalid path rewrite configuration for resource ${resourceId}: ${validation.error}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
resourcesMap.set(mapKey, {
|
resourcesMap.set(mapKey, {
|
||||||
@@ -520,8 +514,8 @@ export async function getTraefikConfig(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const additionalMiddlewares =
|
const additionalMiddlewares =
|
||||||
config.getRawConfig().traefik.additional_middlewares || [];
|
config.getRawConfig().traefik.additional_middlewares || [];
|
||||||
|
|
||||||
const routerMiddlewares = [
|
const routerMiddlewares = [
|
||||||
badgerMiddlewareName,
|
badgerMiddlewareName,
|
||||||
@@ -529,14 +523,14 @@ export async function getTraefikConfig(
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Handle path rewriting middleware
|
// Handle path rewriting middleware
|
||||||
if (resource.rewritePath &&
|
if (resource.rewritePath &&
|
||||||
resource.path &&
|
resource.path &&
|
||||||
resource.pathMatchType &&
|
resource.pathMatchType &&
|
||||||
resource.rewritePathType) {
|
resource.rewritePathType) {
|
||||||
|
|
||||||
// Create a unique middleware name
|
// Create a unique middleware name
|
||||||
const rewriteMiddlewareName = `rewrite-r${resource.resourceId}-${sanitizeForMiddlewareName(key)}`;
|
const rewriteMiddlewareName = `rewrite-r${resource.resourceId}-${sanitizeForMiddlewareName(key)}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const rewriteResult = createPathRewriteMiddleware(
|
const rewriteResult = createPathRewriteMiddleware(
|
||||||
rewriteMiddlewareName,
|
rewriteMiddlewareName,
|
||||||
@@ -572,7 +566,7 @@ export async function getTraefikConfig(
|
|||||||
// Handle custom headers middleware
|
// Handle custom headers middleware
|
||||||
if (resource.headers || resource.setHostHeader) {
|
if (resource.headers || resource.setHostHeader) {
|
||||||
const headersObj: { [key: string]: string } = {};
|
const headersObj: { [key: string]: string } = {};
|
||||||
|
|
||||||
if (resource.headers) {
|
if (resource.headers) {
|
||||||
let headersArr: { name: string; value: string }[] = [];
|
let headersArr: { name: string; value: string }[] = [];
|
||||||
try {
|
try {
|
||||||
@@ -668,15 +662,15 @@ export async function getTraefikConfig(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
(targets as TargetWithSite[])
|
(targets as TargetWithSite[])
|
||||||
.filter((target: TargetWithSite) => {
|
.filter((target: TargetWithSite) => {
|
||||||
if (!target.enabled) {
|
if (!target.enabled) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any sites are online, exclude offline sites
|
// If any sites are online, exclude offline sites
|
||||||
if (anySitesOnline && !target.site.online) {
|
if (anySitesOnline && !target.site.online) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
target.site.type === "local" ||
|
target.site.type === "local" ||
|
||||||
@@ -689,33 +683,33 @@ export async function getTraefikConfig(
|
|||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (target.site.type === "newt") {
|
} else if (target.site.type === "newt") {
|
||||||
if (
|
if (
|
||||||
!target.internalPort ||
|
!target.internalPort ||
|
||||||
!target.method ||
|
!target.method ||
|
||||||
!target.site.subnet
|
!target.site.subnet
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.map((target: TargetWithSite) => {
|
.map((target: TargetWithSite) => {
|
||||||
if (
|
if (
|
||||||
target.site.type === "local" ||
|
target.site.type === "local" ||
|
||||||
target.site.type === "wireguard"
|
target.site.type === "wireguard"
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
url: `${target.method}://${target.ip}:${target.port}`
|
url: `${target.method}://${target.ip}:${target.port}`
|
||||||
};
|
};
|
||||||
} else if (target.site.type === "newt") {
|
} else if (target.site.type === "newt") {
|
||||||
const ip =
|
const ip =
|
||||||
target.site.subnet!.split("/")[0];
|
target.site.subnet!.split("/")[0];
|
||||||
return {
|
return {
|
||||||
url: `${target.method}://${ip}:${target.internalPort}`
|
url: `${target.method}://${ip}:${target.internalPort}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// filter out duplicates
|
// filter out duplicates
|
||||||
.filter(
|
.filter(
|
||||||
(v, i, a) =>
|
(v, i, a) =>
|
||||||
@@ -729,7 +723,7 @@ export async function getTraefikConfig(
|
|||||||
? {
|
? {
|
||||||
sticky: {
|
sticky: {
|
||||||
cookie: {
|
cookie: {
|
||||||
name: "p_sticky", // TODO: make this configurable via config.yml like other cookies
|
name: "p_sticky", // TODO: make this configurable via config.yml like other cookies
|
||||||
secure: resource.ssl,
|
secure: resource.ssl,
|
||||||
httpOnly: true
|
httpOnly: true
|
||||||
}
|
}
|
||||||
@@ -811,7 +805,7 @@ export async function getTraefikConfig(
|
|||||||
!target.internalPort ||
|
!target.internalPort ||
|
||||||
!target.site.subnet
|
!target.site.subnet
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -852,16 +846,16 @@ export async function getTraefikConfig(
|
|||||||
|
|
||||||
function sanitizePath(path: string | null | undefined): string | undefined {
|
function sanitizePath(path: string | null | undefined): string | undefined {
|
||||||
if (!path) return undefined;
|
if (!path) return undefined;
|
||||||
|
|
||||||
const trimmed = path.trim();
|
const trimmed = path.trim();
|
||||||
if (!trimmed) return undefined;
|
if (!trimmed) return undefined;
|
||||||
|
|
||||||
// Preserve path structure for rewriting, only warn if very long
|
// Preserve path structure for rewriting, only warn if very long
|
||||||
if (trimmed.length > 1000) {
|
if (trimmed.length > 1000) {
|
||||||
logger.warn(`Path exceeds 1000 characters: ${trimmed.substring(0, 100)}...`);
|
logger.warn(`Path exceeds 1000 characters: ${trimmed.substring(0, 100)}...`);
|
||||||
return trimmed.substring(0, 1000);
|
return trimmed.substring(0, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user