@wtasnorg/node-lib 0.0.8 → 0.0.9
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/changelog.txt +12 -0
- package/docs/README.md +10 -0
- package/docs/docs.json +570 -137
- package/docs/functions/createFindDirectories.md +1 -1
- package/docs/functions/decode.md +49 -0
- package/docs/functions/encode.md +45 -0
- package/docs/functions/hello.md +1 -1
- package/docs/functions/parseUserAgent.md +1 -1
- package/docs/functions/pojo.md +1 -1
- package/docs/interfaces/FileSystemDependencies.md +3 -3
- package/docs/interfaces/FindDirectoriesOptions.md +5 -5
- package/docs/interfaces/UserAgentInfo.md +6 -6
- package/docs/type-aliases/Base64CharsetType.md +13 -0
- package/docs/variables/Base64Charset.md +17 -0
- package/gen-docs/001_base64_refine.txt +50 -0
- package/gen-sec/001_base64_security.txt +75 -0
- package/package.json +1 -1
- package/readme.txt +1 -0
- package/src/base64.d.ts +58 -0
- package/src/base64.js +138 -0
- package/src/base64.test.d.ts +2 -0
- package/src/base64.test.js +106 -0
- package/src/base64.test.ts +125 -0
- package/src/base64.ts +163 -0
- package/src/index.d.ts +4 -2
- package/src/index.js +2 -1
- package/src/index.ts +7 -1
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> **createFindDirectories**(`deps`): (`root`, `options`) => `Promise`\<`string`[]\>
|
|
10
10
|
|
|
11
|
-
Defined in: [find.ts:19](https://github.com/wtasg/node-lib/blob/
|
|
11
|
+
Defined in: [find.ts:19](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L19)
|
|
12
12
|
|
|
13
13
|
Factory that produces an async findDirectories function with
|
|
14
14
|
injected filesystem dependencies for full testability.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[**@wtasnorg/node-lib**](../README.md)
|
|
2
|
+
|
|
3
|
+
***
|
|
4
|
+
|
|
5
|
+
[@wtasnorg/node-lib](../README.md) / decode
|
|
6
|
+
|
|
7
|
+
# Function: decode()
|
|
8
|
+
|
|
9
|
+
> **decode**(`input`, `charset`): `string`
|
|
10
|
+
|
|
11
|
+
Defined in: base64.ts:119
|
|
12
|
+
|
|
13
|
+
Decode a Base64 string.
|
|
14
|
+
|
|
15
|
+
## Parameters
|
|
16
|
+
|
|
17
|
+
### input
|
|
18
|
+
|
|
19
|
+
`string`
|
|
20
|
+
|
|
21
|
+
The Base64 encoded string.
|
|
22
|
+
|
|
23
|
+
### charset
|
|
24
|
+
|
|
25
|
+
The charset variant to use (default: "standard").
|
|
26
|
+
|
|
27
|
+
`"standard"` | `"urlsafe"` | `"imap"` | `"radix64"`
|
|
28
|
+
|
|
29
|
+
## Returns
|
|
30
|
+
|
|
31
|
+
`string`
|
|
32
|
+
|
|
33
|
+
The decoded string.
|
|
34
|
+
|
|
35
|
+
## Example
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { decode } from "./base64.js";
|
|
39
|
+
|
|
40
|
+
decode("SGVsbG8sIFdvcmxkIQ==");
|
|
41
|
+
// => "Hello, World!"
|
|
42
|
+
|
|
43
|
+
decode("SGVsbG8sIFdvcmxkIQ==", "standard");
|
|
44
|
+
// => "Hello, World!"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Throws
|
|
48
|
+
|
|
49
|
+
Error if the input contains invalid characters.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[**@wtasnorg/node-lib**](../README.md)
|
|
2
|
+
|
|
3
|
+
***
|
|
4
|
+
|
|
5
|
+
[@wtasnorg/node-lib](../README.md) / encode
|
|
6
|
+
|
|
7
|
+
# Function: encode()
|
|
8
|
+
|
|
9
|
+
> **encode**(`input`, `charset`): `string`
|
|
10
|
+
|
|
11
|
+
Defined in: base64.ts:79
|
|
12
|
+
|
|
13
|
+
Encode a string to Base64.
|
|
14
|
+
|
|
15
|
+
## Parameters
|
|
16
|
+
|
|
17
|
+
### input
|
|
18
|
+
|
|
19
|
+
`string`
|
|
20
|
+
|
|
21
|
+
The string to encode.
|
|
22
|
+
|
|
23
|
+
### charset
|
|
24
|
+
|
|
25
|
+
The charset variant to use (default: "standard").
|
|
26
|
+
|
|
27
|
+
`"standard"` | `"urlsafe"` | `"imap"` | `"radix64"`
|
|
28
|
+
|
|
29
|
+
## Returns
|
|
30
|
+
|
|
31
|
+
`string`
|
|
32
|
+
|
|
33
|
+
The Base64 encoded string.
|
|
34
|
+
|
|
35
|
+
## Example
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { encode } from "./base64.js";
|
|
39
|
+
|
|
40
|
+
encode("Hello, World!");
|
|
41
|
+
// => "SGVsbG8sIFdvcmxkIQ=="
|
|
42
|
+
|
|
43
|
+
encode("Hello, World!", "urlsafe");
|
|
44
|
+
// => "SGVsbG8sIFdvcmxkIQ=="
|
|
45
|
+
```
|
package/docs/functions/hello.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> **hello**(): `Promise`\<`string`\>
|
|
10
10
|
|
|
11
|
-
Defined in: [hello.ts:6](https://github.com/wtasg/node-lib/blob/
|
|
11
|
+
Defined in: [hello.ts:6](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/hello.ts#L6)
|
|
12
12
|
|
|
13
13
|
A sample function that should work to test if lib is installed correctly.
|
|
14
14
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> **parseUserAgent**(`ua`): [`UserAgentInfo`](../interfaces/UserAgentInfo.md)
|
|
10
10
|
|
|
11
|
-
Defined in: [user-agent.ts:48](https://github.com/wtasg/node-lib/blob/
|
|
11
|
+
Defined in: [user-agent.ts:48](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/user-agent.ts#L48)
|
|
12
12
|
|
|
13
13
|
Parses a user-agent string into a UserAgentInfo object.
|
|
14
14
|
|
package/docs/functions/pojo.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
> **pojo**\<`T`\>(`instance`): `Record`\<`string`, `unknown`\>
|
|
10
10
|
|
|
11
|
-
Defined in: [pojo.ts:10](https://github.com/wtasg/node-lib/blob/
|
|
11
|
+
Defined in: [pojo.ts:10](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/pojo.ts#L10)
|
|
12
12
|
|
|
13
13
|
Convert a class instance into a plain JavaScript object.
|
|
14
14
|
Copies only the instance's own enumerable data properties
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: FileSystemDependencies
|
|
8
8
|
|
|
9
|
-
Defined in: [find.ts:3](https://github.com/wtasg/node-lib/blob/
|
|
9
|
+
Defined in: [find.ts:3](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L3)
|
|
10
10
|
|
|
11
11
|
## Properties
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ Defined in: [find.ts:3](https://github.com/wtasg/node-lib/blob/ac07f7b7be8233cfd
|
|
|
14
14
|
|
|
15
15
|
> **readdir**: (`_path`, `_opts`) => `Promise`\<`object`[]\>
|
|
16
16
|
|
|
17
|
-
Defined in: [find.ts:4](https://github.com/wtasg/node-lib/blob/
|
|
17
|
+
Defined in: [find.ts:4](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L4)
|
|
18
18
|
|
|
19
19
|
#### Parameters
|
|
20
20
|
|
|
@@ -38,7 +38,7 @@ Defined in: [find.ts:4](https://github.com/wtasg/node-lib/blob/ac07f7b7be8233cfd
|
|
|
38
38
|
|
|
39
39
|
> **stat**: (`_path`) => `Promise`\<\{ `isDirectory`: `boolean`; \}\>
|
|
40
40
|
|
|
41
|
-
Defined in: [find.ts:5](https://github.com/wtasg/node-lib/blob/
|
|
41
|
+
Defined in: [find.ts:5](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L5)
|
|
42
42
|
|
|
43
43
|
#### Parameters
|
|
44
44
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: FindDirectoriesOptions
|
|
8
8
|
|
|
9
|
-
Defined in: [find.ts:8](https://github.com/wtasg/node-lib/blob/
|
|
9
|
+
Defined in: [find.ts:8](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L8)
|
|
10
10
|
|
|
11
11
|
## Properties
|
|
12
12
|
|
|
@@ -14,7 +14,7 @@ Defined in: [find.ts:8](https://github.com/wtasg/node-lib/blob/ac07f7b7be8233cfd
|
|
|
14
14
|
|
|
15
15
|
> `optional` **allowlist**: `string`[] \| (`_absPath`, `_name`) => `boolean`
|
|
16
16
|
|
|
17
|
-
Defined in: [find.ts:11](https://github.com/wtasg/node-lib/blob/
|
|
17
|
+
Defined in: [find.ts:11](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L11)
|
|
18
18
|
|
|
19
19
|
***
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ Defined in: [find.ts:11](https://github.com/wtasg/node-lib/blob/ac07f7b7be8233cf
|
|
|
22
22
|
|
|
23
23
|
> `optional` **blocklist**: `string`[] \| (`_absPath`, `_name`) => `boolean`
|
|
24
24
|
|
|
25
|
-
Defined in: [find.ts:12](https://github.com/wtasg/node-lib/blob/
|
|
25
|
+
Defined in: [find.ts:12](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L12)
|
|
26
26
|
|
|
27
27
|
***
|
|
28
28
|
|
|
@@ -30,7 +30,7 @@ Defined in: [find.ts:12](https://github.com/wtasg/node-lib/blob/ac07f7b7be8233cf
|
|
|
30
30
|
|
|
31
31
|
> `optional` **followSymlinks**: `boolean`
|
|
32
32
|
|
|
33
|
-
Defined in: [find.ts:10](https://github.com/wtasg/node-lib/blob/
|
|
33
|
+
Defined in: [find.ts:10](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L10)
|
|
34
34
|
|
|
35
35
|
***
|
|
36
36
|
|
|
@@ -38,4 +38,4 @@ Defined in: [find.ts:10](https://github.com/wtasg/node-lib/blob/ac07f7b7be8233cf
|
|
|
38
38
|
|
|
39
39
|
> `optional` **maxDepth**: `number`
|
|
40
40
|
|
|
41
|
-
Defined in: [find.ts:9](https://github.com/wtasg/node-lib/blob/
|
|
41
|
+
Defined in: [find.ts:9](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/find.ts#L9)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
# Interface: UserAgentInfo
|
|
8
8
|
|
|
9
|
-
Defined in: [user-agent.ts:4](https://github.com/wtasg/node-lib/blob/
|
|
9
|
+
Defined in: [user-agent.ts:4](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/user-agent.ts#L4)
|
|
10
10
|
|
|
11
11
|
Information extracted from a user-agent string.
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ Information extracted from a user-agent string.
|
|
|
16
16
|
|
|
17
17
|
> **browser**: `string`
|
|
18
18
|
|
|
19
|
-
Defined in: [user-agent.ts:8](https://github.com/wtasg/node-lib/blob/
|
|
19
|
+
Defined in: [user-agent.ts:8](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/user-agent.ts#L8)
|
|
20
20
|
|
|
21
21
|
Browser name (e.g., Chrome, Firefox, Safari, Edge, Opera, Other).
|
|
22
22
|
|
|
@@ -26,7 +26,7 @@ Browser name (e.g., Chrome, Firefox, Safari, Edge, Opera, Other).
|
|
|
26
26
|
|
|
27
27
|
> **device**: `string`
|
|
28
28
|
|
|
29
|
-
Defined in: [user-agent.ts:20](https://github.com/wtasg/node-lib/blob/
|
|
29
|
+
Defined in: [user-agent.ts:20](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/user-agent.ts#L20)
|
|
30
30
|
|
|
31
31
|
Device type (e.g., Mobile, Tablet, Desktop, Other).
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ Device type (e.g., Mobile, Tablet, Desktop, Other).
|
|
|
36
36
|
|
|
37
37
|
> **engine**: `string`
|
|
38
38
|
|
|
39
|
-
Defined in: [user-agent.ts:24](https://github.com/wtasg/node-lib/blob/
|
|
39
|
+
Defined in: [user-agent.ts:24](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/user-agent.ts#L24)
|
|
40
40
|
|
|
41
41
|
Rendering engine (e.g., Blink, WebKit, Gecko, Presto, Other).
|
|
42
42
|
|
|
@@ -46,7 +46,7 @@ Rendering engine (e.g., Blink, WebKit, Gecko, Presto, Other).
|
|
|
46
46
|
|
|
47
47
|
> **os**: `string`
|
|
48
48
|
|
|
49
|
-
Defined in: [user-agent.ts:16](https://github.com/wtasg/node-lib/blob/
|
|
49
|
+
Defined in: [user-agent.ts:16](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/user-agent.ts#L16)
|
|
50
50
|
|
|
51
51
|
Operating system (e.g., Windows, macOS, Linux, iOS, Android, Other).
|
|
52
52
|
|
|
@@ -56,6 +56,6 @@ Operating system (e.g., Windows, macOS, Linux, iOS, Android, Other).
|
|
|
56
56
|
|
|
57
57
|
> **version**: `string`
|
|
58
58
|
|
|
59
|
-
Defined in: [user-agent.ts:12](https://github.com/wtasg/node-lib/blob/
|
|
59
|
+
Defined in: [user-agent.ts:12](https://github.com/wtasg/node-lib/blob/b5efd5c345e8fa1bdc2a6d3ea4dd4b2eb5b9cc62/src/user-agent.ts#L12)
|
|
60
60
|
|
|
61
61
|
Browser version (e.g., 120.0.0.0).
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[**@wtasnorg/node-lib**](../README.md)
|
|
2
|
+
|
|
3
|
+
***
|
|
4
|
+
|
|
5
|
+
[@wtasnorg/node-lib](../README.md) / Base64CharsetType
|
|
6
|
+
|
|
7
|
+
# Type Alias: Base64CharsetType
|
|
8
|
+
|
|
9
|
+
> **Base64CharsetType** = *typeof* [`Base64Charset`](../variables/Base64Charset.md)\[`number`\]
|
|
10
|
+
|
|
11
|
+
Defined in: base64.ts:18
|
|
12
|
+
|
|
13
|
+
Base64 charset type.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[**@wtasnorg/node-lib**](../README.md)
|
|
2
|
+
|
|
3
|
+
***
|
|
4
|
+
|
|
5
|
+
[@wtasnorg/node-lib](../README.md) / Base64Charset
|
|
6
|
+
|
|
7
|
+
# Variable: Base64Charset
|
|
8
|
+
|
|
9
|
+
> `const` **Base64Charset**: readonly \[`"standard"`, `"urlsafe"`, `"imap"`, `"radix64"`\]
|
|
10
|
+
|
|
11
|
+
Defined in: base64.ts:13
|
|
12
|
+
|
|
13
|
+
Available Base64 charset variants.
|
|
14
|
+
- `standard`: RFC 4648 standard alphabet (A-Z, a-z, 0-9, +, /)
|
|
15
|
+
- `urlsafe`: URL and filename safe (A-Z, a-z, 0-9, -, _)
|
|
16
|
+
- `imap`: Modified Base64 for IMAP mailbox names (A-Z, a-z, 0-9, +, ,)
|
|
17
|
+
- `radix64`: Base64 variant used in OpenPGP (A-Z, a-z, 0-9, +, /)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Base64 Module Refinement Pass
|
|
2
|
+
# Date: 2026-01-19
|
|
3
|
+
# Scope: src/base64.ts
|
|
4
|
+
|
|
5
|
+
## SRP Analysis
|
|
6
|
+
- encode(): Single responsibility - string to Base64
|
|
7
|
+
- decode(): Single responsibility - Base64 to string
|
|
8
|
+
- buildDecodeTable(): Single responsibility - lookup table creation
|
|
9
|
+
- No business logic mixing, no I/O coupling
|
|
10
|
+
|
|
11
|
+
## Dependency Direction
|
|
12
|
+
- No external dependencies beyond Node.js built-ins (TextEncoder/TextDecoder)
|
|
13
|
+
- No circular dependencies
|
|
14
|
+
- Pure computation, no framework coupling
|
|
15
|
+
|
|
16
|
+
## Purity & Side-Effects
|
|
17
|
+
- All functions are pure (no I/O, no global state mutation)
|
|
18
|
+
- Deterministic: same input always produces same output
|
|
19
|
+
- No hidden state mutation
|
|
20
|
+
|
|
21
|
+
## Naming Review
|
|
22
|
+
- encode/decode: Clear, idiomatic names
|
|
23
|
+
- Base64Charset: Descriptive, matches domain
|
|
24
|
+
- CHARSETS/DECODE_TABLES: Clear internal constants
|
|
25
|
+
- buildDecodeTable: Accurate verb+noun pattern
|
|
26
|
+
|
|
27
|
+
## Error Handling
|
|
28
|
+
- decode() throws Error with specific character on invalid input
|
|
29
|
+
- Error message includes the offending character
|
|
30
|
+
- No swallowed exceptions
|
|
31
|
+
|
|
32
|
+
## API Surface
|
|
33
|
+
- Exports: encode, decode, Base64Charset, Base64CharsetType
|
|
34
|
+
- Minimal and focused public API
|
|
35
|
+
- Internal helpers (buildDecodeTable, CHARSETS, PAD) are not exported
|
|
36
|
+
|
|
37
|
+
## Invariants
|
|
38
|
+
- Charset type is constrained via TypeScript const assertion
|
|
39
|
+
- Invalid charset impossible at compile time
|
|
40
|
+
- Padding handled correctly per Base64 spec
|
|
41
|
+
|
|
42
|
+
## Test Coverage
|
|
43
|
+
- 74 tests total, base64 tests cover:
|
|
44
|
+
- Encode: empty, single char, padding, all charsets, UTF-8
|
|
45
|
+
- Decode: empty, padding, error handling
|
|
46
|
+
- Round-trip: all charsets with 10 test cases each
|
|
47
|
+
- Tests verify behavior, not implementation
|
|
48
|
+
|
|
49
|
+
## Summary
|
|
50
|
+
No actionable refinement items. Code is clean, focused, and well-tested.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Base64 Module Security Assessment
|
|
2
|
+
# Date: 2026-01-19
|
|
3
|
+
# Scope: src/base64.ts
|
|
4
|
+
|
|
5
|
+
## Attack Surface Inventory
|
|
6
|
+
- encode(input: string, charset): accepts user-controlled string
|
|
7
|
+
- decode(input: string, charset): accepts user-controlled Base64 string
|
|
8
|
+
- No network I/O, no file I/O, no exec
|
|
9
|
+
|
|
10
|
+
## Threat Model
|
|
11
|
+
- Attacker model: untrusted string input
|
|
12
|
+
- Assets: application stability, memory
|
|
13
|
+
- Trust boundary: function input parameters
|
|
14
|
+
|
|
15
|
+
## OWASP Top 10 Review
|
|
16
|
+
|
|
17
|
+
### A01 - Broken Access Control
|
|
18
|
+
- N/A: Pure computation, no access control
|
|
19
|
+
|
|
20
|
+
### A02 - Cryptographic Failures
|
|
21
|
+
- N/A: Not a cryptographic function (encoding != encryption)
|
|
22
|
+
- Note: radix64 is named for OpenPGP but is just Base64 alphabet
|
|
23
|
+
|
|
24
|
+
### A03 - Injection
|
|
25
|
+
- N/A: No SQL, command, or template execution
|
|
26
|
+
- Output is string manipulation only
|
|
27
|
+
|
|
28
|
+
### A04 - Insecure Design
|
|
29
|
+
- PASS: Input validation on decode via lookup table
|
|
30
|
+
- PASS: Invalid characters throw explicit error
|
|
31
|
+
|
|
32
|
+
### A05 - Security Misconfiguration
|
|
33
|
+
- N/A: No configuration, pure library code
|
|
34
|
+
|
|
35
|
+
### A06 - Vulnerable Components
|
|
36
|
+
- N/A: No external dependencies
|
|
37
|
+
|
|
38
|
+
### A07 - Identification & Authentication
|
|
39
|
+
- N/A: No auth logic
|
|
40
|
+
|
|
41
|
+
### A08 - Software & Data Integrity
|
|
42
|
+
- N/A: No deserialization or external data
|
|
43
|
+
|
|
44
|
+
### A09 - Logging & Monitoring
|
|
45
|
+
- N/A: Library code, no logging (appropriate)
|
|
46
|
+
|
|
47
|
+
### A10 - SSRF
|
|
48
|
+
- N/A: No URL handling
|
|
49
|
+
|
|
50
|
+
## Denial of Service Analysis
|
|
51
|
+
- Large input: TextEncoder/TextDecoder handle arbitrary sizes
|
|
52
|
+
- Memory: proportional to input size (expected for encoding)
|
|
53
|
+
- No regex catastrophic backtracking (simple /=+$/ pattern)
|
|
54
|
+
- No infinite loops: bounded by input length
|
|
55
|
+
|
|
56
|
+
## Input Validation
|
|
57
|
+
- encode(): accepts any valid JS string, converts via TextEncoder
|
|
58
|
+
- decode(): validates each character against charset lookup table
|
|
59
|
+
- Invalid input: throws Error immediately (fail-fast)
|
|
60
|
+
|
|
61
|
+
## Memory Safety
|
|
62
|
+
- Uses Uint8Array and standard JS arrays
|
|
63
|
+
- No buffer overflows possible in JS/TS
|
|
64
|
+
- No manual memory management
|
|
65
|
+
|
|
66
|
+
## Findings
|
|
67
|
+
Severity: NONE
|
|
68
|
+
|
|
69
|
+
## Summary
|
|
70
|
+
No security issues identified. The module is a pure computation library with:
|
|
71
|
+
- No external I/O
|
|
72
|
+
- No dangerous operations
|
|
73
|
+
- Proper input validation
|
|
74
|
+
- Explicit error handling
|
|
75
|
+
- Bounded resource usage
|
package/package.json
CHANGED
package/readme.txt
CHANGED
|
@@ -11,6 +11,7 @@ A library project for nodejs. #nodejs #typescript #library
|
|
|
11
11
|
2. `pojo` for converting class objects to Plain Old Javascript Objects.
|
|
12
12
|
3. `createFindDirectories` as a factory for finding directories; think `find path -type d`.
|
|
13
13
|
4. `parseUserAgent` for extracting information from user-agent strings.
|
|
14
|
+
5. `encode` / `decode` for Base64 encoding/decoding with charset variants (`standard`, `urlsafe`, `imap`, `radix64`).
|
|
14
15
|
|
|
15
16
|
## Develop
|
|
16
17
|
|
package/src/base64.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 encoding/decoding with multiple charset variants.
|
|
3
|
+
* @module base64
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Available Base64 charset variants.
|
|
7
|
+
* - `standard`: RFC 4648 standard alphabet (A-Z, a-z, 0-9, +, /)
|
|
8
|
+
* - `urlsafe`: URL and filename safe (A-Z, a-z, 0-9, -, _)
|
|
9
|
+
* - `imap`: Modified Base64 for IMAP mailbox names (A-Z, a-z, 0-9, +, ,)
|
|
10
|
+
* - `radix64`: Base64 variant used in OpenPGP (A-Z, a-z, 0-9, +, /)
|
|
11
|
+
*/
|
|
12
|
+
declare const Base64Charset: readonly ["standard", "urlsafe", "imap", "radix64"];
|
|
13
|
+
/**
|
|
14
|
+
* Base64 charset type.
|
|
15
|
+
*/
|
|
16
|
+
type Base64CharsetType = (typeof Base64Charset)[number];
|
|
17
|
+
/**
|
|
18
|
+
* Encode a string to Base64.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* import { encode } from "./base64.js";
|
|
23
|
+
*
|
|
24
|
+
* encode("Hello, World!");
|
|
25
|
+
* // => "SGVsbG8sIFdvcmxkIQ=="
|
|
26
|
+
*
|
|
27
|
+
* encode("Hello, World!", "urlsafe");
|
|
28
|
+
* // => "SGVsbG8sIFdvcmxkIQ=="
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @param input - The string to encode.
|
|
32
|
+
* @param charset - The charset variant to use (default: "standard").
|
|
33
|
+
* @returns The Base64 encoded string.
|
|
34
|
+
*/
|
|
35
|
+
declare function encode(input: string, charset?: Base64CharsetType): string;
|
|
36
|
+
/**
|
|
37
|
+
* Decode a Base64 string.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import { decode } from "./base64.js";
|
|
42
|
+
*
|
|
43
|
+
* decode("SGVsbG8sIFdvcmxkIQ==");
|
|
44
|
+
* // => "Hello, World!"
|
|
45
|
+
*
|
|
46
|
+
* decode("SGVsbG8sIFdvcmxkIQ==", "standard");
|
|
47
|
+
* // => "Hello, World!"
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @param input - The Base64 encoded string.
|
|
51
|
+
* @param charset - The charset variant to use (default: "standard").
|
|
52
|
+
* @returns The decoded string.
|
|
53
|
+
* @throws Error if the input contains invalid characters.
|
|
54
|
+
*/
|
|
55
|
+
declare function decode(input: string, charset?: Base64CharsetType): string;
|
|
56
|
+
export { encode, decode, Base64Charset };
|
|
57
|
+
export type { Base64CharsetType };
|
|
58
|
+
//# sourceMappingURL=base64.d.ts.map
|
package/src/base64.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base64 encoding/decoding with multiple charset variants.
|
|
3
|
+
* @module base64
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Available Base64 charset variants.
|
|
7
|
+
* - `standard`: RFC 4648 standard alphabet (A-Z, a-z, 0-9, +, /)
|
|
8
|
+
* - `urlsafe`: URL and filename safe (A-Z, a-z, 0-9, -, _)
|
|
9
|
+
* - `imap`: Modified Base64 for IMAP mailbox names (A-Z, a-z, 0-9, +, ,)
|
|
10
|
+
* - `radix64`: Base64 variant used in OpenPGP (A-Z, a-z, 0-9, +, /)
|
|
11
|
+
*/
|
|
12
|
+
const Base64Charset = ["standard", "urlsafe", "imap", "radix64"];
|
|
13
|
+
/**
|
|
14
|
+
* Charset alphabets for Base64 variants.
|
|
15
|
+
*/
|
|
16
|
+
const CHARSETS = {
|
|
17
|
+
standard: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
|
|
18
|
+
urlsafe: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
|
|
19
|
+
imap: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,",
|
|
20
|
+
radix64: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Padding character for Base64 encoding.
|
|
24
|
+
*/
|
|
25
|
+
const PAD = "=";
|
|
26
|
+
/**
|
|
27
|
+
* Build a reverse lookup table for decoding.
|
|
28
|
+
* @param alphabet - The 64-character alphabet string.
|
|
29
|
+
* @returns Map of character to index.
|
|
30
|
+
*/
|
|
31
|
+
function buildDecodeTable(alphabet) {
|
|
32
|
+
const table = new Map();
|
|
33
|
+
for (let i = 0; i < alphabet.length; i++) {
|
|
34
|
+
const char = alphabet[i];
|
|
35
|
+
if (char !== undefined) {
|
|
36
|
+
table.set(char, i);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return table;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Pre-built decode tables for each charset.
|
|
43
|
+
*/
|
|
44
|
+
const DECODE_TABLES = {
|
|
45
|
+
standard: buildDecodeTable(CHARSETS.standard),
|
|
46
|
+
urlsafe: buildDecodeTable(CHARSETS.urlsafe),
|
|
47
|
+
imap: buildDecodeTable(CHARSETS.imap),
|
|
48
|
+
radix64: buildDecodeTable(CHARSETS.radix64)
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Encode a string to Base64.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* import { encode } from "./base64.js";
|
|
56
|
+
*
|
|
57
|
+
* encode("Hello, World!");
|
|
58
|
+
* // => "SGVsbG8sIFdvcmxkIQ=="
|
|
59
|
+
*
|
|
60
|
+
* encode("Hello, World!", "urlsafe");
|
|
61
|
+
* // => "SGVsbG8sIFdvcmxkIQ=="
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @param input - The string to encode.
|
|
65
|
+
* @param charset - The charset variant to use (default: "standard").
|
|
66
|
+
* @returns The Base64 encoded string.
|
|
67
|
+
*/
|
|
68
|
+
function encode(input, charset = "standard") {
|
|
69
|
+
const alphabet = CHARSETS[charset];
|
|
70
|
+
const bytes = new TextEncoder().encode(input);
|
|
71
|
+
let result = "";
|
|
72
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
73
|
+
const b0 = bytes[i] ?? 0;
|
|
74
|
+
const b1 = i + 1 < bytes.length ? (bytes[i + 1] ?? 0) : 0;
|
|
75
|
+
const b2 = i + 2 < bytes.length ? (bytes[i + 2] ?? 0) : 0;
|
|
76
|
+
const triple = (b0 << 16) | (b1 << 8) | b2;
|
|
77
|
+
result += alphabet[(triple >> 18) & 0x3f];
|
|
78
|
+
result += alphabet[(triple >> 12) & 0x3f];
|
|
79
|
+
result += i + 1 < bytes.length ? alphabet[(triple >> 6) & 0x3f] : PAD;
|
|
80
|
+
result += i + 2 < bytes.length ? alphabet[triple & 0x3f] : PAD;
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Decode a Base64 string.
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* import { decode } from "./base64.js";
|
|
90
|
+
*
|
|
91
|
+
* decode("SGVsbG8sIFdvcmxkIQ==");
|
|
92
|
+
* // => "Hello, World!"
|
|
93
|
+
*
|
|
94
|
+
* decode("SGVsbG8sIFdvcmxkIQ==", "standard");
|
|
95
|
+
* // => "Hello, World!"
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @param input - The Base64 encoded string.
|
|
99
|
+
* @param charset - The charset variant to use (default: "standard").
|
|
100
|
+
* @returns The decoded string.
|
|
101
|
+
* @throws Error if the input contains invalid characters.
|
|
102
|
+
*/
|
|
103
|
+
function decode(input, charset = "standard") {
|
|
104
|
+
const decodeTable = DECODE_TABLES[charset];
|
|
105
|
+
// Remove padding
|
|
106
|
+
const cleanInput = input.replace(/=+$/, "");
|
|
107
|
+
const bytes = [];
|
|
108
|
+
for (let i = 0; i < cleanInput.length; i += 4) {
|
|
109
|
+
const c0 = cleanInput[i];
|
|
110
|
+
const c1 = cleanInput[i + 1];
|
|
111
|
+
const c2 = cleanInput[i + 2];
|
|
112
|
+
const c3 = cleanInput[i + 3];
|
|
113
|
+
if (c0 === undefined) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
const v0 = decodeTable.get(c0);
|
|
117
|
+
const v1 = c1 !== undefined ? decodeTable.get(c1) : 0;
|
|
118
|
+
const v2 = c2 !== undefined ? decodeTable.get(c2) : 0;
|
|
119
|
+
const v3 = c3 !== undefined ? decodeTable.get(c3) : 0;
|
|
120
|
+
if (v0 === undefined) {
|
|
121
|
+
throw new Error(`Invalid Base64 character: ${c0}`);
|
|
122
|
+
}
|
|
123
|
+
if (c1 !== undefined && v1 === undefined) {
|
|
124
|
+
throw new Error(`Invalid Base64 character: ${c1}`);
|
|
125
|
+
}
|
|
126
|
+
const triple = ((v0 ?? 0) << 18) | ((v1 ?? 0) << 12) | ((v2 ?? 0) << 6) | (v3 ?? 0);
|
|
127
|
+
bytes.push((triple >> 16) & 0xff);
|
|
128
|
+
if (c2 !== undefined) {
|
|
129
|
+
bytes.push((triple >> 8) & 0xff);
|
|
130
|
+
}
|
|
131
|
+
if (c3 !== undefined) {
|
|
132
|
+
bytes.push(triple & 0xff);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return new TextDecoder().decode(new Uint8Array(bytes));
|
|
136
|
+
}
|
|
137
|
+
export { encode, decode, Base64Charset };
|
|
138
|
+
//# sourceMappingURL=base64.js.map
|