@setzkasten-cms/astro-admin 1.4.6 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-routes/_auth-guard.d.ts +27 -3
- package/dist/api-routes/_auth-guard.js +5 -2
- package/dist/api-routes/_dev-session-secret.d.ts +8 -0
- package/dist/api-routes/_dev-session-secret.js +8 -0
- package/dist/api-routes/_github-token.js +1 -1
- package/dist/api-routes/_role-resolver.js +6 -3
- package/dist/api-routes/_session-secret.d.ts +19 -0
- package/dist/api-routes/_session-secret.js +7 -0
- package/dist/api-routes/_session-signing.d.ts +45 -0
- package/dist/api-routes/_session-signing.js +8 -0
- package/dist/api-routes/_webhook-dispatcher.js +4 -4
- package/dist/api-routes/asset-proxy.js +1 -1
- package/dist/api-routes/auth-callback.js +12 -5
- package/dist/api-routes/auth-logout.d.ts +4 -4
- package/dist/api-routes/auth-logout.js +8 -2
- package/dist/api-routes/auth-session.d.ts +6 -0
- package/dist/api-routes/auth-session.js +19 -19
- package/dist/api-routes/auth-setzkasten-login.js +14 -7
- package/dist/api-routes/catalog-add.js +59 -17
- package/dist/api-routes/catalog-export.js +14 -4
- package/dist/api-routes/config.d.ts +10 -3
- package/dist/api-routes/config.js +26 -4
- package/dist/api-routes/deploy-hook.js +8 -8
- package/dist/api-routes/editors.d.ts +1 -1
- package/dist/api-routes/editors.js +5 -2
- package/dist/api-routes/github-proxy.js +30 -8
- package/dist/api-routes/global-config.js +6 -3
- package/dist/api-routes/history-rollback.js +31 -14
- package/dist/api-routes/history-version.js +8 -6
- package/dist/api-routes/history.js +5 -2
- package/dist/api-routes/icons-local.js +1 -1
- package/dist/api-routes/init-add-section.js +113 -47
- package/dist/api-routes/init-apply.js +56 -42
- package/dist/api-routes/init-migrate.js +43 -36
- package/dist/api-routes/init-scan-page.d.ts +1 -1
- package/dist/api-routes/init-scan-page.js +59 -13
- package/dist/api-routes/init-scan.js +22 -7
- package/dist/api-routes/migrate-to-multi.js +5 -2
- package/dist/api-routes/pages.js +15 -4
- package/dist/api-routes/section-add.js +68 -16
- package/dist/api-routes/section-commit-pending.js +70 -22
- package/dist/api-routes/section-delete.js +49 -14
- package/dist/api-routes/section-duplicate.js +65 -16
- package/dist/api-routes/section-prepare-copy.js +15 -2
- package/dist/api-routes/section-prepare.js +25 -4
- package/dist/api-routes/setup-github-app-bounce.js +15 -1
- package/dist/api-routes/setup-github-app-branches.js +9 -6
- package/dist/api-routes/setup-github-app-callback.js +24 -1
- package/dist/api-routes/setup-github-app-credentials.d.ts +27 -0
- package/dist/api-routes/setup-github-app-credentials.js +43 -0
- package/dist/api-routes/setup-github-app-installed.js +22 -1
- package/dist/api-routes/setup-github-app-repos.js +5 -2
- package/dist/api-routes/setup-github-app.d.ts +4 -0
- package/dist/api-routes/setup-github-app.js +19 -2
- package/dist/api-routes/updater-register.js +7 -1
- package/dist/api-routes/webhooks-status.js +5 -2
- package/dist/api-routes/webhooks-test.js +9 -8
- package/dist/api-routes/webhooks.js +12 -14
- package/dist/api-routes/websites-add.js +5 -2
- package/dist/api-routes/websites-remove.js +5 -2
- package/dist/{chunk-ZQDGGWJP.js → chunk-5KMGSFCZ.js} +2 -2
- package/dist/{chunk-Q3N336KR.js → chunk-CDXCYYQR.js} +29 -24
- package/dist/{chunk-NKDATSPA.js → chunk-DP6RTINQ.js} +1 -1
- package/dist/chunk-KENFINT4.js +76 -0
- package/dist/chunk-ONP6BRZO.js +47 -0
- package/dist/{chunk-INIWFKQ3.js → chunk-Q5HV47DW.js} +33 -19
- package/dist/chunk-QVCW6EF3.js +26 -0
- package/dist/{chunk-TD76R3A6.js → chunk-UHI6323G.js} +293 -174
- package/dist/{chunk-AM4DZXXM.js → chunk-UJAFZEX2.js} +76 -9
- package/package.json +12 -6
- package/src/api-routes/__tests__/_session-signing.test.ts +114 -0
- package/src/api-routes/__tests__/_session-test-helper.ts +27 -0
- package/src/api-routes/__tests__/add-section-helpers.test.ts +59 -25
- package/src/api-routes/__tests__/auth-guard.test.ts +46 -7
- package/src/api-routes/__tests__/catalog-api.test.ts +14 -6
- package/src/api-routes/__tests__/commit-trailers.test.ts +5 -5
- package/src/api-routes/__tests__/deferred-operations.test.ts +9 -12
- package/src/api-routes/__tests__/deploy-hook.test.ts +3 -8
- package/src/api-routes/__tests__/feature-gate.test.ts +1 -1
- package/src/api-routes/__tests__/github-cache.test.ts +1 -1
- package/src/api-routes/__tests__/github-token.test.ts +1 -1
- package/src/api-routes/__tests__/global-config-theme.test.ts +4 -4
- package/src/api-routes/__tests__/history-rollback.test.ts +6 -3
- package/src/api-routes/__tests__/history.test.ts +9 -6
- package/src/api-routes/__tests__/init-scan-page-resolve-config.test.ts +11 -3
- package/src/api-routes/__tests__/migrate-to-multi.test.ts +5 -1
- package/src/api-routes/__tests__/pages-meta-store.test.ts +10 -5
- package/src/api-routes/__tests__/pages.test.ts +7 -2
- package/src/api-routes/__tests__/patch-page-file.test.ts +71 -19
- package/src/api-routes/__tests__/route-registry.test.ts +11 -18
- package/src/api-routes/__tests__/scan-page-helpers.test.ts +13 -10
- package/src/api-routes/__tests__/section-management.test.ts +28 -28
- package/src/api-routes/__tests__/setup-github-app-callback.test.ts +58 -16
- package/src/api-routes/__tests__/setup-github-app-repos.test.ts +4 -5
- package/src/api-routes/__tests__/setup-github-app.test.ts +27 -7
- package/src/api-routes/__tests__/storage-config-for-request.test.ts +83 -0
- package/src/api-routes/__tests__/updater-register.test.ts +230 -0
- package/src/api-routes/__tests__/webhook-signing.test.ts +1 -1
- package/src/api-routes/__tests__/webhooks.test.ts +19 -7
- package/src/api-routes/__tests__/websites-add.test.ts +2 -1
- package/src/api-routes/__tests__/websites-remove.test.ts +2 -1
- package/src/api-routes/_auth-guard.ts +47 -15
- package/src/api-routes/_commit-trailers.ts +3 -2
- package/src/api-routes/_dev-session-secret.ts +79 -0
- package/src/api-routes/_github-token.ts +1 -1
- package/src/api-routes/_pages-meta-store.ts +2 -2
- package/src/api-routes/_role-resolver.ts +7 -5
- package/src/api-routes/_session-secret.ts +46 -0
- package/src/api-routes/_session-signing.ts +135 -0
- package/src/api-routes/_vercel-origin.ts +2 -6
- package/src/api-routes/_webhook-dispatcher.ts +12 -16
- package/src/api-routes/_website-resolver.ts +3 -10
- package/src/api-routes/auth-callback.ts +9 -5
- package/src/api-routes/auth-login.ts +5 -3
- package/src/api-routes/auth-logout.ts +18 -1
- package/src/api-routes/auth-session.ts +13 -21
- package/src/api-routes/auth-setzkasten-login.ts +12 -9
- package/src/api-routes/catalog-add.ts +89 -31
- package/src/api-routes/catalog-export.ts +30 -10
- package/src/api-routes/config.ts +39 -6
- package/src/api-routes/deploy-hook.ts +13 -11
- package/src/api-routes/editors.ts +33 -22
- package/src/api-routes/github-proxy.ts +25 -11
- package/src/api-routes/global-config.ts +103 -18
- package/src/api-routes/history-rollback.ts +41 -14
- package/src/api-routes/history-version.ts +5 -6
- package/src/api-routes/history.ts +3 -3
- package/src/api-routes/icons-local.ts +2 -2
- package/src/api-routes/init-add-section.ts +174 -79
- package/src/api-routes/init-apply.ts +71 -56
- package/src/api-routes/init-migrate.ts +54 -48
- package/src/api-routes/init-scan-page.ts +77 -30
- package/src/api-routes/init-scan.ts +19 -11
- package/src/api-routes/pages.ts +16 -11
- package/src/api-routes/section-add.ts +98 -27
- package/src/api-routes/section-commit-pending.ts +87 -34
- package/src/api-routes/section-delete.ts +76 -27
- package/src/api-routes/section-duplicate.ts +95 -28
- package/src/api-routes/section-management.ts +3 -7
- package/src/api-routes/section-prepare-copy.ts +29 -8
- package/src/api-routes/section-prepare.ts +38 -10
- package/src/api-routes/setup-github-app-bounce.ts +7 -1
- package/src/api-routes/setup-github-app-branches.ts +6 -7
- package/src/api-routes/setup-github-app-callback.ts +18 -1
- package/src/api-routes/setup-github-app-credentials.ts +55 -0
- package/src/api-routes/setup-github-app-installed.ts +12 -1
- package/src/api-routes/setup-github-app-repos.ts +2 -3
- package/src/api-routes/setup-github-app.ts +14 -5
- package/src/api-routes/updater-check.ts +6 -4
- package/src/api-routes/updater-register.ts +34 -20
- package/src/api-routes/updater-transfer.ts +8 -6
- package/src/api-routes/updater-unbind.ts +14 -10
- package/src/api-routes/webhooks-test.ts +9 -11
- package/src/api-routes/webhooks.ts +15 -19
- package/src/init/__tests__/page-level.test.ts +279 -105
- package/src/init/__tests__/page-list-coverage.test.ts +70 -70
- package/src/init/__tests__/patcher-child-component.test.ts +12 -3
- package/src/init/__tests__/patcher-edge-cases.test.ts +47 -23
- package/src/init/__tests__/patcher-mixed-content-wrapper.test.ts +16 -6
- package/src/init/__tests__/patcher-page-mode.test.ts +30 -20
- package/src/init/__tests__/section-pipeline.test.ts +53 -19
- package/src/init/astro-config-patcher.ts +4 -18
- package/src/init/astro-detector.ts +2 -7
- package/src/init/astro-section-analyzer-v2.ts +475 -193
- package/src/init/field-label-enricher.ts +6 -6
- package/src/init/template-patcher-v2.ts +218 -97
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requireAdmin
|
|
3
|
+
} from "../chunk-Q5HV47DW.js";
|
|
4
|
+
import "../chunk-QVCW6EF3.js";
|
|
5
|
+
import "../chunk-KENFINT4.js";
|
|
6
|
+
import "../chunk-6UIKVKED.js";
|
|
7
|
+
import "../chunk-ONP6BRZO.js";
|
|
8
|
+
import "../chunk-5PIMDP4N.js";
|
|
9
|
+
import "../chunk-45ARVNT3.js";
|
|
10
|
+
import "../chunk-DP6RTINQ.js";
|
|
11
|
+
import "../chunk-TJNJKPUL.js";
|
|
12
|
+
import "../chunk-KH22FJO5.js";
|
|
13
|
+
|
|
14
|
+
// src/api-routes/setup-github-app-credentials.ts
|
|
15
|
+
var COOKIE_NAME = "sk_app_setup";
|
|
16
|
+
var GET = async ({ cookies }) => {
|
|
17
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
18
|
+
if (denied) return denied;
|
|
19
|
+
const raw = cookies.get(COOKIE_NAME)?.value;
|
|
20
|
+
if (!raw) {
|
|
21
|
+
return Response.json({ available: false }, { status: 404 });
|
|
22
|
+
}
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = JSON.parse(raw);
|
|
26
|
+
} catch {
|
|
27
|
+
return Response.json({ available: false, error: "malformed" }, { status: 500 });
|
|
28
|
+
}
|
|
29
|
+
if (!parsed || typeof parsed !== "object") {
|
|
30
|
+
return Response.json({ available: false }, { status: 404 });
|
|
31
|
+
}
|
|
32
|
+
return Response.json({ available: true, credentials: parsed });
|
|
33
|
+
};
|
|
34
|
+
var DELETE = async ({ cookies }) => {
|
|
35
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
36
|
+
if (denied) return denied;
|
|
37
|
+
cookies.delete(COOKIE_NAME, { path: "/" });
|
|
38
|
+
return Response.json({ ok: true });
|
|
39
|
+
};
|
|
40
|
+
export {
|
|
41
|
+
DELETE,
|
|
42
|
+
GET
|
|
43
|
+
};
|
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPublicOrigin
|
|
3
3
|
} from "../chunk-5ZFTG4BW.js";
|
|
4
|
+
import {
|
|
5
|
+
requireAdmin
|
|
6
|
+
} from "../chunk-Q5HV47DW.js";
|
|
7
|
+
import "../chunk-QVCW6EF3.js";
|
|
8
|
+
import "../chunk-KENFINT4.js";
|
|
9
|
+
import "../chunk-6UIKVKED.js";
|
|
10
|
+
import "../chunk-ONP6BRZO.js";
|
|
11
|
+
import "../chunk-5PIMDP4N.js";
|
|
12
|
+
import "../chunk-45ARVNT3.js";
|
|
13
|
+
import "../chunk-DP6RTINQ.js";
|
|
14
|
+
import "../chunk-TJNJKPUL.js";
|
|
15
|
+
import "../chunk-KH22FJO5.js";
|
|
4
16
|
|
|
5
17
|
// src/api-routes/setup-github-app-installed.ts
|
|
6
18
|
var COOKIE_NAME = "sk_app_setup";
|
|
7
19
|
var COOKIE_MAX_AGE = 600;
|
|
8
20
|
var GET = async ({ url, request, cookies }) => {
|
|
21
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
22
|
+
if (denied) return denied;
|
|
9
23
|
const config = globalThis.__SETZKASTEN_CONFIG__;
|
|
10
24
|
const adminPath = config?.adminPath ?? "/admin";
|
|
11
25
|
const adminUrl = new URL(adminPath, getPublicOrigin(request));
|
|
@@ -20,7 +34,14 @@ var GET = async ({ url, request, cookies }) => {
|
|
|
20
34
|
cookies.set(
|
|
21
35
|
COOKIE_NAME,
|
|
22
36
|
JSON.stringify({ ...data, installationId }),
|
|
23
|
-
|
|
37
|
+
// C6: same httpOnly hardening as the callback route.
|
|
38
|
+
{
|
|
39
|
+
httpOnly: true,
|
|
40
|
+
secure: import.meta.env.PROD,
|
|
41
|
+
sameSite: "lax",
|
|
42
|
+
maxAge: COOKIE_MAX_AGE,
|
|
43
|
+
path: "/"
|
|
44
|
+
}
|
|
24
45
|
);
|
|
25
46
|
} catch {
|
|
26
47
|
adminUrl.searchParams.set("github-app-error", "invalid_session");
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
requireAdmin
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-Q5HV47DW.js";
|
|
4
|
+
import "../chunk-QVCW6EF3.js";
|
|
5
|
+
import "../chunk-KENFINT4.js";
|
|
4
6
|
import "../chunk-6UIKVKED.js";
|
|
7
|
+
import "../chunk-ONP6BRZO.js";
|
|
5
8
|
import "../chunk-5PIMDP4N.js";
|
|
6
9
|
import "../chunk-45ARVNT3.js";
|
|
7
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-DP6RTINQ.js";
|
|
8
11
|
import "../chunk-TJNJKPUL.js";
|
|
9
12
|
import "../chunk-KH22FJO5.js";
|
|
10
13
|
|
|
@@ -8,6 +8,10 @@ import { APIRoute } from 'astro';
|
|
|
8
8
|
*
|
|
9
9
|
* Credentials werden NICHT persistiert – der Nutzer setzt die env vars manuell.
|
|
10
10
|
* Der POST-Endpunkt validiert die Verbindung durch einen echten Token-Request.
|
|
11
|
+
*
|
|
12
|
+
* Both methods are admin-only. Pre-fix the GET let any unauthenticated
|
|
13
|
+
* visitor probe whether a deployment was configured (reconnaissance for
|
|
14
|
+
* targeting half-set-up instances).
|
|
11
15
|
*/
|
|
12
16
|
declare const GET: APIRoute;
|
|
13
17
|
declare const POST: APIRoute;
|
|
@@ -1,13 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requireAdmin
|
|
3
|
+
} from "../chunk-Q5HV47DW.js";
|
|
4
|
+
import "../chunk-QVCW6EF3.js";
|
|
5
|
+
import "../chunk-KENFINT4.js";
|
|
6
|
+
import "../chunk-6UIKVKED.js";
|
|
7
|
+
import "../chunk-ONP6BRZO.js";
|
|
8
|
+
import "../chunk-5PIMDP4N.js";
|
|
9
|
+
import "../chunk-45ARVNT3.js";
|
|
10
|
+
import "../chunk-DP6RTINQ.js";
|
|
11
|
+
import "../chunk-TJNJKPUL.js";
|
|
12
|
+
import "../chunk-KH22FJO5.js";
|
|
13
|
+
|
|
1
14
|
// src/api-routes/setup-github-app.ts
|
|
2
15
|
import { GitHubAppClient } from "@setzkasten-cms/github-adapter";
|
|
3
|
-
var GET = async () => {
|
|
16
|
+
var GET = async ({ cookies }) => {
|
|
17
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
18
|
+
if (denied) return denied;
|
|
4
19
|
const appId = process.env.GITHUB_APP_ID;
|
|
5
20
|
const privateKey = process.env.GITHUB_APP_PRIVATE_KEY;
|
|
6
21
|
const installationId = process.env.GITHUB_APP_INSTALLATION_ID;
|
|
7
22
|
const configured = Boolean(appId && privateKey && installationId);
|
|
8
23
|
return Response.json({ configured, ...configured ? { appId } : {} });
|
|
9
24
|
};
|
|
10
|
-
var POST = async ({ request }) => {
|
|
25
|
+
var POST = async ({ request, cookies }) => {
|
|
26
|
+
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
27
|
+
if (denied) return denied;
|
|
11
28
|
let body;
|
|
12
29
|
try {
|
|
13
30
|
body = await request.json();
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listAllWebsites
|
|
3
|
+
} from "../chunk-V6IMPVF3.js";
|
|
4
|
+
|
|
1
5
|
// src/api-routes/updater-register.ts
|
|
2
6
|
var POST = async ({ cookies, request }) => {
|
|
3
7
|
const session = cookies.get("setzkasten_session")?.value;
|
|
@@ -34,6 +38,8 @@ var POST = async ({ cookies, request }) => {
|
|
|
34
38
|
}
|
|
35
39
|
} catch {
|
|
36
40
|
}
|
|
41
|
+
const websitesResult = await listAllWebsites();
|
|
42
|
+
const managedWebsites = websitesResult.ok ? websitesResult.value.map((w) => w.id) : [];
|
|
37
43
|
try {
|
|
38
44
|
const response = await fetch(`${updaterUrl}/api/register`, {
|
|
39
45
|
method: "POST",
|
|
@@ -45,7 +51,7 @@ var POST = async ({ cookies, request }) => {
|
|
|
45
51
|
licenseEmail,
|
|
46
52
|
licenseKey,
|
|
47
53
|
telemetryEnabled: true,
|
|
48
|
-
managedWebsites
|
|
54
|
+
managedWebsites
|
|
49
55
|
}),
|
|
50
56
|
signal: AbortSignal.timeout(5e3)
|
|
51
57
|
});
|
|
@@ -3,11 +3,14 @@ import {
|
|
|
3
3
|
} from "../chunk-W3QHY5GW.js";
|
|
4
4
|
import {
|
|
5
5
|
requireAdmin
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-Q5HV47DW.js";
|
|
7
|
+
import "../chunk-QVCW6EF3.js";
|
|
8
|
+
import "../chunk-KENFINT4.js";
|
|
7
9
|
import "../chunk-6UIKVKED.js";
|
|
10
|
+
import "../chunk-ONP6BRZO.js";
|
|
8
11
|
import "../chunk-5PIMDP4N.js";
|
|
9
12
|
import "../chunk-45ARVNT3.js";
|
|
10
|
-
import "../chunk-
|
|
13
|
+
import "../chunk-DP6RTINQ.js";
|
|
11
14
|
import "../chunk-TJNJKPUL.js";
|
|
12
15
|
import "../chunk-KH22FJO5.js";
|
|
13
16
|
|
|
@@ -1,30 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
signPayload
|
|
3
|
-
} from "../chunk-737TIZRU.js";
|
|
4
1
|
import {
|
|
5
2
|
recordWebhookFire
|
|
6
3
|
} from "../chunk-W3QHY5GW.js";
|
|
4
|
+
import {
|
|
5
|
+
signPayload
|
|
6
|
+
} from "../chunk-737TIZRU.js";
|
|
7
7
|
import {
|
|
8
8
|
parseSession,
|
|
9
9
|
requireAdmin
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-Q5HV47DW.js";
|
|
11
|
+
import "../chunk-QVCW6EF3.js";
|
|
12
|
+
import "../chunk-KENFINT4.js";
|
|
11
13
|
import {
|
|
12
14
|
resolveStorageConfigForRequest
|
|
13
15
|
} from "../chunk-6UIKVKED.js";
|
|
16
|
+
import "../chunk-ONP6BRZO.js";
|
|
14
17
|
import {
|
|
15
18
|
gateFeature
|
|
16
19
|
} from "../chunk-5PIMDP4N.js";
|
|
17
20
|
import "../chunk-45ARVNT3.js";
|
|
18
21
|
import {
|
|
19
22
|
resolveGitHubTokenForRequest
|
|
20
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-DP6RTINQ.js";
|
|
21
24
|
import "../chunk-TJNJKPUL.js";
|
|
22
25
|
import "../chunk-KH22FJO5.js";
|
|
23
26
|
|
|
24
27
|
// src/api-routes/webhooks-test.ts
|
|
25
|
-
import {
|
|
26
|
-
parseWebhooksFile
|
|
27
|
-
} from "@setzkasten-cms/core";
|
|
28
|
+
import { parseWebhooksFile } from "@setzkasten-cms/core";
|
|
28
29
|
var WEBHOOKS_FILE = (contentPath) => `${contentPath}/_webhooks.json`;
|
|
29
30
|
var TEST_TIMEOUT_MS = 1e4;
|
|
30
31
|
var POST = async ({ request, cookies }) => {
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseSession,
|
|
3
3
|
requireAdmin
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-Q5HV47DW.js";
|
|
5
|
+
import "../chunk-QVCW6EF3.js";
|
|
6
|
+
import "../chunk-KENFINT4.js";
|
|
5
7
|
import {
|
|
6
8
|
resolveStorageConfigForRequest
|
|
7
9
|
} from "../chunk-6UIKVKED.js";
|
|
10
|
+
import "../chunk-ONP6BRZO.js";
|
|
8
11
|
import {
|
|
9
12
|
gateFeature
|
|
10
13
|
} from "../chunk-5PIMDP4N.js";
|
|
@@ -14,17 +17,14 @@ import {
|
|
|
14
17
|
} from "../chunk-45ARVNT3.js";
|
|
15
18
|
import {
|
|
16
19
|
resolveGitHubTokenForRequest
|
|
17
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-DP6RTINQ.js";
|
|
18
21
|
import "../chunk-TJNJKPUL.js";
|
|
19
22
|
import {
|
|
20
23
|
withTrailers
|
|
21
24
|
} from "../chunk-KH22FJO5.js";
|
|
22
25
|
|
|
23
26
|
// src/api-routes/webhooks.ts
|
|
24
|
-
import {
|
|
25
|
-
parseWebhooksFile,
|
|
26
|
-
validateWebhookConfig
|
|
27
|
-
} from "@setzkasten-cms/core";
|
|
27
|
+
import { parseWebhooksFile, validateWebhookConfig } from "@setzkasten-cms/core";
|
|
28
28
|
var WEBHOOKS_FILE = (contentPath) => `${contentPath}/_webhooks.json`;
|
|
29
29
|
var GET = async ({ request, cookies }) => {
|
|
30
30
|
const denied = requireAdmin(cookies.get("setzkasten_session")?.value);
|
|
@@ -82,10 +82,7 @@ var PUT = async ({ request, cookies }) => {
|
|
|
82
82
|
for (let i = 0; i < body.webhooks.length; i++) {
|
|
83
83
|
const result = validateWebhookConfig(body.webhooks[i]);
|
|
84
84
|
if (!result.ok) {
|
|
85
|
-
return Response.json(
|
|
86
|
-
{ error: result.error.message, index: i },
|
|
87
|
-
{ status: 400 }
|
|
88
|
-
);
|
|
85
|
+
return Response.json({ error: result.error.message, index: i }, { status: 400 });
|
|
89
86
|
}
|
|
90
87
|
if (seenIds.has(result.value.id)) {
|
|
91
88
|
return Response.json(
|
|
@@ -127,10 +124,11 @@ var PUT = async ({ request, cookies }) => {
|
|
|
127
124
|
branch
|
|
128
125
|
};
|
|
129
126
|
if (currentSha) putBody.sha = currentSha;
|
|
130
|
-
const putRes = await fetch(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
127
|
+
const putRes = await fetch(`https://api.github.com/repos/${owner}/${repo}/contents/${filePath}`, {
|
|
128
|
+
method: "PUT",
|
|
129
|
+
headers,
|
|
130
|
+
body: JSON.stringify(putBody)
|
|
131
|
+
});
|
|
134
132
|
if (!putRes.ok) {
|
|
135
133
|
const text = await putRes.text();
|
|
136
134
|
return Response.json({ error: `Webhook write failed: ${text}` }, { status: 502 });
|
|
@@ -5,13 +5,16 @@ import {
|
|
|
5
5
|
} from "../chunk-35S35OIV.js";
|
|
6
6
|
import {
|
|
7
7
|
requireAdmin
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-Q5HV47DW.js";
|
|
9
|
+
import "../chunk-QVCW6EF3.js";
|
|
10
|
+
import "../chunk-KENFINT4.js";
|
|
9
11
|
import "../chunk-6UIKVKED.js";
|
|
12
|
+
import "../chunk-ONP6BRZO.js";
|
|
10
13
|
import "../chunk-5PIMDP4N.js";
|
|
11
14
|
import "../chunk-45ARVNT3.js";
|
|
12
15
|
import {
|
|
13
16
|
resolveConfigRepoToken
|
|
14
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-DP6RTINQ.js";
|
|
15
18
|
import {
|
|
16
19
|
resolveLicenseTier
|
|
17
20
|
} from "../chunk-TJNJKPUL.js";
|
|
@@ -5,13 +5,16 @@ import {
|
|
|
5
5
|
} from "../chunk-35S35OIV.js";
|
|
6
6
|
import {
|
|
7
7
|
requireAdmin
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-Q5HV47DW.js";
|
|
9
|
+
import "../chunk-QVCW6EF3.js";
|
|
10
|
+
import "../chunk-KENFINT4.js";
|
|
9
11
|
import "../chunk-6UIKVKED.js";
|
|
12
|
+
import "../chunk-ONP6BRZO.js";
|
|
10
13
|
import "../chunk-5PIMDP4N.js";
|
|
11
14
|
import "../chunk-45ARVNT3.js";
|
|
12
15
|
import {
|
|
13
16
|
resolveConfigRepoToken
|
|
14
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-DP6RTINQ.js";
|
|
15
18
|
import "../chunk-TJNJKPUL.js";
|
|
16
19
|
import "../chunk-KH22FJO5.js";
|
|
17
20
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
readEditorsFileStatus
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Q5HV47DW.js";
|
|
4
4
|
import {
|
|
5
5
|
resolveStorageConfig
|
|
6
6
|
} from "./chunk-6UIKVKED.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveConfigRepoToken
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-DP6RTINQ.js";
|
|
10
10
|
|
|
11
11
|
// src/api-routes/_role-resolver.ts
|
|
12
12
|
import { resolveRoleForUser } from "@setzkasten-cms/core";
|
|
@@ -9,7 +9,8 @@ function findNormalizedText(haystack, needle, startFrom) {
|
|
|
9
9
|
const escaped = normalized.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/ /g, "\\s+");
|
|
10
10
|
const regex = new RegExp(escaped);
|
|
11
11
|
const match = regex.exec(haystack.slice(startFrom));
|
|
12
|
-
if (match)
|
|
12
|
+
if (match)
|
|
13
|
+
return { start: startFrom + match.index, end: startFrom + match.index + match[0].length };
|
|
13
14
|
return null;
|
|
14
15
|
}
|
|
15
16
|
async function patchTemplateForFields(source, sectionKey, fields, repeatedGroups = [], options) {
|
|
@@ -64,7 +65,13 @@ const { data: ${varName} } = Astro.props
|
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
|
-
const patched2 = await patchTemplateForFields(
|
|
68
|
+
const patched2 = await patchTemplateForFields(
|
|
69
|
+
modifiedSource,
|
|
70
|
+
sectionKey,
|
|
71
|
+
fields,
|
|
72
|
+
repeatedGroups,
|
|
73
|
+
options
|
|
74
|
+
);
|
|
68
75
|
return removeOldVarDeclarations(patched2, fields, repeatedGroups, varName);
|
|
69
76
|
}
|
|
70
77
|
const existingBindings = /* @__PURE__ */ new Set();
|
|
@@ -579,7 +586,7 @@ function patchArrayField(source, sectionKey, field, varName, mapExpressions, edi
|
|
|
579
586
|
insert: `(${varName}?.${field.key} ?? [])`
|
|
580
587
|
});
|
|
581
588
|
} else {
|
|
582
|
-
const varMapRegex =
|
|
589
|
+
const varMapRegex = /(\w+)\.map\s*\(/;
|
|
583
590
|
const varMapMatch = exprSource.match(varMapRegex);
|
|
584
591
|
if (varMapMatch) {
|
|
585
592
|
const varRef = varMapMatch[1];
|
|
@@ -802,7 +809,7 @@ function collectDynamicClassEdits(innerEdits, source, instances, tmpl, group) {
|
|
|
802
809
|
if (!tmplPos) continue;
|
|
803
810
|
const fieldTag = field.tag;
|
|
804
811
|
let bestAttrIdx = -1;
|
|
805
|
-
let bestDist =
|
|
812
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
806
813
|
for (let ai = 0; ai < tmplAttrs.length; ai++) {
|
|
807
814
|
const pathParts = tmplAttrs[ai].path.split("/");
|
|
808
815
|
const leafTag = (pathParts[pathParts.length - 1] ?? "").replace(/:\d+$/, "");
|
|
@@ -1091,7 +1098,7 @@ ${indent}))}`;
|
|
|
1091
1098
|
for (let i = instances.length - 1; i >= 1; i--) {
|
|
1092
1099
|
const inst = instances[i];
|
|
1093
1100
|
let deleteStart = inst.start;
|
|
1094
|
-
|
|
1101
|
+
const deleteEnd = inst.end;
|
|
1095
1102
|
while (deleteStart > 0 && /\s/.test(source[deleteStart - 1]) && source[deleteStart - 1] !== "\n") {
|
|
1096
1103
|
deleteStart--;
|
|
1097
1104
|
}
|
|
@@ -1351,7 +1358,8 @@ function removeOldVarDeclarations(source, fields, repeatedGroups, cmsVarName = "
|
|
|
1351
1358
|
return source.slice(0, fmStart + 4) + frontmatter + source.slice(fmEnd);
|
|
1352
1359
|
}
|
|
1353
1360
|
function patchChildComponentForFieldPrefix(source, innerFields) {
|
|
1354
|
-
if (source.includes("fieldPrefix?: string") || source.includes("fieldPrefix?:string"))
|
|
1361
|
+
if (source.includes("fieldPrefix?: string") || source.includes("fieldPrefix?:string"))
|
|
1362
|
+
return source;
|
|
1355
1363
|
const fmStart = source.indexOf("---");
|
|
1356
1364
|
const fmEnd = source.indexOf("---", fmStart + 3);
|
|
1357
1365
|
if (fmStart === -1 || fmEnd === -1) return source;
|
|
@@ -1365,15 +1373,12 @@ function patchChildComponentForFieldPrefix(source, innerFields) {
|
|
|
1365
1373
|
const closeFm = result.indexOf("---", result.indexOf("---") + 3);
|
|
1366
1374
|
result = result.slice(0, closeFm) + "interface Props { fieldPrefix?: string }\n" + result.slice(closeFm);
|
|
1367
1375
|
}
|
|
1368
|
-
result = result.replace(
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
return `${trimmed}${sep}fieldPrefix${after}`;
|
|
1375
|
-
}
|
|
1376
|
-
);
|
|
1376
|
+
result = result.replace(/(\bconst\s*\{[^}]*)(}\s*=\s*Astro\.props)/, (_m, before, after) => {
|
|
1377
|
+
if (before.includes("fieldPrefix")) return _m;
|
|
1378
|
+
const trimmed = before.trimEnd();
|
|
1379
|
+
const sep = trimmed.endsWith(",") ? " " : ",\n ";
|
|
1380
|
+
return `${trimmed}${sep}fieldPrefix${after}`;
|
|
1381
|
+
});
|
|
1377
1382
|
const closingFm = result.indexOf("---", result.indexOf("---") + 3);
|
|
1378
1383
|
const frontmatterPart = result.slice(0, closingFm + 3);
|
|
1379
1384
|
let templatePart = result.slice(closingFm + 3);
|
|
@@ -1399,10 +1404,7 @@ function patchChildComponentForFieldPrefix(source, innerFields) {
|
|
|
1399
1404
|
});
|
|
1400
1405
|
}
|
|
1401
1406
|
for (const field of arrayFields) {
|
|
1402
|
-
const mapParamRegex = new RegExp(
|
|
1403
|
-
`(${field.key}\\.map\\s*\\(\\s*\\(\\s*)(\\w+)(\\s*\\))`,
|
|
1404
|
-
"g"
|
|
1405
|
-
);
|
|
1407
|
+
const mapParamRegex = new RegExp(`(${field.key}\\.map\\s*\\(\\s*\\(\\s*)(\\w+)(\\s*\\))`, "g");
|
|
1406
1408
|
templatePart = templatePart.replace(
|
|
1407
1409
|
new RegExp(`(<(?:ul|ol)[^>]*?)(\\/?>)([\\s\\S]*?${field.key}\\.map)`, "g"),
|
|
1408
1410
|
(_m, ulOpen, ulClose, rest) => {
|
|
@@ -1419,11 +1421,14 @@ function patchChildComponentForFieldPrefix(source, innerFields) {
|
|
|
1419
1421
|
`(${field.key}\\.map\\s*\\([^)]*\\)\\s*=>\\s*\\([\\s\\S]*?)(<(?:span|li|td)\\b)([^>]*?>)([^<]*\\{\\w+\\})`,
|
|
1420
1422
|
"g"
|
|
1421
1423
|
);
|
|
1422
|
-
templatePart = templatePart.replace(
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1424
|
+
templatePart = templatePart.replace(
|
|
1425
|
+
mapBlockRegex,
|
|
1426
|
+
(_m, mapHead, tagOpen, tagClose, content) => {
|
|
1427
|
+
if (tagClose.includes("data-sk-field")) return _m;
|
|
1428
|
+
const attr = ` data-sk-field={fieldPrefix ? \`\${fieldPrefix}.${field.key}.\${_fi}\` : undefined}`;
|
|
1429
|
+
return `${mapHead}${tagOpen}${tagClose.slice(0, -1)}${attr}>${content}`;
|
|
1430
|
+
}
|
|
1431
|
+
);
|
|
1427
1432
|
}
|
|
1428
1433
|
return frontmatterPart + templatePart;
|
|
1429
1434
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/api-routes/_github-token.ts
|
|
2
|
-
import {
|
|
2
|
+
import { authError, err } from "@setzkasten-cms/core";
|
|
3
3
|
import { GitHubAppClient } from "@setzkasten-cms/github-adapter";
|
|
4
4
|
async function resolveConfigRepoToken() {
|
|
5
5
|
const appId = process.env.GITHUB_APP_ID;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// src/api-routes/_session-signing.ts
|
|
2
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
3
|
+
var SEPARATOR = ".";
|
|
4
|
+
function base64urlEncode(input) {
|
|
5
|
+
const buf = typeof input === "string" ? Buffer.from(input, "utf-8") : input;
|
|
6
|
+
return buf.toString("base64url");
|
|
7
|
+
}
|
|
8
|
+
function base64urlDecode(input) {
|
|
9
|
+
if (!/^[A-Za-z0-9_-]+$/.test(input)) return null;
|
|
10
|
+
try {
|
|
11
|
+
return Buffer.from(input, "base64url");
|
|
12
|
+
} catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function hmac(payload, secret) {
|
|
17
|
+
return createHmac("sha256", secret).update(payload).digest();
|
|
18
|
+
}
|
|
19
|
+
function signSession(session, secret) {
|
|
20
|
+
if (typeof secret !== "string" || secret.trim().length === 0) {
|
|
21
|
+
throw new Error("signSession: missing secret");
|
|
22
|
+
}
|
|
23
|
+
const json = JSON.stringify(session);
|
|
24
|
+
const payloadB64 = base64urlEncode(json);
|
|
25
|
+
const sigB64 = hmac(payloadB64, secret).toString("base64url");
|
|
26
|
+
return `${payloadB64}${SEPARATOR}${sigB64}`;
|
|
27
|
+
}
|
|
28
|
+
function verifySessionCookie(raw, secret, now = Date.now()) {
|
|
29
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
30
|
+
return { ok: false, reason: "malformed" };
|
|
31
|
+
}
|
|
32
|
+
if (typeof secret !== "string" || secret.trim().length === 0) {
|
|
33
|
+
return { ok: false, reason: "malformed" };
|
|
34
|
+
}
|
|
35
|
+
const segments = raw.split(SEPARATOR);
|
|
36
|
+
if (segments.length !== 2) return { ok: false, reason: "malformed" };
|
|
37
|
+
const [payloadB64, sigB64] = segments;
|
|
38
|
+
if (!payloadB64 || !sigB64) return { ok: false, reason: "malformed" };
|
|
39
|
+
const expected = hmac(payloadB64, secret);
|
|
40
|
+
const actual = base64urlDecode(sigB64);
|
|
41
|
+
if (!actual) return { ok: false, reason: "malformed" };
|
|
42
|
+
if (actual.length !== expected.length) return { ok: false, reason: "bad-signature" };
|
|
43
|
+
if (!timingSafeEqual(actual, expected)) return { ok: false, reason: "bad-signature" };
|
|
44
|
+
const payloadBuf = base64urlDecode(payloadB64);
|
|
45
|
+
if (!payloadBuf) return { ok: false, reason: "malformed" };
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(payloadBuf.toString("utf-8"));
|
|
49
|
+
} catch {
|
|
50
|
+
return { ok: false, reason: "invalid-payload" };
|
|
51
|
+
}
|
|
52
|
+
if (!isAuthSessionShape(parsed)) {
|
|
53
|
+
return { ok: false, reason: "invalid-payload" };
|
|
54
|
+
}
|
|
55
|
+
if (typeof parsed.expiresAt !== "number" || !Number.isFinite(parsed.expiresAt)) {
|
|
56
|
+
return { ok: false, reason: "missing-expiry" };
|
|
57
|
+
}
|
|
58
|
+
if (parsed.expiresAt <= now) {
|
|
59
|
+
return { ok: false, reason: "expired" };
|
|
60
|
+
}
|
|
61
|
+
return { ok: true, value: parsed };
|
|
62
|
+
}
|
|
63
|
+
function isAuthSessionShape(value) {
|
|
64
|
+
if (!value || typeof value !== "object") return false;
|
|
65
|
+
const v = value;
|
|
66
|
+
if (!v.user || typeof v.user !== "object") return false;
|
|
67
|
+
const u = v.user;
|
|
68
|
+
if (typeof u.email !== "string" || u.email.length === 0) return false;
|
|
69
|
+
if (u.role !== "admin" && u.role !== "editor") return false;
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export {
|
|
74
|
+
signSession,
|
|
75
|
+
verifySessionCookie
|
|
76
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/api-routes/_dev-session-secret.ts
|
|
2
|
+
import { randomBytes } from "crypto";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
var DEV_SECRET_DIR = ".setzkasten";
|
|
6
|
+
var DEV_SECRET_FILE = "dev-secret";
|
|
7
|
+
var cachedSecret = null;
|
|
8
|
+
function ensureDevSessionSecret() {
|
|
9
|
+
if (cachedSecret) return cachedSecret;
|
|
10
|
+
const dir = join(process.cwd(), DEV_SECRET_DIR);
|
|
11
|
+
const file = join(dir, DEV_SECRET_FILE);
|
|
12
|
+
if (existsSync(file)) {
|
|
13
|
+
const content = readFileSync(file, "utf-8").trim();
|
|
14
|
+
if (content.length >= 32) {
|
|
15
|
+
cachedSecret = content;
|
|
16
|
+
return content;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
mkdirSync(dir, { recursive: true });
|
|
20
|
+
const fresh = randomBytes(32).toString("hex");
|
|
21
|
+
try {
|
|
22
|
+
writeFileSync(file, `${fresh}
|
|
23
|
+
`, { flag: "wx", mode: 384 });
|
|
24
|
+
} catch (cause) {
|
|
25
|
+
if (cause?.code === "EEXIST") {
|
|
26
|
+
const content = readFileSync(file, "utf-8").trim();
|
|
27
|
+
if (content.length >= 32) {
|
|
28
|
+
cachedSecret = content;
|
|
29
|
+
return content;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
throw cause;
|
|
33
|
+
}
|
|
34
|
+
console.warn(
|
|
35
|
+
`[setzkasten] Generated dev session secret at ${file} (mode 0600). Set SETZKASTEN_SESSION_SECRET in production. Delete the file to rotate.`
|
|
36
|
+
);
|
|
37
|
+
cachedSecret = fresh;
|
|
38
|
+
return fresh;
|
|
39
|
+
}
|
|
40
|
+
function __setDevSessionSecretForTests(secret) {
|
|
41
|
+
cachedSecret = secret;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
ensureDevSessionSecret,
|
|
46
|
+
__setDevSessionSecretForTests
|
|
47
|
+
};
|