@ibgib/web-gib 0.0.59 → 0.0.61
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/helpers.d.mts.map +1 -1
- package/dist/helpers.mjs +1 -0
- package/dist/helpers.mjs.map +1 -1
- package/dist/identity/device-delegate-helper.d.mts +43 -0
- package/dist/identity/device-delegate-helper.d.mts.map +1 -0
- package/dist/identity/device-delegate-helper.mjs +106 -0
- package/dist/identity/device-delegate-helper.mjs.map +1 -0
- package/dist/identity/device-delegate.respec.d.mts +2 -0
- package/dist/identity/device-delegate.respec.d.mts.map +1 -0
- package/dist/identity/device-delegate.respec.mjs +106 -0
- package/dist/identity/device-delegate.respec.mjs.map +1 -0
- package/dist/identity/identity-constants.mjs +2 -2
- package/dist/identity/identity-constants.mjs.map +1 -1
- package/dist/identity/identity-types.d.mts +4 -4
- package/dist/identity/identity-types.d.mts.map +1 -1
- package/dist/identity/keystone-sync-service.d.mts +18 -0
- package/dist/identity/keystone-sync-service.d.mts.map +1 -1
- package/dist/identity/keystone-sync-service.mjs +77 -1
- package/dist/identity/keystone-sync-service.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -2
- package/dist/index.mjs.map +1 -1
- package/dist/storage/storage-helpers.web.d.mts +9 -0
- package/dist/storage/storage-helpers.web.d.mts.map +1 -1
- package/dist/storage/storage-helpers.web.mjs +42 -0
- package/dist/storage/storage-helpers.web.mjs.map +1 -1
- package/dist/ui/component/identity/add-device/add-device.css +93 -17
- package/dist/ui/component/identity/add-device/add-device.d.mts +24 -7
- package/dist/ui/component/identity/add-device/add-device.d.mts.map +1 -1
- package/dist/ui/component/identity/add-device/add-device.html +97 -23
- package/dist/ui/component/identity/add-device/add-device.mjs +489 -198
- package/dist/ui/component/identity/add-device/add-device.mjs.map +1 -1
- package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts.map +1 -1
- package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs +48 -61
- package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs.map +1 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.css +1 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.d.mts +11 -8
- package/dist/ui/component/identity/keystone-details/keystone-details.d.mts.map +1 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.html +29 -20
- package/dist/ui/component/identity/keystone-details/keystone-details.mjs +358 -97
- package/dist/ui/component/identity/keystone-details/keystone-details.mjs.map +1 -1
- package/dist/ui/component/identity/remove-device/remove-device.d.mts +1 -1
- package/dist/ui/component/identity/remove-device/remove-device.d.mts.map +1 -1
- package/dist/ui/component/identity/remove-device/remove-device.html +3 -3
- package/dist/ui/component/identity/remove-device/remove-device.mjs +7 -7
- package/dist/ui/component/identity/remove-device/remove-device.mjs.map +1 -1
- package/dist/ui/ui-constants.d.mts +1 -0
- package/dist/ui/ui-constants.d.mts.map +1 -1
- package/dist/ui/ui-constants.mjs +1 -0
- package/dist/ui/ui-constants.mjs.map +1 -1
- package/dist/ui/ui-types.d.mts +5 -0
- package/dist/ui/ui-types.d.mts.map +1 -1
- package/dist/util/device-helper.d.mts +30 -0
- package/dist/util/device-helper.d.mts.map +1 -0
- package/dist/util/device-helper.mjs +90 -0
- package/dist/util/device-helper.mjs.map +1 -0
- package/dist/util/device-helper.respec.d.mts +2 -0
- package/dist/util/device-helper.respec.d.mts.map +1 -0
- package/dist/util/device-helper.respec.mjs +83 -0
- package/dist/util/device-helper.respec.mjs.map +1 -0
- package/package.json +3 -3
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/helpers.mts +1 -0
- package/src/identity/custodian-delegate-helper.mts.bak +7 -0
- package/src/identity/device-delegate-helper.mts +135 -0
- package/src/identity/device-delegate.respec.mts +125 -0
- package/src/identity/identity-constants.mts +2 -2
- package/src/identity/identity-types.mts +4 -4
- package/src/identity/keystone-sync-service.mts +95 -2
- package/src/index.mts +1 -2
- package/src/storage/storage-helpers.web.mts +47 -0
- package/src/ui/component/identity/add-device/add-device.css +93 -17
- package/src/ui/component/identity/add-device/add-device.html +97 -23
- package/src/ui/component/identity/add-device/add-device.mts +579 -208
- package/src/ui/component/identity/keystone-creator/keystone-creator.mts +55 -69
- package/src/ui/component/identity/keystone-details/keystone-details.css +1 -1
- package/src/ui/component/identity/keystone-details/keystone-details.html +29 -20
- package/src/ui/component/identity/keystone-details/keystone-details.mts +374 -106
- package/src/ui/component/identity/remove-device/remove-device.html +3 -3
- package/src/ui/component/identity/remove-device/remove-device.mts +8 -8
- package/src/ui/ui-constants.mts +1 -0
- package/src/ui/ui-types.mts +6 -0
- package/src/util/device-helper.mts +104 -0
- package/src/util/device-helper.respec.mts +90 -0
- package/dist/identity/custodian-delegate-helper.d.mts +0 -22
- package/dist/identity/custodian-delegate-helper.d.mts.map +0 -1
- package/dist/identity/custodian-delegate-helper.mjs +0 -50
- package/dist/identity/custodian-delegate-helper.mjs.map +0 -1
- package/src/identity/custodian-delegate-helper.mts +0 -61
|
@@ -15,7 +15,9 @@ import { parseSpaceIb } from "@ibgib/core-gib/dist/witness/space/space-helper.mj
|
|
|
15
15
|
import { executeSsoOAuthPopup } from "../../../../identity/sso-popup-helper.mjs";
|
|
16
16
|
import { getComponentCtorArg } from "../../../../app-bootstrap/init-orchestration.mjs";
|
|
17
17
|
import { promptForSecret } from "../../../../helpers.web.mjs";
|
|
18
|
-
import { isSsoProviderLinked } from "
|
|
18
|
+
import { isSsoProviderLinked, getKeystoneCapabilities, isDelegateExpired } from "@ibgib/core-gib/dist/keystone/delegate/delegate-helpers.mjs";
|
|
19
|
+
import { generatePoolChallenges } from "@ibgib/core-gib/dist/keystone/keystone-helpers.mjs";
|
|
20
|
+
import { POOL_ID_MANAGE } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
|
|
19
21
|
import { getGlobalMetaspace_waitIfNeeded } from "../../../../helpers.mjs";
|
|
20
22
|
const logalot = false;
|
|
21
23
|
export const KEYSTONE_DETAILS_COMPONENT_NAME = 'ibgib-keystone-details';
|
|
@@ -51,6 +53,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
51
53
|
isHistoricalFrame = false;
|
|
52
54
|
_onIdentityChanged = null;
|
|
53
55
|
keystoneCache = new Map();
|
|
56
|
+
aggregatedDetails;
|
|
54
57
|
constructor() {
|
|
55
58
|
super();
|
|
56
59
|
}
|
|
@@ -145,12 +148,12 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
145
148
|
this.elements.btnLinkGoogleEl = shadow.getElementById('btn-link-google');
|
|
146
149
|
this.elements.btnLinkGithubEl = shadow.getElementById('btn-link-github');
|
|
147
150
|
this.elements.ssoStatusMsgEl = shadow.getElementById('sso-status-msg');
|
|
148
|
-
this.elements.
|
|
149
|
-
this.elements.
|
|
150
|
-
this.elements.
|
|
151
|
-
this.elements.
|
|
152
|
-
this.elements.
|
|
153
|
-
this.elements.
|
|
151
|
+
this.elements.inputCurrentPasswordEl = shadow.getElementById('input-current-password');
|
|
152
|
+
this.elements.inputNewPasswordEl = shadow.getElementById('input-new-password');
|
|
153
|
+
this.elements.inputConfirmPasswordEl = shadow.getElementById('input-confirm-password');
|
|
154
|
+
this.elements.btnChangePasswordEl = shadow.getElementById('btn-change-password');
|
|
155
|
+
this.elements.changePasswordStatusEl = shadow.getElementById('change-password-status');
|
|
156
|
+
this.elements.changePasswordCardEl = shadow.getElementById('change-password-card');
|
|
154
157
|
// ElementBase requires contentEl
|
|
155
158
|
this.elements.contentEl = shadow.getElementById('identity-details-view');
|
|
156
159
|
this.initHandlers();
|
|
@@ -190,7 +193,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
190
193
|
this.elements.btnUpdateIdentityEl.addEventListener('click', () => this.handleUpdateIdentity());
|
|
191
194
|
this.elements.btnLinkGoogleEl.addEventListener('click', () => this.handleSSOClick('google'));
|
|
192
195
|
this.elements.btnLinkGithubEl.addEventListener('click', () => this.handleSSOClick('github'));
|
|
193
|
-
this.elements.
|
|
196
|
+
this.elements.btnChangePasswordEl.addEventListener('click', () => this.handleChangePassword());
|
|
194
197
|
}
|
|
195
198
|
toggleAccordion() {
|
|
196
199
|
const header = this.elements.rawAccordionHeaderEl;
|
|
@@ -394,21 +397,36 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
394
397
|
this.elements.btnSetActiveEl.disabled = isTimelineActive;
|
|
395
398
|
this.elements.btnLinkGoogleEl.classList.remove('disabled');
|
|
396
399
|
this.elements.btnLinkGithubEl.classList.remove('disabled');
|
|
397
|
-
// Check if
|
|
398
|
-
const
|
|
399
|
-
const
|
|
400
|
+
// Check if origin provider or linked
|
|
401
|
+
const originProvider = this.aggregatedDetails?.custodianProvider || this.ibGib?.data?.frameDetails?.custodianProvider;
|
|
402
|
+
const isGoogleLinked = isSsoProviderLinked({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails, providerId: 'google' });
|
|
403
|
+
const isGithubLinked = isSsoProviderLinked({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails, providerId: 'github' });
|
|
404
|
+
const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
|
|
400
405
|
// Google Card States
|
|
401
406
|
const googleCard = this.elements.btnLinkGoogleEl;
|
|
402
407
|
const googleLabel = googleCard.querySelector('.toggle-state-text');
|
|
403
408
|
if (isGoogleLinked) {
|
|
404
409
|
googleCard.classList.remove('unlinked');
|
|
405
410
|
googleCard.classList.add('linked');
|
|
406
|
-
|
|
411
|
+
const isOrigin = originProvider === 'google';
|
|
412
|
+
if (isOrigin && !caps.isSovereign) {
|
|
413
|
+
googleLabel.textContent = "Google (Primary Account) 🔒";
|
|
414
|
+
googleCard.title = "Cannot unlink primary account without first adding a Master Password below.";
|
|
415
|
+
}
|
|
416
|
+
else if (isOrigin) {
|
|
417
|
+
googleLabel.textContent = "Google (Primary Account) ✅";
|
|
418
|
+
googleCard.title = "Click to unlink Google provider (requires Master Password).";
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
googleLabel.textContent = "Google Linked ✅";
|
|
422
|
+
googleCard.title = "Click to unlink Google provider.";
|
|
423
|
+
}
|
|
407
424
|
}
|
|
408
425
|
else {
|
|
409
426
|
googleCard.classList.remove('linked');
|
|
410
427
|
googleCard.classList.add('unlinked');
|
|
411
428
|
googleLabel.textContent = "Unlinked";
|
|
429
|
+
googleCard.title = "Click to link Google account.";
|
|
412
430
|
}
|
|
413
431
|
// GitHub Card States
|
|
414
432
|
const githubCard = this.elements.btnLinkGithubEl;
|
|
@@ -416,15 +434,56 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
416
434
|
if (isGithubLinked) {
|
|
417
435
|
githubCard.classList.remove('unlinked');
|
|
418
436
|
githubCard.classList.add('linked');
|
|
419
|
-
|
|
437
|
+
const isOrigin = originProvider === 'github';
|
|
438
|
+
if (isOrigin && !caps.isSovereign) {
|
|
439
|
+
githubLabel.textContent = "GitHub (Primary Account) 🔒";
|
|
440
|
+
githubCard.title = "Cannot unlink primary account without first adding a Master Password below.";
|
|
441
|
+
}
|
|
442
|
+
else if (isOrigin) {
|
|
443
|
+
githubLabel.textContent = "GitHub (Primary Account) ✅";
|
|
444
|
+
githubCard.title = "Click to unlink GitHub provider (requires Master Password).";
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
githubLabel.textContent = "GitHub Linked ✅";
|
|
448
|
+
githubCard.title = "Click to unlink GitHub provider.";
|
|
449
|
+
}
|
|
420
450
|
}
|
|
421
451
|
else {
|
|
422
452
|
githubCard.classList.remove('linked');
|
|
423
453
|
githubCard.classList.add('unlinked');
|
|
424
454
|
githubLabel.textContent = "Unlinked";
|
|
455
|
+
githubCard.title = "Click to link GitHub account.";
|
|
425
456
|
}
|
|
426
457
|
}
|
|
427
458
|
}
|
|
459
|
+
updatePasswordCardView() {
|
|
460
|
+
const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
|
|
461
|
+
const cardTitleEl = this.elements?.changePasswordCardEl?.querySelector('h3');
|
|
462
|
+
const cardDescEl = this.elements?.changePasswordCardEl?.querySelector('.description');
|
|
463
|
+
const currentPasswordGroup = this.elements?.inputCurrentPasswordEl?.closest('.form-group');
|
|
464
|
+
const btnChangePassword = this.elements?.btnChangePasswordEl;
|
|
465
|
+
const isCustodialOnly = caps.isCustodial && !caps.isSovereign;
|
|
466
|
+
if (isCustodialOnly) {
|
|
467
|
+
if (cardTitleEl)
|
|
468
|
+
cardTitleEl.textContent = "Add Master Password";
|
|
469
|
+
if (cardDescEl)
|
|
470
|
+
cardDescEl.textContent = "Establish sovereign ownership by adding a master password. This enables direct, independent cryptographic management without relying solely on custodian authentication.";
|
|
471
|
+
if (currentPasswordGroup)
|
|
472
|
+
currentPasswordGroup.style.display = 'none';
|
|
473
|
+
if (btnChangePassword)
|
|
474
|
+
btnChangePassword.textContent = "Add Master Password";
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
if (cardTitleEl)
|
|
478
|
+
cardTitleEl.textContent = "Change Password";
|
|
479
|
+
if (cardDescEl)
|
|
480
|
+
cardDescEl.textContent = "Rotate your local password that drives this identity. This will cryptographically evolve your primary identity and all registered user-owned delegate keystones to the new password.";
|
|
481
|
+
if (currentPasswordGroup)
|
|
482
|
+
currentPasswordGroup.style.display = '';
|
|
483
|
+
if (btnChangePassword)
|
|
484
|
+
btnChangePassword.textContent = "Update Password";
|
|
485
|
+
}
|
|
486
|
+
}
|
|
428
487
|
async updateFrameDetailsView() {
|
|
429
488
|
const lc = `${this.lc}[${this.updateFrameDetailsView.name}]`;
|
|
430
489
|
try {
|
|
@@ -484,6 +543,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
484
543
|
metaspace,
|
|
485
544
|
space
|
|
486
545
|
});
|
|
546
|
+
this.aggregatedDetails = aggregated;
|
|
487
547
|
this.elements.identityAggrDetailsEl.textContent = aggregated ? pretty(aggregated) : '{}';
|
|
488
548
|
// Update Username and Description fields
|
|
489
549
|
this.elements.identityNameEl.textContent = aggregated?.username || aggregated?.profile?.name || aggregated?.name || '-';
|
|
@@ -491,18 +551,21 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
491
551
|
}
|
|
492
552
|
catch (err) {
|
|
493
553
|
console.warn(`${lc} Error aggregating details: ${extractErrorMsg(err)}`);
|
|
554
|
+
this.aggregatedDetails = undefined;
|
|
494
555
|
this.elements.identityAggrDetailsEl.textContent = '{}';
|
|
495
556
|
this.elements.identityNameEl.textContent = '-';
|
|
496
557
|
this.elements.identityDescriptionEl.textContent = '-';
|
|
497
558
|
}
|
|
498
559
|
}
|
|
499
560
|
else {
|
|
561
|
+
this.aggregatedDetails = undefined;
|
|
500
562
|
this.elements.identityAggrDetailsEl.textContent = '{}';
|
|
501
563
|
this.elements.identityNameEl.textContent = '-';
|
|
502
564
|
this.elements.identityDescriptionEl.textContent = '-';
|
|
503
565
|
}
|
|
504
566
|
}
|
|
505
567
|
else {
|
|
568
|
+
this.aggregatedDetails = undefined;
|
|
506
569
|
this.elements.identityAggrDetailsEl.textContent = '{}';
|
|
507
570
|
this.elements.identityNameEl.textContent = '-';
|
|
508
571
|
this.elements.identityDescriptionEl.textContent = '-';
|
|
@@ -525,18 +588,19 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
525
588
|
this.elements.rawKeystoneJsonEl.textContent = pretty(keystone);
|
|
526
589
|
// Render Challenge Pools
|
|
527
590
|
this.renderChallengePools(keystone.data?.challengePools || []);
|
|
528
|
-
// Render Delegates, SSO link, and
|
|
591
|
+
// Render Delegates, SSO link, and Password Change cards (only if this is a primary keystone, hide them for delegate/session keystones)
|
|
529
592
|
const details = await this.getKeystoneDetails(this.ibGibAddr);
|
|
530
593
|
if (details.isPrimary) {
|
|
531
594
|
this.elements.delegatesCardEl.classList.remove('hidden');
|
|
532
595
|
await this.renderDelegates(keystone.data?.delegates);
|
|
533
596
|
this.elements.ssoLinkCardEl.classList.remove('hidden');
|
|
534
|
-
this.elements.
|
|
597
|
+
this.elements.changePasswordCardEl.classList.remove('hidden');
|
|
598
|
+
this.updatePasswordCardView();
|
|
535
599
|
}
|
|
536
600
|
else {
|
|
537
601
|
this.elements.delegatesCardEl.classList.add('hidden');
|
|
538
602
|
this.elements.ssoLinkCardEl.classList.add('hidden');
|
|
539
|
-
this.elements.
|
|
603
|
+
this.elements.changePasswordCardEl.classList.add('hidden');
|
|
540
604
|
}
|
|
541
605
|
this.updateActiveButtonState();
|
|
542
606
|
}
|
|
@@ -554,6 +618,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
554
618
|
if (!this.elements) {
|
|
555
619
|
return;
|
|
556
620
|
}
|
|
621
|
+
this.aggregatedDetails = undefined;
|
|
557
622
|
this.isHistoricalFrame = false;
|
|
558
623
|
if (this.elements.historicalWarningBannerEl) {
|
|
559
624
|
this.elements.historicalWarningBannerEl.classList.add('hidden');
|
|
@@ -730,39 +795,66 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
730
795
|
return;
|
|
731
796
|
}
|
|
732
797
|
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
798
|
+
if (!metaspace) {
|
|
799
|
+
throw new Error(`(UNEXPECTED) metaspace falsy? (E: 8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3e)`);
|
|
800
|
+
}
|
|
801
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
802
|
+
if (!space) {
|
|
803
|
+
throw new Error(`(UNEXPECTED) space falsy? (E: 9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4f)`);
|
|
739
804
|
}
|
|
805
|
+
const localSpaceId = space.ib ? parseSpaceIb({ spaceIb: space.ib }).spaceId : undefined;
|
|
740
806
|
for (const [delegateTjpAddr, info] of Object.entries(delegates)) {
|
|
741
807
|
const tr = document.createElement('tr');
|
|
742
808
|
const deviceName = info.deviceName || info.details?.deviceTag || info.details?.name || 'Device Delegate';
|
|
743
809
|
const tdName = document.createElement('td');
|
|
744
810
|
const delegateSpaceId = info.spaceId || info.details?.spaceId;
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
badgeEl.textContent = 'This Device';
|
|
755
|
-
badgeEl.className = 'badge badge-this-device';
|
|
756
|
-
badgeEl.style.backgroundColor = '#1b5e20';
|
|
757
|
-
badgeEl.style.color = '#a5d6a7';
|
|
811
|
+
// Check if delegate is present in local space (via spaceId match or direct presence check)
|
|
812
|
+
let isThisDevice = false;
|
|
813
|
+
if (localSpaceId && delegateSpaceId === localSpaceId) {
|
|
814
|
+
isThisDevice = true;
|
|
815
|
+
}
|
|
816
|
+
else {
|
|
817
|
+
try {
|
|
818
|
+
const resGet = await metaspace.get({ addrs: [delegateTjpAddr], space });
|
|
819
|
+
isThisDevice = !!(resGet.success && resGet.ibGibs && resGet.ibGibs.length > 0);
|
|
758
820
|
}
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
badgeEl.className = 'badge badge-remote-device';
|
|
762
|
-
badgeEl.style.backgroundColor = '#0d47a1';
|
|
763
|
-
badgeEl.style.color = '#90caf9';
|
|
821
|
+
catch {
|
|
822
|
+
isThisDevice = false;
|
|
764
823
|
}
|
|
765
824
|
}
|
|
825
|
+
const badgeEl = document.createElement('span');
|
|
826
|
+
badgeEl.style.marginLeft = '0.5rem';
|
|
827
|
+
badgeEl.style.padding = '0.15rem 0.4rem';
|
|
828
|
+
badgeEl.style.borderRadius = '4px';
|
|
829
|
+
badgeEl.style.fontSize = '0.75rem';
|
|
830
|
+
badgeEl.style.fontWeight = 'bold';
|
|
831
|
+
if (isThisDevice) {
|
|
832
|
+
badgeEl.textContent = 'This Device';
|
|
833
|
+
badgeEl.className = 'badge badge-this-device';
|
|
834
|
+
badgeEl.style.backgroundColor = '#1b5e20';
|
|
835
|
+
badgeEl.style.color = '#a5d6a7';
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
badgeEl.textContent = 'Remote Device';
|
|
839
|
+
badgeEl.className = 'badge badge-remote-device';
|
|
840
|
+
badgeEl.style.backgroundColor = '#0d47a1';
|
|
841
|
+
badgeEl.style.color = '#90caf9';
|
|
842
|
+
}
|
|
843
|
+
// Check expiration
|
|
844
|
+
const isExpired = isDelegateExpired({ delegateInfo: info });
|
|
845
|
+
let expiredBadgeEl = null;
|
|
846
|
+
if (isExpired) {
|
|
847
|
+
expiredBadgeEl = document.createElement('span');
|
|
848
|
+
expiredBadgeEl.textContent = 'Expired';
|
|
849
|
+
expiredBadgeEl.className = 'badge badge-expired';
|
|
850
|
+
expiredBadgeEl.style.marginLeft = '0.3rem';
|
|
851
|
+
expiredBadgeEl.style.padding = '0.15rem 0.4rem';
|
|
852
|
+
expiredBadgeEl.style.borderRadius = '4px';
|
|
853
|
+
expiredBadgeEl.style.fontSize = '0.75rem';
|
|
854
|
+
expiredBadgeEl.style.fontWeight = 'bold';
|
|
855
|
+
expiredBadgeEl.style.backgroundColor = '#b71c1c';
|
|
856
|
+
expiredBadgeEl.style.color = '#ef9a9a';
|
|
857
|
+
}
|
|
766
858
|
const applyNameAndBadge = (displayName, hoverText) => {
|
|
767
859
|
tdName.innerHTML = '';
|
|
768
860
|
const textSpan = document.createElement('span');
|
|
@@ -771,6 +863,9 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
771
863
|
if (badgeEl) {
|
|
772
864
|
tdName.appendChild(badgeEl);
|
|
773
865
|
}
|
|
866
|
+
if (expiredBadgeEl) {
|
|
867
|
+
tdName.appendChild(expiredBadgeEl);
|
|
868
|
+
}
|
|
774
869
|
tdName.title = hoverText || displayName;
|
|
775
870
|
};
|
|
776
871
|
const displayName = `💻 ${deviceName}`;
|
|
@@ -781,7 +876,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
781
876
|
const tdVerbs = document.createElement('td');
|
|
782
877
|
tdVerbs.textContent = info.allowedVerbs ? info.allowedVerbs.join(', ') : '-';
|
|
783
878
|
tdVerbs.title = tdVerbs.textContent;
|
|
784
|
-
const isRemote =
|
|
879
|
+
const isRemote = !isThisDevice;
|
|
785
880
|
const tdActions = document.createElement('td');
|
|
786
881
|
const btnView = document.createElement('button');
|
|
787
882
|
btnView.className = 'action-btn secondary small';
|
|
@@ -792,22 +887,22 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
792
887
|
this.showRemoteDelegateModal(info);
|
|
793
888
|
}
|
|
794
889
|
else {
|
|
795
|
-
if (info.delegateAddr) {
|
|
890
|
+
if (info.delegateAddr || delegateTjpAddr) {
|
|
796
891
|
let addrToLoad = info.delegateAddr;
|
|
797
|
-
|
|
798
|
-
const
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
}
|
|
806
|
-
catch (err) {
|
|
807
|
-
console.warn(`${lc} Error resolving latest delegate address: ${extractErrorMsg(err)}`);
|
|
808
|
-
}
|
|
892
|
+
try {
|
|
893
|
+
const keystoneService = new KeystoneService_V1();
|
|
894
|
+
const latestKeystone = await keystoneService.getLatestKeystone({
|
|
895
|
+
addr: delegateTjpAddr,
|
|
896
|
+
metaspace,
|
|
897
|
+
space
|
|
898
|
+
});
|
|
899
|
+
if (latestKeystone) {
|
|
900
|
+
addrToLoad = getIbGibAddr({ ibGib: latestKeystone });
|
|
809
901
|
}
|
|
810
902
|
}
|
|
903
|
+
catch (err) {
|
|
904
|
+
console.warn(`${lc} Error resolving latest delegate keystone: ${extractErrorMsg(err)}`);
|
|
905
|
+
}
|
|
811
906
|
this.dispatchEvent(new CustomEvent('ibgib-view-keystone-details', {
|
|
812
907
|
detail: { addr: addrToLoad },
|
|
813
908
|
bubbles: true,
|
|
@@ -841,7 +936,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
841
936
|
let masterSecret;
|
|
842
937
|
try {
|
|
843
938
|
masterSecret = await promptForSecret({
|
|
844
|
-
msg: `Enter Master
|
|
939
|
+
msg: `Enter Master Password to revoke delegate '${deviceName}':`,
|
|
845
940
|
confirm: false
|
|
846
941
|
});
|
|
847
942
|
}
|
|
@@ -1011,8 +1106,8 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1011
1106
|
while (tries < maxTries && !isCorrect) {
|
|
1012
1107
|
try {
|
|
1013
1108
|
const promptMsg = tries === 0
|
|
1014
|
-
? "Link successful! Enter your local Master Secret (
|
|
1015
|
-
: `Incorrect
|
|
1109
|
+
? "Link successful! Enter your local Master Secret (Password) to sign and register the custodian pool"
|
|
1110
|
+
: `Incorrect password. Please try again (${maxTries - tries} tries remaining):`;
|
|
1016
1111
|
masterSecret = await promptForSecret({
|
|
1017
1112
|
msg: promptMsg,
|
|
1018
1113
|
confirm: false
|
|
@@ -1040,7 +1135,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1040
1135
|
}
|
|
1041
1136
|
}
|
|
1042
1137
|
if (!isCorrect) {
|
|
1043
|
-
this.setSSOStatus("Link cancelled or failed (incorrect
|
|
1138
|
+
this.setSSOStatus("Link cancelled or failed (incorrect password).", "error");
|
|
1044
1139
|
return;
|
|
1045
1140
|
}
|
|
1046
1141
|
this.setSSOStatus("Evolving identity locally and generating cryptographic signatures...", "info");
|
|
@@ -1090,8 +1185,13 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1090
1185
|
}
|
|
1091
1186
|
}
|
|
1092
1187
|
async handleSSOClick(providerId) {
|
|
1093
|
-
const isLinked = isSsoProviderLinked({ keystone: this.ibGib, providerId });
|
|
1188
|
+
const isLinked = isSsoProviderLinked({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails, providerId });
|
|
1094
1189
|
if (isLinked) {
|
|
1190
|
+
const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
|
|
1191
|
+
if (!caps.isSovereign) {
|
|
1192
|
+
this.setSSOStatus(`Cannot unlink ${providerId}: This is your only identity recovery and management method. Please add a Master Password first in the Password card below to enable sovereign ownership before unlinking.`, "error");
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1095
1195
|
await this.handleSSOUnlink(providerId);
|
|
1096
1196
|
}
|
|
1097
1197
|
else {
|
|
@@ -1102,7 +1202,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1102
1202
|
const lc = `${this.lc}[${this.handleSSOUnlink.name}]`;
|
|
1103
1203
|
this.setSSOStatus(`Unlinking ${providerId}...`, "info");
|
|
1104
1204
|
try {
|
|
1105
|
-
// 1. Prompt user for
|
|
1205
|
+
// 1. Prompt user for password
|
|
1106
1206
|
const keystoneService = new KeystoneService_V1();
|
|
1107
1207
|
let masterSecret;
|
|
1108
1208
|
let isCorrect = false;
|
|
@@ -1111,8 +1211,8 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1111
1211
|
while (tries < maxTries && !isCorrect) {
|
|
1112
1212
|
try {
|
|
1113
1213
|
const promptMsg = tries === 0
|
|
1114
|
-
? `Are you sure you want to unlink your ${providerId} account? If so, enter your local Master Secret (
|
|
1115
|
-
: `Incorrect
|
|
1214
|
+
? `Are you sure you want to unlink your ${providerId} account? If so, enter your local Master Secret (Password) to authorize. Otherwise, click Cancel.`
|
|
1215
|
+
: `Incorrect password. Please try again (${maxTries - tries} tries remaining):`;
|
|
1116
1216
|
masterSecret = await promptForSecret({
|
|
1117
1217
|
msg: promptMsg,
|
|
1118
1218
|
confirm: false
|
|
@@ -1136,7 +1236,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1136
1236
|
}
|
|
1137
1237
|
}
|
|
1138
1238
|
if (!isCorrect) {
|
|
1139
|
-
this.setSSOStatus("Unlink cancelled or failed (incorrect
|
|
1239
|
+
this.setSSOStatus("Unlink cancelled or failed (incorrect password).", "error");
|
|
1140
1240
|
return;
|
|
1141
1241
|
}
|
|
1142
1242
|
this.setSSOStatus("Evolving identity locally and removing custodian pool...", "info");
|
|
@@ -1149,13 +1249,28 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1149
1249
|
}
|
|
1150
1250
|
// 2. Evolve parent keystone to remove the custodian pool
|
|
1151
1251
|
const targetPoolId = `custodian-manage-${providerId}`;
|
|
1152
|
-
|
|
1252
|
+
let evolvedParent = await keystoneService.removePools({
|
|
1153
1253
|
latestKeystone: this.ibGib,
|
|
1154
1254
|
masterSecret: masterSecret,
|
|
1155
1255
|
poolIds: [targetPoolId],
|
|
1156
1256
|
metaspace,
|
|
1157
1257
|
space
|
|
1158
1258
|
});
|
|
1259
|
+
// Unregister any corresponding outward delegate for this provider if present
|
|
1260
|
+
const delegatesMap = this.ibGib?.data?.delegates;
|
|
1261
|
+
if (delegatesMap) {
|
|
1262
|
+
for (const [delegateTjpAddr, info] of Object.entries(delegatesMap)) {
|
|
1263
|
+
if (info.deviceName?.includes(providerId)) {
|
|
1264
|
+
evolvedParent = await keystoneService.unregisterDelegate({
|
|
1265
|
+
parentKeystone: evolvedParent,
|
|
1266
|
+
delegateTjpAddr,
|
|
1267
|
+
masterSecret: masterSecret,
|
|
1268
|
+
metaspace,
|
|
1269
|
+
space,
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1159
1274
|
// 3. Sync evolved parent keystone back to server
|
|
1160
1275
|
this.setSSOStatus("Publishing evolved identity keystone to server...", "info");
|
|
1161
1276
|
const syncRes = await getApiBridge().putEvolveKeystone({
|
|
@@ -1186,43 +1301,189 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1186
1301
|
this.setSSOStatus(`Unlink failed: ${extractErrorMsg(error)}`, "error");
|
|
1187
1302
|
}
|
|
1188
1303
|
}
|
|
1189
|
-
|
|
1190
|
-
const el = this.elements.
|
|
1304
|
+
setChangePasswordStatus(msg, type) {
|
|
1305
|
+
const el = this.elements.changePasswordStatusEl;
|
|
1191
1306
|
el.textContent = msg;
|
|
1192
1307
|
el.className = `status-msg ${type}`;
|
|
1193
1308
|
el.classList.remove('hidden');
|
|
1194
1309
|
}
|
|
1195
|
-
async
|
|
1196
|
-
const lc = `${this.lc}[${this.
|
|
1197
|
-
this.
|
|
1310
|
+
async handleAddMasterPassword() {
|
|
1311
|
+
const lc = `${this.lc}[${this.handleAddMasterPassword.name}]`;
|
|
1312
|
+
this.setChangePasswordStatus("Validating entries...", "info");
|
|
1313
|
+
try {
|
|
1314
|
+
const newPassword = this.elements.inputNewPasswordEl.value;
|
|
1315
|
+
const confirmPassword = this.elements.inputConfirmPasswordEl.value;
|
|
1316
|
+
if (!newPassword) {
|
|
1317
|
+
this.setChangePasswordStatus("Master password is required.", "error");
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
if (newPassword !== confirmPassword) {
|
|
1321
|
+
this.setChangePasswordStatus("Master password and confirmation do not match.", "error");
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
const initialManagePool = this.ibGib?.data?.challengePools?.find(p => p.id === POOL_ID_MANAGE);
|
|
1325
|
+
if (!initialManagePool) {
|
|
1326
|
+
this.setChangePasswordStatus("Primary keystone missing active manage challenge pool.", "error");
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
this.showBusy({
|
|
1330
|
+
isBusy: true,
|
|
1331
|
+
title: 'Elevating Identity...',
|
|
1332
|
+
msg: 'Generating cryptographic sovereign challenge pool...',
|
|
1333
|
+
animationEmoji: '🔑'
|
|
1334
|
+
});
|
|
1335
|
+
this.setChangePasswordStatus("Generating sovereign challenge pool...", "info");
|
|
1336
|
+
const newChallenges = await generatePoolChallenges({
|
|
1337
|
+
config: initialManagePool.config,
|
|
1338
|
+
masterSecret: newPassword,
|
|
1339
|
+
});
|
|
1340
|
+
const newManagePool = {
|
|
1341
|
+
id: POOL_ID_MANAGE,
|
|
1342
|
+
config: initialManagePool.config,
|
|
1343
|
+
challenges: newChallenges,
|
|
1344
|
+
};
|
|
1345
|
+
const primaryTjpAddr = getTjpAddr({ ibGib: this.ibGib }) || getIbGibAddr({ ibGib: this.ibGib });
|
|
1346
|
+
const custodianProvider = this.aggregatedDetails?.custodianProvider || 'google';
|
|
1347
|
+
let requestBody = {
|
|
1348
|
+
primaryTjpAddr,
|
|
1349
|
+
newManagePool,
|
|
1350
|
+
};
|
|
1351
|
+
if (custodianProvider === 'google' || custodianProvider === 'github') {
|
|
1352
|
+
this.showBusy({
|
|
1353
|
+
isBusy: true,
|
|
1354
|
+
title: 'Re-authenticating with Provider...',
|
|
1355
|
+
msg: `Please complete authentication in the ${custodianProvider} popup window...`,
|
|
1356
|
+
animationEmoji: '🔒'
|
|
1357
|
+
});
|
|
1358
|
+
this.setChangePasswordStatus(`Please authenticate in the popup with ${custodianProvider} to verify ownership...`, "info");
|
|
1359
|
+
const resPopup = await executeSsoOAuthPopup({
|
|
1360
|
+
providerId: custodianProvider,
|
|
1361
|
+
parentTjpAddr: primaryTjpAddr,
|
|
1362
|
+
});
|
|
1363
|
+
if (!resPopup.success || !resPopup.code) {
|
|
1364
|
+
this.showBusy({ isBusy: false });
|
|
1365
|
+
this.setChangePasswordStatus(resPopup.message || "Re-authentication cancelled.", "error");
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
requestBody.providerId = custodianProvider;
|
|
1369
|
+
requestBody.code = resPopup.code;
|
|
1370
|
+
requestBody.redirectUri = resPopup.redirectUri;
|
|
1371
|
+
}
|
|
1372
|
+
else {
|
|
1373
|
+
this.showBusy({ isBusy: false });
|
|
1374
|
+
// Email OTP fallback
|
|
1375
|
+
const email = this.aggregatedDetails?.emails?.[0] || this.ibGib?.data?.emails?.[0];
|
|
1376
|
+
const otpCode = await promptForSecret({
|
|
1377
|
+
msg: `Enter 6-digit verification code sent to ${email}:`,
|
|
1378
|
+
confirm: false,
|
|
1379
|
+
});
|
|
1380
|
+
if (!otpCode) {
|
|
1381
|
+
this.setChangePasswordStatus("Verification code required.", "error");
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
requestBody.email = email;
|
|
1385
|
+
requestBody.code = otpCode;
|
|
1386
|
+
}
|
|
1387
|
+
this.showBusy({
|
|
1388
|
+
isBusy: true,
|
|
1389
|
+
title: 'Updating Keystone Timeline...',
|
|
1390
|
+
msg: 'Publishing sovereign master password and evolving identity DAG...',
|
|
1391
|
+
animationEmoji: '⏳'
|
|
1392
|
+
});
|
|
1393
|
+
this.setChangePasswordStatus("Elevating identity to sovereign master password on server...", "info");
|
|
1394
|
+
const response = await fetch('/api/identity/custodian/add-master-password', {
|
|
1395
|
+
method: 'POST',
|
|
1396
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1397
|
+
body: JSON.stringify(requestBody),
|
|
1398
|
+
});
|
|
1399
|
+
const resJson = await response.json();
|
|
1400
|
+
if (!response.ok || !resJson.success) {
|
|
1401
|
+
throw new Error(resJson.error || resJson.message || `Server error (${response.status})`);
|
|
1402
|
+
}
|
|
1403
|
+
const evolvedParent = resJson.primaryKeystone;
|
|
1404
|
+
// Save to local user space & metaspace
|
|
1405
|
+
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
1406
|
+
if (!metaspace) {
|
|
1407
|
+
throw new Error("Global metaspace not available");
|
|
1408
|
+
}
|
|
1409
|
+
const space = await metaspace.getLocalUserSpace({ lock: false });
|
|
1410
|
+
if (!space) {
|
|
1411
|
+
throw new Error("Local user space not available");
|
|
1412
|
+
}
|
|
1413
|
+
await metaspace.put({ ibGibs: [evolvedParent], space });
|
|
1414
|
+
await metaspace.registerNewIbGib({ ibGib: evolvedParent, space });
|
|
1415
|
+
await updateSpecialIndex({
|
|
1416
|
+
type: "keystones",
|
|
1417
|
+
rel8nInfos: [
|
|
1418
|
+
{
|
|
1419
|
+
rel8nName: "keystone",
|
|
1420
|
+
ibGibs: [toDto({ ibGib: evolvedParent })]
|
|
1421
|
+
}
|
|
1422
|
+
],
|
|
1423
|
+
metaspace,
|
|
1424
|
+
space
|
|
1425
|
+
});
|
|
1426
|
+
const evolvedAddr = getIbGibAddr({ ibGib: evolvedParent });
|
|
1427
|
+
// Dispatch EVENT_IBGIB_IDENTITY_CHANGED
|
|
1428
|
+
window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_CHANGED, {
|
|
1429
|
+
detail: { activeIdentityAddr: evolvedAddr },
|
|
1430
|
+
bubbles: true,
|
|
1431
|
+
composed: true
|
|
1432
|
+
}));
|
|
1433
|
+
this.setChangePasswordStatus("Successfully added Master Password! Identity is now sovereign.", "success");
|
|
1434
|
+
// Refresh the view
|
|
1435
|
+
this.ibGibAddr = evolvedAddr;
|
|
1436
|
+
this.staticIbGib = evolvedParent;
|
|
1437
|
+
await this.loadIbGib({ getLatest: true });
|
|
1438
|
+
// Clear inputs
|
|
1439
|
+
this.elements.inputNewPasswordEl.value = '';
|
|
1440
|
+
this.elements.inputConfirmPasswordEl.value = '';
|
|
1441
|
+
}
|
|
1442
|
+
catch (error) {
|
|
1443
|
+
console.error(`${lc} Elevation failed: ${extractErrorMsg(error)}`);
|
|
1444
|
+
this.setChangePasswordStatus(`Failed to add master password: ${extractErrorMsg(error)}`, "error");
|
|
1445
|
+
}
|
|
1446
|
+
finally {
|
|
1447
|
+
this.showBusy({ isBusy: false });
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
async handleChangePassword() {
|
|
1451
|
+
const lc = `${this.lc}[${this.handleChangePassword.name}]`;
|
|
1452
|
+
const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
|
|
1453
|
+
const isCustodialOnly = caps.isCustodial && !caps.isSovereign;
|
|
1454
|
+
if (isCustodialOnly) {
|
|
1455
|
+
await this.handleAddMasterPassword();
|
|
1456
|
+
return;
|
|
1457
|
+
}
|
|
1458
|
+
this.setChangePasswordStatus("Validating entries...", "info");
|
|
1198
1459
|
try {
|
|
1199
|
-
const
|
|
1200
|
-
const
|
|
1201
|
-
const
|
|
1202
|
-
if (!
|
|
1203
|
-
this.
|
|
1460
|
+
const currentPassword = this.elements.inputCurrentPasswordEl.value;
|
|
1461
|
+
const newPassword = this.elements.inputNewPasswordEl.value;
|
|
1462
|
+
const confirmPassword = this.elements.inputConfirmPasswordEl.value;
|
|
1463
|
+
if (!currentPassword) {
|
|
1464
|
+
this.setChangePasswordStatus("Current password is required.", "error");
|
|
1204
1465
|
return;
|
|
1205
1466
|
}
|
|
1206
|
-
if (!
|
|
1207
|
-
this.
|
|
1467
|
+
if (!newPassword) {
|
|
1468
|
+
this.setChangePasswordStatus("New password is required.", "error");
|
|
1208
1469
|
return;
|
|
1209
1470
|
}
|
|
1210
|
-
if (
|
|
1211
|
-
this.
|
|
1471
|
+
if (newPassword !== confirmPassword) {
|
|
1472
|
+
this.setChangePasswordStatus("New password and confirmation do not match.", "error");
|
|
1212
1473
|
return;
|
|
1213
1474
|
}
|
|
1214
1475
|
const keystoneService = new KeystoneService_V1();
|
|
1215
|
-
// 1. Verify current
|
|
1476
|
+
// 1. Verify current password against parent manage pool
|
|
1216
1477
|
const isMatch = await keystoneService.verifySigningSecret({
|
|
1217
1478
|
keystoneIbGib: this.ibGib,
|
|
1218
|
-
signingSecret:
|
|
1479
|
+
signingSecret: currentPassword,
|
|
1219
1480
|
poolId: 'manage'
|
|
1220
1481
|
});
|
|
1221
1482
|
if (!isMatch) {
|
|
1222
|
-
this.
|
|
1483
|
+
this.setChangePasswordStatus("Incorrect current password.", "error");
|
|
1223
1484
|
return;
|
|
1224
1485
|
}
|
|
1225
|
-
this.
|
|
1486
|
+
this.setChangePasswordStatus("Evolving primary identity keystone...", "info");
|
|
1226
1487
|
const metaspace = await getGlobalMetaspace_waitIfNeeded();
|
|
1227
1488
|
if (!metaspace) {
|
|
1228
1489
|
throw new Error(`(UNEXPECTED) metaspace falsy? (E: 95e3c8374b0f088f339f5c5a8700f826)`);
|
|
@@ -1235,14 +1496,14 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1235
1496
|
debugger; // walk through this...looking for delegate failure // hmm...I thought we got change password going?
|
|
1236
1497
|
const { newKeystone: evolvedParent, newDelegates: evolvedDelegates } = await keystoneService.changePassword({
|
|
1237
1498
|
keystoneIbGib: this.ibGib,
|
|
1238
|
-
newMasterSecret:
|
|
1239
|
-
signingSecret:
|
|
1499
|
+
newMasterSecret: newPassword,
|
|
1500
|
+
signingSecret: currentPassword,
|
|
1240
1501
|
signingPoolId: 'manage',
|
|
1241
1502
|
metaspace,
|
|
1242
1503
|
space
|
|
1243
1504
|
});
|
|
1244
1505
|
debugger; // look at evolvedDelegates
|
|
1245
|
-
this.
|
|
1506
|
+
this.setChangePasswordStatus("Resolving and rotating delegate keystones...", "info");
|
|
1246
1507
|
// // 3. Evolve registered delegate keystones (preserving custodian/foreign delegate secrets)
|
|
1247
1508
|
// const delegates = this.ibGib!.data?.delegates || {};
|
|
1248
1509
|
// const evolvedDelegates: KeystoneIbGib_V1[] = [];
|
|
@@ -1253,7 +1514,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1253
1514
|
// metaspace,
|
|
1254
1515
|
// space,
|
|
1255
1516
|
// });
|
|
1256
|
-
// // Identify user-owned challenge pools in the delegate that match the old
|
|
1517
|
+
// // Identify user-owned challenge pools in the delegate that match the old password
|
|
1257
1518
|
// const poolsToRotate: string[] = [];
|
|
1258
1519
|
// for (const pool of delegateKeystone.data?.challengePools ?? []) {
|
|
1259
1520
|
// if (!pool.isForeign) {
|
|
@@ -1268,7 +1529,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1268
1529
|
// */
|
|
1269
1530
|
// const isPoolMatch = await keystoneService.verifySigningSecret({
|
|
1270
1531
|
// keystoneIbGib: delegateKeystone,
|
|
1271
|
-
// signingSecret:
|
|
1532
|
+
// signingSecret: currentPassword,
|
|
1272
1533
|
// poolId: pool.id
|
|
1273
1534
|
// });
|
|
1274
1535
|
// if (isPoolMatch) { poolsToRotate.push(pool.id); }
|
|
@@ -1278,8 +1539,8 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1278
1539
|
// console.log(`${lc} Rotating pools in delegate ${delegateInfo.delegateTjpAddr}: ${poolsToRotate.join(', ')}`);
|
|
1279
1540
|
// const {newKeystone: evolvedDelegate} = await keystoneService.changePassword({
|
|
1280
1541
|
// keystoneIbGib: delegateKeystone,
|
|
1281
|
-
// newMasterSecret:
|
|
1282
|
-
// signingSecret:
|
|
1542
|
+
// newMasterSecret: newPassword,
|
|
1543
|
+
// signingSecret: currentPassword,
|
|
1283
1544
|
// signingPoolId: 'manage',
|
|
1284
1545
|
// poolIds: poolsToRotate,
|
|
1285
1546
|
// metaspace,
|
|
@@ -1289,7 +1550,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1289
1550
|
// }
|
|
1290
1551
|
// }
|
|
1291
1552
|
// 4. Sync evolved parent and all evolved delegate keystones atomically
|
|
1292
|
-
this.
|
|
1553
|
+
this.setChangePasswordStatus("Syncing evolved keystones to server...", "info");
|
|
1293
1554
|
const parentTjpAddr = getIbGibAddr({ ibGib: this.ibGib }); // is this.ibGib the tjp always? or is it the latest in the keystone line? Does it matter?
|
|
1294
1555
|
const syncRes = await getApiBridge().putEvolveKeystone({
|
|
1295
1556
|
domainAddr: parentTjpAddr,
|
|
@@ -1300,7 +1561,7 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1300
1561
|
throw new Error(`Server synchronization rejected: ${syncRes.message}`);
|
|
1301
1562
|
}
|
|
1302
1563
|
// 5. Update index locally
|
|
1303
|
-
this.
|
|
1564
|
+
this.setChangePasswordStatus("Updating local indexes...", "info");
|
|
1304
1565
|
const newKeystoneIbGibs = [toDto({ ibGib: evolvedParent })];
|
|
1305
1566
|
if (evolvedDelegates) {
|
|
1306
1567
|
evolvedDelegates.forEach(d => {
|
|
@@ -1320,15 +1581,15 @@ export class KeystoneDetailsComponentInstance extends IbGibDynamicComponentInsta
|
|
|
1320
1581
|
space
|
|
1321
1582
|
});
|
|
1322
1583
|
// Clear inputs
|
|
1323
|
-
this.elements.
|
|
1324
|
-
this.elements.
|
|
1325
|
-
this.elements.
|
|
1326
|
-
this.
|
|
1584
|
+
this.elements.inputCurrentPasswordEl.value = "";
|
|
1585
|
+
this.elements.inputNewPasswordEl.value = "";
|
|
1586
|
+
this.elements.inputConfirmPasswordEl.value = "";
|
|
1587
|
+
this.setChangePasswordStatus("Password updated successfully!", "success");
|
|
1327
1588
|
await this.loadIbGib({ getLatest: true });
|
|
1328
1589
|
}
|
|
1329
1590
|
catch (error) {
|
|
1330
|
-
console.error(`${lc}
|
|
1331
|
-
this.
|
|
1591
|
+
console.error(`${lc} Password rotation failed: ${extractErrorMsg(error)}`);
|
|
1592
|
+
this.setChangePasswordStatus(`Update failed: ${extractErrorMsg(error)}`, "error");
|
|
1332
1593
|
}
|
|
1333
1594
|
}
|
|
1334
1595
|
}
|