tangled
alpha
login
or
join now
dunkirk.sh
/
control
0
fork
atom
a control panel for my server
0
fork
atom
overview
issues
pulls
pipelines
feat: add redaction
dunkirk.sh
2 months ago
e431de6f
f7c2ec16
verified
This commit was signed with the committer's
known signature
.
dunkirk.sh
SSH Key Fingerprint:
SHA256:DqcG0RXYExE26KiWo3VxJnsxswN1QNfTBvB+bdSpk80=
+64
2 changed files
expand all
collapse all
unified
split
src
flags.ts
index.ts
+29
src/flags.ts
···
35
35
name: string;
36
36
description: string;
37
37
paths: string[]; // The paths this flag blocks
38
38
+
redact?: Record<string, string[]>; // path -> fields to strip from JSON
38
39
}
39
40
40
41
export interface ServiceDefinition {
···
147
148
148
149
return false;
149
150
}
151
151
+
152
152
+
// Get fields to redact from a JSON response based on host and path
153
153
+
export function getRedactions(host: string, path: string): string[] {
154
154
+
const config = getConfig();
155
155
+
const fields: string[] = [];
156
156
+
157
157
+
for (const [serviceId, service] of Object.entries(config.services)) {
158
158
+
if (!host.includes(serviceId) && !serviceId.includes(host)) {
159
159
+
continue;
160
160
+
}
161
161
+
162
162
+
for (const [flagId, flag] of Object.entries(service.flags)) {
163
163
+
if (!getFlagStatus(flagId)) {
164
164
+
continue;
165
165
+
}
166
166
+
167
167
+
if (flag.redact) {
168
168
+
for (const [redactPath, redactFields] of Object.entries(flag.redact)) {
169
169
+
if (path === redactPath || path.startsWith(redactPath + "?")) {
170
170
+
fields.push(...redactFields);
171
171
+
}
172
172
+
}
173
173
+
}
174
174
+
}
175
175
+
}
176
176
+
177
177
+
return fields;
178
178
+
}
+35
src/index.ts
···
19
19
setFlag,
20
20
getFlagDefinition,
21
21
shouldBlock,
22
22
+
getRedactions,
22
23
} from "./flags";
23
24
24
25
import homepage from "../public/index.html";
···
55
56
}
56
57
57
58
return c.text("OK", 200);
59
59
+
});
60
60
+
61
61
+
// Proxy JSON endpoint and redact configured fields
62
62
+
app.get("/proxy/*", async (c) => {
63
63
+
const host = c.req.header("X-Orig-Host") || c.req.header("Host") || "";
64
64
+
const origPath = c.req.header("X-Orig-Path") || "";
65
65
+
const backendUrl = c.req.header("X-Backend-Url");
66
66
+
67
67
+
if (!backendUrl) {
68
68
+
return c.text("Missing X-Backend-Url header", 400);
69
69
+
}
70
70
+
71
71
+
const res = await fetch(backendUrl);
72
72
+
if (!res.ok) {
73
73
+
return c.text("Backend error", res.status);
74
74
+
}
75
75
+
76
76
+
const data = await res.json();
77
77
+
78
78
+
// Redact fields based on config
79
79
+
const fieldsToRedact = getRedactions(host, origPath);
80
80
+
for (const field of fieldsToRedact) {
81
81
+
if (field in data) {
82
82
+
if (Array.isArray(data[field])) {
83
83
+
data[field] = [];
84
84
+
} else if (typeof data[field] === "object" && data[field] !== null) {
85
85
+
data[field] = {};
86
86
+
} else {
87
87
+
delete data[field];
88
88
+
}
89
89
+
}
90
90
+
}
91
91
+
92
92
+
return c.json(data);
58
93
});
59
94
60
95
app.get("/auth/login", (c) => {