@ibgib/web-gib 0.0.61 → 0.0.62
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.web.d.mts +3 -1
- package/dist/helpers.web.d.mts.map +1 -1
- package/dist/helpers.web.mjs +17 -1
- package/dist/helpers.web.mjs.map +1 -1
- package/dist/identity/device-delegate-helper.d.mts +48 -0
- package/dist/identity/device-delegate-helper.d.mts.map +1 -1
- package/dist/identity/device-delegate-helper.mjs +86 -2
- package/dist/identity/device-delegate-helper.mjs.map +1 -1
- package/dist/identity/device-delegate.respec.mjs +6 -6
- package/dist/identity/device-delegate.respec.mjs.map +1 -1
- package/dist/identity/passkey-helper.d.mts +72 -0
- package/dist/identity/passkey-helper.d.mts.map +1 -0
- package/dist/identity/passkey-helper.mjs +237 -0
- package/dist/identity/passkey-helper.mjs.map +1 -0
- package/dist/identity/passkey.respec.d.mts +2 -0
- package/dist/identity/passkey.respec.d.mts.map +1 -0
- package/dist/identity/passkey.respec.mjs +169 -0
- package/dist/identity/passkey.respec.mjs.map +1 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -0
- package/dist/index.mjs.map +1 -1
- package/dist/ui/component/identity/add-device/add-device.d.mts.map +1 -1
- package/dist/ui/component/identity/add-device/add-device.mjs +1 -0
- package/dist/ui/component/identity/add-device/add-device.mjs.map +1 -1
- package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts +18 -1
- package/dist/ui/component/identity/keystone-creator/keystone-creator.d.mts.map +1 -1
- package/dist/ui/component/identity/keystone-creator/keystone-creator.html +42 -3
- package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs +510 -74
- package/dist/ui/component/identity/keystone-creator/keystone-creator.mjs.map +1 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.d.mts +16 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.d.mts.map +1 -1
- package/dist/ui/component/identity/keystone-details/keystone-details.html +38 -0
- package/dist/ui/component/identity/keystone-details/keystone-details.mjs +946 -122
- package/dist/ui/component/identity/keystone-details/keystone-details.mjs.map +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.mjs +1 -0
- package/dist/ui/component/identity/remove-device/remove-device.mjs.map +1 -1
- package/dist/ui/ui-helpers.d.mts +3 -0
- package/dist/ui/ui-helpers.d.mts.map +1 -1
- package/dist/ui/ui-helpers.mjs +110 -6
- package/dist/ui/ui-helpers.mjs.map +1 -1
- package/package.json +2 -2
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/helpers.web.mts +22 -2
- package/src/identity/device-delegate-helper.mts +135 -2
- package/src/identity/device-delegate.respec.mts +6 -6
- package/src/identity/passkey-helper.mts +304 -0
- package/src/identity/passkey.respec.mts +194 -0
- package/src/index.mts +1 -0
- package/src/ui/component/identity/add-device/add-device.mts +1 -0
- package/src/ui/component/identity/keystone-creator/keystone-creator.html +42 -3
- package/src/ui/component/identity/keystone-creator/keystone-creator.mts +551 -77
- package/src/ui/component/identity/keystone-details/keystone-details.html +38 -0
- package/src/ui/component/identity/keystone-details/keystone-details.mts +1011 -131
- package/src/ui/component/identity/remove-device/remove-device.mts +1 -0
- package/src/ui/ui-helpers.mts +118 -5
package/src/ui/ui-helpers.mts
CHANGED
|
@@ -49,6 +49,9 @@ export interface ShowFullscreenDialogOpts {
|
|
|
49
49
|
isPassword?: boolean;
|
|
50
50
|
isBusy?: boolean;
|
|
51
51
|
animationEmoji?: string;
|
|
52
|
+
passkeys?: Record<string, any>;
|
|
53
|
+
passkeyButtonTitle?: string;
|
|
54
|
+
onPasskeyAuth?: (passkeyEntry?: any) => Promise<string | undefined>;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
export async function showFullscreenDialog(opts: ShowFullscreenDialogOpts & { isBusy: true }): Promise<FullscreenDialogController>;
|
|
@@ -64,6 +67,9 @@ export async function showFullscreenDialog({
|
|
|
64
67
|
isPassword,
|
|
65
68
|
isBusy,
|
|
66
69
|
animationEmoji,
|
|
70
|
+
passkeys,
|
|
71
|
+
passkeyButtonTitle,
|
|
72
|
+
onPasskeyAuth,
|
|
67
73
|
}: ShowFullscreenDialogOpts): Promise<string | undefined | FullscreenDialogController> {
|
|
68
74
|
const lc = `[${showFullscreenDialog.name}]`;
|
|
69
75
|
try {
|
|
@@ -112,6 +118,75 @@ export async function showFullscreenDialog({
|
|
|
112
118
|
messageElement.appendChild(animDiv);
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
// Clean up any previous passkey container
|
|
122
|
+
let prevPasskeyContainer = document.getElementById('fullscreen-dialog-passkey-container');
|
|
123
|
+
if (prevPasskeyContainer) { prevPasskeyContainer.remove(); }
|
|
124
|
+
|
|
125
|
+
let passkeyContainer: HTMLDivElement | null = null;
|
|
126
|
+
let btnPasskey: HTMLButtonElement | null = null;
|
|
127
|
+
let selectPasskey: HTMLSelectElement | null = null;
|
|
128
|
+
const validPasskeys = Object.values(passkeys || {}).filter(p => p !== null && p !== undefined);
|
|
129
|
+
|
|
130
|
+
if (validPasskeys.length > 0 && onPasskeyAuth && !isBusy) {
|
|
131
|
+
passkeyContainer = document.createElement('div');
|
|
132
|
+
passkeyContainer.id = 'fullscreen-dialog-passkey-container';
|
|
133
|
+
passkeyContainer.style.margin = '1rem 0';
|
|
134
|
+
passkeyContainer.style.textAlign = 'center';
|
|
135
|
+
|
|
136
|
+
btnPasskey = document.createElement('button');
|
|
137
|
+
btnPasskey.id = 'fullscreen-dialog-btn-passkey';
|
|
138
|
+
btnPasskey.type = 'button';
|
|
139
|
+
btnPasskey.className = 'action-btn';
|
|
140
|
+
btnPasskey.style.width = '100%';
|
|
141
|
+
btnPasskey.style.padding = '0.75rem 1rem';
|
|
142
|
+
btnPasskey.style.background = 'linear-gradient(135deg, #1b5e20, #2e7d32)';
|
|
143
|
+
btnPasskey.style.color = '#ffffff';
|
|
144
|
+
btnPasskey.style.fontWeight = 'bold';
|
|
145
|
+
btnPasskey.style.borderRadius = '8px';
|
|
146
|
+
btnPasskey.style.border = '1px solid rgba(255,255,255,0.2)';
|
|
147
|
+
btnPasskey.style.cursor = 'pointer';
|
|
148
|
+
btnPasskey.style.fontSize = '0.95rem';
|
|
149
|
+
btnPasskey.style.marginBottom = '0.75rem';
|
|
150
|
+
btnPasskey.textContent = passkeyButtonTitle || '🛡️ Touch ID / Security Key';
|
|
151
|
+
|
|
152
|
+
if (validPasskeys.length > 1) {
|
|
153
|
+
selectPasskey = document.createElement('select');
|
|
154
|
+
selectPasskey.style.width = '100%';
|
|
155
|
+
selectPasskey.style.padding = '0.4rem';
|
|
156
|
+
selectPasskey.style.marginBottom = '0.5rem';
|
|
157
|
+
selectPasskey.style.borderRadius = '4px';
|
|
158
|
+
selectPasskey.style.background = 'rgba(0,0,0,0.3)';
|
|
159
|
+
selectPasskey.style.color = 'inherit';
|
|
160
|
+
selectPasskey.style.border = '1px solid rgba(255,255,255,0.2)';
|
|
161
|
+
validPasskeys.forEach((p: any, idx: number) => {
|
|
162
|
+
const opt = document.createElement('option');
|
|
163
|
+
opt.value = idx.toString();
|
|
164
|
+
opt.textContent = `${p.name || 'Key'} (${p.credentialId?.substring(0, 8)}...)`;
|
|
165
|
+
selectPasskey!.appendChild(opt);
|
|
166
|
+
});
|
|
167
|
+
passkeyContainer.appendChild(selectPasskey);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
passkeyContainer.appendChild(btnPasskey);
|
|
171
|
+
|
|
172
|
+
const divider = document.createElement('div');
|
|
173
|
+
divider.style.display = 'flex';
|
|
174
|
+
divider.style.alignItems = 'center';
|
|
175
|
+
divider.style.justifyContent = 'center';
|
|
176
|
+
divider.style.gap = '0.5rem';
|
|
177
|
+
divider.style.fontSize = '0.8rem';
|
|
178
|
+
divider.style.color = 'var(--clr-text-secondary, #b3b3b3)';
|
|
179
|
+
divider.style.margin = '0.5rem 0';
|
|
180
|
+
divider.innerHTML = `
|
|
181
|
+
<span style="flex: 1; height: 1px; background: rgba(255,255,255,0.15);"></span>
|
|
182
|
+
<span>OR enter Password below</span>
|
|
183
|
+
<span style="flex: 1; height: 1px; background: rgba(255,255,255,0.15);"></span>
|
|
184
|
+
`;
|
|
185
|
+
passkeyContainer.appendChild(divider);
|
|
186
|
+
|
|
187
|
+
promptInput.parentElement?.insertBefore(passkeyContainer, promptInput);
|
|
188
|
+
}
|
|
189
|
+
|
|
115
190
|
// reset the input classList and button displays
|
|
116
191
|
promptInput.classList.remove('collapsed');
|
|
117
192
|
cancelButton.classList.remove('collapsed');
|
|
@@ -241,6 +316,12 @@ export async function showFullscreenDialog({
|
|
|
241
316
|
if (prompt || showInput) {
|
|
242
317
|
promptInput.removeEventListener('keypress', onKeypress);
|
|
243
318
|
}
|
|
319
|
+
if (btnPasskey) {
|
|
320
|
+
btnPasskey.removeEventListener('click', onPasskeyClick);
|
|
321
|
+
}
|
|
322
|
+
if (passkeyContainer) {
|
|
323
|
+
passkeyContainer.remove();
|
|
324
|
+
}
|
|
244
325
|
okButton.removeEventListener('click', onOK);
|
|
245
326
|
cancelButton.removeEventListener('click', onCancel);
|
|
246
327
|
dialog.removeEventListener('close', onClose); // Remove dialog-level listener too
|
|
@@ -256,6 +337,38 @@ export async function showFullscreenDialog({
|
|
|
256
337
|
resolve(result);
|
|
257
338
|
};
|
|
258
339
|
|
|
340
|
+
/** user clicks Passkey button */
|
|
341
|
+
const onPasskeyClick = async () => {
|
|
342
|
+
try {
|
|
343
|
+
if (!onPasskeyAuth) return;
|
|
344
|
+
btnPasskey!.disabled = true;
|
|
345
|
+
btnPasskey!.textContent = 'Waiting for biometrics / security key...';
|
|
346
|
+
let selectedPasskey = validPasskeys[0];
|
|
347
|
+
if (selectPasskey) {
|
|
348
|
+
const selectedIdx = parseInt(selectPasskey.value, 10);
|
|
349
|
+
selectedPasskey = validPasskeys[selectedIdx] || validPasskeys[0];
|
|
350
|
+
}
|
|
351
|
+
const passkeySecret = await onPasskeyAuth(selectedPasskey);
|
|
352
|
+
if (passkeySecret) {
|
|
353
|
+
removeEventListeners();
|
|
354
|
+
if (promptInput) { promptInput.value = ''; }
|
|
355
|
+
dialog.close(passkeySecret);
|
|
356
|
+
resolve(passkeySecret);
|
|
357
|
+
} else {
|
|
358
|
+
btnPasskey!.disabled = false;
|
|
359
|
+
btnPasskey!.textContent = passkeyButtonTitle || '🛡️ Touch ID / Security Key';
|
|
360
|
+
}
|
|
361
|
+
} catch (err) {
|
|
362
|
+
console.warn('Passkey assertion in dialog failed/cancelled:', err);
|
|
363
|
+
btnPasskey!.disabled = false;
|
|
364
|
+
btnPasskey!.textContent = passkeyButtonTitle || '🛡️ Touch ID / Security Key';
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
if (btnPasskey) {
|
|
369
|
+
btnPasskey.addEventListener('click', onPasskeyClick);
|
|
370
|
+
}
|
|
371
|
+
|
|
259
372
|
/** user actively clicks Cancel */
|
|
260
373
|
const onCancel = () => {
|
|
261
374
|
removeEventListeners();
|
|
@@ -264,11 +377,11 @@ export async function showFullscreenDialog({
|
|
|
264
377
|
resolve(undefined);
|
|
265
378
|
};
|
|
266
379
|
/**
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
380
|
+
* Handle dialog.close() without button click (e.g., Esc key)
|
|
381
|
+
*
|
|
382
|
+
* NOTE: this does not trigger when dialog.close() is executed. This
|
|
383
|
+
* is only firing when esc is pressed.
|
|
384
|
+
*/
|
|
272
385
|
const onClose = () => {
|
|
273
386
|
removeEventListeners();
|
|
274
387
|
if (promptInput) { promptInput.value = ''; } // Clear input for next time
|