@ampless/backend 1.0.0-beta.77 → 1.0.0-beta.79
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/README.ja.md +2 -2
- package/README.md +2 -2
- package/dist/events/processor-trusted.js +11 -11
- package/dist/index.d.ts +20 -1
- package/dist/index.js +28 -12
- package/package.json +3 -3
package/README.ja.md
CHANGED
|
@@ -64,7 +64,7 @@ amplessAuthConfig({ // カスタム
|
|
|
64
64
|
amplessAuthConfig({ postConfirmation, webAuthn: false }) // パスワードのみのサインイン
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
Amplify Hosting パイプラインビルドでは、テンプレートが `cms.config.ts` の `site.url` から `resolveWebAuthn({ override, siteUrl, isPipeline })` を通じて Relying Party ID を自動導出します。最も一般的なケースでは手動設定不要です。`ampx sandbox` では RP ID は `localhost` のまま(Amplify が自動解決)です。管理画面を `site.url` と**異なるサブドメイン**で配信している場合は、`amplify/auth/resource.custom.ts` でオペレーターがアクセスする bare domain を `relyingPartyId` に固定してください。パスキー登録後に RP ID を変更すると、登録済みの認証情報がすべて無効化されます。[docs/passkeys.ja.md](https://github.com/heavymoons/ampless/blob/main/docs/passkeys.ja.md) を参照してください。
|
|
68
68
|
|
|
69
69
|
### `amplify/data/resource.ts`
|
|
70
70
|
|
|
@@ -127,7 +127,7 @@ export { handler } from '@ampless/backend/functions/api-key-renewer'
|
|
|
127
127
|
|
|
128
128
|
## サブパス
|
|
129
129
|
|
|
130
|
-
- `@ampless/backend` — `defineAmplessBackend`、`amplessAuthConfig`、`amplessStorageConfig`、`amplessSchemaModels`、`extendAmplessSchema`、`defaultAuthorizationModes`
|
|
130
|
+
- `@ampless/backend` — `defineAmplessBackend`、`amplessAuthConfig`、`resolveWebAuthn`、`amplessStorageConfig`、`amplessSchemaModels`、`extendAmplessSchema`、`defaultAuthorizationModes`
|
|
131
131
|
- `@ampless/backend/auth/post-confirmation` — Lambda ハンドラー
|
|
132
132
|
- `@ampless/backend/events/dispatcher` — Lambda ハンドラー
|
|
133
133
|
- `@ampless/backend/events/processor-trusted` — `createProcessorTrustedHandler({ plugins, site })`
|
package/README.md
CHANGED
|
@@ -64,7 +64,7 @@ amplessAuthConfig({ // pin the Relyin
|
|
|
64
64
|
amplessAuthConfig({ postConfirmation, webAuthn: false }) // password-only sign-in
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
In Amplify Hosting pipeline builds the template auto-derives the Relying Party ID from `site.url` in `cms.config.ts` via `resolveWebAuthn({ override, siteUrl, isPipeline })` — no manual configuration needed for the common case. In `ampx sandbox` the RP ID stays `localhost` (auto-resolved by Amplify). If the admin is served from a **different subdomain** than `site.url`, pin `relyingPartyId` to the bare domain operators visit in `amplify/auth/resource.custom.ts`. Changing the RP ID after passkeys exist invalidates every registered credential. See [docs/passkeys.md](https://github.com/heavymoons/ampless/blob/main/docs/passkeys.md).
|
|
68
68
|
|
|
69
69
|
### `amplify/data/resource.ts`
|
|
70
70
|
|
|
@@ -127,7 +127,7 @@ export { handler } from '@ampless/backend/functions/api-key-renewer'
|
|
|
127
127
|
|
|
128
128
|
## Sub-paths
|
|
129
129
|
|
|
130
|
-
- `@ampless/backend` — `defineAmplessBackend`, `amplessAuthConfig`, `amplessStorageConfig`, `amplessSchemaModels`, `extendAmplessSchema`, `defaultAuthorizationModes`
|
|
130
|
+
- `@ampless/backend` — `defineAmplessBackend`, `amplessAuthConfig`, `resolveWebAuthn`, `amplessStorageConfig`, `amplessSchemaModels`, `extendAmplessSchema`, `defaultAuthorizationModes`
|
|
131
131
|
- `@ampless/backend/auth/post-confirmation` — Lambda handler
|
|
132
132
|
- `@ampless/backend/events/dispatcher` — Lambda handler
|
|
133
133
|
- `@ampless/backend/events/processor-trusted` — `createProcessorTrustedHandler({ plugins, site })`
|
|
@@ -64,14 +64,6 @@ function decryptSecret(rawKey, b64) {
|
|
|
64
64
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
65
65
|
return plaintext.toString("utf8");
|
|
66
66
|
}
|
|
67
|
-
function safeParse(s) {
|
|
68
|
-
try {
|
|
69
|
-
return JSON.parse(s);
|
|
70
|
-
} catch (err) {
|
|
71
|
-
console.warn("[trusted-processor] post.body is not valid JSON; passing through as string", err);
|
|
72
|
-
return s;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
67
|
function createProcessorTrustedHandler(opts) {
|
|
76
68
|
const privilegedHookedPlugins = (opts.plugins ?? []).filter(
|
|
77
69
|
(p) => typeof p === "object" && p.trust_level === "privileged" && !!p.hooks && Object.keys(p.hooks).length > 0
|
|
@@ -145,7 +137,15 @@ function createProcessorTrustedHandler(opts) {
|
|
|
145
137
|
title: row.title,
|
|
146
138
|
excerpt: row.excerpt ?? void 0,
|
|
147
139
|
format: row.format ?? "markdown",
|
|
148
|
-
|
|
140
|
+
// DynamoDBDocumentClient unmarshals AWSJSON-backed attributes
|
|
141
|
+
// into native JS types (S→string, N→number, BOOL→boolean,
|
|
142
|
+
// M→object), so `row.body` is already correctly typed here and
|
|
143
|
+
// must NOT be re-parsed. Re-running JSON.parse on a pure-numeric
|
|
144
|
+
// or JSON-looking string body (e.g. a markdown/html body of
|
|
145
|
+
// "1470" or "123") double-decodes it into a number and corrupts
|
|
146
|
+
// the post. Only the Amplify GraphQL-client read path returns an
|
|
147
|
+
// AWSJSON wire string and needs decodeAwsJson.
|
|
148
|
+
body: row.body,
|
|
149
149
|
status: row.status ?? "published",
|
|
150
150
|
publishedAt: row.publishedAt ?? void 0,
|
|
151
151
|
tags: Array.isArray(row.tags) ? row.tags : []
|
|
@@ -281,7 +281,7 @@ function createProcessorTrustedHandler(opts) {
|
|
|
281
281
|
const sk = row.sk;
|
|
282
282
|
if (!sk) continue;
|
|
283
283
|
const raw = row.value;
|
|
284
|
-
settings[sk] =
|
|
284
|
+
settings[sk] = raw;
|
|
285
285
|
}
|
|
286
286
|
exclusiveStartKey = res.LastEvaluatedKey;
|
|
287
287
|
} while (exclusiveStartKey);
|
|
@@ -314,7 +314,7 @@ function createProcessorTrustedHandler(opts) {
|
|
|
314
314
|
try {
|
|
315
315
|
await rebuildSiteSettingsCache();
|
|
316
316
|
} catch (err) {
|
|
317
|
-
console.error("[trusted-processor] site-settings-cache rebuild failed", err);
|
|
317
|
+
console.error("[trusted-processor][ALERT] site-settings-cache rebuild failed", err);
|
|
318
318
|
throw err;
|
|
319
319
|
}
|
|
320
320
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -120,6 +120,25 @@ interface AmplessAuthConfigOpts {
|
|
|
120
120
|
*/
|
|
121
121
|
webAuthn?: AmplessWebAuthnOption | false;
|
|
122
122
|
}
|
|
123
|
+
interface ResolveWebAuthnOpts {
|
|
124
|
+
/** Explicit override from resource.custom.ts. When present, takes precedence. */
|
|
125
|
+
override?: AmplessWebAuthnOption | false;
|
|
126
|
+
/** `site.url` from cms.config — used to derive hostname in pipeline builds. */
|
|
127
|
+
siteUrl: string;
|
|
128
|
+
/** True only in Amplify Hosting pipeline builds (`Boolean(process.env.AWS_BRANCH)`). */
|
|
129
|
+
isPipeline: boolean;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Single source of truth for the WebAuthn relying-party configuration.
|
|
133
|
+
*
|
|
134
|
+
* Priority:
|
|
135
|
+
* 1. `override !== undefined` → return it verbatim (supports `false` to disable).
|
|
136
|
+
* 2. Not a pipeline build (sandbox / local) → return `true` so Amplify
|
|
137
|
+
* auto-resolves the RP ID from `localhost` (no RP ID needed in dev).
|
|
138
|
+
* 3. Pipeline build → derive `{ relyingPartyId }` from `siteUrl`.
|
|
139
|
+
* Falls back to `true` if `siteUrl` is not a valid URL (logs a warning).
|
|
140
|
+
*/
|
|
141
|
+
declare function resolveWebAuthn(opts: ResolveWebAuthnOpts): AmplessWebAuthnOption | false;
|
|
123
142
|
/**
|
|
124
143
|
* Build the ampless Cognito configuration (User Pool + Identity Pool
|
|
125
144
|
* with the three role groups and the optional post-confirmation
|
|
@@ -327,4 +346,4 @@ declare function amplessSchemaAuthorization(allow: any, opts?: AmplessSchemaAuth
|
|
|
327
346
|
*/
|
|
328
347
|
declare const defaultAuthorizationModes: Parameters<typeof defineData>[0]['authorizationModes'];
|
|
329
348
|
|
|
330
|
-
export { type AmplessAuthConfigOpts, type AmplessBackend, type AmplessResolverPaths, type AmplessSchemaAuthorizationOpts, type AmplessSchemaModelsOpts, type AmplessWebAuthnOption, DEFAULT_RESOLVER_PATHS, type DefineAmplessBackendOpts, amplessAuthConfig, amplessSchemaAuthorization, amplessSchemaModels, amplessStorageConfig, defaultAuthorizationModes, defineAmplessBackend, extendAmplessSchema };
|
|
349
|
+
export { type AmplessAuthConfigOpts, type AmplessBackend, type AmplessResolverPaths, type AmplessSchemaAuthorizationOpts, type AmplessSchemaModelsOpts, type AmplessWebAuthnOption, DEFAULT_RESOLVER_PATHS, type DefineAmplessBackendOpts, type ResolveWebAuthnOpts, amplessAuthConfig, amplessSchemaAuthorization, amplessSchemaModels, amplessStorageConfig, defaultAuthorizationModes, defineAmplessBackend, extendAmplessSchema, resolveWebAuthn };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,9 @@ import { FunctionUrlAuthType, HttpMethod, StartingPosition } from "aws-cdk-lib/a
|
|
|
7
7
|
import { DynamoEventSource, SqsEventSource } from "aws-cdk-lib/aws-lambda-event-sources";
|
|
8
8
|
import { Rule, Schedule } from "aws-cdk-lib/aws-events";
|
|
9
9
|
import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
|
|
10
|
+
function siteSettingsCacheS3Resources(bucketArn) {
|
|
11
|
+
return [`${bucketArn}/public/plugins/*`, `${bucketArn}/public/site-settings.json`];
|
|
12
|
+
}
|
|
10
13
|
function defineAmplessBackend(opts) {
|
|
11
14
|
const backend = defineBackend({
|
|
12
15
|
auth: opts.auth,
|
|
@@ -152,17 +155,15 @@ function defineAmplessBackend(opts) {
|
|
|
152
155
|
new PolicyStatement({
|
|
153
156
|
effect: Effect.ALLOW,
|
|
154
157
|
actions: ["s3:PutObject", "s3:DeleteObject"],
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
`${backend.storage.resources.bucket.bucketArn}/public/site-settings.json`
|
|
165
|
-
]
|
|
158
|
+
// Built-in cache: rebuildSiteSettingsCache writes the single JSON
|
|
159
|
+
// file the public site reads. The resource list MUST contain the
|
|
160
|
+
// exact-match key `public/site-settings.json` — a wildcard like
|
|
161
|
+
// `public/site-settings/*` would NOT match the single-file key and
|
|
162
|
+
// the PutObject would fail silently with AccessDenied, so the public
|
|
163
|
+
// site would never see admin-side theme / settings changes. Extracted
|
|
164
|
+
// into siteSettingsCacheS3Resources() so backend.test.ts can guard
|
|
165
|
+
// the exact ARN against this regression.
|
|
166
|
+
resources: siteSettingsCacheS3Resources(backend.storage.resources.bucket.bucketArn)
|
|
166
167
|
})
|
|
167
168
|
);
|
|
168
169
|
const pluginSecretTable = backend.data.resources.tables["PluginSecret"];
|
|
@@ -264,6 +265,20 @@ function defineAmplessBackend(opts) {
|
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
// src/auth/index.ts
|
|
268
|
+
function resolveWebAuthn(opts) {
|
|
269
|
+
if (opts.override !== void 0) return opts.override;
|
|
270
|
+
if (!opts.isPipeline) return true;
|
|
271
|
+
try {
|
|
272
|
+
const hostname = new URL(opts.siteUrl).hostname;
|
|
273
|
+
return { relyingPartyId: hostname };
|
|
274
|
+
} catch {
|
|
275
|
+
console.warn(
|
|
276
|
+
"[ampless] invalid site.url for WebAuthn relying party, falling back to auto:",
|
|
277
|
+
opts.siteUrl
|
|
278
|
+
);
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
267
282
|
function amplessAuthConfig(opts = {}) {
|
|
268
283
|
return {
|
|
269
284
|
loginWith: {
|
|
@@ -749,5 +764,6 @@ export {
|
|
|
749
764
|
amplessStorageConfig,
|
|
750
765
|
defaultAuthorizationModes,
|
|
751
766
|
defineAmplessBackend,
|
|
752
|
-
extendAmplessSchema
|
|
767
|
+
extendAmplessSchema,
|
|
768
|
+
resolveWebAuthn
|
|
753
769
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ampless/backend",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.79",
|
|
4
4
|
"description": "Amplify Gen 2 backend factories for ampless: auth, data, storage, event processors, API key renewer",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"@smithy/protocol-http": "^5.4.4",
|
|
70
70
|
"@smithy/signature-v4": "^5.4.4",
|
|
71
71
|
"fflate": "^0.8.3",
|
|
72
|
-
"@ampless/mcp-server": "1.0.0-beta.
|
|
73
|
-
"ampless": "1.0.0-beta.
|
|
72
|
+
"@ampless/mcp-server": "1.0.0-beta.59",
|
|
73
|
+
"ampless": "1.0.0-beta.53"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@aws-amplify/backend": "^1.19.0",
|