@ibgib/web-gib 0.0.56 → 0.0.58
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/AUTO-GENERATED-version.d.mts +1 -1
- package/dist/AUTO-GENERATED-version.mjs +1 -1
- package/dist/api/api-index.mjs +1 -1
- package/dist/api/api-index.mjs.map +1 -1
- package/dist/api/ibgib-api-bridge.d.mts +97 -0
- package/dist/api/ibgib-api-bridge.d.mts.map +1 -1
- package/dist/api/ibgib-api-bridge.mjs +205 -3
- package/dist/api/ibgib-api-bridge.mjs.map +1 -1
- package/dist/identity/custodian-delegate-helper.d.mts +22 -0
- package/dist/identity/custodian-delegate-helper.d.mts.map +1 -0
- package/dist/identity/custodian-delegate-helper.mjs +50 -0
- package/dist/identity/custodian-delegate-helper.mjs.map +1 -0
- package/dist/identity/sso-popup-helper.d.mts +33 -0
- package/dist/identity/sso-popup-helper.d.mts.map +1 -0
- package/dist/identity/sso-popup-helper.mjs +124 -0
- package/dist/identity/sso-popup-helper.mjs.map +1 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -1
- package/dist/ui/component/identity/add-device/add-device.d.mts.map +1 -1
- package/dist/ui/component/identity/add-device/add-device.html +6 -7
- package/dist/ui/component/identity/add-device/add-device.mjs +13 -10
- package/dist/ui/component/identity/add-device/add-device.mjs.map +1 -1
- package/dist/ui/component/identity/identity-header/identity-header.d.mts.map +1 -1
- package/dist/ui/component/identity/identity-header/identity-header.mjs +2 -1
- package/dist/ui/component/identity/identity-header/identity-header.mjs.map +1 -1
- package/dist/ui/component/identity/keystone-creator/keystone-creator.css +114 -9
- package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts +23 -0
- package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts.map +1 -1
- package/dist/ui/component/identity/keystone-creator/keystone-creator.html +122 -50
- package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs +529 -83
- package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs.map +1 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.d.mts.map +1 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.mjs +19 -61
- package/dist/ui/component/identity/keystone-details/keystone-details.mjs.map +1 -1
- package/package.json +4 -4
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/api/api-index.mts +1 -1
- package/src/api/ibgib-api-bridge.mts +288 -4
- package/src/identity/custodian-delegate-helper.mts +61 -0
- package/src/identity/sso/{sso-custodian-service.mts → sso-custodian-service.mts.bak} +65 -38
- package/src/identity/sso/{sso-custodian-service.respec.mts → sso-custodian-service.respec.mts.bak} +15 -14
- package/src/identity/sso-popup-helper.mts +155 -0
- package/src/index.mts +3 -0
- package/src/ui/component/identity/add-device/add-device.html +6 -7
- package/src/ui/component/identity/add-device/add-device.mts +17 -16
- package/src/ui/component/identity/identity-header/identity-header.mts +2 -1
- package/src/ui/component/identity/keystone-creator/keystone-creator.css +114 -9
- package/src/ui/component/identity/keystone-creator/keystone-creator.html +122 -50
- package/src/ui/component/identity/keystone-creator/keystone-creator.mts +599 -100
- package/src/ui/component/identity/keystone-details/keystone-details.mts +26 -77
- package/dist/identity/sso/sso-config-helper.d.mts +0 -7
- package/dist/identity/sso/sso-config-helper.d.mts.map +0 -1
- package/dist/identity/sso/sso-config-helper.mjs +0 -42
- package/dist/identity/sso/sso-config-helper.mjs.map +0 -1
- package/dist/identity/sso/sso-custodian-service.d.mts +0 -139
- package/dist/identity/sso/sso-custodian-service.d.mts.map +0 -1
- package/dist/identity/sso/sso-custodian-service.mjs +0 -443
- package/dist/identity/sso/sso-custodian-service.mjs.map +0 -1
- package/dist/identity/sso/sso-custodian-service.respec.d.mts +0 -2
- package/dist/identity/sso/sso-custodian-service.respec.d.mts.map +0 -1
- package/dist/identity/sso/sso-custodian-service.respec.mjs +0 -254
- package/dist/identity/sso/sso-custodian-service.respec.mjs.map +0 -1
- /package/src/identity/sso/{sso-config-helper.mts → sso-config-helper.mts.bak} +0 -0
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import thisCss from "./keystone-creator.css";
|
|
2
2
|
import thisHtml from "./keystone-creator.html";
|
|
3
3
|
import commonComponentStylesCss from "../../common-component-styles.css";
|
|
4
|
-
import { delay, extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
4
|
+
import { delay, extractErrorMsg, } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
5
5
|
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
6
6
|
import { KeystoneService_V1 } from "@ibgib/core-gib/dist/keystone/keystone-service-v1.mjs";
|
|
7
7
|
import { KeystoneProfileBuilder } from "@ibgib/core-gib/dist/keystone/policy/keystone-profile-builder.mjs";
|
|
8
|
-
import {
|
|
8
|
+
import { updateSpecialIndex, } from "@ibgib/core-gib/dist/timeline/timeline-api.mjs";
|
|
9
|
+
import { toDto, getTjpAddr } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
|
|
10
|
+
import { validateEmail } from "@ibgib/core-gib/dist/keystone/keystone-helpers.mjs";
|
|
11
|
+
import { KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP, KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
|
|
12
|
+
import { deriveDelegateSecret } from "@ibgib/core-gib/dist/keystone/strategy/hash-reveal-v1/hash-reveal-v1.mjs";
|
|
13
|
+
import { getGlobalMetaspace_waitIfNeeded, } from "../../../../helpers.mjs";
|
|
9
14
|
import { IbGibDynamicComponentMetaBase, IbGibFormInstanceBase, } from "../../ibgib-dynamic-component-bases.mjs";
|
|
10
15
|
import { getComponentCtorArg } from "../../../../app-bootstrap/init-orchestration.mjs";
|
|
11
16
|
import { getApiBridge } from "../../../../api/ibgib-api-bridge.mjs";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { validateEmail } from "@ibgib/core-gib/dist/keystone/keystone-helpers.mjs";
|
|
15
|
-
import { KEYSTONE_USERNAME_REGEXP, KEYSTONE_DESCRIPTION_REGEXP, KEYSTONE_VERB_SYNC, KEYSTONE_VERB_CONNECT } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
|
|
17
|
+
import { deriveLocalCustodianDelegateSecret } from "../../../../identity/custodian-delegate-helper.mjs";
|
|
18
|
+
import { executeSsoOAuthPopup } from "../../../../identity/sso-popup-helper.mjs";
|
|
16
19
|
import { EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, EVENT_IBGIB_UI_MESSAGE } from "../../../ui-constants.mjs";
|
|
17
|
-
import {
|
|
20
|
+
import { alertUser, shadowRoot_getElementById } from "../../../../helpers.web.mjs";
|
|
18
21
|
export const KEYSTONE_CREATOR_COMPONENT_NAME = 'ibgib-keystone-creator';
|
|
19
22
|
/**
|
|
20
23
|
* Metadata for the Keystone Creator component.
|
|
@@ -112,6 +115,50 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
112
115
|
// cleanup if needed
|
|
113
116
|
}
|
|
114
117
|
initHandlers() {
|
|
118
|
+
// Mode Tab Switching (Quick vs Password-based)
|
|
119
|
+
const tabQuick = this.shadowRoot?.getElementById('tab-quick');
|
|
120
|
+
const tabPassword = this.shadowRoot?.getElementById('tab-password');
|
|
121
|
+
const panelQuick = this.shadowRoot?.getElementById('panel-quick');
|
|
122
|
+
const panelPassword = this.shadowRoot?.getElementById('panel-password');
|
|
123
|
+
const subtitleQuick = this.shadowRoot?.getElementById('subtitle-quick');
|
|
124
|
+
const subtitlePassword = this.shadowRoot?.getElementById('subtitle-password');
|
|
125
|
+
tabQuick?.addEventListener('click', () => {
|
|
126
|
+
tabQuick.classList.add('active');
|
|
127
|
+
tabPassword?.classList.remove('active');
|
|
128
|
+
panelQuick?.classList.remove('hidden');
|
|
129
|
+
panelPassword?.classList.add('hidden');
|
|
130
|
+
subtitleQuick?.classList.remove('hidden');
|
|
131
|
+
subtitlePassword?.classList.add('hidden');
|
|
132
|
+
});
|
|
133
|
+
tabPassword?.addEventListener('click', () => {
|
|
134
|
+
tabPassword.classList.add('active');
|
|
135
|
+
tabQuick?.classList.remove('active');
|
|
136
|
+
panelPassword?.classList.remove('hidden');
|
|
137
|
+
panelQuick?.classList.add('hidden');
|
|
138
|
+
subtitlePassword?.classList.remove('hidden');
|
|
139
|
+
subtitleQuick?.classList.add('hidden');
|
|
140
|
+
});
|
|
141
|
+
const btnGoogleSso = this.shadowRoot?.getElementById('btn-google-sso');
|
|
142
|
+
btnGoogleSso?.addEventListener('click', () => this.handleSsoClick('google'));
|
|
143
|
+
const btnGithubSso = this.shadowRoot?.getElementById('btn-github-sso');
|
|
144
|
+
btnGithubSso?.addEventListener('click', () => this.handleSsoClick('github'));
|
|
145
|
+
// Email Sign-In Info Button
|
|
146
|
+
const btnEmailInfo = this.shadowRoot?.getElementById('btn-email-info');
|
|
147
|
+
btnEmailInfo?.addEventListener('click', (e) => {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
alertUser({
|
|
150
|
+
title: 'Custom Email Sign-In',
|
|
151
|
+
msg: 'When you enter your email address, we dispatch a 6-digit one-time verification code to your inbox.\n\nEntering the code creates your cryptographic identity delegate on your device and signs you in seamlessly without needing a password!'
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
// Quick Email Verification Code Handlers
|
|
155
|
+
const btnQuickSendCode = this.shadowRoot?.getElementById('btn-quick-send-code');
|
|
156
|
+
const inputQuickEmail = this.shadowRoot?.getElementById('input-quick-email');
|
|
157
|
+
const secQuickOtp = this.shadowRoot?.getElementById('section-quick-otp');
|
|
158
|
+
const inputQuickOtp = this.shadowRoot?.getElementById('input-quick-otp');
|
|
159
|
+
const btnQuickVerifyCode = this.shadowRoot?.getElementById('btn-quick-verify-code');
|
|
160
|
+
btnQuickSendCode?.addEventListener('click', () => this.handleQuickSendCode());
|
|
161
|
+
btnQuickVerifyCode?.addEventListener('click', () => this.handleQuickVerifyCode());
|
|
115
162
|
this.elements.btnGenerateEl.addEventListener('click', () => this.handleGenerate());
|
|
116
163
|
this.shadowRoot.getElementById('btn-switch-sign-in')?.addEventListener('click', (e) => {
|
|
117
164
|
e.preventDefault();
|
|
@@ -122,16 +169,16 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
122
169
|
}));
|
|
123
170
|
});
|
|
124
171
|
// Clear invalid styling when user inputs text
|
|
125
|
-
this.elements.inputUsername
|
|
172
|
+
this.elements.inputUsername?.addEventListener('input', () => {
|
|
126
173
|
this.elements.inputUsername.classList.remove('invalid');
|
|
127
174
|
});
|
|
128
|
-
this.elements.inputDescription
|
|
175
|
+
this.elements.inputDescription?.addEventListener('input', () => {
|
|
129
176
|
this.elements.inputDescription.classList.remove('invalid');
|
|
130
177
|
});
|
|
131
|
-
this.elements.inputEmail
|
|
178
|
+
this.elements.inputEmail?.addEventListener('input', () => {
|
|
132
179
|
this.elements.inputEmail.classList.remove('invalid');
|
|
133
180
|
});
|
|
134
|
-
this.elements.inputSecret
|
|
181
|
+
this.elements.inputSecret?.addEventListener('input', () => {
|
|
135
182
|
this.elements.inputSecret.classList.remove('invalid');
|
|
136
183
|
});
|
|
137
184
|
}
|
|
@@ -142,6 +189,223 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
142
189
|
btn.textContent = isLoading ? 'Generating...' : 'Generate Identity Keystone';
|
|
143
190
|
}
|
|
144
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* Triggered by Google / GitHub SSO buttons.
|
|
194
|
+
* Opens OAuth popup, exchanges authorization code, builds local delegate keystone,
|
|
195
|
+
* registers delegate on server, and finalizes onboarding.
|
|
196
|
+
*/
|
|
197
|
+
async handleSsoClick(providerId) {
|
|
198
|
+
const lc = `${this.lc}[${this.handleSsoClick.name}]`;
|
|
199
|
+
this.setStatus(`Opening ${providerId.toUpperCase()} SSO authorization window...`, 'info');
|
|
200
|
+
const resPopup = await executeSsoOAuthPopup({ providerId });
|
|
201
|
+
if (!resPopup.success || !resPopup.code) {
|
|
202
|
+
this.setStatus(resPopup.message || `${providerId.toUpperCase()} sign-in cancelled.`, 'error');
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this.setStatus(`Exchanging ${providerId.toUpperCase()} authorization code...`, 'info');
|
|
206
|
+
const apiBridge = getApiBridge();
|
|
207
|
+
const resLogin = await apiBridge.postSsoLogin({
|
|
208
|
+
code: resPopup.code,
|
|
209
|
+
providerId,
|
|
210
|
+
redirectUri: resPopup.redirectUri
|
|
211
|
+
});
|
|
212
|
+
if (!resLogin.success || !resLogin.primaryTjpAddr || !resLogin.custodianReqs) {
|
|
213
|
+
this.setStatus(resLogin.message || `${providerId.toUpperCase()} login failed.`, 'error');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const { primaryTjpAddr, custodianReqs } = resLogin;
|
|
217
|
+
this.setStatus('Deriving local device delegate keys...', 'info');
|
|
218
|
+
const delegateSecret = await deriveLocalCustodianDelegateSecret({ primaryTjpAddr });
|
|
219
|
+
const email = resLogin.userInfo?.email || '';
|
|
220
|
+
const username = email ? email.split('@')[0] : 'user';
|
|
221
|
+
const delegateBuilder = KeystoneProfileBuilder.buildKeystone('sync')
|
|
222
|
+
.withUsername(`${username}-sync`)
|
|
223
|
+
.withDescription(`Sync Delegate for ${username}`)
|
|
224
|
+
.withDetails({
|
|
225
|
+
client: 'space-gib-web',
|
|
226
|
+
role: 'sync-delegate',
|
|
227
|
+
primaryTjpAddr,
|
|
228
|
+
custodianReqs,
|
|
229
|
+
});
|
|
230
|
+
const configs = await delegateBuilder.compileConfigs();
|
|
231
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
232
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
233
|
+
if (!space) {
|
|
234
|
+
this.setStatus('Could not access local user space.', 'error');
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const keystoneService = new KeystoneService_V1();
|
|
238
|
+
const delegateKeystone = await keystoneService.genesis({
|
|
239
|
+
masterSecret: delegateSecret,
|
|
240
|
+
configs,
|
|
241
|
+
metaspace,
|
|
242
|
+
space,
|
|
243
|
+
frameDetails: delegateBuilder.getFrameDetails(),
|
|
244
|
+
isPrimary: false
|
|
245
|
+
});
|
|
246
|
+
this.setStatus('Registering device delegate with custodian server...', 'info');
|
|
247
|
+
const resRegister = await apiBridge.postCustodianRegisterDelegate({ delegateKeystone });
|
|
248
|
+
if (!resRegister.success) {
|
|
249
|
+
this.setStatus(resRegister.message || 'Custodian delegate registration failed.', 'error');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
// Finalize onboarding: update keystones index, activate identity, and navigate to identity manager
|
|
253
|
+
await this.finalizeIdentityOnboarding({
|
|
254
|
+
primaryKeystone: resRegister.evolvedPrimaryKeystone || resLogin.primaryKeystone,
|
|
255
|
+
primaryGraph: resRegister.primaryGraph || resLogin.primaryGraph,
|
|
256
|
+
delegateKeystone,
|
|
257
|
+
primaryTjpAddr,
|
|
258
|
+
delegateSecret,
|
|
259
|
+
makeActive: true
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Triggered by the "Send 6-Digit Verification Code" button.
|
|
264
|
+
* Validates quick email input and dispatches a 6-digit OTP code to the user's inbox.
|
|
265
|
+
*/
|
|
266
|
+
async handleQuickSendCode() {
|
|
267
|
+
const lc = `${this.lc}[${this.handleQuickSendCode.name}]`;
|
|
268
|
+
const btnQuickSendCode = this.shadowRoot?.getElementById('btn-quick-send-code');
|
|
269
|
+
const inputQuickEmail = this.shadowRoot?.getElementById('input-quick-email');
|
|
270
|
+
const secQuickOtp = this.shadowRoot?.getElementById('section-quick-otp');
|
|
271
|
+
const email = (inputQuickEmail?.value || '').trim();
|
|
272
|
+
if (!email || !validateEmail(email)) {
|
|
273
|
+
this.setStatus("Please enter a valid email address.", "error");
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (btnQuickSendCode) {
|
|
277
|
+
btnQuickSendCode.disabled = true;
|
|
278
|
+
btnQuickSendCode.textContent = "Sending Verification Code...";
|
|
279
|
+
}
|
|
280
|
+
this.setStatus("Requesting verification code...", "info");
|
|
281
|
+
try {
|
|
282
|
+
const resCode = await getApiBridge().postVerificationCode({ email });
|
|
283
|
+
if (resCode.success) {
|
|
284
|
+
secQuickOtp?.classList.remove('hidden');
|
|
285
|
+
this.setStatus("✉️ 6-digit verification code sent to your email!", "success");
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
this.setStatus(resCode.message || "Failed to dispatch verification code.", "error");
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
const emsg = extractErrorMsg(error);
|
|
293
|
+
console.error(`${lc} ${emsg}`);
|
|
294
|
+
this.setStatus(`Failed to dispatch verification code: ${emsg}`, "error");
|
|
295
|
+
}
|
|
296
|
+
finally {
|
|
297
|
+
if (btnQuickSendCode) {
|
|
298
|
+
btnQuickSendCode.disabled = false;
|
|
299
|
+
btnQuickSendCode.textContent = "Send 6-Digit Verification Code";
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Triggered by the "Verify Code" button.
|
|
305
|
+
* Submits 6-digit OTP code to custodian server, builds local sync delegate keystone,
|
|
306
|
+
* registers delegate on server, and finalizes onboarding.
|
|
307
|
+
*/
|
|
308
|
+
async handleQuickVerifyCode() {
|
|
309
|
+
const lc = `${this.lc}[${this.handleQuickVerifyCode.name}]`;
|
|
310
|
+
const inputQuickEmail = this.shadowRoot?.getElementById('input-quick-email');
|
|
311
|
+
const inputQuickOtp = this.shadowRoot?.getElementById('input-quick-otp');
|
|
312
|
+
const btnQuickVerifyCode = this.shadowRoot?.getElementById('btn-quick-verify-code');
|
|
313
|
+
const email = (inputQuickEmail?.value || '').trim();
|
|
314
|
+
const code = (inputQuickOtp?.value || '').trim();
|
|
315
|
+
if (!code || code.length !== 6 || !/^\d{6}$/.test(code)) {
|
|
316
|
+
this.setStatus("Please enter a valid 6-digit verification code.", "error");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (btnQuickVerifyCode) {
|
|
320
|
+
btnQuickVerifyCode.disabled = true;
|
|
321
|
+
btnQuickVerifyCode.textContent = "Verifying...";
|
|
322
|
+
}
|
|
323
|
+
this.setStatus("Verifying code & completing onboarding...", "info");
|
|
324
|
+
this.showBusy({
|
|
325
|
+
isBusy: true,
|
|
326
|
+
title: 'Verifying Code...',
|
|
327
|
+
msg: 'Great! Juust a moment...\n(Validating code, promoting server domain space, other security stuff...)',
|
|
328
|
+
animationEmoji: '🔐'
|
|
329
|
+
});
|
|
330
|
+
try {
|
|
331
|
+
const resGenesis = await getApiBridge().postCustodianGenesis({ email, code });
|
|
332
|
+
if (!resGenesis.success || !resGenesis.primaryTjpAddr || !resGenesis.custodianReqs) {
|
|
333
|
+
this.setStatus(resGenesis.message || "Custodian verification failed.", "error");
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const primaryTjpAddr = resGenesis.primaryTjpAddr;
|
|
337
|
+
const custodianReqs = resGenesis.custodianReqs;
|
|
338
|
+
// Construct local delegate keystone
|
|
339
|
+
this.setStatus("Constructing local sync delegate...", "info");
|
|
340
|
+
this.showBusy({
|
|
341
|
+
isBusy: true,
|
|
342
|
+
title: 'Creating Sync Delegate...',
|
|
343
|
+
msg: 'Generating cryptographic sync delegate keys...',
|
|
344
|
+
animationEmoji: '🔑'
|
|
345
|
+
});
|
|
346
|
+
const delegateSecret = await deriveLocalCustodianDelegateSecret({ primaryTjpAddr });
|
|
347
|
+
const username = email.split('@')[0];
|
|
348
|
+
const delegateBuilder = KeystoneProfileBuilder.buildKeystone('sync')
|
|
349
|
+
.withUsername(`${username}-sync`)
|
|
350
|
+
.withDescription(`Sync Delegate for ${username}`)
|
|
351
|
+
.withDetails({
|
|
352
|
+
client: 'space-gib-web',
|
|
353
|
+
role: 'sync-delegate',
|
|
354
|
+
primaryTjpAddr,
|
|
355
|
+
custodianReqs,
|
|
356
|
+
});
|
|
357
|
+
const configs = await delegateBuilder.compileConfigs();
|
|
358
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
359
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
360
|
+
if (!space) {
|
|
361
|
+
this.setStatus("Failed to access local user space.", "error");
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const keystoneService = new KeystoneService_V1();
|
|
365
|
+
const delegateKeystone = await keystoneService.genesis({
|
|
366
|
+
masterSecret: delegateSecret,
|
|
367
|
+
configs,
|
|
368
|
+
metaspace,
|
|
369
|
+
space,
|
|
370
|
+
frameDetails: delegateBuilder.getFrameDetails(),
|
|
371
|
+
isPrimary: false
|
|
372
|
+
});
|
|
373
|
+
// Register delegate with server
|
|
374
|
+
this.setStatus("Registering device delegate with custodian server...", "info");
|
|
375
|
+
this.showBusy({
|
|
376
|
+
isBusy: true,
|
|
377
|
+
title: 'Registering Delegate...',
|
|
378
|
+
msg: 'Registering local delegate with custodian server...',
|
|
379
|
+
animationEmoji: '📝'
|
|
380
|
+
});
|
|
381
|
+
const resRegister = await getApiBridge().postCustodianRegisterDelegate({ delegateKeystone });
|
|
382
|
+
if (!resRegister.success) {
|
|
383
|
+
this.setStatus(resRegister.message || "Failed to register delegate with custodian server.", "error");
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
// Finalize onboarding: update keystones index, activate identity, and navigate to identity manager
|
|
387
|
+
await this.finalizeIdentityOnboarding({
|
|
388
|
+
primaryKeystone: resRegister.evolvedPrimaryKeystone || resGenesis.primaryKeystone,
|
|
389
|
+
primaryGraph: resRegister.primaryGraph || resGenesis.primaryGraph,
|
|
390
|
+
delegateKeystone,
|
|
391
|
+
primaryTjpAddr,
|
|
392
|
+
delegateSecret,
|
|
393
|
+
makeActive: true
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
const emsg = extractErrorMsg(error);
|
|
398
|
+
console.error(`${lc} ${emsg}`, error);
|
|
399
|
+
this.setStatus(`Error: ${emsg}`, "error");
|
|
400
|
+
}
|
|
401
|
+
finally {
|
|
402
|
+
this.showBusy({ isBusy: false });
|
|
403
|
+
if (btnQuickVerifyCode) {
|
|
404
|
+
btnQuickVerifyCode.disabled = false;
|
|
405
|
+
btnQuickVerifyCode.textContent = "Verify Code";
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
145
409
|
/**
|
|
146
410
|
* Triggered by the "Generate" button.
|
|
147
411
|
* Orchestrates: Secret -> Local Genesis -> Graph Collection -> Server Sync.
|
|
@@ -218,7 +482,11 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
218
482
|
animationEmoji: '⚙️'
|
|
219
483
|
});
|
|
220
484
|
// 1. Prepare Primary/Domain Keystone Configs
|
|
221
|
-
const
|
|
485
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
486
|
+
const requestedProfile = (process.env.KEYSTONE_PROFILE || 'domain').toLowerCase();
|
|
487
|
+
const profileName = (isProd && requestedProfile === 'test') ? 'domain' : requestedProfile;
|
|
488
|
+
console.log(`${lc} Using keystone policy profile '${profileName}' (I: 90123456789abcdef0123456789abcde)`);
|
|
489
|
+
const builder = KeystoneProfileBuilder.buildKeystone(profileName)
|
|
222
490
|
.withUsername(username)
|
|
223
491
|
.withDescription(description);
|
|
224
492
|
if (email) {
|
|
@@ -252,11 +520,11 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
252
520
|
frameDetails: builder.getFrameDetails(),
|
|
253
521
|
isPrimary: true
|
|
254
522
|
});
|
|
255
|
-
const
|
|
256
|
-
console.log(`${lc} local genesis complete: ${
|
|
523
|
+
const primaryTjpAddr = getTjpAddr({ ibGib: keystoneIbGib, defaultIfNone: 'incomingAddr' });
|
|
524
|
+
console.log(`${lc} local genesis complete: ${primaryTjpAddr}`);
|
|
257
525
|
await delay(humanEyeDelay); // for human eyes, not needed for functionality
|
|
258
526
|
this.setStatus("Local genesis complete. Creating sync delegate...", "info");
|
|
259
|
-
console.log(`✓ Local genesis complete: ${
|
|
527
|
+
console.log(`✓ Local genesis complete: ${primaryTjpAddr}`);
|
|
260
528
|
// Automatically generate Sync Delegate Keystone
|
|
261
529
|
this.showBusy({
|
|
262
530
|
isBusy: true,
|
|
@@ -265,12 +533,13 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
265
533
|
animationEmoji: '🔑'
|
|
266
534
|
});
|
|
267
535
|
const delegateSecret = await deriveDelegateSecret({ masterSecret });
|
|
268
|
-
const delegateBuilder = KeystoneProfileBuilder.buildKeystone(
|
|
536
|
+
const delegateBuilder = KeystoneProfileBuilder.buildKeystone(profileName)
|
|
269
537
|
.withUsername(`${username}-sync`)
|
|
270
538
|
.withDescription(`Sync Delegate for ${username}`)
|
|
271
539
|
.withDetails({
|
|
272
540
|
client: 'space-gib-web',
|
|
273
|
-
role: 'sync-delegate'
|
|
541
|
+
role: 'sync-delegate',
|
|
542
|
+
primaryTjpAddr: primaryTjpAddr,
|
|
274
543
|
});
|
|
275
544
|
const delegateConfigs = await delegateBuilder.compileConfigs();
|
|
276
545
|
const delegateKeystoneIbGib = await keystoneService.genesis({
|
|
@@ -303,15 +572,11 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
303
572
|
console.log(`${lc} delegate registered. evolved parent address: ${evolvedParentAddr}`);
|
|
304
573
|
await delay(humanEyeDelay);
|
|
305
574
|
// 4. Post to Server
|
|
306
|
-
|
|
307
|
-
this.setStatus("Syncing genesis to server...", "info");
|
|
575
|
+
this.setStatus("Syncing genesis keystone to server...", "info");
|
|
308
576
|
this.showBusy({
|
|
309
577
|
isBusy: true,
|
|
310
578
|
title: 'Syncing to Server...',
|
|
311
|
-
msg:
|
|
312
|
-
'Posting genesis keystone to server sync node...',
|
|
313
|
-
'(may take awhile, depending on strength of keystone...)',
|
|
314
|
-
].join('\n'),
|
|
579
|
+
msg: 'Staging pending genesis keystone on server...',
|
|
315
580
|
animationEmoji: '🔄'
|
|
316
581
|
});
|
|
317
582
|
const resSync = await getApiBridge().postGenesisKeystone(keystoneIbGib);
|
|
@@ -323,69 +588,115 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
323
588
|
this.setButtonLoading(false);
|
|
324
589
|
return;
|
|
325
590
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
isBusy: true,
|
|
330
|
-
title: 'Syncing Delegate...',
|
|
331
|
-
msg: 'Posting evolved domain identity and sync delegate to server...',
|
|
332
|
-
animationEmoji: '🔄'
|
|
333
|
-
});
|
|
334
|
-
const resEvolve = await getApiBridge().putEvolveKeystone({
|
|
335
|
-
domainAddr: addr,
|
|
336
|
-
keystoneIbGib: evolvedParentKeystoneIbGib,
|
|
337
|
-
relatedKeystoneIbGibs: [delegateKeystoneIbGib]
|
|
338
|
-
});
|
|
339
|
-
if (!resEvolve.success) {
|
|
340
|
-
const msg = `Delegate registration sync failed: ${resEvolve.message}`;
|
|
341
|
-
console.error(`${lc} ${msg}`);
|
|
342
|
-
this.setStatus(msg, "error");
|
|
591
|
+
const isPending = resSync.pending || resSync.statusCode === 202;
|
|
592
|
+
if (isPending) {
|
|
593
|
+
console.log(`${lc} Genesis keystone quarantined in pending staging area. Prompting for 6-digit verification code.`);
|
|
343
594
|
this.showBusy({ isBusy: false });
|
|
344
|
-
this.
|
|
345
|
-
|
|
595
|
+
this.setFormDisabled(true);
|
|
596
|
+
if (!this.shadowRoot) {
|
|
597
|
+
throw new Error(`(UNEXPECTED) this.shadowRoot falsy? (E: 6d316f5a2bf8e6a0286306468d35c826)`);
|
|
598
|
+
}
|
|
599
|
+
const secVerify = shadowRoot_getElementById(this.shadowRoot, 'section-code-verification');
|
|
600
|
+
const inputVerifyCode = shadowRoot_getElementById(this.shadowRoot, 'input-verify-code');
|
|
601
|
+
const btnSubmitCode = shadowRoot_getElementById(this.shadowRoot, 'btn-submit-code');
|
|
602
|
+
const btnResendCode = shadowRoot_getElementById(this.shadowRoot, 'btn-resend-code');
|
|
603
|
+
secVerify.classList.remove('hidden');
|
|
604
|
+
secVerify.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
605
|
+
this.setStatus("✉️ Verification code sent to your email. Enter 6-digit code below:", "info");
|
|
606
|
+
const onResendCode = async () => {
|
|
607
|
+
btnResendCode.disabled = true;
|
|
608
|
+
btnResendCode.textContent = "Sending...";
|
|
609
|
+
this.setStatus("Resending verification code to your email...", "info");
|
|
610
|
+
const resResend = await getApiBridge().postVerificationCode({ email, primaryTjpAddr: primaryTjpAddr });
|
|
611
|
+
if (resResend.success) {
|
|
612
|
+
this.setStatus("✉️ New verification code sent to your email!", "success");
|
|
613
|
+
}
|
|
614
|
+
else {
|
|
615
|
+
this.setStatus(resResend.message || "Failed to resend verification code.", "error");
|
|
616
|
+
}
|
|
617
|
+
btnResendCode.disabled = false;
|
|
618
|
+
btnResendCode.textContent = "Resend Code";
|
|
619
|
+
};
|
|
620
|
+
btnResendCode.addEventListener('click', onResendCode);
|
|
621
|
+
await new Promise((resolve, reject) => {
|
|
622
|
+
const onSubmitCode = async () => {
|
|
623
|
+
const code = inputVerifyCode.value.trim();
|
|
624
|
+
if (!code || code.length !== 6 || !/^\d{6}$/.test(code)) {
|
|
625
|
+
this.setStatus("Please enter a valid 6-digit numeric verification code (e.g. 482901).", "error");
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
btnSubmitCode.disabled = true;
|
|
629
|
+
btnSubmitCode.textContent = "Verifying...";
|
|
630
|
+
this.showBusy({
|
|
631
|
+
isBusy: true,
|
|
632
|
+
title: 'Verifying & Activating...',
|
|
633
|
+
msg: 'Great! Juust a moment...\n(Validating code, promoting server domain space, other security stuff...)',
|
|
634
|
+
animationEmoji: '🔐'
|
|
635
|
+
});
|
|
636
|
+
const resVerify = await getApiBridge().postVerifyCode({ email, primaryTjpAddr: primaryTjpAddr, code });
|
|
637
|
+
if (!resVerify.success) {
|
|
638
|
+
this.showBusy({ isBusy: false });
|
|
639
|
+
this.setStatus(resVerify.message || "Incorrect verification code.", "error");
|
|
640
|
+
btnSubmitCode.disabled = false;
|
|
641
|
+
btnSubmitCode.textContent = "Verify Code";
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
console.log(`${lc} Code verified & server domain promoted! Syncing delegate...`);
|
|
645
|
+
this.showBusy({
|
|
646
|
+
isBusy: true,
|
|
647
|
+
title: 'Syncing Delegate...',
|
|
648
|
+
msg: 'Posting evolved domain identity and sync delegate to server...',
|
|
649
|
+
animationEmoji: '⚡'
|
|
650
|
+
});
|
|
651
|
+
btnSubmitCode.removeEventListener('click', onSubmitCode);
|
|
652
|
+
secVerify.classList.add('hidden');
|
|
653
|
+
this.setFormDisabled(false);
|
|
654
|
+
// Now that server domain space is promoted, post evolved keystone + delegate
|
|
655
|
+
const resEvolve = await getApiBridge().putEvolveKeystone({
|
|
656
|
+
domainAddr: primaryTjpAddr,
|
|
657
|
+
keystoneIbGib: evolvedParentKeystoneIbGib,
|
|
658
|
+
relatedKeystoneIbGibs: [delegateKeystoneIbGib]
|
|
659
|
+
});
|
|
660
|
+
if (!resEvolve.success) {
|
|
661
|
+
console.warn(`${lc} Delegate sync warning after code verification: ${resEvolve.message}`);
|
|
662
|
+
}
|
|
663
|
+
resolve();
|
|
664
|
+
};
|
|
665
|
+
btnSubmitCode.addEventListener('click', onSubmitCode);
|
|
666
|
+
});
|
|
346
667
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
// Expose for dev tools
|
|
370
|
-
window.dev_domainI = evolvedParentKeystoneIbGib;
|
|
371
|
-
window.dev_domainIMasterSecret = masterSecret;
|
|
372
|
-
window.dev_syncDelegate = delegateKeystoneIbGib;
|
|
373
|
-
window.dev_syncDelegateSecret = delegateSecret;
|
|
374
|
-
// 6. Request to make the new identity active if the checkbox is checked
|
|
375
|
-
const makeActive = this.elements.checkboxMakeActive?.checked;
|
|
376
|
-
if (makeActive) {
|
|
377
|
-
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
|
|
378
|
-
detail: { activeIdentityAddr: evolvedParentAddr },
|
|
379
|
-
bubbles: true,
|
|
380
|
-
composed: true
|
|
381
|
-
}));
|
|
668
|
+
else {
|
|
669
|
+
// Post evolved keystone + delegate keystone immediately (no email or pre-verified)
|
|
670
|
+
this.setStatus("Syncing delegate registration to server...", "info");
|
|
671
|
+
this.showBusy({
|
|
672
|
+
isBusy: true,
|
|
673
|
+
title: 'Syncing Delegate...',
|
|
674
|
+
msg: 'Posting evolved domain identity and sync delegate to server...',
|
|
675
|
+
animationEmoji: '🔄'
|
|
676
|
+
});
|
|
677
|
+
const resEvolve = await getApiBridge().putEvolveKeystone({
|
|
678
|
+
domainAddr: primaryTjpAddr,
|
|
679
|
+
keystoneIbGib: evolvedParentKeystoneIbGib,
|
|
680
|
+
relatedKeystoneIbGibs: [delegateKeystoneIbGib]
|
|
681
|
+
});
|
|
682
|
+
if (!resEvolve.success) {
|
|
683
|
+
const msg = `Delegate registration sync failed: ${resEvolve.message}`;
|
|
684
|
+
console.error(`${lc} ${msg}`);
|
|
685
|
+
this.setStatus(msg, "error");
|
|
686
|
+
this.showBusy({ isBusy: false });
|
|
687
|
+
this.setButtonLoading(false);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
382
690
|
}
|
|
383
|
-
//
|
|
384
|
-
this.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
691
|
+
// 5. Finalize onboarding: update keystones index, activate identity, and navigate to identity manager
|
|
692
|
+
await this.finalizeIdentityOnboarding({
|
|
693
|
+
primaryKeystone: evolvedParentKeystoneIbGib,
|
|
694
|
+
delegateKeystone: delegateKeystoneIbGib,
|
|
695
|
+
primaryTjpAddr: evolvedParentAddr,
|
|
696
|
+
masterSecret,
|
|
697
|
+
delegateSecret,
|
|
698
|
+
makeActive: this.elements.checkboxMakeActive?.checked ?? true
|
|
699
|
+
});
|
|
389
700
|
}
|
|
390
701
|
catch (error) {
|
|
391
702
|
const emsg = extractErrorMsg(error);
|
|
@@ -400,6 +711,141 @@ export class KeystoneCreatorComponentInstance extends IbGibFormInstanceBase {
|
|
|
400
711
|
this.setButtonLoading(false);
|
|
401
712
|
}
|
|
402
713
|
}
|
|
714
|
+
/**
|
|
715
|
+
* DRY helper to register keystones in the local keystones special index,
|
|
716
|
+
* set the active identity, and navigate to the Identity Manager component.
|
|
717
|
+
*/
|
|
718
|
+
async finalizeIdentityOnboarding({ primaryKeystone, primaryGraph, delegateKeystone, primaryTjpAddr, masterSecret, delegateSecret, makeActive = true, }) {
|
|
719
|
+
const lc = `${this.lc}[${this.finalizeIdentityOnboarding.name}]`;
|
|
720
|
+
const humanEyeDelay = 500;
|
|
721
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
722
|
+
if (!metaspace) {
|
|
723
|
+
throw new Error(`(UNEXPECTED) metaspace falsy? Expected active global metaspace instance. (E: 2e37a8b6fe987449c5d8693a7d4a2827)`);
|
|
724
|
+
}
|
|
725
|
+
const space = await metaspace.getLocalUserSpace({});
|
|
726
|
+
if (!space) {
|
|
727
|
+
throw new Error(`(UNEXPECTED) space falsy? Expected valid default local user space from metaspace. (E: 1e37a8b6fe987449c5d8693a7d4a2826)`);
|
|
728
|
+
}
|
|
729
|
+
// 0. Persist all frames of primary identity graph into local browser space
|
|
730
|
+
if (primaryGraph) {
|
|
731
|
+
const graphIbGibs = Object.values(primaryGraph);
|
|
732
|
+
for (const frame of graphIbGibs) {
|
|
733
|
+
await metaspace.put({ ibGibs: [frame], space });
|
|
734
|
+
await metaspace.registerNewIbGib({ ibGib: frame, space });
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
else if (primaryKeystone) {
|
|
738
|
+
await metaspace.put({ ibGibs: [primaryKeystone], space });
|
|
739
|
+
await metaspace.registerNewIbGib({ ibGib: primaryKeystone, space });
|
|
740
|
+
}
|
|
741
|
+
// 0.5 Verify primary keystone exists in local browser space via getLatestKeystone
|
|
742
|
+
const keystoneService = new KeystoneService_V1();
|
|
743
|
+
try {
|
|
744
|
+
await keystoneService.getLatestKeystone({
|
|
745
|
+
addr: primaryTjpAddr,
|
|
746
|
+
metaspace,
|
|
747
|
+
space
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
catch (error) {
|
|
751
|
+
const emsg = `Primary identity keystone ${primaryTjpAddr} not found in local browser space! Error: ${extractErrorMsg(error)}`;
|
|
752
|
+
console.error(`${lc} ${emsg} (E: a123456789abcdef0123456789c0001)`);
|
|
753
|
+
throw new Error(emsg);
|
|
754
|
+
}
|
|
755
|
+
// 1. Register with the local keystones special index
|
|
756
|
+
this.showBusy({
|
|
757
|
+
isBusy: true,
|
|
758
|
+
title: 'Registering Identity...',
|
|
759
|
+
msg: 'Updating local identity indexes and scope settings...',
|
|
760
|
+
animationEmoji: '💾'
|
|
761
|
+
});
|
|
762
|
+
const ibGibsToRegister = [toDto({ ibGib: delegateKeystone })];
|
|
763
|
+
if (!primaryKeystone && !primaryGraph) {
|
|
764
|
+
throw new Error(`(UNEXPECTED) primaryKeystone and primaryGraph both falsy? We should have gotten this back from the server. (E: e34cd882ac66633c75c53318a3b28826)`);
|
|
765
|
+
}
|
|
766
|
+
if (!delegateKeystone) {
|
|
767
|
+
throw new Error(`(UNEXPECTED) delegateKeystone falsy? We should have made this locally and even registered it with the server. (E: 56b1c396269e15f008b7e298c71bc826)`);
|
|
768
|
+
}
|
|
769
|
+
if (primaryKeystone) {
|
|
770
|
+
ibGibsToRegister.unshift(toDto({ ibGib: primaryKeystone }));
|
|
771
|
+
}
|
|
772
|
+
await updateSpecialIndex({
|
|
773
|
+
type: "keystones",
|
|
774
|
+
rel8nInfos: [
|
|
775
|
+
{
|
|
776
|
+
rel8nName: "keystone",
|
|
777
|
+
ibGibs: ibGibsToRegister,
|
|
778
|
+
},
|
|
779
|
+
],
|
|
780
|
+
metaspace,
|
|
781
|
+
space,
|
|
782
|
+
});
|
|
783
|
+
// Expose for dev tools debugging if available
|
|
784
|
+
if (masterSecret) {
|
|
785
|
+
window.dev_domainI = primaryKeystone;
|
|
786
|
+
window.dev_domainIMasterSecret = masterSecret;
|
|
787
|
+
window.dev_syncDelegate = delegateKeystone;
|
|
788
|
+
window.dev_syncDelegateSecret = delegateSecret;
|
|
789
|
+
}
|
|
790
|
+
// 2. Request to make the new identity active
|
|
791
|
+
if (makeActive) {
|
|
792
|
+
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_REQUEST_CHANGE, {
|
|
793
|
+
detail: { activeIdentityAddr: primaryTjpAddr },
|
|
794
|
+
bubbles: true,
|
|
795
|
+
composed: true
|
|
796
|
+
}));
|
|
797
|
+
}
|
|
798
|
+
// 3. Display success status
|
|
799
|
+
const successMsg = "Identity successfully created and activated!";
|
|
800
|
+
this.showBusy({
|
|
801
|
+
isBusy: true,
|
|
802
|
+
title: 'Success!',
|
|
803
|
+
msg: successMsg,
|
|
804
|
+
animationEmoji: '✅'
|
|
805
|
+
});
|
|
806
|
+
await delay(humanEyeDelay);
|
|
807
|
+
if (this.elements?.keystoneAddrEl) {
|
|
808
|
+
this.elements.keystoneAddrEl.textContent = primaryTjpAddr;
|
|
809
|
+
}
|
|
810
|
+
if (this.elements?.statusArea) {
|
|
811
|
+
this.elements.statusArea.classList.remove('hidden');
|
|
812
|
+
}
|
|
813
|
+
this.setStatus(successMsg, "success");
|
|
814
|
+
console.log(`${lc} ✓ ${successMsg}`);
|
|
815
|
+
// 4. Dispatch UI navigation message to close creator and open identity manager
|
|
816
|
+
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_UI_MESSAGE, {
|
|
817
|
+
detail: { action: 'show-identity-manager', addr: primaryTjpAddr },
|
|
818
|
+
bubbles: true,
|
|
819
|
+
composed: true
|
|
820
|
+
}));
|
|
821
|
+
this.showBusy({ isBusy: false });
|
|
822
|
+
}
|
|
823
|
+
setFormDisabled(disabled) {
|
|
824
|
+
const root = this.shadowRoot;
|
|
825
|
+
const inputIds = [
|
|
826
|
+
'input-username',
|
|
827
|
+
'input-description',
|
|
828
|
+
'input-email',
|
|
829
|
+
'input-secret',
|
|
830
|
+
'checkbox-make-active',
|
|
831
|
+
'btn-generate',
|
|
832
|
+
'btn-switch-sign-in',
|
|
833
|
+
];
|
|
834
|
+
for (const id of inputIds) {
|
|
835
|
+
const el = root.getElementById(id);
|
|
836
|
+
if (el) {
|
|
837
|
+
el.disabled = disabled;
|
|
838
|
+
if (disabled) {
|
|
839
|
+
el.style.opacity = '0.5';
|
|
840
|
+
el.style.pointerEvents = 'none';
|
|
841
|
+
}
|
|
842
|
+
else {
|
|
843
|
+
el.style.opacity = '1';
|
|
844
|
+
el.style.pointerEvents = 'auto';
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
403
849
|
async renderUI() {
|
|
404
850
|
// No complex rendering needed for this simple creator component yet
|
|
405
851
|
}
|