@sebastienrousseau/crypto-server 0.0.9 → 0.0.24
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/config/auth-policy.d.ts.map +1 -1
- package/dist/config/auth-policy.js +18 -1
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +7 -1
- package/dist/lib/key-store.d.ts +8 -1
- package/dist/lib/key-store.d.ts.map +1 -1
- package/dist/lib/key-store.js +102 -5
- package/dist/lib/opaque-store.d.ts +34 -0
- package/dist/lib/opaque-store.d.ts.map +1 -0
- package/dist/lib/opaque-store.js +72 -0
- package/dist/lib/problem.d.ts +1 -0
- package/dist/lib/problem.d.ts.map +1 -1
- package/dist/lib/problem.js +10 -0
- package/dist/routes/v1/decrypt.d.ts.map +1 -1
- package/dist/routes/v1/decrypt.js +4 -1
- package/dist/routes/v1/verify.d.ts.map +1 -1
- package/dist/routes/v1/verify.js +4 -1
- package/dist/routes/v2/hpke.d.ts +3 -0
- package/dist/routes/v2/hpke.d.ts.map +1 -0
- package/dist/routes/v2/hpke.js +168 -0
- package/dist/routes/v2/index.d.ts.map +1 -1
- package/dist/routes/v2/index.js +6 -0
- package/dist/routes/v2/kms.d.ts +7 -0
- package/dist/routes/v2/kms.d.ts.map +1 -0
- package/dist/routes/v2/kms.js +310 -0
- package/dist/routes/v2/mac.d.ts.map +1 -1
- package/dist/routes/v2/mac.js +1 -0
- package/dist/routes/v2/opaque.d.ts +4 -0
- package/dist/routes/v2/opaque.d.ts.map +1 -0
- package/dist/routes/v2/opaque.js +174 -0
- package/dist/routes/v2/pq-hash-sign.d.ts.map +1 -1
- package/dist/routes/v2/pq-hash-sign.js +3 -0
- package/dist/routes/v2/pq-sign.d.ts.map +1 -1
- package/dist/routes/v2/pq-sign.js +1 -0
- package/dist/routes/v2/signing.d.ts.map +1 -1
- package/dist/routes/v2/signing.js +1 -0
- package/dist/routes/v2/stream-schemas.d.ts +296 -0
- package/dist/routes/v2/stream-schemas.d.ts.map +1 -0
- package/dist/routes/v2/stream-schemas.js +207 -0
- package/dist/routes/v2/stream.d.ts.map +1 -1
- package/dist/routes/v2/stream.js +117 -129
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +4 -0
- package/dist/utils/trace.d.ts +12 -0
- package/dist/utils/trace.d.ts.map +1 -0
- package/dist/utils/trace.js +62 -0
- package/package.json +4 -3
package/dist/routes/v2/stream.js
CHANGED
|
@@ -1,135 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const crypto_lib_1 = require("@sebastienrousseau/crypto-lib");
|
|
4
|
+
const streaming_1 = require("@sebastienrousseau/crypto-lib/streaming");
|
|
4
5
|
const protocols_1 = require("@sebastienrousseau/crypto-lib/protocols");
|
|
5
6
|
const route_helpers_1 = require("../../utils/route-helpers");
|
|
6
7
|
const keys_1 = require("../../utils/keys");
|
|
7
|
-
const
|
|
8
|
-
tags: ["Streaming"],
|
|
9
|
-
summary: "Batch sign messages with sub-millisecond throughput",
|
|
10
|
-
description: "Process high-throughput batch digital signing operations over multiple payloads.",
|
|
11
|
-
body: {
|
|
12
|
-
type: "object",
|
|
13
|
-
required: ["items"],
|
|
14
|
-
additionalProperties: false,
|
|
15
|
-
properties: {
|
|
16
|
-
items: {
|
|
17
|
-
type: "array",
|
|
18
|
-
minItems: 1,
|
|
19
|
-
maxItems: 1000,
|
|
20
|
-
items: {
|
|
21
|
-
type: "object",
|
|
22
|
-
required: ["id", "message", "keyId"],
|
|
23
|
-
additionalProperties: false,
|
|
24
|
-
properties: {
|
|
25
|
-
id: { type: "string" },
|
|
26
|
-
message: { type: "string", minLength: 1 },
|
|
27
|
-
keyId: keys_1.KEY_ID_SCHEMA,
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
const VERIFY_SCHEMA = {
|
|
35
|
-
tags: ["Streaming"],
|
|
36
|
-
summary: "Batch verify digital signatures",
|
|
37
|
-
description: "Batch verification pipeline for high-concurrency payment and transaction verification.",
|
|
38
|
-
body: {
|
|
39
|
-
type: "object",
|
|
40
|
-
required: ["items"],
|
|
41
|
-
additionalProperties: false,
|
|
42
|
-
properties: {
|
|
43
|
-
items: {
|
|
44
|
-
type: "array",
|
|
45
|
-
minItems: 1,
|
|
46
|
-
maxItems: 1000,
|
|
47
|
-
items: {
|
|
48
|
-
type: "object",
|
|
49
|
-
required: ["id", "message", "signature", "publicKey"],
|
|
50
|
-
additionalProperties: false,
|
|
51
|
-
properties: {
|
|
52
|
-
id: { type: "string" },
|
|
53
|
-
message: { type: "string", minLength: 1 },
|
|
54
|
-
signature: { type: "string", minLength: 1 },
|
|
55
|
-
publicKey: { type: "string", minLength: 64, maxLength: 64 },
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
},
|
|
61
|
-
};
|
|
62
|
-
const ISO20022_SCHEMA = {
|
|
63
|
-
tags: ["Wholesale Payments"],
|
|
64
|
-
summary: "Verify ISO 20022 post-quantum dual-signature envelope",
|
|
65
|
-
description: "Validates the payload digest and both the Ed25519 and ML-DSA signatures of a pacs.008, pain.001 or camt.053 envelope. Signatures are checked against trustedKeys, the signer's public keys from the caller's own registry; the public keys inside the envelope are ignored.",
|
|
66
|
-
body: {
|
|
67
|
-
type: "object",
|
|
68
|
-
required: ["envelope", "payload", "trustedKeys"],
|
|
69
|
-
additionalProperties: false,
|
|
70
|
-
properties: {
|
|
71
|
-
trustedKeys: {
|
|
72
|
-
type: "object",
|
|
73
|
-
required: ["classicalPublicKey", "postQuantumPublicKey"],
|
|
74
|
-
additionalProperties: false,
|
|
75
|
-
properties: {
|
|
76
|
-
classicalPublicKey: { type: "string", minLength: 1 },
|
|
77
|
-
postQuantumPublicKey: { type: "string", minLength: 1 },
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
envelope: {
|
|
81
|
-
type: "object",
|
|
82
|
-
required: [
|
|
83
|
-
"messageId",
|
|
84
|
-
"messageType",
|
|
85
|
-
"payloadDigest",
|
|
86
|
-
"digestAlgorithm",
|
|
87
|
-
"timestamp",
|
|
88
|
-
"classical",
|
|
89
|
-
"postQuantum",
|
|
90
|
-
],
|
|
91
|
-
additionalProperties: false,
|
|
92
|
-
properties: {
|
|
93
|
-
messageId: { type: "string" },
|
|
94
|
-
messageType: {
|
|
95
|
-
type: "string",
|
|
96
|
-
enum: ["pacs.008", "pain.001", "camt.053", "generic"],
|
|
97
|
-
},
|
|
98
|
-
payloadDigest: { type: "string" },
|
|
99
|
-
digestAlgorithm: {
|
|
100
|
-
type: "string",
|
|
101
|
-
enum: ["sha256", "sha384", "sha512"],
|
|
102
|
-
},
|
|
103
|
-
timestamp: { type: "string" },
|
|
104
|
-
classical: {
|
|
105
|
-
type: "object",
|
|
106
|
-
required: ["algorithm", "signature", "publicKey"],
|
|
107
|
-
additionalProperties: false,
|
|
108
|
-
properties: {
|
|
109
|
-
algorithm: { type: "string" },
|
|
110
|
-
signature: { type: "string" },
|
|
111
|
-
publicKey: { type: "string" },
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
postQuantum: {
|
|
115
|
-
type: "object",
|
|
116
|
-
required: ["algorithm", "signature", "publicKey"],
|
|
117
|
-
additionalProperties: false,
|
|
118
|
-
properties: {
|
|
119
|
-
algorithm: {
|
|
120
|
-
type: "string",
|
|
121
|
-
enum: ["ml-dsa-44", "ml-dsa-65", "ml-dsa-87"],
|
|
122
|
-
},
|
|
123
|
-
signature: { type: "string" },
|
|
124
|
-
publicKey: { type: "string" },
|
|
125
|
-
},
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
payload: {},
|
|
130
|
-
},
|
|
131
|
-
},
|
|
132
|
-
};
|
|
8
|
+
const stream_schemas_1 = require("./stream-schemas");
|
|
133
9
|
async function resolveBatchKeys(request, items) {
|
|
134
10
|
const keys = new Map();
|
|
135
11
|
for (const keyId of new Set(items.map((i) => i.keyId))) {
|
|
@@ -138,7 +14,7 @@ async function resolveBatchKeys(request, items) {
|
|
|
138
14
|
return keys;
|
|
139
15
|
}
|
|
140
16
|
function registerBatchSign(app) {
|
|
141
|
-
app.post("/v2/stream/sign", { schema: SIGN_SCHEMA }, async (request, reply) => {
|
|
17
|
+
app.post("/v2/stream/sign", { schema: stream_schemas_1.SIGN_SCHEMA }, async (request, reply) => {
|
|
142
18
|
const { items } = request.body;
|
|
143
19
|
const keys = await resolveBatchKeys(request, items);
|
|
144
20
|
const signatures = items.map((item) => {
|
|
@@ -159,7 +35,10 @@ function registerBatchSign(app) {
|
|
|
159
35
|
});
|
|
160
36
|
}
|
|
161
37
|
function registerBatchVerify(app) {
|
|
162
|
-
app.post("/v2/stream/verify", {
|
|
38
|
+
app.post("/v2/stream/verify", {
|
|
39
|
+
schema: stream_schemas_1.VERIFY_SCHEMA,
|
|
40
|
+
config: { rateLimit: { max: 100, timeWindow: "1 minute" } },
|
|
41
|
+
}, async (request, reply) => {
|
|
163
42
|
try {
|
|
164
43
|
const { items } = request.body;
|
|
165
44
|
let validCount = 0;
|
|
@@ -189,7 +68,10 @@ function registerBatchVerify(app) {
|
|
|
189
68
|
});
|
|
190
69
|
}
|
|
191
70
|
function registerIso20022Verify(app) {
|
|
192
|
-
app.post("/v2/stream/iso20022", {
|
|
71
|
+
app.post("/v2/stream/iso20022", {
|
|
72
|
+
schema: stream_schemas_1.ISO20022_SCHEMA,
|
|
73
|
+
config: { rateLimit: { max: 100, timeWindow: "1 minute" } },
|
|
74
|
+
}, async (request, reply) => {
|
|
193
75
|
try {
|
|
194
76
|
const { envelope, payload, trustedKeys } = request.body;
|
|
195
77
|
const result = (0, protocols_1.verifyIso20022Payment)(envelope, payload, {
|
|
@@ -203,9 +85,115 @@ function registerIso20022Verify(app) {
|
|
|
203
85
|
}
|
|
204
86
|
});
|
|
205
87
|
}
|
|
88
|
+
function registerStreamPqEncrypt(app) {
|
|
89
|
+
app.post("/v2/stream/pq-encrypt", { schema: stream_schemas_1.STREAM_PQ_ENCRYPT_SCHEMA }, async (request, reply) => {
|
|
90
|
+
try {
|
|
91
|
+
const { x25519PublicKey, mlKemPublicKey, plaintext, chunkSize } = request.body;
|
|
92
|
+
const ptBytes = Buffer.from(plaintext, "utf8");
|
|
93
|
+
const res = (0, streaming_1.streamPqEncrypt)({
|
|
94
|
+
recipientX25519Public: x25519PublicKey,
|
|
95
|
+
recipientMlKemPublic: mlKemPublicKey,
|
|
96
|
+
plaintext: ptBytes,
|
|
97
|
+
...(chunkSize !== undefined ? { chunkSize } : {}),
|
|
98
|
+
});
|
|
99
|
+
return reply.send({
|
|
100
|
+
data: {
|
|
101
|
+
ciphertext: Buffer.from(res.ciphertext).toString("base64"),
|
|
102
|
+
algorithm: res.algorithm,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "PQ stream encryption");
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function registerStreamPqDecrypt(app) {
|
|
112
|
+
app.post("/v2/stream/pq-decrypt", { schema: stream_schemas_1.STREAM_PQ_DECRYPT_SCHEMA }, async (request, reply) => {
|
|
113
|
+
const { keyId, ciphertext, chunkSize } = request.body;
|
|
114
|
+
const key = await (0, keys_1.resolveKey)(request, keyId, ["x25519-ml-kem-768"]);
|
|
115
|
+
try {
|
|
116
|
+
const ctBytes = Buffer.from(ciphertext, "base64");
|
|
117
|
+
const decrypted = (0, streaming_1.streamPqDecrypt)({
|
|
118
|
+
recipientX25519Secret: key.privateParts["x25519PrivateKey"],
|
|
119
|
+
recipientMlKemSecret: key.privateParts["mlKemSecretKey"],
|
|
120
|
+
ciphertext: ctBytes,
|
|
121
|
+
...(chunkSize !== undefined ? { chunkSize } : {}),
|
|
122
|
+
});
|
|
123
|
+
const plaintext = Buffer.from(decrypted).toString("utf8");
|
|
124
|
+
(0, crypto_lib_1.wipeMemory)(decrypted);
|
|
125
|
+
return reply.send({ data: { plaintext } });
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "PQ stream decryption");
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function registerStreamMultiPqEncrypt(app) {
|
|
133
|
+
app.post("/v2/stream/multi-pq-encrypt", { schema: stream_schemas_1.STREAM_MULTI_PQ_ENCRYPT_SCHEMA }, async (request, reply) => {
|
|
134
|
+
try {
|
|
135
|
+
const { recipients, plaintext, chunkSize } = request.body;
|
|
136
|
+
const ptBytes = Buffer.from(plaintext, "utf8");
|
|
137
|
+
const res = (0, streaming_1.streamMultiPqEncrypt)({
|
|
138
|
+
recipients: recipients.map((r) => ({
|
|
139
|
+
recipientId: r.recipientId,
|
|
140
|
+
recipientX25519Public: r.x25519PublicKey,
|
|
141
|
+
recipientMlKemPublic: r.mlKemPublicKey,
|
|
142
|
+
})),
|
|
143
|
+
plaintext: ptBytes,
|
|
144
|
+
...(chunkSize !== undefined ? { chunkSize } : {}),
|
|
145
|
+
});
|
|
146
|
+
(0, crypto_lib_1.wipeMemory)(ptBytes);
|
|
147
|
+
return reply.send({
|
|
148
|
+
data: {
|
|
149
|
+
ciphertext: Buffer.from(res.ciphertext).toString("base64"),
|
|
150
|
+
algorithm: res.algorithm,
|
|
151
|
+
recipientCount: res.recipientCount,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Multi-PQ stream encryption");
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function registerStreamMultiPqDecrypt(app) {
|
|
161
|
+
app.post("/v2/stream/multi-pq-decrypt", {
|
|
162
|
+
schema: stream_schemas_1.STREAM_MULTI_PQ_DECRYPT_SCHEMA,
|
|
163
|
+
config: { rateLimit: { max: 100, timeWindow: "1 minute" } },
|
|
164
|
+
}, async (request, reply) => {
|
|
165
|
+
const { keyId, recipientId, ciphertext, chunkSize } = request.body;
|
|
166
|
+
const key = await (0, keys_1.resolveKey)(request, keyId, ["x25519-ml-kem-768"]);
|
|
167
|
+
try {
|
|
168
|
+
const ctBytes = Buffer.from(ciphertext, "base64");
|
|
169
|
+
const decrypted = (0, streaming_1.streamMultiPqDecrypt)({
|
|
170
|
+
...(recipientId !== undefined ? { recipientId } : {}),
|
|
171
|
+
recipientX25519Secret: key.privateParts["x25519PrivateKey"],
|
|
172
|
+
recipientMlKemSecret: key.privateParts["mlKemSecretKey"],
|
|
173
|
+
ciphertext: ctBytes,
|
|
174
|
+
...(chunkSize !== undefined ? { chunkSize } : {}),
|
|
175
|
+
});
|
|
176
|
+
const plaintext = Buffer.from(decrypted.plaintext).toString("utf8");
|
|
177
|
+
(0, crypto_lib_1.wipeMemory)(decrypted.plaintext);
|
|
178
|
+
return reply.send({
|
|
179
|
+
data: {
|
|
180
|
+
plaintext,
|
|
181
|
+
recipientId: decrypted.recipientId,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
return (0, route_helpers_1.classifyCryptoError)(error, request, reply, "Multi-PQ stream decryption");
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
}
|
|
206
190
|
exports.default = (app) => {
|
|
207
191
|
registerBatchSign(app);
|
|
208
192
|
registerBatchVerify(app);
|
|
209
193
|
registerIso20022Verify(app);
|
|
194
|
+
registerStreamPqEncrypt(app);
|
|
195
|
+
registerStreamPqDecrypt(app);
|
|
196
|
+
registerStreamMultiPqEncrypt(app);
|
|
197
|
+
registerStreamMultiPqDecrypt(app);
|
|
210
198
|
};
|
|
211
199
|
//# sourceMappingURL=stream.js.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA6CA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAuCnC,iBAAe,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAgFtD;AAED,OAAO,EAAE,IAAI,EAAE,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -55,6 +55,8 @@ const metering_1 = require("./enterprise/metering");
|
|
|
55
55
|
const key_store_1 = require("./lib/key-store");
|
|
56
56
|
const kdf_runner_1 = require("./lib/kdf-runner");
|
|
57
57
|
const problem_1 = require("./lib/problem");
|
|
58
|
+
const trace_1 = require("./utils/trace");
|
|
59
|
+
const opaque_store_1 = require("./lib/opaque-store");
|
|
58
60
|
const routes_1 = __importDefault(require("./routes"));
|
|
59
61
|
const fastify = __importStar(require("fastify"));
|
|
60
62
|
async function registerDocs(app) {
|
|
@@ -92,6 +94,7 @@ async function init() {
|
|
|
92
94
|
app.addHook("onRequest", async (request, reply) => {
|
|
93
95
|
const reqId = request.headers["x-request-id"] ?? (0, crypto_1.randomUUID)();
|
|
94
96
|
reply.header("x-request-id", reqId);
|
|
97
|
+
(0, trace_1.propagateTraceContext)(request, reply);
|
|
95
98
|
});
|
|
96
99
|
app.addHook("onSend", async (request, reply) => {
|
|
97
100
|
if (request.url.startsWith("/v2/")) {
|
|
@@ -122,6 +125,7 @@ async function init() {
|
|
|
122
125
|
});
|
|
123
126
|
app.decorate("keyStore", (0, key_store_1.keyStoreFromEnv)());
|
|
124
127
|
app.decorate("kdf", new kdf_runner_1.KdfRunner());
|
|
128
|
+
app.decorate("opaqueStore", new opaque_store_1.OpaqueStore());
|
|
125
129
|
app.addHook("onClose", () => app.kdf.close());
|
|
126
130
|
(0, metering_1.registerMetering)(app);
|
|
127
131
|
await app.register(async (scope) => {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FastifyReply, FastifyRequest } from "fastify";
|
|
2
|
+
export interface TraceparentComponents {
|
|
3
|
+
version: string;
|
|
4
|
+
traceId: string;
|
|
5
|
+
parentId: string;
|
|
6
|
+
flags: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function isValidTraceparent(header: unknown): header is string;
|
|
9
|
+
export declare function parseTraceparent(header: string): TraceparentComponents | null;
|
|
10
|
+
export declare function generateTraceparent(sampled?: boolean): string;
|
|
11
|
+
export declare function propagateTraceContext(request: FastifyRequest, reply: FastifyReply): void;
|
|
12
|
+
//# sourceMappingURL=trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/utils/trace.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAa5D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAQD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI,MAAM,CAUpE;AAQD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAS7E;AAQD,wBAAgB,mBAAmB,CAAC,OAAO,UAAO,GAAG,MAAM,CAK1D;AASD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,GAClB,IAAI,CAqBN"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isValidTraceparent = isValidTraceparent;
|
|
4
|
+
exports.parseTraceparent = parseTraceparent;
|
|
5
|
+
exports.generateTraceparent = generateTraceparent;
|
|
6
|
+
exports.propagateTraceContext = propagateTraceContext;
|
|
7
|
+
const crypto_1 = require("crypto");
|
|
8
|
+
const TRACEPARENT_REGEX = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/;
|
|
9
|
+
const ALL_ZERO_TRACE_ID = "0".repeat(32);
|
|
10
|
+
const ALL_ZERO_PARENT_ID = "0".repeat(16);
|
|
11
|
+
function isValidTraceparent(header) {
|
|
12
|
+
if (typeof header !== "string")
|
|
13
|
+
return false;
|
|
14
|
+
const match = TRACEPARENT_REGEX.exec(header.trim());
|
|
15
|
+
if (!match)
|
|
16
|
+
return false;
|
|
17
|
+
const traceId = match[1];
|
|
18
|
+
const parentId = match[2];
|
|
19
|
+
if (traceId === ALL_ZERO_TRACE_ID || parentId === ALL_ZERO_PARENT_ID) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
function parseTraceparent(header) {
|
|
25
|
+
if (!isValidTraceparent(header))
|
|
26
|
+
return null;
|
|
27
|
+
const match = TRACEPARENT_REGEX.exec(header.trim());
|
|
28
|
+
return {
|
|
29
|
+
version: "00",
|
|
30
|
+
traceId: match[1],
|
|
31
|
+
parentId: match[2],
|
|
32
|
+
flags: match[3],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function generateTraceparent(sampled = true) {
|
|
36
|
+
const traceId = (0, crypto_1.randomBytes)(16).toString("hex");
|
|
37
|
+
const parentId = (0, crypto_1.randomBytes)(8).toString("hex");
|
|
38
|
+
const flags = sampled ? "01" : "00";
|
|
39
|
+
return `00-${traceId}-${parentId}-${flags}`;
|
|
40
|
+
}
|
|
41
|
+
function propagateTraceContext(request, reply) {
|
|
42
|
+
const incoming = request.headers["traceparent"];
|
|
43
|
+
let traceparentValue;
|
|
44
|
+
if (isValidTraceparent(incoming)) {
|
|
45
|
+
traceparentValue = incoming.trim();
|
|
46
|
+
const tracestate = request.headers["tracestate"];
|
|
47
|
+
if (typeof tracestate === "string" && tracestate.trim().length > 0) {
|
|
48
|
+
reply.header("tracestate", tracestate.trim());
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
traceparentValue = generateTraceparent();
|
|
53
|
+
}
|
|
54
|
+
reply.header("traceparent", traceparentValue);
|
|
55
|
+
const parsed = parseTraceparent(traceparentValue);
|
|
56
|
+
if (parsed) {
|
|
57
|
+
request.traceId = parsed.traceId;
|
|
58
|
+
}
|
|
59
|
+
request.traceparent =
|
|
60
|
+
traceparentValue;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=trace.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sebastienrousseau/crypto-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "Crypto Server is a Fastify web server that exposes easy consumable REST APIs to perform low-level cryptographic operations.",
|
|
5
5
|
"author": "Sebastien Rousseau <sebastienrousseau@users.noreply.github.com>",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
@@ -60,7 +60,8 @@
|
|
|
60
60
|
"fastify-healthcheck": "^5.1.0",
|
|
61
61
|
"uuid": "^14.0.2",
|
|
62
62
|
"winston": "^3.17.0",
|
|
63
|
-
"@sebastienrousseau/crypto-
|
|
63
|
+
"@sebastienrousseau/crypto-kms": "0.0.24",
|
|
64
|
+
"@sebastienrousseau/crypto-lib": "0.0.24"
|
|
64
65
|
},
|
|
65
66
|
"devDependencies": {
|
|
66
67
|
"@types/chai": "^5.2.3",
|
|
@@ -73,7 +74,7 @@
|
|
|
73
74
|
"chai-as-promised": "^8.0.2",
|
|
74
75
|
"fast-check": "^4.10.2",
|
|
75
76
|
"mocha": "^12.0.3",
|
|
76
|
-
"openpgp": "^6.3.
|
|
77
|
+
"openpgp": "^6.3.2",
|
|
77
78
|
"prettier": "^3.9.9",
|
|
78
79
|
"rimraf": "^6.1.3",
|
|
79
80
|
"ts-node": "^10.9.2",
|