@neat.is/core 0.3.7 → 0.3.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/dist/{chunk-75IBA4UL.js → chunk-7TYESDAI.js} +69 -2
- package/dist/chunk-7TYESDAI.js.map +1 -0
- package/dist/{chunk-ZU2RQRCN.js → chunk-CZ3T6TE2.js} +251 -245
- package/dist/{chunk-ZU2RQRCN.js.map → chunk-CZ3T6TE2.js.map} +1 -1
- package/dist/{chunk-EDHOCFOG.js → chunk-LQ3JFBTX.js} +15 -5
- package/dist/chunk-LQ3JFBTX.js.map +1 -0
- package/dist/{chunk-CY67YKNO.js → chunk-V4TU7OKZ.js} +16 -2
- package/dist/chunk-V4TU7OKZ.js.map +1 -0
- package/dist/cli.cjs +1185 -405
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.d.cts +5 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +879 -156
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +98 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -4
- package/dist/neatd.cjs +111 -3
- package/dist/neatd.cjs.map +1 -1
- package/dist/neatd.js +14 -4
- package/dist/neatd.js.map +1 -1
- package/dist/{otel-grpc-PM4SWPZE.js → otel-grpc-S3AENOZ6.js} +3 -3
- package/dist/server.cjs +110 -6
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +25 -7
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-75IBA4UL.js.map +0 -1
- package/dist/chunk-CY67YKNO.js.map +0 -1
- package/dist/chunk-EDHOCFOG.js.map +0 -1
- /package/dist/{otel-grpc-PM4SWPZE.js.map → otel-grpc-S3AENOZ6.js.map} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -40,6 +40,75 @@ var init_cjs_shims = __esm({
|
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
// src/auth.ts
|
|
44
|
+
function isLoopbackHost(host) {
|
|
45
|
+
if (!host) return false;
|
|
46
|
+
return LOOPBACK_HOSTS.has(host);
|
|
47
|
+
}
|
|
48
|
+
function assertBindAuthority(host, token) {
|
|
49
|
+
if (token && token.length > 0) return;
|
|
50
|
+
if (isLoopbackHost(host)) return;
|
|
51
|
+
throw new BindAuthorityError(host);
|
|
52
|
+
}
|
|
53
|
+
function mountBearerAuth(app, opts) {
|
|
54
|
+
if (!opts.token || opts.token.length === 0) return;
|
|
55
|
+
if (opts.trustProxy) return;
|
|
56
|
+
const expected = Buffer.from(opts.token, "utf8");
|
|
57
|
+
const suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...opts.extraUnauthenticatedSuffixes ?? []];
|
|
58
|
+
app.addHook("preHandler", (req, reply, done) => {
|
|
59
|
+
const path37 = (req.url.split("?")[0] ?? "").replace(/\/+$/, "");
|
|
60
|
+
for (const suffix of suffixes) {
|
|
61
|
+
if (path37 === suffix || path37.endsWith(suffix)) {
|
|
62
|
+
done();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const header = req.headers.authorization;
|
|
67
|
+
if (typeof header !== "string" || !header.startsWith("Bearer ")) {
|
|
68
|
+
void reply.code(401).send({ error: "unauthorized" });
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const provided = Buffer.from(header.slice("Bearer ".length).trim(), "utf8");
|
|
72
|
+
if (provided.length !== expected.length || !(0, import_node_crypto.timingSafeEqual)(provided, expected)) {
|
|
73
|
+
void reply.code(401).send({ error: "unauthorized" });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
done();
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function readAuthEnv(env = process.env) {
|
|
80
|
+
const t = env.NEAT_AUTH_TOKEN;
|
|
81
|
+
const ot = env.NEAT_OTEL_TOKEN;
|
|
82
|
+
return {
|
|
83
|
+
authToken: t && t.length > 0 ? t : void 0,
|
|
84
|
+
otelToken: ot && ot.length > 0 ? ot : t && t.length > 0 ? t : void 0,
|
|
85
|
+
trustProxy: env.NEAT_AUTH_PROXY === "true"
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
var import_node_crypto, LOOPBACK_HOSTS, BindAuthorityError, DEFAULT_UNAUTH_SUFFIXES;
|
|
89
|
+
var init_auth = __esm({
|
|
90
|
+
"src/auth.ts"() {
|
|
91
|
+
"use strict";
|
|
92
|
+
init_cjs_shims();
|
|
93
|
+
import_node_crypto = require("crypto");
|
|
94
|
+
LOOPBACK_HOSTS = /* @__PURE__ */ new Set([
|
|
95
|
+
"127.0.0.1",
|
|
96
|
+
"localhost",
|
|
97
|
+
"::1",
|
|
98
|
+
"::ffff:127.0.0.1"
|
|
99
|
+
]);
|
|
100
|
+
BindAuthorityError = class extends Error {
|
|
101
|
+
constructor(host) {
|
|
102
|
+
super(
|
|
103
|
+
`NEAT refuses to bind on a public interface without \`NEAT_AUTH_TOKEN\` set (host="${host}"). Set the token or bind to loopback only.`
|
|
104
|
+
);
|
|
105
|
+
this.name = "BindAuthorityError";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
DEFAULT_UNAUTH_SUFFIXES = ["/health", "/healthz", "/readyz"];
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
43
112
|
// src/otel-grpc.ts
|
|
44
113
|
var otel_grpc_exports = {};
|
|
45
114
|
__export(otel_grpc_exports, {
|
|
@@ -122,8 +191,21 @@ function loadTraceService() {
|
|
|
122
191
|
async function startOtelGrpcReceiver(opts) {
|
|
123
192
|
const server = new grpc.Server();
|
|
124
193
|
const service = loadTraceService();
|
|
194
|
+
const requiresAuth = !opts.trustProxy && !!opts.authToken && opts.authToken.length > 0;
|
|
195
|
+
const expectedHeader = requiresAuth ? `Bearer ${opts.authToken}` : "";
|
|
125
196
|
server.addService(service, {
|
|
126
197
|
Export: (call, callback) => {
|
|
198
|
+
if (requiresAuth) {
|
|
199
|
+
const meta = call.metadata.get("authorization");
|
|
200
|
+
const got = meta.length > 0 ? String(meta[0]) : "";
|
|
201
|
+
const a = Buffer.from(got, "utf8");
|
|
202
|
+
const b = Buffer.from(expectedHeader, "utf8");
|
|
203
|
+
const ok = a.length === b.length && (0, import_node_crypto2.timingSafeEqual)(a, b);
|
|
204
|
+
if (!ok) {
|
|
205
|
+
callback({ code: grpc.status.UNAUTHENTICATED, message: "unauthorized" });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
127
209
|
void (async () => {
|
|
128
210
|
try {
|
|
129
211
|
const reshaped = reshapeGrpcRequest(call.request ?? {});
|
|
@@ -156,13 +238,14 @@ async function startOtelGrpcReceiver(opts) {
|
|
|
156
238
|
})
|
|
157
239
|
};
|
|
158
240
|
}
|
|
159
|
-
var import_node_url, import_node_path34, grpc, protoLoader;
|
|
241
|
+
var import_node_url, import_node_path34, import_node_crypto2, grpc, protoLoader;
|
|
160
242
|
var init_otel_grpc = __esm({
|
|
161
243
|
"src/otel-grpc.ts"() {
|
|
162
244
|
"use strict";
|
|
163
245
|
init_cjs_shims();
|
|
164
246
|
import_node_url = require("url");
|
|
165
247
|
import_node_path34 = __toESM(require("path"), 1);
|
|
248
|
+
import_node_crypto2 = require("crypto");
|
|
166
249
|
grpc = __toESM(require("@grpc/grpc-js"), 1);
|
|
167
250
|
protoLoader = __toESM(require("@grpc/proto-loader"), 1);
|
|
168
251
|
init_otel();
|
|
@@ -303,6 +386,7 @@ async function buildOtelReceiver(opts) {
|
|
|
303
386
|
logger: false,
|
|
304
387
|
bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024
|
|
305
388
|
});
|
|
389
|
+
mountBearerAuth(app, { token: opts.authToken, trustProxy: opts.trustProxy });
|
|
306
390
|
const queue = [];
|
|
307
391
|
let draining = false;
|
|
308
392
|
let drainPromise = Promise.resolve();
|
|
@@ -398,6 +482,7 @@ var init_otel = __esm({
|
|
|
398
482
|
import_node_url2 = require("url");
|
|
399
483
|
import_fastify2 = __toESM(require("fastify"), 1);
|
|
400
484
|
import_protobufjs = __toESM(require("protobufjs"), 1);
|
|
485
|
+
init_auth();
|
|
401
486
|
exportTraceServiceRequestType = null;
|
|
402
487
|
exportTraceServiceResponseType = null;
|
|
403
488
|
cachedProtobufResponseBody = null;
|
|
@@ -4843,6 +4928,7 @@ data: ${JSON.stringify(envelope.payload)}
|
|
|
4843
4928
|
}
|
|
4844
4929
|
|
|
4845
4930
|
// src/api.ts
|
|
4931
|
+
init_auth();
|
|
4846
4932
|
function serializeGraph(graph) {
|
|
4847
4933
|
const nodes = [];
|
|
4848
4934
|
graph.forEachNode((_id, attrs) => {
|
|
@@ -5208,6 +5294,7 @@ function registerRoutes(scope, ctx) {
|
|
|
5208
5294
|
async function buildApi(opts) {
|
|
5209
5295
|
const app = (0, import_fastify.default)({ logger: false });
|
|
5210
5296
|
await app.register(import_cors.default, { origin: true });
|
|
5297
|
+
mountBearerAuth(app, { token: opts.authToken, trustProxy: opts.trustProxy });
|
|
5211
5298
|
const startedAt = opts.startedAt ?? Date.now();
|
|
5212
5299
|
const registry = buildLegacyRegistry(opts);
|
|
5213
5300
|
const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== void 0;
|
|
@@ -5278,6 +5365,7 @@ init_cjs_shims();
|
|
|
5278
5365
|
var import_node_fs21 = require("fs");
|
|
5279
5366
|
var import_node_path36 = __toESM(require("path"), 1);
|
|
5280
5367
|
init_otel();
|
|
5368
|
+
init_auth();
|
|
5281
5369
|
function neatHomeFor(opts) {
|
|
5282
5370
|
if (opts.neatHome && opts.neatHome.length > 0) return import_node_path36.default.resolve(opts.neatHome);
|
|
5283
5371
|
const env = process.env.NEAT_HOME;
|
|
@@ -5484,8 +5572,14 @@ async function startDaemon(opts = {}) {
|
|
|
5484
5572
|
const host = resolveHost(opts);
|
|
5485
5573
|
const restPort = resolveRestPort(opts);
|
|
5486
5574
|
const otlpPort = resolveOtlpPort(opts);
|
|
5575
|
+
const auth = readAuthEnv();
|
|
5576
|
+
assertBindAuthority(host, auth.authToken);
|
|
5487
5577
|
try {
|
|
5488
|
-
restApp = await buildApi({
|
|
5578
|
+
restApp = await buildApi({
|
|
5579
|
+
projects: registry,
|
|
5580
|
+
authToken: auth.authToken,
|
|
5581
|
+
trustProxy: auth.trustProxy
|
|
5582
|
+
});
|
|
5489
5583
|
restAddress = await restApp.listen({ port: restPort, host });
|
|
5490
5584
|
console.log(`neatd: REST listening on ${restAddress}`);
|
|
5491
5585
|
} catch (err) {
|
|
@@ -5522,6 +5616,8 @@ async function startDaemon(opts = {}) {
|
|
|
5522
5616
|
}
|
|
5523
5617
|
try {
|
|
5524
5618
|
otlpApp = await buildOtelReceiver({
|
|
5619
|
+
authToken: auth.otelToken,
|
|
5620
|
+
trustProxy: auth.trustProxy,
|
|
5525
5621
|
onSpan: async (span) => {
|
|
5526
5622
|
const slot = await resolveTargetSlot(span.service);
|
|
5527
5623
|
if (!slot) return;
|