@atproto/common 0.6.3 → 0.6.5
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.md +30 -0
- package/dist/logger.d.ts +2 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +16 -20
- package/dist/logger.js.map +1 -1
- package/package.json +17 -12
- package/jest.config.cjs +0 -21
- package/src/buffers.ts +0 -14
- package/src/dates.ts +0 -20
- package/src/env.ts +0 -25
- package/src/fs.ts +0 -54
- package/src/index.ts +0 -10
- package/src/ipld-multi.ts +0 -9
- package/src/ipld.ts +0 -138
- package/src/logger.ts +0 -36
- package/src/obfuscate.ts +0 -85
- package/src/streams.ts +0 -239
- package/tests/ipld-multi.test.ts +0 -34
- package/tests/ipld-vectors.ts +0 -277
- package/tests/ipld.test.ts +0 -29
- package/tests/streams.test.ts +0 -263
- package/tsconfig.build.json +0 -8
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @atproto/common
|
|
2
2
|
|
|
3
|
+
## 0.6.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update TypeScript build to rely on references to composite internal projects
|
|
8
|
+
|
|
9
|
+
- [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Bundle only necessary files in the NPM tarball, including the `CHANGELOG.md` and `README.md` files (if present).
|
|
10
|
+
|
|
11
|
+
- [#5099](https://github.com/bluesky-social/atproto/pull/5099) [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Build with `noImplicitAny` enabled
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07), [`b43ec31`](https://github.com/bluesky-social/atproto/commit/b43ec31f247f4461725b01226885f88bd430ca07)]:
|
|
14
|
+
- @atproto/lex-cbor@0.1.3
|
|
15
|
+
- @atproto/lex-data@0.1.4
|
|
16
|
+
- @atproto/common-web@0.5.3
|
|
17
|
+
|
|
18
|
+
## 0.6.4
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#5149](https://github.com/bluesky-social/atproto/pull/5149) [`f2cf8f7`](https://github.com/bluesky-social/atproto/commit/f2cf8f7fc5f3a10847f2e6d785e5fa2244ee8cfb) Thanks [@matthieusieben](https://github.com/matthieusieben)! - `LOG_ENABLED` now supports upper case (TRUE) for enabling logging
|
|
23
|
+
|
|
24
|
+
- [#5151](https://github.com/bluesky-social/atproto/pull/5151) [`a51c45d`](https://github.com/bluesky-social/atproto/commit/a51c45d38f6bd7b8765f640e564cf921d52162e7) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update dependencies
|
|
25
|
+
|
|
26
|
+
- [#5149](https://github.com/bluesky-social/atproto/pull/5149) [`f2cf8f7`](https://github.com/bluesky-social/atproto/commit/f2cf8f7fc5f3a10847f2e6d785e5fa2244ee8cfb) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Update `pino` logger to version 10
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [[`a51c45d`](https://github.com/bluesky-social/atproto/commit/a51c45d38f6bd7b8765f640e564cf921d52162e7)]:
|
|
29
|
+
- @atproto/common-web@0.5.2
|
|
30
|
+
- @atproto/lex-cbor@0.1.2
|
|
31
|
+
- @atproto/lex-data@0.1.3
|
|
32
|
+
|
|
3
33
|
## 0.6.3
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare const subsystemLogger: (name: string) =>
|
|
1
|
+
import { type Logger } from 'pino';
|
|
2
|
+
export declare const subsystemLogger: (name: string) => Logger;
|
|
3
3
|
//# sourceMappingURL=logger.d.ts.map
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAqB,MAAM,MAAM,CAAA;AAgBrD,eAAO,MAAM,eAAe,SAAU,MAAM,KAAG,MAY9C,CAAA"}
|
package/dist/logger.js
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import { destination, pino } from 'pino';
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
.replace(',', ' ')
|
|
5
|
-
.split(' ');
|
|
6
|
-
const enabledEnv = process.env.LOG_ENABLED;
|
|
7
|
-
const enabled = enabledEnv === 'true' || enabledEnv === 't' || enabledEnv === '1';
|
|
2
|
+
const enabled = /^(true|t|1)$/i.test(process.env.LOG_ENABLED ?? '0');
|
|
3
|
+
const dest = process.env.LOG_DESTINATION;
|
|
8
4
|
const level = process.env.LOG_LEVEL || 'info';
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
13
|
-
const
|
|
14
|
-
? pino(config, destination(process.env.LOG_DESTINATION))
|
|
15
|
-
: pino(config);
|
|
16
|
-
const subsystems = {};
|
|
5
|
+
const systems = process.env.LOG_SYSTEMS?.trim()
|
|
6
|
+
? process.env.LOG_SYSTEMS.replace(',', ' ').split(/\s+/).filter(Boolean)
|
|
7
|
+
: null;
|
|
8
|
+
const rootLogger = pino({ enabled, level }, dest ? destination(dest) : undefined);
|
|
9
|
+
const subsystems = new Map();
|
|
17
10
|
export const subsystemLogger = (name) => {
|
|
18
|
-
if (subsystems
|
|
19
|
-
return subsystems
|
|
20
|
-
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
if (subsystems.has(name))
|
|
12
|
+
return subsystems.get(name);
|
|
13
|
+
// can't disable child loggers, so we just set their level to "silent"
|
|
14
|
+
// to effectively turn them off
|
|
15
|
+
const subsystemEnabled = !systems || systems.includes(name);
|
|
16
|
+
const subsystemLevel = enabled && subsystemEnabled ? level : 'silent';
|
|
17
|
+
const logger = rootLogger.child({ name }, { level: subsystemLevel });
|
|
18
|
+
subsystems.set(name, logger);
|
|
19
|
+
return logger;
|
|
24
20
|
};
|
|
25
21
|
//# sourceMappingURL=logger.js.map
|
package/dist/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,WAAW,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAErD,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,CAAA;AACpE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAA;AACxC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,CAAA;AAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE;IAC7C,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IACxE,CAAC,CAAC,IAAI,CAAA;AAER,MAAM,UAAU,GAAG,IAAI,CACrB,EAAE,OAAO,EAAE,KAAK,EAAE,EAClB,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CACrC,CAAA;AAED,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;AAE5C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,IAAY,EAAU,EAAE;IACtD,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,UAAU,CAAC,GAAG,CAAC,IAAI,CAAE,CAAA;IAEtD,sEAAsE;IACtE,+BAA+B;IAC/B,MAAM,gBAAgB,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC3D,MAAM,cAAc,GAAG,OAAO,IAAI,gBAAgB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAA;IAErE,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAA;IAEpE,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC5B,OAAO,MAAM,CAAA;AACf,CAAC,CAAA","sourcesContent":["import { type Logger, destination, pino } from 'pino'\n\nconst enabled = /^(true|t|1)$/i.test(process.env.LOG_ENABLED ?? '0')\nconst dest = process.env.LOG_DESTINATION\nconst level = process.env.LOG_LEVEL || 'info'\nconst systems = process.env.LOG_SYSTEMS?.trim()\n ? process.env.LOG_SYSTEMS.replace(',', ' ').split(/\\s+/).filter(Boolean)\n : null\n\nconst rootLogger = pino(\n { enabled, level },\n dest ? destination(dest) : undefined,\n)\n\nconst subsystems = new Map<string, Logger>()\n\nexport const subsystemLogger = (name: string): Logger => {\n if (subsystems.has(name)) return subsystems.get(name)!\n\n // can't disable child loggers, so we just set their level to \"silent\"\n // to effectively turn them off\n const subsystemEnabled = !systems || systems.includes(name)\n const subsystemLevel = enabled && subsystemEnabled ? level : 'silent'\n\n const logger = rootLogger.child({ name }, { level: subsystemLevel })\n\n subsystems.set(name, logger)\n return logger\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/common",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Shared web-platform-friendly code for atproto libraries",
|
|
6
6
|
"keywords": [
|
|
@@ -12,27 +12,32 @@
|
|
|
12
12
|
"url": "https://github.com/bluesky-social/atproto",
|
|
13
13
|
"directory": "packages/common"
|
|
14
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"./dist",
|
|
17
|
+
"./README.md",
|
|
18
|
+
"./CHANGELOG.md"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"default": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
15
27
|
"engines": {
|
|
16
28
|
"node": ">=22"
|
|
17
29
|
},
|
|
18
30
|
"dependencies": {
|
|
19
31
|
"multiformats": "^13.0.0",
|
|
20
|
-
"pino": "^
|
|
21
|
-
"@atproto/lex-cbor": "^0.1.
|
|
22
|
-
"@atproto/lex-data": "^0.1.
|
|
23
|
-
"@atproto/common-web": "^0.5.
|
|
32
|
+
"pino": "^10.3.1",
|
|
33
|
+
"@atproto/lex-cbor": "^0.1.3",
|
|
34
|
+
"@atproto/lex-data": "^0.1.4",
|
|
35
|
+
"@atproto/common-web": "^0.5.3"
|
|
24
36
|
},
|
|
25
37
|
"devDependencies": {
|
|
26
38
|
"jest": "^30.0.0",
|
|
27
39
|
"uint8arrays": "^5.0.0"
|
|
28
40
|
},
|
|
29
|
-
"type": "module",
|
|
30
|
-
"exports": {
|
|
31
|
-
".": {
|
|
32
|
-
"types": "./dist/index.d.ts",
|
|
33
|
-
"default": "./dist/index.js"
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
41
|
"scripts": {
|
|
37
42
|
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
|
|
38
43
|
"build": "tsgo --build tsconfig.build.json"
|
package/jest.config.cjs
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/** @type {import('jest').Config} */
|
|
2
|
-
module.exports = {
|
|
3
|
-
displayName: 'Common',
|
|
4
|
-
transform: {
|
|
5
|
-
'^.+\\.(t|j)s$': [
|
|
6
|
-
'@swc/jest',
|
|
7
|
-
{
|
|
8
|
-
jsc: {
|
|
9
|
-
parser: { syntax: 'typescript', importAttributes: true },
|
|
10
|
-
experimental: { keepImportAttributes: true },
|
|
11
|
-
transform: {},
|
|
12
|
-
},
|
|
13
|
-
module: { type: 'es6' },
|
|
14
|
-
},
|
|
15
|
-
],
|
|
16
|
-
},
|
|
17
|
-
extensionsToTreatAsEsm: ['.ts'],
|
|
18
|
-
transformIgnorePatterns: [],
|
|
19
|
-
setupFiles: ['<rootDir>/../../test.setup.ts'],
|
|
20
|
-
moduleNameMapper: { '^(\\.\\.?\\/.+)\\.js$': ['$1.ts', '$1.js'] },
|
|
21
|
-
}
|
package/src/buffers.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function ui8ToBuffer(bytes: Uint8Array): Buffer {
|
|
2
|
-
return Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength)
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export function ui8ToArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
6
|
-
if (bytes.buffer instanceof ArrayBuffer) {
|
|
7
|
-
return bytes.buffer.slice(
|
|
8
|
-
bytes.byteOffset,
|
|
9
|
-
bytes.byteLength + bytes.byteOffset,
|
|
10
|
-
)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return new Uint8Array(bytes).buffer
|
|
14
|
-
}
|
package/src/dates.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// Normalize date strings to simplified ISO so that the lexical sort preserves temporal sort.
|
|
2
|
-
// Rather than failing on an invalid date format, returns valid unix epoch.
|
|
3
|
-
export function toSimplifiedISOSafe(dateStr: string) {
|
|
4
|
-
const date = new Date(dateStr)
|
|
5
|
-
if (isNaN(date.getTime())) {
|
|
6
|
-
return new Date(0).toISOString()
|
|
7
|
-
}
|
|
8
|
-
const iso = date.toISOString()
|
|
9
|
-
|
|
10
|
-
// Date.toISOString() always returns `YYYY-MM-DDTHH:mm:ss.sssZ` or
|
|
11
|
-
// `±YYYYYY-MM-DDTHH:mm:ss.sssZ`
|
|
12
|
-
// (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
|
13
|
-
// However, the leading `±` and 6 digit year can break lexical sorting, so we
|
|
14
|
-
// need to catch those cases and return a safe value.
|
|
15
|
-
if (iso.startsWith('-') || iso.startsWith('+')) {
|
|
16
|
-
return new Date(0).toISOString()
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return iso // YYYY-MM-DDTHH:mm:ss.sssZ
|
|
20
|
-
}
|
package/src/env.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { parseIntWithFallback } from '@atproto/common-web'
|
|
2
|
-
|
|
3
|
-
export const envInt = (name: string): number | undefined => {
|
|
4
|
-
const str = process.env[name]
|
|
5
|
-
return parseIntWithFallback(str, undefined)
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export const envStr = (name: string): string | undefined => {
|
|
9
|
-
const str = process.env[name]
|
|
10
|
-
if (str === undefined || str.length === 0) return undefined
|
|
11
|
-
return str
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const envBool = (name: string): boolean | undefined => {
|
|
15
|
-
const str = process.env[name]
|
|
16
|
-
if (str === 'true' || str === '1') return true
|
|
17
|
-
if (str === 'false' || str === '0') return false
|
|
18
|
-
return undefined
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export const envList = (name: string): string[] => {
|
|
22
|
-
const str = process.env[name]
|
|
23
|
-
if (str === undefined || str.length === 0) return []
|
|
24
|
-
return str.split(',')
|
|
25
|
-
}
|
package/src/fs.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { constants } from 'node:fs'
|
|
2
|
-
import fs from 'node:fs/promises'
|
|
3
|
-
import { isErrnoException } from '@atproto/common-web'
|
|
4
|
-
|
|
5
|
-
export const fileExists = async (location: string): Promise<boolean> => {
|
|
6
|
-
try {
|
|
7
|
-
await fs.access(location, constants.F_OK)
|
|
8
|
-
return true
|
|
9
|
-
} catch (err) {
|
|
10
|
-
if (isErrnoException(err) && err.code === 'ENOENT') {
|
|
11
|
-
return false
|
|
12
|
-
}
|
|
13
|
-
throw err
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const readIfExists = async (
|
|
18
|
-
filepath: string,
|
|
19
|
-
): Promise<Uint8Array | undefined> => {
|
|
20
|
-
try {
|
|
21
|
-
return await fs.readFile(filepath)
|
|
22
|
-
} catch (err) {
|
|
23
|
-
if (isErrnoException(err) && err.code === 'ENOENT') {
|
|
24
|
-
return
|
|
25
|
-
}
|
|
26
|
-
throw err
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export const rmIfExists = async (
|
|
31
|
-
filepath: string,
|
|
32
|
-
recursive = false,
|
|
33
|
-
): Promise<void> => {
|
|
34
|
-
await fs.rm(filepath, {
|
|
35
|
-
force: true, // ignore errors if the file/directory does not exist
|
|
36
|
-
recursive,
|
|
37
|
-
maxRetries: 5,
|
|
38
|
-
retryDelay: 50,
|
|
39
|
-
})
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export const renameIfExists = async (
|
|
43
|
-
oldPath: string,
|
|
44
|
-
newPath: string,
|
|
45
|
-
): Promise<void> => {
|
|
46
|
-
try {
|
|
47
|
-
await fs.rename(oldPath, newPath)
|
|
48
|
-
} catch (err) {
|
|
49
|
-
if (isErrnoException(err) && err.code === 'ENOENT') {
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
throw err
|
|
53
|
-
}
|
|
54
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export * from '@atproto/common-web'
|
|
2
|
-
export * from './buffers.js'
|
|
3
|
-
export * from './dates.js'
|
|
4
|
-
export * from './env.js'
|
|
5
|
-
export * from './fs.js'
|
|
6
|
-
export * from './ipld.js'
|
|
7
|
-
export * from './ipld-multi.js'
|
|
8
|
-
export * from './logger.js'
|
|
9
|
-
export * from './obfuscate.js'
|
|
10
|
-
export * from './streams.js'
|
package/src/ipld-multi.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { decodeAll } from '@atproto/lex-cbor'
|
|
2
|
-
import { LexValue } from '@atproto/lex-data'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @deprecated Use {@link decodeAll} from `@atproto/lex-cbor` instead.
|
|
6
|
-
*/
|
|
7
|
-
export function cborDecodeMulti(encoded: Uint8Array): LexValue[] {
|
|
8
|
-
return Array.from(decodeAll(encoded))
|
|
9
|
-
}
|
package/src/ipld.ts
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto'
|
|
2
|
-
import { Transform } from 'node:stream'
|
|
3
|
-
import { encode as encodeBlock } from 'multiformats/block'
|
|
4
|
-
import type { BlockView, ByteView } from 'multiformats/block/interface'
|
|
5
|
-
import { sha256 as hasher } from 'multiformats/hashes/sha2'
|
|
6
|
-
import { cidForLex, decode, encode } from '@atproto/lex-cbor'
|
|
7
|
-
import {
|
|
8
|
-
CBOR_DATA_CODEC,
|
|
9
|
-
type CID,
|
|
10
|
-
Cid,
|
|
11
|
-
LexValue,
|
|
12
|
-
asMultiformatsCID,
|
|
13
|
-
// eslint-disable-next-line
|
|
14
|
-
cidForCbor,
|
|
15
|
-
cidForRawHash,
|
|
16
|
-
decodeCid,
|
|
17
|
-
isCidForBytes,
|
|
18
|
-
isTypedLexMap,
|
|
19
|
-
validateCidString,
|
|
20
|
-
} from '@atproto/lex-data'
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* @deprecated Use {@link encode} from `@atproto/lex-cbor` instead.
|
|
24
|
-
*/
|
|
25
|
-
const cborEncodeLegacy = encode as <T = unknown>(data: T) => ByteView<T>
|
|
26
|
-
export { cborEncodeLegacy as cborEncode }
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @deprecated Use {@link decode} from `@atproto/lex-cbor` instead.
|
|
30
|
-
*/
|
|
31
|
-
const cborDecodeLegacy = decode as <T = unknown>(bytes: ByteView<T>) => T
|
|
32
|
-
export { cborDecodeLegacy as cborDecode }
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @deprecated Use {@link encode} and {@link cidForCbor} from `@atproto/lex-cbor` instead.
|
|
36
|
-
*/
|
|
37
|
-
export async function dataToCborBlock<T>(
|
|
38
|
-
value: T,
|
|
39
|
-
): Promise<BlockView<T, 0x71, 0x12, 1>> {
|
|
40
|
-
return encodeBlock<T, 0x71, 0x12>({
|
|
41
|
-
value,
|
|
42
|
-
codec: {
|
|
43
|
-
name: 'at-cbor', // Not actually used
|
|
44
|
-
code: CBOR_DATA_CODEC,
|
|
45
|
-
encode: encode as (data: T) => ByteView<T>,
|
|
46
|
-
},
|
|
47
|
-
hasher,
|
|
48
|
-
})
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* @deprecated Use {@link cidForLex} from `@atproto/lex-cbor` instead.
|
|
53
|
-
*/
|
|
54
|
-
async function cidForCborLegacy(data: unknown): Promise<CID> {
|
|
55
|
-
return asMultiformatsCID(await cidForLex(data as LexValue))
|
|
56
|
-
}
|
|
57
|
-
export { cidForCborLegacy as cidForCbor }
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @deprecated Use {@link validateCidString} from '@atproto/lex-data' instead.
|
|
61
|
-
*/
|
|
62
|
-
export async function isValidCid(cidStr: string): Promise<boolean> {
|
|
63
|
-
// @NOTE we keep the wrapper function to return a Promise (for backward
|
|
64
|
-
// compatibility).
|
|
65
|
-
return validateCidString(cidStr)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @deprecated Use {@link decode} from `@atproto/lex-cbor`, and {@link isTypedLexMap} from `@atproto/lex-data` instead.
|
|
70
|
-
*/
|
|
71
|
-
export function cborBytesToRecord(bytes: Uint8Array): Record<string, unknown> {
|
|
72
|
-
const data = decode(bytes) as LexValue
|
|
73
|
-
if (isTypedLexMap(data)) return data
|
|
74
|
-
|
|
75
|
-
throw new Error(`Expected record with $type property`)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* @deprecated Use {@link isCidForBytes} from `@atproto/lex-cbor` instead.
|
|
80
|
-
*/
|
|
81
|
-
export async function verifyCidForBytes(
|
|
82
|
-
cid: Cid,
|
|
83
|
-
bytes: Uint8Array,
|
|
84
|
-
): Promise<void> {
|
|
85
|
-
if (!(await isCidForBytes(cid, bytes))) {
|
|
86
|
-
throw new Error(`Not a valid CID for bytes (${cid.toString()})`)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* @deprecated Use {@link cidForRawHash} from `@atproto/lex-cbor` instead.
|
|
92
|
-
*/
|
|
93
|
-
export function sha256RawToCid(hash: Uint8Array): CID {
|
|
94
|
-
return asMultiformatsCID(cidForRawHash(hash))
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* @deprecated Use {@link decodeCid} from `@atproto/lex-cbor` instead.
|
|
99
|
-
*/
|
|
100
|
-
export function parseCidFromBytes(bytes: Uint8Array): CID {
|
|
101
|
-
return asMultiformatsCID(decodeCid(bytes, { flavor: 'dasl' }))
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export class VerifyCidTransform extends Transform {
|
|
105
|
-
constructor(public cid: Cid) {
|
|
106
|
-
const hasher = createHash('sha256')
|
|
107
|
-
super({
|
|
108
|
-
transform(chunk, encoding, callback) {
|
|
109
|
-
hasher.update(chunk)
|
|
110
|
-
callback(null, chunk)
|
|
111
|
-
},
|
|
112
|
-
flush(callback) {
|
|
113
|
-
try {
|
|
114
|
-
const actual = sha256RawToCid(hasher.digest())
|
|
115
|
-
if (actual.equals(cid)) {
|
|
116
|
-
return callback()
|
|
117
|
-
} else {
|
|
118
|
-
return callback(new VerifyCidError(cid, actual))
|
|
119
|
-
}
|
|
120
|
-
} catch (err) {
|
|
121
|
-
return callback(asError(err))
|
|
122
|
-
}
|
|
123
|
-
},
|
|
124
|
-
})
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const asError = (err: unknown): Error =>
|
|
129
|
-
err instanceof Error ? err : new Error('Unexpected error', { cause: err })
|
|
130
|
-
|
|
131
|
-
export class VerifyCidError extends Error {
|
|
132
|
-
constructor(
|
|
133
|
-
public expected: Cid,
|
|
134
|
-
public actual: Cid,
|
|
135
|
-
) {
|
|
136
|
-
super('Bad cid check')
|
|
137
|
-
}
|
|
138
|
-
}
|
package/src/logger.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { destination, pino } from 'pino'
|
|
2
|
-
|
|
3
|
-
const allSystemsEnabled = !process.env.LOG_SYSTEMS
|
|
4
|
-
const enabledSystems = (process.env.LOG_SYSTEMS || '')
|
|
5
|
-
.replace(',', ' ')
|
|
6
|
-
.split(' ')
|
|
7
|
-
|
|
8
|
-
const enabledEnv = process.env.LOG_ENABLED
|
|
9
|
-
const enabled =
|
|
10
|
-
enabledEnv === 'true' || enabledEnv === 't' || enabledEnv === '1'
|
|
11
|
-
|
|
12
|
-
const level = process.env.LOG_LEVEL || 'info'
|
|
13
|
-
|
|
14
|
-
const config = {
|
|
15
|
-
enabled,
|
|
16
|
-
level,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const rootLogger = process.env.LOG_DESTINATION
|
|
20
|
-
? pino(config, destination(process.env.LOG_DESTINATION))
|
|
21
|
-
: pino(config)
|
|
22
|
-
|
|
23
|
-
const subsystems: Record<string, pino.Logger> = {}
|
|
24
|
-
|
|
25
|
-
export const subsystemLogger = (name: string): pino.Logger => {
|
|
26
|
-
if (subsystems[name]) return subsystems[name]
|
|
27
|
-
const subsystemEnabled =
|
|
28
|
-
enabled && (allSystemsEnabled || enabledSystems.indexOf(name) > -1)
|
|
29
|
-
|
|
30
|
-
// can't disable child loggers, so we just set their level to fatal to effectively turn them off
|
|
31
|
-
subsystems[name] = rootLogger.child(
|
|
32
|
-
{ name },
|
|
33
|
-
{ level: subsystemEnabled ? level : 'silent' },
|
|
34
|
-
)
|
|
35
|
-
return subsystems[name]
|
|
36
|
-
}
|
package/src/obfuscate.ts
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
export function obfuscateEmail(email: string) {
|
|
2
|
-
const [local, domain] = email.split('@')
|
|
3
|
-
return `${obfuscateWord(local)}@${obfuscateWord(domain)}`
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export function obfuscateWord(word: string) {
|
|
7
|
-
return `${word.charAt(0)}***${word.charAt(word.length - 1)}`
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function obfuscateHeaders(headers: Record<string, string>) {
|
|
11
|
-
const obfuscatedHeaders: Record<string, string> = {}
|
|
12
|
-
for (const key in headers) {
|
|
13
|
-
if (key.toLowerCase() === 'authorization') {
|
|
14
|
-
obfuscatedHeaders[key] = obfuscateAuthHeader(headers[key])
|
|
15
|
-
} else if (key.toLowerCase() === 'dpop') {
|
|
16
|
-
obfuscatedHeaders[key] = obfuscateJwt(headers[key]) || 'Invalid'
|
|
17
|
-
} else {
|
|
18
|
-
obfuscatedHeaders[key] = headers[key]
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return obfuscatedHeaders
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function obfuscateAuthHeader(authHeader: string): string {
|
|
25
|
-
// This is a hot path (runs on every request). Avoid using split() or regex.
|
|
26
|
-
|
|
27
|
-
const spaceIdx = authHeader.indexOf(' ')
|
|
28
|
-
if (spaceIdx === -1) return 'Invalid'
|
|
29
|
-
|
|
30
|
-
const type = authHeader.slice(0, spaceIdx)
|
|
31
|
-
switch (type.toLowerCase()) {
|
|
32
|
-
case 'bearer':
|
|
33
|
-
case 'dpop':
|
|
34
|
-
return `${type} ${obfuscateBearer(authHeader.slice(spaceIdx + 1))}`
|
|
35
|
-
case 'basic':
|
|
36
|
-
return `${type} ${obfuscateBasic(authHeader.slice(spaceIdx + 1)) || 'Invalid'}`
|
|
37
|
-
default:
|
|
38
|
-
return `Invalid`
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function obfuscateBasic(token: string): null | string {
|
|
43
|
-
if (!token) return null
|
|
44
|
-
const buffer = Buffer.from(token, 'base64')
|
|
45
|
-
if (!buffer.length) return null // Buffer.from will silently ignore invalid base64 chars
|
|
46
|
-
const authHeader = buffer.toString('utf8')
|
|
47
|
-
const colIdx = authHeader.indexOf(':')
|
|
48
|
-
if (colIdx === -1) return null
|
|
49
|
-
const username = authHeader.slice(0, colIdx)
|
|
50
|
-
return `${username}:***`
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function obfuscateBearer(token: string): string {
|
|
54
|
-
return obfuscateJwt(token) || obfuscateToken(token)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function obfuscateToken(token: string): string {
|
|
58
|
-
if (token.length >= 12) return obfuscateWord(token)
|
|
59
|
-
return token ? '***' : ''
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function obfuscateJwt(token: string): null | string {
|
|
63
|
-
const firstDot = token.indexOf('.')
|
|
64
|
-
if (firstDot === -1) return null
|
|
65
|
-
|
|
66
|
-
const secondDot = token.indexOf('.', firstDot + 1)
|
|
67
|
-
if (secondDot === -1) return null
|
|
68
|
-
|
|
69
|
-
// Expected to be missing
|
|
70
|
-
const thirdDot = token.indexOf('.', secondDot + 1)
|
|
71
|
-
if (thirdDot !== -1) return null
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
const payloadEnc = token.slice(firstDot + 1, secondDot)
|
|
75
|
-
const payloadJson = Buffer.from(payloadEnc, 'base64').toString('utf8')
|
|
76
|
-
const payload = JSON.parse(payloadJson)
|
|
77
|
-
if (typeof payload.sub === 'string') return payload.sub
|
|
78
|
-
} catch {
|
|
79
|
-
// Invalid JWT
|
|
80
|
-
return null
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Strip the signature
|
|
84
|
-
return token.slice(0, secondDot) + '.obfuscated'
|
|
85
|
-
}
|