@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
@@ -23,10 +23,11 @@ import { updateSpecialIndex } from "@ibgib/core-gib/dist/timeline/timeline-api.m
23
23
  import { getTjpAddr, toDto } from "@ibgib/core-gib/dist/common/other/ibgib-helper.mjs";
24
24
  import { parseSpaceIb } from "@ibgib/core-gib/dist/witness/space/space-helper.mjs";
25
25
  import { executeSsoOAuthPopup } from "../../../../identity/sso-popup-helper.mjs";
26
-
27
26
  import { getComponentCtorArg } from "../../../../app-bootstrap/init-orchestration.mjs";
28
27
  import { promptForSecret } from "../../../../helpers.web.mjs";
29
- import { isSsoProviderLinked } from "../../../../identity/sso/sso-helpers.mjs";
28
+ import { isSsoProviderLinked, getKeystoneCapabilities, isDelegateExpired } from "@ibgib/core-gib/dist/keystone/delegate/delegate-helpers.mjs";
29
+ import { generatePoolChallenges } from "@ibgib/core-gib/dist/keystone/keystone-helpers.mjs";
30
+ import { POOL_ID_MANAGE } from "@ibgib/core-gib/dist/keystone/keystone-constants.mjs";
30
31
  import { getGlobalMetaspace_waitIfNeeded } from "../../../../helpers.mjs";
31
32
 
32
33
  const logalot = false;
@@ -94,12 +95,12 @@ interface KeystoneDetailsElements extends ElementsBase {
94
95
  btnLinkGoogleEl: HTMLDivElement;
95
96
  btnLinkGithubEl: HTMLDivElement;
96
97
  ssoStatusMsgEl: HTMLDivElement;
97
- inputCurrentPassphraseEl: HTMLInputElement;
98
- inputNewPassphraseEl: HTMLInputElement;
99
- inputConfirmPassphraseEl: HTMLInputElement;
100
- btnChangePassphraseEl: HTMLButtonElement;
101
- changePassphraseStatusEl: HTMLDivElement;
102
- changePassphraseCardEl: HTMLDivElement;
98
+ inputCurrentPasswordEl: HTMLInputElement;
99
+ inputNewPasswordEl: HTMLInputElement;
100
+ inputConfirmPasswordEl: HTMLInputElement;
101
+ btnChangePasswordEl: HTMLButtonElement;
102
+ changePasswordStatusEl: HTMLDivElement;
103
+ changePasswordCardEl: HTMLDivElement;
103
104
  }
104
105
 
105
106
  export class KeystoneDetailsComponentInstance
@@ -118,6 +119,7 @@ export class KeystoneDetailsComponentInstance
118
119
  private isHistoricalFrame: boolean = false;
119
120
  private _onIdentityChanged: ((e: any) => void) | null = null;
120
121
  private keystoneCache: Map<string, { username: string, description: string, isPrimary: boolean, n: number }> = new Map();
122
+ private aggregatedDetails?: any;
121
123
 
122
124
  constructor() {
123
125
  super();
@@ -212,12 +214,12 @@ export class KeystoneDetailsComponentInstance
212
214
  this.elements.btnLinkGoogleEl = shadow.getElementById('btn-link-google') as HTMLDivElement;
213
215
  this.elements.btnLinkGithubEl = shadow.getElementById('btn-link-github') as HTMLDivElement;
214
216
  this.elements.ssoStatusMsgEl = shadow.getElementById('sso-status-msg') as HTMLDivElement;
215
- this.elements.inputCurrentPassphraseEl = shadow.getElementById('input-current-passphrase') as HTMLInputElement;
216
- this.elements.inputNewPassphraseEl = shadow.getElementById('input-new-passphrase') as HTMLInputElement;
217
- this.elements.inputConfirmPassphraseEl = shadow.getElementById('input-confirm-passphrase') as HTMLInputElement;
218
- this.elements.btnChangePassphraseEl = shadow.getElementById('btn-change-passphrase') as HTMLButtonElement;
219
- this.elements.changePassphraseStatusEl = shadow.getElementById('change-passphrase-status') as HTMLDivElement;
220
- this.elements.changePassphraseCardEl = shadow.getElementById('change-passphrase-card') as HTMLDivElement;
217
+ this.elements.inputCurrentPasswordEl = shadow.getElementById('input-current-password') as HTMLInputElement;
218
+ this.elements.inputNewPasswordEl = shadow.getElementById('input-new-password') as HTMLInputElement;
219
+ this.elements.inputConfirmPasswordEl = shadow.getElementById('input-confirm-password') as HTMLInputElement;
220
+ this.elements.btnChangePasswordEl = shadow.getElementById('btn-change-password') as HTMLButtonElement;
221
+ this.elements.changePasswordStatusEl = shadow.getElementById('change-password-status') as HTMLDivElement;
222
+ this.elements.changePasswordCardEl = shadow.getElementById('change-password-card') as HTMLDivElement;
221
223
 
222
224
  // ElementBase requires contentEl
223
225
  this.elements.contentEl = shadow.getElementById('identity-details-view') as HTMLDivElement;
@@ -260,7 +262,7 @@ export class KeystoneDetailsComponentInstance
260
262
  this.elements!.btnUpdateIdentityEl.addEventListener('click', () => this.handleUpdateIdentity());
261
263
  this.elements!.btnLinkGoogleEl.addEventListener('click', () => this.handleSSOClick('google'));
262
264
  this.elements!.btnLinkGithubEl.addEventListener('click', () => this.handleSSOClick('github'));
263
- this.elements!.btnChangePassphraseEl.addEventListener('click', () => this.handleChangePassphrase());
265
+ this.elements!.btnChangePasswordEl.addEventListener('click', () => this.handleChangePassword());
264
266
  }
