@ekaone/nano-otp 0.0.1 → 0.1.2
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/LICENSE +20 -20
- package/README.md +246 -246
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +16 -15
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Eka Prasetia <ekaone3033@gmail.com> (https://prasetia.me)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Eka Prasetia <ekaone3033@gmail.com> (https://prasetia.me)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,247 +1,247 @@
|
|
|
1
|
-
# @ekaone/nano-otp
|
|
2
|
-
|
|
3
|
-
A tiny, zero-dependency One-Time Password (OTP) library for JavaScript and TypeScript.
|
|
4
|
-
|
|
5
|
-
**@ekaone/nano-otp** is designed to be lightweight, secure, and easy to integrate into modern applications. It uses Node.js built-in `crypto` for cryptographically secure random generation — no external dependencies required.
|
|
6
|
-
|
|
7
|
-
> ⚠️ **Status: Under Active Development**
|
|
8
|
-
> APIs and features may change before v1.0.0.
|
|
9
|
-
> Track progress at: https://github.com/ekaone/nano-otp
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# pnpm
|
|
17
|
-
pnpm add @ekaone/nano-otp
|
|
18
|
-
|
|
19
|
-
# npm
|
|
20
|
-
npm install @ekaone/nano-otp
|
|
21
|
-
|
|
22
|
-
# yarn
|
|
23
|
-
yarn add @ekaone/nano-otp
|
|
24
|
-
|
|
25
|
-
# bun
|
|
26
|
-
bun add @ekaone/nano-otp
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
### Generate an OTP
|
|
34
|
-
|
|
35
|
-
```javascript
|
|
36
|
-
import { generate } from "@ekaone/nano-otp";
|
|
37
|
-
|
|
38
|
-
// default: 6-digit numeric OTP
|
|
39
|
-
const otp = generate();
|
|
40
|
-
console.log(otp);
|
|
41
|
-
// => "482910"
|
|
42
|
-
|
|
43
|
-
// custom length
|
|
44
|
-
const otp8 = generate({ length: 8 });
|
|
45
|
-
console.log(otp8);
|
|
46
|
-
// => "30571846"
|
|
47
|
-
|
|
48
|
-
// alpha charset (uppercase letters)
|
|
49
|
-
const otpAlpha = generate({ charset: "alpha" });
|
|
50
|
-
console.log(otpAlpha);
|
|
51
|
-
// => "KXRTBM"
|
|
52
|
-
|
|
53
|
-
// alphanumeric charset
|
|
54
|
-
const otpAlphaNum = generate({ charset: "alphanumeric", length: 8 });
|
|
55
|
-
console.log(otpAlphaNum);
|
|
56
|
-
// => "4BX9K2RZ"
|
|
57
|
-
|
|
58
|
-
// custom charset
|
|
59
|
-
const otpCustom = generate({ charset: "ABCDEF0123", length: 6 });
|
|
60
|
-
console.log(otpCustom);
|
|
61
|
-
// => "C3A0FB"
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### Verify an OTP
|
|
65
|
-
|
|
66
|
-
```javascript
|
|
67
|
-
import { verify } from "@ekaone/nano-otp";
|
|
68
|
-
|
|
69
|
-
// basic match
|
|
70
|
-
const isValid = verify({ input: "482910", code: "482910" });
|
|
71
|
-
console.log(isValid);
|
|
72
|
-
// => true
|
|
73
|
-
|
|
74
|
-
// mismatch
|
|
75
|
-
const isInvalid = verify({ input: "000000", code: "482910" });
|
|
76
|
-
console.log(isInvalid);
|
|
77
|
-
// => false
|
|
78
|
-
|
|
79
|
-
// with expiry (expiresAt is a Unix timestamp in milliseconds)
|
|
80
|
-
const isValidWithExpiry = verify({
|
|
81
|
-
input: "482910",
|
|
82
|
-
code: "482910",
|
|
83
|
-
expiresAt: Date.now() + 5 * 60 * 1000, // expires in 5 minutes
|
|
84
|
-
});
|
|
85
|
-
console.log(isValidWithExpiry);
|
|
86
|
-
// => true
|
|
87
|
-
|
|
88
|
-
// expired OTP
|
|
89
|
-
const isExpired = verify({
|
|
90
|
-
input: "482910",
|
|
91
|
-
code: "482910",
|
|
92
|
-
expiresAt: Date.now() - 1000, // already expired
|
|
93
|
-
});
|
|
94
|
-
console.log(isExpired);
|
|
95
|
-
// => false
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### Generate a batch of OTPs
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
import { batch } from "@ekaone/nano-otp";
|
|
102
|
-
|
|
103
|
-
// generate 5 OTPs (may contain duplicates)
|
|
104
|
-
const otps = batch(5);
|
|
105
|
-
console.log(otps);
|
|
106
|
-
// => ["482910", "039471", "182930", "482910", "748201"]
|
|
107
|
-
|
|
108
|
-
// with options
|
|
109
|
-
const otpsAlpha = batch(3, { charset: "alpha", length: 8 });
|
|
110
|
-
console.log(otpsAlpha);
|
|
111
|
-
// => ["KXRTBMQZ", "LNVWACPD", "ERJHMKXB"]
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
### Generate a batch of unique OTPs
|
|
115
|
-
|
|
116
|
-
```javascript
|
|
117
|
-
import { batchUnique } from "@ekaone/nano-otp";
|
|
118
|
-
|
|
119
|
-
// generate 5 guaranteed-unique OTPs
|
|
120
|
-
const uniqueOtps = batchUnique(5);
|
|
121
|
-
console.log(uniqueOtps);
|
|
122
|
-
// => ["482910", "039471", "182930", "748201", "910284"]
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Full workflow example
|
|
126
|
-
|
|
127
|
-
```javascript
|
|
128
|
-
import { generate, verify } from "@ekaone/nano-otp";
|
|
129
|
-
|
|
130
|
-
// 1. generate and store OTP with a 10-minute expiry
|
|
131
|
-
const code = generate({ length: 6 });
|
|
132
|
-
const expiresAt = Date.now() + 10 * 60 * 1000;
|
|
133
|
-
|
|
134
|
-
console.log("Send this code to the user:", code);
|
|
135
|
-
// => "Send this code to the user: 482910"
|
|
136
|
-
|
|
137
|
-
// 2. later, verify what the user submitted
|
|
138
|
-
const userInput = "482910"; // submitted by user
|
|
139
|
-
|
|
140
|
-
const result = verify({ input: userInput, code, expiresAt });
|
|
141
|
-
console.log("Verification passed:", result);
|
|
142
|
-
// => "Verification passed: true"
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
|
|
147
|
-
## API
|
|
148
|
-
|
|
149
|
-
### `generate(options?)`
|
|
150
|
-
|
|
151
|
-
Generates a single cryptographically secure OTP.
|
|
152
|
-
|
|
153
|
-
```ts
|
|
154
|
-
generate(options?: OTPOptions): string
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
| Option | Type | Default | Description |
|
|
158
|
-
| --------- | ----------------------------------------- | ----------- | ---------------------------------------- |
|
|
159
|
-
| `length` | `number` | `6` | Length of the generated OTP |
|
|
160
|
-
| `charset` | `"numeric" \| "alpha" \| "alphanumeric" \| string` | `"numeric"` | Character set to use, or a custom string |
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
### `verify(options)`
|
|
165
|
-
|
|
166
|
-
Verifies an OTP using constant-time comparison to prevent timing attacks.
|
|
167
|
-
|
|
168
|
-
```ts
|
|
169
|
-
verify(options: VerifyOptions): boolean
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
| Option | Type | Required | Description |
|
|
173
|
-
| ----------- | -------- | -------- | -------------------------------------------------------- |
|
|
174
|
-
| `input` | `string` | ✅ | The OTP submitted by the user |
|
|
175
|
-
| `code` | `string` | ✅ | The original generated OTP to compare against |
|
|
176
|
-
| `expiresAt` | `number` | — | Unix timestamp (ms) after which the OTP is invalid |
|
|
177
|
-
| `now` | `number` | — | Override current time (ms) — useful for testing |
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
### `batch(count, options?)`
|
|
182
|
-
|
|
183
|
-
Generates multiple OTPs. May contain duplicates.
|
|
184
|
-
|
|
185
|
-
```ts
|
|
186
|
-
batch(count: number, options?: OTPOptions): string[]
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
| Parameter | Type | Description |
|
|
190
|
-
| --------- | ----------- | ---------------------------------- |
|
|
191
|
-
| `count` | `number` | Number of OTPs to generate |
|
|
192
|
-
| `options` | `OTPOptions`| Same options as `generate` |
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
### `batchUnique(count, options?)`
|
|
197
|
-
|
|
198
|
-
Generates multiple guaranteed-unique OTPs. Throws if the requested count exceeds the number of possible combinations for the given charset and length.
|
|
199
|
-
|
|
200
|
-
```ts
|
|
201
|
-
batchUnique(count: number, options?: OTPOptions): string[]
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
| Parameter | Type | Description |
|
|
205
|
-
| --------- | ------------ | ---------------------------------- |
|
|
206
|
-
| `count` | `number` | Number of unique OTPs to generate |
|
|
207
|
-
| `options` | `OTPOptions` | Same options as `generate` |
|
|
208
|
-
|
|
209
|
-
---
|
|
210
|
-
|
|
211
|
-
## Types
|
|
212
|
-
|
|
213
|
-
```ts
|
|
214
|
-
interface OTPOptions {
|
|
215
|
-
length?: number;
|
|
216
|
-
charset?: "numeric" | "alpha" | "alphanumeric" | string;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
interface VerifyOptions {
|
|
220
|
-
input: string;
|
|
221
|
-
code: string;
|
|
222
|
-
expiresAt?: number;
|
|
223
|
-
now?: number;
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
---
|
|
228
|
-
|
|
229
|
-
## Security
|
|
230
|
-
|
|
231
|
-
- Random generation uses Node.js `crypto.randomInt` — cryptographically secure, not `Math.random()`
|
|
232
|
-
- `verify` uses constant-time comparison (XOR-based) to prevent timing attacks
|
|
233
|
-
- Zero runtime dependencies — no supply chain risk from third-party packages
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## License
|
|
238
|
-
|
|
239
|
-
MIT © Eka Prasetia — see [LICENSE](./LICENSE) for details.
|
|
240
|
-
|
|
241
|
-
---
|
|
242
|
-
|
|
243
|
-
## Links
|
|
244
|
-
|
|
245
|
-
- [NPM Package](https://www.npmjs.com/package/@ekaone/nano-otp)
|
|
246
|
-
- [GitHub Repository](https://github.com/ekaone/nano-otp)
|
|
1
|
+
# @ekaone/nano-otp
|
|
2
|
+
|
|
3
|
+
A tiny, zero-dependency One-Time Password (OTP) library for JavaScript and TypeScript.
|
|
4
|
+
|
|
5
|
+
**@ekaone/nano-otp** is designed to be lightweight, secure, and easy to integrate into modern applications. It uses Node.js built-in `crypto` for cryptographically secure random generation — no external dependencies required.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Status: Under Active Development**
|
|
8
|
+
> APIs and features may change before v1.0.0.
|
|
9
|
+
> Track progress at: https://github.com/ekaone/nano-otp
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# pnpm
|
|
17
|
+
pnpm add @ekaone/nano-otp
|
|
18
|
+
|
|
19
|
+
# npm
|
|
20
|
+
npm install @ekaone/nano-otp
|
|
21
|
+
|
|
22
|
+
# yarn
|
|
23
|
+
yarn add @ekaone/nano-otp
|
|
24
|
+
|
|
25
|
+
# bun
|
|
26
|
+
bun add @ekaone/nano-otp
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Generate an OTP
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
import { generate } from "@ekaone/nano-otp";
|
|
37
|
+
|
|
38
|
+
// default: 6-digit numeric OTP
|
|
39
|
+
const otp = generate();
|
|
40
|
+
console.log(otp);
|
|
41
|
+
// => "482910"
|
|
42
|
+
|
|
43
|
+
// custom length
|
|
44
|
+
const otp8 = generate({ length: 8 });
|
|
45
|
+
console.log(otp8);
|
|
46
|
+
// => "30571846"
|
|
47
|
+
|
|
48
|
+
// alpha charset (uppercase letters)
|
|
49
|
+
const otpAlpha = generate({ charset: "alpha" });
|
|
50
|
+
console.log(otpAlpha);
|
|
51
|
+
// => "KXRTBM"
|
|
52
|
+
|
|
53
|
+
// alphanumeric charset
|
|
54
|
+
const otpAlphaNum = generate({ charset: "alphanumeric", length: 8 });
|
|
55
|
+
console.log(otpAlphaNum);
|
|
56
|
+
// => "4BX9K2RZ"
|
|
57
|
+
|
|
58
|
+
// custom charset
|
|
59
|
+
const otpCustom = generate({ charset: "ABCDEF0123", length: 6 });
|
|
60
|
+
console.log(otpCustom);
|
|
61
|
+
// => "C3A0FB"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Verify an OTP
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
import { verify } from "@ekaone/nano-otp";
|
|
68
|
+
|
|
69
|
+
// basic match
|
|
70
|
+
const isValid = verify({ input: "482910", code: "482910" });
|
|
71
|
+
console.log(isValid);
|
|
72
|
+
// => true
|
|
73
|
+
|
|
74
|
+
// mismatch
|
|
75
|
+
const isInvalid = verify({ input: "000000", code: "482910" });
|
|
76
|
+
console.log(isInvalid);
|
|
77
|
+
// => false
|
|
78
|
+
|
|
79
|
+
// with expiry (expiresAt is a Unix timestamp in milliseconds)
|
|
80
|
+
const isValidWithExpiry = verify({
|
|
81
|
+
input: "482910",
|
|
82
|
+
code: "482910",
|
|
83
|
+
expiresAt: Date.now() + 5 * 60 * 1000, // expires in 5 minutes
|
|
84
|
+
});
|
|
85
|
+
console.log(isValidWithExpiry);
|
|
86
|
+
// => true
|
|
87
|
+
|
|
88
|
+
// expired OTP
|
|
89
|
+
const isExpired = verify({
|
|
90
|
+
input: "482910",
|
|
91
|
+
code: "482910",
|
|
92
|
+
expiresAt: Date.now() - 1000, // already expired
|
|
93
|
+
});
|
|
94
|
+
console.log(isExpired);
|
|
95
|
+
// => false
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Generate a batch of OTPs
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
import { batch } from "@ekaone/nano-otp";
|
|
102
|
+
|
|
103
|
+
// generate 5 OTPs (may contain duplicates)
|
|
104
|
+
const otps = batch(5);
|
|
105
|
+
console.log(otps);
|
|
106
|
+
// => ["482910", "039471", "182930", "482910", "748201"]
|
|
107
|
+
|
|
108
|
+
// with options
|
|
109
|
+
const otpsAlpha = batch(3, { charset: "alpha", length: 8 });
|
|
110
|
+
console.log(otpsAlpha);
|
|
111
|
+
// => ["KXRTBMQZ", "LNVWACPD", "ERJHMKXB"]
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Generate a batch of unique OTPs
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
import { batchUnique } from "@ekaone/nano-otp";
|
|
118
|
+
|
|
119
|
+
// generate 5 guaranteed-unique OTPs
|
|
120
|
+
const uniqueOtps = batchUnique(5);
|
|
121
|
+
console.log(uniqueOtps);
|
|
122
|
+
// => ["482910", "039471", "182930", "748201", "910284"]
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Full workflow example
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
import { generate, verify } from "@ekaone/nano-otp";
|
|
129
|
+
|
|
130
|
+
// 1. generate and store OTP with a 10-minute expiry
|
|
131
|
+
const code = generate({ length: 6 });
|
|
132
|
+
const expiresAt = Date.now() + 10 * 60 * 1000;
|
|
133
|
+
|
|
134
|
+
console.log("Send this code to the user:", code);
|
|
135
|
+
// => "Send this code to the user: 482910"
|
|
136
|
+
|
|
137
|
+
// 2. later, verify what the user submitted
|
|
138
|
+
const userInput = "482910"; // submitted by user
|
|
139
|
+
|
|
140
|
+
const result = verify({ input: userInput, code, expiresAt });
|
|
141
|
+
console.log("Verification passed:", result);
|
|
142
|
+
// => "Verification passed: true"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## API
|
|
148
|
+
|
|
149
|
+
### `generate(options?)`
|
|
150
|
+
|
|
151
|
+
Generates a single cryptographically secure OTP.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
generate(options?: OTPOptions): string
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| Option | Type | Default | Description |
|
|
158
|
+
| --------- | ----------------------------------------- | ----------- | ---------------------------------------- |
|
|
159
|
+
| `length` | `number` | `6` | Length of the generated OTP |
|
|
160
|
+
| `charset` | `"numeric" \| "alpha" \| "alphanumeric" \| string` | `"numeric"` | Character set to use, or a custom string |
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
### `verify(options)`
|
|
165
|
+
|
|
166
|
+
Verifies an OTP using constant-time comparison to prevent timing attacks.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
verify(options: VerifyOptions): boolean
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
| Option | Type | Required | Description |
|
|
173
|
+
| ----------- | -------- | -------- | -------------------------------------------------------- |
|
|
174
|
+
| `input` | `string` | ✅ | The OTP submitted by the user |
|
|
175
|
+
| `code` | `string` | ✅ | The original generated OTP to compare against |
|
|
176
|
+
| `expiresAt` | `number` | — | Unix timestamp (ms) after which the OTP is invalid |
|
|
177
|
+
| `now` | `number` | — | Override current time (ms) — useful for testing |
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
### `batch(count, options?)`
|
|
182
|
+
|
|
183
|
+
Generates multiple OTPs. May contain duplicates.
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
batch(count: number, options?: OTPOptions): string[]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
| Parameter | Type | Description |
|
|
190
|
+
| --------- | ----------- | ---------------------------------- |
|
|
191
|
+
| `count` | `number` | Number of OTPs to generate |
|
|
192
|
+
| `options` | `OTPOptions`| Same options as `generate` |
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### `batchUnique(count, options?)`
|
|
197
|
+
|
|
198
|
+
Generates multiple guaranteed-unique OTPs. Throws if the requested count exceeds the number of possible combinations for the given charset and length.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
batchUnique(count: number, options?: OTPOptions): string[]
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
| Parameter | Type | Description |
|
|
205
|
+
| --------- | ------------ | ---------------------------------- |
|
|
206
|
+
| `count` | `number` | Number of unique OTPs to generate |
|
|
207
|
+
| `options` | `OTPOptions` | Same options as `generate` |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Types
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
interface OTPOptions {
|
|
215
|
+
length?: number;
|
|
216
|
+
charset?: "numeric" | "alpha" | "alphanumeric" | string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
interface VerifyOptions {
|
|
220
|
+
input: string;
|
|
221
|
+
code: string;
|
|
222
|
+
expiresAt?: number;
|
|
223
|
+
now?: number;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Security
|
|
230
|
+
|
|
231
|
+
- Random generation uses Node.js `crypto.randomInt` — cryptographically secure, not `Math.random()`
|
|
232
|
+
- `verify` uses constant-time comparison (XOR-based) to prevent timing attacks
|
|
233
|
+
- Zero runtime dependencies — no supply chain risk from third-party packages
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## License
|
|
238
|
+
|
|
239
|
+
MIT © Eka Prasetia — see [LICENSE](./LICENSE) for details.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Links
|
|
244
|
+
|
|
245
|
+
- [NPM Package](https://www.npmjs.com/package/@ekaone/nano-otp)
|
|
246
|
+
- [GitHub Repository](https://github.com/ekaone/nano-otp)
|
|
247
247
|
- [Issue Tracker](https://github.com/ekaone/nano-otp/issues)
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/core/generate.ts","../src/utils/resolveCharset.ts","../src/core/batch.ts","../src/utils/calculateMax.ts","../src/core/batchUnique.ts","../src/utils/safeCompare.ts","../src/core/verify.ts"],"sourcesContent":["/**\n * index.ts\n * @description Main entry point for the nano-otp package\n * @author Eka Prasetia\n * @date 2024-06-01\n * @version 1.0.0\n */\n\nimport { generate } from \"./core/generate\";\nimport { batch } from \"./core/batch\";\nimport { batchUnique } from \"./core/batchUnique\";\nimport { verify } from \"./core/verify\";\n\nexport const otp = {\n generate,\n batch,\n batchUnique,\n verify,\n};\n\nexport { generate, batch, batchUnique, verify };\nexport type { OTPOptions, VerifyOptions } from \"./types/otp.types\";\n","import { randomInt } from \"crypto\";\
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/generate.ts","../src/utils/resolveCharset.ts","../src/core/batch.ts","../src/utils/calculateMax.ts","../src/core/batchUnique.ts","../src/utils/safeCompare.ts","../src/core/verify.ts"],"sourcesContent":["/**\n * index.ts\n * @description Main entry point for the nano-otp package\n * @author Eka Prasetia\n * @date 2024-06-01\n * @version 1.0.0\n */\n\nimport { generate } from \"./core/generate\";\nimport { batch } from \"./core/batch\";\nimport { batchUnique } from \"./core/batchUnique\";\nimport { verify } from \"./core/verify\";\n\nexport const otp = {\n generate,\n batch,\n batchUnique,\n verify,\n};\n\nexport { generate, batch, batchUnique, verify };\nexport type { OTPOptions, VerifyOptions } from \"./types/otp.types\";\n","import { randomInt } from \"crypto\";\nimport type { OTPOptions } from \"../types/otp.types\";\nimport { resolveCharset } from \"../utils/resolveCharset\";\n\nexport function generate(options: OTPOptions = {}): string {\n const length = options.length ?? 6;\n\n if (!Number.isInteger(length) || length < 1) {\n throw new Error(\"length must be a positive integer\");\n }\n\n const charset = resolveCharset(options);\n\n if (charset.length === 0) {\n throw new Error(\"charset must not be empty\");\n }\n\n let result = \"\";\n\n for (let i = 0; i < length; i++) {\n result += charset[randomInt(0, charset.length)];\n }\n\n return result;\n}\n","import type { OTPOptions } from \"../types/otp.types\";\n\nconst NUMERIC = \"0123456789\";\nconst ALPHA = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nconst ALPHANUMERIC = NUMERIC + ALPHA;\n\nexport function resolveCharset(options: OTPOptions = {}): string {\n switch (options.charset) {\n case \"alpha\":\n return ALPHA;\n case \"alphanumeric\":\n return ALPHANUMERIC;\n case \"numeric\":\n return NUMERIC;\n default:\n // custom charset string passed directly\n if (typeof options.charset === \"string\") {\n if (options.charset.length === 0) {\n throw new Error(\"charset must not be empty\");\n }\n return options.charset;\n }\n // undefined → fallback to numeric\n return NUMERIC;\n }\n}\n","import type { OTPOptions } from \"../types/otp.types\";\nimport { generate } from \"./generate\";\n\nexport function batch(count: number, options: OTPOptions = {}): string[] {\n if (!Number.isInteger(count) || count <= 0) {\n throw new Error(\"batch count must be a positive integer\");\n }\n\n const results: string[] = [];\n\n for (let i = 0; i < count; i++) {\n results.push(generate(options));\n }\n\n return results;\n}\n","export function calculateMaxCombinations(\n charsetLength: number,\n length: number,\n): number {\n if (charsetLength < 1 || length < 1) {\n return 0;\n }\n\n // Math.pow can exceed Number.MAX_SAFE_INTEGER for large inputs\n // (e.g. charsetLength=62, length=20 → ~7×10^35).\n // Cap at MAX_SAFE_INTEGER to keep comparisons in batchUnique meaningful.\n const result = Math.pow(charsetLength, length);\n return Math.min(result, Number.MAX_SAFE_INTEGER);\n}\n","import type { OTPOptions } from \"../types/otp.types\";\nimport { generate } from \"./generate\";\nimport { resolveCharset } from \"../utils/resolveCharset\";\nimport { calculateMaxCombinations } from \"../utils/calculateMax\";\n\nexport function batchUnique(count: number, options: OTPOptions = {}): string[] {\n if (!Number.isInteger(count) || count <= 0) {\n throw new Error(\"batchUnique count must be a positive integer\");\n }\n\n const length = options.length ?? 6;\n const charset = resolveCharset(options);\n const max = calculateMaxCombinations(charset.length, length);\n\n if (count > max) {\n throw new Error(\n `Requested ${count} unique OTPs but only ${max} combinations possible with charset length ${charset.length} and OTP length ${length}`,\n );\n }\n\n const results = new Set<string>();\n\n // Note: performance degrades as count approaches max combinations due to\n // increasing collision rate. Consider a shuffle-based approach for\n // high-density requests (count > max * 0.8).\n while (results.size < count) {\n results.add(generate(options));\n }\n\n return Array.from(results);\n}\n","/**\n * Constant-time string comparison to prevent timing attacks.\n *\n * Iterates the full length of both strings regardless of where\n * a mismatch occurs, so execution time does not reveal how many\n * characters matched. Note: length difference is detectable via\n * timing, but OTP length is typically public knowledge so this\n * is an acceptable tradeoff.\n */\nexport function safeCompare(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n\n let result = 0;\n\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n\n return result === 0;\n}\n","import type { VerifyOptions } from \"../types/otp.types\";\nimport { safeCompare } from \"../utils/safeCompare\";\n\nexport function verify(options: VerifyOptions): boolean {\n const { input, code, expiresAt, now = Date.now() } = options;\n\n if (!input || !code) {\n return false;\n }\n\n if (expiresAt !== undefined && now > expiresAt) {\n return false;\n }\n\n return safeCompare(input, code);\n}\n"],"mappings":"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","names":["index_exports","__export","batch","batchUnique","generate","otp","verify","__toCommonJS","import_crypto","NUMERIC","ALPHA","ALPHANUMERIC","resolveCharset","options","generate","options","_a","length","charset","resolveCharset","result","batch","count","options","results","i","generate","calculateMaxCombinations","charsetLength","length","result","batchUnique","count","options","_a","length","charset","resolveCharset","max","calculateMaxCombinations","results","generate","safeCompare","a","b","result","i","verify","options","input","code","expiresAt","now","safeCompare","otp","generate","batch","batchUnique","verify"]}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/generate.ts","../src/utils/resolveCharset.ts","../src/core/batch.ts","../src/utils/calculateMax.ts","../src/core/batchUnique.ts","../src/utils/safeCompare.ts","../src/core/verify.ts","../src/index.ts"],"sourcesContent":["import { randomInt } from \"crypto\";\
|
|
1
|
+
{"version":3,"sources":["../src/core/generate.ts","../src/utils/resolveCharset.ts","../src/core/batch.ts","../src/utils/calculateMax.ts","../src/core/batchUnique.ts","../src/utils/safeCompare.ts","../src/core/verify.ts","../src/index.ts"],"sourcesContent":["import { randomInt } from \"crypto\";\nimport type { OTPOptions } from \"../types/otp.types\";\nimport { resolveCharset } from \"../utils/resolveCharset\";\n\nexport function generate(options: OTPOptions = {}): string {\n const length = options.length ?? 6;\n\n if (!Number.isInteger(length) || length < 1) {\n throw new Error(\"length must be a positive integer\");\n }\n\n const charset = resolveCharset(options);\n\n if (charset.length === 0) {\n throw new Error(\"charset must not be empty\");\n }\n\n let result = \"\";\n\n for (let i = 0; i < length; i++) {\n result += charset[randomInt(0, charset.length)];\n }\n\n return result;\n}\n","import type { OTPOptions } from \"../types/otp.types\";\n\nconst NUMERIC = \"0123456789\";\nconst ALPHA = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\nconst ALPHANUMERIC = NUMERIC + ALPHA;\n\nexport function resolveCharset(options: OTPOptions = {}): string {\n switch (options.charset) {\n case \"alpha\":\n return ALPHA;\n case \"alphanumeric\":\n return ALPHANUMERIC;\n case \"numeric\":\n return NUMERIC;\n default:\n // custom charset string passed directly\n if (typeof options.charset === \"string\") {\n if (options.charset.length === 0) {\n throw new Error(\"charset must not be empty\");\n }\n return options.charset;\n }\n // undefined → fallback to numeric\n return NUMERIC;\n }\n}\n","import type { OTPOptions } from \"../types/otp.types\";\nimport { generate } from \"./generate\";\n\nexport function batch(count: number, options: OTPOptions = {}): string[] {\n if (!Number.isInteger(count) || count <= 0) {\n throw new Error(\"batch count must be a positive integer\");\n }\n\n const results: string[] = [];\n\n for (let i = 0; i < count; i++) {\n results.push(generate(options));\n }\n\n return results;\n}\n","export function calculateMaxCombinations(\n charsetLength: number,\n length: number,\n): number {\n if (charsetLength < 1 || length < 1) {\n return 0;\n }\n\n // Math.pow can exceed Number.MAX_SAFE_INTEGER for large inputs\n // (e.g. charsetLength=62, length=20 → ~7×10^35).\n // Cap at MAX_SAFE_INTEGER to keep comparisons in batchUnique meaningful.\n const result = Math.pow(charsetLength, length);\n return Math.min(result, Number.MAX_SAFE_INTEGER);\n}\n","import type { OTPOptions } from \"../types/otp.types\";\nimport { generate } from \"./generate\";\nimport { resolveCharset } from \"../utils/resolveCharset\";\nimport { calculateMaxCombinations } from \"../utils/calculateMax\";\n\nexport function batchUnique(count: number, options: OTPOptions = {}): string[] {\n if (!Number.isInteger(count) || count <= 0) {\n throw new Error(\"batchUnique count must be a positive integer\");\n }\n\n const length = options.length ?? 6;\n const charset = resolveCharset(options);\n const max = calculateMaxCombinations(charset.length, length);\n\n if (count > max) {\n throw new Error(\n `Requested ${count} unique OTPs but only ${max} combinations possible with charset length ${charset.length} and OTP length ${length}`,\n );\n }\n\n const results = new Set<string>();\n\n // Note: performance degrades as count approaches max combinations due to\n // increasing collision rate. Consider a shuffle-based approach for\n // high-density requests (count > max * 0.8).\n while (results.size < count) {\n results.add(generate(options));\n }\n\n return Array.from(results);\n}\n","/**\n * Constant-time string comparison to prevent timing attacks.\n *\n * Iterates the full length of both strings regardless of where\n * a mismatch occurs, so execution time does not reveal how many\n * characters matched. Note: length difference is detectable via\n * timing, but OTP length is typically public knowledge so this\n * is an acceptable tradeoff.\n */\nexport function safeCompare(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n\n let result = 0;\n\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n\n return result === 0;\n}\n","import type { VerifyOptions } from \"../types/otp.types\";\nimport { safeCompare } from \"../utils/safeCompare\";\n\nexport function verify(options: VerifyOptions): boolean {\n const { input, code, expiresAt, now = Date.now() } = options;\n\n if (!input || !code) {\n return false;\n }\n\n if (expiresAt !== undefined && now > expiresAt) {\n return false;\n }\n\n return safeCompare(input, code);\n}\n","/**\n * index.ts\n * @description Main entry point for the nano-otp package\n * @author Eka Prasetia\n * @date 2024-06-01\n * @version 1.0.0\n */\n\nimport { generate } from \"./core/generate\";\nimport { batch } from \"./core/batch\";\nimport { batchUnique } from \"./core/batchUnique\";\nimport { verify } from \"./core/verify\";\n\nexport const otp = {\n generate,\n batch,\n batchUnique,\n verify,\n};\n\nexport { generate, batch, batchUnique, verify };\nexport type { OTPOptions, VerifyOptions } from \"./types/otp.types\";\n"],"mappings":"AAAA,OAAS,aAAAA,MAAiB,SCE1B,IAAMC,EAAU,aACVC,EAAQ,6BACRC,EAAeF,EAAUC,EAExB,SAASE,EAAeC,EAAsB,CAAC,EAAW,CAC/D,OAAQA,EAAQ,QAAS,CACvB,IAAK,QACH,OAAOH,EACT,IAAK,eACH,OAAOC,EACT,IAAK,UACH,OAAOF,EACT,QAEE,GAAI,OAAOI,EAAQ,SAAY,SAAU,CACvC,GAAIA,EAAQ,QAAQ,SAAW,EAC7B,MAAM,IAAI,MAAM,2BAA2B,EAE7C,OAAOA,EAAQ,OACjB,CAEA,OAAOJ,CACX,CACF,CDrBO,SAASK,EAASC,EAAsB,CAAC,EAAW,CAJ3D,IAAAC,EAKE,IAAMC,GAASD,EAAAD,EAAQ,SAAR,KAAAC,EAAkB,EAEjC,GAAI,CAAC,OAAO,UAAUC,CAAM,GAAKA,EAAS,EACxC,MAAM,IAAI,MAAM,mCAAmC,EAGrD,IAAMC,EAAUC,EAAeJ,CAAO,EAEtC,GAAIG,EAAQ,SAAW,EACrB,MAAM,IAAI,MAAM,2BAA2B,EAG7C,IAAIE,EAAS,GAEb,QAASC,EAAI,EAAGA,EAAIJ,EAAQI,IAC1BD,GAAUF,EAAQI,EAAU,EAAGJ,EAAQ,MAAM,CAAC,EAGhD,OAAOE,CACT,CErBO,SAASG,EAAMC,EAAeC,EAAsB,CAAC,EAAa,CACvE,GAAI,CAAC,OAAO,UAAUD,CAAK,GAAKA,GAAS,EACvC,MAAM,IAAI,MAAM,wCAAwC,EAG1D,IAAME,EAAoB,CAAC,EAE3B,QAASC,EAAI,EAAGA,EAAIH,EAAOG,IACzBD,EAAQ,KAAKE,EAASH,CAAO,CAAC,EAGhC,OAAOC,CACT,CCfO,SAASG,EACdC,EACAC,EACQ,CACR,GAAID,EAAgB,GAAKC,EAAS,EAChC,MAAO,GAMT,IAAMC,EAAS,KAAK,IAAIF,EAAeC,CAAM,EAC7C,OAAO,KAAK,IAAIC,EAAQ,OAAO,gBAAgB,CACjD,CCRO,SAASC,EAAYC,EAAeC,EAAsB,CAAC,EAAa,CAL/E,IAAAC,EAME,GAAI,CAAC,OAAO,UAAUF,CAAK,GAAKA,GAAS,EACvC,MAAM,IAAI,MAAM,8CAA8C,EAGhE,IAAMG,GAASD,EAAAD,EAAQ,SAAR,KAAAC,EAAkB,EAC3BE,EAAUC,EAAeJ,CAAO,EAChCK,EAAMC,EAAyBH,EAAQ,OAAQD,CAAM,EAE3D,GAAIH,EAAQM,EACV,MAAM,IAAI,MACR,aAAaN,CAAK,yBAAyBM,CAAG,8CAA8CF,EAAQ,MAAM,mBAAmBD,CAAM,EACrI,EAGF,IAAMK,EAAU,IAAI,IAKpB,KAAOA,EAAQ,KAAOR,GACpBQ,EAAQ,IAAIC,EAASR,CAAO,CAAC,EAG/B,OAAO,MAAM,KAAKO,CAAO,CAC3B,CCrBO,SAASE,EAAYC,EAAWC,EAAoB,CACzD,GAAID,EAAE,SAAWC,EAAE,OAAQ,MAAO,GAElC,IAAIC,EAAS,EAEb,QAASC,EAAI,EAAGA,EAAIH,EAAE,OAAQG,IAC5BD,GAAUF,EAAE,WAAWG,CAAC,EAAIF,EAAE,WAAWE,CAAC,EAG5C,OAAOD,IAAW,CACpB,CChBO,SAASE,EAAOC,EAAiC,CACtD,GAAM,CAAE,MAAAC,EAAO,KAAAC,EAAM,UAAAC,EAAW,IAAAC,EAAM,KAAK,IAAI,CAAE,EAAIJ,EAMrD,MAJI,CAACC,GAAS,CAACC,GAIXC,IAAc,QAAaC,EAAMD,EAC5B,GAGFE,EAAYJ,EAAOC,CAAI,CAChC,CCFO,IAAMI,EAAM,CACjB,SAAAC,EACA,MAAAC,EACA,YAAAC,EACA,OAAAC,CACF","names":["randomInt","NUMERIC","ALPHA","ALPHANUMERIC","resolveCharset","options","generate","options","_a","length","charset","resolveCharset","result","i","randomInt","batch","count","options","results","i","generate","calculateMaxCombinations","charsetLength","length","result","batchUnique","count","options","_a","length","charset","resolveCharset","max","calculateMaxCombinations","results","generate","safeCompare","a","b","result","i","verify","options","input","code","expiresAt","now","safeCompare","otp","generate","batch","batchUnique","verify"]}
|
package/package.json
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekaone/nano-otp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "A lightweight, zero-dependency TypeScript library for generating and validating OTPs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"otp",
|
|
7
|
-
"
|
|
7
|
+
"one-time-password",
|
|
8
|
+
"two-factor-authentication",
|
|
8
9
|
"2fa",
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"privacy",
|
|
10
|
+
"totp",
|
|
11
|
+
"authentication",
|
|
12
12
|
"security",
|
|
13
|
-
"
|
|
14
|
-
"data-protection",
|
|
13
|
+
"crypto",
|
|
15
14
|
"typescript",
|
|
16
|
-
"
|
|
17
|
-
"privacy",
|
|
18
|
-
"security",
|
|
19
|
-
"data-protection"
|
|
15
|
+
"zero-dependency"
|
|
20
16
|
],
|
|
21
17
|
"author": {
|
|
22
18
|
"name": "Eka Prasetia",
|
|
@@ -33,9 +29,14 @@
|
|
|
33
29
|
"types": "./dist/index.d.ts",
|
|
34
30
|
"exports": {
|
|
35
31
|
".": {
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/index.d.mts",
|
|
34
|
+
"default": "./dist/index.mjs"
|
|
35
|
+
},
|
|
36
|
+
"require": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"default": "./dist/index.js"
|
|
39
|
+
}
|
|
39
40
|
}
|
|
40
41
|
},
|
|
41
42
|
"publishConfig": {
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
],
|
|
47
48
|
"repository": {
|
|
48
49
|
"type": "git",
|
|
49
|
-
"url": "https://github.com/ekaone/nano-otp.git"
|
|
50
|
+
"url": "git+https://github.com/ekaone/nano-otp.git"
|
|
50
51
|
},
|
|
51
52
|
"bugs": {
|
|
52
53
|
"url": "https://github.com/ekaone/nano-otp/issues"
|