@pgpm/totp 0.4.0 → 0.6.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/Makefile
CHANGED
package/README.md
CHANGED
|
@@ -2,9 +2,73 @@
|
|
|
2
2
|
|
|
3
3
|
TOTP implementation in pure PostgreSQL plpgsql
|
|
4
4
|
|
|
5
|
-
This extension provides the HMAC Time-Based One-Time Password Algorithm (TOTP) as
|
|
5
|
+
This extension provides the HMAC Time-Based One-Time Password Algorithm (TOTP) as specified in RFC 4226 as pure plpgsql functions.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
`@pgpm/totp` implements Time-based One-Time Password (TOTP) authentication entirely in PostgreSQL using plpgsql. This package enables two-factor authentication (2FA) directly in your database without external dependencies. It supports TOTP code generation, verification, and QR code URL generation for authenticator apps like Google Authenticator, Authy, and 1Password.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Pure plpgsql Implementation**: No external dependencies or libraries required
|
|
14
|
+
- **TOTP Code Generation**: Generate 6-digit time-based codes
|
|
15
|
+
- **Code Verification**: Verify user-provided TOTP codes
|
|
16
|
+
- **QR Code URLs**: Generate otpauth:// URLs for authenticator apps
|
|
17
|
+
- **Configurable Parameters**: Customize interval and code length
|
|
18
|
+
- **RFC 4226 Compliant**: Follows the HOTP standard
|
|
19
|
+
- **Base32 Integration**: Uses `@pgpm/base32` for secret encoding
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
If you have `pgpm` installed:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pgpm install @pgpm/totp
|
|
27
|
+
pgpm deploy
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This is a quick way to get started. The sections below provide more detailed installation options.
|
|
31
|
+
|
|
32
|
+
### Prerequisites
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Install pgpm globally
|
|
36
|
+
npm install -g pgpm
|
|
37
|
+
|
|
38
|
+
# Start PostgreSQL
|
|
39
|
+
pgpm docker start
|
|
40
|
+
|
|
41
|
+
# Set environment variables
|
|
42
|
+
eval "$(pgpm env)"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Deploy
|
|
46
|
+
|
|
47
|
+
#### Option 1: Deploy by installing with pgpm
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pgpm install @pgpm/totp
|
|
51
|
+
pgpm deploy
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Option 2: Deploy from Package Directory
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
cd packages/security/totp
|
|
58
|
+
pgpm deploy --createdb
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Option 3: Deploy from Workspace Root
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Install workspace dependencies
|
|
65
|
+
pnpm install
|
|
66
|
+
|
|
67
|
+
# Deploy with dependencies
|
|
68
|
+
pgpm deploy mydb1 --yes --createdb
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
8
72
|
|
|
9
73
|
## totp.generate
|
|
10
74
|
|
|
@@ -50,11 +114,97 @@ Will produce a URL-encoded string
|
|
|
50
114
|
otpauth://totp/customer@email.com?secret=mysecret&period=30&issuer=Acme%20Inc
|
|
51
115
|
```
|
|
52
116
|
|
|
53
|
-
|
|
117
|
+
## Integration Examples
|
|
118
|
+
|
|
119
|
+
### User Registration with 2FA
|
|
120
|
+
|
|
121
|
+
```sql
|
|
122
|
+
-- Store TOTP secret for user
|
|
123
|
+
CREATE TABLE user_totp (
|
|
124
|
+
user_id uuid PRIMARY KEY,
|
|
125
|
+
totp_secret text NOT NULL,
|
|
126
|
+
enabled boolean DEFAULT false,
|
|
127
|
+
created_at timestamptz DEFAULT now()
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
-- Generate and store secret for new user
|
|
131
|
+
INSERT INTO user_totp (user_id, totp_secret)
|
|
132
|
+
VALUES ('user-uuid', 'mysecret');
|
|
133
|
+
|
|
134
|
+
-- Get QR code URL for user to scan
|
|
135
|
+
SELECT totp.url(
|
|
136
|
+
'user@example.com',
|
|
137
|
+
totp_secret,
|
|
138
|
+
30,
|
|
139
|
+
'My App'
|
|
140
|
+
) FROM user_totp WHERE user_id = 'user-uuid';
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Login Verification
|
|
144
|
+
|
|
145
|
+
```sql
|
|
146
|
+
-- Verify TOTP code during login
|
|
147
|
+
CREATE FUNCTION verify_user_totp(
|
|
148
|
+
p_user_id uuid,
|
|
149
|
+
p_code text
|
|
150
|
+
) RETURNS boolean AS $$
|
|
151
|
+
DECLARE
|
|
152
|
+
v_secret text;
|
|
153
|
+
BEGIN
|
|
154
|
+
SELECT totp_secret INTO v_secret
|
|
155
|
+
FROM user_totp
|
|
156
|
+
WHERE user_id = p_user_id AND enabled = true;
|
|
157
|
+
|
|
158
|
+
IF v_secret IS NULL THEN
|
|
159
|
+
RETURN false;
|
|
160
|
+
END IF;
|
|
161
|
+
|
|
162
|
+
RETURN totp.verify(v_secret, p_code, 30, 6);
|
|
163
|
+
END;
|
|
164
|
+
$$ LANGUAGE plpgsql;
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Enable 2FA Flow
|
|
168
|
+
|
|
169
|
+
```sql
|
|
170
|
+
-- 1. Generate secret and QR code URL
|
|
171
|
+
SELECT totp.url('user@example.com', 'newsecret', 30, 'My App');
|
|
172
|
+
|
|
173
|
+
-- 2. User scans QR code with authenticator app
|
|
174
|
+
|
|
175
|
+
-- 3. User provides first code to verify setup
|
|
176
|
+
SELECT totp.verify('newsecret', '123456', 30, 6);
|
|
177
|
+
|
|
178
|
+
-- 4. If verified, enable 2FA
|
|
179
|
+
UPDATE user_totp
|
|
180
|
+
SET enabled = true
|
|
181
|
+
WHERE user_id = 'user-uuid';
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Use Cases
|
|
185
|
+
|
|
186
|
+
- **Two-Factor Authentication (2FA)**: Add an extra layer of security to user logins
|
|
187
|
+
- **API Access Tokens**: Generate time-based tokens for API authentication
|
|
188
|
+
- **Transaction Verification**: Require TOTP codes for sensitive operations
|
|
189
|
+
- **Admin Access**: Require 2FA for administrative functions
|
|
190
|
+
- **Password Reset**: Use TOTP as part of password reset flow
|
|
191
|
+
|
|
192
|
+
## Dependencies
|
|
193
|
+
|
|
194
|
+
- `@pgpm/base32`: Base32 encoding for TOTP secrets
|
|
195
|
+
- `@pgpm/verify`: Verification utilities
|
|
196
|
+
|
|
197
|
+
## Testing
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
pnpm test
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Caveats
|
|
54
204
|
|
|
55
205
|
Currently only supports `sha1`, pull requests welcome!
|
|
56
206
|
|
|
57
|
-
|
|
207
|
+
## Debugging
|
|
58
208
|
|
|
59
209
|
use the verbose option to show keys
|
|
60
210
|
|
|
@@ -75,8 +225,7 @@ using time for testing
|
|
|
75
225
|
|
|
76
226
|
oathtool --totp -v -d 6 -s 30s -b vmlhl2knm27eftq7 --now "2020-02-05 22:11:40 UTC"
|
|
77
227
|
|
|
78
|
-
|
|
79
|
-
# credits
|
|
228
|
+
## Credits
|
|
80
229
|
|
|
81
230
|
Thanks to
|
|
82
231
|
|
|
@@ -90,7 +239,9 @@ And major improvements from
|
|
|
90
239
|
|
|
91
240
|
https://gist.github.com/bwbroersma/676d0de32263ed554584ab132434ebd9
|
|
92
241
|
|
|
93
|
-
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Development
|
|
94
245
|
|
|
95
246
|
## start the postgres db process
|
|
96
247
|
|
|
@@ -131,30 +282,110 @@ yarn test:watch
|
|
|
131
282
|
Create a new folder in `packages/`
|
|
132
283
|
|
|
133
284
|
```sh
|
|
134
|
-
|
|
285
|
+
pgpm init
|
|
135
286
|
```
|
|
136
287
|
|
|
137
288
|
Then, run a generator:
|
|
138
289
|
|
|
139
290
|
```sh
|
|
140
|
-
|
|
291
|
+
pgpm generate
|
|
141
292
|
```
|
|
142
293
|
|
|
143
294
|
You can also add arguments if you already know what you want to do:
|
|
144
295
|
|
|
145
296
|
```sh
|
|
146
|
-
|
|
147
|
-
|
|
297
|
+
pgpm generate schema --schema myschema
|
|
298
|
+
pgpm generate table --schema myschema --table mytable
|
|
148
299
|
```
|
|
149
300
|
|
|
150
301
|
## deploy code as extensions
|
|
151
302
|
|
|
152
|
-
`cd` into `packages/<module>`, and run `
|
|
303
|
+
`cd` into `packages/<module>`, and run `pgpm package`. This will make an sql file in `packages/<module>/sql/` used for `CREATE EXTENSION` calls to install your sqitch module as an extension.
|
|
153
304
|
|
|
154
305
|
## recursive deploy
|
|
155
306
|
|
|
156
307
|
You can also deploy all modules utilizing versioning as sqtich modules. Remove `--createdb` if you already created your db:
|
|
157
308
|
|
|
158
309
|
```sh
|
|
159
|
-
|
|
310
|
+
pgpm deploy mydb1 --yes --createdb
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
### **Before You Begin**
|
|
316
|
+
|
|
317
|
+
```bash
|
|
318
|
+
# 1. Install pgpm
|
|
319
|
+
npm install -g pgpm
|
|
320
|
+
|
|
321
|
+
# 2. Start Postgres (Docker or local)
|
|
322
|
+
pgpm docker start
|
|
323
|
+
|
|
324
|
+
# 3. Load PG* environment variables (PGHOST, PGUSER, ...)
|
|
325
|
+
eval "$(pgpm env)"
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### **Starting a New Project**
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# 1. Create a workspace
|
|
334
|
+
pgpm init --workspace
|
|
335
|
+
cd my-app
|
|
336
|
+
|
|
337
|
+
# 2. Create your first module
|
|
338
|
+
pgpm init
|
|
339
|
+
|
|
340
|
+
# 3. Add a migration
|
|
341
|
+
pgpm add some_change
|
|
342
|
+
|
|
343
|
+
# 4. Deploy (auto-creates database)
|
|
344
|
+
pgpm deploy --createdb
|
|
160
345
|
```
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
### **Working With an Existing Project**
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
# 1. Clone and enter the project
|
|
353
|
+
git clone <repo> && cd <project>
|
|
354
|
+
|
|
355
|
+
# 2. Install dependencies
|
|
356
|
+
pnpm install
|
|
357
|
+
|
|
358
|
+
# 3. Deploy locally
|
|
359
|
+
pgpm deploy --createdb
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
### **Testing a Module Inside a Workspace**
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
# 1. Install workspace deps
|
|
368
|
+
pnpm install
|
|
369
|
+
|
|
370
|
+
# 2. Enter the module directory
|
|
371
|
+
cd packages/<some-module>
|
|
372
|
+
|
|
373
|
+
# 3. Run tests in watch mode
|
|
374
|
+
pnpm test:watch
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Related Tooling
|
|
378
|
+
|
|
379
|
+
* [pgpm](https://github.com/launchql/launchql/tree/main/packages/pgpm): **🖥️ PostgreSQL Package Manager** for modular Postgres development. Works with database workspaces, scaffolding, migrations, seeding, and installing database packages.
|
|
380
|
+
* [pgsql-test](https://github.com/launchql/launchql/tree/main/packages/pgsql-test): **📊 Isolated testing environments** with per-test transaction rollbacks—ideal for integration tests, complex migrations, and RLS simulation.
|
|
381
|
+
* [supabase-test](https://github.com/launchql/launchql/tree/main/packages/supabase-test): **🧪 Supabase-native test harness** preconfigured for the local Supabase stack—per-test rollbacks, JWT/role context helpers, and CI/GitHub Actions ready.
|
|
382
|
+
* [graphile-test](https://github.com/launchql/launchql/tree/main/packages/graphile-test): **🔐 Authentication mocking** for Graphile-focused test helpers and emulating row-level security contexts.
|
|
383
|
+
* [pgsql-parser](https://github.com/launchql/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
|
|
384
|
+
* [libpg-query-node](https://github.com/launchql/libpg-query-node): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
|
|
385
|
+
* [pg-proto-parser](https://github.com/launchql/pg-proto-parser): **📦 Protobuf parser** for parsing PostgreSQL Protocol Buffers definitions to generate TypeScript interfaces, utility functions, and JSON mappings for enums.
|
|
386
|
+
|
|
387
|
+
## Disclaimer
|
|
388
|
+
|
|
389
|
+
AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
|
|
390
|
+
|
|
391
|
+
No developer or entity involved in creating this software will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the code, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.
|
package/launchql-totp.control
CHANGED
package/package.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgpm/totp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Time-based One-Time Password (TOTP) authentication",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
|
-
"bundle": "
|
|
9
|
+
"bundle": "pgpm package",
|
|
10
10
|
"test": "jest",
|
|
11
11
|
"test:watch": "jest --watch"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@pgpm/base32": "0.
|
|
15
|
-
"@pgpm/verify": "0.
|
|
14
|
+
"@pgpm/base32": "0.6.0",
|
|
15
|
+
"@pgpm/verify": "0.6.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"
|
|
18
|
+
"pgpm": "^0.2.0"
|
|
19
19
|
},
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "https://github.com/launchql/
|
|
22
|
+
"url": "https://github.com/launchql/pgpm-modules"
|
|
23
23
|
},
|
|
24
|
-
"homepage": "https://github.com/launchql/
|
|
24
|
+
"homepage": "https://github.com/launchql/pgpm-modules",
|
|
25
25
|
"bugs": {
|
|
26
|
-
"url": "https://github.com/launchql/
|
|
26
|
+
"url": "https://github.com/launchql/pgpm-modules/issues"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "c7d0eae588d7a764b382a330c8b853b341b13fb2"
|
|
29
29
|
}
|
|
File without changes
|
|
File without changes
|