265
267
 
266
268
  private toggleAccordion() {
@@ -454,9 +456,12 @@ export class KeystoneDetailsComponentInstance
454
456
  this.elements.btnLinkGoogleEl.classList.remove('disabled');
455
457
  this.elements.btnLinkGithubEl.classList.remove('disabled');
456
458
 
457
- // Check if already linked
458
- const isGoogleLinked = isSsoProviderLinked({ keystone: this.ibGib, providerId: 'google' });
459
- const isGithubLinked = isSsoProviderLinked({ keystone: this.ibGib, providerId: 'github' });
459
+ // Check if origin provider or linked
460
+ const originProvider = this.aggregatedDetails?.custodianProvider || this.ibGib?.data?.frameDetails?.custodianProvider;
461
+ const isGoogleLinked = isSsoProviderLinked({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails, providerId: 'google' });
462
+ const isGithubLinked = isSsoProviderLinked({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails, providerId: 'github' });
463
+
464
+ const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
460
465
 
461
466
  // Google Card States
462
467
  const googleCard = this.elements.btnLinkGoogleEl;
@@ -464,11 +469,22 @@ export class KeystoneDetailsComponentInstance
464
469
  if (isGoogleLinked) {
465
470
  googleCard.classList.remove('unlinked');
466
471
  googleCard.classList.add('linked');
467
- googleLabel.textContent = "Google Linked ✅";
472
+ const isOrigin = originProvider === 'google';
473
+ if (isOrigin && !caps.isSovereign) {
474
+ googleLabel.textContent = "Google (Primary Account) 🔒";
475
+ googleCard.title = "Cannot unlink primary account without first adding a Master Password below.";
476
+ } else if (isOrigin) {
477
+ googleLabel.textContent = "Google (Primary Account) ✅";
478
+ googleCard.title = "Click to unlink Google provider (requires Master Password).";
479
+ } else {
480
+ googleLabel.textContent = "Google Linked ✅";
481
+ googleCard.title = "Click to unlink Google provider.";
482
+ }
468
483
  } else {
469
484
  googleCard.classList.remove('linked');
470
485
  googleCard.classList.add('unlinked');
471
486
  googleLabel.textContent = "Unlinked";
487
+ googleCard.title = "Click to link Google account.";
472
488
  }
473
489
 
474
490
  // GitHub Card States
@@ -477,15 +493,47 @@ export class KeystoneDetailsComponentInstance
477
493
  if (isGithubLinked) {
478
494
  githubCard.classList.remove('unlinked');
479
495
  githubCard.classList.add('linked');
480
- githubLabel.textContent = "GitHub Linked ✅";
496
+ const isOrigin = originProvider === 'github';
497
+ if (isOrigin && !caps.isSovereign) {
498
+ githubLabel.textContent = "GitHub (Primary Account) 🔒";
499
+ githubCard.title = "Cannot unlink primary account without first adding a Master Password below.";
500
+ } else if (isOrigin) {
501
+ githubLabel.textContent = "GitHub (Primary Account) ✅";
502
+ githubCard.title = "Click to unlink GitHub provider (requires Master Password).";
503
+ } else {
504
+ githubLabel.textContent = "GitHub Linked ✅";
505
+ githubCard.title = "Click to unlink GitHub provider.";
506
+ }
481
507
  } else {
482
508
  githubCard.classList.remove('linked');
483
509
  githubCard.classList.add('unlinked');
484
510
  githubLabel.textContent = "Unlinked";
511
+ githubCard.title = "Click to link GitHub account.";
485
512
  }
486
513
  }
487
514
  }
488
515
 
516
+ private updatePasswordCardView(): void {
517
+ const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
518
+ const cardTitleEl = this.elements?.changePasswordCardEl?.querySelector('h3');
519
+ const cardDescEl = this.elements?.changePasswordCardEl?.querySelector('.description');
520
+ const currentPasswordGroup = this.elements?.inputCurrentPasswordEl?.closest('.form-group') as HTMLElement | null;
521
+ const btnChangePassword = this.elements?.btnChangePasswordEl;
522
+
523
+ const isCustodialOnly = caps.isCustodial && !caps.isSovereign;
524
+ if (isCustodialOnly) {
525
+ if (cardTitleEl) cardTitleEl.textContent = "Add Master Password";
526
+ if (cardDescEl) cardDescEl.textContent = "Establish sovereign ownership by adding a master password. This enables direct, independent cryptographic management without relying solely on custodian authentication.";
527
+ if (currentPasswordGroup) currentPasswordGroup.style.display = 'none';
528
+ if (btnChangePassword) btnChangePassword.textContent = "Add Master Password";
529
+ } else {
530
+ if (cardTitleEl) cardTitleEl.textContent = "Change Password";
531
+ if (cardDescEl) 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.";
532
+ if (currentPasswordGroup) currentPasswordGroup.style.display = '';
533
+ if (btnChangePassword) btnChangePassword.textContent = "Update Password";
534
+ }
535
+ }
536
+
489
537
  private async updateFrameDetailsView(): Promise<void> {
490
538
  const lc = `${this.lc}[${this.updateFrameDetailsView.name}]`;
491
539
  try {
@@ -549,6 +597,7 @@ export class KeystoneDetailsComponentInstance
549
597
  space
550
598
  });
551
599
 
