dphelper 4.2.0 → 4.2.3
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/README.md +6 -5
- package/index.cjs +1 -1
- package/index.js +1 -1
- package/package.json +3 -3
- package/markdown/ai.md +0 -345
- package/markdown/anchor.md +0 -156
- package/markdown/array.md +0 -208
- package/markdown/audio.md +0 -113
- package/markdown/avoid.md +0 -53
- package/markdown/biometric.md +0 -338
- package/markdown/browser.md +0 -203
- package/markdown/check.md +0 -65
- package/markdown/color.md +0 -159
- package/markdown/compress.md +0 -310
- package/markdown/cookie.md +0 -115
- package/markdown/coords.md +0 -127
- package/markdown/credits.md +0 -56
- package/markdown/date.md +0 -260
- package/markdown/disable.md +0 -109
- package/markdown/dispatch.md +0 -108
- package/markdown/element.md +0 -53
- package/markdown/event.md +0 -85
- package/markdown/fetch.md +0 -122
- package/markdown/form.md +0 -302
- package/markdown/format.md +0 -122
- package/markdown/i18n.md +0 -292
- package/markdown/image.md +0 -298
- package/markdown/json.md +0 -269
- package/markdown/load.md +0 -133
- package/markdown/logging.md +0 -99
- package/markdown/math.md +0 -172
- package/markdown/memory.md +0 -85
- package/markdown/navigation.md +0 -152
- package/markdown/net.md +0 -60
- package/markdown/obj.md +0 -242
- package/markdown/path.md +0 -46
- package/markdown/promise.md +0 -94
- package/markdown/sanitize.md +0 -118
- package/markdown/screen.md +0 -78
- package/markdown/scrollbar.md +0 -82
- package/markdown/security.md +0 -289
- package/markdown/shortcut.md +0 -100
- package/markdown/socket.md +0 -134
- package/markdown/sse.md +0 -120
- package/markdown/svg.md +0 -167
- package/markdown/sync.md +0 -147
- package/markdown/system.md +0 -78
- package/markdown/terminal.md +0 -73
- package/markdown/text.md +0 -245
- package/markdown/timer.md +0 -98
- package/markdown/tools.md +0 -111
- package/markdown/translators.md +0 -65
- package/markdown/trigger.md +0 -99
- package/markdown/triggers.md +0 -133
- package/markdown/type.md +0 -109
- package/markdown/types.md +0 -102
- package/markdown/ui.md +0 -45
- package/markdown/window.md +0 -211
- package/markdown/worker.md +0 -223
package/markdown/array.md
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
# array
|
|
2
|
-
|
|
3
|
-
Advanced utilities for JavaScript array manipulation with support for nested structures, merging, filtering, and more.
|
|
4
|
-
|
|
5
|
-
## Functions
|
|
6
|
-
|
|
7
|
-
| Function | Description | Example |
|
|
8
|
-
|----------|-------------|---------|
|
|
9
|
-
| `find` | Finds an element recursively in nested arrays | `dphelper.array.find(array, 'key')` |
|
|
10
|
-
| `delete` | Deletes an element recursively by key | `dphelper.array.delete(array, 'key')` |
|
|
11
|
-
| `merge` | Deep merges two objects/arrays (safe from prototype pollution) | `dphelper.array.merge(arrA, arrB)` |
|
|
12
|
-
| `mergeByKey` | Merges two arrays of objects via a specific key | `dphelper.array.mergeByKey(arrA, arrB, 'id')` |
|
|
13
|
-
| `unique` | Removes duplicate values from an array | `dphelper.array.unique(array)` |
|
|
14
|
-
| `asc` | Sorts array in ascending order | `dphelper.array.asc(array)` |
|
|
15
|
-
| `desc` | Sorts array in descending order | `dphelper.array.desc(array)` |
|
|
16
|
-
| `duplicates` | Finds duplicate elements in an array | `dphelper.array.duplicates(array)` |
|
|
17
|
-
| `even` | Filters even numbers from an array | `dphelper.array.even(array)` |
|
|
18
|
-
| `odd` | Filters odd numbers from an array | `dphelper.array.odd(array)` |
|
|
19
|
-
| `toObj` | Converts an array to an object | `dphelper.array.toObj(array)` |
|
|
20
|
-
| `sumColumn` | Sums values of a column in a multidimensional array | `dphelper.array.sumColumn(arr, 0)` |
|
|
21
|
-
| `shuffle` | Randomly shuffles elements (Fisher-Yates algorithm) | `dphelper.array.shuffle(array)` |
|
|
22
|
-
| `generate` | Generates an array of random numbers (1 to n) | `dphelper.array.generate(10)` |
|
|
23
|
-
| `testArrayInt` | Checks for missing numbers in a consecutive sequence | `dphelper.array.testArrayInt([1,2,4])` |
|
|
24
|
-
| `rand32` | Generates an array of random 32-bit unsigned integers | `dphelper.array.rand32(5)` |
|
|
25
|
-
| `findindex` | Finds the index of an element by key | `dphelper.array.findindex(array, 'name')` |
|
|
26
|
-
| `pathToJson` | Converts an array of paths into a JSON object | `dphelper.array.pathToJson(paths, '/')` |
|
|
27
|
-
| `deepClone` | Creates a deep clone using structuredClone | `dphelper.array.deepClone(array)` |
|
|
28
|
-
| `match` | Finds intersection between two arrays | `dphelper.array.match(arrA, arrB)` |
|
|
29
|
-
|
|
30
|
-
## Description
|
|
31
|
-
|
|
32
|
-
Comprehensive array manipulation library that provides utilities for:
|
|
33
|
-
- **Recursive operations** - Find, delete in nested structures
|
|
34
|
-
- **Merging** - Deep merge with prototype pollution protection
|
|
35
|
-
- **Filtering** - Even/odd numbers, duplicates
|
|
36
|
-
- **Sorting** - Ascending/descending order
|
|
37
|
-
- **Generation** - Random numbers, sequences
|
|
38
|
-
- **Conversion** - Array to object, paths to JSON
|
|
39
|
-
|
|
40
|
-
## Usage Examples
|
|
41
|
-
|
|
42
|
-
### Finding Elements in Nested Arrays
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
const data = [
|
|
46
|
-
{ id: 1, name: 'John', children: [{ id: 2, name: 'Jane' }] },
|
|
47
|
-
{ id: 3, name: 'Bob', children: [{ id: 4, name: 'Alice' }] }
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
// Find element with id 2
|
|
51
|
-
const found = dphelper.array.find(data, 2);
|
|
52
|
-
console.log(found); // { id: 2, name: 'Jane' }
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Deep Merging Objects
|
|
56
|
-
|
|
57
|
-
```javascript
|
|
58
|
-
const obj1 = { a: 1, b: { c: 2 } };
|
|
59
|
-
const obj2 = { b: { d: 3 }, e: 4 };
|
|
60
|
-
|
|
61
|
-
const merged = dphelper.array.merge(obj1, obj2);
|
|
62
|
-
console.log(merged); // { a: 1, b: { c: 2, d: 3 }, e: 4 }
|
|
63
|
-
|
|
64
|
-
// Safe from prototype pollution
|
|
65
|
-
const dangerous = { '__proto__': { dangerous: true } };
|
|
66
|
-
const safe = dphelper.array.merge({}, dangerous);
|
|
67
|
-
console.log(safe); // { __proto__: { dangerous: true } } - safe!
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### Merging Arrays by Key
|
|
71
|
-
|
|
72
|
-
```javascript
|
|
73
|
-
const users = [
|
|
74
|
-
{ id: 1, name: 'John', age: 30 },
|
|
75
|
-
{ id: 2, name: 'Jane', age: 25 }
|
|
76
|
-
];
|
|
77
|
-
|
|
78
|
-
const details = [
|
|
79
|
-
{ id: 1, email: 'john@example.com' },
|
|
80
|
-
{ id: 2, email: 'jane@example.com' }
|
|
81
|
-
];
|
|
82
|
-
|
|
83
|
-
const merged = dphelper.array.mergeByKey(users, details, 'id');
|
|
84
|
-
// Result: [{ id: 1, name: 'John', age: 30, email: 'john@example.com' }, ...]
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### Finding Duplicates
|
|
88
|
-
|
|
89
|
-
```javascript
|
|
90
|
-
const numbers = [1, 2, 3, 2, 4, 3, 5, 1];
|
|
91
|
-
const dups = dphelper.array.duplicates(numbers);
|
|
92
|
-
console.log(dups); // [2, 3, 1]
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### Filtering Even/Odd Numbers
|
|
96
|
-
|
|
97
|
-
```javascript
|
|
98
|
-
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
99
|
-
|
|
100
|
-
console.log(dphelper.array.even(numbers)); // [2, 4, 6, 8, 10]
|
|
101
|
-
console.log(dphelper.array.odd(numbers)); // [1, 3, 5, 7, 9]
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Sum Column in Multidimensional Array
|
|
105
|
-
|
|
106
|
-
```javascript
|
|
107
|
-
const matrix = [
|
|
108
|
-
[1, 2, 3], // row 0
|
|
109
|
-
[4, 5, 6], // row 1
|
|
110
|
-
[7, 8, 9] // row 2
|
|
111
|
-
];
|
|
112
|
-
|
|
113
|
-
// Sum first column (index 0)
|
|
114
|
-
console.log(dphelper.array.sumColumn(matrix, 0)); // 12 (1+4+7)
|
|
115
|
-
|
|
116
|
-
// Sum second column (index 1)
|
|
117
|
-
console.log(dphelper.array.sumColumn(matrix, 1)); // 15 (2+5+8)
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Shuffle Array (Fisher-Yates)
|
|
121
|
-
|
|
122
|
-
```javascript
|
|
123
|
-
const cards = ['A', 'B', 'C', 'D', 'E'];
|
|
124
|
-
const shuffled = dphelper.array.shuffle([...cards]);
|
|
125
|
-
console.log(shuffled); // Random order, e.g., ['C', 'A', 'E', 'D', 'B']
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Generate Random Number Sequence
|
|
129
|
-
|
|
130
|
-
```javascript
|
|
131
|
-
// Generate numbers 1-10 in random order
|
|
132
|
-
const sequence = dphelper.array.generate(10);
|
|
133
|
-
console.log(sequence); // e.g., [3, 1, 8, 5, 2, 9, 4, 7, 6, 10]
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
### Test for Consecutive Integers
|
|
137
|
-
|
|
138
|
-
```javascript
|
|
139
|
-
// Check for missing numbers in sequence [1, 2, 3, 4, 5]
|
|
140
|
-
console.log(dphelper.array.testArrayInt([1, 2, 3, 4, 5])); // [] (complete)
|
|
141
|
-
|
|
142
|
-
// Check for missing numbers in [1, 2, 4, 5]
|
|
143
|
-
console.log(dphelper.array.testArrayInt([1, 2, 4, 5])); // [3] (missing 3)
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Generate Random 32-bit Integers
|
|
147
|
-
|
|
148
|
-
```javascript
|
|
149
|
-
const randomNumbers = dphelper.array.rand32(5);
|
|
150
|
-
console.log(randomNumbers.nums); // [random1, random2, random3, random4, random5]
|
|
151
|
-
console.log(randomNumbers.time); // [execution time in ms]
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
### Path to JSON Conversion
|
|
155
|
-
|
|
156
|
-
```javascript
|
|
157
|
-
const paths = [
|
|
158
|
-
'/users/John',
|
|
159
|
-
'/users/John/profile',
|
|
160
|
-
'/users/John/settings',
|
|
161
|
-
'/users/Jane'
|
|
162
|
-
];
|
|
163
|
-
|
|
164
|
-
const json = dphelper.array.pathToJson(paths, '/');
|
|
165
|
-
// Result:
|
|
166
|
-
// {
|
|
167
|
-
// users: {
|
|
168
|
-
// John: {
|
|
169
|
-
// profile: null,
|
|
170
|
-
// settings: null
|
|
171
|
-
// },
|
|
172
|
-
// Jane: null
|
|
173
|
-
// }
|
|
174
|
-
// }
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Deep Clone Array
|
|
178
|
-
|
|
179
|
-
```javascript
|
|
180
|
-
const original = [{ a: 1 }, { b: 2 }];
|
|
181
|
-
const cloned = dphelper.array.deepClone(original);
|
|
182
|
-
|
|
183
|
-
cloned[0].a = 99;
|
|
184
|
-
console.log(original[0].a); // 1 (original unchanged)
|
|
185
|
-
console.log(cloned[0].a); // 99
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Find Array Intersection
|
|
189
|
-
|
|
190
|
-
```javascript
|
|
191
|
-
const words = ['apple', 'banana', 'cherry', 'date'];
|
|
192
|
-
const check = ['banana', 'date', 'elderberry'];
|
|
193
|
-
|
|
194
|
-
const matches = dphelper.array.match(words, check);
|
|
195
|
-
console.log(matches); // ['banana', 'date']
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Details
|
|
199
|
-
|
|
200
|
-
- **Author:** Dario Passariello
|
|
201
|
-
- **Version:** 0.0.2
|
|
202
|
-
- **Creation Date:** 20210101
|
|
203
|
-
- **Last Modified:** 20260220
|
|
204
|
-
- **Environment:** Works in both client and server environments
|
|
205
|
-
|
|
206
|
-
---
|
|
207
|
-
|
|
208
|
-
*Automatically generated document*
|
package/markdown/audio.md
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
# audio
|
|
2
|
-
|
|
3
|
-
Audio playback utilities for managing sound effects and background music in web applications.
|
|
4
|
-
|
|
5
|
-
## Functions
|
|
6
|
-
|
|
7
|
-
| Function | Description | Example |
|
|
8
|
-
|----------|-------------|---------|
|
|
9
|
-
| `play` | Plays an audio file or removes all audio elements | `dphelper.audio.play('notification.mp3', '/sounds/')` |
|
|
10
|
-
|
|
11
|
-
## Description
|
|
12
|
-
|
|
13
|
-
Simple audio management for web applications:
|
|
14
|
-
- **Play Sound** - Load and play audio files with optional looping
|
|
15
|
-
- **Stop All** - Remove all dpHelper audio elements from the DOM
|
|
16
|
-
- **Multiple Sounds** - Play different sounds simultaneously (each gets unique ID)
|
|
17
|
-
|
|
18
|
-
## Usage Examples
|
|
19
|
-
|
|
20
|
-
### Playing Sound Effects
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
// Play a simple notification sound
|
|
24
|
-
dphelper.audio.play('notification.mp3');
|
|
25
|
-
|
|
26
|
-
// Play with custom path
|
|
27
|
-
dphelper.audio.play('click.mp3', '/assets/sounds/');
|
|
28
|
-
|
|
29
|
-
// Loop background music
|
|
30
|
-
dphelper.audio.play('music.mp3', '/assets/audio/', true);
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Stopping Audio
|
|
34
|
-
|
|
35
|
-
```javascript
|
|
36
|
-
// Stop all dpHelper audio elements
|
|
37
|
-
dphelper.audio.play();
|
|
38
|
-
|
|
39
|
-
// This removes all audio tags created by dphelper.audio
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Complete Example
|
|
43
|
-
|
|
44
|
-
```javascript
|
|
45
|
-
// Sound manager class
|
|
46
|
-
class SoundManager {
|
|
47
|
-
constructor(soundPath = '/sounds/') {
|
|
48
|
-
this.path = soundPath;
|
|
49
|
-
this.enabled = true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
playSound(name, loop = false) {
|
|
53
|
-
if (!this.enabled) return;
|
|
54
|
-
dphelper.audio.play(name, this.path, loop);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
stopAll() {
|
|
58
|
-
dphelper.audio.play(); // No args = remove all
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
toggle(enabled) {
|
|
62
|
-
this.enabled = enabled;
|
|
63
|
-
if (!enabled) this.stopAll();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Usage
|
|
68
|
-
const sounds = new SoundManager('/assets/sounds/');
|
|
69
|
-
|
|
70
|
-
// Play various sounds
|
|
71
|
-
sounds.playSound('click.mp3');
|
|
72
|
-
sounds.playSound('notification.mp3');
|
|
73
|
-
sounds.playSound('background.mp3', true); // Loop
|
|
74
|
-
|
|
75
|
-
// Mute all
|
|
76
|
-
sounds.toggle(false);
|
|
77
|
-
|
|
78
|
-
// Unmute
|
|
79
|
-
sounds.toggle(true);
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### UI Sound Effects
|
|
83
|
-
|
|
84
|
-
```javascript
|
|
85
|
-
// Add sounds to UI interactions
|
|
86
|
-
document.querySelectorAll('button').forEach(btn => {
|
|
87
|
-
btn.addEventListener('click', () => {
|
|
88
|
-
dphelper.audio.play('click.mp3', '/sounds/');
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// Form submission
|
|
93
|
-
document.querySelector('form').addEventListener('submit', () => {
|
|
94
|
-
dphelper.audio.play('success.mp3', '/sounds/');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
// Error handling
|
|
98
|
-
function showError() {
|
|
99
|
-
dphelper.audio.play('error.mp3', '/sounds/');
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Details
|
|
104
|
-
|
|
105
|
-
- **Author:** Dario Passariello
|
|
106
|
-
- **Version:** 0.0.2
|
|
107
|
-
- **Creation Date:** 20240924
|
|
108
|
-
- **Last Modified:** 20240924
|
|
109
|
-
- **Environment:** Client-side only (browser)
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
*Automatically generated document*
|
package/markdown/avoid.md
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# avoid
|
|
2
|
-
|
|
3
|
-
Utilities for preventing caching issues in web applications.
|
|
4
|
-
|
|
5
|
-
## Functions
|
|
6
|
-
|
|
7
|
-
| Function | Description | Example |
|
|
8
|
-
|----------|-------------|---------|
|
|
9
|
-
| `cache` | Appends cache-busting query parameter to URL | `dphelper.avoid.cache('/api/data')` |
|
|
10
|
-
|
|
11
|
-
## Description
|
|
12
|
-
|
|
13
|
-
Prevents browser caching issues:
|
|
14
|
-
- **Cache Busting** - Add unique query params to URLs
|
|
15
|
-
|
|
16
|
-
## Usage Examples
|
|
17
|
-
|
|
18
|
-
### Cache Busting
|
|
19
|
-
|
|
20
|
-
```javascript
|
|
21
|
-
// Add unique query parameter to prevent caching
|
|
22
|
-
const url = '/api/users';
|
|
23
|
-
const uncachedUrl = dphelper.avoid.cache(url);
|
|
24
|
-
console.log(uncachedUrl); // "/api/users?t=abc123xyz"
|
|
25
|
-
|
|
26
|
-
// Useful for:
|
|
27
|
-
// - API calls that need fresh data
|
|
28
|
-
// - Dynamic content
|
|
29
|
-
// - Debugging (force reload)
|
|
30
|
-
dphelper.avoid.cache('/api/latest-data');
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Using with Fetch
|
|
34
|
-
|
|
35
|
-
```javascript
|
|
36
|
-
// Fetch with cache busting
|
|
37
|
-
async function fetchFresh(url) {
|
|
38
|
-
const response = await fetch(dphelper.avoid.cache(url));
|
|
39
|
-
return response.json();
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Details
|
|
44
|
-
|
|
45
|
-
- **Author:** Dario Passariello
|
|
46
|
-
- **Version:** 0.0.2
|
|
47
|
-
- **Creation Date:** 20210101
|
|
48
|
-
- **Last Modified:** 20260220
|
|
49
|
-
- **Environment:** Works in both client and server environments
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
*Automatically generated document*
|
package/markdown/biometric.md
DELETED
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
# biometric
|
|
2
|
-
|
|
3
|
-
WebAuthn and biometric authentication utilities for secure passwordless login using fingerprint, face recognition, and hardware security keys.
|
|
4
|
-
|
|
5
|
-
## Functions
|
|
6
|
-
|
|
7
|
-
| Function | Description | Example |
|
|
8
|
-
|----------|-------------|---------|
|
|
9
|
-
| `isAvailable` | Check if WebAuthn is available | `dphelper.biometric.isAvailable()` |
|
|
10
|
-
| `getWebAuthnSupport` | Get detailed support info | `dphelper.biometric.getWebAuthnSupport()` |
|
|
11
|
-
| `isSensorAvailable` | Check specific sensor (fingerprint/face/iris) | `await dphelper.biometric.isSensorAvailable('fingerprint')` |
|
|
12
|
-
| `register` | Register new credential | `await dphelper.biometric.register('user123', 'example.com')` |
|
|
13
|
-
| `authenticate` | Authenticate with credential | `await dphelper.biometric.authenticate('user123', 'example.com')` |
|
|
14
|
-
| `getCredential` | Get stored credential by ID | `dphelper.biometric.getCredential(credentialId)` |
|
|
15
|
-
| `deleteCredential` | Delete stored credential | `dphelper.biometric.deleteCredential(credentialId)` |
|
|
16
|
-
| `listCredentials` | List all stored credentials | `dphelper.biometric.listCredentials()` |
|
|
17
|
-
|
|
18
|
-
## Description
|
|
19
|
-
|
|
20
|
-
Secure biometric authentication module providing:
|
|
21
|
-
- **WebAuthn/FIDO2** - Industry-standard passwordless authentication
|
|
22
|
-
- **Platform Authenticators** - Fingerprint, Face ID, Windows Hello
|
|
23
|
-
- **Cross-platform** - Works with hardware security keys (YubiKey, etc.)
|
|
24
|
-
- **Credential Management** - Store, retrieve, and delete credentials
|
|
25
|
-
- **Sensor Detection** - Check availability of specific biometric types
|
|
26
|
-
|
|
27
|
-
## Usage Examples
|
|
28
|
-
|
|
29
|
-
### Checking Availability
|
|
30
|
-
|
|
31
|
-
```javascript
|
|
32
|
-
// Simple availability check
|
|
33
|
-
if (dphelper.biometric.isAvailable()) {
|
|
34
|
-
console.log('Biometric authentication is available!');
|
|
35
|
-
} else {
|
|
36
|
-
console.log('Biometric auth not supported');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Get detailed support information
|
|
40
|
-
const support = dphelper.biometric.getWebAuthnSupport();
|
|
41
|
-
console.log(support);
|
|
42
|
-
// {
|
|
43
|
-
// supported: true,
|
|
44
|
-
// platformAuthenticator: true,
|
|
45
|
-
// hybridTransport: false,
|
|
46
|
-
// uvToken: false
|
|
47
|
-
// }
|
|
48
|
-
|
|
49
|
-
// Check specific sensor
|
|
50
|
-
const hasFingerprint = await dphelper.biometric.isSensorAvailable('fingerprint');
|
|
51
|
-
const hasFace = await dphelper.biometric.isSensorAvailable('face');
|
|
52
|
-
console.log('Fingerprint:', hasFingerprint, 'Face:', hasFace);
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Registration (Enrolling a Credential)
|
|
56
|
-
|
|
57
|
-
```javascript
|
|
58
|
-
// Register a new biometric credential
|
|
59
|
-
async function registerUser(userId) {
|
|
60
|
-
if (!dphelper.biometric.isAvailable()) {
|
|
61
|
-
return { success: false, error: 'WebAuthn not supported' };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const result = await dphelper.biometric.register(
|
|
65
|
-
userId, // User ID
|
|
66
|
-
'example.com', // Relying Party ID (your domain)
|
|
67
|
-
'My App', // Relying Party Name
|
|
68
|
-
'john@example.com' // Display name
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
if (result.success) {
|
|
72
|
-
console.log('Registered! Credential ID:', result.credentialId);
|
|
73
|
-
// Store credentialId in your database for this user
|
|
74
|
-
} else {
|
|
75
|
-
console.error('Registration failed:', result.error);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return result;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Usage
|
|
82
|
-
const result = await registerUser('user_123');
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Authentication (Login)
|
|
86
|
-
|
|
87
|
-
```javascript
|
|
88
|
-
// Authenticate with stored credential
|
|
89
|
-
async function loginUser(userId, credentialId) {
|
|
90
|
-
if (!dphelper.biometric.isAvailable()) {
|
|
91
|
-
return { success: false, error: 'WebAuthn not supported' };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const result = await dphelper.biometric.authenticate(
|
|
95
|
-
userId, // User ID
|
|
96
|
-
'example.com', // Relying Party ID
|
|
97
|
-
credentialId // Optional: specific credential to use
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
if (result.success) {
|
|
101
|
-
console.log('Authentication successful!');
|
|
102
|
-
} else {
|
|
103
|
-
console.error('Authentication failed:', result.error);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return result;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Usage - login with known credential
|
|
110
|
-
const result = await loginUser('user_123', 'stored_credential_id');
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Credential Management
|
|
114
|
-
|
|
115
|
-
```javascript
|
|
116
|
-
// List all stored credentials
|
|
117
|
-
const credentials = dphelper.biometric.listCredentials();
|
|
118
|
-
console.log('Stored credentials:', credentials);
|
|
119
|
-
|
|
120
|
-
// Get a specific credential
|
|
121
|
-
const cred = dphelper.biometric.getCredential('credential_id_123');
|
|
122
|
-
console.log('Credential:', cred);
|
|
123
|
-
|
|
124
|
-
// Delete a credential
|
|
125
|
-
const deleted = dphelper.biometric.deleteCredential('credential_id_123');
|
|
126
|
-
console.log('Deleted:', deleted);
|
|
127
|
-
|
|
128
|
-
// After deletion
|
|
129
|
-
console.log('Remaining:', dphelper.biometric.listCredentials());
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Advanced Usage
|
|
133
|
-
|
|
134
|
-
### Complete Authentication System
|
|
135
|
-
|
|
136
|
-
```javascript
|
|
137
|
-
class BiometricAuth {
|
|
138
|
-
constructor(rpId, rpName) {
|
|
139
|
-
this.rpId = rpId;
|
|
140
|
-
this.rpName = rpName;
|
|
141
|
-
this.available = dphelper.biometric.isAvailable();
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async checkSupport() {
|
|
145
|
-
if (!this.available) {
|
|
146
|
-
return { supported: false, reason: 'WebAuthn not supported' };
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const support = dphelper.biometric.getWebAuthnSupport();
|
|
150
|
-
const fingerprint = await dphelper.biometric.isSensorAvailable('fingerprint');
|
|
151
|
-
const face = await dphelper.biometric.isSensorAvailable('face');
|
|
152
|
-
|
|
153
|
-
return {
|
|
154
|
-
supported: true,
|
|
155
|
-
platformAuthenticator: support.platformAuthenticator,
|
|
156
|
-
fingerprint,
|
|
157
|
-
face
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async register(userId, userName) {
|
|
162
|
-
if (!this.available) {
|
|
163
|
-
throw new Error('Biometric authentication not available');
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const result = await dphelper.biometric.register(
|
|
167
|
-
userId,
|
|
168
|
-
this.rpId,
|
|
169
|
-
this.rpName,
|
|
170
|
-
userName
|
|
171
|
-
);
|
|
172
|
-
|
|
173
|
-
if (result.success) {
|
|
174
|
-
// In production: save credentialId to your backend
|
|
175
|
-
console.log('Biometric registered:', result.credentialId);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return result;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async login(userId, credentialId) {
|
|
182
|
-
if (!this.available) {
|
|
183
|
-
throw new Error('Biometric authentication not available');
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return await dphelper.biometric.authenticate(
|
|
187
|
-
userId,
|
|
188
|
-
this.rpId,
|
|
189
|
-
credentialId
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
getStoredCredentials() {
|
|
194
|
-
return dphelper.biometric.listCredentials();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
removeCredential(credentialId) {
|
|
198
|
-
return dphelper.biometric.deleteCredential(credentialId);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Usage
|
|
203
|
-
const auth = new BiometricAuth('example.com', 'My Application');
|
|
204
|
-
|
|
205
|
-
// Check if biometric is available
|
|
206
|
-
const support = await auth.checkSupport();
|
|
207
|
-
if (support.supported) {
|
|
208
|
-
console.log('Biometric types available:', support);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Register new user
|
|
212
|
-
await auth.register('user_123', 'john@example.com');
|
|
213
|
-
|
|
214
|
-
// Login
|
|
215
|
-
const loginResult = await auth.login('user_123');
|
|
216
|
-
if (loginResult.success) {
|
|
217
|
-
console.log('Logged in with biometric!');
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Passwordless Login Flow
|
|
222
|
-
|
|
223
|
-
```javascript
|
|
224
|
-
// Frontend: Initiate passwordless login
|
|
225
|
-
async function initiatePasswordlessLogin() {
|
|
226
|
-
// 1. Check if biometric is available
|
|
227
|
-
if (!dphelper.biometric.isAvailable()) {
|
|
228
|
-
alert('Please use a supported browser');
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// 2. Get available credentials for this user
|
|
233
|
-
const credentials = dphelper.biometric.listCredentials();
|
|
234
|
-
|
|
235
|
-
if (credentials.length === 0) {
|
|
236
|
-
// No credentials - prompt to register
|
|
237
|
-
const register = confirm('No biometric credentials found. Register now?');
|
|
238
|
-
if (register) {
|
|
239
|
-
await registerNewUser();
|
|
240
|
-
}
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// 3. Attempt authentication with any stored credential
|
|
245
|
-
for (const credId of credentials) {
|
|
246
|
-
const result = await dphelper.biometric.authenticate(
|
|
247
|
-
'current_user',
|
|
248
|
-
window.location.hostname,
|
|
249
|
-
credId
|
|
250
|
-
);
|
|
251
|
-
|
|
252
|
-
if (result.success) {
|
|
253
|
-
// 4. Verify with server
|
|
254
|
-
await verifyWithServer(credId);
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
console.log('All credentials failed');
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Server verification (pseudo-code)
|
|
263
|
-
async function verifyWithServer(credentialId) {
|
|
264
|
-
const response = await fetch('/api/auth/verify', {
|
|
265
|
-
method: 'POST',
|
|
266
|
-
headers: { 'Content-Type': 'application/json' },
|
|
267
|
-
body: JSON.stringify({ credentialId })
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
if (response.ok) {
|
|
271
|
-
const { token } = await response.json();
|
|
272
|
-
localStorage.setItem('auth_token', token);
|
|
273
|
-
window.location.href = '/dashboard';
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Progressive Registration
|
|
279
|
-
|
|
280
|
-
```javascript
|
|
281
|
-
// Offer biometric as an option during existing login
|
|
282
|
-
async function offerBiometricUpgrade(userId, userName) {
|
|
283
|
-
const support = await dphelper.biometric.checkSupport();
|
|
284
|
-
|
|
285
|
-
if (!support.supported) {
|
|
286
|
-
console.log('Biometric not available on this device');
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// Show modal or prompt
|
|
291
|
-
const shouldRegister = confirm(
|
|
292
|
-
`Enable ${support.fingerprint ? 'fingerprint' : 'biometric'} login for faster access?`
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
if (shouldRegister) {
|
|
296
|
-
const result = await dphelper.biometric.register(
|
|
297
|
-
userId,
|
|
298
|
-
window.location.hostname,
|
|
299
|
-
'My App',
|
|
300
|
-
userName
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
if (result.success) {
|
|
304
|
-
// Save credential to user account
|
|
305
|
-
await saveCredentialToUser(userId, result.credentialId);
|
|
306
|
-
alert('Biometric authentication enabled!');
|
|
307
|
-
} else {
|
|
308
|
-
alert('Registration failed: ' + result.error);
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
## Security Notes
|
|
315
|
-
|
|
316
|
-
### WebAuthn Security Features
|
|
317
|
-
- **Public-key cryptography** - Uses asymmetric keys, never transmitted
|
|
318
|
-
- **User presence** - Requires user action (touch/face) to authenticate
|
|
319
|
-
- **Platform binding** - Credentials bound to specific device
|
|
320
|
-
- **Phishing resistance** - Relying Party ID must match exactly
|
|
321
|
-
|
|
322
|
-
### Best Practices
|
|
323
|
-
- Always verify authentication on the server side
|
|
324
|
-
- Store credential IDs in your database, not the credentials themselves
|
|
325
|
-
- Support multiple credentials per user (different devices)
|
|
326
|
-
- Provide fallback for unsupported browsers
|
|
327
|
-
|
|
328
|
-
## Details
|
|
329
|
-
|
|
330
|
-
- **Author:** Dario Passariello
|
|
331
|
-
- **Version:** 0.0.1
|
|
332
|
-
- **Creation Date:** 20260313
|
|
333
|
-
- **Last Modified:** 20260313
|
|
334
|
-
- **Environment:** Client-side only (browser with WebAuthn support)
|
|
335
|
-
|
|
336
|
-
---
|
|
337
|
-
|
|
338
|
-
*Automatically generated document*
|