@camstack/server 1.2.592 → 1.2.594
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/addon-root-inventory.js +11 -50
- package/dist/agent/addon-scan.js +6 -44
- package/dist/agent/agent-addon-runtime.js +3 -8
- package/dist/agent/agent-addon-updates.js +12 -52
- package/dist/agent/agent-cap-dispatch-service.js +3 -5
- package/dist/agent/agent-config.js +7 -42
- package/dist/agent/agent-deploy-swap.js +5 -41
- package/dist/agent/agent-group-runner.js +8 -47
- package/dist/agent/agent-http-auth.js +10 -22
- package/dist/agent/agent-http.js +69 -115
- package/dist/agent/agent-hub-addon-update.js +10 -16
- package/dist/agent/agent-hub-registration.js +4 -7
- package/dist/agent/agent-infra-capabilities.js +5 -9
- package/dist/agent/agent-json-file.js +5 -42
- package/dist/agent/agent-mesh-gate.js +5 -8
- package/dist/agent/agent-node-certificates.js +25 -28
- package/dist/agent/agent-pairing-local.js +10 -47
- package/dist/agent/agent-pairing-routes.js +16 -20
- package/dist/agent/agent-pairing-store.js +18 -58
- package/dist/agent/agent-reconnect.js +1 -4
- package/dist/agent/agent-service.js +42 -78
- package/dist/agent/agent-sniffing-listener.js +11 -48
- package/dist/agent/agent-undeploy.js +5 -41
- package/dist/agent/agent-update-routes.js +14 -19
- package/dist/agent/agent-update-service.js +38 -80
- package/dist/agent/apply-model-distribution.js +1 -4
- package/dist/agent/apply-stage-dev-uploads.js +6 -9
- package/dist/agent/derive-hub-url.js +3 -8
- package/dist/agent/fetch-bundle-from-hub.js +6 -9
- package/dist/agent/hubs-found.js +6 -43
- package/dist/agent/infra-boot-guard.js +1 -4
- package/dist/agent/infra-boot-plan.js +2 -6
- package/dist/agent/main.js +158 -186
- package/dist/agent/register-agent-cap-dispatch.js +3 -6
- package/dist/agent/serial-queue.js +2 -7
- package/dist/agent-status-page.js +1 -4
- package/dist/api/addon-upload.js +22 -61
- package/dist/api/agent-addon-delivery.js +6 -11
- package/dist/api/auth-whoami.js +1 -4
- package/dist/api/backup-download-pump.js +5 -9
- package/dist/api/backup-download.js +7 -10
- package/dist/api/core/addon-settings.router.js +16 -19
- package/dist/api/core/agent-pairing.router.js +76 -79
- package/dist/api/core/agents.router.js +21 -24
- package/dist/api/core/auth-admin-tokens.procedures.js +48 -52
- package/dist/api/core/auth-device-cert.procedures.js +62 -67
- package/dist/api/core/auth-limits.js +16 -25
- package/dist/api/core/auth-reauth.procedures.js +32 -37
- package/dist/api/core/auth-revoke-credentials.procedures.js +22 -26
- package/dist/api/core/auth-sessions.procedures.js +52 -56
- package/dist/api/core/auth.router.js +300 -304
- package/dist/api/core/cap-providers.js +74 -121
- package/dist/api/core/capabilities.router.js +34 -37
- package/dist/api/core/capability-preference-writes.js +10 -17
- package/dist/api/core/certificates.router.js +106 -109
- package/dist/api/core/cluster-nodes.router.js +15 -18
- package/dist/api/core/collection-preference.js +2 -6
- package/dist/api/core/event-bus-proxy.router.js +34 -37
- package/dist/api/core/failure-contributions.js +4 -8
- package/dist/api/core/hwaccel.router.js +17 -20
- package/dist/api/core/integration-secrets.js +8 -12
- package/dist/api/core/lifecycle-job-runner.js +13 -49
- package/dist/api/core/live-events.router.js +29 -32
- package/dist/api/core/load-contributions.js +4 -8
- package/dist/api/core/logging-settings.js +30 -43
- package/dist/api/core/logs.router.js +40 -43
- package/dist/api/core/notifications.router.js +15 -18
- package/dist/api/core/public-event-filter.js +4 -8
- package/dist/api/core/repl.router.js +18 -21
- package/dist/api/core/request-census-settings.js +11 -16
- package/dist/api/core/server-management.provider.js +1 -4
- package/dist/api/core/server-name.js +9 -17
- package/dist/api/core/site-location.js +16 -24
- package/dist/api/core/stream-probe.router.js +21 -24
- package/dist/api/core/system-events.router.js +23 -26
- package/dist/api/cors/cors-policy.js +20 -29
- package/dist/api/cors/register-cors-policy.js +9 -14
- package/dist/api/deploy-stage-registry.js +6 -10
- package/dist/api/dev-uploads-bundle.js +12 -50
- package/dist/api/health/adaptive-probe.routes.js +9 -13
- package/dist/api/health/health.routes.js +8 -13
- package/dist/api/hub-cluster-url.js +3 -9
- package/dist/api/model-distributor.js +12 -50
- package/dist/api/oauth2/consent-page.js +10 -13
- package/dist/api/oauth2/oauth2-routes.js +17 -25
- package/dist/api/oauth2/private-host.js +1 -4
- package/dist/api/server-upload-propagate.js +15 -51
- package/dist/api/server-upload.js +13 -50
- package/dist/api/sse-no-compression.js +1 -4
- package/dist/api/static/frame-policy.js +4 -9
- package/dist/api/static/precompressed-asset.js +15 -57
- package/dist/api/static/spa-mount.js +8 -47
- package/dist/api/static/spa-static.js +5 -12
- package/dist/api/tarball-manifest.js +7 -44
- package/dist/api/trpc/cap-mount-helpers.js +7 -12
- package/dist/api/trpc/cap-route-error-formatter.js +10 -13
- package/dist/api/trpc/cap-router-runtime.js +40 -51
- package/dist/api/trpc/client-ip.js +9 -20
- package/dist/api/trpc/core-cap-bridge.js +32 -42
- package/dist/api/trpc/device-collection-dispatch.js +23 -27
- package/dist/api/trpc/device-config-secret-redaction.js +24 -40
- package/dist/api/trpc/generated-cap-mounts.js +219 -221
- package/dist/api/trpc/generated-cap-routers.js +4878 -4726
- package/dist/api/trpc/http-request-census-hook.js +8 -11
- package/dist/api/trpc/http-request-census.js +34 -41
- package/dist/api/trpc/http-request-census.singleton.js +4 -8
- package/dist/api/trpc/localized-schema-paths.js +1 -4
- package/dist/api/trpc/principal-visibility.js +14 -22
- package/dist/api/trpc/remote-addon-update-grant.js +1 -4
- package/dist/api/trpc/scope-access.js +10 -15
- package/dist/api/trpc/server-provided-caps.js +3 -7
- package/dist/api/trpc/share-view-access.js +6 -14
- package/dist/api/trpc/trpc-error-device-tags.js +3 -6
- package/dist/api/trpc/trpc-error-principal.js +2 -6
- package/dist/api/trpc/trpc.context.js +20 -25
- package/dist/api/trpc/trpc.middleware.js +38 -46
- package/dist/api/trpc/trpc.router.js +58 -99
- package/dist/api/trpc/user-error.js +5 -8
- package/dist/api/trpc/ws-request-census.js +17 -24
- package/dist/api/trpc/ws-slow-consumer-guard.js +11 -16
- package/dist/api/upload-auth.js +5 -9
- package/dist/auth/addon-route-jwt-gate.js +4 -7
- package/dist/auth/addon-route-share-gate.js +7 -12
- package/dist/auth/app-confirm-page.js +17 -22
- package/dist/auth/app-confirm-routes.js +26 -31
- package/dist/auth/app-confirmations.js +7 -44
- package/dist/auth/app-page-shell.js +17 -30
- package/dist/auth/app-page-strings.js +11 -17
- package/dist/auth/app-passkey-page.js +16 -21
- package/dist/auth/app-passkey-routes.js +37 -41
- package/dist/auth/app-refused-route.js +13 -18
- package/dist/auth/auth-network-policy.js +11 -15
- package/dist/auth/auth-provider-gate.js +4 -9
- package/dist/auth/auth-rate-limit.js +3 -7
- package/dist/auth/client-address.js +6 -9
- package/dist/auth/device-enroll-proofs.js +6 -43
- package/dist/auth/external-link-intents.js +3 -7
- package/dist/auth/hub-sessions.js +6 -12
- package/dist/auth/native-link-completions.js +7 -11
- package/dist/auth/native-return.js +9 -13
- package/dist/auth/passkey-provider.js +26 -32
- package/dist/auth/second-factors.js +6 -10
- package/dist/auth/session-connections.js +6 -12
- package/dist/auth/session-cookie.js +12 -23
- package/dist/auth/session-lifetimes.js +8 -12
- package/dist/auth/session-mint.js +4 -11
- package/dist/auth/sso-finish-app.js +13 -16
- package/dist/auth/sso-finish-deps.js +21 -27
- package/dist/auth/sso-finish.js +28 -38
- package/dist/auth/sso-routes.js +22 -25
- package/dist/auth/used-bridge-ids.js +1 -5
- package/dist/boot/boot-config.js +16 -55
- package/dist/boot/init-sequence.js +1 -4
- package/dist/boot/integration-id-backfill.js +3 -8
- package/dist/boot/platform-keychain-key.js +5 -42
- package/dist/boot/post-boot.service.js +14 -18
- package/dist/boot/reconcile-lifecycle-jobs.js +3 -6
- package/dist/boot/retired-public-url-env.js +4 -8
- package/dist/bootstrap-packages.js +1 -4
- package/dist/closure-node-modules.js +2 -38
- package/dist/closure-patches/patch-reach.json +6 -2
- package/dist/core/addon/addon-call-gateway.js +1 -5
- package/dist/core/addon/addon-package.service.js +83 -123
- package/dist/core/addon/addon-process-view.js +2 -6
- package/dist/core/addon/addon-realign-plan.js +1 -4
- package/dist/core/addon/addon-registry.service.js +254 -197
- package/dist/core/addon/addon-row-manifest.js +1 -4
- package/dist/core/addon/addon-search.service.js +3 -7
- package/dist/core/addon/addon-settings-provider.js +1 -3
- package/dist/core/addon/addon-uninstall.js +4 -11
- package/dist/core/addon/addon.tokens.js +2 -5
- package/dist/core/addon/device-meta-mirror.js +8 -13
- package/dist/core/addon/forked-custom-actions.js +6 -11
- package/dist/core/addon/integration-visibility.js +3 -6
- package/dist/core/addon/materialize-route-path.js +1 -4
- package/dist/core/addon/package-dir-utils.js +8 -45
- package/dist/core/addon/prune-misplaced-addons.js +5 -43
- package/dist/core/addon/runner-convergence.js +1 -4
- package/dist/core/addon/runner-serialization.js +1 -4
- package/dist/core/addon/runner-spawn-fanout.js +3 -8
- package/dist/core/addon/settings-door-wiring.js +5 -8
- package/dist/core/addon/single-flight-refresh.js +1 -4
- package/dist/core/addon-bridge/addon-bridge.service.js +7 -44
- package/dist/core/addon-pages/addon-pages.service.js +3 -40
- package/dist/core/addon-widgets/addon-widgets.service.js +4 -42
- package/dist/core/agent/agent-addon-backfill.js +9 -17
- package/dist/core/agent/agent-delivery-ledger.js +3 -7
- package/dist/core/agent/agent-liveness-event.js +2 -6
- package/dist/core/agent/agent-pairing-http.js +41 -45
- package/dist/core/agent/agent-registry.service.js +53 -92
- package/dist/core/agent/cluster-node-history-mirror.js +3 -7
- package/dist/core/agent/cluster-node-history-store.js +113 -58
- package/dist/core/agent/hub-agent-pairing.js +1 -5
- package/dist/core/agent/node-certificates-client.js +3 -6
- package/dist/core/agent/node-directory.js +1 -4
- package/dist/core/app-links/well-known-app-links.js +2 -6
- package/dist/core/auth/auth.service.js +3 -8
- package/dist/core/auth/handoff-code.service.js +11 -49
- package/dist/core/auth/record-kinds.js +35 -0
- package/dist/core/auth/share-token.service.js +174 -122
- package/dist/core/capability/capability.service.js +1 -5
- package/dist/core/config/config.schema.js +1 -6
- package/dist/core/config/config.service.js +2 -6
- package/dist/core/events/event-bus.service.js +3 -7
- package/dist/core/feature/feature.service.js +2 -6
- package/dist/core/lifecycle/lifecycle-runner.singleton.js +5 -10
- package/dist/core/lifecycle/lifecycle-state-machine.js +1 -5
- package/dist/core/logging/log-ring-buffer.js +1 -5
- package/dist/core/logging/logging.service.js +5 -9
- package/dist/core/logging/scoped-logger.js +1 -5
- package/dist/core/moleculer/agent-readiness-pull.js +1 -4
- package/dist/core/moleculer/agent-registration-request.js +3 -7
- package/dist/core/moleculer/cap-call-fn.js +39 -5
- package/dist/core/moleculer/cap-route-authority.js +3 -8
- package/dist/core/moleculer/hub-mesh-guard.js +5 -9
- package/dist/core/moleculer/moleculer.service.js +108 -119
- package/dist/core/network/network-quality.service.js +2 -6
- package/dist/core/notification/notification-wrapper.service.js +3 -7
- package/dist/core/notification/toast-wrapper.service.js +3 -7
- package/dist/core/provider/provider.tokens.js +1 -4
- package/dist/core/repl/repl-engine.service.js +4 -8
- package/dist/core/runner-health/runner-boot-check.js +7 -15
- package/dist/core/runner-health/update-preflight.js +9 -14
- package/dist/core/server-update/server-update.service.js +12 -49
- package/dist/core/server-update/system-apply-closure-patches.js +6 -42
- package/dist/core/server-update/system-ensure-prebuilds.js +3 -6
- package/dist/core/server-update/system-exec-npm.js +2 -5
- package/dist/core/storage/fs-storage-backend.js +1 -5
- package/dist/core/storage/storage-location-manager.js +1 -5
- package/dist/core/storage/storage.service.js +2 -6
- package/dist/core/streaming/ffmpeg-stream-info.js +3 -8
- package/dist/core/streaming/stream-probe.service.js +12 -16
- package/dist/core/streaming/ttl-cache.js +1 -5
- package/dist/core/topology/topology-emitter.service.js +19 -23
- package/dist/core/update-availability-emitter.js +3 -7
- package/dist/core/update-availability-store.js +8 -45
- package/dist/core/updates/agent-installed-packages.js +5 -9
- package/dist/core/updates/restart-marker.js +3 -8
- package/dist/core/updates/update-check-scheduler.js +13 -18
- package/dist/core/updates/wrapper-update-checker.js +3 -7
- package/dist/first-boot-addon-plan.js +2 -6
- package/dist/framework-nodepath.js +2 -38
- package/dist/i18n/request-lang.js +7 -11
- package/dist/launcher.js +30 -65
- package/dist/lifecycle-journal-path.js +2 -38
- package/dist/main.js +287 -324
- package/dist/manual-boot.js +120 -157
- package/dist/node-role.js +1 -4
- package/dist/package-inventory.js +7 -48
- package/dist/pending-restore.js +7 -43
- package/dist/single-copy-cleanup-runner.js +9 -45
- package/dist/single-copy-cleanup.js +7 -15
- package/dist/sqlite-restore.js +9 -48
- package/dist/starter.js +4 -39
- package/dist/ui-serving/lazy-ui-serving.js +3 -39
- package/package.json +13 -13
|
@@ -1,41 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.isSafeDevUploadVersion = isSafeDevUploadVersion;
|
|
37
|
-
exports.packDevUploadVersionDir = packDevUploadVersionDir;
|
|
38
|
-
exports.unpackDevUploadVersionBundle = unpackDevUploadVersionBundle;
|
|
39
1
|
/**
|
|
40
2
|
* Pack / unpack a hub `server-root/dev-uploads/<version>/` directory for
|
|
41
3
|
* agent fan-out (`POST /api/server-upload/propagate` → `$agent.stageDevUploads`).
|
|
@@ -43,15 +5,15 @@ exports.unpackDevUploadVersionBundle = unpackDevUploadVersionBundle;
|
|
|
43
5
|
* One gzipped tar carries every tarball + `manifest.json`. Fail-closed on
|
|
44
6
|
* path traversal and on a layout that would not satisfy RootUpdateService.
|
|
45
7
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import * as os from 'node:os';
|
|
10
|
+
import * as path from 'node:path';
|
|
11
|
+
import * as tar from 'tar';
|
|
12
|
+
import { DEV_UPLOAD_MANIFEST_FILE, isDevChannelVersion, readDevUploadManifest, } from '../server-root/index.js';
|
|
51
13
|
/** Version chars safe as a single path segment (matches server-upload). */
|
|
52
14
|
const SAFE_VERSION_RE = /^[0-9A-Za-z][0-9A-Za-z.-]*$/;
|
|
53
|
-
function isSafeDevUploadVersion(version) {
|
|
54
|
-
return SAFE_VERSION_RE.test(version) &&
|
|
15
|
+
export function isSafeDevUploadVersion(version) {
|
|
16
|
+
return SAFE_VERSION_RE.test(version) && isDevChannelVersion(version);
|
|
55
17
|
}
|
|
56
18
|
function hasPathTraversal(name) {
|
|
57
19
|
return name.includes('/') || name.includes('\\') || name.includes('..');
|
|
@@ -60,8 +22,8 @@ function hasPathTraversal(name) {
|
|
|
60
22
|
* Pack every file in `versionDir` (basename entries only) into a gzipped tar.
|
|
61
23
|
* Refuses if the manifest is missing/invalid or lists a missing tarball.
|
|
62
24
|
*/
|
|
63
|
-
async function packDevUploadVersionDir(versionDir) {
|
|
64
|
-
const manifest =
|
|
25
|
+
export async function packDevUploadVersionDir(versionDir) {
|
|
26
|
+
const manifest = readDevUploadManifest(versionDir);
|
|
65
27
|
if (manifest === null) {
|
|
66
28
|
throw new Error(`dev-uploads manifest missing or invalid in ${versionDir}`);
|
|
67
29
|
}
|
|
@@ -74,7 +36,7 @@ async function packDevUploadVersionDir(versionDir) {
|
|
|
74
36
|
throw new Error(`dev-uploads tarball listed in manifest is missing: ${filename}`);
|
|
75
37
|
}
|
|
76
38
|
}
|
|
77
|
-
if (!fs.existsSync(path.join(versionDir,
|
|
39
|
+
if (!fs.existsSync(path.join(versionDir, DEV_UPLOAD_MANIFEST_FILE))) {
|
|
78
40
|
throw new Error(`dev-uploads manifest file missing in ${versionDir}`);
|
|
79
41
|
}
|
|
80
42
|
const entries = fs.readdirSync(versionDir).filter((name) => {
|
|
@@ -100,7 +62,7 @@ async function packDevUploadVersionDir(versionDir) {
|
|
|
100
62
|
* atomically (stage sibling + rename). Validates version shape, entry names,
|
|
101
63
|
* and that the extracted layout matches the manifest.
|
|
102
64
|
*/
|
|
103
|
-
async function unpackDevUploadVersionBundle(args) {
|
|
65
|
+
export async function unpackDevUploadVersionBundle(args) {
|
|
104
66
|
const { serverRoot, version, bundle } = args;
|
|
105
67
|
if (!isSafeDevUploadVersion(version)) {
|
|
106
68
|
throw new Error(`Refused: version "${version}" is not a safe dev-channel version for staging`);
|
|
@@ -132,7 +94,7 @@ async function unpackDevUploadVersionBundle(args) {
|
|
|
132
94
|
if (refusedEntry !== null) {
|
|
133
95
|
throw new Error(`Refused: archive entry is not a basename: ${refusedEntry}`);
|
|
134
96
|
}
|
|
135
|
-
const manifest =
|
|
97
|
+
const manifest = readDevUploadManifest(stagingDir);
|
|
136
98
|
if (manifest === null) {
|
|
137
99
|
throw new Error('extracted archive has no valid manifest.json');
|
|
138
100
|
}
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ADAPTIVE_PROBE_PER_IP_PER_MINUTE = exports.ADAPTIVE_PROBE_BYTES = void 0;
|
|
4
|
-
exports.registerAdaptiveProbeRoute = registerAdaptiveProbeRoute;
|
|
5
1
|
/**
|
|
6
2
|
* Burst blob for adaptive-tier downlink measurement (D635).
|
|
7
3
|
*
|
|
@@ -24,16 +20,16 @@ exports.registerAdaptiveProbeRoute = registerAdaptiveProbeRoute;
|
|
|
24
20
|
* check the stream data plane applies — and is rate-limited per client IP.
|
|
25
21
|
* Everything a refusal returns is a few bytes.
|
|
26
22
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
import { randomBytes } from 'node:crypto';
|
|
24
|
+
import { isAuthorizedHealthRequest } from './health.routes.js';
|
|
25
|
+
import { clientKeyFromRequest } from '../../auth/auth-rate-limit.js';
|
|
26
|
+
export const ADAPTIVE_PROBE_BYTES = 1024 * 1024;
|
|
31
27
|
/**
|
|
32
28
|
* Probes a client IP may draw per minute: 12. The client probes at most once
|
|
33
29
|
* per 30 s per app (single-flight + cache), so 12 leaves room for several
|
|
34
30
|
* apps/devices behind one NAT and caps an abuser at 12 MiB/min.
|
|
35
31
|
*/
|
|
36
|
-
|
|
32
|
+
export const ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
|
|
37
33
|
/**
|
|
38
34
|
* Random, so it is INCOMPRESSIBLE. The previous body was one repeated byte and
|
|
39
35
|
* `@fastify/compress` (global in `main.ts`; its default types include
|
|
@@ -41,11 +37,11 @@ exports.ADAPTIVE_PROBE_PER_IP_PER_MINUTE = 12;
|
|
|
41
37
|
* trip and called it bandwidth. `compress: false` below stops our own
|
|
42
38
|
* compressor; randomness also defeats one in a relay on the way.
|
|
43
39
|
*/
|
|
44
|
-
const BODY =
|
|
45
|
-
function registerAdaptiveProbeRoute(fastify, deps) {
|
|
40
|
+
const BODY = randomBytes(ADAPTIVE_PROBE_BYTES);
|
|
41
|
+
export function registerAdaptiveProbeRoute(fastify, deps) {
|
|
46
42
|
fastify.get('/adaptive-probe', { compress: false }, async (req, reply) => {
|
|
47
43
|
reply.header('cache-control', 'no-store');
|
|
48
|
-
const authorized =
|
|
44
|
+
const authorized = isAuthorizedHealthRequest({
|
|
49
45
|
...(typeof req.headers.authorization === 'string'
|
|
50
46
|
? { authorization: req.headers.authorization }
|
|
51
47
|
: {}),
|
|
@@ -53,7 +49,7 @@ function registerAdaptiveProbeRoute(fastify, deps) {
|
|
|
53
49
|
}, deps.verifyToken);
|
|
54
50
|
if (!authorized)
|
|
55
51
|
return reply.status(401).send({ ok: false, error: 'unauthorized' });
|
|
56
|
-
const key =
|
|
52
|
+
const key = clientKeyFromRequest(req, deps.network);
|
|
57
53
|
if (key !== null) {
|
|
58
54
|
const verdict = deps.limiter.check(`adaptive-probe:${key}`);
|
|
59
55
|
if (!verdict.allowed) {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Health endpoints — fast probe surface for monitoring (k8s, uptime,
|
|
4
3
|
* external watchdogs).
|
|
@@ -19,17 +18,13 @@
|
|
|
19
18
|
* monitors talking to the hub and monitors talking directly to an agent
|
|
20
19
|
* (`http://<agent>:4444/health`) see identical payloads.
|
|
21
20
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
exports.isAuthorizedHealthRequest = isAuthorizedHealthRequest;
|
|
25
|
-
exports.registerHealthRoutes = registerHealthRoutes;
|
|
26
|
-
const runner_boot_check_js_1 = require("../../core/runner-health/runner-boot-check.js");
|
|
27
|
-
const session_cookie_js_1 = require("../../auth/session-cookie.js");
|
|
21
|
+
import { isRunnerBootCheckDegraded } from '../../core/runner-health/runner-boot-check.js';
|
|
22
|
+
import { isSessionGradeJwtPayload, readSessionCookieFromHeader } from '../../auth/session-cookie.js';
|
|
28
23
|
const AGENT_HEALTH_TIMEOUT_MS = 3_000;
|
|
29
24
|
function nowIso() {
|
|
30
25
|
return new Date().toISOString();
|
|
31
26
|
}
|
|
32
|
-
async function buildHubHealth(deps, proc = process) {
|
|
27
|
+
export async function buildHubHealth(deps, proc = process) {
|
|
33
28
|
// Fan-out-free: in-memory registry snapshot only, never a per-node RPC (#26).
|
|
34
29
|
const nodes = deps.agentRegistry.listNodeLiveness();
|
|
35
30
|
const remote = nodes.filter((n) => !n.isHub);
|
|
@@ -40,7 +35,7 @@ async function buildHubHealth(deps, proc = process) {
|
|
|
40
35
|
const runners = check === undefined
|
|
41
36
|
? undefined
|
|
42
37
|
: {
|
|
43
|
-
degraded:
|
|
38
|
+
degraded: isRunnerBootCheckDegraded(check),
|
|
44
39
|
expected: check.expected,
|
|
45
40
|
running: check.running,
|
|
46
41
|
failed: check.failed.length,
|
|
@@ -90,16 +85,16 @@ async function fetchAgentHealth(deps, nodeId) {
|
|
|
90
85
|
* (agent ids, versions, pids) — public probes get only `{ok}`.
|
|
91
86
|
* Pure over (headers, verifier) so the spec exercises it directly.
|
|
92
87
|
*/
|
|
93
|
-
function isAuthorizedHealthRequest(headers, verifyToken) {
|
|
88
|
+
export function isAuthorizedHealthRequest(headers, verifyToken) {
|
|
94
89
|
const bearer = headers.authorization?.startsWith('Bearer ')
|
|
95
90
|
? headers.authorization.slice('Bearer '.length)
|
|
96
91
|
: null;
|
|
97
|
-
const cookieToken =
|
|
92
|
+
const cookieToken = readSessionCookieFromHeader(headers.cookie);
|
|
98
93
|
for (const token of [bearer, cookieToken]) {
|
|
99
94
|
if (!token)
|
|
100
95
|
continue;
|
|
101
96
|
try {
|
|
102
|
-
if (
|
|
97
|
+
if (isSessionGradeJwtPayload(verifyToken(token)))
|
|
103
98
|
return true;
|
|
104
99
|
}
|
|
105
100
|
catch {
|
|
@@ -108,7 +103,7 @@ function isAuthorizedHealthRequest(headers, verifyToken) {
|
|
|
108
103
|
}
|
|
109
104
|
return false;
|
|
110
105
|
}
|
|
111
|
-
function registerHealthRoutes(fastify, deps) {
|
|
106
|
+
export function registerHealthRoutes(fastify, deps) {
|
|
112
107
|
const authorized = (req) => isAuthorizedHealthRequest({
|
|
113
108
|
...(typeof req.headers.authorization === 'string'
|
|
114
109
|
? { authorization: req.headers.authorization }
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HubAddressUnavailableError = void 0;
|
|
4
|
-
exports.resolveHubBaseUrl = resolveHubBaseUrl;
|
|
5
|
-
exports.clusterBaseUrlResolver = clusterBaseUrlResolver;
|
|
6
1
|
/** Thrown when the hub cannot name an address `audience` can reach. */
|
|
7
|
-
class HubAddressUnavailableError extends Error {
|
|
2
|
+
export class HubAddressUnavailableError extends Error {
|
|
8
3
|
audience;
|
|
9
4
|
reason;
|
|
10
5
|
constructor(audience, reason) {
|
|
@@ -17,13 +12,12 @@ class HubAddressUnavailableError extends Error {
|
|
|
17
12
|
this.name = 'HubAddressUnavailableError';
|
|
18
13
|
}
|
|
19
14
|
}
|
|
20
|
-
exports.HubAddressUnavailableError = HubAddressUnavailableError;
|
|
21
15
|
/**
|
|
22
16
|
* Resolve the hub's base URL for `audience` from the live provider. Called per
|
|
23
17
|
* delivery — interfaces and the allowlist move, and a deploy is rare enough
|
|
24
18
|
* that a cache would only add a way to be stale.
|
|
25
19
|
*/
|
|
26
|
-
async function resolveHubBaseUrl(getSource, audience) {
|
|
20
|
+
export async function resolveHubBaseUrl(getSource, audience) {
|
|
27
21
|
const source = getSource();
|
|
28
22
|
if (source === null)
|
|
29
23
|
throw new HubAddressUnavailableError(audience, 'local-network-unavailable');
|
|
@@ -32,6 +26,6 @@ async function resolveHubBaseUrl(getSource, audience) {
|
|
|
32
26
|
throw new HubAddressUnavailableError(audience, 'no-reachable-endpoint');
|
|
33
27
|
return baseUrl;
|
|
34
28
|
}
|
|
35
|
-
function clusterBaseUrlResolver(getSource) {
|
|
29
|
+
export function clusterBaseUrlResolver(getSource) {
|
|
36
30
|
return () => resolveHubBaseUrl(getSource, 'internal');
|
|
37
31
|
}
|
|
@@ -1,46 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.tarModelFiles = tarModelFiles;
|
|
37
|
-
exports.distributeModelWith = distributeModelWith;
|
|
38
|
-
exports.buildModelDistributorProvider = buildModelDistributorProvider;
|
|
39
|
-
const node_child_process_1 = require("node:child_process");
|
|
40
|
-
const fs = __importStar(require("node:fs"));
|
|
41
|
-
const path = __importStar(require("node:path"));
|
|
42
|
-
const system_1 = require("@camstack/system");
|
|
43
|
-
const addon_upload_js_1 = require("./addon-upload.js");
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { collectModelFiles, isModelDownloaded } from '@camstack/system';
|
|
5
|
+
import { buildHubHttpSource } from './addon-upload.js';
|
|
44
6
|
const AGENT_DISTRIBUTE_TIMEOUT_MS = 60_000;
|
|
45
7
|
function hubModelsDir() {
|
|
46
8
|
return path.join(process.env['CAMSTACK_DATA'] ?? 'camstack-data', 'models');
|
|
@@ -50,9 +12,9 @@ function hubModelsDir() {
|
|
|
50
12
|
* Async (spawn, not execFileSync) so a large model doesn't block the event
|
|
51
13
|
* loop. The agent untars this exact buffer into its own modelsDir.
|
|
52
14
|
*/
|
|
53
|
-
function tarModelFiles(cwd, files) {
|
|
15
|
+
export function tarModelFiles(cwd, files) {
|
|
54
16
|
return new Promise((resolve, reject) => {
|
|
55
|
-
const child =
|
|
17
|
+
const child = spawn('tar', ['-czf', '-', '-C', cwd, ...files]);
|
|
56
18
|
const chunks = [];
|
|
57
19
|
const errChunks = [];
|
|
58
20
|
child.stdout.on('data', (c) => chunks.push(c));
|
|
@@ -71,7 +33,7 @@ function tarModelFiles(cwd, files) {
|
|
|
71
33
|
* precondition-check → collect → tar → stage → trigger the agent pull.
|
|
72
34
|
* `nodeId === 'hub'` is a no-op (the artifact is already resident).
|
|
73
35
|
*/
|
|
74
|
-
async function distributeModelWith(seam, input) {
|
|
36
|
+
export async function distributeModelWith(seam, input) {
|
|
75
37
|
const { targetNodeId, modelId, format, entry } = input;
|
|
76
38
|
if (targetNodeId === 'hub') {
|
|
77
39
|
return { ok: true, sha256: '', bytes: 0, path: seam.modelsDir };
|
|
@@ -79,7 +41,7 @@ async function distributeModelWith(seam, input) {
|
|
|
79
41
|
if (!seam.isPresent(entry, format)) {
|
|
80
42
|
throw new Error(`model ${modelId}/${format} not present on hub — download or convert it first`);
|
|
81
43
|
}
|
|
82
|
-
const files =
|
|
44
|
+
const files = collectModelFiles(entry, format).filter((f) => seam.fileExists(f));
|
|
83
45
|
if (files.length === 0) {
|
|
84
46
|
throw new Error(`model ${modelId}/${format} resolved no files to distribute`);
|
|
85
47
|
}
|
|
@@ -94,17 +56,17 @@ async function distributeModelWith(seam, input) {
|
|
|
94
56
|
* Moleculer broker + the deploy-stage registry, which a forked addon can't
|
|
95
57
|
* reach.
|
|
96
58
|
*/
|
|
97
|
-
function buildModelDistributorProvider(moleculer, loggingService,
|
|
59
|
+
export function buildModelDistributorProvider(moleculer, loggingService,
|
|
98
60
|
/** The `local-network` cap's cluster address (`hub-cluster-url.ts`). */
|
|
99
61
|
resolveClusterBaseUrl) {
|
|
100
62
|
const logger = loggingService.createLogger('model-distributor');
|
|
101
63
|
const modelsDir = hubModelsDir();
|
|
102
64
|
const seam = {
|
|
103
65
|
modelsDir,
|
|
104
|
-
isPresent: (entry, format) =>
|
|
66
|
+
isPresent: (entry, format) => isModelDownloaded(modelsDir, entry, format),
|
|
105
67
|
fileExists: (rel) => fs.existsSync(path.join(modelsDir, rel)),
|
|
106
68
|
tar: (files) => tarModelFiles(modelsDir, files),
|
|
107
|
-
stage: async (buffer) =>
|
|
69
|
+
stage: async (buffer) => buildHubHttpSource(buffer, await resolveClusterBaseUrl()),
|
|
108
70
|
callAgent: async (nodeId, payload) => {
|
|
109
71
|
const broker = moleculer?.broker;
|
|
110
72
|
if (!broker)
|
|
@@ -1,28 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.renderConsentPage = renderConsentPage;
|
|
4
|
-
const app_page_shell_js_1 = require("../../auth/app-page-shell.js");
|
|
5
|
-
const app_page_strings_js_1 = require("../../auth/app-page-strings.js");
|
|
1
|
+
import { appHiddenField, appHint, appSubmitButton, escapeHtml, renderAppPage, } from '../../auth/app-page-shell.js';
|
|
2
|
+
import { appStrings } from '../../auth/app-page-strings.js';
|
|
6
3
|
/** Allow/Deny consent screen on the hub's shared page shell (the look of the
|
|
7
4
|
* app sign-in pages). Submitting POSTs to the same path with the hidden query
|
|
8
5
|
* fields + `consent=allow|deny`. */
|
|
9
|
-
function renderConsentPage(input) {
|
|
6
|
+
export function renderConsentPage(input) {
|
|
10
7
|
const hidden = Object.entries(input.hidden)
|
|
11
|
-
.map(([name, value]) =>
|
|
8
|
+
.map(([name, value]) => appHiddenField(name, value))
|
|
12
9
|
.join('');
|
|
13
|
-
const t =
|
|
10
|
+
const t = appStrings(input.lang).consent;
|
|
14
11
|
const destination = input.redirectUri
|
|
15
|
-
? `<p class="hint">${
|
|
12
|
+
? `<p class="hint">${escapeHtml(t.sendingTo)}<code>${escapeHtml(input.redirectUri)}</code></p>`
|
|
16
13
|
: '';
|
|
17
|
-
return
|
|
14
|
+
return renderAppPage({
|
|
18
15
|
lang: input.lang,
|
|
19
16
|
title: `${t.titlePrefix}${input.displayName}`,
|
|
20
17
|
heading: `${t.headingPrefix}${input.displayName}`,
|
|
21
18
|
body: [
|
|
22
|
-
`<p>${
|
|
23
|
-
|
|
19
|
+
`<p>${escapeHtml(t.signedInAs)}<strong>${escapeHtml(input.username)}</strong></p>`,
|
|
20
|
+
appHint(`${t.grantPrefix}${input.scopeSummary}`),
|
|
24
21
|
destination,
|
|
25
|
-
`<form method="POST">${hidden}<div class="actions">${
|
|
22
|
+
`<form method="POST">${hidden}<div class="actions">${appSubmitButton(t.allow, 'consent', 'allow')}${appSubmitButton(t.deny, 'consent', 'deny', true)}</div></form>`,
|
|
26
23
|
].join(''),
|
|
27
24
|
});
|
|
28
25
|
}
|
|
@@ -1,15 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
exports.validateAuthorizeQuery = validateAuthorizeQuery;
|
|
6
|
-
exports.isRedirectUriAllowed = isRedirectUriAllowed;
|
|
7
|
-
exports.summariseScopes = summariseScopes;
|
|
8
|
-
exports.registerOauth2Routes = registerOauth2Routes;
|
|
9
|
-
const session_cookie_js_1 = require("../../auth/session-cookie.js");
|
|
10
|
-
const app_page_strings_js_1 = require("../../auth/app-page-strings.js");
|
|
11
|
-
const consent_page_js_1 = require("./consent-page.js");
|
|
12
|
-
const private_host_js_1 = require("./private-host.js");
|
|
1
|
+
import { loginRedirectUrl, SESSION_COOKIE, shouldRedirectToLogin, } from '../../auth/session-cookie.js';
|
|
2
|
+
import { resolveAppPageLang } from '../../auth/app-page-strings.js';
|
|
3
|
+
import { renderConsentPage } from './consent-page.js';
|
|
4
|
+
import { isPrivateHost } from './private-host.js';
|
|
13
5
|
/**
|
|
14
6
|
* Query keys whose VALUE may be logged.
|
|
15
7
|
*
|
|
@@ -34,7 +26,7 @@ function truncate(value, max) {
|
|
|
34
26
|
return value.length > max ? `${value.slice(0, max)}…` : value;
|
|
35
27
|
}
|
|
36
28
|
/** Rebuild a query string with every non-allow-listed value replaced. */
|
|
37
|
-
function redactAuthorizeQuery(rawQuery) {
|
|
29
|
+
export function redactAuthorizeQuery(rawQuery) {
|
|
38
30
|
if (rawQuery === '')
|
|
39
31
|
return '';
|
|
40
32
|
const parts = [];
|
|
@@ -57,7 +49,7 @@ function describeReferer(raw) {
|
|
|
57
49
|
}
|
|
58
50
|
}
|
|
59
51
|
/** Everything the log is allowed to know about an inbound authorize call. */
|
|
60
|
-
function describeAuthorizeCall(url, headers, hasSessionCookie) {
|
|
52
|
+
export function describeAuthorizeCall(url, headers, hasSessionCookie) {
|
|
61
53
|
const q = url.indexOf('?');
|
|
62
54
|
const ua = headers['user-agent'];
|
|
63
55
|
return {
|
|
@@ -118,7 +110,7 @@ function resolveIntegrationParam(raw) {
|
|
|
118
110
|
* NOT checked — that pair is verified only at the Lambda boundary, and a
|
|
119
111
|
* PUBLIC client (`requiresPkce`) has no secret to check it against at all;
|
|
120
112
|
* the S256 challenge is what binds the code to its requester instead. */
|
|
121
|
-
function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
|
|
113
|
+
export function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
|
|
122
114
|
if (q.response_type !== 'code')
|
|
123
115
|
return { ok: false, status: 400, error: 'unsupported_response_type' };
|
|
124
116
|
// Four distinct faults used to collapse into one opaque string.
|
|
@@ -198,7 +190,7 @@ function validateAuthorizeQuery(q, knownIntegrations, pendingAddons = []) {
|
|
|
198
190
|
* `startsWith` on a string the browser will parse differently is exactly how an
|
|
199
191
|
* allow-list gets walked around.
|
|
200
192
|
*/
|
|
201
|
-
function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPaths = []) {
|
|
193
|
+
export function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPaths = []) {
|
|
202
194
|
if (allowedPrefixes.some((p) => redirectUri.startsWith(p)))
|
|
203
195
|
return true;
|
|
204
196
|
if (allowedPrivateHostPaths.length === 0)
|
|
@@ -212,12 +204,12 @@ function isRedirectUriAllowed(redirectUri, allowedPrefixes, allowedPrivateHostPa
|
|
|
212
204
|
}
|
|
213
205
|
if (url.protocol !== 'http:' && url.protocol !== 'https:')
|
|
214
206
|
return false;
|
|
215
|
-
if (!
|
|
207
|
+
if (!isPrivateHost(url.hostname))
|
|
216
208
|
return false;
|
|
217
209
|
return allowedPrivateHostPaths.includes(url.pathname);
|
|
218
210
|
}
|
|
219
211
|
/** One-line human summary of a scope list for the consent screen. */
|
|
220
|
-
function summariseScopes(scopes) {
|
|
212
|
+
export function summariseScopes(scopes) {
|
|
221
213
|
if (scopes.some((s) => s.type === 'category' && s.target === 'device')) {
|
|
222
214
|
return 'view and control all your cameras and devices';
|
|
223
215
|
}
|
|
@@ -257,10 +249,10 @@ function refuseAuthorize(reply, logger, method, call, refusal) {
|
|
|
257
249
|
* it" is invisible and every refusal reads as a first arrival.
|
|
258
250
|
*/
|
|
259
251
|
function refuseUnauthenticated(request, reply, logger, call, reason) {
|
|
260
|
-
const redirected =
|
|
252
|
+
const redirected = shouldRedirectToLogin(request.method, request.headers.accept);
|
|
261
253
|
logger.info(redirected ? 'oauth2 authorize bounced to login' : 'oauth2 authorize refused: unauthenticated', { meta: { method: request.method, reason, redirected, ...call } });
|
|
262
254
|
if (redirected)
|
|
263
|
-
return reply.redirect(
|
|
255
|
+
return reply.redirect(loginRedirectUrl(request.url));
|
|
264
256
|
return reply.status(401).send({ error: 'unauthorized' });
|
|
265
257
|
}
|
|
266
258
|
/** Read integrationId → descriptor from every registered `oauth-integration`
|
|
@@ -286,7 +278,7 @@ function parseFormBody(raw) {
|
|
|
286
278
|
}
|
|
287
279
|
return result;
|
|
288
280
|
}
|
|
289
|
-
function registerOauth2Routes(fastify, deps) {
|
|
281
|
+
export function registerOauth2Routes(fastify, deps) {
|
|
290
282
|
// Register a content-type parser for application/x-www-form-urlencoded so that
|
|
291
283
|
// consent POST and token POST can read form bodies. @fastify/formbody is not in
|
|
292
284
|
// the project's dependencies; we use URLSearchParams (Node built-in) instead.
|
|
@@ -303,7 +295,7 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
303
295
|
// the PWA service-worker navigate fallback, and the Vite dev proxy — no
|
|
304
296
|
// per-path special-casing anywhere.
|
|
305
297
|
fastify.get('/api/oauth2/authorize', async (request, reply) => {
|
|
306
|
-
const cookie = request.cookies[
|
|
298
|
+
const cookie = request.cookies[SESSION_COOKIE];
|
|
307
299
|
const call = describeAuthorizeCall(request.url, request.headers, Boolean(cookie));
|
|
308
300
|
if (!cookie) {
|
|
309
301
|
return refuseUnauthenticated(request, reply, deps.logger, call, 'no-session-cookie');
|
|
@@ -341,8 +333,8 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
341
333
|
.status(400)
|
|
342
334
|
.send({ error: 'invalid_request — redirect_uri not allowed for this integration' });
|
|
343
335
|
}
|
|
344
|
-
const html =
|
|
345
|
-
lang:
|
|
336
|
+
const html = renderConsentPage({
|
|
337
|
+
lang: resolveAppPageLang({
|
|
346
338
|
lang: request.query['lang'],
|
|
347
339
|
acceptLanguage: request.headers['accept-language'],
|
|
348
340
|
}),
|
|
@@ -401,7 +393,7 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
401
393
|
});
|
|
402
394
|
// ─── POST /api/oauth2/authorize ───────────────────────────────────────────
|
|
403
395
|
fastify.post('/api/oauth2/authorize', async (request, reply) => {
|
|
404
|
-
const cookie = request.cookies[
|
|
396
|
+
const cookie = request.cookies[SESSION_COOKIE];
|
|
405
397
|
// `query` is empty here by nature, not by loss: the consent POST carries its
|
|
406
398
|
// parameters as form fields. `method: POST` in the same line says so.
|
|
407
399
|
const call = describeAuthorizeCall(request.url, request.headers, Boolean(cookie));
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Is this hostname unreachable from the public internet?
|
|
4
3
|
*
|
|
@@ -15,8 +14,6 @@
|
|
|
15
14
|
* not the one the browser will use). Names are admitted only by suffix, from a
|
|
16
15
|
* closed list of suffixes that cannot be registered on the public internet.
|
|
17
16
|
*/
|
|
18
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.isPrivateHost = isPrivateHost;
|
|
20
17
|
/** Suffixes that are, by definition, not publicly routable names. */
|
|
21
18
|
const PRIVATE_NAME_SUFFIXES = ['.local', '.internal', '.home.arpa', '.ts.net'];
|
|
22
19
|
/** Names that are exactly the loopback host. */
|
|
@@ -67,7 +64,7 @@ function isPrivateIpv6(host) {
|
|
|
67
64
|
* True iff `host` (a `URL.hostname`, already lowercased by the URL parser) is
|
|
68
65
|
* private by literal inspection. Never resolves.
|
|
69
66
|
*/
|
|
70
|
-
function isPrivateHost(host) {
|
|
67
|
+
export function isPrivateHost(host) {
|
|
71
68
|
if (host === '')
|
|
72
69
|
return false;
|
|
73
70
|
if (LOOPBACK_NAMES.includes(host))
|