@downcity/city 0.2.200 → 0.2.211
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/README.md +89 -13
- package/bin/client/bureau.d.ts +41 -0
- package/bin/client/bureau.d.ts.map +1 -0
- package/bin/client/bureau.js +240 -0
- package/bin/client/bureau.js.map +1 -0
- package/bin/client/city.d.ts +15 -79
- package/bin/client/city.d.ts.map +1 -1
- package/bin/client/city.js +15 -99
- package/bin/client/city.js.map +1 -1
- package/bin/client/federation-admin.d.ts +32 -0
- package/bin/client/federation-admin.d.ts.map +1 -0
- package/bin/client/federation-admin.js +54 -0
- package/bin/client/federation-admin.js.map +1 -0
- package/bin/client/types.d.ts +10 -70
- package/bin/client/types.d.ts.map +1 -1
- package/bin/client/types.js +3 -3
- package/bin/federation/auth/authenticator.d.ts +17 -13
- package/bin/federation/auth/authenticator.d.ts.map +1 -1
- package/bin/federation/auth/authenticator.js +38 -27
- package/bin/federation/auth/authenticator.js.map +1 -1
- package/bin/federation/auth/bureau-token-schema.d.ts +274 -0
- package/bin/federation/auth/bureau-token-schema.d.ts.map +1 -0
- package/bin/federation/auth/bureau-token-schema.js +43 -0
- package/bin/federation/auth/bureau-token-schema.js.map +1 -0
- package/bin/federation/auth/bureau-token-store.d.ts +22 -0
- package/bin/federation/auth/bureau-token-store.d.ts.map +1 -0
- package/bin/federation/auth/bureau-token-store.js +122 -0
- package/bin/federation/auth/bureau-token-store.js.map +1 -0
- package/bin/federation/auth/federation-key-store.d.ts +26 -0
- package/bin/federation/auth/federation-key-store.d.ts.map +1 -0
- package/bin/federation/auth/federation-key-store.js +96 -0
- package/bin/federation/auth/federation-key-store.js.map +1 -0
- package/bin/federation/auth/key-schema.d.ts +275 -0
- package/bin/federation/auth/key-schema.d.ts.map +1 -0
- package/bin/federation/auth/key-schema.js +44 -0
- package/bin/federation/auth/key-schema.js.map +1 -0
- package/bin/federation/auth/types.d.ts +62 -4
- package/bin/federation/auth/types.d.ts.map +1 -1
- package/bin/federation/auth/user-token-authority.d.ts +26 -0
- package/bin/federation/auth/user-token-authority.d.ts.map +1 -0
- package/bin/federation/auth/user-token-authority.js +179 -0
- package/bin/federation/auth/user-token-authority.js.map +1 -0
- package/bin/federation/federation-init.d.ts.map +1 -1
- package/bin/federation/federation-init.js +23 -4
- package/bin/federation/federation-init.js.map +1 -1
- package/bin/federation/federation-router.d.ts +3 -1
- package/bin/federation/federation-router.d.ts.map +1 -1
- package/bin/federation/federation-router.js +17 -0
- package/bin/federation/federation-router.js.map +1 -1
- package/bin/federation/federation-runtime.d.ts.map +1 -1
- package/bin/federation/federation-runtime.js +14 -2
- package/bin/federation/federation-runtime.js.map +1 -1
- package/bin/federation/federation.d.ts.map +1 -1
- package/bin/federation/federation.js +2 -0
- package/bin/federation/federation.js.map +1 -1
- package/bin/federation/runtime.d.ts +4 -0
- package/bin/federation/runtime.d.ts.map +1 -1
- package/bin/index.d.ts +11 -10
- package/bin/index.d.ts.map +1 -1
- package/bin/index.js +5 -3
- package/bin/index.js.map +1 -1
- package/bin/pact/admin/index.d.ts +7 -19
- package/bin/pact/admin/index.d.ts.map +1 -1
- package/bin/pact/admin/index.js +10 -18
- package/bin/pact/admin/index.js.map +1 -1
- package/bin/pact/admin/types.d.ts +4 -10
- package/bin/pact/admin/types.d.ts.map +1 -1
- package/bin/pact/invoker/ai/CityModel.d.ts +1 -1
- package/bin/pact/invoker/ai/CityModel.d.ts.map +1 -1
- package/bin/pact/invoker/ai/CityModel.js +3 -65
- package/bin/pact/invoker/ai/CityModel.js.map +1 -1
- package/bin/pact/invoker/ai/types.d.ts +1 -1
- package/bin/pact/invoker/ai/types.js +1 -1
- package/bin/pact/invoker/bureaus/index.d.ts +25 -0
- package/bin/pact/invoker/bureaus/index.d.ts.map +1 -0
- package/bin/pact/invoker/bureaus/index.js +36 -0
- package/bin/pact/invoker/bureaus/index.js.map +1 -0
- package/bin/pact/invoker/cities/types.d.ts +2 -2
- package/bin/pact/invoker/cities/types.d.ts.map +1 -1
- package/bin/pact/invoker/user/index.d.ts +19 -0
- package/bin/pact/invoker/user/index.d.ts.map +1 -0
- package/bin/pact/invoker/user/index.js +24 -0
- package/bin/pact/invoker/user/index.js.map +1 -0
- package/bin/pact/user/index.d.ts +2 -1
- package/bin/pact/user/index.d.ts.map +1 -1
- package/bin/pact/user/index.js +7 -3
- package/bin/pact/user/index.js.map +1 -1
- package/bin/pact/user/types.d.ts +11 -6
- package/bin/pact/user/types.d.ts.map +1 -1
- package/bin/service/ai/AIChannel.d.ts +57 -0
- package/bin/service/ai/AIChannel.d.ts.map +1 -0
- package/bin/service/ai/AIChannel.js +151 -0
- package/bin/service/ai/AIChannel.js.map +1 -0
- package/bin/service/ai/OpenAIChatCompletionsAdapter.d.ts +23 -0
- package/bin/service/ai/OpenAIChatCompletionsAdapter.d.ts.map +1 -0
- package/bin/service/ai/OpenAIChatCompletionsAdapter.js +503 -0
- package/bin/service/ai/OpenAIChatCompletionsAdapter.js.map +1 -0
- package/bin/service/ai/ai-service-values.d.ts +16 -19
- package/bin/service/ai/ai-service-values.d.ts.map +1 -1
- package/bin/service/ai/ai-service-values.js +9 -13
- package/bin/service/ai/ai-service-values.js.map +1 -1
- package/bin/service/ai/ai-service.d.ts +16 -15
- package/bin/service/ai/ai-service.d.ts.map +1 -1
- package/bin/service/ai/ai-service.js +97 -106
- package/bin/service/ai/ai-service.js.map +1 -1
- package/bin/service/ai/helpers.d.ts +8 -35
- package/bin/service/ai/helpers.d.ts.map +1 -1
- package/bin/service/ai/helpers.js +8 -140
- package/bin/service/ai/helpers.js.map +1 -1
- package/bin/service/ai/image-job-store.d.ts +2 -3
- package/bin/service/ai/image-job-store.d.ts.map +1 -1
- package/bin/service/ai/image-job-store.js.map +1 -1
- package/bin/service/ai/language-model-stream.d.ts +9 -4
- package/bin/service/ai/language-model-stream.d.ts.map +1 -1
- package/bin/service/ai/language-model-stream.js +8 -4
- package/bin/service/ai/language-model-stream.js.map +1 -1
- package/bin/service/ai/language-model-text.d.ts +15 -0
- package/bin/service/ai/language-model-text.d.ts.map +1 -0
- package/bin/service/ai/language-model-text.js +67 -0
- package/bin/service/ai/language-model-text.js.map +1 -0
- package/bin/service/ai/model-context-window.d.ts +2 -2
- package/bin/service/ai/model-context-window.d.ts.map +1 -1
- package/bin/service/ai/model-context-window.js.map +1 -1
- package/bin/service/ai/model-registry.d.ts +9 -8
- package/bin/service/ai/model-registry.d.ts.map +1 -1
- package/bin/service/ai/model-registry.js +1 -5
- package/bin/service/ai/model-registry.js.map +1 -1
- package/bin/service/ai/model-routing.d.ts +1 -1
- package/bin/service/ai/model-routing.d.ts.map +1 -1
- package/bin/service/ai/model-routing.js +1 -1
- package/bin/service/ai/model-routing.js.map +1 -1
- package/bin/service/ai/reasoning.d.ts +4 -4
- package/bin/service/ai/reasoning.d.ts.map +1 -1
- package/bin/service/ai/reasoning.js.map +1 -1
- package/bin/service/bureaus/bureaus-service.d.ts +15 -0
- package/bin/service/bureaus/bureaus-service.d.ts.map +1 -0
- package/bin/service/bureaus/bureaus-service.js +55 -0
- package/bin/service/bureaus/bureaus-service.js.map +1 -0
- package/bin/service/installable-service.d.ts +5 -2
- package/bin/service/installable-service.d.ts.map +1 -1
- package/bin/service/installable-service.js +1 -0
- package/bin/service/installable-service.js.map +1 -1
- package/bin/service/instruction.js +1 -1
- package/bin/service/instruction.js.map +1 -1
- package/bin/service/service.d.ts +15 -2
- package/bin/service/service.d.ts.map +1 -1
- package/bin/service/service.js +2 -0
- package/bin/service/service.js.map +1 -1
- package/bin/types/AI.d.ts +289 -0
- package/bin/types/AI.d.ts.map +1 -0
- package/bin/types/AI.js +8 -0
- package/bin/types/AI.js.map +1 -0
- package/bin/types/AITransport.d.ts +251 -0
- package/bin/types/AITransport.d.ts.map +1 -0
- package/bin/types/AITransport.js +12 -0
- package/bin/types/AITransport.js.map +1 -0
- package/bin/types/Bureau.d.ts +96 -0
- package/bin/types/Bureau.d.ts.map +1 -0
- package/bin/types/Bureau.js +8 -0
- package/bin/types/Bureau.js.map +1 -0
- package/bin/types/FederationAdmin.d.ts +16 -0
- package/bin/types/FederationAdmin.d.ts.map +1 -0
- package/bin/types/FederationAdmin.js +7 -0
- package/bin/types/FederationAdmin.js.map +1 -0
- package/bin/types/Metering.d.ts +2 -2
- package/bin/types/Metering.d.ts.map +1 -1
- package/bin/types/User.d.ts +24 -0
- package/bin/types/User.d.ts.map +1 -0
- package/bin/types/User.js +8 -0
- package/bin/types/User.js.map +1 -0
- package/bin/utils/CityLanguageModelCodec.d.ts +1 -1
- package/bin/utils/CityLanguageModelCodec.d.ts.map +1 -1
- package/bin/utils/CityLanguageModelResult.d.ts +11 -0
- package/bin/utils/CityLanguageModelResult.d.ts.map +1 -0
- package/bin/utils/CityLanguageModelResult.js +76 -0
- package/bin/utils/CityLanguageModelResult.js.map +1 -0
- package/package.json +4 -3
- package/bin/federation/auth/token-signer.d.ts +0 -27
- package/bin/federation/auth/token-signer.d.ts.map +0 -1
- package/bin/federation/auth/token-signer.js +0 -116
- package/bin/federation/auth/token-signer.js.map +0 -1
- package/bin/service/ai/charge.d.ts +0 -76
- package/bin/service/ai/charge.d.ts.map +0 -1
- package/bin/service/ai/charge.js +0 -10
- package/bin/service/ai/charge.js.map +0 -1
- package/bin/service/ai/job-types.d.ts +0 -69
- package/bin/service/ai/job-types.d.ts.map +0 -1
- package/bin/service/ai/job-types.js +0 -9
- package/bin/service/ai/job-types.js.map +0 -1
- package/bin/service/ai/provider.d.ts +0 -143
- package/bin/service/ai/provider.d.ts.map +0 -1
- package/bin/service/ai/provider.js +0 -221
- package/bin/service/ai/provider.js.map +0 -1
- package/bin/service/ai/types.d.ts +0 -174
- package/bin/service/ai/types.d.ts.map +0 -1
- package/bin/service/ai/types.js +0 -7
- package/bin/service/ai/types.js.map +0 -1
- package/bin/types/AIImageJobClaim.d.ts +0 -14
- package/bin/types/AIImageJobClaim.d.ts.map +0 -1
- package/bin/types/AIImageJobClaim.js +0 -7
- package/bin/types/AIImageJobClaim.js.map +0 -1
- package/bin/types/AIReasoning.d.ts +0 -25
- package/bin/types/AIReasoning.d.ts.map +0 -1
- package/bin/types/AIReasoning.js +0 -7
- package/bin/types/AIReasoning.js.map +0 -1
- package/bin/types/AIRouting.d.ts +0 -37
- package/bin/types/AIRouting.d.ts.map +0 -1
- package/bin/types/AIRouting.js +0 -7
- package/bin/types/AIRouting.js.map +0 -1
- package/bin/types/CityLanguageModelRuntime.d.ts +0 -46
- package/bin/types/CityLanguageModelRuntime.d.ts.map +0 -1
- package/bin/types/CityLanguageModelRuntime.js +0 -8
- package/bin/types/CityLanguageModelRuntime.js.map +0 -1
- package/bin/types/CityLanguageModelTransport.d.ts +0 -49
- package/bin/types/CityLanguageModelTransport.d.ts.map +0 -1
- package/bin/types/CityLanguageModelTransport.js +0 -9
- package/bin/types/CityLanguageModelTransport.js.map +0 -1
- package/bin/types/CityModelRuntime.d.ts +0 -17
- package/bin/types/CityModelRuntime.d.ts.map +0 -1
- package/bin/types/CityModelRuntime.js +0 -8
- package/bin/types/CityModelRuntime.js.map +0 -1
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federation Bureau Token 数据库表。
|
|
3
|
+
*
|
|
4
|
+
* 只保存 Token hash 和权限元数据,不持久化 Bureau Token 明文。
|
|
5
|
+
*/
|
|
6
|
+
/** Federation SQLite Bureau Token 表。 */
|
|
7
|
+
export declare const sqlite_bureau_tokens: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
|
|
8
|
+
name: "federation_bureau_tokens";
|
|
9
|
+
schema: undefined;
|
|
10
|
+
columns: {
|
|
11
|
+
token_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
12
|
+
name: "token_id";
|
|
13
|
+
tableName: "federation_bureau_tokens";
|
|
14
|
+
dataType: "string";
|
|
15
|
+
columnType: "SQLiteText";
|
|
16
|
+
data: string;
|
|
17
|
+
driverParam: string;
|
|
18
|
+
notNull: true;
|
|
19
|
+
hasDefault: false;
|
|
20
|
+
isPrimaryKey: true;
|
|
21
|
+
isAutoincrement: false;
|
|
22
|
+
hasRuntimeDefault: false;
|
|
23
|
+
enumValues: [string, ...string[]];
|
|
24
|
+
baseColumn: never;
|
|
25
|
+
identity: undefined;
|
|
26
|
+
generated: undefined;
|
|
27
|
+
}, {}, {
|
|
28
|
+
length: number | undefined;
|
|
29
|
+
}>;
|
|
30
|
+
city_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
31
|
+
name: "city_id";
|
|
32
|
+
tableName: "federation_bureau_tokens";
|
|
33
|
+
dataType: "string";
|
|
34
|
+
columnType: "SQLiteText";
|
|
35
|
+
data: string;
|
|
36
|
+
driverParam: string;
|
|
37
|
+
notNull: true;
|
|
38
|
+
hasDefault: false;
|
|
39
|
+
isPrimaryKey: false;
|
|
40
|
+
isAutoincrement: false;
|
|
41
|
+
hasRuntimeDefault: false;
|
|
42
|
+
enumValues: [string, ...string[]];
|
|
43
|
+
baseColumn: never;
|
|
44
|
+
identity: undefined;
|
|
45
|
+
generated: undefined;
|
|
46
|
+
}, {}, {
|
|
47
|
+
length: number | undefined;
|
|
48
|
+
}>;
|
|
49
|
+
token_hash: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
50
|
+
name: "token_hash";
|
|
51
|
+
tableName: "federation_bureau_tokens";
|
|
52
|
+
dataType: "string";
|
|
53
|
+
columnType: "SQLiteText";
|
|
54
|
+
data: string;
|
|
55
|
+
driverParam: string;
|
|
56
|
+
notNull: true;
|
|
57
|
+
hasDefault: false;
|
|
58
|
+
isPrimaryKey: false;
|
|
59
|
+
isAutoincrement: false;
|
|
60
|
+
hasRuntimeDefault: false;
|
|
61
|
+
enumValues: [string, ...string[]];
|
|
62
|
+
baseColumn: never;
|
|
63
|
+
identity: undefined;
|
|
64
|
+
generated: undefined;
|
|
65
|
+
}, {}, {
|
|
66
|
+
length: number | undefined;
|
|
67
|
+
}>;
|
|
68
|
+
capabilities: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
69
|
+
name: "capabilities";
|
|
70
|
+
tableName: "federation_bureau_tokens";
|
|
71
|
+
dataType: "string";
|
|
72
|
+
columnType: "SQLiteText";
|
|
73
|
+
data: string;
|
|
74
|
+
driverParam: string;
|
|
75
|
+
notNull: true;
|
|
76
|
+
hasDefault: false;
|
|
77
|
+
isPrimaryKey: false;
|
|
78
|
+
isAutoincrement: false;
|
|
79
|
+
hasRuntimeDefault: false;
|
|
80
|
+
enumValues: [string, ...string[]];
|
|
81
|
+
baseColumn: never;
|
|
82
|
+
identity: undefined;
|
|
83
|
+
generated: undefined;
|
|
84
|
+
}, {}, {
|
|
85
|
+
length: number | undefined;
|
|
86
|
+
}>;
|
|
87
|
+
status: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
88
|
+
name: "status";
|
|
89
|
+
tableName: "federation_bureau_tokens";
|
|
90
|
+
dataType: "string";
|
|
91
|
+
columnType: "SQLiteText";
|
|
92
|
+
data: string;
|
|
93
|
+
driverParam: string;
|
|
94
|
+
notNull: true;
|
|
95
|
+
hasDefault: false;
|
|
96
|
+
isPrimaryKey: false;
|
|
97
|
+
isAutoincrement: false;
|
|
98
|
+
hasRuntimeDefault: false;
|
|
99
|
+
enumValues: [string, ...string[]];
|
|
100
|
+
baseColumn: never;
|
|
101
|
+
identity: undefined;
|
|
102
|
+
generated: undefined;
|
|
103
|
+
}, {}, {
|
|
104
|
+
length: number | undefined;
|
|
105
|
+
}>;
|
|
106
|
+
created_at: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
107
|
+
name: "created_at";
|
|
108
|
+
tableName: "federation_bureau_tokens";
|
|
109
|
+
dataType: "string";
|
|
110
|
+
columnType: "SQLiteText";
|
|
111
|
+
data: string;
|
|
112
|
+
driverParam: string;
|
|
113
|
+
notNull: true;
|
|
114
|
+
hasDefault: false;
|
|
115
|
+
isPrimaryKey: false;
|
|
116
|
+
isAutoincrement: false;
|
|
117
|
+
hasRuntimeDefault: false;
|
|
118
|
+
enumValues: [string, ...string[]];
|
|
119
|
+
baseColumn: never;
|
|
120
|
+
identity: undefined;
|
|
121
|
+
generated: undefined;
|
|
122
|
+
}, {}, {
|
|
123
|
+
length: number | undefined;
|
|
124
|
+
}>;
|
|
125
|
+
updated_at: import("drizzle-orm/sqlite-core").SQLiteColumn<{
|
|
126
|
+
name: "updated_at";
|
|
127
|
+
tableName: "federation_bureau_tokens";
|
|
128
|
+
dataType: "string";
|
|
129
|
+
columnType: "SQLiteText";
|
|
130
|
+
data: string;
|
|
131
|
+
driverParam: string;
|
|
132
|
+
notNull: true;
|
|
133
|
+
hasDefault: false;
|
|
134
|
+
isPrimaryKey: false;
|
|
135
|
+
isAutoincrement: false;
|
|
136
|
+
hasRuntimeDefault: false;
|
|
137
|
+
enumValues: [string, ...string[]];
|
|
138
|
+
baseColumn: never;
|
|
139
|
+
identity: undefined;
|
|
140
|
+
generated: undefined;
|
|
141
|
+
}, {}, {
|
|
142
|
+
length: number | undefined;
|
|
143
|
+
}>;
|
|
144
|
+
};
|
|
145
|
+
dialect: "sqlite";
|
|
146
|
+
}>;
|
|
147
|
+
/** Federation Postgres Bureau Token 表。 */
|
|
148
|
+
export declare const pg_bureau_tokens: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
149
|
+
name: "federation_bureau_tokens";
|
|
150
|
+
schema: undefined;
|
|
151
|
+
columns: {
|
|
152
|
+
token_id: import("drizzle-orm/pg-core").PgColumn<{
|
|
153
|
+
name: "token_id";
|
|
154
|
+
tableName: "federation_bureau_tokens";
|
|
155
|
+
dataType: "string";
|
|
156
|
+
columnType: "PgText";
|
|
157
|
+
data: string;
|
|
158
|
+
driverParam: string;
|
|
159
|
+
notNull: true;
|
|
160
|
+
hasDefault: false;
|
|
161
|
+
isPrimaryKey: true;
|
|
162
|
+
isAutoincrement: false;
|
|
163
|
+
hasRuntimeDefault: false;
|
|
164
|
+
enumValues: [string, ...string[]];
|
|
165
|
+
baseColumn: never;
|
|
166
|
+
identity: undefined;
|
|
167
|
+
generated: undefined;
|
|
168
|
+
}, {}, {}>;
|
|
169
|
+
city_id: import("drizzle-orm/pg-core").PgColumn<{
|
|
170
|
+
name: "city_id";
|
|
171
|
+
tableName: "federation_bureau_tokens";
|
|
172
|
+
dataType: "string";
|
|
173
|
+
columnType: "PgText";
|
|
174
|
+
data: string;
|
|
175
|
+
driverParam: string;
|
|
176
|
+
notNull: true;
|
|
177
|
+
hasDefault: false;
|
|
178
|
+
isPrimaryKey: false;
|
|
179
|
+
isAutoincrement: false;
|
|
180
|
+
hasRuntimeDefault: false;
|
|
181
|
+
enumValues: [string, ...string[]];
|
|
182
|
+
baseColumn: never;
|
|
183
|
+
identity: undefined;
|
|
184
|
+
generated: undefined;
|
|
185
|
+
}, {}, {}>;
|
|
186
|
+
token_hash: import("drizzle-orm/pg-core").PgColumn<{
|
|
187
|
+
name: "token_hash";
|
|
188
|
+
tableName: "federation_bureau_tokens";
|
|
189
|
+
dataType: "string";
|
|
190
|
+
columnType: "PgText";
|
|
191
|
+
data: string;
|
|
192
|
+
driverParam: string;
|
|
193
|
+
notNull: true;
|
|
194
|
+
hasDefault: false;
|
|
195
|
+
isPrimaryKey: false;
|
|
196
|
+
isAutoincrement: false;
|
|
197
|
+
hasRuntimeDefault: false;
|
|
198
|
+
enumValues: [string, ...string[]];
|
|
199
|
+
baseColumn: never;
|
|
200
|
+
identity: undefined;
|
|
201
|
+
generated: undefined;
|
|
202
|
+
}, {}, {}>;
|
|
203
|
+
capabilities: import("drizzle-orm/pg-core").PgColumn<{
|
|
204
|
+
name: "capabilities";
|
|
205
|
+
tableName: "federation_bureau_tokens";
|
|
206
|
+
dataType: "string";
|
|
207
|
+
columnType: "PgText";
|
|
208
|
+
data: string;
|
|
209
|
+
driverParam: string;
|
|
210
|
+
notNull: true;
|
|
211
|
+
hasDefault: false;
|
|
212
|
+
isPrimaryKey: false;
|
|
213
|
+
isAutoincrement: false;
|
|
214
|
+
hasRuntimeDefault: false;
|
|
215
|
+
enumValues: [string, ...string[]];
|
|
216
|
+
baseColumn: never;
|
|
217
|
+
identity: undefined;
|
|
218
|
+
generated: undefined;
|
|
219
|
+
}, {}, {}>;
|
|
220
|
+
status: import("drizzle-orm/pg-core").PgColumn<{
|
|
221
|
+
name: "status";
|
|
222
|
+
tableName: "federation_bureau_tokens";
|
|
223
|
+
dataType: "string";
|
|
224
|
+
columnType: "PgText";
|
|
225
|
+
data: string;
|
|
226
|
+
driverParam: string;
|
|
227
|
+
notNull: true;
|
|
228
|
+
hasDefault: false;
|
|
229
|
+
isPrimaryKey: false;
|
|
230
|
+
isAutoincrement: false;
|
|
231
|
+
hasRuntimeDefault: false;
|
|
232
|
+
enumValues: [string, ...string[]];
|
|
233
|
+
baseColumn: never;
|
|
234
|
+
identity: undefined;
|
|
235
|
+
generated: undefined;
|
|
236
|
+
}, {}, {}>;
|
|
237
|
+
created_at: import("drizzle-orm/pg-core").PgColumn<{
|
|
238
|
+
name: "created_at";
|
|
239
|
+
tableName: "federation_bureau_tokens";
|
|
240
|
+
dataType: "string";
|
|
241
|
+
columnType: "PgText";
|
|
242
|
+
data: string;
|
|
243
|
+
driverParam: string;
|
|
244
|
+
notNull: true;
|
|
245
|
+
hasDefault: false;
|
|
246
|
+
isPrimaryKey: false;
|
|
247
|
+
isAutoincrement: false;
|
|
248
|
+
hasRuntimeDefault: false;
|
|
249
|
+
enumValues: [string, ...string[]];
|
|
250
|
+
baseColumn: never;
|
|
251
|
+
identity: undefined;
|
|
252
|
+
generated: undefined;
|
|
253
|
+
}, {}, {}>;
|
|
254
|
+
updated_at: import("drizzle-orm/pg-core").PgColumn<{
|
|
255
|
+
name: "updated_at";
|
|
256
|
+
tableName: "federation_bureau_tokens";
|
|
257
|
+
dataType: "string";
|
|
258
|
+
columnType: "PgText";
|
|
259
|
+
data: string;
|
|
260
|
+
driverParam: string;
|
|
261
|
+
notNull: true;
|
|
262
|
+
hasDefault: false;
|
|
263
|
+
isPrimaryKey: false;
|
|
264
|
+
isAutoincrement: false;
|
|
265
|
+
hasRuntimeDefault: false;
|
|
266
|
+
enumValues: [string, ...string[]];
|
|
267
|
+
baseColumn: never;
|
|
268
|
+
identity: undefined;
|
|
269
|
+
generated: undefined;
|
|
270
|
+
}, {}, {}>;
|
|
271
|
+
};
|
|
272
|
+
dialect: "pg";
|
|
273
|
+
}>;
|
|
274
|
+
//# sourceMappingURL=bureau-token-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bureau-token-schema.d.ts","sourceRoot":"","sources":["../../../src/federation/auth/bureau-token-schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,wCAAwC;AACxC,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe/B,CAAC;AAEH,0CAA0C;AAC1C,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAe3B,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federation Bureau Token 数据库表。
|
|
3
|
+
*
|
|
4
|
+
* 只保存 Token hash 和权限元数据,不持久化 Bureau Token 明文。
|
|
5
|
+
*/
|
|
6
|
+
import { pgTable, text as pgText } from "drizzle-orm/pg-core";
|
|
7
|
+
import { sqliteTable, text as sqliteText } from "drizzle-orm/sqlite-core";
|
|
8
|
+
const BUREAU_TOKEN_TABLE = "federation_bureau_tokens";
|
|
9
|
+
/** Federation SQLite Bureau Token 表。 */
|
|
10
|
+
export const sqlite_bureau_tokens = sqliteTable(BUREAU_TOKEN_TABLE, {
|
|
11
|
+
/** Bureau Token 查找 ID。 */
|
|
12
|
+
token_id: sqliteText("token_id").primaryKey(),
|
|
13
|
+
/** Token 绑定的 City。 */
|
|
14
|
+
city_id: sqliteText("city_id").notNull(),
|
|
15
|
+
/** Token SHA-256 Base64URL hash。 */
|
|
16
|
+
token_hash: sqliteText("token_hash").notNull(),
|
|
17
|
+
/** JSON capability 列表。 */
|
|
18
|
+
capabilities: sqliteText("capabilities").notNull(),
|
|
19
|
+
/** active 或 revoked。 */
|
|
20
|
+
status: sqliteText("status").notNull(),
|
|
21
|
+
/** 创建时间。 */
|
|
22
|
+
created_at: sqliteText("created_at").notNull(),
|
|
23
|
+
/** 更新时间。 */
|
|
24
|
+
updated_at: sqliteText("updated_at").notNull(),
|
|
25
|
+
});
|
|
26
|
+
/** Federation Postgres Bureau Token 表。 */
|
|
27
|
+
export const pg_bureau_tokens = pgTable(BUREAU_TOKEN_TABLE, {
|
|
28
|
+
/** Bureau Token 查找 ID。 */
|
|
29
|
+
token_id: pgText("token_id").primaryKey(),
|
|
30
|
+
/** Token 绑定的 City。 */
|
|
31
|
+
city_id: pgText("city_id").notNull(),
|
|
32
|
+
/** Token SHA-256 Base64URL hash。 */
|
|
33
|
+
token_hash: pgText("token_hash").notNull(),
|
|
34
|
+
/** JSON capability 列表。 */
|
|
35
|
+
capabilities: pgText("capabilities").notNull(),
|
|
36
|
+
/** active 或 revoked。 */
|
|
37
|
+
status: pgText("status").notNull(),
|
|
38
|
+
/** 创建时间。 */
|
|
39
|
+
created_at: pgText("created_at").notNull(),
|
|
40
|
+
/** 更新时间。 */
|
|
41
|
+
updated_at: pgText("updated_at").notNull(),
|
|
42
|
+
});
|
|
43
|
+
//# sourceMappingURL=bureau-token-schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bureau-token-schema.js","sourceRoot":"","sources":["../../../src/federation/auth/bureau-token-schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1E,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAEtD,wCAAwC;AACxC,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAC,kBAAkB,EAAE;IAClE,0BAA0B;IAC1B,QAAQ,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,UAAU,EAAE;IAC7C,sBAAsB;IACtB,OAAO,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;IACxC,oCAAoC;IACpC,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAC9C,0BAA0B;IAC1B,YAAY,EAAE,UAAU,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE;IAClD,wBAAwB;IACxB,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;IACtC,YAAY;IACZ,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAC9C,YAAY;IACZ,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;CAC/C,CAAC,CAAC;AAEH,0CAA0C;AAC1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,EAAE;IAC1D,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,UAAU,EAAE;IACzC,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;IACpC,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAC1C,0BAA0B;IAC1B,YAAY,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE;IAC9C,wBAAwB;IACxB,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;IAClC,YAAY;IACZ,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAC1C,YAAY;IACZ,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;CAC3C,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federation Bureau Token Store。
|
|
3
|
+
*
|
|
4
|
+
* Token 使用 `fb_<token_id>.<secret>` 格式。数据库只保存完整 token 的 SHA-256 hash,
|
|
5
|
+
* 通过 token_id 定位记录后再比较 hash,从而支持注册表状态校验和撤销。
|
|
6
|
+
*/
|
|
7
|
+
import type { CityTableApi } from "../../store/table-api.js";
|
|
8
|
+
import type { BureauTokenRecord, BureauTokenSummary, RegisterBureauTokenInput, RuntimeBureau } from "../../types/Bureau.js";
|
|
9
|
+
/** Bureau Token 持久化与验证入口。 */
|
|
10
|
+
export declare class BureauTokenStore {
|
|
11
|
+
private readonly table;
|
|
12
|
+
constructor(table: CityTableApi<BureauTokenRecord>);
|
|
13
|
+
/** 登记 CLI 生成的 Bureau Token hash,不接触 Token 明文。 */
|
|
14
|
+
register(input: RegisterBureauTokenInput): Promise<BureauTokenSummary>;
|
|
15
|
+
/** 验证 Bureau Token 并返回绑定身份。 */
|
|
16
|
+
resolve(bureau_token: string): Promise<RuntimeBureau | undefined>;
|
|
17
|
+
/** 列出 Bureau Token 元数据,不返回 token hash。 */
|
|
18
|
+
list(): Promise<BureauTokenSummary[]>;
|
|
19
|
+
/** 立即撤销 Bureau Token。 */
|
|
20
|
+
revoke(token_id: string): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=bureau-token-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bureau-token-store.d.ts","sourceRoot":"","sources":["../../../src/federation/auth/bureau-token-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAEV,iBAAiB,EACjB,kBAAkB,EAClB,wBAAwB,EACxB,aAAa,EACd,MAAM,uBAAuB,CAAC;AAI/B,6BAA6B;AAC7B,qBAAa,gBAAgB;IACf,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY,CAAC,iBAAiB,CAAC;IAEnE,iDAAiD;IAC3C,QAAQ,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA4B5E,+BAA+B;IACzB,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC;IAavE,0CAA0C;IACpC,IAAI,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAW3C,yBAAyB;IACnB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU9C"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federation Bureau Token Store。
|
|
3
|
+
*
|
|
4
|
+
* Token 使用 `fb_<token_id>.<secret>` 格式。数据库只保存完整 token 的 SHA-256 hash,
|
|
5
|
+
* 通过 token_id 定位记录后再比较 hash,从而支持注册表状态校验和撤销。
|
|
6
|
+
*/
|
|
7
|
+
import { base64UrlEncodeBytes } from "../../utils/helpers.js";
|
|
8
|
+
const DEFAULT_CAPABILITIES = ["accounts:read"];
|
|
9
|
+
/** Bureau Token 持久化与验证入口。 */
|
|
10
|
+
export class BureauTokenStore {
|
|
11
|
+
table;
|
|
12
|
+
constructor(table) {
|
|
13
|
+
this.table = table;
|
|
14
|
+
}
|
|
15
|
+
/** 登记 CLI 生成的 Bureau Token hash,不接触 Token 明文。 */
|
|
16
|
+
async register(input) {
|
|
17
|
+
const token_id = read_token_id_value(input.token_id);
|
|
18
|
+
const token_hash = read_token_hash(input.token_hash);
|
|
19
|
+
const city_id = read_required_string(input.city_id, "city_id");
|
|
20
|
+
const capabilities = normalize_capabilities(input.capabilities);
|
|
21
|
+
if ((await this.table.select({ token_id }))[0]) {
|
|
22
|
+
throw new TypeError(`Bureau token already registered: ${token_id}`);
|
|
23
|
+
}
|
|
24
|
+
const now = new Date().toISOString();
|
|
25
|
+
await this.table.insert({
|
|
26
|
+
token_id,
|
|
27
|
+
city_id,
|
|
28
|
+
token_hash,
|
|
29
|
+
capabilities: JSON.stringify(capabilities),
|
|
30
|
+
status: "active",
|
|
31
|
+
created_at: now,
|
|
32
|
+
updated_at: now,
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
token_id,
|
|
36
|
+
city_id,
|
|
37
|
+
capabilities,
|
|
38
|
+
status: "active",
|
|
39
|
+
created_at: now,
|
|
40
|
+
updated_at: now,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** 验证 Bureau Token 并返回绑定身份。 */
|
|
44
|
+
async resolve(bureau_token) {
|
|
45
|
+
const token_id = read_token_id(bureau_token);
|
|
46
|
+
if (!token_id)
|
|
47
|
+
return undefined;
|
|
48
|
+
const record = (await this.table.select({ token_id }))[0];
|
|
49
|
+
if (!record || record.status !== "active")
|
|
50
|
+
return undefined;
|
|
51
|
+
if (record.token_hash !== await hash_token(bureau_token))
|
|
52
|
+
return undefined;
|
|
53
|
+
return {
|
|
54
|
+
token_id: record.token_id,
|
|
55
|
+
city_id: record.city_id,
|
|
56
|
+
capabilities: normalize_capabilities(JSON.parse(record.capabilities)),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** 列出 Bureau Token 元数据,不返回 token hash。 */
|
|
60
|
+
async list() {
|
|
61
|
+
return (await this.table.select()).map((record) => ({
|
|
62
|
+
token_id: record.token_id,
|
|
63
|
+
city_id: record.city_id,
|
|
64
|
+
capabilities: normalize_capabilities(JSON.parse(record.capabilities)),
|
|
65
|
+
status: record.status,
|
|
66
|
+
created_at: record.created_at,
|
|
67
|
+
updated_at: record.updated_at,
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
/** 立即撤销 Bureau Token。 */
|
|
71
|
+
async revoke(token_id) {
|
|
72
|
+
const id = read_required_string(token_id, "token_id");
|
|
73
|
+
if (!(await this.table.select({ token_id: id }))[0]) {
|
|
74
|
+
throw new TypeError(`Unknown Bureau token: ${id}`);
|
|
75
|
+
}
|
|
76
|
+
await this.table.update({
|
|
77
|
+
where: { token_id: id },
|
|
78
|
+
values: { status: "revoked", updated_at: new Date().toISOString() },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function read_token_id_value(value) {
|
|
83
|
+
const token_id = read_required_string(value, "token_id");
|
|
84
|
+
if (!/^br_[A-Za-z0-9_-]{16,}$/u.test(token_id)) {
|
|
85
|
+
throw new TypeError("token_id must use the br_<random> format");
|
|
86
|
+
}
|
|
87
|
+
return token_id;
|
|
88
|
+
}
|
|
89
|
+
function read_token_hash(value) {
|
|
90
|
+
const token_hash = read_required_string(value, "token_hash");
|
|
91
|
+
if (!/^[A-Za-z0-9_-]{43}$/u.test(token_hash)) {
|
|
92
|
+
throw new TypeError("token_hash must be a SHA-256 Base64URL value");
|
|
93
|
+
}
|
|
94
|
+
return token_hash;
|
|
95
|
+
}
|
|
96
|
+
function read_token_id(token) {
|
|
97
|
+
const match = String(token ?? "").trim().match(/^fb_(br_[A-Za-z0-9_-]+)\.[A-Za-z0-9_-]+$/u);
|
|
98
|
+
return match?.[1];
|
|
99
|
+
}
|
|
100
|
+
async function hash_token(token) {
|
|
101
|
+
const hash = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token));
|
|
102
|
+
return base64UrlEncodeBytes(new Uint8Array(hash));
|
|
103
|
+
}
|
|
104
|
+
function normalize_capabilities(input) {
|
|
105
|
+
const values = input ?? DEFAULT_CAPABILITIES;
|
|
106
|
+
const allowed = new Set(["accounts:read"]);
|
|
107
|
+
const result = [...new Set(values)];
|
|
108
|
+
if (result.length === 0)
|
|
109
|
+
throw new TypeError("Bureau Token requires at least one capability");
|
|
110
|
+
for (const capability of result) {
|
|
111
|
+
if (!allowed.has(capability))
|
|
112
|
+
throw new TypeError(`Unknown Bureau capability: ${capability}`);
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
function read_required_string(value, name) {
|
|
117
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
118
|
+
throw new TypeError(`${name} must be a non-empty string`);
|
|
119
|
+
}
|
|
120
|
+
return value.trim();
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=bureau-token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bureau-token-store.js","sourceRoot":"","sources":["../../../src/federation/auth/bureau-token-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federation Ed25519 Key Ring 存储模块。
|
|
3
|
+
*
|
|
4
|
+
* 该模块负责生成、持久化和读取 Federation 用户 token 签名密钥。
|
|
5
|
+
* 私钥只通过 get_active_signing_key() 返回给内部签发路径,JWKS 始终剥离私钥字段。
|
|
6
|
+
*/
|
|
7
|
+
import type { CityTableApi } from "../../store/table-api.js";
|
|
8
|
+
import type { FederationAuthKeyRecord, FederationJwks } from "./types.js";
|
|
9
|
+
/** 当前用户 token 使用的 JOSE 算法。 */
|
|
10
|
+
export declare const USER_TOKEN_ALGORITHM: "EdDSA";
|
|
11
|
+
/** Federation Key Ring 数据访问入口。 */
|
|
12
|
+
export declare class FederationKeyStore {
|
|
13
|
+
private readonly table;
|
|
14
|
+
constructor(table: CityTableApi<FederationAuthKeyRecord>);
|
|
15
|
+
/** 确保 Federation 至少存在一把 active signing key。 */
|
|
16
|
+
ensure_active_key(): Promise<FederationAuthKeyRecord>;
|
|
17
|
+
/** 读取当前唯一 active signing key。 */
|
|
18
|
+
get_active_key(): Promise<FederationAuthKeyRecord | undefined>;
|
|
19
|
+
/** 按 kid 读取可用于验签的密钥。 */
|
|
20
|
+
get_verification_key(key_id: string): Promise<FederationAuthKeyRecord | undefined>;
|
|
21
|
+
/** 返回只包含公开字段的 JWKS。 */
|
|
22
|
+
get_public_jwks(): Promise<FederationJwks>;
|
|
23
|
+
/** 生成并保存新的 active Ed25519 signing key。 */
|
|
24
|
+
private create_active_key;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=federation-key-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federation-key-store.d.ts","sourceRoot":"","sources":["../../../src/federation/auth/federation-key-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EACV,uBAAuB,EACvB,cAAc,EAEf,MAAM,YAAY,CAAC;AAEpB,8BAA8B;AAC9B,eAAO,MAAM,oBAAoB,EAAG,OAAgB,CAAC;AAErD,kCAAkC;AAClC,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,YAAY,CAAC,uBAAuB,CAAC;IAEzE,+CAA+C;IACzC,iBAAiB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAK3D,iCAAiC;IAC3B,cAAc,IAAI,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC;IAQpE,wBAAwB;IAClB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,GAAG,SAAS,CAAC;IAOxF,uBAAuB;IACjB,eAAe,IAAI,OAAO,CAAC,cAAc,CAAC;IAQhD,0CAA0C;YAC5B,iBAAiB;CAiChC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Federation Ed25519 Key Ring 存储模块。
|
|
3
|
+
*
|
|
4
|
+
* 该模块负责生成、持久化和读取 Federation 用户 token 签名密钥。
|
|
5
|
+
* 私钥只通过 get_active_signing_key() 返回给内部签发路径,JWKS 始终剥离私钥字段。
|
|
6
|
+
*/
|
|
7
|
+
import { exportJWK, generateKeyPair } from "jose";
|
|
8
|
+
import { randomSecret } from "../../utils/helpers.js";
|
|
9
|
+
/** 当前用户 token 使用的 JOSE 算法。 */
|
|
10
|
+
export const USER_TOKEN_ALGORITHM = "EdDSA";
|
|
11
|
+
/** Federation Key Ring 数据访问入口。 */
|
|
12
|
+
export class FederationKeyStore {
|
|
13
|
+
table;
|
|
14
|
+
constructor(table) {
|
|
15
|
+
this.table = table;
|
|
16
|
+
}
|
|
17
|
+
/** 确保 Federation 至少存在一把 active signing key。 */
|
|
18
|
+
async ensure_active_key() {
|
|
19
|
+
const active_key = await this.get_active_key();
|
|
20
|
+
return active_key ?? this.create_active_key();
|
|
21
|
+
}
|
|
22
|
+
/** 读取当前唯一 active signing key。 */
|
|
23
|
+
async get_active_key() {
|
|
24
|
+
const rows = await this.table.select({ status: "active" });
|
|
25
|
+
if (rows.length > 1) {
|
|
26
|
+
throw new Error("Federation must have exactly one active user token signing key");
|
|
27
|
+
}
|
|
28
|
+
return rows[0];
|
|
29
|
+
}
|
|
30
|
+
/** 按 kid 读取可用于验签的密钥。 */
|
|
31
|
+
async get_verification_key(key_id) {
|
|
32
|
+
const rows = await this.table.select({ key_id });
|
|
33
|
+
const key = rows[0];
|
|
34
|
+
if (!key || key.status === "revoked")
|
|
35
|
+
return undefined;
|
|
36
|
+
return key;
|
|
37
|
+
}
|
|
38
|
+
/** 返回只包含公开字段的 JWKS。 */
|
|
39
|
+
async get_public_jwks() {
|
|
40
|
+
const rows = await this.table.select();
|
|
41
|
+
const keys = rows
|
|
42
|
+
.filter((row) => row.status !== "revoked")
|
|
43
|
+
.map((row) => parse_public_jwk(row));
|
|
44
|
+
return { keys };
|
|
45
|
+
}
|
|
46
|
+
/** 生成并保存新的 active Ed25519 signing key。 */
|
|
47
|
+
async create_active_key() {
|
|
48
|
+
const existing = await this.get_active_key();
|
|
49
|
+
if (existing)
|
|
50
|
+
return existing;
|
|
51
|
+
const key_id = `key_${randomSecret(16)}`;
|
|
52
|
+
const key_pair = await generateKeyPair(USER_TOKEN_ALGORITHM, {
|
|
53
|
+
crv: "Ed25519",
|
|
54
|
+
extractable: true,
|
|
55
|
+
});
|
|
56
|
+
const public_jwk = await exportJWK(key_pair.publicKey);
|
|
57
|
+
const private_jwk = await exportJWK(key_pair.privateKey);
|
|
58
|
+
const record = {
|
|
59
|
+
key_id,
|
|
60
|
+
algorithm: USER_TOKEN_ALGORITHM,
|
|
61
|
+
public_jwk: JSON.stringify({
|
|
62
|
+
...public_jwk,
|
|
63
|
+
alg: USER_TOKEN_ALGORITHM,
|
|
64
|
+
use: "sig",
|
|
65
|
+
kid: key_id,
|
|
66
|
+
}),
|
|
67
|
+
private_jwk: JSON.stringify({
|
|
68
|
+
...private_jwk,
|
|
69
|
+
alg: USER_TOKEN_ALGORITHM,
|
|
70
|
+
use: "sig",
|
|
71
|
+
kid: key_id,
|
|
72
|
+
}),
|
|
73
|
+
status: "active",
|
|
74
|
+
created_at: new Date().toISOString(),
|
|
75
|
+
retired_at: "",
|
|
76
|
+
};
|
|
77
|
+
await this.table.insert(record);
|
|
78
|
+
return record;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** 将数据库 JSON 转成严格的公开 Ed25519 JWK。 */
|
|
82
|
+
function parse_public_jwk(record) {
|
|
83
|
+
const value = JSON.parse(record.public_jwk);
|
|
84
|
+
if (value.kty !== "OKP" || value.crv !== "Ed25519" || typeof value.x !== "string" || !value.x) {
|
|
85
|
+
throw new Error(`Invalid Federation public JWK: ${record.key_id}`);
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
kty: "OKP",
|
|
89
|
+
crv: "Ed25519",
|
|
90
|
+
alg: USER_TOKEN_ALGORITHM,
|
|
91
|
+
use: "sig",
|
|
92
|
+
kid: record.key_id,
|
|
93
|
+
x: value.x,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=federation-key-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"federation-key-store.js","sourceRoot":"","sources":["../../../src/federation/auth/federation-key-store.ts"],"names":[],"mappings":"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"}
|