@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.
Files changed (92) hide show
  1. package/dist/AUTO-GENERATED-version.d.mts +1 -1
  2. package/dist/AUTO-GENERATED-version.mjs +1 -1
  3. package/dist/helpers.d.mts.map +1 -1
  4. package/dist/helpers.mjs +1 -0
  5. package/dist/helpers.mjs.map +1 -1
  6. package/dist/identity/device-delegate-helper.d.mts +43 -0
  7. package/dist/identity/device-delegate-helper.d.mts.map +1 -0
  8. package/dist/identity/device-delegate-helper.mjs +106 -0
  9. package/dist/identity/device-delegate-helper.mjs.map +1 -0
  10. package/dist/identity/device-delegate.respec.d.mts +2 -0
  11. package/dist/identity/device-delegate.respec.d.mts.map +1 -0
  12. package/dist/identity/device-delegate.respec.mjs +106 -0
  13. package/dist/identity/device-delegate.respec.mjs.map +1 -0
  14. package/dist/identity/identity-constants.mjs +2 -2
  15. package/dist/identity/identity-constants.mjs.map +1 -1
  16. package/dist/identity/identity-types.d.mts +4 -4
  17. package/dist/identity/identity-types.d.mts.map +1 -1
  18. package/dist/identity/keystone-sync-service.d.mts +18 -0
  19. package/dist/identity/keystone-sync-service.d.mts.map +1 -1
  20. package/dist/identity/keystone-sync-service.mjs +77 -1
  21. package/dist/identity/keystone-sync-service.mjs.map +1 -1
  22. package/dist/index.d.mts +1 -1
  23. package/dist/index.d.mts.map +1 -1
  24. package/dist/index.mjs +1 -2
  25. package/dist/index.mjs.map +1 -1
  26. package/dist/storage/storage-helpers.web.d.mts +9 -0
  27. package/dist/storage/storage-helpers.web.d.mts.map +1 -1
  28. package/dist/storage/storage-helpers.web.mjs +42 -0
  29. package/dist/storage/storage-helpers.web.mjs.map +1 -1
  30. package/dist/ui/component/identity/add-device/add-device.css +93 -17
  31. package/dist/ui/component/identity/add-device/add-device.d.mts +24 -7
  32. package/dist/ui/component/identity/add-device/add-device.d.mts.map +1 -1
  33. package/dist/ui/component/identity/add-device/add-device.html +97 -23
  34. package/dist/ui/component/identity/add-device/add-device.mjs +489 -198
  35. package/dist/ui/component/identity/add-device/add-device.mjs.map +1 -1
  36. package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts.map +1 -1
  37. package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs +48 -61
  38. package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs.map +1 -1
  39. package/dist/ui/component/identity/keystone-details/keystone-details.css +1 -1
  40. package/dist/ui/component/identity/keystone-details/keystone-details.d.mts +11 -8
  41. package/dist/ui/component/identity/keystone-details/keystone-details.d.mts.map +1 -1
  42. package/dist/ui/component/identity/keystone-details/keystone-details.html +29 -20
  43. package/dist/ui/component/identity/keystone-details/keystone-details.mjs +358 -97
  44. package/dist/ui/component/identity/keystone-details/keystone-details.mjs.map +1 -1
  45. package/dist/ui/component/identity/remove-device/remove-device.d.mts +1 -1
  46. package/dist/ui/component/identity/remove-device/remove-device.d.mts.map +1 -1
  47. package/dist/ui/component/identity/remove-device/remove-device.html +3 -3
  48. package/dist/ui/component/identity/remove-device/remove-device.mjs +7 -7
  49. package/dist/ui/component/identity/remove-device/remove-device.mjs.map +1 -1
  50. package/dist/ui/ui-constants.d.mts +1 -0
  51. package/dist/ui/ui-constants.d.mts.map +1 -1
  52. package/dist/ui/ui-constants.mjs +1 -0
  53. package/dist/ui/ui-constants.mjs.map +1 -1
  54. package/dist/ui/ui-types.d.mts +5 -0
  55. package/dist/ui/ui-types.d.mts.map +1 -1
  56. package/dist/util/device-helper.d.mts +30 -0
  57. package/dist/util/device-helper.d.mts.map +1 -0
  58. package/dist/util/device-helper.mjs +90 -0
  59. package/dist/util/device-helper.mjs.map +1 -0
  60. package/dist/util/device-helper.respec.d.mts +2 -0
  61. package/dist/util/device-helper.respec.d.mts.map +1 -0
  62. package/dist/util/device-helper.respec.mjs +83 -0
  63. package/dist/util/device-helper.respec.mjs.map +1 -0
  64. package/package.json +3 -3
  65. package/src/AUTO-GENERATED-version.mts +1 -1
  66. package/src/helpers.mts +1 -0
  67. package/src/identity/custodian-delegate-helper.mts.bak +7 -0
  68. package/src/identity/device-delegate-helper.mts +135 -0
  69. package/src/identity/device-delegate.respec.mts +125 -0
  70. package/src/identity/identity-constants.mts +2 -2
  71. package/src/identity/identity-types.mts +4 -4
  72. package/src/identity/keystone-sync-service.mts +95 -2
  73. package/src/index.mts +1 -2
  74. package/src/storage/storage-helpers.web.mts +47 -0
  75. package/src/ui/component/identity/add-device/add-device.css +93 -17
  76. package/src/ui/component/identity/add-device/add-device.html +97 -23
  77. package/src/ui/component/identity/add-device/add-device.mts +579 -208
  78. package/src/ui/component/identity/keystone-creator/keystone-creator.mts +55 -69
  79. package/src/ui/component/identity/keystone-details/keystone-details.css +1 -1
  80. package/src/ui/component/identity/keystone-details/keystone-details.html +29 -20
  81. package/src/ui/component/identity/keystone-details/keystone-details.mts +374 -106
  82. package/src/ui/component/identity/remove-device/remove-device.html +3 -3
  83. package/src/ui/component/identity/remove-device/remove-device.mts +8 -8
  84. package/src/ui/ui-constants.mts +1 -0
  85. package/src/ui/ui-types.mts +6 -0
  86. package/src/util/device-helper.mts +104 -0
  87. package/src/util/device-helper.respec.mts +90 -0
  88. package/dist/identity/custodian-delegate-helper.d.mts +0 -22
  89. package/dist/identity/custodian-delegate-helper.d.mts.map +0 -1
  90. package/dist/identity/custodian-delegate-helper.mjs +0 -50
  91. package/dist/identity/custodian-delegate-helper.mjs.map +0 -1
  92. 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 "../../../../identity/sso/sso-helpers.mjs";
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.inputCurrentPassphraseEl = shadow.getElementById('input-current-passphrase');
149
- this.elements.inputNewPassphraseEl = shadow.getElementById('input-new-passphrase');
150
- this.elements.inputConfirmPassphraseEl = shadow.getElementById('input-confirm-passphrase');
151
- this.elements.btnChangePassphraseEl = shadow.getElementById('btn-change-passphrase');
152
- this.elements.changePassphraseStatusEl = shadow.getElementById('change-passphrase-status');
153
- this.elements.changePassphraseCardEl = shadow.getElementById('change-passphrase-card');
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.btnChangePassphraseEl.addEventListener('click', () => this.handleChangePassphrase());
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 already linked
398
- const isGoogleLinked = isSsoProviderLinked({ keystone: this.ibGib, providerId: 'google' });
399
- const isGithubLinked = isSsoProviderLinked({ keystone: this.ibGib, providerId: 'github' });
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
- googleLabel.textContent = "Google Linked ✅";
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
- githubLabel.textContent = "GitHub Linked ✅";
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 Passphrase Change cards (only if this is a primary keystone, hide them for delegate/session keystones)
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.changePassphraseCardEl.classList.remove('hidden');
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.changePassphraseCardEl.classList.add('hidden');
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
- let localSpaceId;
734
- if (metaspace) {
735
- const space = await metaspace.getLocalUserSpace({ lock: false });
736
- if (space?.ib) {
737
- localSpaceId = parseSpaceIb({ spaceIb: space.ib }).spaceId;
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
- let badgeEl = null;
746
- if (delegateSpaceId) {
747
- badgeEl = document.createElement('span');
748
- badgeEl.style.marginLeft = '0.5rem';
749
- badgeEl.style.padding = '0.15rem 0.4rem';
750
- badgeEl.style.borderRadius = '4px';
751
- badgeEl.style.fontSize = '0.75rem';
752
- badgeEl.style.fontWeight = 'bold';
753
- if (localSpaceId && delegateSpaceId === localSpaceId) {
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
- else {
760
- badgeEl.textContent = 'Remote Device';
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 = !!(delegateSpaceId && localSpaceId && delegateSpaceId !== localSpaceId);
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
- if (metaspace) {
798
- const space = await metaspace.getLocalUserSpace({ lock: false });
799
- if (space) {
800
- try {
801
- const latest = await metaspace.getLatestAddr({ addr: delegateTjpAddr, space });
802
- if (latest) {
803
- addrToLoad = latest;
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 Passphrase to revoke delegate '${deviceName}':`,
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 (Passphrase) to sign and register the custodian pool"
1015
- : `Incorrect passphrase. Please try again (${maxTries - tries} tries remaining):`;
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 passphrase).", "error");
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 passphrase
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 (Passphrase) to authorize. Otherwise, click Cancel.`
1115
- : `Incorrect passphrase. Please try again (${maxTries - tries} tries remaining):`;
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 passphrase).", "error");
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
- const evolvedParent = await keystoneService.removePools({
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
- setChangePassphraseStatus(msg, type) {
1190
- const el = this.elements.changePassphraseStatusEl;
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 handleChangePassphrase() {
1196
- const lc = `${this.lc}[${this.handleChangePassphrase.name}]`;
1197
- this.setChangePassphraseStatus("Validating entries...", "info");
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 currentPassphrase = this.elements.inputCurrentPassphraseEl.value;
1200
- const newPassphrase = this.elements.inputNewPassphraseEl.value;
1201
- const confirmPassphrase = this.elements.inputConfirmPassphraseEl.value;
1202
- if (!currentPassphrase) {
1203
- this.setChangePassphraseStatus("Current passphrase is required.", "error");
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 (!newPassphrase) {
1207
- this.setChangePassphraseStatus("New passphrase is required.", "error");
1467
+ if (!newPassword) {
1468
+ this.setChangePasswordStatus("New password is required.", "error");
1208
1469
  return;
1209
1470
  }
1210
- if (newPassphrase !== confirmPassphrase) {
1211
- this.setChangePassphraseStatus("New passphrase and confirmation do not match.", "error");
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 passphrase against parent manage pool
1476
+ // 1. Verify current password against parent manage pool
1216
1477
  const isMatch = await keystoneService.verifySigningSecret({
1217
1478
  keystoneIbGib: this.ibGib,
1218
- signingSecret: currentPassphrase,
1479
+ signingSecret: currentPassword,
1219
1480
  poolId: 'manage'
1220
1481
  });
1221
1482
  if (!isMatch) {
1222
- this.setChangePassphraseStatus("Incorrect current passphrase.", "error");
1483
+ this.setChangePasswordStatus("Incorrect current password.", "error");
1223
1484
  return;
1224
1485
  }
1225
- this.setChangePassphraseStatus("Evolving primary identity keystone...", "info");
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: newPassphrase,
1239
- signingSecret: currentPassphrase,
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.setChangePassphraseStatus("Resolving and rotating delegate keystones...", "info");
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 passphrase
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: currentPassphrase,
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: newPassphrase,
1282
- // signingSecret: currentPassphrase,
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.setChangePassphraseStatus("Syncing evolved keystones to server...", "info");
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.setChangePassphraseStatus("Updating local indexes...", "info");
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.inputCurrentPassphraseEl.value = "";
1324
- this.elements.inputNewPassphraseEl.value = "";
1325
- this.elements.inputConfirmPassphraseEl.value = "";
1326
- this.setChangePassphraseStatus("Passphrase updated successfully!", "success");
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} Passphrase rotation failed: ${extractErrorMsg(error)}`);
1331
- this.setChangePassphraseStatus(`Update failed: ${extractErrorMsg(error)}`, "error");
1591
+ console.error(`${lc} Password rotation failed: ${extractErrorMsg(error)}`);
1592
+ this.setChangePasswordStatus(`Update failed: ${extractErrorMsg(error)}`, "error");
1332
1593
  }
1333
1594
  }
1334
1595
  }