@character-foundry/character-foundry 0.4.2 → 0.4.3-dev.1766019473
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/charx.cjs +15 -36
- package/dist/charx.cjs.map +1 -1
- package/dist/charx.d.cts +18 -9
- package/dist/charx.d.ts +18 -9
- package/dist/charx.js +15 -36
- package/dist/charx.js.map +1 -1
- package/dist/exporter.cjs +34 -38
- package/dist/exporter.cjs.map +1 -1
- package/dist/exporter.d.cts +18 -9
- package/dist/exporter.d.ts +18 -9
- package/dist/exporter.js +34 -38
- package/dist/exporter.js.map +1 -1
- package/dist/federation.cjs +104 -36
- package/dist/federation.cjs.map +1 -1
- package/dist/federation.d.cts +53 -9
- package/dist/federation.d.ts +53 -9
- package/dist/federation.js +104 -36
- package/dist/federation.js.map +1 -1
- package/dist/index.cjs +34 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -21
- package/dist/index.d.ts +42 -21
- package/dist/index.js +34 -38
- package/dist/index.js.map +1 -1
- package/dist/loader.cjs +101 -15
- package/dist/loader.cjs.map +1 -1
- package/dist/loader.d.cts +42 -14
- package/dist/loader.d.ts +42 -14
- package/dist/loader.js +101 -15
- package/dist/loader.js.map +1 -1
- package/dist/lorebook.d.cts +34 -17
- package/dist/lorebook.d.ts +34 -17
- package/dist/normalizer.cjs +2 -2
- package/dist/normalizer.cjs.map +1 -1
- package/dist/normalizer.d.cts +60 -30
- package/dist/normalizer.d.ts +60 -30
- package/dist/normalizer.js +2 -2
- package/dist/normalizer.js.map +1 -1
- package/dist/png.cjs +2 -2
- package/dist/png.cjs.map +1 -1
- package/dist/png.d.cts +32 -16
- package/dist/png.d.ts +32 -16
- package/dist/png.js +2 -2
- package/dist/png.js.map +1 -1
- package/dist/schemas.cjs +7 -7
- package/dist/schemas.cjs.map +1 -1
- package/dist/schemas.d.cts +96 -48
- package/dist/schemas.d.ts +96 -48
- package/dist/schemas.js +7 -7
- package/dist/schemas.js.map +1 -1
- package/dist/voxta.cjs +21 -4
- package/dist/voxta.cjs.map +1 -1
- package/dist/voxta.d.cts +28 -14
- package/dist/voxta.d.ts +28 -14
- package/dist/voxta.js +21 -4
- package/dist/voxta.js.map +1 -1
- package/package.json +6 -6
package/dist/federation.d.cts
CHANGED
|
@@ -41,7 +41,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
41
41
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
42
42
|
z.ZodEnum<[
|
|
43
43
|
"before_char",
|
|
44
|
-
"after_char"
|
|
44
|
+
"after_char",
|
|
45
|
+
"in_chat"
|
|
45
46
|
]>,
|
|
46
47
|
z.ZodNumber,
|
|
47
48
|
z.ZodLiteral<"">
|
|
@@ -84,7 +85,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
84
85
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
85
86
|
z.ZodEnum<[
|
|
86
87
|
"before_char",
|
|
87
|
-
"after_char"
|
|
88
|
+
"after_char",
|
|
89
|
+
"in_chat"
|
|
88
90
|
]>,
|
|
89
91
|
z.ZodNumber,
|
|
90
92
|
z.ZodLiteral<"">
|
|
@@ -127,7 +129,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
127
129
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
128
130
|
z.ZodEnum<[
|
|
129
131
|
"before_char",
|
|
130
|
-
"after_char"
|
|
132
|
+
"after_char",
|
|
133
|
+
"in_chat"
|
|
131
134
|
]>,
|
|
132
135
|
z.ZodNumber,
|
|
133
136
|
z.ZodLiteral<"">
|
|
@@ -172,7 +175,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
172
175
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
173
176
|
z.ZodEnum<[
|
|
174
177
|
"before_char",
|
|
175
|
-
"after_char"
|
|
178
|
+
"after_char",
|
|
179
|
+
"in_chat"
|
|
176
180
|
]>,
|
|
177
181
|
z.ZodNumber,
|
|
178
182
|
z.ZodLiteral<"">
|
|
@@ -223,7 +227,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
223
227
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
224
228
|
z.ZodEnum<[
|
|
225
229
|
"before_char",
|
|
226
|
-
"after_char"
|
|
230
|
+
"after_char",
|
|
231
|
+
"in_chat"
|
|
227
232
|
]>,
|
|
228
233
|
z.ZodNumber,
|
|
229
234
|
z.ZodLiteral<"">
|
|
@@ -322,7 +327,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
322
327
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
323
328
|
z.ZodEnum<[
|
|
324
329
|
"before_char",
|
|
325
|
-
"after_char"
|
|
330
|
+
"after_char",
|
|
331
|
+
"in_chat"
|
|
326
332
|
]>,
|
|
327
333
|
z.ZodNumber,
|
|
328
334
|
z.ZodLiteral<"">
|
|
@@ -397,7 +403,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
397
403
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
398
404
|
z.ZodEnum<[
|
|
399
405
|
"before_char",
|
|
400
|
-
"after_char"
|
|
406
|
+
"after_char",
|
|
407
|
+
"in_chat"
|
|
401
408
|
]>,
|
|
402
409
|
z.ZodNumber,
|
|
403
410
|
z.ZodLiteral<"">
|
|
@@ -482,7 +489,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
482
489
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
483
490
|
z.ZodEnum<[
|
|
484
491
|
"before_char",
|
|
485
|
-
"after_char"
|
|
492
|
+
"after_char",
|
|
493
|
+
"in_chat"
|
|
486
494
|
]>,
|
|
487
495
|
z.ZodNumber,
|
|
488
496
|
z.ZodLiteral<"">
|
|
@@ -561,7 +569,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
561
569
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
562
570
|
z.ZodEnum<[
|
|
563
571
|
"before_char",
|
|
564
|
-
"after_char"
|
|
572
|
+
"after_char",
|
|
573
|
+
"in_chat"
|
|
565
574
|
]>,
|
|
566
575
|
z.ZodNumber,
|
|
567
576
|
z.ZodLiteral<"">
|
|
@@ -619,6 +628,23 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
619
628
|
* Character Card v3 full structure
|
|
620
629
|
*/
|
|
621
630
|
export type CCv3Data = z.infer<typeof CCv3DataSchema>;
|
|
631
|
+
/**
|
|
632
|
+
* Federation Logger
|
|
633
|
+
*
|
|
634
|
+
* Lightweight logger with configurable verbosity and a safe default (warn).
|
|
635
|
+
* No external dependencies.
|
|
636
|
+
*/
|
|
637
|
+
export type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
638
|
+
export interface Logger {
|
|
639
|
+
debug: (...args: unknown[]) => void;
|
|
640
|
+
info: (...args: unknown[]) => void;
|
|
641
|
+
warn: (...args: unknown[]) => void;
|
|
642
|
+
error: (...args: unknown[]) => void;
|
|
643
|
+
}
|
|
644
|
+
export declare function createConsoleLogger(level?: LogLevel): Logger;
|
|
645
|
+
declare function getLogger(): Logger;
|
|
646
|
+
declare function setLogger(logger: Logger): void;
|
|
647
|
+
declare function setLogLevel(level: LogLevel): void;
|
|
622
648
|
/**
|
|
623
649
|
* Federation Types
|
|
624
650
|
*
|
|
@@ -978,6 +1004,17 @@ export interface InboxHandlerOptions {
|
|
|
978
1004
|
strictMode?: boolean;
|
|
979
1005
|
/** Maximum age for signatures in seconds (default 300) */
|
|
980
1006
|
maxAge?: number;
|
|
1007
|
+
/**
|
|
1008
|
+
* Optional shared network key for internal-only federation.
|
|
1009
|
+
*
|
|
1010
|
+
* When set, incoming requests must include a matching network key header.
|
|
1011
|
+
* In strictMode, the header must also be included in the signed header list.
|
|
1012
|
+
*/
|
|
1013
|
+
networkKey?: string;
|
|
1014
|
+
/**
|
|
1015
|
+
* Header name for the shared network key (default: X-Foundry-Network-Key)
|
|
1016
|
+
*/
|
|
1017
|
+
networkKeyHeader?: string;
|
|
981
1018
|
}
|
|
982
1019
|
/**
|
|
983
1020
|
* ActivityPub Utilities
|
|
@@ -3098,6 +3135,10 @@ export declare class RateLimiter {
|
|
|
3098
3135
|
*/
|
|
3099
3136
|
export declare function enableFederation(options?: {
|
|
3100
3137
|
skipEnvCheck?: boolean;
|
|
3138
|
+
/** Optional logger override */
|
|
3139
|
+
logger?: Logger;
|
|
3140
|
+
/** Optional log level (used when logger is not provided). Default: warn */
|
|
3141
|
+
logLevel?: LogLevel;
|
|
3101
3142
|
}): void;
|
|
3102
3143
|
/**
|
|
3103
3144
|
* Check if federation is enabled
|
|
@@ -3113,6 +3154,9 @@ export declare function isFederationEnabled(): boolean;
|
|
|
3113
3154
|
export declare function assertFederationEnabled(feature: string): void;
|
|
3114
3155
|
|
|
3115
3156
|
export {
|
|
3157
|
+
getLogger as getFederationLogger,
|
|
3158
|
+
setLogLevel as setFederationLogLevel,
|
|
3159
|
+
setLogger as setFederationLogger,
|
|
3116
3160
|
validateActivitySignature as validateHttpSignature,
|
|
3117
3161
|
validateBlockActivity as validateBlockActivityFields,
|
|
3118
3162
|
validateFlagActivity as validateFlagActivityFields,
|
package/dist/federation.d.ts
CHANGED
|
@@ -41,7 +41,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
41
41
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
42
42
|
z.ZodEnum<[
|
|
43
43
|
"before_char",
|
|
44
|
-
"after_char"
|
|
44
|
+
"after_char",
|
|
45
|
+
"in_chat"
|
|
45
46
|
]>,
|
|
46
47
|
z.ZodNumber,
|
|
47
48
|
z.ZodLiteral<"">
|
|
@@ -84,7 +85,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
84
85
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
85
86
|
z.ZodEnum<[
|
|
86
87
|
"before_char",
|
|
87
|
-
"after_char"
|
|
88
|
+
"after_char",
|
|
89
|
+
"in_chat"
|
|
88
90
|
]>,
|
|
89
91
|
z.ZodNumber,
|
|
90
92
|
z.ZodLiteral<"">
|
|
@@ -127,7 +129,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
127
129
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
128
130
|
z.ZodEnum<[
|
|
129
131
|
"before_char",
|
|
130
|
-
"after_char"
|
|
132
|
+
"after_char",
|
|
133
|
+
"in_chat"
|
|
131
134
|
]>,
|
|
132
135
|
z.ZodNumber,
|
|
133
136
|
z.ZodLiteral<"">
|
|
@@ -172,7 +175,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
172
175
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
173
176
|
z.ZodEnum<[
|
|
174
177
|
"before_char",
|
|
175
|
-
"after_char"
|
|
178
|
+
"after_char",
|
|
179
|
+
"in_chat"
|
|
176
180
|
]>,
|
|
177
181
|
z.ZodNumber,
|
|
178
182
|
z.ZodLiteral<"">
|
|
@@ -223,7 +227,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
223
227
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
224
228
|
z.ZodEnum<[
|
|
225
229
|
"before_char",
|
|
226
|
-
"after_char"
|
|
230
|
+
"after_char",
|
|
231
|
+
"in_chat"
|
|
227
232
|
]>,
|
|
228
233
|
z.ZodNumber,
|
|
229
234
|
z.ZodLiteral<"">
|
|
@@ -322,7 +327,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
322
327
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
323
328
|
z.ZodEnum<[
|
|
324
329
|
"before_char",
|
|
325
|
-
"after_char"
|
|
330
|
+
"after_char",
|
|
331
|
+
"in_chat"
|
|
326
332
|
]>,
|
|
327
333
|
z.ZodNumber,
|
|
328
334
|
z.ZodLiteral<"">
|
|
@@ -397,7 +403,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
397
403
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
398
404
|
z.ZodEnum<[
|
|
399
405
|
"before_char",
|
|
400
|
-
"after_char"
|
|
406
|
+
"after_char",
|
|
407
|
+
"in_chat"
|
|
401
408
|
]>,
|
|
402
409
|
z.ZodNumber,
|
|
403
410
|
z.ZodLiteral<"">
|
|
@@ -482,7 +489,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
482
489
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
483
490
|
z.ZodEnum<[
|
|
484
491
|
"before_char",
|
|
485
|
-
"after_char"
|
|
492
|
+
"after_char",
|
|
493
|
+
"in_chat"
|
|
486
494
|
]>,
|
|
487
495
|
z.ZodNumber,
|
|
488
496
|
z.ZodLiteral<"">
|
|
@@ -561,7 +569,8 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
561
569
|
position: z.ZodOptional<z.ZodNullable<z.ZodUnion<[
|
|
562
570
|
z.ZodEnum<[
|
|
563
571
|
"before_char",
|
|
564
|
-
"after_char"
|
|
572
|
+
"after_char",
|
|
573
|
+
"in_chat"
|
|
565
574
|
]>,
|
|
566
575
|
z.ZodNumber,
|
|
567
576
|
z.ZodLiteral<"">
|
|
@@ -619,6 +628,23 @@ declare const CCv3DataSchema: z.ZodObject<{
|
|
|
619
628
|
* Character Card v3 full structure
|
|
620
629
|
*/
|
|
621
630
|
export type CCv3Data = z.infer<typeof CCv3DataSchema>;
|
|
631
|
+
/**
|
|
632
|
+
* Federation Logger
|
|
633
|
+
*
|
|
634
|
+
* Lightweight logger with configurable verbosity and a safe default (warn).
|
|
635
|
+
* No external dependencies.
|
|
636
|
+
*/
|
|
637
|
+
export type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
638
|
+
export interface Logger {
|
|
639
|
+
debug: (...args: unknown[]) => void;
|
|
640
|
+
info: (...args: unknown[]) => void;
|
|
641
|
+
warn: (...args: unknown[]) => void;
|
|
642
|
+
error: (...args: unknown[]) => void;
|
|
643
|
+
}
|
|
644
|
+
export declare function createConsoleLogger(level?: LogLevel): Logger;
|
|
645
|
+
declare function getLogger(): Logger;
|
|
646
|
+
declare function setLogger(logger: Logger): void;
|
|
647
|
+
declare function setLogLevel(level: LogLevel): void;
|
|
622
648
|
/**
|
|
623
649
|
* Federation Types
|
|
624
650
|
*
|
|
@@ -978,6 +1004,17 @@ export interface InboxHandlerOptions {
|
|
|
978
1004
|
strictMode?: boolean;
|
|
979
1005
|
/** Maximum age for signatures in seconds (default 300) */
|
|
980
1006
|
maxAge?: number;
|
|
1007
|
+
/**
|
|
1008
|
+
* Optional shared network key for internal-only federation.
|
|
1009
|
+
*
|
|
1010
|
+
* When set, incoming requests must include a matching network key header.
|
|
1011
|
+
* In strictMode, the header must also be included in the signed header list.
|
|
1012
|
+
*/
|
|
1013
|
+
networkKey?: string;
|
|
1014
|
+
/**
|
|
1015
|
+
* Header name for the shared network key (default: X-Foundry-Network-Key)
|
|
1016
|
+
*/
|
|
1017
|
+
networkKeyHeader?: string;
|
|
981
1018
|
}
|
|
982
1019
|
/**
|
|
983
1020
|
* ActivityPub Utilities
|
|
@@ -3098,6 +3135,10 @@ export declare class RateLimiter {
|
|
|
3098
3135
|
*/
|
|
3099
3136
|
export declare function enableFederation(options?: {
|
|
3100
3137
|
skipEnvCheck?: boolean;
|
|
3138
|
+
/** Optional logger override */
|
|
3139
|
+
logger?: Logger;
|
|
3140
|
+
/** Optional log level (used when logger is not provided). Default: warn */
|
|
3141
|
+
logLevel?: LogLevel;
|
|
3101
3142
|
}): void;
|
|
3102
3143
|
/**
|
|
3103
3144
|
* Check if federation is enabled
|
|
@@ -3113,6 +3154,9 @@ export declare function isFederationEnabled(): boolean;
|
|
|
3113
3154
|
export declare function assertFederationEnabled(feature: string): void;
|
|
3114
3155
|
|
|
3115
3156
|
export {
|
|
3157
|
+
getLogger as getFederationLogger,
|
|
3158
|
+
setLogLevel as setFederationLogLevel,
|
|
3159
|
+
setLogger as setFederationLogger,
|
|
3116
3160
|
validateActivitySignature as validateHttpSignature,
|
|
3117
3161
|
validateBlockActivity as validateBlockActivityFields,
|
|
3118
3162
|
validateFlagActivity as validateFlagActivityFields,
|
package/dist/federation.js
CHANGED
|
@@ -44,6 +44,50 @@ function generateUUID() {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// ../federation/dist/index.js
|
|
47
|
+
var LEVELS = {
|
|
48
|
+
silent: 0,
|
|
49
|
+
error: 1,
|
|
50
|
+
warn: 2,
|
|
51
|
+
info: 3,
|
|
52
|
+
debug: 4
|
|
53
|
+
};
|
|
54
|
+
var noop = () => {
|
|
55
|
+
};
|
|
56
|
+
function createConsoleLogger(level = "warn") {
|
|
57
|
+
const severity = LEVELS[level] ?? LEVELS.warn;
|
|
58
|
+
const hasConsole = typeof console !== "undefined";
|
|
59
|
+
const c = hasConsole ? console : void 0;
|
|
60
|
+
const debugImpl = c?.debug ? c.debug.bind(c) : c?.log ? c.log.bind(c) : noop;
|
|
61
|
+
const infoImpl = c?.info ? c.info.bind(c) : c?.log ? c.log.bind(c) : noop;
|
|
62
|
+
const warnImpl = c?.warn ? c.warn.bind(c) : c?.log ? c.log.bind(c) : noop;
|
|
63
|
+
const errorImpl = c?.error ? c.error.bind(c) : c?.log ? c.log.bind(c) : noop;
|
|
64
|
+
return {
|
|
65
|
+
debug: severity >= LEVELS.debug ? debugImpl : noop,
|
|
66
|
+
info: severity >= LEVELS.info ? infoImpl : noop,
|
|
67
|
+
warn: severity >= LEVELS.warn ? warnImpl : noop,
|
|
68
|
+
error: severity >= LEVELS.error ? errorImpl : noop
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
var federationLogger = createConsoleLogger("warn");
|
|
72
|
+
function getLogger() {
|
|
73
|
+
return federationLogger;
|
|
74
|
+
}
|
|
75
|
+
function setLogger(logger) {
|
|
76
|
+
federationLogger = logger;
|
|
77
|
+
}
|
|
78
|
+
function setLogLevel(level) {
|
|
79
|
+
federationLogger = createConsoleLogger(level);
|
|
80
|
+
}
|
|
81
|
+
function configureLogger(options) {
|
|
82
|
+
if (!options) return;
|
|
83
|
+
if (options.logger) {
|
|
84
|
+
setLogger(options.logger);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (options.logLevel) {
|
|
88
|
+
setLogLevel(options.logLevel);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
47
91
|
var ACTIVITY_CONTEXT = [
|
|
48
92
|
"https://www.w3.org/ns/activitystreams",
|
|
49
93
|
{
|
|
@@ -402,7 +446,7 @@ var SyncEngine = class {
|
|
|
402
446
|
try {
|
|
403
447
|
listener(event);
|
|
404
448
|
} catch (err) {
|
|
405
|
-
|
|
449
|
+
getLogger().error("[federation] Event listener error:", err);
|
|
406
450
|
}
|
|
407
451
|
}
|
|
408
452
|
}
|
|
@@ -1531,7 +1575,7 @@ var HttpPlatformAdapter = class extends BasePlatformAdapter {
|
|
|
1531
1575
|
const data = await response.json();
|
|
1532
1576
|
return this.config.transformers?.get ? this.config.transformers.get(data) : data;
|
|
1533
1577
|
} catch (err) {
|
|
1534
|
-
|
|
1578
|
+
getLogger().error(`[federation] Failed to get card ${localId}:`, err);
|
|
1535
1579
|
return null;
|
|
1536
1580
|
}
|
|
1537
1581
|
}
|
|
@@ -2083,27 +2127,14 @@ function parseSignatureHeader(header) {
|
|
|
2083
2127
|
return {
|
|
2084
2128
|
keyId: params.keyId,
|
|
2085
2129
|
algorithm: params.algorithm || "rsa-sha256",
|
|
2086
|
-
headers: (params.headers || "(request-target) host date").split(
|
|
2130
|
+
headers: (params.headers || "(request-target) host date").trim().split(/\s+/).filter(Boolean).map((h) => h.toLowerCase()),
|
|
2087
2131
|
signature: params.signature
|
|
2088
2132
|
};
|
|
2089
2133
|
}
|
|
2090
2134
|
function buildSigningString(method, path, headers, headerNames) {
|
|
2091
2135
|
const result = buildSigningStringStrict(method, path, headers, headerNames);
|
|
2092
2136
|
if (!result.success) {
|
|
2093
|
-
|
|
2094
|
-
const lines = [];
|
|
2095
|
-
for (const name of headerNames) {
|
|
2096
|
-
if (name === "(request-target)") {
|
|
2097
|
-
lines.push(`(request-target): ${method.toLowerCase()} ${path}`);
|
|
2098
|
-
} else if (name === "(created)" || name === "(expires)") {
|
|
2099
|
-
} else {
|
|
2100
|
-
const value = headers.get(name);
|
|
2101
|
-
if (value !== null) {
|
|
2102
|
-
lines.push(`${name.toLowerCase()}: ${value}`);
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2105
|
-
}
|
|
2106
|
-
return lines.join("\n");
|
|
2137
|
+
throw new Error(result.error);
|
|
2107
2138
|
}
|
|
2108
2139
|
return result.signingString;
|
|
2109
2140
|
}
|
|
@@ -2112,16 +2143,17 @@ function buildSigningStringStrict(method, path, headers, headerNames) {
|
|
|
2112
2143
|
const missingHeaders = [];
|
|
2113
2144
|
const syntheticHeaders = /* @__PURE__ */ new Set(["(request-target)", "(created)", "(expires)"]);
|
|
2114
2145
|
for (const name of headerNames) {
|
|
2115
|
-
|
|
2146
|
+
const normalizedName = name.toLowerCase();
|
|
2147
|
+
if (normalizedName === "(request-target)") {
|
|
2116
2148
|
lines.push(`(request-target): ${method.toLowerCase()} ${path}`);
|
|
2117
|
-
} else if (
|
|
2118
|
-
} else if (
|
|
2149
|
+
} else if (normalizedName === "(created)") {
|
|
2150
|
+
} else if (normalizedName === "(expires)") {
|
|
2119
2151
|
} else {
|
|
2120
|
-
const value = headers.get(
|
|
2152
|
+
const value = headers.get(normalizedName);
|
|
2121
2153
|
if (value !== null) {
|
|
2122
|
-
lines.push(`${
|
|
2123
|
-
} else if (!syntheticHeaders.has(
|
|
2124
|
-
missingHeaders.push(
|
|
2154
|
+
lines.push(`${normalizedName}: ${value}`);
|
|
2155
|
+
} else if (!syntheticHeaders.has(normalizedName)) {
|
|
2156
|
+
missingHeaders.push(normalizedName);
|
|
2125
2157
|
}
|
|
2126
2158
|
}
|
|
2127
2159
|
}
|
|
@@ -2142,7 +2174,7 @@ async function verifyHttpSignature(parsed, publicKeyPem, method, path, headers,
|
|
|
2142
2174
|
if (options.strictHeaders) {
|
|
2143
2175
|
const strictResult = buildSigningStringStrict(method, path, headers, parsed.headers);
|
|
2144
2176
|
if (!strictResult.success) {
|
|
2145
|
-
|
|
2177
|
+
getLogger().warn(`[federation] Strict header verification failed: ${strictResult.error}`);
|
|
2146
2178
|
return false;
|
|
2147
2179
|
}
|
|
2148
2180
|
}
|
|
@@ -2162,7 +2194,7 @@ async function verifyHttpSignature(parsed, publicKeyPem, method, path, headers,
|
|
|
2162
2194
|
data
|
|
2163
2195
|
);
|
|
2164
2196
|
} catch (error) {
|
|
2165
|
-
|
|
2197
|
+
getLogger().error("[federation] Signature verification failed:", error);
|
|
2166
2198
|
return false;
|
|
2167
2199
|
}
|
|
2168
2200
|
}
|
|
@@ -2300,7 +2332,7 @@ async function importPublicKey(pem) {
|
|
|
2300
2332
|
["verify"]
|
|
2301
2333
|
);
|
|
2302
2334
|
} catch (error) {
|
|
2303
|
-
|
|
2335
|
+
getLogger().error("[federation] Failed to import public key:", error);
|
|
2304
2336
|
return null;
|
|
2305
2337
|
}
|
|
2306
2338
|
}
|
|
@@ -2316,7 +2348,7 @@ async function importPrivateKey(pem) {
|
|
|
2316
2348
|
["sign"]
|
|
2317
2349
|
);
|
|
2318
2350
|
} catch (error) {
|
|
2319
|
-
|
|
2351
|
+
getLogger().error("[federation] Failed to import private key:", error);
|
|
2320
2352
|
return null;
|
|
2321
2353
|
}
|
|
2322
2354
|
}
|
|
@@ -2345,9 +2377,31 @@ function extractHostFromActorId(actorId) {
|
|
|
2345
2377
|
return null;
|
|
2346
2378
|
}
|
|
2347
2379
|
}
|
|
2380
|
+
function timingSafeEqualString(a, b) {
|
|
2381
|
+
let mismatch = a.length === b.length ? 0 : 1;
|
|
2382
|
+
const maxLen = Math.max(a.length, b.length);
|
|
2383
|
+
for (let i = 0; i < maxLen; i++) {
|
|
2384
|
+
const aCode = a.charCodeAt(i) || 0;
|
|
2385
|
+
const bCode = b.charCodeAt(i) || 0;
|
|
2386
|
+
mismatch |= aCode ^ bCode;
|
|
2387
|
+
}
|
|
2388
|
+
return mismatch === 0;
|
|
2389
|
+
}
|
|
2348
2390
|
async function handleInbox(body, headers, options) {
|
|
2349
2391
|
assertFederationEnabled("handleInbox");
|
|
2350
2392
|
try {
|
|
2393
|
+
const normalizedHeaders = headers instanceof Headers ? headers : new Headers(headers);
|
|
2394
|
+
const networkKey = typeof options.networkKey === "string" ? options.networkKey : void 0;
|
|
2395
|
+
const networkKeyHeader = options.networkKeyHeader ?? "X-Foundry-Network-Key";
|
|
2396
|
+
if (networkKey && networkKey.length > 0) {
|
|
2397
|
+
const provided = normalizedHeaders.get(networkKeyHeader);
|
|
2398
|
+
if (!provided || !timingSafeEqualString(provided, networkKey)) {
|
|
2399
|
+
return {
|
|
2400
|
+
accepted: false,
|
|
2401
|
+
error: "Unauthorized: invalid or missing network key"
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2351
2405
|
if (options.moderationStore) {
|
|
2352
2406
|
const actorId = typeof body === "object" && body !== null && "actor" in body ? String(body.actor) : null;
|
|
2353
2407
|
if (actorId) {
|
|
@@ -2370,7 +2424,7 @@ async function handleInbox(body, headers, options) {
|
|
|
2370
2424
|
};
|
|
2371
2425
|
}
|
|
2372
2426
|
if (options.strictMode) {
|
|
2373
|
-
const signatureHeader =
|
|
2427
|
+
const signatureHeader = normalizedHeaders.get("signature");
|
|
2374
2428
|
if (!signatureHeader) {
|
|
2375
2429
|
return {
|
|
2376
2430
|
accepted: false,
|
|
@@ -2384,6 +2438,15 @@ async function handleInbox(body, headers, options) {
|
|
|
2384
2438
|
error: "Invalid Signature header format"
|
|
2385
2439
|
};
|
|
2386
2440
|
}
|
|
2441
|
+
if (networkKey && networkKey.length > 0) {
|
|
2442
|
+
const requiredSigned = networkKeyHeader.toLowerCase();
|
|
2443
|
+
if (!parsedSig.headers.includes(requiredSigned)) {
|
|
2444
|
+
return {
|
|
2445
|
+
accepted: false,
|
|
2446
|
+
error: `Strict mode: signature missing required header: ${requiredSigned}`
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2387
2450
|
const missingSignedHeaders = REQUIRED_SIGNED_HEADERS.filter(
|
|
2388
2451
|
(h) => !parsedSig.headers.includes(h)
|
|
2389
2452
|
);
|
|
@@ -2393,14 +2456,14 @@ async function handleInbox(body, headers, options) {
|
|
|
2393
2456
|
error: `Strict mode: signature missing required headers: ${missingSignedHeaders.join(", ")}`
|
|
2394
2457
|
};
|
|
2395
2458
|
}
|
|
2396
|
-
const dateHeader =
|
|
2459
|
+
const dateHeader = normalizedHeaders.get("date");
|
|
2397
2460
|
if (!dateHeader) {
|
|
2398
2461
|
return {
|
|
2399
2462
|
accepted: false,
|
|
2400
2463
|
error: "Strict mode: Date header required"
|
|
2401
2464
|
};
|
|
2402
2465
|
}
|
|
2403
|
-
const hostHeader =
|
|
2466
|
+
const hostHeader = normalizedHeaders.get("host");
|
|
2404
2467
|
if (!hostHeader) {
|
|
2405
2468
|
return {
|
|
2406
2469
|
accepted: false,
|
|
@@ -2443,7 +2506,7 @@ async function handleInbox(body, headers, options) {
|
|
|
2443
2506
|
error: `Invalid key ID or actor URL`
|
|
2444
2507
|
};
|
|
2445
2508
|
}
|
|
2446
|
-
const digestHeader =
|
|
2509
|
+
const digestHeader = normalizedHeaders.get("digest");
|
|
2447
2510
|
if (digestHeader) {
|
|
2448
2511
|
if (!options.rawBody) {
|
|
2449
2512
|
return {
|
|
@@ -2474,13 +2537,13 @@ async function handleInbox(body, headers, options) {
|
|
|
2474
2537
|
}
|
|
2475
2538
|
const method = options.method || "POST";
|
|
2476
2539
|
const path = options.path || "/inbox";
|
|
2477
|
-
const normalizedHeaders = headers instanceof Headers ? headers : new Headers(headers);
|
|
2478
2540
|
const isValid = await verifyHttpSignature(
|
|
2479
2541
|
parsedSig,
|
|
2480
2542
|
actor.publicKey.publicKeyPem,
|
|
2481
2543
|
method,
|
|
2482
2544
|
path,
|
|
2483
|
-
normalizedHeaders
|
|
2545
|
+
normalizedHeaders,
|
|
2546
|
+
{ strictHeaders: true }
|
|
2484
2547
|
);
|
|
2485
2548
|
if (!isValid) {
|
|
2486
2549
|
return {
|
|
@@ -3559,7 +3622,7 @@ var PolicyEngine = class {
|
|
|
3559
3622
|
if (!regex) {
|
|
3560
3623
|
const safetyWarning = checkRegexSafety(rule.pattern);
|
|
3561
3624
|
if (safetyWarning) {
|
|
3562
|
-
|
|
3625
|
+
getLogger().warn(`[moderation] Rule "${rule.name}": ${safetyWarning}`);
|
|
3563
3626
|
}
|
|
3564
3627
|
try {
|
|
3565
3628
|
regex = new RegExp(rule.pattern, "i");
|
|
@@ -3799,11 +3862,12 @@ function getEnvVar(name) {
|
|
|
3799
3862
|
return void 0;
|
|
3800
3863
|
}
|
|
3801
3864
|
function enableFederation(options) {
|
|
3865
|
+
configureLogger(options);
|
|
3802
3866
|
explicitlyEnabled = true;
|
|
3803
3867
|
envCheckSkipped = options?.skipEnvCheck ?? false;
|
|
3804
3868
|
const nodeEnv = getEnvVar("NODE_ENV");
|
|
3805
3869
|
if (nodeEnv === "development" || nodeEnv === "test") {
|
|
3806
|
-
|
|
3870
|
+
getLogger().warn(
|
|
3807
3871
|
"[character-foundry/federation] Federation enabled. WARNING: Verify HTTP signatures in production. Do NOT use in production with untrusted inputs without signature validation."
|
|
3808
3872
|
);
|
|
3809
3873
|
}
|
|
@@ -3867,6 +3931,7 @@ export {
|
|
|
3867
3931
|
createAnnounceActivity,
|
|
3868
3932
|
createArchiveAdapter,
|
|
3869
3933
|
createBlockActivity,
|
|
3934
|
+
createConsoleLogger,
|
|
3870
3935
|
createCreateActivity,
|
|
3871
3936
|
createDeleteActivity,
|
|
3872
3937
|
createFlagActivity,
|
|
@@ -3881,6 +3946,7 @@ export {
|
|
|
3881
3946
|
enableFederation,
|
|
3882
3947
|
generateActivityId,
|
|
3883
3948
|
generateCardId,
|
|
3949
|
+
getLogger as getFederationLogger,
|
|
3884
3950
|
handleActor,
|
|
3885
3951
|
handleInbox,
|
|
3886
3952
|
handleNodeInfo,
|
|
@@ -3893,6 +3959,8 @@ export {
|
|
|
3893
3959
|
parseForkActivity,
|
|
3894
3960
|
parseInstallActivity,
|
|
3895
3961
|
parseSignatureHeader,
|
|
3962
|
+
setLogLevel as setFederationLogLevel,
|
|
3963
|
+
setLogger as setFederationLogger,
|
|
3896
3964
|
signRequest,
|
|
3897
3965
|
stCharacterToCCv3,
|
|
3898
3966
|
validateBlockActivity as validateBlockActivityFields,
|