@camstack/server 1.2.602 → 1.2.603
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.
|
@@ -6,6 +6,7 @@ exports.validateAuthorizeQuery = validateAuthorizeQuery;
|
|
|
6
6
|
exports.isRedirectUriAllowed = isRedirectUriAllowed;
|
|
7
7
|
exports.summariseScopes = summariseScopes;
|
|
8
8
|
exports.registerOauth2Routes = registerOauth2Routes;
|
|
9
|
+
const types_1 = require("@camstack/types");
|
|
9
10
|
const session_cookie_js_1 = require("../../auth/session-cookie.js");
|
|
10
11
|
const app_page_strings_js_1 = require("../../auth/app-page-strings.js");
|
|
11
12
|
const consent_page_js_1 = require("./consent-page.js");
|
|
@@ -232,7 +233,7 @@ function summariseScopes(scopes) {
|
|
|
232
233
|
* weakened. The RESPONSE carries only the caller's own echoed input; it tells
|
|
233
234
|
* a client nothing about what else this hub has installed.
|
|
234
235
|
*/
|
|
235
|
-
function refuseAuthorize(reply, logger, method, call, refusal) {
|
|
236
|
+
function refuseAuthorize(request, reply, logger, method, call, refusal) {
|
|
236
237
|
logger.warn(`oauth2 authorize refused: ${refusal.error}`, {
|
|
237
238
|
meta: {
|
|
238
239
|
method,
|
|
@@ -245,7 +246,28 @@ function refuseAuthorize(reply, logger, method, call, refusal) {
|
|
|
245
246
|
if (refusal.retryAfterSec !== undefined) {
|
|
246
247
|
void reply.header('Retry-After', String(refusal.retryAfterSec));
|
|
247
248
|
}
|
|
248
|
-
return reply
|
|
249
|
+
return answerRefusal(request, reply, refusal.status, { error: refusal.error, ...refusal.detail }, refusal.status === 503 ? 'unavailable' : 'invalid_request', typeof refusal.detail?.received === 'string' ? refusal.detail.received : undefined);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Answer a refused authorize. A BROWSER (it asked for HTML: a person who
|
|
253
|
+
* followed a link) is sent to the CamStack completion page with a reason CODE
|
|
254
|
+
* — a bare JSON body is a dead end for them. A machine caller keeps the status
|
|
255
|
+
* and JSON it always got. Relative: the browser is already on the hub's origin,
|
|
256
|
+
* and nothing the request carried (the redirect target, the state, any code)
|
|
257
|
+
* goes into the URL.
|
|
258
|
+
*/
|
|
259
|
+
function answerRefusal(request, reply, status, body, reason, integration) {
|
|
260
|
+
const accept = request.headers.accept;
|
|
261
|
+
if (typeof accept === 'string' && accept.includes('text/html')) {
|
|
262
|
+
return reply.redirect((0, types_1.oauthLandingUrl)(null, {
|
|
263
|
+
status: 'error',
|
|
264
|
+
reason,
|
|
265
|
+
...(integration !== undefined && /^[A-Za-z0-9._-]{1,64}$/.test(integration)
|
|
266
|
+
? { integration }
|
|
267
|
+
: {}),
|
|
268
|
+
}));
|
|
269
|
+
}
|
|
270
|
+
return reply.status(status).send(body);
|
|
249
271
|
}
|
|
250
272
|
/**
|
|
251
273
|
* An authorize call turned away for want of a usable session.
|
|
@@ -317,13 +339,13 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
317
339
|
}
|
|
318
340
|
const registry = deps.getRegistry();
|
|
319
341
|
if (!registry) {
|
|
320
|
-
return reply
|
|
342
|
+
return answerRefusal(request, reply, 503, { error: 'service_unavailable' }, 'unavailable');
|
|
321
343
|
}
|
|
322
344
|
const { descriptors, pendingAddons } = await readIntegrationRegistry(registry);
|
|
323
345
|
const query = request.query;
|
|
324
346
|
const v = validateAuthorizeQuery(query, descriptors, pendingAddons);
|
|
325
347
|
if (!v.ok) {
|
|
326
|
-
return refuseAuthorize(reply, deps.logger, 'GET', call, v);
|
|
348
|
+
return refuseAuthorize(request, reply, deps.logger, 'GET', call, v);
|
|
327
349
|
}
|
|
328
350
|
const descriptor = descriptors.get(v.integration);
|
|
329
351
|
if (!isRedirectUriAllowed(v.redirectUri, descriptor.allowedRedirectPrefixes, descriptor.allowedPrivateHostPaths ?? [])) {
|
|
@@ -337,9 +359,7 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
337
359
|
allowedPrivateHostPaths: descriptor.allowedPrivateHostPaths ?? [],
|
|
338
360
|
},
|
|
339
361
|
});
|
|
340
|
-
return reply
|
|
341
|
-
.status(400)
|
|
342
|
-
.send({ error: 'invalid_request — redirect_uri not allowed for this integration' });
|
|
362
|
+
return answerRefusal(request, reply, 400, { error: 'invalid_request — redirect_uri not allowed for this integration' }, 'invalid_request', v.integration);
|
|
343
363
|
}
|
|
344
364
|
const html = (0, consent_page_js_1.renderConsentPage)({
|
|
345
365
|
lang: (0, app_page_strings_js_1.resolveAppPageLang)({
|
|
@@ -417,7 +437,7 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
417
437
|
}
|
|
418
438
|
const registry = deps.getRegistry();
|
|
419
439
|
if (!registry) {
|
|
420
|
-
return reply
|
|
440
|
+
return answerRefusal(request, reply, 503, { error: 'service_unavailable' }, 'unavailable');
|
|
421
441
|
}
|
|
422
442
|
const { descriptors, pendingAddons } = await readIntegrationRegistry(registry);
|
|
423
443
|
const body = request.body;
|
|
@@ -433,7 +453,7 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
433
453
|
// and every one of them is attacker-editable.
|
|
434
454
|
const v = validateAuthorizeQuery(formQuery, descriptors, pendingAddons);
|
|
435
455
|
if (!v.ok) {
|
|
436
|
-
return refuseAuthorize(reply, deps.logger, 'POST', call, v);
|
|
456
|
+
return refuseAuthorize(request, reply, deps.logger, 'POST', call, v);
|
|
437
457
|
}
|
|
438
458
|
const descriptor = descriptors.get(v.integration);
|
|
439
459
|
if (!isRedirectUriAllowed(v.redirectUri, descriptor.allowedRedirectPrefixes, descriptor.allowedPrivateHostPaths ?? [])) {
|
|
@@ -447,9 +467,7 @@ function registerOauth2Routes(fastify, deps) {
|
|
|
447
467
|
allowedPrivateHostPaths: descriptor.allowedPrivateHostPaths ?? [],
|
|
448
468
|
},
|
|
449
469
|
});
|
|
450
|
-
return reply
|
|
451
|
-
.status(400)
|
|
452
|
-
.send({ error: 'invalid_request — redirect_uri not allowed for this integration' });
|
|
470
|
+
return answerRefusal(request, reply, 400, { error: 'invalid_request — redirect_uri not allowed for this integration' }, 'invalid_request', v.integration);
|
|
453
471
|
}
|
|
454
472
|
if (body.consent !== 'allow') {
|
|
455
473
|
return reply.redirect(`${v.redirectUri}?error=access_denied&state=${encodeURIComponent(v.state)}`);
|
|
@@ -4269,6 +4269,15 @@ function createCapRouter_dishwasher(getProvider, createRemoteProxy) {
|
|
|
4269
4269
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4270
4270
|
return p.pause(methodInput);
|
|
4271
4271
|
}),
|
|
4272
|
+
resume: trpc_middleware_js_1.protectedProcedure
|
|
4273
|
+
.input(types_56.dishwasherCapability.methods.resume.input.loose())
|
|
4274
|
+
.output(types_56.dishwasherCapability.methods.resume.output)
|
|
4275
|
+
.mutation(async ({ input, ctx }) => {
|
|
4276
|
+
const { nodeId, ...methodInput } = input;
|
|
4277
|
+
const p = resolveProvider('dishwasher', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4278
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4279
|
+
return p.resume(methodInput);
|
|
4280
|
+
}),
|
|
4272
4281
|
stop: trpc_middleware_js_1.protectedProcedure
|
|
4273
4282
|
.input(types_56.dishwasherCapability.methods.stop.input.loose())
|
|
4274
4283
|
.output(types_56.dishwasherCapability.methods.stop.output)
|
|
@@ -4359,6 +4368,15 @@ function createCapRouter_dishwasher(getProvider, createRemoteProxy) {
|
|
|
4359
4368
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4360
4369
|
return p.setOption(methodInput);
|
|
4361
4370
|
}),
|
|
4371
|
+
getOptions: trpc_middleware_js_1.protectedProcedure
|
|
4372
|
+
.input(types_56.dishwasherCapability.methods.getOptions.input.loose())
|
|
4373
|
+
.output(types_56.dishwasherCapability.methods.getOptions.output)
|
|
4374
|
+
.query(async ({ input, ctx }) => {
|
|
4375
|
+
const { nodeId, ...methodInput } = input;
|
|
4376
|
+
const p = resolveProvider('dishwasher', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
4377
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
4378
|
+
return p.getOptions(methodInput);
|
|
4379
|
+
}),
|
|
4362
4380
|
});
|
|
4363
4381
|
}
|
|
4364
4382
|
function createCapRouter_doorbell(getProvider, createRemoteProxy) {
|
|
@@ -11128,6 +11146,15 @@ function createCapRouter_storageMigration(getProvider, createRemoteProxy) {
|
|
|
11128
11146
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
11129
11147
|
return p.movers(methodInput);
|
|
11130
11148
|
}),
|
|
11149
|
+
moverClearance: trpc_middleware_js_1.adminProcedure
|
|
11150
|
+
.input(types_127.storageMigrationCapability.methods.moverClearance.input.loose())
|
|
11151
|
+
.output(types_127.storageMigrationCapability.methods.moverClearance.output)
|
|
11152
|
+
.query(async ({ input, ctx }) => {
|
|
11153
|
+
const { nodeId, ...methodInput } = input;
|
|
11154
|
+
const p = resolveProvider('storage-migration', nodeId, () => getProvider(ctx), createRemoteProxy);
|
|
11155
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
|
|
11156
|
+
return p.moverClearance(methodInput);
|
|
11157
|
+
}),
|
|
11131
11158
|
residue: trpc_middleware_js_1.adminProcedure
|
|
11132
11159
|
.input(types_127.storageMigrationCapability.methods.residue.input.loose())
|
|
11133
11160
|
.output(types_127.storageMigrationCapability.methods.residue.output)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.alexaLambdaPageStyleSource = alexaLambdaPageStyleSource;
|
|
4
|
+
/**
|
|
5
|
+
* The source text of the skill Lambda's `page-style.js`: the hub's standalone
|
|
6
|
+
* page stylesheet plus the brand mark, as constants. Kept here, beside
|
|
7
|
+
* `app-page-shell.ts`, so there is ONE place the look lives and a spec holds the
|
|
8
|
+
* Lambda's copy to it (`scripts/gen-alexa-lambda-page-style.ts` writes it).
|
|
9
|
+
*/
|
|
10
|
+
const app_page_shell_js_1 = require("./app-page-shell.js");
|
|
11
|
+
function alexaLambdaPageStyleSource() {
|
|
12
|
+
return `// biome-ignore-all format: generated file
|
|
13
|
+
// biome-ignore-all lint: generated file
|
|
14
|
+
/**
|
|
15
|
+
* GENERATED by scripts/gen-alexa-lambda-page-style.ts from the hub's page shell
|
|
16
|
+
* (server/backend/src/auth/app-page-shell.ts). Do not edit: change the shell and
|
|
17
|
+
* regenerate. The Lambda ships plain files, so the stylesheet travels as a constant.
|
|
18
|
+
*/
|
|
19
|
+
'use strict'
|
|
20
|
+
|
|
21
|
+
const STYLE = ${JSON.stringify(app_page_shell_js_1.APP_PAGE_STYLE)}
|
|
22
|
+
const LOGO_DARK = ${JSON.stringify(app_page_shell_js_1.APP_PAGE_LOGOS.dark)}
|
|
23
|
+
const LOGO_LIGHT = ${JSON.stringify(app_page_shell_js_1.APP_PAGE_LOGOS.light)}
|
|
24
|
+
|
|
25
|
+
module.exports = { STYLE, LOGO_DARK, LOGO_LIGHT }
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
@@ -64,6 +64,10 @@ const COMPONENT_CSS = [
|
|
|
64
64
|
`.error:empty{display:none}`,
|
|
65
65
|
`.btn:focus-visible,.link:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}`,
|
|
66
66
|
`code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;overflow-wrap:anywhere}`,
|
|
67
|
+
`.field{display:flex;flex-direction:column;gap:var(--spacing-md)}`,
|
|
68
|
+
`.field label{font-size:12px;line-height:16px;font-weight:500;color:var(--color-foreground-muted)}`,
|
|
69
|
+
`input[type=url],input[type=text]{width:100%;min-height:44px;padding:10px 12px;border:1px solid var(--color-border);border-radius:var(--radius-lg);background:var(--color-background);color:var(--color-foreground);font:inherit}`,
|
|
70
|
+
`input[type=url]:focus-visible,input[type=text]:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}`,
|
|
67
71
|
`form{display:contents}`,
|
|
68
72
|
`.actions{display:flex;flex-direction:column;gap:var(--spacing-md)}`,
|
|
69
73
|
].join('');
|
package/dist/manual-boot.js
CHANGED
|
@@ -267,7 +267,7 @@ async function bootManual(opts) {
|
|
|
267
267
|
throw new Error('the process service did not answer');
|
|
268
268
|
return rows;
|
|
269
269
|
},
|
|
270
|
-
// The verdict reaches the alert centre (one
|
|
270
|
+
// The verdict reaches the alert centre (one critical alert).
|
|
271
271
|
onResult: (check) => {
|
|
272
272
|
eventBusService.emit({
|
|
273
273
|
id: (0, node_crypto_1.randomUUID)(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/server",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.603",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"files": [
|
|
@@ -38,19 +38,19 @@
|
|
|
38
38
|
]
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@camstack/addon-admin-ui": "1.2.
|
|
42
|
-
"@camstack/addon-agent-ui": "1.2.
|
|
43
|
-
"@camstack/addon-auth": "1.2.
|
|
44
|
-
"@camstack/addon-decoder-nodeav": "1.2.
|
|
45
|
-
"@camstack/addon-notifiers": "1.2.
|
|
46
|
-
"@camstack/addon-pipeline": "1.2.
|
|
47
|
-
"@camstack/addon-pipeline-orchestrator": "1.2.
|
|
48
|
-
"@camstack/addon-post-analysis": "1.2.
|
|
49
|
-
"@camstack/develop": "0.1.
|
|
50
|
-
"@camstack/sdk": "1.2.
|
|
51
|
-
"@camstack/system": "1.2.
|
|
52
|
-
"@camstack/types": "1.2.
|
|
53
|
-
"@camstack/ui-library": "1.2.
|
|
41
|
+
"@camstack/addon-admin-ui": "1.2.440",
|
|
42
|
+
"@camstack/addon-agent-ui": "1.2.246",
|
|
43
|
+
"@camstack/addon-auth": "1.2.151",
|
|
44
|
+
"@camstack/addon-decoder-nodeav": "1.2.125",
|
|
45
|
+
"@camstack/addon-notifiers": "1.2.603",
|
|
46
|
+
"@camstack/addon-pipeline": "1.2.603",
|
|
47
|
+
"@camstack/addon-pipeline-orchestrator": "1.2.604",
|
|
48
|
+
"@camstack/addon-post-analysis": "1.2.608",
|
|
49
|
+
"@camstack/develop": "0.1.15",
|
|
50
|
+
"@camstack/sdk": "1.2.135",
|
|
51
|
+
"@camstack/system": "1.2.454",
|
|
52
|
+
"@camstack/types": "1.2.385",
|
|
53
|
+
"@camstack/ui-library": "1.2.302",
|
|
54
54
|
"@fastify/compress": "^9.0.0",
|
|
55
55
|
"@fastify/cookie": "^11.0.2",
|
|
56
56
|
"@fastify/cors": "^11.2.0",
|