600
+ this.aggregatedDetails = aggregated;
552
601
  this.elements.identityAggrDetailsEl.textContent = aggregated ? pretty(aggregated) : '{}';
553
602
 
554
603
  // Update Username and Description fields
@@ -556,16 +605,19 @@ export class KeystoneDetailsComponentInstance
556
605
  this.elements.identityDescriptionEl.textContent = aggregated?.description || aggregated?.profile?.description || '-';
557
606
  } catch (err) {
558
607
  console.warn(`${lc} Error aggregating details: ${extractErrorMsg(err)}`);
608
+ this.aggregatedDetails = undefined;
559
609
  this.elements.identityAggrDetailsEl.textContent = '{}';
560
610
  this.elements.identityNameEl.textContent = '-';
561
611
  this.elements.identityDescriptionEl.textContent = '-';
562
612
  }
563
613
  } else {
614
+ this.aggregatedDetails = undefined;
564
615
  this.elements.identityAggrDetailsEl.textContent = '{}';
565
616
  this.elements.identityNameEl.textContent = '-';
566
617
  this.elements.identityDescriptionEl.textContent = '-';
567
618
  }
568
619
  } else {
620
+ this.aggregatedDetails = undefined;
569
621
  this.elements.identityAggrDetailsEl.textContent = '{}';
570
622
  this.elements.identityNameEl.textContent = '-';
571
623
  this.elements.identityDescriptionEl.textContent = '-';
@@ -591,17 +643,18 @@ export class KeystoneDetailsComponentInstance
591
643
  // Render Challenge Pools
592
644
  this.renderChallengePools(keystone.data?.challengePools || []);
593
645
 
594
- // Render Delegates, SSO link, and Passphrase Change cards (only if this is a primary keystone, hide them for delegate/session keystones)
646
+ // Render Delegates, SSO link, and Password Change cards (only if this is a primary keystone, hide them for delegate/session keystones)
595
647
  const details = await this.getKeystoneDetails(this.ibGibAddr);
596
648
  if (details.isPrimary) {
597
649
  this.elements.delegatesCardEl.classList.remove('hidden');
598
650
  await this.renderDelegates(keystone.data?.delegates);
599
651
  this.elements.ssoLinkCardEl.classList.remove('hidden');
600
- this.elements.changePassphraseCardEl.classList.remove('hidden');
652
+ this.elements.changePasswordCardEl.classList.remove('hidden');
653
+ this.updatePasswordCardView();
601
654
  } else {
602
655
  this.elements.delegatesCardEl.classList.add('hidden');
603
656
  this.elements.ssoLinkCardEl.classList.add('hidden');
604
- this.elements.changePassphraseCardEl.classList.add('hidden');
657
+ this.elements.changePasswordCardEl.classList.add('hidden');
605
658
  }
606
659
 
607
660
  this.updateActiveButtonState();
@@ -615,6 +668,7 @@ export class KeystoneDetailsComponentInstance
615
668
 
616
669
  private clearActiveDetails() {
617
670
  if (!this.elements) { return; }
671
+ this.aggregatedDetails = undefined;
618
672
  this.isHistoricalFrame = false;
619
673
  if (this.elements.historicalWarningBannerEl) {
620
674
  this.elements.historicalWarningBannerEl.classList.add('hidden');
@@ -804,43 +858,71 @@ export class KeystoneDetailsComponentInstance
804
858
  }
805
859
 
806
860
  const metaspace = await getGlobalMetaspace_waitIfNeeded();
807
- let localSpaceId: string | undefined;
808
- if (metaspace) {
809
- const space = await metaspace.getLocalUserSpace({ lock: false });
810
- if (space?.ib) {
811
- localSpaceId = parseSpaceIb({ spaceIb: space.ib }).spaceId;
812
- }
861
+ if (!metaspace) {
862
+ throw new Error(`(UNEXPECTED) metaspace falsy? (E: 8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3e)`);
863
+ }
864
+ const space = await metaspace.getLocalUserSpace({ lock: false });
865
+ if (!space) {
866
+ throw new Error(`(UNEXPECTED) space falsy? (E: 9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4f)`);
813
867
  }
868
+ const localSpaceId = space.ib ? parseSpaceIb({ spaceIb: space.ib }).spaceId : undefined;
814
869
 
815
870
  for (const [delegateTjpAddr, info] of Object.entries(delegates)) {
816
871
  const tr = document.createElement('tr');
817
872
 
818
- const deviceName = info.deviceName || info.details?.deviceTag || info.details?.name || 'Device Delegate';
873
+ const deviceName = info.deviceName || (info as any).details?.deviceTag || (info as any).details?.name || 'Device Delegate';
819
874
  const tdName = document.createElement('td');
820
875
 
821
- const delegateSpaceId = info.spaceId || info.details?.spaceId;
822
- let badgeEl: HTMLSpanElement | null = null;
823
-
824
- if (delegateSpaceId) {
825
- 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 (localSpaceId && delegateSpaceId === localSpaceId) {
832
- badgeEl.textContent = 'This Device';
833
- badgeEl.className = 'badge badge-this-device';
834
- badgeEl.style.backgroundColor = '#1b5e20';
835
- badgeEl.style.color = '#a5d6a7';
836
- } else {
837
- badgeEl.textContent = 'Remote Device';
838
- badgeEl.className = 'badge badge-remote-device';
839
- badgeEl.style.backgroundColor = '#0d47a1';
840
- badgeEl.style.color = '#90caf9';
876
+ const delegateSpaceId = info.spaceId || (info as any).details?.spaceId;
877
+
878
+ // Check if delegate is present in local space (via spaceId match or direct presence check)
879
+ let isThisDevice = false;
880
+ if (localSpaceId && delegateSpaceId === localSpaceId) {
881
+ isThisDevice = true;
882
+ } else {
883
+ try {
884
+ const resGet = await metaspace.get({ addrs: [delegateTjpAddr], space });
885
+ isThisDevice = !!(resGet.success && resGet.ibGibs && resGet.ibGibs.length > 0);
886
+ } catch {
887
+ isThisDevice = false;
841
888
  }
842
889
  }
843
890
 
891
+ const badgeEl = document.createElement('span');
892
+ badgeEl.style.marginLeft = '0.5rem';
893
+ badgeEl.style.padding = '0.15rem 0.4rem';
894
+ badgeEl.style.borderRadius = '4px';
895
+ badgeEl.style.fontSize = '0.75rem';
896
+ badgeEl.style.fontWeight = 'bold';
897
+
898
+ if (isThisDevice) {
899
+ badgeEl.textContent = 'This Device';
900
+ badgeEl.className = 'badge badge-this-device';
901
+ badgeEl.style.backgroundColor = '#1b5e20';
902
+ badgeEl.style.color = '#a5d6a7';
903
+ } else {
904
+ badgeEl.textContent = 'Remote Device';
905
+ badgeEl.className = 'badge badge-remote-device';
906
+ badgeEl.style.backgroundColor = '#0d47a1';
907
+ badgeEl.style.color = '#90caf9';
908
+ }
909
+
910
+ // Check expiration
911
+ const isExpired = isDelegateExpired({ delegateInfo: info });
912
+ let expiredBadgeEl: HTMLSpanElement | null = null;
913
+ if (isExpired) {
914
+ expiredBadgeEl = document.createElement('span');
915
+ expiredBadgeEl.textContent = 'Expired';
916
+ expiredBadgeEl.className = 'badge badge-expired';
917
+ expiredBadgeEl.style.marginLeft = '0.3rem';
918
+ expiredBadgeEl.style.padding = '0.15rem 0.4rem';
919
+ expiredBadgeEl.style.borderRadius = '4px';
920
+ expiredBadgeEl.style.fontSize = '0.75rem';
921
+ expiredBadgeEl.style.fontWeight = 'bold';
922
+ expiredBadgeEl.style.backgroundColor = '#b71c1c';
923
+ expiredBadgeEl.style.color = '#ef9a9a';
924
+ }
925
+
844
926
  const applyNameAndBadge = (displayName: string, hoverText?: string) => {
845
927
  tdName.innerHTML = '';
846
928
  const textSpan = document.createElement('span');
@@ -849,6 +931,9 @@ export class KeystoneDetailsComponentInstance
849
931
  if (badgeEl) {
850
932
  tdName.appendChild(badgeEl);
851
933
  }
934
+ if (expiredBadgeEl) {
935
+ tdName.appendChild(expiredBadgeEl);
936
+ }
852
937
  tdName.title = hoverText || displayName;
853
938
  };
854
939
 
@@ -863,7 +948,7 @@ export class KeystoneDetailsComponentInstance
863
948
  tdVerbs.textContent = info.allowedVerbs ? info.allowedVerbs.join(', ') : '-';
864
949
  tdVerbs.title = tdVerbs.textContent;
865
950
 
866
- const isRemote = !!(delegateSpaceId && localSpaceId && delegateSpaceId !== localSpaceId);
951
+ const isRemote = !isThisDevice;
867
952
 
868
953
  const tdActions = document.createElement('td');
869
954
  const btnView = document.createElement('button');
@@ -874,20 +959,20 @@ export class KeystoneDetailsComponentInstance
874
959
  if (isRemote) {
875
960
  this.showRemoteDelegateModal(info);
876
961
  } else {
877
- if (info.delegateAddr) {
962
+ if (info.delegateAddr || delegateTjpAddr) {
878
963
  let addrToLoad = info.delegateAddr;
879
- if (metaspace) {
880
- const space = await metaspace.getLocalUserSpace({ lock: false });
881
- if (space) {
882
- try {
883
- const latest = await metaspace.getLatestAddr({ addr: delegateTjpAddr, space });
884
- if (latest) {
885
- addrToLoad = latest;
886
- }
887
- } catch (err) {
888
- console.warn(`${lc} Error resolving latest delegate address: ${extractErrorMsg(err)}`);
889
- }
964
+ try {
965
+ const keystoneService = new KeystoneService_V1();
966
+ const latestKeystone = await keystoneService.getLatestKeystone({
967
+ addr: delegateTjpAddr,
968
+ metaspace,
969
+ space
970
+ });
971
+ if (latestKeystone) {
972
+ addrToLoad = getIbGibAddr({ ibGib: latestKeystone });
890
973
  }
974
+ } catch (err) {
975
+ console.warn(`${lc} Error resolving latest delegate keystone: ${extractErrorMsg(err)}`);
891
976
  }
892
977
  this.dispatchEvent(new CustomEvent('ibgib-view-keystone-details', {
893
978
  detail: { addr: addrToLoad },
@@ -924,7 +1009,7 @@ export class KeystoneDetailsComponentInstance
924
1009
  let masterSecret: string;
925
1010
  try {
926
1011
  masterSecret = await promptForSecret({
927
- msg: `Enter Master Passphrase to revoke delegate '${deviceName}':`,
1012
+ msg: `Enter Master Password to revoke delegate '${deviceName}':`,
928
1013
  confirm: false
929
1014
  });
930
1015
  } catch (err) {
@@ -1103,8 +1188,8 @@ export class KeystoneDetailsComponentInstance
1103
1188
  while (tries < maxTries && !isCorrect) {
1104
1189
  try {
1105
1190
  const promptMsg = tries === 0
1106
- ? "Link successful! Enter your local Master Secret (Passphrase) to sign and register the custodian pool"
1107
- : `Incorrect passphrase. Please try again (${maxTries - tries} tries remaining):`;
1191
+ ? "Link successful! Enter your local Master Secret (Password) to sign and register the custodian pool"
1192
+ : `Incorrect password. Please try again (${maxTries - tries} tries remaining):`;
1108
1193
  masterSecret = await promptForSecret({
1109
1194
  msg: promptMsg,
1110
1195
  confirm: false
@@ -1133,7 +1218,7 @@ export class KeystoneDetailsComponentInstance
1133
1218
  }
1134
1219
 
1135
1220
  if (!isCorrect) {
1136
- this.setSSOStatus("Link cancelled or failed (incorrect passphrase).", "error");
1221
+ this.setSSOStatus("Link cancelled or failed (incorrect password).", "error");
1137
1222
  return;
1138
1223
  }
1139
1224
 
@@ -1187,8 +1272,13 @@ export class KeystoneDetailsComponentInstance
1187
1272
  }
1188
1273
 
1189
1274
  protected async handleSSOClick(providerId: 'google' | 'github') {
1190
- const isLinked = isSsoProviderLinked({ keystone: this.ibGib, providerId });
1275
+ const isLinked = isSsoProviderLinked({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails, providerId });
1191
1276
  if (isLinked) {
1277
+ const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
1278
+ if (!caps.isSovereign) {
1279
+ 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");
1280
+ return;
1281
+ }
1192
1282
  await this.handleSSOUnlink(providerId);
1193
1283
  } else {
1194
1284
  await this.handleSSOLink(providerId);
@@ -1200,7 +1290,7 @@ export class KeystoneDetailsComponentInstance
1200
1290
  this.setSSOStatus(`Unlinking ${providerId}...`, "info");
1201
1291
 
1202
1292
  try {
1203
- // 1. Prompt user for passphrase
1293
+ // 1. Prompt user for password
1204
1294
  const keystoneService = new KeystoneService_V1();
1205
1295
  let masterSecret: string | undefined;
1206
1296
  let isCorrect = false;
@@ -1210,8 +1300,8 @@ export class KeystoneDetailsComponentInstance
1210
1300
  while (tries < maxTries && !isCorrect) {
1211
1301
  try {
1212
1302
  const promptMsg = tries === 0
1213
- ? `Are you sure you want to unlink your ${providerId} account? If so, enter your local Master Secret (Passphrase) to authorize. Otherwise, click Cancel.`
1214
- : `Incorrect passphrase. Please try again (${maxTries - tries} tries remaining):`;
1303
+ ? `Are you sure you want to unlink your ${providerId} account? If so, enter your local Master Secret (Password) to authorize. Otherwise, click Cancel.`
1304
+ : `Incorrect password. Please try again (${maxTries - tries} tries remaining):`;
1215
1305
  masterSecret = await promptForSecret({
1216
1306
  msg: promptMsg,
1217
1307
  confirm: false
@@ -1238,7 +1328,7 @@ export class KeystoneDetailsComponentInstance
1238
1328
  }
1239
1329
 
1240
1330
  if (!isCorrect) {
1241
- this.setSSOStatus("Unlink cancelled or failed (incorrect passphrase).", "error");
1331
+ this.setSSOStatus("Unlink cancelled or failed (incorrect password).", "error");
1242
1332
  return;
1243
1333
  }
1244
1334
 
@@ -1251,7 +1341,7 @@ export class KeystoneDetailsComponentInstance
1251
1341
 
1252
1342
  // 2. Evolve parent keystone to remove the custodian pool
1253
1343
  const targetPoolId = `custodian-manage-${providerId}`;
1254
- const evolvedParent = await keystoneService.removePools({
1344
+ let evolvedParent = await keystoneService.removePools({
1255
1345
  latestKeystone: this.ibGib!,
1256
1346
  masterSecret: masterSecret!,
1257
1347
  poolIds: [targetPoolId],
@@ -1259,6 +1349,22 @@ export class KeystoneDetailsComponentInstance
1259
1349
  space
1260
1350
  });
1261
1351
 
1352
+ // Unregister any corresponding outward delegate for this provider if present
1353
+ const delegatesMap = this.ibGib?.data?.delegates;
1354
+ if (delegatesMap) {
1355
+ for (const [delegateTjpAddr, info] of Object.entries(delegatesMap)) {
1356
+ if (info.deviceName?.includes(providerId)) {
1357
+ evolvedParent = await keystoneService.unregisterDelegate({
1358
+ parentKeystone: evolvedParent,
1359
+ delegateTjpAddr,
1360
+ masterSecret: masterSecret!,
1361
+ metaspace,
1362
+ space,
1363
+ });
1364
+ }
1365
+ }
1366
+ }
1367
+
1262
1368
  // 3. Sync evolved parent keystone back to server
1263
1369
  this.setSSOStatus("Publishing evolved identity keystone to server...", "info");
1264
1370
  const syncRes = await getApiBridge().putEvolveKeystone({
@@ -1292,49 +1398,211 @@ export class KeystoneDetailsComponentInstance
1292
1398
  }
1293
1399
  }
1294
1400
 
1295
- private setChangePassphraseStatus(msg: string, type: 'info' | 'success' | 'error') {
1296
- const el = this.elements!.changePassphraseStatusEl;
1401
+ private setChangePasswordStatus(msg: string, type: 'info' | 'success' | 'error') {
1402
+ const el = this.elements!.changePasswordStatusEl;
1297
1403
  el.textContent = msg;
1298
1404
  el.className = `status-msg ${type}`;
1299
1405
  el.classList.remove('hidden');
1300
1406
  }
1301
1407
 
1302
- protected async handleChangePassphrase(): Promise<void> {
1303
- const lc = `${this.lc}[${this.handleChangePassphrase.name}]`;
1304
- this.setChangePassphraseStatus("Validating entries...", "info");
1408
+ protected async handleAddMasterPassword(): Promise<void> {
1409
+ const lc = `${this.lc}[${this.handleAddMasterPassword.name}]`;
1410
+ this.setChangePasswordStatus("Validating entries...", "info");
1411
+
1412
+ try {
1413
+ const newPassword = this.elements!.inputNewPasswordEl.value;
1414
+ const confirmPassword = this.elements!.inputConfirmPasswordEl.value;
1415
+
1416
+ if (!newPassword) {
1417
+ this.setChangePasswordStatus("Master password is required.", "error");
1418
+ return;
1419
+ }
1420
+ if (newPassword !== confirmPassword) {
1421
+ this.setChangePasswordStatus("Master password and confirmation do not match.", "error");
1422
+ return;
1423
+ }
1424
+
1425
+ const initialManagePool = this.ibGib?.data?.challengePools?.find(p => p.id === POOL_ID_MANAGE);
1426
+ if (!initialManagePool) {
1427
+ this.setChangePasswordStatus("Primary keystone missing active manage challenge pool.", "error");
1428
+ return;
1429
+ }
1430
+
1431
+ this.showBusy({
1432
+ isBusy: true,
1433
+ title: 'Elevating Identity...',
1434
+ msg: 'Generating cryptographic sovereign challenge pool...',
1435
+ animationEmoji: '🔑'
1436
+ });
1437
+ this.setChangePasswordStatus("Generating sovereign challenge pool...", "info");
1438
+ const newChallenges = await generatePoolChallenges({
1439
+ config: initialManagePool.config,
1440
+ masterSecret: newPassword,
1441
+ });
1442
+ const newManagePool = {
1443
+ id: POOL_ID_MANAGE,
1444
+ config: initialManagePool.config,
1445
+ challenges: newChallenges,
1446
+ };
1447
+
1448
+ const primaryTjpAddr = getTjpAddr({ ibGib: this.ibGib! }) || getIbGibAddr({ ibGib: this.ibGib! });
1449
+ const custodianProvider = this.aggregatedDetails?.custodianProvider || 'google';
1450
+
1451
+ let requestBody: any = {
1452
+ primaryTjpAddr,
1453
+ newManagePool,
1454
+ };
1455
+
1456
+ if (custodianProvider === 'google' || custodianProvider === 'github') {
1457
+ this.showBusy({
1458
+ isBusy: true,
1459
+ title: 'Re-authenticating with Provider...',
1460
+ msg: `Please complete authentication in the ${custodianProvider} popup window...`,
1461
+ animationEmoji: '🔒'
1462
+ });
1463
+ this.setChangePasswordStatus(`Please authenticate in the popup with ${custodianProvider} to verify ownership...`, "info");
1464
+ const resPopup = await executeSsoOAuthPopup({
1465
+ providerId: custodianProvider,
1466
+ parentTjpAddr: primaryTjpAddr,
1467
+ });
1468
+
1469
+ if (!resPopup.success || !resPopup.code) {
1470
+ this.showBusy({ isBusy: false });
1471
+ this.setChangePasswordStatus(resPopup.message || "Re-authentication cancelled.", "error");
1472
+ return;
1473
+ }
1474
+
1475
+ requestBody.providerId = custodianProvider;
1476
+ requestBody.code = resPopup.code;
1477
+ requestBody.redirectUri = resPopup.redirectUri;
1478
+ } else {
1479
+ this.showBusy({ isBusy: false });
1480
+ // Email OTP fallback
1481
+ const email = this.aggregatedDetails?.emails?.[0] || this.ibGib?.data?.emails?.[0];
1482
+ const otpCode = await promptForSecret({
1483
+ msg: `Enter 6-digit verification code sent to ${email}:`,
1484
+ confirm: false,
1485
+ });
1486
+ if (!otpCode) {
1487
+ this.setChangePasswordStatus("Verification code required.", "error");
1488
+ return;
1489
+ }
1490
+ requestBody.email = email;
1491
+ requestBody.code = otpCode;
1492
+ }
1493
+
1494
+ this.showBusy({
1495
+ isBusy: true,
1496
+ title: 'Updating Keystone Timeline...',
1497
+ msg: 'Publishing sovereign master password and evolving identity DAG...',
1498
+ animationEmoji: '⏳'
1499
+ });
1500
+ this.setChangePasswordStatus("Elevating identity to sovereign master password on server...", "info");
1501
+ const response = await fetch('/api/identity/custodian/add-master-password', {
1502
+ method: 'POST',
1503
+ headers: { 'Content-Type': 'application/json' },
1504
+ body: JSON.stringify(requestBody),
1505
+ });
1506
+
1507
+ const resJson = await response.json();
1508
+ if (!response.ok || !resJson.success) {
1509
+ throw new Error(resJson.error || resJson.message || `Server error (${response.status})`);
1510
+ }
1511
+
1512
+ const evolvedParent = resJson.primaryKeystone;
1513
+
1514
+ // Save to local user space & metaspace
1515
+ const metaspace = await getGlobalMetaspace_waitIfNeeded();
1516
+ if (!metaspace) { throw new Error("Global metaspace not available"); }
1517
+ const space = await metaspace.getLocalUserSpace({ lock: false });
1518
+ if (!space) { throw new Error("Local user space not available"); }
1519
+
1520
+ await metaspace.put({ ibGibs: [evolvedParent], space });
1521
+ await metaspace.registerNewIbGib({ ibGib: evolvedParent, space });
1522
+ await updateSpecialIndex({
1523
+ type: "keystones",
1524
+ rel8nInfos: [
1525
+ {
1526
+ rel8nName: "keystone",
1527
+ ibGibs: [toDto({ ibGib: evolvedParent })]
1528
+ }
1529
+ ],
1530
+ metaspace,
1531
+ space
1532
+ });
1533
+
1534
+ const evolvedAddr = getIbGibAddr({ ibGib: evolvedParent });
1535
+
1536
+ // Dispatch EVENT_IBGIB_IDENTITY_CHANGED
1537
+ window.dispatchEvent(new CustomEvent(EVENT_IBGIB_IDENTITY_CHANGED, {
1538
+ detail: { activeIdentityAddr: evolvedAddr },
1539
+ bubbles: true,
1540
+ composed: true
1541
+ }));
1542
+
1543
+ this.setChangePasswordStatus("Successfully added Master Password! Identity is now sovereign.", "success");
1544
+
1545
+ // Refresh the view
1546
+ this.ibGibAddr = evolvedAddr;
1547
+ this.staticIbGib = evolvedParent;
1548
+ await this.loadIbGib({ getLatest: true });
1549
+
1550
+ // Clear inputs
1551
+ this.elements!.inputNewPasswordEl.value = '';
1552
+ this.elements!.inputConfirmPasswordEl.value = '';
1553
+
1554
+ } catch (error) {
1555
+ console.error(`${lc} Elevation failed: ${extractErrorMsg(error)}`);
1556
+ this.setChangePasswordStatus(`Failed to add master password: ${extractErrorMsg(error)}`, "error");
1557
+ } finally {
1558
+ this.showBusy({ isBusy: false });
1559
+ }
1560
+ }
1561
+
1562
+ protected async handleChangePassword(): Promise<void> {
1563
+ const lc = `${this.lc}[${this.handleChangePassword.name}]`;
1564
+
1565
+ const caps = getKeystoneCapabilities({ keystone: this.ibGib, aggregatedDetails: this.aggregatedDetails });
1566
+ const isCustodialOnly = caps.isCustodial && !caps.isSovereign;
1567
+ if (isCustodialOnly) {
1568
+ await this.handleAddMasterPassword();
1569
+ return;
1570
+ }
1571
+
1572
+ this.setChangePasswordStatus("Validating entries...", "info");
1305
1573
 
1306
1574
  try {
1307
- const currentPassphrase = this.elements!.inputCurrentPassphraseEl.value;
1308
- const newPassphrase = this.elements!.inputNewPassphraseEl.value;
1309
- const confirmPassphrase = this.elements!.inputConfirmPassphraseEl.value;
1575
+ const currentPassword = this.elements!.inputCurrentPasswordEl.value;
1576
+ const newPassword = this.elements!.inputNewPasswordEl.value;
1577
+ const confirmPassword = this.elements!.inputConfirmPasswordEl.value;
1310
1578
 
1311
- if (!currentPassphrase) {
1312
- this.setChangePassphraseStatus("Current passphrase is required.", "error");
1579
+ if (!currentPassword) {
1580
+ this.setChangePasswordStatus("Current password is required.", "error");
1313
1581
  return;
1314
1582
  }
1315
- if (!newPassphrase) {
1316
- this.setChangePassphraseStatus("New passphrase is required.", "error");
1583
+ if (!newPassword) {
1584
+ this.setChangePasswordStatus("New password is required.", "error");
1317
1585
  return;
1318
1586
  }
1319
- if (newPassphrase !== confirmPassphrase) {
1320
- this.setChangePassphraseStatus("New passphrase and confirmation do not match.", "error");
1587
+ if (newPassword !== confirmPassword) {
1588
+ this.setChangePasswordStatus("New password and confirmation do not match.", "error");
1321
1589
  return;
1322
1590
  }
1323
1591
 
1324
1592
  const keystoneService = new KeystoneService_V1();
1325
1593
 
1326
- // 1. Verify current passphrase against parent manage pool
1594
+ // 1. Verify current password against parent manage pool
1327
1595
  const isMatch = await keystoneService.verifySigningSecret({
1328
1596
  keystoneIbGib: this.ibGib!,
1329
- signingSecret: currentPassphrase,
1597
+ signingSecret: currentPassword,
1330
1598
  poolId: 'manage'
1331
1599
  });
1332
1600
  if (!isMatch) {
1333
- this.setChangePassphraseStatus("Incorrect current passphrase.", "error");
1601
+ this.setChangePasswordStatus("Incorrect current password.", "error");
1334
1602
  return;
1335
1603
  }
1336
1604
 
1337
- this.setChangePassphraseStatus("Evolving primary identity keystone...", "info");
1605
+ this.setChangePasswordStatus("Evolving primary identity keystone...", "info");
1338
1606
 
1339
1607
  const metaspace = await getGlobalMetaspace_waitIfNeeded();
1340
1608
  if (!metaspace) { throw new Error(`(UNEXPECTED) metaspace falsy? (E: 95e3c8374b0f088f339f5c5a8700f826)`); }
@@ -1346,15 +1614,15 @@ export class KeystoneDetailsComponentInstance
1346
1614
  const { newKeystone: evolvedParent, newDelegates: evolvedDelegates } =
1347
1615
  await keystoneService.changePassword({
1348
1616
  keystoneIbGib: this.ibGib!,
1349
- newMasterSecret: newPassphrase,
1350
- signingSecret: currentPassphrase,
1617
+ newMasterSecret: newPassword,
1618
+ signingSecret: currentPassword,
1351
1619
  signingPoolId: 'manage',
1352
1620
  metaspace,
1353
1621
  space
1354
1622
  });
1355
1623
  debugger; // look at evolvedDelegates
1356
1624
 
1357
- this.setChangePassphraseStatus("Resolving and rotating delegate keystones...", "info");
1625
+ this.setChangePasswordStatus("Resolving and rotating delegate keystones...", "info");
1358
1626
 
1359
1627
  // // 3. Evolve registered delegate keystones (preserving custodian/foreign delegate secrets)
1360
1628
  // const delegates = this.ibGib!.data?.delegates || {};
@@ -1368,7 +1636,7 @@ export class KeystoneDetailsComponentInstance
1368
1636
  // space,
1369
1637
  // });
1370
1638
 
1371
- // // Identify user-owned challenge pools in the delegate that match the old passphrase
1639
+ // // Identify user-owned challenge pools in the delegate that match the old password
1372
1640
  // const poolsToRotate: string[] = [];
1373
1641
  // for (const pool of delegateKeystone.data?.challengePools ?? []) {
1374
1642
  // if (!pool.isForeign) {
@@ -1383,7 +1651,7 @@ export class KeystoneDetailsComponentInstance
1383
1651
  // */
1384
1652
  // const isPoolMatch = await keystoneService.verifySigningSecret({
1385
1653
  // keystoneIbGib: delegateKeystone,
1386
- // signingSecret: currentPassphrase,
1654
+ // signingSecret: currentPassword,
1387
1655
  // poolId: pool.id
1388
1656
  // });
1389
1657
  // if (isPoolMatch) { poolsToRotate.push(pool.id); }
@@ -1394,8 +1662,8 @@ export class KeystoneDetailsComponentInstance
1394
1662
  // console.log(`${lc} Rotating pools in delegate ${delegateInfo.delegateTjpAddr}: ${poolsToRotate.join(', ')}`);
1395
1663
  // const {newKeystone: evolvedDelegate} = await keystoneService.changePassword({
1396
1664
  // keystoneIbGib: delegateKeystone,
1397
- // newMasterSecret: newPassphrase,
1398
- // signingSecret: currentPassphrase,
1665
+ // newMasterSecret: newPassword,
1666
+ // signingSecret: currentPassword,
1399
1667
  // signingPoolId: 'manage',
1400
1668
  // poolIds: poolsToRotate,
1401
1669
  // metaspace,
@@ -1406,7 +1674,7 @@ export class KeystoneDetailsComponentInstance
1406
1674
  // }
1407
1675
 
1408
1676
  // 4. Sync evolved parent and all evolved delegate keystones atomically
1409
- this.setChangePassphraseStatus("Syncing evolved keystones to server...", "info");
1677
+ this.setChangePasswordStatus("Syncing evolved keystones to server...", "info");
1410
1678
  const parentTjpAddr = getIbGibAddr({ ibGib: this.ibGib! }); // is this.ibGib the tjp always? or is it the latest in the keystone line? Does it matter?
1411
1679
 
1412
1680
  const syncRes = await getApiBridge().putEvolveKeystone({
@@ -1419,7 +1687,7 @@ export class KeystoneDetailsComponentInstance
1419
1687
  }
1420
1688
 
1421
1689
  // 5. Update index locally
1422
- this.setChangePassphraseStatus("Updating local indexes...", "info");
1690
+ this.setChangePasswordStatus("Updating local indexes...", "info");
1423
1691
  const newKeystoneIbGibs = [toDto({ ibGib: evolvedParent })];
1424
1692
  if (evolvedDelegates) {
1425
1693
  evolvedDelegates.forEach(d => {
@@ -1440,16 +1708,16 @@ export class KeystoneDetailsComponentInstance
1440
1708
  });
1441
1709
 
1442
1710
  // Clear inputs
1443
- this.elements!.inputCurrentPassphraseEl.value = "";
1444
- this.elements!.inputNewPassphraseEl.value = "";
1445
- this.elements!.inputConfirmPassphraseEl.value = "";
1711
+ this.elements!.inputCurrentPasswordEl.value = "";
1712
+ this.elements!.inputNewPasswordEl.value = "";
1713
+ this.elements!.inputConfirmPasswordEl.value = "";
1446
1714
 
1447
- this.setChangePassphraseStatus("Passphrase updated successfully!", "success");
1715
+ this.setChangePasswordStatus("Password updated successfully!", "success");
1448
1716
  await this.loadIbGib({ getLatest: true });
1449
1717
 
1450
1718
  } catch (error) {
1451
- console.error(`${lc} Passphrase rotation failed: ${extractErrorMsg(error)}`);
1452
- this.setChangePassphraseStatus(`Update failed: ${extractErrorMsg(error)}`, "error");
1719
+ console.error(`${lc} Password rotation failed: ${extractErrorMsg(error)}`);
1720
+ this.setChangePasswordStatus(`Update failed: ${extractErrorMsg(error)}`, "error");
1453
1721
  }
1454
1722
  }
1455
1723
  }