@seliseblocks/cli-os 0.2.5 → 0.2.6
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.
|
@@ -7,7 +7,7 @@ import { requestContext } from "../../../lib/request-context.js";
|
|
|
7
7
|
import { parseCommand, selectedProject } from "../../../lib/workspace.js";
|
|
8
8
|
export async function authConfigSave(argv) {
|
|
9
9
|
const { flags } = parseCommand(argv);
|
|
10
|
-
const
|
|
10
|
+
const overrides = {
|
|
11
11
|
...(await jsonBodyFlag(flags)),
|
|
12
12
|
...compact({
|
|
13
13
|
absoluteRefreshTokenValidForNumberMinutes: optionalIntegerFlag(flags, "absolute-refresh-token-minutes"),
|
|
@@ -21,12 +21,22 @@ export async function authConfigSave(argv) {
|
|
|
21
21
|
rememberMeRefreshTokenValidForNumberMinutes: optionalIntegerFlag(flags, "remember-me-refresh-token-minutes")
|
|
22
22
|
})
|
|
23
23
|
};
|
|
24
|
+
const projectKey = await selectedProject(flags);
|
|
25
|
+
// POST /auth/config replaces the whole config document rather than merging
|
|
26
|
+
// (confirmed against the portal's own save call, which always resends every
|
|
27
|
+
// field it read on load) -- fetch the current config first so fields the
|
|
28
|
+
// caller didn't mention here survive the round trip instead of resetting.
|
|
29
|
+
const current = await blocksRequest("/iam/v4/auth/config", {
|
|
30
|
+
impersonatedProjectAuth: true,
|
|
31
|
+
...requestContext(flags),
|
|
32
|
+
projectTenantId: projectKey
|
|
33
|
+
});
|
|
34
|
+
const body = { ...current, ...overrides };
|
|
24
35
|
if (booleanFlag(flags, "dry-run")) {
|
|
25
36
|
writeOutput({ dryRun: true, endpoint: "/iam/v4/auth/config", request: body }, flags);
|
|
26
37
|
return;
|
|
27
38
|
}
|
|
28
39
|
await confirmMutation(flags, "Save AuthController configuration for the selected project.");
|
|
29
|
-
const projectKey = await selectedProject(flags);
|
|
30
40
|
const result = await blocksRequest("/iam/v4/auth/config", {
|
|
31
41
|
body,
|
|
32
42
|
impersonatedProjectAuth: true,
|
|
@@ -8,7 +8,7 @@ import { parseCommand, selectedProject } from "../../../lib/workspace.js";
|
|
|
8
8
|
/** Upsert: omit --item-id to register a new OIDC client, pass it to update an existing one. */
|
|
9
9
|
export async function authOidcClientsSave(argv) {
|
|
10
10
|
const { flags } = parseCommand(argv);
|
|
11
|
-
const
|
|
11
|
+
const overrides = {
|
|
12
12
|
...(await jsonBodyFlag(flags)),
|
|
13
13
|
...compact({
|
|
14
14
|
allowedMfaMethods: listFlag(flags, "allowed-mfa-methods")?.map(Number),
|
|
@@ -36,12 +36,27 @@ export async function authOidcClientsSave(argv) {
|
|
|
36
36
|
useTokensCookie: optionalBooleanFlag(flags, "use-tokens-cookie")
|
|
37
37
|
})
|
|
38
38
|
};
|
|
39
|
+
const projectKey = await selectedProject(flags);
|
|
40
|
+
const itemId = typeof overrides.itemId === "string" ? overrides.itemId : undefined;
|
|
41
|
+
// Saving an existing client (itemId set) replaces the whole client document
|
|
42
|
+
// rather than merging -- the portal's own Edit dialog always resubmits every
|
|
43
|
+
// field, including ones this command wasn't asked to change. Fetch the
|
|
44
|
+
// current client first so unmentioned fields (redirectUris, scope, PKCE, ...)
|
|
45
|
+
// survive instead of being reset to defaults. A new client (no itemId) has
|
|
46
|
+
// no prior state to merge.
|
|
47
|
+
const current = itemId
|
|
48
|
+
? await blocksRequest(`/iam/v4/oidc-clients/${encodeURIComponent(itemId)}`, {
|
|
49
|
+
impersonatedProjectAuth: true,
|
|
50
|
+
...requestContext(flags),
|
|
51
|
+
projectTenantId: projectKey
|
|
52
|
+
})
|
|
53
|
+
: {};
|
|
54
|
+
const body = { ...current, ...overrides };
|
|
39
55
|
if (booleanFlag(flags, "dry-run")) {
|
|
40
56
|
writeOutput({ dryRun: true, endpoint: "/iam/v4/oidc-clients", request: redactSecret(body) }, flags);
|
|
41
57
|
return;
|
|
42
58
|
}
|
|
43
59
|
await confirmMutation(flags, `Save OIDC client '${body.clientDisplayName ?? body.itemId ?? "(new)"}'. The response's client secret is shown once.`);
|
|
44
|
-
const projectKey = await selectedProject(flags);
|
|
45
60
|
const result = await blocksRequest("/iam/v4/oidc-clients", {
|
|
46
61
|
body,
|
|
47
62
|
impersonatedProjectAuth: true,
|
package/dist/commands/new/web.js
CHANGED
|
@@ -21,6 +21,15 @@ export async function newWeb(argv) {
|
|
|
21
21
|
const appDomain = await resolveAppDomain(project, flags);
|
|
22
22
|
const apiUrl = stringFlag(flags, "blocks-api-url") || apiUrlFromAppDomain(appDomain);
|
|
23
23
|
const oidcClientId = await resolveOidcClientId(tenantId, appDomain, name, flags);
|
|
24
|
+
if (oidcClientId) {
|
|
25
|
+
try {
|
|
26
|
+
await ensureOidcLoginEnabled(tenantId, flags);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.warn(`Warning: could not confirm/enable OIDC login on this project's AuthController config: ${error.message}`);
|
|
30
|
+
console.warn("Enable it manually: 'blocks auth:config:save --oidc-enabled --project " + tenantId + "', or in the Blocks portal under IAM > Auth Config.");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
24
33
|
await scaffoldWebProject({
|
|
25
34
|
apiUrl,
|
|
26
35
|
appDomain,
|
|
@@ -116,6 +125,32 @@ async function listOidcClientSummaries(tenantId, flags) {
|
|
|
116
125
|
}
|
|
117
126
|
return summaries;
|
|
118
127
|
}
|
|
128
|
+
// Creating/selecting an OIDC client is not enough for the hosted login flow to
|
|
129
|
+
// work: AuthController separately gates the whole OIDC/IdP path behind
|
|
130
|
+
// isOidcEnabled on the tenant's auth config, off by default. Without this,
|
|
131
|
+
// scaffolded apps 404/error on login until someone flips it manually in the
|
|
132
|
+
// portal (IAM > Auth Config), so check-and-enable it here as part of setup.
|
|
133
|
+
// POST /auth/config replaces the whole config document rather than merging
|
|
134
|
+
// (confirmed against the portal's own save call, which always resends every
|
|
135
|
+
// field) -- sending just `{ isOidcEnabled: true }` would reset every other
|
|
136
|
+
// AuthController setting for this tenant, so the fetched config is spread
|
|
137
|
+
// back in full with only that one field overridden.
|
|
138
|
+
async function ensureOidcLoginEnabled(tenantId, flags) {
|
|
139
|
+
const config = await blocksRequest("/iam/v4/auth/config", {
|
|
140
|
+
impersonatedProjectAuth: true,
|
|
141
|
+
projectTenantId: tenantId,
|
|
142
|
+
...requestContext(flags)
|
|
143
|
+
});
|
|
144
|
+
if (config.isOidcEnabled)
|
|
145
|
+
return;
|
|
146
|
+
await confirmMutation(flags, "Enable OIDC login on this project's AuthController configuration.");
|
|
147
|
+
await blocksRequest("/iam/v4/auth/config", {
|
|
148
|
+
body: { ...config, isOidcEnabled: true },
|
|
149
|
+
impersonatedProjectAuth: true,
|
|
150
|
+
projectTenantId: tenantId,
|
|
151
|
+
...requestContext(flags)
|
|
152
|
+
});
|
|
153
|
+
}
|
|
119
154
|
function normalizeList(raw) {
|
|
120
155
|
if (Array.isArray(raw))
|
|
121
156
|
return raw;
|
|
@@ -135,10 +170,15 @@ async function createOidcClientInteractively(tenantId, appDomain, appName, flags
|
|
|
135
170
|
// clientType drives IAM's tokenEndpointAuthMethod: omitting it stores this browser
|
|
136
171
|
// app as confidential ("client_secret_post") and lets it request client_credentials.
|
|
137
172
|
// The scaffold only ever produces a PKCE SPA, so it is always "public".
|
|
173
|
+
// isAutoRedirect: the scaffolded login page's startLogin() already navigates
|
|
174
|
+
// straight to the provider via window.location.assign -- without this flag IAM
|
|
175
|
+
// shows an interstitial "continue" click on the hosted login page instead of
|
|
176
|
+
// redirecting immediately, which is dead weight for a flow the SPA already drives.
|
|
138
177
|
const body = {
|
|
139
178
|
clientDisplayName: displayName,
|
|
140
179
|
clientType: "public",
|
|
141
180
|
isActive: true,
|
|
181
|
+
isAutoRedirect: true,
|
|
142
182
|
redirectUris: [redirectUri],
|
|
143
183
|
registerAsIdentityProvider: true,
|
|
144
184
|
requirePkce: true,
|