@otplib/uri 13.0.0

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gerald Yeo
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
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,270 @@
1
+ # @otplib/uri
2
+
3
+ Parse and generate `otpauth://` URIs for OTP account provisioning.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @otplib/uri
9
+ pnpm add @otplib/uri
10
+ yarn add @otplib/uri
11
+ ```
12
+
13
+ ## Overview
14
+
15
+ The `@otplib/uri` package provides utilities for working with `otpauth://` URIs - the standard format for sharing OTP account information. These URIs are commonly used in QR codes for authenticator app setup.
16
+
17
+ ### URI Format
18
+
19
+ ```
20
+ otpauth://TYPE/LABEL?PARAMETERS
21
+ ```
22
+
23
+ - **TYPE**: `totp` or `hotp`
24
+ - **LABEL**: `issuer:account` or just `account`
25
+ - **PARAMETERS**: `secret`, `issuer`, `algorithm`, `digits`, `period`/`counter`
26
+
27
+ Example:
28
+
29
+ ```
30
+ otpauth://totp/GitHub:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub
31
+ ```
32
+
33
+ ## Parsing URIs
34
+
35
+ ### Basic Parsing
36
+
37
+ ```typescript
38
+ import { parse } from "@otplib/uri";
39
+
40
+ const uri = "otpauth://totp/GitHub:user@example.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub";
41
+ const result = parse(uri);
42
+
43
+ console.log(result);
44
+ // {
45
+ // type: 'totp',
46
+ // label: 'GitHub:user@example.com',
47
+ // params: {
48
+ // secret: 'JBSWY3DPEHPK3PXP',
49
+ // issuer: 'GitHub',
50
+ // algorithm: 'sha1',
51
+ // digits: 6,
52
+ // period: 30
53
+ // }
54
+ // }
55
+ ```
56
+
57
+ ### Extracting Account Details
58
+
59
+ ```typescript
60
+ import { parse } from "@otplib/uri";
61
+
62
+ const uri = "otpauth://totp/ACME%20Corp:john@example.com?secret=JBSWY3DPEHPK3PXP";
63
+ const { label, params } = parse(uri);
64
+
65
+ // Split label to get issuer and account
66
+ const [issuer, account] = label.includes(":") ? label.split(":") : [params.issuer, label];
67
+
68
+ console.log("Issuer:", issuer); // 'ACME Corp'
69
+ console.log("Account:", account); // 'john@example.com'
70
+ console.log("Secret:", params.secret);
71
+ ```
72
+
73
+ ### Error Handling
74
+
75
+ ```typescript
76
+ import {
77
+ parse,
78
+ URIParseError,
79
+ InvalidURIError,
80
+ MissingParameterError,
81
+ InvalidParameterError,
82
+ } from "@otplib/uri";
83
+
84
+ try {
85
+ const result = parse("invalid-uri");
86
+ } catch (error) {
87
+ if (error instanceof InvalidURIError) {
88
+ console.error("Not a valid otpauth:// URI");
89
+ } else if (error instanceof MissingParameterError) {
90
+ console.error("Missing required parameter (e.g., secret)");
91
+ } else if (error instanceof InvalidParameterError) {
92
+ console.error("Invalid parameter value");
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Generating URIs
98
+
99
+ ### TOTP URI
100
+
101
+ ```typescript
102
+ import { generateTOTP } from "@otplib/uri";
103
+
104
+ const uri = generateTOTP({
105
+ issuer: "ACME Corp",
106
+ label: "john@example.com",
107
+ secret: "JBSWY3DPEHPK3PXP",
108
+ });
109
+
110
+ console.log(uri);
111
+ // 'otpauth://totp/ACME%20Corp:john@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ACME%20Corp'
112
+ ```
113
+
114
+ ### TOTP with Custom Options
115
+
116
+ ```typescript
117
+ import { generateTOTP } from "@otplib/uri";
118
+
119
+ const uri = generateTOTP({
120
+ issuer: "GitHub",
121
+ label: "user@github.com",
122
+ secret: "JBSWY3DPEHPK3PXP",
123
+ algorithm: "sha256", // Non-default algorithm
124
+ digits: 8, // 8-digit tokens
125
+ period: 60, // 60-second period
126
+ });
127
+ ```
128
+
129
+ ### HOTP URI
130
+
131
+ ```typescript
132
+ import { generateHOTP } from "@otplib/uri";
133
+
134
+ const uri = generateHOTP({
135
+ issuer: "MyApp",
136
+ label: "user123",
137
+ secret: "JBSWY3DPEHPK3PXP",
138
+ counter: 0, // Starting counter
139
+ });
140
+
141
+ console.log(uri);
142
+ // 'otpauth://hotp/MyApp:user123?secret=JBSWY3DPEHPK3PXP&issuer=MyApp&counter=0'
143
+ ```
144
+
145
+ ### Low-Level Generation
146
+
147
+ For more control, use the `generate` function directly:
148
+
149
+ ```typescript
150
+ import { generate } from "@otplib/uri";
151
+
152
+ const uri = generate({
153
+ type: "totp",
154
+ label: "CustomApp:user@example.com",
155
+ params: {
156
+ secret: "JBSWY3DPEHPK3PXP",
157
+ issuer: "CustomApp",
158
+ algorithm: "sha1",
159
+ digits: 6,
160
+ period: 30,
161
+ },
162
+ });
163
+ ```
164
+
165
+ ## Google Authenticator Compatibility
166
+
167
+ ::: warning Google Authenticator Limitations
168
+ Google Authenticator has specific requirements:
169
+
170
+ - Only supports `sha1` algorithm
171
+ - Only supports `6` or `8` digits
172
+ - Only supports `30` second period for TOTP
173
+ - Issuer should be included in both label and parameter
174
+ :::
175
+
176
+ ### Compatible URI
177
+
178
+ ```typescript
179
+ import { generateTOTP } from "@otplib/uri";
180
+
181
+ // This URI is fully compatible with Google Authenticator
182
+ const uri = generateTOTP({
183
+ issuer: "MyService",
184
+ label: "user@example.com",
185
+ secret: "JBSWY3DPEHPK3PXP",
186
+ // algorithm: 'sha1', // Default, compatible
187
+ // digits: 6, // Default, compatible
188
+ // period: 30, // Default, compatible
189
+ });
190
+ ```
191
+
192
+ ## QR Code Integration
193
+
194
+ Generate a QR code for the URI using any QR library:
195
+
196
+ ```typescript
197
+ import { generateTOTP } from "@otplib/uri";
198
+ import QRCode from "qrcode"; // Example library
199
+
200
+ const uri = generateTOTP({
201
+ issuer: "MyApp",
202
+ label: "user@example.com",
203
+ secret: "JBSWY3DPEHPK3PXP",
204
+ });
205
+
206
+ // Generate QR code as data URL
207
+ const qrDataUrl = await QRCode.toDataURL(uri);
208
+
209
+ // Or generate as SVG
210
+ const qrSvg = await QRCode.toString(uri, { type: "svg" });
211
+ ```
212
+
213
+ ## Type Definitions
214
+
215
+ ### OTPAuthURI
216
+
217
+ ```typescript
218
+ interface OTPAuthURI {
219
+ type: "hotp" | "totp";
220
+ label: string;
221
+ params: OTPAuthParams;
222
+ }
223
+ ```
224
+
225
+ ### OTPAuthParams
226
+
227
+ ```typescript
228
+ interface OTPAuthParams {
229
+ secret: string; // Required
230
+ issuer?: string; // Recommended
231
+ algorithm?: "sha1" | "sha256" | "sha512"; // Default: 'sha1'
232
+ digits?: 6 | 7 | 8; // Default: 6
233
+ counter?: number; // HOTP only
234
+ period?: number; // TOTP only, default: 30
235
+ }
236
+ ```
237
+
238
+ ### URIOptions
239
+
240
+ ```typescript
241
+ interface URIOptions {
242
+ issuer?: string;
243
+ label?: string;
244
+ secret: string;
245
+ algorithm?: "sha1" | "sha256" | "sha512";
246
+ digits?: 6 | 7 | 8;
247
+ period?: number; // TOTP only
248
+ counter?: number; // HOTP only
249
+ }
250
+ ```
251
+
252
+ ## Error Classes
253
+
254
+ | Error | Description |
255
+ | ----------------------- | -------------------------------------- |
256
+ | `URIParseError` | Base error for all URI parsing errors |
257
+ | `InvalidURIError` | URI format is invalid |
258
+ | `MissingParameterError` | Required parameter (secret) is missing |
259
+ | `InvalidParameterError` | Parameter value is invalid |
260
+
261
+ ## Documentation
262
+
263
+ Full documentation available at [otplib.yeojz.dev](https://otplib.yeojz.dev):
264
+
265
+ - [Getting Started Guide](https://otplib.yeojz.dev/guide/getting-started)
266
+ - [API Reference](https://otplib.yeojz.dev/api/)
267
+
268
+ ## License
269
+
270
+ [MIT](./LICENSE) © 2026 Gerald Yeo
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var m=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var x=Object.prototype.hasOwnProperty;var U=(t,e)=>{for(var s in e)m(t,s,{get:e[s],enumerable:!0})},R=(t,e,s,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of b(e))!x.call(t,i)&&i!==s&&m(t,i,{get:()=>e[i],enumerable:!(r=T(e,i))||r.enumerable});return t};var A=t=>R(m({},"__esModule",{value:!0}),t);var v={};U(v,{InvalidParameterError:()=>c,InvalidURIError:()=>a,MissingParameterError:()=>u,URIParseError:()=>l,generate:()=>h,generateHOTP:()=>O,generateTOTP:()=>y,parse:()=>d,parseURI:()=>d});module.exports=A(v);var l=class extends Error{constructor(e){super(e),this.name="URIParseError"}},a=class extends l{constructor(e){super(`Invalid otpauth URI: ${e}`),this.name="InvalidURIError"}},u=class extends l{constructor(e){super(`Missing required parameter: ${e}`),this.name="MissingParameterError"}},c=class extends l{constructor(e,s){super(`Invalid value for parameter '${e}': ${s}`),this.name="InvalidParameterError"}};var f=2048,I=512,w=1024;function $(t,e){let s=t instanceof Error?t.message:String(t);return`Invalid URI encoding in ${e}: ${s}`}function g(t,e,s){if(t.length>e*3)throw new a(`${s} exceeds maximum length`);try{let r=decodeURIComponent(t);if(r.length>e)throw new a(`${s} exceeds maximum length of ${e} characters`);return r}catch(r){throw r instanceof a?r:new a($(r,s))}}function d(t){if(t.length>f)throw new a(`URI exceeds maximum length of ${f} characters`);if(!t.startsWith("otpauth://"))throw new a(t);let e=t.slice(10),s=e.indexOf("/");if(s===-1)throw new a(t);let r=e.slice(0,s);if(r!=="hotp"&&r!=="totp")throw new c("type",r);let i=e.slice(s+1),o=i.indexOf("?"),n,p;o===-1?(n=g(i,I,"label"),p=""):(n=g(i.slice(0,o),I,"label"),p=i.slice(o+1));let P=H(p);return{type:r,label:n,params:P}}function H(t){let e={};if(!t)return e;let s=t.split("&");for(let r of s){let i=r.indexOf("=");if(i===-1)continue;let o=g(r.slice(0,i),64,"parameter key"),n=g(r.slice(i+1),w,`parameter '${o}'`);switch(o){case"secret":e.secret=n;break;case"issuer":e.issuer=n;break;case"algorithm":e.algorithm=E(n);break;case"digits":e.digits=k(n);break;case"counter":e.counter=parseInt(n,10);break;case"period":e.period=parseInt(n,10);break}}return e}function E(t){let e=t.toLowerCase();if(e==="sha1"||e==="sha-1")return"sha1";if(e==="sha256"||e==="sha-256")return"sha256";if(e==="sha512"||e==="sha-512")return"sha512";throw new c("algorithm",t)}function k(t){let e=parseInt(t,10);if(e===6||e===7||e===8)return e;throw new c("digits",t)}function h(t){let{type:e,label:s,params:r}=t,i=s.split(":").map(p=>encodeURIComponent(p)).join(":"),o=`otpauth://${e}/${i}?`,n=[];return r.secret&&n.push(`secret=${r.secret}`),r.issuer&&n.push(`issuer=${encodeURIComponent(r.issuer)}`),r.algorithm&&r.algorithm!=="sha1"&&n.push(`algorithm=${r.algorithm.toUpperCase()}`),r.digits&&r.digits!==6&&n.push(`digits=${r.digits}`),e==="hotp"&&r.counter!==void 0&&n.push(`counter=${r.counter}`),e==="totp"&&r.period!==void 0&&r.period!==30&&n.push(`period=${r.period}`),o+=n.join("&"),o}function y(t){let{issuer:e,label:s,secret:r,algorithm:i="sha1",digits:o=6,period:n=30}=t,p=e?`${e}:${s}`:s;return h({type:"totp",label:p,params:{secret:r,issuer:e,algorithm:i,digits:o,period:n}})}function O(t){let{issuer:e,label:s,secret:r,counter:i=0,algorithm:o="sha1",digits:n=6}=t,p=e?`${e}:${s}`:s;return h({type:"hotp",label:p,params:{secret:r,issuer:e,algorithm:o,digits:n,counter:i}})}0&&(module.exports={InvalidParameterError,InvalidURIError,MissingParameterError,URIParseError,generate,generateHOTP,generateTOTP,parse,parseURI});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/parse.ts","../src/generate.ts"],"sourcesContent":["export { parse, parse as parseURI } from \"./parse.js\";\n\nexport { generate, generateTOTP, generateHOTP } from \"./generate.js\";\nexport type { URIOptions, TOTPURIOptions, HOTPURIOptions } from \"./generate.js\";\n\nexport {\n URIParseError,\n InvalidURIError,\n MissingParameterError,\n InvalidParameterError,\n} from \"./types.js\";\n\nexport type { OTPAuthURI, OTPAuthParams, OTPType } from \"./types.js\";\n","import type { HashAlgorithm, Digits } from \"@otplib/core\";\n\n/**\n * OTP type (HOTP or TOTP)\n */\nexport type OTPType = \"hotp\" | \"totp\";\n\n/**\n * otpauth:// URI parameters\n */\nexport type OTPAuthParams = {\n /**\n * Base32-encoded shared secret (required)\n */\n readonly secret: string;\n\n /**\n * Service/provider name (recommended)\n */\n readonly issuer?: string;\n\n /**\n * Hash algorithm (default: sha1)\n * Note: Google Authenticator only supports sha1\n */\n readonly algorithm?: HashAlgorithm;\n\n /**\n * Number of digits (default: 6)\n * Google Authenticator supports 6 or 8\n */\n readonly digits?: Digits;\n\n /**\n * Initial counter value for HOTP (default: 0)\n */\n readonly counter?: number;\n\n /**\n * Time step in seconds for TOTP (default: 30)\n */\n readonly period?: number;\n};\n\n/**\n * otpauth:// URI structure\n */\nexport type OTPAuthURI = {\n /**\n * Type of OTP (hotp or totp)\n */\n readonly type: OTPType;\n\n /**\n * The label (typically: issuer:account or account)\n */\n readonly label: string;\n\n /**\n * Parameters from the URI\n */\n readonly params: OTPAuthParams;\n};\n\n/**\n * Error thrown when URI parsing fails\n */\nexport class URIParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"URIParseError\";\n }\n}\n\n/**\n * Error thrown when URI is invalid\n */\nexport class InvalidURIError extends URIParseError {\n constructor(uri: string) {\n super(`Invalid otpauth URI: ${uri}`);\n this.name = \"InvalidURIError\";\n }\n}\n\n/**\n * Error thrown when URI has missing required parameters\n */\nexport class MissingParameterError extends URIParseError {\n constructor(param: string) {\n super(`Missing required parameter: ${param}`);\n this.name = \"MissingParameterError\";\n }\n}\n\n/**\n * Error thrown when URI has invalid parameter value\n */\nexport class InvalidParameterError extends URIParseError {\n constructor(param: string, value: string) {\n super(`Invalid value for parameter '${param}': ${value}`);\n this.name = \"InvalidParameterError\";\n }\n}\n","import { InvalidURIError, InvalidParameterError } from \"./types.js\";\n\nimport type { OTPAuthURI, OTPAuthParams } from \"./types.js\";\nimport type { HashAlgorithm, Digits } from \"@otplib/core\";\n\n// Security limits to prevent DoS attacks\nconst MAX_URI_LENGTH = 2048; // Standard URL length limit\nconst MAX_LABEL_LENGTH = 512;\nconst MAX_PARAM_VALUE_LENGTH = 1024;\n\n/**\n * Format error message for caught errors\n * @internal\n */\nexport function formatErrorMessage(error: unknown, context: string): string {\n const errorStr = error instanceof Error ? error.message : String(error);\n return `Invalid URI encoding in ${context}: ${errorStr}`;\n}\n\n/**\n * Safely decode a URI component with length validation and error handling\n * @throws {InvalidURIError} If decoding fails or length exceeds limit\n */\nfunction safeDecodeURIComponent(str: string, maxLength: number, context: string): string {\n if (str.length > maxLength * 3) {\n throw new InvalidURIError(`${context} exceeds maximum length`);\n }\n\n try {\n const decoded = decodeURIComponent(str);\n if (decoded.length > maxLength) {\n throw new InvalidURIError(`${context} exceeds maximum length of ${maxLength} characters`);\n }\n return decoded;\n } catch (error) {\n if (error instanceof InvalidURIError) {\n throw error;\n }\n throw new InvalidURIError(formatErrorMessage(error, context));\n }\n}\n\n/**\n * Parse an otpauth:// URI into its components\n *\n * @param uri - The otpauth:// URI to parse\n * @returns Parsed URI components\n * @throws {InvalidURIError} If URI is invalid\n * @throws {MissingParameterError} If required parameters are missing\n * @throws {InvalidParameterError} If parameter values are invalid\n *\n * @example\n * ```ts\n * import { parse } from '@otplib/uri';\n *\n * const uri = 'otpauth://totp/ACME:john@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ACME';\n * const parsed = parse(uri);\n * // {\n * // type: 'totp',\n * // label: 'ACME:john@example.com',\n * // params: { secret: 'JBSWY3DPEHPK3PXP', issuer: 'ACME' }\n * // }\n * ```\n */\nexport function parse(uri: string): OTPAuthURI {\n if (uri.length > MAX_URI_LENGTH) {\n throw new InvalidURIError(`URI exceeds maximum length of ${MAX_URI_LENGTH} characters`);\n }\n\n if (!uri.startsWith(\"otpauth://\")) {\n throw new InvalidURIError(uri);\n }\n\n const withoutScheme = uri.slice(\"otpauth://\".length);\n const slashIndex = withoutScheme.indexOf(\"/\");\n\n if (slashIndex === -1) {\n throw new InvalidURIError(uri);\n }\n\n const type = withoutScheme.slice(0, slashIndex);\n if (type !== \"hotp\" && type !== \"totp\") {\n throw new InvalidParameterError(\"type\", type);\n }\n\n const remaining = withoutScheme.slice(slashIndex + 1);\n const queryIndex = remaining.indexOf(\"?\");\n\n let label: string;\n let queryString: string;\n\n if (queryIndex === -1) {\n label = safeDecodeURIComponent(remaining, MAX_LABEL_LENGTH, \"label\");\n queryString = \"\";\n } else {\n label = safeDecodeURIComponent(remaining.slice(0, queryIndex), MAX_LABEL_LENGTH, \"label\");\n queryString = remaining.slice(queryIndex + 1);\n }\n\n const params = parseQueryString(queryString);\n\n return {\n type,\n label,\n params,\n };\n}\n\n/**\n * Parse query string into parameters object\n */\nfunction parseQueryString(queryString: string): OTPAuthParams {\n // Use mutable type during construction\n const params: {\n secret?: string;\n issuer?: string;\n algorithm?: HashAlgorithm;\n digits?: Digits;\n counter?: number;\n period?: number;\n } = {};\n\n if (!queryString) {\n return params as OTPAuthParams;\n }\n\n const pairs = queryString.split(\"&\");\n for (const pair of pairs) {\n const equalIndex = pair.indexOf(\"=\");\n if (equalIndex === -1) {\n continue;\n }\n\n const key = safeDecodeURIComponent(pair.slice(0, equalIndex), 64, \"parameter key\");\n const value = safeDecodeURIComponent(\n pair.slice(equalIndex + 1),\n MAX_PARAM_VALUE_LENGTH,\n `parameter '${key}'`,\n );\n\n switch (key) {\n case \"secret\":\n params.secret = value;\n break;\n case \"issuer\":\n params.issuer = value;\n break;\n case \"algorithm\":\n params.algorithm = parseAlgorithm(value);\n break;\n case \"digits\":\n params.digits = parseDigits(value);\n break;\n case \"counter\":\n params.counter = parseInt(value, 10);\n break;\n case \"period\":\n params.period = parseInt(value, 10);\n break;\n }\n }\n\n return params as OTPAuthParams;\n}\n\n/**\n * Parse algorithm string\n */\nfunction parseAlgorithm(value: string): HashAlgorithm {\n const normalized = value.toLowerCase();\n if (normalized === \"sha1\" || normalized === \"sha-1\") {\n return \"sha1\";\n }\n if (normalized === \"sha256\" || normalized === \"sha-256\") {\n return \"sha256\";\n }\n if (normalized === \"sha512\" || normalized === \"sha-512\") {\n return \"sha512\";\n }\n throw new InvalidParameterError(\"algorithm\", value);\n}\n\n/**\n * Parse digits string\n */\nfunction parseDigits(value: string): Digits {\n const digits = parseInt(value, 10);\n if (digits === 6 || digits === 7 || digits === 8) {\n return digits;\n }\n throw new InvalidParameterError(\"digits\", value);\n}\n","import type { OTPAuthURI } from \"./types.js\";\nimport type { HashAlgorithm, Digits } from \"@otplib/core\";\n\n/**\n * Base options for URI generation\n */\nexport type URIOptions = {\n /**\n * Service/provider name (e.g., 'ACME Co', 'GitHub', 'AWS')\n */\n issuer?: string;\n\n /**\n * Account identifier (e.g., email, username)\n */\n label?: string;\n\n /**\n * Base32-encoded secret key\n */\n secret: string;\n\n /**\n * Hash algorithm (default: 'sha1')\n * Note: Google Authenticator only supports sha1\n */\n algorithm?: HashAlgorithm;\n\n /**\n * Number of digits (default: 6)\n * Google Authenticator supports 6 or 8, RFC also allows 7\n */\n digits?: Digits;\n\n /**\n * Time step in seconds for TOTP (default: 30)\n */\n period?: number;\n\n /**\n * Counter value for HOTP\n */\n counter?: number;\n};\n\n/**\n * TOTP-specific URI options\n */\nexport type TOTPURIOptions = URIOptions & {\n period?: number;\n counter?: never;\n};\n\n/**\n * HOTP-specific URI options\n */\nexport type HOTPURIOptions = URIOptions & {\n period?: never;\n counter?: number;\n};\n\n/**\n * Generate an otpauth:// URI\n *\n * @param uri - The URI components\n * @returns The otpauth:// URI string\n *\n * @example\n * ```ts\n * import { generate } from '@otplib/uri';\n * import { encode } from '@otplib/base32';\n *\n * const secret = encode(new Uint8Array([1, 2, 3, 4, 5]));\n *\n * const uri = generate({\n * type: 'totp',\n * label: 'ACME:john@example.com',\n * params: {\n * secret,\n * issuer: 'ACME',\n * algorithm: 'sha1',\n * digits: 6,\n * },\n * });\n * // Returns: 'otpauth://totp/ACME:john%40example.com?secret=...'\n * ```\n */\nexport function generate(uri: OTPAuthURI): string {\n const { type, label, params } = uri;\n\n // Encode label parts while preserving ':' as the issuer/account separator\n const encodedLabel = label\n .split(\":\")\n .map((part) => encodeURIComponent(part))\n .join(\":\");\n\n let result = `otpauth://${type}/${encodedLabel}?`;\n\n const queryParams: string[] = [];\n\n if (params.secret) {\n queryParams.push(`secret=${params.secret}`);\n }\n\n if (params.issuer) {\n queryParams.push(`issuer=${encodeURIComponent(params.issuer)}`);\n }\n\n if (params.algorithm && params.algorithm !== \"sha1\") {\n queryParams.push(`algorithm=${params.algorithm.toUpperCase()}`);\n }\n\n if (params.digits && params.digits !== 6) {\n queryParams.push(`digits=${params.digits}`);\n }\n\n if (type === \"hotp\" && params.counter !== undefined) {\n queryParams.push(`counter=${params.counter}`);\n }\n\n if (type === \"totp\" && params.period !== undefined && params.period !== 30) {\n queryParams.push(`period=${params.period}`);\n }\n\n result += queryParams.join(\"&\");\n\n return result;\n}\n\n/**\n * Generate a TOTP otpauth:// URI with simplified parameters\n *\n * @param options - TOTP URI generation options\n * @returns The otpauth:// URI string\n */\nexport function generateTOTP(options: TOTPURIOptions & { issuer: string; label: string }): string {\n const { issuer, label: account, secret, algorithm = \"sha1\", digits = 6, period = 30 } = options;\n\n const fullLabel = issuer ? `${issuer}:${account}` : account;\n\n return generate({\n type: \"totp\",\n label: fullLabel,\n params: {\n secret,\n issuer,\n algorithm,\n digits,\n period,\n },\n });\n}\n\n/**\n * Generate a HOTP otpauth:// URI with simplified parameters\n *\n * @param options - HOTP URI generation options\n * @returns The otpauth:// URI string\n */\nexport function generateHOTP(options: HOTPURIOptions & { issuer: string; label: string }): string {\n const { issuer, label: account, secret, counter = 0, algorithm = \"sha1\", digits = 6 } = options;\n\n const fullLabel = issuer ? `${issuer}:${account}` : account;\n\n return generate({\n type: \"hotp\",\n label: fullLabel,\n params: {\n secret,\n issuer,\n algorithm,\n digits,\n counter,\n },\n });\n}\n"],"mappings":"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","names":["index_exports","__export","InvalidParameterError","InvalidURIError","MissingParameterError","URIParseError","generate","generateHOTP","generateTOTP","parse","__toCommonJS","URIParseError","message","InvalidURIError","uri","MissingParameterError","param","InvalidParameterError","value","MAX_URI_LENGTH","MAX_LABEL_LENGTH","MAX_PARAM_VALUE_LENGTH","formatErrorMessage","error","context","errorStr","safeDecodeURIComponent","str","maxLength","InvalidURIError","decoded","parse","uri","withoutScheme","slashIndex","type","InvalidParameterError","remaining","queryIndex","label","queryString","params","parseQueryString","pairs","pair","equalIndex","key","value","parseAlgorithm","parseDigits","normalized","digits","generate","uri","type","label","params","encodedLabel","part","result","queryParams","generateTOTP","options","issuer","account","secret","algorithm","digits","period","fullLabel","generateHOTP","counter"]}
@@ -0,0 +1,201 @@
1
+ import { HashAlgorithm, Digits } from '@otplib/core';
2
+
3
+ /**
4
+ * OTP type (HOTP or TOTP)
5
+ */
6
+ type OTPType = "hotp" | "totp";
7
+ /**
8
+ * otpauth:// URI parameters
9
+ */
10
+ type OTPAuthParams = {
11
+ /**
12
+ * Base32-encoded shared secret (required)
13
+ */
14
+ readonly secret: string;
15
+ /**
16
+ * Service/provider name (recommended)
17
+ */
18
+ readonly issuer?: string;
19
+ /**
20
+ * Hash algorithm (default: sha1)
21
+ * Note: Google Authenticator only supports sha1
22
+ */
23
+ readonly algorithm?: HashAlgorithm;
24
+ /**
25
+ * Number of digits (default: 6)
26
+ * Google Authenticator supports 6 or 8
27
+ */
28
+ readonly digits?: Digits;
29
+ /**
30
+ * Initial counter value for HOTP (default: 0)
31
+ */
32
+ readonly counter?: number;
33
+ /**
34
+ * Time step in seconds for TOTP (default: 30)
35
+ */
36
+ readonly period?: number;
37
+ };
38
+ /**
39
+ * otpauth:// URI structure
40
+ */
41
+ type OTPAuthURI = {
42
+ /**
43
+ * Type of OTP (hotp or totp)
44
+ */
45
+ readonly type: OTPType;
46
+ /**
47
+ * The label (typically: issuer:account or account)
48
+ */
49
+ readonly label: string;
50
+ /**
51
+ * Parameters from the URI
52
+ */
53
+ readonly params: OTPAuthParams;
54
+ };
55
+ /**
56
+ * Error thrown when URI parsing fails
57
+ */
58
+ declare class URIParseError extends Error {
59
+ constructor(message: string);
60
+ }
61
+ /**
62
+ * Error thrown when URI is invalid
63
+ */
64
+ declare class InvalidURIError extends URIParseError {
65
+ constructor(uri: string);
66
+ }
67
+ /**
68
+ * Error thrown when URI has missing required parameters
69
+ */
70
+ declare class MissingParameterError extends URIParseError {
71
+ constructor(param: string);
72
+ }
73
+ /**
74
+ * Error thrown when URI has invalid parameter value
75
+ */
76
+ declare class InvalidParameterError extends URIParseError {
77
+ constructor(param: string, value: string);
78
+ }
79
+
80
+ /**
81
+ * Parse an otpauth:// URI into its components
82
+ *
83
+ * @param uri - The otpauth:// URI to parse
84
+ * @returns Parsed URI components
85
+ * @throws {InvalidURIError} If URI is invalid
86
+ * @throws {MissingParameterError} If required parameters are missing
87
+ * @throws {InvalidParameterError} If parameter values are invalid
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import { parse } from '@otplib/uri';
92
+ *
93
+ * const uri = 'otpauth://totp/ACME:john@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ACME';
94
+ * const parsed = parse(uri);
95
+ * // {
96
+ * // type: 'totp',
97
+ * // label: 'ACME:john@example.com',
98
+ * // params: { secret: 'JBSWY3DPEHPK3PXP', issuer: 'ACME' }
99
+ * // }
100
+ * ```
101
+ */
102
+ declare function parse(uri: string): OTPAuthURI;
103
+
104
+ /**
105
+ * Base options for URI generation
106
+ */
107
+ type URIOptions = {
108
+ /**
109
+ * Service/provider name (e.g., 'ACME Co', 'GitHub', 'AWS')
110
+ */
111
+ issuer?: string;
112
+ /**
113
+ * Account identifier (e.g., email, username)
114
+ */
115
+ label?: string;
116
+ /**
117
+ * Base32-encoded secret key
118
+ */
119
+ secret: string;
120
+ /**
121
+ * Hash algorithm (default: 'sha1')
122
+ * Note: Google Authenticator only supports sha1
123
+ */
124
+ algorithm?: HashAlgorithm;
125
+ /**
126
+ * Number of digits (default: 6)
127
+ * Google Authenticator supports 6 or 8, RFC also allows 7
128
+ */
129
+ digits?: Digits;
130
+ /**
131
+ * Time step in seconds for TOTP (default: 30)
132
+ */
133
+ period?: number;
134
+ /**
135
+ * Counter value for HOTP
136
+ */
137
+ counter?: number;
138
+ };
139
+ /**
140
+ * TOTP-specific URI options
141
+ */
142
+ type TOTPURIOptions = URIOptions & {
143
+ period?: number;
144
+ counter?: never;
145
+ };
146
+ /**
147
+ * HOTP-specific URI options
148
+ */
149
+ type HOTPURIOptions = URIOptions & {
150
+ period?: never;
151
+ counter?: number;
152
+ };
153
+ /**
154
+ * Generate an otpauth:// URI
155
+ *
156
+ * @param uri - The URI components
157
+ * @returns The otpauth:// URI string
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * import { generate } from '@otplib/uri';
162
+ * import { encode } from '@otplib/base32';
163
+ *
164
+ * const secret = encode(new Uint8Array([1, 2, 3, 4, 5]));
165
+ *
166
+ * const uri = generate({
167
+ * type: 'totp',
168
+ * label: 'ACME:john@example.com',
169
+ * params: {
170
+ * secret,
171
+ * issuer: 'ACME',
172
+ * algorithm: 'sha1',
173
+ * digits: 6,
174
+ * },
175
+ * });
176
+ * // Returns: 'otpauth://totp/ACME:john%40example.com?secret=...'
177
+ * ```
178
+ */
179
+ declare function generate(uri: OTPAuthURI): string;
180
+ /**
181
+ * Generate a TOTP otpauth:// URI with simplified parameters
182
+ *
183
+ * @param options - TOTP URI generation options
184
+ * @returns The otpauth:// URI string
185
+ */
186
+ declare function generateTOTP(options: TOTPURIOptions & {
187
+ issuer: string;
188
+ label: string;
189
+ }): string;
190
+ /**
191
+ * Generate a HOTP otpauth:// URI with simplified parameters
192
+ *
193
+ * @param options - HOTP URI generation options
194
+ * @returns The otpauth:// URI string
195
+ */
196
+ declare function generateHOTP(options: HOTPURIOptions & {
197
+ issuer: string;
198
+ label: string;
199
+ }): string;
200
+
201
+ export { type HOTPURIOptions, InvalidParameterError, InvalidURIError, MissingParameterError, type OTPAuthParams, type OTPAuthURI, type OTPType, type TOTPURIOptions, type URIOptions, URIParseError, generate, generateHOTP, generateTOTP, parse, parse as parseURI };
@@ -0,0 +1,201 @@
1
+ import { HashAlgorithm, Digits } from '@otplib/core';
2
+
3
+ /**
4
+ * OTP type (HOTP or TOTP)
5
+ */
6
+ type OTPType = "hotp" | "totp";
7
+ /**
8
+ * otpauth:// URI parameters
9
+ */
10
+ type OTPAuthParams = {
11
+ /**
12
+ * Base32-encoded shared secret (required)
13
+ */
14
+ readonly secret: string;
15
+ /**
16
+ * Service/provider name (recommended)
17
+ */
18
+ readonly issuer?: string;
19
+ /**
20
+ * Hash algorithm (default: sha1)
21
+ * Note: Google Authenticator only supports sha1
22
+ */
23
+ readonly algorithm?: HashAlgorithm;
24
+ /**
25
+ * Number of digits (default: 6)
26
+ * Google Authenticator supports 6 or 8
27
+ */
28
+ readonly digits?: Digits;
29
+ /**
30
+ * Initial counter value for HOTP (default: 0)
31
+ */
32
+ readonly counter?: number;
33
+ /**
34
+ * Time step in seconds for TOTP (default: 30)
35
+ */
36
+ readonly period?: number;
37
+ };
38
+ /**
39
+ * otpauth:// URI structure
40
+ */
41
+ type OTPAuthURI = {
42
+ /**
43
+ * Type of OTP (hotp or totp)
44
+ */
45
+ readonly type: OTPType;
46
+ /**
47
+ * The label (typically: issuer:account or account)
48
+ */
49
+ readonly label: string;
50
+ /**
51
+ * Parameters from the URI
52
+ */
53
+ readonly params: OTPAuthParams;
54
+ };
55
+ /**
56
+ * Error thrown when URI parsing fails
57
+ */
58
+ declare class URIParseError extends Error {
59
+ constructor(message: string);
60
+ }
61
+ /**
62
+ * Error thrown when URI is invalid
63
+ */
64
+ declare class InvalidURIError extends URIParseError {
65
+ constructor(uri: string);
66
+ }
67
+ /**
68
+ * Error thrown when URI has missing required parameters
69
+ */
70
+ declare class MissingParameterError extends URIParseError {
71
+ constructor(param: string);
72
+ }
73
+ /**
74
+ * Error thrown when URI has invalid parameter value
75
+ */
76
+ declare class InvalidParameterError extends URIParseError {
77
+ constructor(param: string, value: string);
78
+ }
79
+
80
+ /**
81
+ * Parse an otpauth:// URI into its components
82
+ *
83
+ * @param uri - The otpauth:// URI to parse
84
+ * @returns Parsed URI components
85
+ * @throws {InvalidURIError} If URI is invalid
86
+ * @throws {MissingParameterError} If required parameters are missing
87
+ * @throws {InvalidParameterError} If parameter values are invalid
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import { parse } from '@otplib/uri';
92
+ *
93
+ * const uri = 'otpauth://totp/ACME:john@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ACME';
94
+ * const parsed = parse(uri);
95
+ * // {
96
+ * // type: 'totp',
97
+ * // label: 'ACME:john@example.com',
98
+ * // params: { secret: 'JBSWY3DPEHPK3PXP', issuer: 'ACME' }
99
+ * // }
100
+ * ```
101
+ */
102
+ declare function parse(uri: string): OTPAuthURI;
103
+
104
+ /**
105
+ * Base options for URI generation
106
+ */
107
+ type URIOptions = {
108
+ /**
109
+ * Service/provider name (e.g., 'ACME Co', 'GitHub', 'AWS')
110
+ */
111
+ issuer?: string;
112
+ /**
113
+ * Account identifier (e.g., email, username)
114
+ */
115
+ label?: string;
116
+ /**
117
+ * Base32-encoded secret key
118
+ */
119
+ secret: string;
120
+ /**
121
+ * Hash algorithm (default: 'sha1')
122
+ * Note: Google Authenticator only supports sha1
123
+ */
124
+ algorithm?: HashAlgorithm;
125
+ /**
126
+ * Number of digits (default: 6)
127
+ * Google Authenticator supports 6 or 8, RFC also allows 7
128
+ */
129
+ digits?: Digits;
130
+ /**
131
+ * Time step in seconds for TOTP (default: 30)
132
+ */
133
+ period?: number;
134
+ /**
135
+ * Counter value for HOTP
136
+ */
137
+ counter?: number;
138
+ };
139
+ /**
140
+ * TOTP-specific URI options
141
+ */
142
+ type TOTPURIOptions = URIOptions & {
143
+ period?: number;
144
+ counter?: never;
145
+ };
146
+ /**
147
+ * HOTP-specific URI options
148
+ */
149
+ type HOTPURIOptions = URIOptions & {
150
+ period?: never;
151
+ counter?: number;
152
+ };
153
+ /**
154
+ * Generate an otpauth:// URI
155
+ *
156
+ * @param uri - The URI components
157
+ * @returns The otpauth:// URI string
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * import { generate } from '@otplib/uri';
162
+ * import { encode } from '@otplib/base32';
163
+ *
164
+ * const secret = encode(new Uint8Array([1, 2, 3, 4, 5]));
165
+ *
166
+ * const uri = generate({
167
+ * type: 'totp',
168
+ * label: 'ACME:john@example.com',
169
+ * params: {
170
+ * secret,
171
+ * issuer: 'ACME',
172
+ * algorithm: 'sha1',
173
+ * digits: 6,
174
+ * },
175
+ * });
176
+ * // Returns: 'otpauth://totp/ACME:john%40example.com?secret=...'
177
+ * ```
178
+ */
179
+ declare function generate(uri: OTPAuthURI): string;
180
+ /**
181
+ * Generate a TOTP otpauth:// URI with simplified parameters
182
+ *
183
+ * @param options - TOTP URI generation options
184
+ * @returns The otpauth:// URI string
185
+ */
186
+ declare function generateTOTP(options: TOTPURIOptions & {
187
+ issuer: string;
188
+ label: string;
189
+ }): string;
190
+ /**
191
+ * Generate a HOTP otpauth:// URI with simplified parameters
192
+ *
193
+ * @param options - HOTP URI generation options
194
+ * @returns The otpauth:// URI string
195
+ */
196
+ declare function generateHOTP(options: HOTPURIOptions & {
197
+ issuer: string;
198
+ label: string;
199
+ }): string;
200
+
201
+ export { type HOTPURIOptions, InvalidParameterError, InvalidURIError, MissingParameterError, type OTPAuthParams, type OTPAuthURI, type OTPType, type TOTPURIOptions, type URIOptions, URIParseError, generate, generateHOTP, generateTOTP, parse, parse as parseURI };
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var l=class extends Error{constructor(e){super(e),this.name="URIParseError"}},a=class extends l{constructor(e){super(`Invalid otpauth URI: ${e}`),this.name="InvalidURIError"}},g=class extends l{constructor(e){super(`Missing required parameter: ${e}`),this.name="MissingParameterError"}},c=class extends l{constructor(e,n){super(`Invalid value for parameter '${e}': ${n}`),this.name="InvalidParameterError"}};var m=2048,d=512,y=1024;function O(r,e){let n=r instanceof Error?r.message:String(r);return`Invalid URI encoding in ${e}: ${n}`}function u(r,e,n){if(r.length>e*3)throw new a(`${n} exceeds maximum length`);try{let t=decodeURIComponent(r);if(t.length>e)throw new a(`${n} exceeds maximum length of ${e} characters`);return t}catch(t){throw t instanceof a?t:new a(O(t,n))}}function f(r){if(r.length>m)throw new a(`URI exceeds maximum length of ${m} characters`);if(!r.startsWith("otpauth://"))throw new a(r);let e=r.slice(10),n=e.indexOf("/");if(n===-1)throw new a(r);let t=e.slice(0,n);if(t!=="hotp"&&t!=="totp")throw new c("type",t);let i=e.slice(n+1),o=i.indexOf("?"),s,p;o===-1?(s=u(i,d,"label"),p=""):(s=u(i.slice(0,o),d,"label"),p=i.slice(o+1));let I=P(p);return{type:t,label:s,params:I}}function P(r){let e={};if(!r)return e;let n=r.split("&");for(let t of n){let i=t.indexOf("=");if(i===-1)continue;let o=u(t.slice(0,i),64,"parameter key"),s=u(t.slice(i+1),y,`parameter '${o}'`);switch(o){case"secret":e.secret=s;break;case"issuer":e.issuer=s;break;case"algorithm":e.algorithm=T(s);break;case"digits":e.digits=b(s);break;case"counter":e.counter=parseInt(s,10);break;case"period":e.period=parseInt(s,10);break}}return e}function T(r){let e=r.toLowerCase();if(e==="sha1"||e==="sha-1")return"sha1";if(e==="sha256"||e==="sha-256")return"sha256";if(e==="sha512"||e==="sha-512")return"sha512";throw new c("algorithm",r)}function b(r){let e=parseInt(r,10);if(e===6||e===7||e===8)return e;throw new c("digits",r)}function h(r){let{type:e,label:n,params:t}=r,i=n.split(":").map(p=>encodeURIComponent(p)).join(":"),o=`otpauth://${e}/${i}?`,s=[];return t.secret&&s.push(`secret=${t.secret}`),t.issuer&&s.push(`issuer=${encodeURIComponent(t.issuer)}`),t.algorithm&&t.algorithm!=="sha1"&&s.push(`algorithm=${t.algorithm.toUpperCase()}`),t.digits&&t.digits!==6&&s.push(`digits=${t.digits}`),e==="hotp"&&t.counter!==void 0&&s.push(`counter=${t.counter}`),e==="totp"&&t.period!==void 0&&t.period!==30&&s.push(`period=${t.period}`),o+=s.join("&"),o}function x(r){let{issuer:e,label:n,secret:t,algorithm:i="sha1",digits:o=6,period:s=30}=r,p=e?`${e}:${n}`:n;return h({type:"totp",label:p,params:{secret:t,issuer:e,algorithm:i,digits:o,period:s}})}function U(r){let{issuer:e,label:n,secret:t,counter:i=0,algorithm:o="sha1",digits:s=6}=r,p=e?`${e}:${n}`:n;return h({type:"hotp",label:p,params:{secret:t,issuer:e,algorithm:o,digits:s,counter:i}})}export{c as InvalidParameterError,a as InvalidURIError,g as MissingParameterError,l as URIParseError,h as generate,U as generateHOTP,x as generateTOTP,f as parse,f as parseURI};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/parse.ts","../src/generate.ts"],"sourcesContent":["import type { HashAlgorithm, Digits } from \"@otplib/core\";\n\n/**\n * OTP type (HOTP or TOTP)\n */\nexport type OTPType = \"hotp\" | \"totp\";\n\n/**\n * otpauth:// URI parameters\n */\nexport type OTPAuthParams = {\n /**\n * Base32-encoded shared secret (required)\n */\n readonly secret: string;\n\n /**\n * Service/provider name (recommended)\n */\n readonly issuer?: string;\n\n /**\n * Hash algorithm (default: sha1)\n * Note: Google Authenticator only supports sha1\n */\n readonly algorithm?: HashAlgorithm;\n\n /**\n * Number of digits (default: 6)\n * Google Authenticator supports 6 or 8\n */\n readonly digits?: Digits;\n\n /**\n * Initial counter value for HOTP (default: 0)\n */\n readonly counter?: number;\n\n /**\n * Time step in seconds for TOTP (default: 30)\n */\n readonly period?: number;\n};\n\n/**\n * otpauth:// URI structure\n */\nexport type OTPAuthURI = {\n /**\n * Type of OTP (hotp or totp)\n */\n readonly type: OTPType;\n\n /**\n * The label (typically: issuer:account or account)\n */\n readonly label: string;\n\n /**\n * Parameters from the URI\n */\n readonly params: OTPAuthParams;\n};\n\n/**\n * Error thrown when URI parsing fails\n */\nexport class URIParseError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"URIParseError\";\n }\n}\n\n/**\n * Error thrown when URI is invalid\n */\nexport class InvalidURIError extends URIParseError {\n constructor(uri: string) {\n super(`Invalid otpauth URI: ${uri}`);\n this.name = \"InvalidURIError\";\n }\n}\n\n/**\n * Error thrown when URI has missing required parameters\n */\nexport class MissingParameterError extends URIParseError {\n constructor(param: string) {\n super(`Missing required parameter: ${param}`);\n this.name = \"MissingParameterError\";\n }\n}\n\n/**\n * Error thrown when URI has invalid parameter value\n */\nexport class InvalidParameterError extends URIParseError {\n constructor(param: string, value: string) {\n super(`Invalid value for parameter '${param}': ${value}`);\n this.name = \"InvalidParameterError\";\n }\n}\n","import { InvalidURIError, InvalidParameterError } from \"./types.js\";\n\nimport type { OTPAuthURI, OTPAuthParams } from \"./types.js\";\nimport type { HashAlgorithm, Digits } from \"@otplib/core\";\n\n// Security limits to prevent DoS attacks\nconst MAX_URI_LENGTH = 2048; // Standard URL length limit\nconst MAX_LABEL_LENGTH = 512;\nconst MAX_PARAM_VALUE_LENGTH = 1024;\n\n/**\n * Format error message for caught errors\n * @internal\n */\nexport function formatErrorMessage(error: unknown, context: string): string {\n const errorStr = error instanceof Error ? error.message : String(error);\n return `Invalid URI encoding in ${context}: ${errorStr}`;\n}\n\n/**\n * Safely decode a URI component with length validation and error handling\n * @throws {InvalidURIError} If decoding fails or length exceeds limit\n */\nfunction safeDecodeURIComponent(str: string, maxLength: number, context: string): string {\n if (str.length > maxLength * 3) {\n throw new InvalidURIError(`${context} exceeds maximum length`);\n }\n\n try {\n const decoded = decodeURIComponent(str);\n if (decoded.length > maxLength) {\n throw new InvalidURIError(`${context} exceeds maximum length of ${maxLength} characters`);\n }\n return decoded;\n } catch (error) {\n if (error instanceof InvalidURIError) {\n throw error;\n }\n throw new InvalidURIError(formatErrorMessage(error, context));\n }\n}\n\n/**\n * Parse an otpauth:// URI into its components\n *\n * @param uri - The otpauth:// URI to parse\n * @returns Parsed URI components\n * @throws {InvalidURIError} If URI is invalid\n * @throws {MissingParameterError} If required parameters are missing\n * @throws {InvalidParameterError} If parameter values are invalid\n *\n * @example\n * ```ts\n * import { parse } from '@otplib/uri';\n *\n * const uri = 'otpauth://totp/ACME:john@example.com?secret=JBSWY3DPEHPK3PXP&issuer=ACME';\n * const parsed = parse(uri);\n * // {\n * // type: 'totp',\n * // label: 'ACME:john@example.com',\n * // params: { secret: 'JBSWY3DPEHPK3PXP', issuer: 'ACME' }\n * // }\n * ```\n */\nexport function parse(uri: string): OTPAuthURI {\n if (uri.length > MAX_URI_LENGTH) {\n throw new InvalidURIError(`URI exceeds maximum length of ${MAX_URI_LENGTH} characters`);\n }\n\n if (!uri.startsWith(\"otpauth://\")) {\n throw new InvalidURIError(uri);\n }\n\n const withoutScheme = uri.slice(\"otpauth://\".length);\n const slashIndex = withoutScheme.indexOf(\"/\");\n\n if (slashIndex === -1) {\n throw new InvalidURIError(uri);\n }\n\n const type = withoutScheme.slice(0, slashIndex);\n if (type !== \"hotp\" && type !== \"totp\") {\n throw new InvalidParameterError(\"type\", type);\n }\n\n const remaining = withoutScheme.slice(slashIndex + 1);\n const queryIndex = remaining.indexOf(\"?\");\n\n let label: string;\n let queryString: string;\n\n if (queryIndex === -1) {\n label = safeDecodeURIComponent(remaining, MAX_LABEL_LENGTH, \"label\");\n queryString = \"\";\n } else {\n label = safeDecodeURIComponent(remaining.slice(0, queryIndex), MAX_LABEL_LENGTH, \"label\");\n queryString = remaining.slice(queryIndex + 1);\n }\n\n const params = parseQueryString(queryString);\n\n return {\n type,\n label,\n params,\n };\n}\n\n/**\n * Parse query string into parameters object\n */\nfunction parseQueryString(queryString: string): OTPAuthParams {\n // Use mutable type during construction\n const params: {\n secret?: string;\n issuer?: string;\n algorithm?: HashAlgorithm;\n digits?: Digits;\n counter?: number;\n period?: number;\n } = {};\n\n if (!queryString) {\n return params as OTPAuthParams;\n }\n\n const pairs = queryString.split(\"&\");\n for (const pair of pairs) {\n const equalIndex = pair.indexOf(\"=\");\n if (equalIndex === -1) {\n continue;\n }\n\n const key = safeDecodeURIComponent(pair.slice(0, equalIndex), 64, \"parameter key\");\n const value = safeDecodeURIComponent(\n pair.slice(equalIndex + 1),\n MAX_PARAM_VALUE_LENGTH,\n `parameter '${key}'`,\n );\n\n switch (key) {\n case \"secret\":\n params.secret = value;\n break;\n case \"issuer\":\n params.issuer = value;\n break;\n case \"algorithm\":\n params.algorithm = parseAlgorithm(value);\n break;\n case \"digits\":\n params.digits = parseDigits(value);\n break;\n case \"counter\":\n params.counter = parseInt(value, 10);\n break;\n case \"period\":\n params.period = parseInt(value, 10);\n break;\n }\n }\n\n return params as OTPAuthParams;\n}\n\n/**\n * Parse algorithm string\n */\nfunction parseAlgorithm(value: string): HashAlgorithm {\n const normalized = value.toLowerCase();\n if (normalized === \"sha1\" || normalized === \"sha-1\") {\n return \"sha1\";\n }\n if (normalized === \"sha256\" || normalized === \"sha-256\") {\n return \"sha256\";\n }\n if (normalized === \"sha512\" || normalized === \"sha-512\") {\n return \"sha512\";\n }\n throw new InvalidParameterError(\"algorithm\", value);\n}\n\n/**\n * Parse digits string\n */\nfunction parseDigits(value: string): Digits {\n const digits = parseInt(value, 10);\n if (digits === 6 || digits === 7 || digits === 8) {\n return digits;\n }\n throw new InvalidParameterError(\"digits\", value);\n}\n","import type { OTPAuthURI } from \"./types.js\";\nimport type { HashAlgorithm, Digits } from \"@otplib/core\";\n\n/**\n * Base options for URI generation\n */\nexport type URIOptions = {\n /**\n * Service/provider name (e.g., 'ACME Co', 'GitHub', 'AWS')\n */\n issuer?: string;\n\n /**\n * Account identifier (e.g., email, username)\n */\n label?: string;\n\n /**\n * Base32-encoded secret key\n */\n secret: string;\n\n /**\n * Hash algorithm (default: 'sha1')\n * Note: Google Authenticator only supports sha1\n */\n algorithm?: HashAlgorithm;\n\n /**\n * Number of digits (default: 6)\n * Google Authenticator supports 6 or 8, RFC also allows 7\n */\n digits?: Digits;\n\n /**\n * Time step in seconds for TOTP (default: 30)\n */\n period?: number;\n\n /**\n * Counter value for HOTP\n */\n counter?: number;\n};\n\n/**\n * TOTP-specific URI options\n */\nexport type TOTPURIOptions = URIOptions & {\n period?: number;\n counter?: never;\n};\n\n/**\n * HOTP-specific URI options\n */\nexport type HOTPURIOptions = URIOptions & {\n period?: never;\n counter?: number;\n};\n\n/**\n * Generate an otpauth:// URI\n *\n * @param uri - The URI components\n * @returns The otpauth:// URI string\n *\n * @example\n * ```ts\n * import { generate } from '@otplib/uri';\n * import { encode } from '@otplib/base32';\n *\n * const secret = encode(new Uint8Array([1, 2, 3, 4, 5]));\n *\n * const uri = generate({\n * type: 'totp',\n * label: 'ACME:john@example.com',\n * params: {\n * secret,\n * issuer: 'ACME',\n * algorithm: 'sha1',\n * digits: 6,\n * },\n * });\n * // Returns: 'otpauth://totp/ACME:john%40example.com?secret=...'\n * ```\n */\nexport function generate(uri: OTPAuthURI): string {\n const { type, label, params } = uri;\n\n // Encode label parts while preserving ':' as the issuer/account separator\n const encodedLabel = label\n .split(\":\")\n .map((part) => encodeURIComponent(part))\n .join(\":\");\n\n let result = `otpauth://${type}/${encodedLabel}?`;\n\n const queryParams: string[] = [];\n\n if (params.secret) {\n queryParams.push(`secret=${params.secret}`);\n }\n\n if (params.issuer) {\n queryParams.push(`issuer=${encodeURIComponent(params.issuer)}`);\n }\n\n if (params.algorithm && params.algorithm !== \"sha1\") {\n queryParams.push(`algorithm=${params.algorithm.toUpperCase()}`);\n }\n\n if (params.digits && params.digits !== 6) {\n queryParams.push(`digits=${params.digits}`);\n }\n\n if (type === \"hotp\" && params.counter !== undefined) {\n queryParams.push(`counter=${params.counter}`);\n }\n\n if (type === \"totp\" && params.period !== undefined && params.period !== 30) {\n queryParams.push(`period=${params.period}`);\n }\n\n result += queryParams.join(\"&\");\n\n return result;\n}\n\n/**\n * Generate a TOTP otpauth:// URI with simplified parameters\n *\n * @param options - TOTP URI generation options\n * @returns The otpauth:// URI string\n */\nexport function generateTOTP(options: TOTPURIOptions & { issuer: string; label: string }): string {\n const { issuer, label: account, secret, algorithm = \"sha1\", digits = 6, period = 30 } = options;\n\n const fullLabel = issuer ? `${issuer}:${account}` : account;\n\n return generate({\n type: \"totp\",\n label: fullLabel,\n params: {\n secret,\n issuer,\n algorithm,\n digits,\n period,\n },\n });\n}\n\n/**\n * Generate a HOTP otpauth:// URI with simplified parameters\n *\n * @param options - HOTP URI generation options\n * @returns The otpauth:// URI string\n */\nexport function generateHOTP(options: HOTPURIOptions & { issuer: string; label: string }): string {\n const { issuer, label: account, secret, counter = 0, algorithm = \"sha1\", digits = 6 } = options;\n\n const fullLabel = issuer ? `${issuer}:${account}` : account;\n\n return generate({\n type: \"hotp\",\n label: fullLabel,\n params: {\n secret,\n issuer,\n algorithm,\n digits,\n counter,\n },\n });\n}\n"],"mappings":"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","names":["URIParseError","message","InvalidURIError","uri","MissingParameterError","param","InvalidParameterError","value","MAX_URI_LENGTH","MAX_LABEL_LENGTH","MAX_PARAM_VALUE_LENGTH","formatErrorMessage","error","context","errorStr","safeDecodeURIComponent","str","maxLength","InvalidURIError","decoded","parse","uri","withoutScheme","slashIndex","type","InvalidParameterError","remaining","queryIndex","label","queryString","params","parseQueryString","pairs","pair","equalIndex","key","value","parseAlgorithm","parseDigits","normalized","digits","generate","uri","type","label","params","encodedLabel","part","result","queryParams","generateTOTP","options","issuer","account","secret","algorithm","digits","period","fullLabel","generateHOTP","counter"]}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@otplib/uri",
3
+ "version": "13.0.0",
4
+ "description": "otpauth:// URI parsing and generation for otplib",
5
+ "license": "MIT",
6
+ "author": "Gerald Yeo <support@yeojz.dev>",
7
+ "homepage": "https://otplib.yeojz.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/yeojz/otplib.git",
11
+ "directory": "packages/uri"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/yeojz/otplib/issues"
15
+ },
16
+ "keywords": [
17
+ "otp",
18
+ "otpauth",
19
+ "uri",
20
+ "qrcode",
21
+ "2fa",
22
+ "authenticator"
23
+ ],
24
+ "sideEffects": false,
25
+ "type": "module",
26
+ "main": "./dist/index.cjs",
27
+ "module": "./dist/index.js",
28
+ "types": "./dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "import": {
32
+ "types": "./dist/index.d.ts",
33
+ "default": "./dist/index.js"
34
+ },
35
+ "require": {
36
+ "types": "./dist/index.d.cts",
37
+ "default": "./dist/index.cjs"
38
+ }
39
+ }
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "README.md",
44
+ "LICENSE"
45
+ ],
46
+ "dependencies": {
47
+ "@otplib/core": "13.0.0"
48
+ },
49
+ "devDependencies": {
50
+ "tsup": "^8.0.1",
51
+ "typescript": "^5.3.3",
52
+ "vitest": "^4.0.16",
53
+ "@repo/testing": "13.0.0"
54
+ },
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "scripts": {
59
+ "build": "tsup",
60
+ "dev": "tsup --watch",
61
+ "test": "vitest",
62
+ "test:ci": "vitest run --coverage",
63
+ "typecheck": "tsc --noEmit",
64
+ "lint": "eslint src/",
65
+ "clean": "rm -rf dist .tsbuildinfo"
66
+ }
67
+ }