@pgpm/base32 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,7 +2,70 @@
|
|
|
2
2
|
|
|
3
3
|
RFC4648 Base32 encode/decode in plpgsql
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`@pgpm/base32` implements Base32 encoding and decoding entirely in PostgreSQL using plpgsql. Base32 is commonly used for encoding binary data in a human-readable format, particularly for TOTP secrets, API keys, and other security tokens. This package provides a pure SQL implementation without external dependencies.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Pure plpgsql Implementation**: No external dependencies or libraries required
|
|
12
|
+
- **RFC 4648 Compliant**: Follows the Base32 standard
|
|
13
|
+
- **Bidirectional Conversion**: Encode to Base32 and decode back to original
|
|
14
|
+
- **Case Insensitive**: Handles both uppercase and lowercase Base32 strings
|
|
15
|
+
- **TOTP Integration**: Perfect for encoding TOTP secrets
|
|
16
|
+
- **Lightweight**: Minimal overhead, runs entirely in PostgreSQL
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
If you have `pgpm` installed:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pgpm install @pgpm/base32
|
|
24
|
+
pgpm deploy
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This is a quick way to get started. The sections below provide more detailed installation options.
|
|
28
|
+
|
|
29
|
+
### Prerequisites
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Install pgpm globally
|
|
33
|
+
npm install -g pgpm
|
|
34
|
+
|
|
35
|
+
# Start PostgreSQL
|
|
36
|
+
pgpm docker start
|
|
37
|
+
|
|
38
|
+
# Set environment variables
|
|
39
|
+
eval "$(pgpm env)"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Deploy
|
|
43
|
+
|
|
44
|
+
#### Option 1: Deploy by installing with pgpm
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pgpm install @pgpm/base32
|
|
48
|
+
pgpm deploy
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Option 2: Deploy from Package Directory
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
cd packages/utils/base32
|
|
55
|
+
pgpm deploy --createdb
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Option 3: Deploy from Workspace Root
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Install workspace dependencies
|
|
62
|
+
pnpm install
|
|
63
|
+
|
|
64
|
+
# Deploy with dependencies
|
|
65
|
+
pgpm deploy mydb1 --yes --createdb
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Usage
|
|
6
69
|
|
|
7
70
|
```sql
|
|
8
71
|
select base32.encode('foo');
|
|
@@ -13,7 +76,158 @@ select base32.decode('MZXW6===');
|
|
|
13
76
|
-- foo
|
|
14
77
|
```
|
|
15
78
|
|
|
16
|
-
|
|
79
|
+
## Use Cases
|
|
80
|
+
|
|
81
|
+
### TOTP Secret Encoding
|
|
82
|
+
|
|
83
|
+
Base32 is the standard encoding for TOTP secrets:
|
|
84
|
+
|
|
85
|
+
```sql
|
|
86
|
+
-- Generate a random secret and encode it
|
|
87
|
+
SELECT base32.encode('randomsecret123');
|
|
88
|
+
-- Result: MJQXGZJTGIQGS4ZAON2XAZLSEBRW63LNN5XCA2LOEBRW63LQMFZXG===
|
|
89
|
+
|
|
90
|
+
-- Use with TOTP
|
|
91
|
+
SELECT totp.generate(base32.encode('mysecret'));
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### API Key Encoding
|
|
95
|
+
|
|
96
|
+
Encode binary data as human-readable API keys:
|
|
97
|
+
|
|
98
|
+
```sql
|
|
99
|
+
-- Encode a UUID as Base32
|
|
100
|
+
SELECT base32.encode(gen_random_uuid()::text);
|
|
101
|
+
|
|
102
|
+
-- Create a table with Base32-encoded keys
|
|
103
|
+
CREATE TABLE api_keys (
|
|
104
|
+
id serial PRIMARY KEY,
|
|
105
|
+
user_id uuid,
|
|
106
|
+
key_encoded text DEFAULT base32.encode(gen_random_bytes(20)::text),
|
|
107
|
+
created_at timestamptz DEFAULT now()
|
|
108
|
+
);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Data Obfuscation
|
|
112
|
+
|
|
113
|
+
Encode sensitive identifiers:
|
|
114
|
+
|
|
115
|
+
```sql
|
|
116
|
+
-- Encode user IDs for public URLs
|
|
117
|
+
CREATE FUNCTION get_public_user_id(user_uuid uuid)
|
|
118
|
+
RETURNS text AS $$
|
|
119
|
+
BEGIN
|
|
120
|
+
RETURN base32.encode(user_uuid::text);
|
|
121
|
+
END;
|
|
122
|
+
$$ LANGUAGE plpgsql;
|
|
123
|
+
|
|
124
|
+
-- Decode back to UUID
|
|
125
|
+
CREATE FUNCTION get_user_from_public_id(public_id text)
|
|
126
|
+
RETURNS uuid AS $$
|
|
127
|
+
BEGIN
|
|
128
|
+
RETURN base32.decode(public_id)::uuid;
|
|
129
|
+
END;
|
|
130
|
+
$$ LANGUAGE plpgsql;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### File Integrity Verification
|
|
134
|
+
|
|
135
|
+
Encode checksums and hashes:
|
|
136
|
+
|
|
137
|
+
```sql
|
|
138
|
+
-- Encode a SHA256 hash
|
|
139
|
+
SELECT base32.encode(
|
|
140
|
+
encode(digest('file contents', 'sha256'), 'hex')
|
|
141
|
+
);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Integration Examples
|
|
145
|
+
|
|
146
|
+
### With @pgpm/totp
|
|
147
|
+
|
|
148
|
+
Base32 is essential for TOTP authentication:
|
|
149
|
+
|
|
150
|
+
```sql
|
|
151
|
+
-- Store TOTP secret in Base32 format
|
|
152
|
+
CREATE TABLE user_2fa (
|
|
153
|
+
user_id uuid PRIMARY KEY,
|
|
154
|
+
secret_base32 text NOT NULL,
|
|
155
|
+
enabled boolean DEFAULT false
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
-- Generate and store Base32-encoded secret
|
|
159
|
+
INSERT INTO user_2fa (user_id, secret_base32)
|
|
160
|
+
VALUES (
|
|
161
|
+
'user-uuid',
|
|
162
|
+
base32.encode('randomsecret')
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
-- Generate TOTP code from Base32 secret
|
|
166
|
+
SELECT totp.generate(
|
|
167
|
+
base32.decode(secret_base32)
|
|
168
|
+
) FROM user_2fa WHERE user_id = 'user-uuid';
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### With @pgpm/encrypted-secrets
|
|
172
|
+
|
|
173
|
+
Combine with encrypted secrets for secure storage:
|
|
174
|
+
|
|
175
|
+
```sql
|
|
176
|
+
-- Store Base32-encoded secret encrypted
|
|
177
|
+
SELECT encrypted_secrets.secrets_upsert(
|
|
178
|
+
'user-uuid',
|
|
179
|
+
'totp_secret',
|
|
180
|
+
base32.encode('mysecret'),
|
|
181
|
+
'pgp'
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
-- Retrieve and use
|
|
185
|
+
SELECT totp.generate(
|
|
186
|
+
base32.decode(
|
|
187
|
+
encrypted_secrets.secrets_getter('user-uuid', 'totp_secret')
|
|
188
|
+
)
|
|
189
|
+
);
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Character Set
|
|
193
|
+
|
|
194
|
+
Base32 uses the following character set (RFC 4648):
|
|
195
|
+
|
|
196
|
+
```
|
|
197
|
+
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 2 3 4 5 6 7
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Padding character: `=`
|
|
201
|
+
|
|
202
|
+
## Comparison with Base64
|
|
203
|
+
|
|
204
|
+
Base32 vs Base64:
|
|
205
|
+
|
|
206
|
+
| Feature | Base32 | Base64 |
|
|
207
|
+
|---------|--------|--------|
|
|
208
|
+
| Character Set | A-Z, 2-7 | A-Z, a-z, 0-9, +, / |
|
|
209
|
+
| Case Sensitive | No | Yes |
|
|
210
|
+
| URL Safe | Yes | Requires modification |
|
|
211
|
+
| Human Readable | More readable | Less readable |
|
|
212
|
+
| Efficiency | ~60% overhead | ~33% overhead |
|
|
213
|
+
| Use Case | TOTP, user-facing | General encoding |
|
|
214
|
+
|
|
215
|
+
Base32 is preferred for TOTP because:
|
|
216
|
+
- Case insensitive (easier to type)
|
|
217
|
+
- No ambiguous characters (0/O, 1/I/l)
|
|
218
|
+
- URL-safe without modification
|
|
219
|
+
|
|
220
|
+
## Testing
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
pnpm test
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Dependencies
|
|
227
|
+
|
|
228
|
+
None - this is a pure plpgsql implementation.
|
|
229
|
+
|
|
230
|
+
## Credits
|
|
17
231
|
|
|
18
232
|
Thanks to
|
|
19
233
|
|
|
@@ -21,7 +235,9 @@ https://tools.ietf.org/html/rfc4648
|
|
|
21
235
|
|
|
22
236
|
https://www.youtube.com/watch?v=Va8FLD-iuTg
|
|
23
237
|
|
|
24
|
-
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Development
|
|
25
241
|
|
|
26
242
|
## start the postgres db process
|
|
27
243
|
|
|
@@ -62,30 +278,110 @@ yarn test:watch
|
|
|
62
278
|
Create a new folder in `packages/`
|
|
63
279
|
|
|
64
280
|
```sh
|
|
65
|
-
|
|
281
|
+
pgpm init
|
|
66
282
|
```
|
|
67
283
|
|
|
68
284
|
Then, run a generator:
|
|
69
285
|
|
|
70
286
|
```sh
|
|
71
|
-
|
|
287
|
+
pgpm generate
|
|
72
288
|
```
|
|
73
289
|
|
|
74
290
|
You can also add arguments if you already know what you want to do:
|
|
75
291
|
|
|
76
292
|
```sh
|
|
77
|
-
|
|
78
|
-
|
|
293
|
+
pgpm generate schema --schema myschema
|
|
294
|
+
pgpm generate table --schema myschema --table mytable
|
|
79
295
|
```
|
|
80
296
|
|
|
81
297
|
## deploy code as extensions
|
|
82
298
|
|
|
83
|
-
`cd` into `packages/<module>`, and run `
|
|
299
|
+
`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.
|
|
84
300
|
|
|
85
301
|
## recursive deploy
|
|
86
302
|
|
|
87
303
|
You can also deploy all modules utilizing versioning as sqtich modules. Remove `--createdb` if you already created your db:
|
|
88
304
|
|
|
89
305
|
```sh
|
|
90
|
-
|
|
91
|
-
```
|
|
306
|
+
pgpm deploy mydb1 --yes --createdb
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### **Before You Begin**
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
# 1. Install pgpm
|
|
315
|
+
npm install -g pgpm
|
|
316
|
+
|
|
317
|
+
# 2. Start Postgres (Docker or local)
|
|
318
|
+
pgpm docker start
|
|
319
|
+
|
|
320
|
+
# 3. Load PG* environment variables (PGHOST, PGUSER, ...)
|
|
321
|
+
eval "$(pgpm env)"
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
### **Starting a New Project**
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
# 1. Create a workspace
|
|
330
|
+
pgpm init --workspace
|
|
331
|
+
cd my-app
|
|
332
|
+
|
|
333
|
+
# 2. Create your first module
|
|
334
|
+
pgpm init
|
|
335
|
+
|
|
336
|
+
# 3. Add a migration
|
|
337
|
+
pgpm add some_change
|
|
338
|
+
|
|
339
|
+
# 4. Deploy (auto-creates database)
|
|
340
|
+
pgpm deploy --createdb
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
### **Working With an Existing Project**
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
# 1. Clone and enter the project
|
|
349
|
+
git clone <repo> && cd <project>
|
|
350
|
+
|
|
351
|
+
# 2. Install dependencies
|
|
352
|
+
pnpm install
|
|
353
|
+
|
|
354
|
+
# 3. Deploy locally
|
|
355
|
+
pgpm deploy --createdb
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
### **Testing a Module Inside a Workspace**
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# 1. Install workspace deps
|
|
364
|
+
pnpm install
|
|
365
|
+
|
|
366
|
+
# 2. Enter the module directory
|
|
367
|
+
cd packages/<some-module>
|
|
368
|
+
|
|
369
|
+
# 3. Run tests in watch mode
|
|
370
|
+
pnpm test:watch
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## Related Tooling
|
|
374
|
+
|
|
375
|
+
* [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.
|
|
376
|
+
* [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.
|
|
377
|
+
* [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.
|
|
378
|
+
* [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.
|
|
379
|
+
* [pgsql-parser](https://github.com/launchql/pgsql-parser): **🔄 SQL conversion engine** that interprets and converts PostgreSQL syntax.
|
|
380
|
+
* [libpg-query-node](https://github.com/launchql/libpg-query-node): **🌉 Node.js bindings** for `libpg_query`, converting SQL into parse trees.
|
|
381
|
+
* [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.
|
|
382
|
+
|
|
383
|
+
## Disclaimer
|
|
384
|
+
|
|
385
|
+
AS DESCRIBED IN THE LICENSES, THE SOFTWARE IS PROVIDED "AS IS", AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.
|
|
386
|
+
|
|
387
|
+
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-base32.control
CHANGED
package/package.json
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pgpm/base32",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Base32 encoding and decoding functions for PostgreSQL",
|
|
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/verify": "0.
|
|
14
|
+
"@pgpm/verify": "0.6.0"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"
|
|
17
|
+
"pgpm": "^0.2.0"
|
|
18
18
|
},
|
|
19
19
|
"repository": {
|
|
20
20
|
"type": "git",
|
|
21
|
-
"url": "https://github.com/launchql/
|
|
21
|
+
"url": "https://github.com/launchql/pgpm-modules"
|
|
22
22
|
},
|
|
23
|
-
"homepage": "https://github.com/launchql/
|
|
23
|
+
"homepage": "https://github.com/launchql/pgpm-modules",
|
|
24
24
|
"bugs": {
|
|
25
|
-
"url": "https://github.com/launchql/
|
|
25
|
+
"url": "https://github.com/launchql/pgpm-modules/issues"
|
|
26
26
|
},
|
|
27
|
-
"gitHead": "
|
|
27
|
+
"gitHead": "c7d0eae588d7a764b382a330c8b853b341b13fb2"
|
|
28
28
|
}
|
|
File without changes
|
|
File without changes
|