@sebastienrousseau/crypto-server 0.0.1 → 0.0.8
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 +292 -123
- package/dist/@types/types.d.ts +34 -14
- package/dist/@types/types.d.ts.map +1 -1
- package/dist/@types/types.js +15 -0
- package/dist/config/auth-policy.d.ts +2 -0
- package/dist/config/auth-policy.d.ts.map +1 -0
- package/dist/config/auth-policy.js +18 -0
- package/dist/config/constants.d.ts +54 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +101 -0
- package/dist/config/env.d.ts +16 -0
- package/dist/config/env.d.ts.map +1 -0
- package/dist/config/env.js +74 -0
- package/dist/enterprise/metering.d.ts +19 -0
- package/dist/enterprise/metering.d.ts.map +1 -0
- package/dist/enterprise/metering.js +159 -0
- package/dist/enterprise/types.d.ts +78 -0
- package/dist/enterprise/types.d.ts.map +1 -0
- package/dist/enterprise/types.js +3 -0
- package/dist/index.js +38 -74
- package/dist/lib/auth.d.ts +14 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +120 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +6 -5
- package/dist/lib/telemetry.d.ts +4 -0
- package/dist/lib/telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry.js +92 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +7 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +19 -4
- package/dist/routes/probes.d.ts +4 -0
- package/dist/routes/probes.d.ts.map +1 -0
- package/dist/routes/probes.js +52 -0
- package/dist/routes/v1/decrypt.d.ts +2 -2
- package/dist/routes/v1/decrypt.d.ts.map +1 -1
- package/dist/routes/v1/decrypt.js +49 -6
- package/dist/routes/v1/encrypt.d.ts +2 -2
- package/dist/routes/v1/encrypt.d.ts.map +1 -1
- package/dist/routes/v1/encrypt.js +48 -6
- package/dist/routes/v1/generate.d.ts +2 -2
- package/dist/routes/v1/generate.d.ts.map +1 -1
- package/dist/routes/v1/generate.js +85 -13
- package/dist/routes/v1/index.d.ts +4 -0
- package/dist/routes/v1/index.d.ts.map +1 -0
- package/dist/routes/v1/index.js +19 -0
- package/dist/routes/v1/revoke.d.ts +2 -2
- package/dist/routes/v1/revoke.d.ts.map +1 -1
- package/dist/routes/v1/revoke.js +57 -5
- package/dist/routes/v1/verify.d.ts +4 -0
- package/dist/routes/v1/verify.d.ts.map +1 -0
- package/dist/routes/v1/verify.js +60 -0
- package/dist/routes/v2/algorithms.d.ts +4 -0
- package/dist/routes/v2/algorithms.d.ts.map +1 -0
- package/dist/routes/v2/algorithms.js +15 -0
- package/dist/routes/v2/compliance.d.ts +31 -0
- package/dist/routes/v2/compliance.d.ts.map +1 -0
- package/dist/routes/v2/compliance.js +223 -0
- package/dist/routes/v2/encrypt.d.ts +4 -0
- package/dist/routes/v2/encrypt.d.ts.map +1 -0
- package/dist/routes/v2/encrypt.js +62 -0
- package/dist/routes/v2/hash.d.ts +4 -0
- package/dist/routes/v2/hash.d.ts.map +1 -0
- package/dist/routes/v2/hash.js +34 -0
- package/dist/routes/v2/index.d.ts +4 -0
- package/dist/routes/v2/index.d.ts.map +1 -0
- package/dist/routes/v2/index.js +44 -0
- package/dist/routes/v2/kdf.d.ts +4 -0
- package/dist/routes/v2/kdf.d.ts.map +1 -0
- package/dist/routes/v2/kdf.js +54 -0
- package/dist/routes/v2/key-wrap.d.ts +4 -0
- package/dist/routes/v2/key-wrap.d.ts.map +1 -0
- package/dist/routes/v2/key-wrap.js +97 -0
- package/dist/routes/v2/keys.d.ts +4 -0
- package/dist/routes/v2/keys.d.ts.map +1 -0
- package/dist/routes/v2/keys.js +88 -0
- package/dist/routes/v2/mac.d.ts +4 -0
- package/dist/routes/v2/mac.d.ts.map +1 -0
- package/dist/routes/v2/mac.js +102 -0
- package/dist/routes/v2/multi-recipient.d.ts +4 -0
- package/dist/routes/v2/multi-recipient.d.ts.map +1 -0
- package/dist/routes/v2/multi-recipient.js +88 -0
- package/dist/routes/v2/password-encrypt.d.ts +4 -0
- package/dist/routes/v2/password-encrypt.d.ts.map +1 -0
- package/dist/routes/v2/password-encrypt.js +92 -0
- package/dist/routes/v2/password.d.ts +4 -0
- package/dist/routes/v2/password.d.ts.map +1 -0
- package/dist/routes/v2/password.js +109 -0
- package/dist/routes/v2/pq-hash-sign.d.ts +4 -0
- package/dist/routes/v2/pq-hash-sign.d.ts.map +1 -0
- package/dist/routes/v2/pq-hash-sign.js +131 -0
- package/dist/routes/v2/pq-sign.d.ts +4 -0
- package/dist/routes/v2/pq-sign.d.ts.map +1 -0
- package/dist/routes/v2/pq-sign.js +117 -0
- package/dist/routes/v2/pq.d.ts +4 -0
- package/dist/routes/v2/pq.d.ts.map +1 -0
- package/dist/routes/v2/pq.js +149 -0
- package/dist/routes/v2/sealedbox.d.ts +4 -0
- package/dist/routes/v2/sealedbox.d.ts.map +1 -0
- package/dist/routes/v2/sealedbox.js +145 -0
- package/dist/routes/v2/secretbox.d.ts +4 -0
- package/dist/routes/v2/secretbox.d.ts.map +1 -0
- package/dist/routes/v2/secretbox.js +94 -0
- package/dist/routes/v2/signing.d.ts +4 -0
- package/dist/routes/v2/signing.d.ts.map +1 -0
- package/dist/routes/v2/signing.js +66 -0
- package/dist/routes/v2/stream.d.ts +4 -0
- package/dist/routes/v2/stream.d.ts.map +1 -0
- package/dist/routes/v2/stream.js +206 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +124 -0
- package/dist/utils/route-helpers.d.ts +15 -0
- package/dist/utils/route-helpers.d.ts.map +1 -0
- package/dist/utils/route-helpers.js +42 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +162 -0
- package/package.json +103 -140
- package/dist/@types/types.js.map +0 -1
- package/dist/COPYRIGHT +0 -14
- package/dist/Report.txt +0 -90
- package/dist/config/endpoints.config.d.ts +0 -7
- package/dist/config/endpoints.config.d.ts.map +0 -1
- package/dist/config/endpoints.config.js +0 -8
- package/dist/config/endpoints.config.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/logger.js.map +0 -1
- package/dist/package.json +0 -141
- package/dist/routes/index.js.map +0 -1
- package/dist/routes/v1/decrypt.js.map +0 -1
- package/dist/routes/v1/encrypt.js.map +0 -1
- package/dist/routes/v1/generate.js.map +0 -1
- package/dist/routes/v1/revoke.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAO7E,eAAO,MAAM,MAAM,2IAST,CAAC;AAGX,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAG5C,MAAM,WAAW,WAAW;IAE1B,GAAG,EAAE,MAAM,CAAC;IAEZ,MAAM,EAAE,KAAK,EAAE,CAAC;IAEhB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD,wBAAsB,YAAY,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAYtE;AAUD,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAqD7B;AAKD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,GAAG,OAAO,CAIvE;AAKD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,YAAY,GAClB,OAAO,CAST"}
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SCOPES = void 0;
|
|
37
|
+
exports.registerAuth = registerAuth;
|
|
38
|
+
exports.authenticate = authenticate;
|
|
39
|
+
exports.hasScope = hasScope;
|
|
40
|
+
exports.requireScope = requireScope;
|
|
41
|
+
const crypto_1 = require("crypto");
|
|
42
|
+
const validation_1 = require("../utils/validation");
|
|
43
|
+
exports.SCOPES = [
|
|
44
|
+
"crypto:encrypt",
|
|
45
|
+
"crypto:decrypt",
|
|
46
|
+
"crypto:sign",
|
|
47
|
+
"crypto:verify",
|
|
48
|
+
"crypto:hash",
|
|
49
|
+
"crypto:kdf",
|
|
50
|
+
"crypto:keys",
|
|
51
|
+
"crypto:admin",
|
|
52
|
+
];
|
|
53
|
+
async function registerAuth(app) {
|
|
54
|
+
const jwtSecret = process.env["JWT_SECRET"];
|
|
55
|
+
if (jwtSecret) {
|
|
56
|
+
const fastifyJwt = await Promise.resolve().then(() => __importStar(require("@fastify/jwt")));
|
|
57
|
+
await app.register(fastifyJwt.default, {
|
|
58
|
+
secret: jwtSecret,
|
|
59
|
+
verify: { algorithms: ["HS256"] },
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function authenticate(request, reply) {
|
|
64
|
+
const jwtSecret = process.env["JWT_SECRET"];
|
|
65
|
+
const apiKey = process.env["CRYPTO_API_KEY"];
|
|
66
|
+
if (!jwtSecret && !apiKey) {
|
|
67
|
+
if ((0, validation_1.anonymousAllowed)()) {
|
|
68
|
+
return { sub: "anonymous", scopes: ["crypto:admin"] };
|
|
69
|
+
}
|
|
70
|
+
reply
|
|
71
|
+
.status(401)
|
|
72
|
+
.send({ error: "Unauthorized: authentication is not configured" });
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const authHeader = request.headers["authorization"];
|
|
76
|
+
if (authHeader?.startsWith("Bearer ") && jwtSecret) {
|
|
77
|
+
try {
|
|
78
|
+
const decoded = await request.jwtVerify();
|
|
79
|
+
return decoded;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
reply.status(401).send({ error: "Invalid or expired JWT token" });
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (apiKey) {
|
|
87
|
+
const providedKey = request.headers["x-api-key"];
|
|
88
|
+
if (!providedKey || typeof providedKey !== "string") {
|
|
89
|
+
reply
|
|
90
|
+
.status(401)
|
|
91
|
+
.send({ error: "Unauthorized: Missing API key or Bearer token" });
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const a = Buffer.from(providedKey);
|
|
95
|
+
const b = Buffer.from(apiKey);
|
|
96
|
+
if (a.length !== b.length || !(0, crypto_1.timingSafeEqual)(a, b)) {
|
|
97
|
+
reply.status(401).send({ error: "Unauthorized: Invalid API key" });
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
return { sub: "api-key", scopes: ["crypto:admin"] };
|
|
101
|
+
}
|
|
102
|
+
reply
|
|
103
|
+
.status(401)
|
|
104
|
+
.send({ error: "Unauthorized: No valid credentials provided" });
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function hasScope(payload, required) {
|
|
108
|
+
return (payload.scopes.includes("crypto:admin") || payload.scopes.includes(required));
|
|
109
|
+
}
|
|
110
|
+
function requireScope(payload, scope, reply) {
|
|
111
|
+
if (!hasScope(payload, scope)) {
|
|
112
|
+
reply.status(403).send({
|
|
113
|
+
error: "Forbidden",
|
|
114
|
+
message: `Missing required scope: ${scope}`,
|
|
115
|
+
});
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/lib/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAsCA,QAAA,MAAM,MAAM,0BAQV,CAAC;AAGH,eAAe,MAAM,CAAC"}
|
package/dist/lib/logger.js
CHANGED
|
@@ -3,14 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const winston_1 = require("winston");
|
|
4
4
|
const uuid_1 = require("uuid");
|
|
5
5
|
const correlationId = (0, uuid_1.v4)();
|
|
6
|
+
const isProduction = process.env["NODE_ENV"] === "production";
|
|
7
|
+
const structuredFormat = winston_1.format.combine(winston_1.format.timestamp({ format: "YYYY-MM-DDTHH:mm:ss.SSSZ" }), winston_1.format.errors({ stack: true }), winston_1.format.json());
|
|
8
|
+
const devFormat = winston_1.format.combine(winston_1.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), winston_1.format.colorize(), winston_1.format.printf((info) => `${correlationId} | ${info.timestamp} | ${info.level}: ${info.message}`));
|
|
6
9
|
const logger = (0, winston_1.createLogger)({
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}), winston_1.format.json()),
|
|
10
|
+
defaultMeta: { service: "crypto-server", correlationId },
|
|
11
|
+
format: isProduction ? structuredFormat : devFormat,
|
|
10
12
|
transports: [
|
|
11
13
|
new winston_1.transports.Console({
|
|
12
|
-
level: "info",
|
|
13
|
-
format: winston_1.format.combine(winston_1.format.colorize(), winston_1.format.printf((info) => `${correlationId} | ${info.timestamp} | ${info.level}: ${info.message}`)),
|
|
14
|
+
level: process.env["LOG_LEVEL"] ?? "info",
|
|
14
15
|
}),
|
|
15
16
|
],
|
|
16
17
|
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function initTelemetry(): void;
|
|
2
|
+
export declare function shutdownTelemetry(): Promise<void>;
|
|
3
|
+
export declare function traceCryptoOperation<T>(operationName: string, attributes: Record<string, string | number>, fn: () => Promise<T> | T): Promise<T>;
|
|
4
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/lib/telemetry.ts"],"names":[],"mappings":"AA2CA,wBAAgB,aAAa,IAAI,IAAI,CA2BpC;AAKD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAIvD;AA8BD,wBAAsB,oBAAoB,CAAC,CAAC,EAC1C,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,EAC3C,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAmCZ"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initTelemetry = initTelemetry;
|
|
4
|
+
exports.shutdownTelemetry = shutdownTelemetry;
|
|
5
|
+
exports.traceCryptoOperation = traceCryptoOperation;
|
|
6
|
+
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
7
|
+
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
8
|
+
const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
|
|
9
|
+
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
|
|
10
|
+
const instrumentation_http_1 = require("@opentelemetry/instrumentation-http");
|
|
11
|
+
const instrumentation_fastify_1 = require("@opentelemetry/instrumentation-fastify");
|
|
12
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
13
|
+
const version_1 = require("./version");
|
|
14
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
15
|
+
const api_1 = require("@opentelemetry/api");
|
|
16
|
+
const SERVICE_NAME = "crypto-server";
|
|
17
|
+
const SERVICE_VERSION = version_1.PACKAGE_VERSION;
|
|
18
|
+
let sdk;
|
|
19
|
+
function initTelemetry() {
|
|
20
|
+
const endpoint = process.env["OTEL_EXPORTER_OTLP_ENDPOINT"];
|
|
21
|
+
if (!endpoint && process.env["NODE_ENV"] !== "production") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const resource = (0, resources_1.resourceFromAttributes)({
|
|
25
|
+
[semantic_conventions_1.ATTR_SERVICE_NAME]: SERVICE_NAME,
|
|
26
|
+
[semantic_conventions_1.ATTR_SERVICE_VERSION]: SERVICE_VERSION,
|
|
27
|
+
});
|
|
28
|
+
const traceExporterOpts = endpoint ? { url: `${endpoint}/v1/traces` } : {};
|
|
29
|
+
const metricExporterOpts = endpoint ? { url: `${endpoint}/v1/metrics` } : {};
|
|
30
|
+
sdk = new sdk_node_1.NodeSDK({
|
|
31
|
+
resource,
|
|
32
|
+
traceExporter: new exporter_trace_otlp_http_1.OTLPTraceExporter(traceExporterOpts),
|
|
33
|
+
metricReader: new sdk_metrics_1.PeriodicExportingMetricReader({
|
|
34
|
+
exporter: new exporter_metrics_otlp_http_1.OTLPMetricExporter(metricExporterOpts),
|
|
35
|
+
exportIntervalMillis: 30000,
|
|
36
|
+
}),
|
|
37
|
+
instrumentations: [new instrumentation_http_1.HttpInstrumentation(), new instrumentation_fastify_1.FastifyInstrumentation()],
|
|
38
|
+
});
|
|
39
|
+
sdk.start();
|
|
40
|
+
}
|
|
41
|
+
async function shutdownTelemetry() {
|
|
42
|
+
if (sdk) {
|
|
43
|
+
await sdk.shutdown();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const tracer = api_1.trace.getTracer(SERVICE_NAME, SERVICE_VERSION);
|
|
47
|
+
const meter = api_1.metrics.getMeter(SERVICE_NAME, SERVICE_VERSION);
|
|
48
|
+
const operationCounter = meter.createCounter("crypto.operations.total", {
|
|
49
|
+
description: "Total number of cryptographic operations performed",
|
|
50
|
+
});
|
|
51
|
+
const operationDuration = meter.createHistogram("crypto.operations.duration_ms", {
|
|
52
|
+
description: "Duration of cryptographic operations in milliseconds",
|
|
53
|
+
unit: "ms",
|
|
54
|
+
});
|
|
55
|
+
async function traceCryptoOperation(operationName, attributes, fn) {
|
|
56
|
+
return tracer.startActiveSpan(`crypto.${operationName}`, async (span) => {
|
|
57
|
+
const start = performance.now();
|
|
58
|
+
span.setAttributes(attributes);
|
|
59
|
+
try {
|
|
60
|
+
const result = await fn();
|
|
61
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
62
|
+
operationCounter.add(1, {
|
|
63
|
+
operation: operationName,
|
|
64
|
+
status: "success",
|
|
65
|
+
...attributes,
|
|
66
|
+
});
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
span.setStatus({
|
|
71
|
+
code: api_1.SpanStatusCode.ERROR,
|
|
72
|
+
message: error.message,
|
|
73
|
+
});
|
|
74
|
+
span.recordException(error);
|
|
75
|
+
operationCounter.add(1, {
|
|
76
|
+
operation: operationName,
|
|
77
|
+
status: "error",
|
|
78
|
+
...attributes,
|
|
79
|
+
});
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
const duration = performance.now() - start;
|
|
84
|
+
operationDuration.record(duration, {
|
|
85
|
+
operation: operationName,
|
|
86
|
+
...attributes,
|
|
87
|
+
});
|
|
88
|
+
span.end();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/lib/version.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,eAAe,QAInB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PACKAGE_VERSION = void 0;
|
|
4
|
+
const fs_1 = require("fs");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
exports.PACKAGE_VERSION = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, "..", "..", "package.json"), "utf8")).version;
|
|
7
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;yBAWnB,KAAK,OAAO,CAAC,eAAe,KAAG,IAAI;AAAnD,wBAuBE"}
|
package/dist/routes/index.js
CHANGED
|
@@ -3,14 +3,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const generate_1 = __importDefault(require("./v1/generate"));
|
|
7
|
-
const encrypt_1 = __importDefault(require("./v1/encrypt"));
|
|
8
6
|
const decrypt_1 = __importDefault(require("./v1/decrypt"));
|
|
7
|
+
const encrypt_1 = __importDefault(require("./v1/encrypt"));
|
|
8
|
+
const generate_1 = __importDefault(require("./v1/generate"));
|
|
9
|
+
const index_1 = __importDefault(require("./v1/index"));
|
|
9
10
|
const revoke_1 = __importDefault(require("./v1/revoke"));
|
|
11
|
+
const verify_1 = __importDefault(require("./v1/verify"));
|
|
12
|
+
const v2_1 = __importDefault(require("./v2"));
|
|
13
|
+
const probes_1 = __importDefault(require("./probes"));
|
|
10
14
|
exports.default = (app) => {
|
|
11
|
-
(
|
|
12
|
-
|
|
15
|
+
app.addHook("onSend", async (request, reply) => {
|
|
16
|
+
if (request.url.startsWith("/v1/")) {
|
|
17
|
+
reply.header("Deprecation", "true");
|
|
18
|
+
reply.header("Sunset", "2027-01-01T00:00:00Z");
|
|
19
|
+
reply.header("Link", '</v2>; rel="successor-version"');
|
|
20
|
+
}
|
|
21
|
+
});
|
|
13
22
|
(0, decrypt_1.default)(app);
|
|
23
|
+
(0, encrypt_1.default)(app);
|
|
24
|
+
(0, generate_1.default)(app);
|
|
25
|
+
(0, index_1.default)(app);
|
|
14
26
|
(0, revoke_1.default)(app);
|
|
27
|
+
(0, verify_1.default)(app);
|
|
28
|
+
(0, v2_1.default)(app);
|
|
29
|
+
(0, probes_1.default)(app);
|
|
15
30
|
};
|
|
16
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"probes.d.ts","sourceRoot":"","sources":["../../src/routes/probes.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAM/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAmEE"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const startTime = Date.now();
|
|
4
|
+
exports.default = (app) => {
|
|
5
|
+
app.get("/live", { schema: { hide: true } }, async () => {
|
|
6
|
+
return {
|
|
7
|
+
status: "alive",
|
|
8
|
+
uptime: Math.floor((Date.now() - startTime) / 1000),
|
|
9
|
+
};
|
|
10
|
+
});
|
|
11
|
+
app.get("/ready", { schema: { hide: true } }, async (_request, reply) => {
|
|
12
|
+
const checks = {
|
|
13
|
+
configLoaded: true,
|
|
14
|
+
serverListening: true,
|
|
15
|
+
};
|
|
16
|
+
const allReady = Object.values(checks).every(Boolean);
|
|
17
|
+
const status = allReady ? 200 : 503;
|
|
18
|
+
return reply.status(status).send({
|
|
19
|
+
status: allReady ? "ready" : "not_ready",
|
|
20
|
+
checks,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
app.get("/metrics", { schema: { hide: true } }, async (_request, reply) => {
|
|
24
|
+
const uptime = Math.floor((Date.now() - startTime) / 1000);
|
|
25
|
+
const memUsage = process.memoryUsage();
|
|
26
|
+
const lines = [
|
|
27
|
+
"# HELP process_uptime_seconds Process uptime in seconds",
|
|
28
|
+
"# TYPE process_uptime_seconds gauge",
|
|
29
|
+
`process_uptime_seconds ${uptime}`,
|
|
30
|
+
"",
|
|
31
|
+
"# HELP process_resident_memory_bytes Resident memory size in bytes",
|
|
32
|
+
"# TYPE process_resident_memory_bytes gauge",
|
|
33
|
+
`process_resident_memory_bytes ${memUsage.rss}`,
|
|
34
|
+
"",
|
|
35
|
+
"# HELP process_heap_used_bytes Heap used in bytes",
|
|
36
|
+
"# TYPE process_heap_used_bytes gauge",
|
|
37
|
+
`process_heap_used_bytes ${memUsage.heapUsed}`,
|
|
38
|
+
"",
|
|
39
|
+
"# HELP process_heap_total_bytes Heap total in bytes",
|
|
40
|
+
"# TYPE process_heap_total_bytes gauge",
|
|
41
|
+
`process_heap_total_bytes ${memUsage.heapTotal}`,
|
|
42
|
+
"",
|
|
43
|
+
"# HELP nodejs_version_info Node.js version",
|
|
44
|
+
"# TYPE nodejs_version_info gauge",
|
|
45
|
+
`nodejs_version_info{version="${process.version}"} 1`,
|
|
46
|
+
"",
|
|
47
|
+
];
|
|
48
|
+
reply.header("content-type", "text/plain; version=0.0.4; charset=utf-8");
|
|
49
|
+
return reply.send(lines.join("\n"));
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=probes.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
declare const _default: (app:
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
declare const _default: (app: FastifyInstance) => void;
|
|
3
3
|
export default _default;
|
|
4
4
|
//# sourceMappingURL=decrypt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/decrypt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decrypt.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/decrypt.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAkC/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAgCE"}
|
|
@@ -4,13 +4,56 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const decrypt_1 = __importDefault(require("@sebastienrousseau/crypto-lib/dist/lib/decrypt"));
|
|
7
|
+
const validation_1 = require("../../utils/validation");
|
|
8
|
+
const route_helpers_1 = require("../../utils/route-helpers");
|
|
9
|
+
const decryptSchema = {
|
|
10
|
+
tags: ["Encryption"],
|
|
11
|
+
summary: "Decrypt a message",
|
|
12
|
+
description: "Decrypts a PGP-encrypted message using private/public key pair and passphrase.",
|
|
13
|
+
response: {
|
|
14
|
+
200: { type: "object", properties: { data: { type: "string" } } },
|
|
15
|
+
400: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: { error: { type: "string" }, details: { type: "array" } },
|
|
18
|
+
},
|
|
19
|
+
401: { type: "object", properties: { error: { type: "string" } } },
|
|
20
|
+
},
|
|
21
|
+
body: {
|
|
22
|
+
type: "object",
|
|
23
|
+
required: ["passphrase", "message", "publicKey", "privateKey"],
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
properties: {
|
|
26
|
+
passphrase: { type: "string", minLength: 1, maxLength: 1024 },
|
|
27
|
+
message: { type: "string", minLength: 1, maxLength: 1024 * 1024 },
|
|
28
|
+
publicKey: { type: "string", minLength: 1, maxLength: 64 * 1024 },
|
|
29
|
+
privateKey: { type: "string", minLength: 1, maxLength: 64 * 1024 },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
7
33
|
exports.default = (app) => {
|
|
8
|
-
app.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
34
|
+
app.post("/v1/decrypt", { schema: decryptSchema }, async (request, reply) => {
|
|
35
|
+
try {
|
|
36
|
+
const body = request.body;
|
|
37
|
+
const v = (0, route_helpers_1.collectValidation)({
|
|
38
|
+
passphrase: (0, validation_1.validateRequiredString)(body.passphrase, "passphrase"),
|
|
39
|
+
message: (0, validation_1.validateBase64)(body.message, "message"),
|
|
40
|
+
publicKey: (0, validation_1.validateBase64)(body.publicKey, "publicKey"),
|
|
41
|
+
privateKey: (0, validation_1.validateBase64)(body.privateKey, "privateKey"),
|
|
42
|
+
}, reply);
|
|
43
|
+
if (!v)
|
|
44
|
+
return;
|
|
45
|
+
const decryptedData = await (0, decrypt_1.default)({
|
|
46
|
+
passphrase: v.passphrase,
|
|
47
|
+
message: v.message,
|
|
48
|
+
publicKey: v.publicKey,
|
|
49
|
+
privateKey: v.privateKey,
|
|
50
|
+
});
|
|
51
|
+
return reply.send({ data: decryptedData });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
request.log.error(error, "Decryption operation failed");
|
|
55
|
+
return reply.status(500).send({ error: "Decryption failed" });
|
|
56
|
+
}
|
|
14
57
|
});
|
|
15
58
|
};
|
|
16
59
|
//# sourceMappingURL=decrypt.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
declare const _default: (app:
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
declare const _default: (app: FastifyInstance) => void;
|
|
3
3
|
export default _default;
|
|
4
4
|
//# sourceMappingURL=encrypt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/encrypt.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"encrypt.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/encrypt.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBAkC/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBA+BE"}
|
|
@@ -4,13 +4,55 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const encrypt_1 = __importDefault(require("@sebastienrousseau/crypto-lib/dist/lib/encrypt"));
|
|
7
|
+
const validation_1 = require("../../utils/validation");
|
|
8
|
+
const route_helpers_1 = require("../../utils/route-helpers");
|
|
9
|
+
const encryptSchema = {
|
|
10
|
+
tags: ["Encryption"],
|
|
11
|
+
summary: "Encrypt a message",
|
|
12
|
+
description: "Encrypts a plaintext message using the supplied PGP public key and passphrase.",
|
|
13
|
+
response: {
|
|
14
|
+
200: { type: "object", properties: { data: { type: "string" } } },
|
|
15
|
+
400: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: { error: { type: "string" }, details: { type: "array" } },
|
|
18
|
+
},
|
|
19
|
+
401: { type: "object", properties: { error: { type: "string" } } },
|
|
20
|
+
},
|
|
21
|
+
body: {
|
|
22
|
+
type: "object",
|
|
23
|
+
required: ["passphrase", "message", "publicKey"],
|
|
24
|
+
additionalProperties: false,
|
|
25
|
+
properties: {
|
|
26
|
+
passphrase: { type: "string", minLength: 1, maxLength: 1024 },
|
|
27
|
+
message: { type: "string", minLength: 1, maxLength: 1024 * 1024 },
|
|
28
|
+
publicKey: { type: "string", minLength: 1, maxLength: 64 * 1024 },
|
|
29
|
+
privateKey: { type: "string", minLength: 1, maxLength: 64 * 1024 },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
7
33
|
exports.default = (app) => {
|
|
8
|
-
app.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
34
|
+
app.post("/v1/encrypt", { schema: encryptSchema }, async (request, reply) => {
|
|
35
|
+
try {
|
|
36
|
+
const body = request.body;
|
|
37
|
+
const v = (0, route_helpers_1.collectValidation)({
|
|
38
|
+
passphrase: (0, validation_1.validateRequiredString)(body.passphrase, "passphrase"),
|
|
39
|
+
message: (0, validation_1.validateRequiredString)(body.message, "message"),
|
|
40
|
+
publicKey: (0, validation_1.validateBase64)(body.publicKey, "publicKey"),
|
|
41
|
+
}, reply);
|
|
42
|
+
if (!v)
|
|
43
|
+
return;
|
|
44
|
+
const encryptedData = await (0, encrypt_1.default)({
|
|
45
|
+
passphrase: v.passphrase,
|
|
46
|
+
message: v.message,
|
|
47
|
+
publicKey: v.publicKey,
|
|
48
|
+
...(body.privateKey ? { privateKey: body.privateKey } : {}),
|
|
49
|
+
});
|
|
50
|
+
return reply.send({ data: encryptedData });
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
request.log.error(error, "Encryption operation failed");
|
|
54
|
+
return reply.status(500).send({ error: "Encryption failed" });
|
|
55
|
+
}
|
|
14
56
|
});
|
|
15
57
|
};
|
|
16
58
|
//# sourceMappingURL=encrypt.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
declare const _default: (app:
|
|
1
|
+
import type { FastifyInstance } from "fastify";
|
|
2
|
+
declare const _default: (app: FastifyInstance) => void;
|
|
3
3
|
export default _default;
|
|
4
4
|
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/routes/v1/generate.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;yBA+D/B,KAAK,eAAe,KAAG,IAAI;AAA3C,wBAkEE"}
|
|
@@ -4,20 +4,92 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const generate_1 = __importDefault(require("@sebastienrousseau/crypto-lib/dist/lib/generate"));
|
|
7
|
+
const types_1 = require("../../@types/types");
|
|
8
|
+
const validation_1 = require("../../utils/validation");
|
|
9
|
+
const route_helpers_1 = require("../../utils/route-helpers");
|
|
10
|
+
const generateSchema = {
|
|
11
|
+
tags: ["Key Management"],
|
|
12
|
+
summary: "Generate a key pair",
|
|
13
|
+
description: "Generates an OpenPGP key pair (RSA or ECC). The private key is NOT returned for security.",
|
|
14
|
+
response: {
|
|
15
|
+
200: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
data: {
|
|
19
|
+
type: "object",
|
|
20
|
+
properties: {
|
|
21
|
+
publicKey: { type: "string" },
|
|
22
|
+
revocationCertificate: { type: "string" },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
warning: { type: "string" },
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
400: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: { error: { type: "string" }, details: { type: "array" } },
|
|
31
|
+
},
|
|
32
|
+
401: { type: "object", properties: { error: { type: "string" } } },
|
|
33
|
+
},
|
|
34
|
+
body: {
|
|
35
|
+
type: "object",
|
|
36
|
+
required: ["name", "email", "type", "passphrase", "curve", "format"],
|
|
37
|
+
additionalProperties: false,
|
|
38
|
+
properties: {
|
|
39
|
+
name: { type: "string", minLength: 1, maxLength: 256 },
|
|
40
|
+
email: { type: "string", minLength: 3, maxLength: 256 },
|
|
41
|
+
type: { type: "string", enum: [...types_1.KEY_TYPES] },
|
|
42
|
+
passphrase: { type: "string", minLength: 1, maxLength: 1024 },
|
|
43
|
+
curve: { type: "string", enum: [...types_1.CURVE_TYPES] },
|
|
44
|
+
format: { type: "string", enum: [...types_1.FORMAT_TYPES] },
|
|
45
|
+
rsaBits: { type: "number", minimum: 2048, maximum: 4096 },
|
|
46
|
+
keyExpirationTime: { type: "number", minimum: 0 },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
7
50
|
exports.default = (app) => {
|
|
8
|
-
app.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
51
|
+
app.post("/v1/generate", { schema: generateSchema }, async (request, reply) => {
|
|
52
|
+
try {
|
|
53
|
+
const body = request.body;
|
|
54
|
+
const v = (0, route_helpers_1.collectValidation)({
|
|
55
|
+
name: (0, validation_1.validateRequiredString)(body.name, "name"),
|
|
56
|
+
email: (0, validation_1.validateEmail)(body.email, "email"),
|
|
57
|
+
type: (0, validation_1.validateEnum)(body.type, "type", types_1.KEY_TYPES),
|
|
58
|
+
passphrase: (0, validation_1.validateRequiredString)(body.passphrase, "passphrase"),
|
|
59
|
+
curve: (0, validation_1.validateEnum)(body.curve, "curve", types_1.CURVE_TYPES),
|
|
60
|
+
format: (0, validation_1.validateEnum)(body.format, "format", types_1.FORMAT_TYPES),
|
|
61
|
+
rsaBits: (0, validation_1.validateOptionalNumber)(body.rsaBits, 2048, "rsaBits", {
|
|
62
|
+
min: 2048,
|
|
63
|
+
max: 4096,
|
|
64
|
+
}),
|
|
65
|
+
keyExpirationTime: (0, validation_1.validateOptionalNumber)(body.keyExpirationTime, 0, "keyExpirationTime", { min: 0 }),
|
|
66
|
+
}, reply);
|
|
67
|
+
if (!v)
|
|
68
|
+
return;
|
|
69
|
+
const generated = (await (0, generate_1.default)({
|
|
70
|
+
date: new Date(),
|
|
71
|
+
name: v.name,
|
|
72
|
+
email: v.email,
|
|
73
|
+
userIDs: [{ name: v.name, email: v.email }],
|
|
74
|
+
type: v.type,
|
|
75
|
+
passphrase: v.passphrase,
|
|
76
|
+
rsaBits: v.rsaBits,
|
|
77
|
+
curve: v.curve,
|
|
78
|
+
keyExpirationTime: v.keyExpirationTime,
|
|
79
|
+
format: v.format,
|
|
80
|
+
}));
|
|
81
|
+
return reply.send({
|
|
82
|
+
data: {
|
|
83
|
+
publicKey: generated.publicKey,
|
|
84
|
+
revocationCertificate: generated.revocationCertificate,
|
|
85
|
+
},
|
|
86
|
+
warning: "Private key not included in response for security. Configure secure key delivery for production use.",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
request.log.error(error, "Key pair generation failed");
|
|
91
|
+
return reply.status(500).send({ error: "Key pair generation failed" });
|
|
92
|
+
}
|
|
21
93
|
});
|
|
22
94
|
};
|
|
23
95
|
//# sourceMappingURL=generate.js.map
|