@digiko-npm/cms 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.d.ts +30 -1
- package/dist/auth/index.js +38 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +41 -4
- package/package.json +24 -13
- package/src/auth/index.ts +1 -0
- package/src/auth/totp.ts +72 -0
- package/src/index.ts +1 -0
package/dist/auth/index.d.ts
CHANGED
|
@@ -17,4 +17,33 @@ declare function verifyPassword(password: string, salt: string, storedHash: stri
|
|
|
17
17
|
*/
|
|
18
18
|
declare function generateSessionToken(bytes?: number): string;
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/** Configuration for TOTP operations */
|
|
21
|
+
interface TotpConfig {
|
|
22
|
+
/** Hash algorithm. Default: 'SHA1' (required for 1Password compatibility) */
|
|
23
|
+
algorithm?: string;
|
|
24
|
+
/** Number of digits. Default: 6 */
|
|
25
|
+
digits?: number;
|
|
26
|
+
/** Time step in seconds. Default: 30 */
|
|
27
|
+
period?: number;
|
|
28
|
+
/** Validation window (number of periods to check before/after). Default: 1 */
|
|
29
|
+
window?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate a new TOTP secret.
|
|
33
|
+
* Returns a base32-encoded string suitable for storing in env vars.
|
|
34
|
+
* Uses 20 bytes (160 bits) as recommended by RFC 4226.
|
|
35
|
+
*/
|
|
36
|
+
declare function generateTotpSecret(): string;
|
|
37
|
+
/**
|
|
38
|
+
* Generate an otpauth:// URI for registering with authenticator apps.
|
|
39
|
+
* Can be entered manually in 1Password or encoded as a QR code.
|
|
40
|
+
*/
|
|
41
|
+
declare function generateTotpUri(secret: string, accountName: string, issuer: string, config?: TotpConfig): string;
|
|
42
|
+
/**
|
|
43
|
+
* Verify a 6-digit TOTP code against a secret.
|
|
44
|
+
* Returns true if the code is valid within the configured time window.
|
|
45
|
+
* Uses timing-safe comparison internally (handled by otpauth library).
|
|
46
|
+
*/
|
|
47
|
+
declare function verifyTotpCode(code: string, secret: string, config?: TotpConfig): boolean;
|
|
48
|
+
|
|
49
|
+
export { type TotpConfig, generateSessionToken, generateTotpSecret, generateTotpUri, hashPassword, verifyPassword, verifyTotpCode };
|
package/dist/auth/index.js
CHANGED
|
@@ -27,8 +27,45 @@ var DEFAULT_TOKEN_BYTES = 32;
|
|
|
27
27
|
function generateSessionToken(bytes) {
|
|
28
28
|
return crypto2.randomBytes(bytes ?? DEFAULT_TOKEN_BYTES).toString("hex");
|
|
29
29
|
}
|
|
30
|
+
|
|
31
|
+
// src/auth/totp.ts
|
|
32
|
+
import { TOTP, Secret } from "otpauth";
|
|
33
|
+
var DEFAULTS2 = {
|
|
34
|
+
algorithm: "SHA1",
|
|
35
|
+
digits: 6,
|
|
36
|
+
period: 30,
|
|
37
|
+
window: 1
|
|
38
|
+
};
|
|
39
|
+
function generateTotpSecret() {
|
|
40
|
+
const secret = new Secret({ size: 20 });
|
|
41
|
+
return secret.base32;
|
|
42
|
+
}
|
|
43
|
+
function generateTotpUri(secret, accountName, issuer, config) {
|
|
44
|
+
const totp = new TOTP({
|
|
45
|
+
issuer,
|
|
46
|
+
label: accountName,
|
|
47
|
+
algorithm: config?.algorithm ?? DEFAULTS2.algorithm,
|
|
48
|
+
digits: config?.digits ?? DEFAULTS2.digits,
|
|
49
|
+
period: config?.period ?? DEFAULTS2.period,
|
|
50
|
+
secret: Secret.fromBase32(secret)
|
|
51
|
+
});
|
|
52
|
+
return totp.toString();
|
|
53
|
+
}
|
|
54
|
+
function verifyTotpCode(code, secret, config) {
|
|
55
|
+
const totp = new TOTP({
|
|
56
|
+
algorithm: config?.algorithm ?? DEFAULTS2.algorithm,
|
|
57
|
+
digits: config?.digits ?? DEFAULTS2.digits,
|
|
58
|
+
period: config?.period ?? DEFAULTS2.period,
|
|
59
|
+
secret: Secret.fromBase32(secret)
|
|
60
|
+
});
|
|
61
|
+
const delta = totp.validate({ token: code, window: config?.window ?? DEFAULTS2.window });
|
|
62
|
+
return delta !== null;
|
|
63
|
+
}
|
|
30
64
|
export {
|
|
31
65
|
generateSessionToken,
|
|
66
|
+
generateTotpSecret,
|
|
67
|
+
generateTotpUri,
|
|
32
68
|
hashPassword,
|
|
33
|
-
verifyPassword
|
|
69
|
+
verifyPassword,
|
|
70
|
+
verifyTotpCode
|
|
34
71
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { createAdminClient, createBrowserClient, createPublicClient } from './supabase/index.js';
|
|
2
2
|
export { UploadOptions, UploadResult, createR2Client, getR2Bucket, getR2PublicUrl, uploadFile } from './r2/index.js';
|
|
3
|
-
export { generateSessionToken, hashPassword, verifyPassword } from './auth/index.js';
|
|
3
|
+
export { TotpConfig, generateSessionToken, generateTotpSecret, generateTotpUri, hashPassword, verifyPassword, verifyTotpCode } from './auth/index.js';
|
|
4
4
|
export { RateLimiter, SessionStore, createRateLimiter, createSessionStore, getDefaultSessionDuration } from './session/index.js';
|
|
5
5
|
export { HTTP_STATUS, HttpStatus } from './http/index.js';
|
|
6
6
|
export { A as AuthConfig, R as R2Config, a as RateLimiterConfig, b as RequestVerifierConfig, S as SessionStoreConfig, c as SupabaseConfig, U as UploadConfig } from './config-qNdTlg1g.js';
|
package/dist/index.js
CHANGED
|
@@ -123,6 +123,40 @@ function generateSessionToken(bytes) {
|
|
|
123
123
|
return crypto2.randomBytes(bytes ?? DEFAULT_TOKEN_BYTES).toString("hex");
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
// src/auth/totp.ts
|
|
127
|
+
import { TOTP, Secret } from "otpauth";
|
|
128
|
+
var DEFAULTS2 = {
|
|
129
|
+
algorithm: "SHA1",
|
|
130
|
+
digits: 6,
|
|
131
|
+
period: 30,
|
|
132
|
+
window: 1
|
|
133
|
+
};
|
|
134
|
+
function generateTotpSecret() {
|
|
135
|
+
const secret = new Secret({ size: 20 });
|
|
136
|
+
return secret.base32;
|
|
137
|
+
}
|
|
138
|
+
function generateTotpUri(secret, accountName, issuer, config) {
|
|
139
|
+
const totp = new TOTP({
|
|
140
|
+
issuer,
|
|
141
|
+
label: accountName,
|
|
142
|
+
algorithm: config?.algorithm ?? DEFAULTS2.algorithm,
|
|
143
|
+
digits: config?.digits ?? DEFAULTS2.digits,
|
|
144
|
+
period: config?.period ?? DEFAULTS2.period,
|
|
145
|
+
secret: Secret.fromBase32(secret)
|
|
146
|
+
});
|
|
147
|
+
return totp.toString();
|
|
148
|
+
}
|
|
149
|
+
function verifyTotpCode(code, secret, config) {
|
|
150
|
+
const totp = new TOTP({
|
|
151
|
+
algorithm: config?.algorithm ?? DEFAULTS2.algorithm,
|
|
152
|
+
digits: config?.digits ?? DEFAULTS2.digits,
|
|
153
|
+
period: config?.period ?? DEFAULTS2.period,
|
|
154
|
+
secret: Secret.fromBase32(secret)
|
|
155
|
+
});
|
|
156
|
+
const delta = totp.validate({ token: code, window: config?.window ?? DEFAULTS2.window });
|
|
157
|
+
return delta !== null;
|
|
158
|
+
}
|
|
159
|
+
|
|
126
160
|
// src/session/store.ts
|
|
127
161
|
import { Redis } from "@upstash/redis";
|
|
128
162
|
var DEFAULT_SESSION_DURATION = 24 * 60 * 60 * 1e3;
|
|
@@ -160,7 +194,7 @@ function getDefaultSessionDuration() {
|
|
|
160
194
|
|
|
161
195
|
// src/session/rate-limit.ts
|
|
162
196
|
import { Redis as Redis2 } from "@upstash/redis";
|
|
163
|
-
var
|
|
197
|
+
var DEFAULTS3 = {
|
|
164
198
|
maxAttempts: 10,
|
|
165
199
|
windowMs: 15 * 60 * 1e3
|
|
166
200
|
// 15 minutes
|
|
@@ -170,8 +204,8 @@ function createRateLimiter(config) {
|
|
|
170
204
|
url: config.redisUrl,
|
|
171
205
|
token: config.redisToken
|
|
172
206
|
});
|
|
173
|
-
const maxAttempts = config.maxAttempts ??
|
|
174
|
-
const windowMs = config.windowMs ??
|
|
207
|
+
const maxAttempts = config.maxAttempts ?? DEFAULTS3.maxAttempts;
|
|
208
|
+
const windowMs = config.windowMs ?? DEFAULTS3.windowMs;
|
|
175
209
|
const rateLimitKey = (key) => `${config.keyPrefix}ratelimit:${key}`;
|
|
176
210
|
return {
|
|
177
211
|
async check(key) {
|
|
@@ -224,10 +258,13 @@ export {
|
|
|
224
258
|
createRateLimiter,
|
|
225
259
|
createSessionStore,
|
|
226
260
|
generateSessionToken,
|
|
261
|
+
generateTotpSecret,
|
|
262
|
+
generateTotpUri,
|
|
227
263
|
getDefaultSessionDuration,
|
|
228
264
|
getR2Bucket,
|
|
229
265
|
getR2PublicUrl,
|
|
230
266
|
hashPassword,
|
|
231
267
|
uploadFile,
|
|
232
|
-
verifyPassword
|
|
268
|
+
verifyPassword,
|
|
269
|
+
verifyTotpCode
|
|
233
270
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digiko-npm/cms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Reusable CMS utilities — Supabase, Cloudflare R2, auth, sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -8,36 +8,44 @@
|
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
11
12
|
"import": "./dist/index.js",
|
|
12
|
-
"
|
|
13
|
+
"default": "./dist/index.js"
|
|
13
14
|
},
|
|
14
15
|
"./supabase": {
|
|
16
|
+
"types": "./dist/supabase/index.d.ts",
|
|
15
17
|
"import": "./dist/supabase/index.js",
|
|
16
|
-
"
|
|
18
|
+
"default": "./dist/supabase/index.js"
|
|
17
19
|
},
|
|
18
20
|
"./r2": {
|
|
21
|
+
"types": "./dist/r2/index.d.ts",
|
|
19
22
|
"import": "./dist/r2/index.js",
|
|
20
|
-
"
|
|
23
|
+
"default": "./dist/r2/index.js"
|
|
21
24
|
},
|
|
22
25
|
"./auth": {
|
|
26
|
+
"types": "./dist/auth/index.d.ts",
|
|
23
27
|
"import": "./dist/auth/index.js",
|
|
24
|
-
"
|
|
28
|
+
"default": "./dist/auth/index.js"
|
|
25
29
|
},
|
|
26
30
|
"./session": {
|
|
31
|
+
"types": "./dist/session/index.d.ts",
|
|
27
32
|
"import": "./dist/session/index.js",
|
|
28
|
-
"
|
|
33
|
+
"default": "./dist/session/index.js"
|
|
29
34
|
},
|
|
30
35
|
"./next": {
|
|
36
|
+
"types": "./dist/next/index.d.ts",
|
|
31
37
|
"import": "./dist/next/index.js",
|
|
32
|
-
"
|
|
38
|
+
"default": "./dist/next/index.js"
|
|
33
39
|
},
|
|
34
40
|
"./http": {
|
|
41
|
+
"types": "./dist/http/index.d.ts",
|
|
35
42
|
"import": "./dist/http/index.js",
|
|
36
|
-
"
|
|
43
|
+
"default": "./dist/http/index.js"
|
|
37
44
|
},
|
|
38
45
|
"./types": {
|
|
46
|
+
"types": "./dist/types/index.d.ts",
|
|
39
47
|
"import": "./dist/types/index.js",
|
|
40
|
-
"
|
|
48
|
+
"default": "./dist/types/index.js"
|
|
41
49
|
}
|
|
42
50
|
},
|
|
43
51
|
"files": [
|
|
@@ -56,9 +64,9 @@
|
|
|
56
64
|
"access": "public"
|
|
57
65
|
},
|
|
58
66
|
"peerDependencies": {
|
|
59
|
-
"@supabase/supabase-js": "^2.0.0",
|
|
60
67
|
"@aws-sdk/client-s3": "^3.0.0",
|
|
61
68
|
"@aws-sdk/s3-request-presigner": "^3.0.0",
|
|
69
|
+
"@supabase/supabase-js": "^2.0.0",
|
|
62
70
|
"@upstash/redis": "^1.0.0",
|
|
63
71
|
"next": ">=14.0.0"
|
|
64
72
|
},
|
|
@@ -77,11 +85,11 @@
|
|
|
77
85
|
}
|
|
78
86
|
},
|
|
79
87
|
"devDependencies": {
|
|
80
|
-
"@supabase/supabase-js": "^2.95.0",
|
|
81
88
|
"@aws-sdk/client-s3": "^3.986.0",
|
|
82
89
|
"@aws-sdk/s3-request-presigner": "^3.986.0",
|
|
83
|
-
"@
|
|
90
|
+
"@supabase/supabase-js": "^2.95.0",
|
|
84
91
|
"@types/node": "^20",
|
|
92
|
+
"@upstash/redis": "^1.36.0",
|
|
85
93
|
"next": "16.1.6",
|
|
86
94
|
"tsup": "^8.0.0",
|
|
87
95
|
"typescript": "^5"
|
|
@@ -97,5 +105,8 @@
|
|
|
97
105
|
"cloudflare-r2",
|
|
98
106
|
"admin",
|
|
99
107
|
"auth"
|
|
100
|
-
]
|
|
108
|
+
],
|
|
109
|
+
"dependencies": {
|
|
110
|
+
"otpauth": "^9.5.0"
|
|
111
|
+
}
|
|
101
112
|
}
|
package/src/auth/index.ts
CHANGED
package/src/auth/totp.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { TOTP, Secret } from 'otpauth'
|
|
2
|
+
|
|
3
|
+
/** Configuration for TOTP operations */
|
|
4
|
+
export interface TotpConfig {
|
|
5
|
+
/** Hash algorithm. Default: 'SHA1' (required for 1Password compatibility) */
|
|
6
|
+
algorithm?: string
|
|
7
|
+
/** Number of digits. Default: 6 */
|
|
8
|
+
digits?: number
|
|
9
|
+
/** Time step in seconds. Default: 30 */
|
|
10
|
+
period?: number
|
|
11
|
+
/** Validation window (number of periods to check before/after). Default: 1 */
|
|
12
|
+
window?: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const DEFAULTS = {
|
|
16
|
+
algorithm: 'SHA1',
|
|
17
|
+
digits: 6,
|
|
18
|
+
period: 30,
|
|
19
|
+
window: 1,
|
|
20
|
+
} as const
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a new TOTP secret.
|
|
24
|
+
* Returns a base32-encoded string suitable for storing in env vars.
|
|
25
|
+
* Uses 20 bytes (160 bits) as recommended by RFC 4226.
|
|
26
|
+
*/
|
|
27
|
+
export function generateTotpSecret(): string {
|
|
28
|
+
const secret = new Secret({ size: 20 })
|
|
29
|
+
return secret.base32
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Generate an otpauth:// URI for registering with authenticator apps.
|
|
34
|
+
* Can be entered manually in 1Password or encoded as a QR code.
|
|
35
|
+
*/
|
|
36
|
+
export function generateTotpUri(
|
|
37
|
+
secret: string,
|
|
38
|
+
accountName: string,
|
|
39
|
+
issuer: string,
|
|
40
|
+
config?: TotpConfig
|
|
41
|
+
): string {
|
|
42
|
+
const totp = new TOTP({
|
|
43
|
+
issuer,
|
|
44
|
+
label: accountName,
|
|
45
|
+
algorithm: config?.algorithm ?? DEFAULTS.algorithm,
|
|
46
|
+
digits: config?.digits ?? DEFAULTS.digits,
|
|
47
|
+
period: config?.period ?? DEFAULTS.period,
|
|
48
|
+
secret: Secret.fromBase32(secret),
|
|
49
|
+
})
|
|
50
|
+
return totp.toString()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Verify a 6-digit TOTP code against a secret.
|
|
55
|
+
* Returns true if the code is valid within the configured time window.
|
|
56
|
+
* Uses timing-safe comparison internally (handled by otpauth library).
|
|
57
|
+
*/
|
|
58
|
+
export function verifyTotpCode(
|
|
59
|
+
code: string,
|
|
60
|
+
secret: string,
|
|
61
|
+
config?: TotpConfig
|
|
62
|
+
): boolean {
|
|
63
|
+
const totp = new TOTP({
|
|
64
|
+
algorithm: config?.algorithm ?? DEFAULTS.algorithm,
|
|
65
|
+
digits: config?.digits ?? DEFAULTS.digits,
|
|
66
|
+
period: config?.period ?? DEFAULTS.period,
|
|
67
|
+
secret: Secret.fromBase32(secret),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
const delta = totp.validate({ token: code, window: config?.window ?? DEFAULTS.window })
|
|
71
|
+
return delta !== null
|
|
72
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { uploadFile, type UploadOptions, type UploadResult } from './r2/upload'
|
|
|
9
9
|
// Auth
|
|
10
10
|
export { hashPassword, verifyPassword } from './auth/password'
|
|
11
11
|
export { generateSessionToken } from './auth/token'
|
|
12
|
+
export { generateTotpSecret, generateTotpUri, verifyTotpCode, type TotpConfig } from './auth/totp'
|
|
12
13
|
|
|
13
14
|
// Sessions
|
|
14
15
|
export { createSessionStore, getDefaultSessionDuration, type SessionStore } from './session/store'
|