@modernman00/shared-js-lib 1.2.89 โ 1.2.90
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/WebAuthnClient.js +125 -0
- package/config/version.php +1 -1
- package/package.json +2 -1
- package/release-history.md +6 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebAuthnClient.js
|
|
3
|
+
*
|
|
4
|
+
* Handles client-side WebAuthn interactions (FaceID, TouchID, Passcodes).
|
|
5
|
+
* Implements David's Gatewatcher mandate: Defensive Degradation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export class WebAuthnClient {
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the device supports WebAuthn (Biometrics/Passkeys)
|
|
11
|
+
* @returns {boolean}
|
|
12
|
+
*/
|
|
13
|
+
static isSupported() {
|
|
14
|
+
return window.PublicKeyCredential !== undefined
|
|
15
|
+
&& typeof window.PublicKeyCredential === 'function';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Base64URL to ArrayBuffer converter
|
|
20
|
+
*/
|
|
21
|
+
static base64URLStringToBuffer(base64URLString) {
|
|
22
|
+
const base64 = base64URLString.replace(/-/g, '+').replace(/_/g, '/');
|
|
23
|
+
const padLength = (4 - (base64.length % 4)) % 4;
|
|
24
|
+
const padded = base64.padEnd(base64.length + padLength, '=');
|
|
25
|
+
const binary = atob(padded);
|
|
26
|
+
const buffer = new ArrayBuffer(binary.length);
|
|
27
|
+
const bytes = new Uint8Array(buffer);
|
|
28
|
+
for (let i = 0; i < binary.length; i++) {
|
|
29
|
+
bytes[i] = binary.charCodeAt(i);
|
|
30
|
+
}
|
|
31
|
+
return buffer;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* ArrayBuffer to Base64URL converter
|
|
36
|
+
*/
|
|
37
|
+
static bufferToBase64URLString(buffer) {
|
|
38
|
+
const bytes = new Uint8Array(buffer);
|
|
39
|
+
let str = '';
|
|
40
|
+
for (let i = 0; i < bytes.byteLength; i++) {
|
|
41
|
+
str += String.fromCharCode(bytes[i]);
|
|
42
|
+
}
|
|
43
|
+
return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Initiates the registration of a new Passkey
|
|
48
|
+
* @param {Object} optionsFromServer JSON options from /webauthn/register/options
|
|
49
|
+
*/
|
|
50
|
+
static async registerDevice(optionsFromServer) {
|
|
51
|
+
if (!this.isSupported()) {
|
|
52
|
+
throw new Error("Device does not support biometrics/passkeys.");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const publicKey = {
|
|
57
|
+
...optionsFromServer,
|
|
58
|
+
challenge: this.base64URLStringToBuffer(optionsFromServer.challenge),
|
|
59
|
+
user: {
|
|
60
|
+
...optionsFromServer.user,
|
|
61
|
+
id: this.base64URLStringToBuffer(optionsFromServer.user.id)
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const credential = await navigator.credentials.create({ publicKey });
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
id: credential.id,
|
|
69
|
+
rawId: this.bufferToBase64URLString(credential.rawId),
|
|
70
|
+
type: credential.type,
|
|
71
|
+
response: {
|
|
72
|
+
attestationObject: this.bufferToBase64URLString(credential.response.attestationObject),
|
|
73
|
+
clientDataJSON: this.bufferToBase64URLString(credential.response.clientDataJSON),
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
} catch (error) {
|
|
77
|
+
// David's Rule: Defensive Degradation. If it fails or is canceled, log and swallow politely.
|
|
78
|
+
console.warn("WebAuthn Registration failed or was canceled:", error);
|
|
79
|
+
throw new Error("Passkey registration was canceled or failed.");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Initiates login using an existing Passkey
|
|
85
|
+
* @param {Object} optionsFromServer JSON options from /webauthn/login/options
|
|
86
|
+
*/
|
|
87
|
+
static async loginWithDevice(optionsFromServer) {
|
|
88
|
+
if (!this.isSupported()) {
|
|
89
|
+
throw new Error("Device does not support biometrics/passkeys.");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const publicKey = {
|
|
94
|
+
...optionsFromServer,
|
|
95
|
+
challenge: this.base64URLStringToBuffer(optionsFromServer.challenge)
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// Convert allowed credentials to buffers if they exist
|
|
99
|
+
if (publicKey.allowCredentials) {
|
|
100
|
+
publicKey.allowCredentials = publicKey.allowCredentials.map(cred => ({
|
|
101
|
+
...cred,
|
|
102
|
+
id: this.base64URLStringToBuffer(cred.id)
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const assertion = await navigator.credentials.get({ publicKey });
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
id: assertion.id,
|
|
110
|
+
rawId: this.bufferToBase64URLString(assertion.rawId),
|
|
111
|
+
type: assertion.type,
|
|
112
|
+
response: {
|
|
113
|
+
authenticatorData: this.bufferToBase64URLString(assertion.response.authenticatorData),
|
|
114
|
+
clientDataJSON: this.bufferToBase64URLString(assertion.response.clientDataJSON),
|
|
115
|
+
signature: this.bufferToBase64URLString(assertion.response.signature),
|
|
116
|
+
userHandle: assertion.response.userHandle ? this.bufferToBase64URLString(assertion.response.userHandle) : null,
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
} catch (error) {
|
|
120
|
+
// David's Rule: Defensive Degradation.
|
|
121
|
+
console.warn("WebAuthn Login failed or was canceled:", error);
|
|
122
|
+
throw new Error("Passkey login was canceled or failed. Please use your password.");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
package/config/version.php
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modernman00/shared-js-lib",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.90",
|
|
4
4
|
"description": "Reusable JS utilities for numerous js problems",
|
|
5
5
|
"homepage": "https://github.com/modernman00/shared-js-lib#readme",
|
|
6
6
|
"keywords": [
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"InlineValidation.js",
|
|
49
49
|
"Clipboard.js",
|
|
50
50
|
"AuthInterceptor.js",
|
|
51
|
+
"WebAuthnClient.js",
|
|
51
52
|
"ShowResponse.js",
|
|
52
53
|
"Utility.js",
|
|
53
54
|
"UtilityHtml.js",
|
package/release-history.md
CHANGED
|
@@ -172,3 +172,9 @@
|
|
|
172
172
|
- ๐งน Auto-commit before release _(by modernman00)_
|
|
173
173
|
- ๐ Release v1.2.88 _(by modernman00)_
|
|
174
174
|
- ๐งน Auto-commit before release _(by modernman00)_
|
|
175
|
+
|
|
176
|
+
## v1.2.90 โ 2026-10-23 17:34
|
|
177
|
+
### Changelog for v1.2.90
|
|
178
|
+
|
|
179
|
+
- fix(package): ship WebAuthnClient.js in the published files list _(by modernman00)_
|
|
180
|
+
- ci: drop npm publish step from release workflow _(by modernman00)_
|