c8y-nitro 0.4.1 → 0.4.2
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/cli/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as name, r as version, t as description } from "../package-
|
|
1
|
+
import { n as name, r as version, t as description } from "../package-C4HtuVu_.mjs";
|
|
2
2
|
import { defineCommand, runMain } from "citty";
|
|
3
3
|
//#region src/cli/index.ts
|
|
4
4
|
runMain(defineCommand({
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as findMicroserviceByName, g as GENERATED_READINESS_ROUTE, h as GENERATED_LIVENESS_ROUTE, l as subscribeToApplication, m as createC8yManifestFromNitro, n as createBasicAuthHeader, o as getBootstrapCredentials, p as createC8yManifest, r as createMicroservice } from "./c8y-api-BBSKRwKs.mjs";
|
|
2
2
|
import { t as writeBootstrapCredentials } from "./env-file-B0BK-uZW.mjs";
|
|
3
|
-
import { n as name } from "./package-
|
|
3
|
+
import { n as name } from "./package-C4HtuVu_.mjs";
|
|
4
4
|
import { basename, dirname, join, relative } from "node:path";
|
|
5
5
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
6
6
|
import { x } from "tinyexec";
|
package/dist/utils.mjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
1
2
|
import process from "node:process";
|
|
2
3
|
import { useLogger } from "evlog/nitro/v3";
|
|
3
4
|
import { BasicAuth, Client, MicroserviceClientRequestAuth } from "@c8y/client";
|
|
4
5
|
import { defineCachedFunction } from "nitro/cache";
|
|
6
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
5
7
|
import { HTTPError, defineHandler } from "nitro/h3";
|
|
6
8
|
import { useStorage } from "nitro/storage";
|
|
7
9
|
import { useRuntimeConfig } from "nitro/runtime-config";
|
|
@@ -30,6 +32,55 @@ function convertRequestHeadersToC8yFormat(request) {
|
|
|
30
32
|
return headers;
|
|
31
33
|
}
|
|
32
34
|
//#endregion
|
|
35
|
+
//#region src/utils/internal/tenant.ts
|
|
36
|
+
const USER_TENANT_CACHE_SALT = randomBytes(32).toString("hex");
|
|
37
|
+
function getCookieValue(cookieHeader, name) {
|
|
38
|
+
try {
|
|
39
|
+
const value = cookieHeader?.match(`(^|;)\\s*${name}\\s*=\\s*([^;]+)`);
|
|
40
|
+
return value ? value.pop() : void 0;
|
|
41
|
+
} catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function getCurrentUserTenantCacheKeyMaterial(requestOrEvent) {
|
|
46
|
+
const request = "req" in requestOrEvent ? requestOrEvent.req : requestOrEvent;
|
|
47
|
+
const cookieAuth = getCookieValue(request.headers.get("cookie"), "authorization");
|
|
48
|
+
if (cookieAuth) return `cookie:${cookieAuth}`;
|
|
49
|
+
const authorization = request.headers.get("authorization");
|
|
50
|
+
if (authorization) return `header:${authorization}`;
|
|
51
|
+
}
|
|
52
|
+
function createCurrentUserTenantCacheKey(requestOrEvent) {
|
|
53
|
+
const material = getCurrentUserTenantCacheKeyMaterial(requestOrEvent);
|
|
54
|
+
if (!material) throw new Error("Cannot create current user tenant cache key without auth material");
|
|
55
|
+
return createHash("sha256").update(USER_TENANT_CACHE_SALT).update(":").update(material).digest("hex");
|
|
56
|
+
}
|
|
57
|
+
function tryGetTenantFromBasicAuth(requestOrEvent) {
|
|
58
|
+
const authorization = ("req" in requestOrEvent ? requestOrEvent.req : requestOrEvent).headers.get("authorization");
|
|
59
|
+
if (!authorization?.startsWith("Basic ")) return;
|
|
60
|
+
try {
|
|
61
|
+
const decoded = Buffer.from(authorization.slice(6), "base64").toString("utf8");
|
|
62
|
+
const separatorIndex = decoded.indexOf(":");
|
|
63
|
+
const userPart = separatorIndex === -1 ? decoded : decoded.slice(0, separatorIndex);
|
|
64
|
+
const slashIndex = userPart.indexOf("/");
|
|
65
|
+
if (slashIndex <= 0) return;
|
|
66
|
+
return userPart.slice(0, slashIndex);
|
|
67
|
+
} catch {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const getCurrentUserTenantId = defineCachedFunction(async (requestOrEvent) => {
|
|
72
|
+
const basicTenant = tryGetTenantFromBasicAuth(requestOrEvent);
|
|
73
|
+
if (basicTenant) return basicTenant;
|
|
74
|
+
return (await useUserClient(requestOrEvent).tenant.current()).data.name;
|
|
75
|
+
}, {
|
|
76
|
+
maxAge: 60,
|
|
77
|
+
name: "_c8y_nitro_get_current_user_tenant_id",
|
|
78
|
+
group: "c8y_nitro",
|
|
79
|
+
swr: false,
|
|
80
|
+
getKey: (requestOrEvent) => createCurrentUserTenantCacheKey(requestOrEvent),
|
|
81
|
+
shouldBypassCache: (requestOrEvent) => !getCurrentUserTenantCacheKeyMaterial(requestOrEvent)
|
|
82
|
+
});
|
|
83
|
+
//#endregion
|
|
33
84
|
//#region src/utils/credentials.ts
|
|
34
85
|
/**
|
|
35
86
|
* Fetches credentials for all tenants subscribed to this microservice.\
|
|
@@ -128,7 +179,7 @@ const useDeployedTenantCredentials = Object.assign(async () => {
|
|
|
128
179
|
async function useUserTenantCredentials(requestOrEvent) {
|
|
129
180
|
const request = "req" in requestOrEvent ? requestOrEvent.req : requestOrEvent;
|
|
130
181
|
if (request.context?.["c8y_user_tenant_credentials"]) return request.context["c8y_user_tenant_credentials"];
|
|
131
|
-
const tenantId =
|
|
182
|
+
const tenantId = await getCurrentUserTenantId(requestOrEvent);
|
|
132
183
|
const userTenantCreds = (await useSubscribedTenantCredentials())[tenantId];
|
|
133
184
|
if (!userTenantCreds) throw new HTTPError({
|
|
134
185
|
message: `No subscribed tenant credentials found for user tenant '${tenantId}'`,
|
|
@@ -172,7 +223,7 @@ function useUserClient(requestOrEvent) {
|
|
|
172
223
|
async function useUserTenantClient(requestOrEvent) {
|
|
173
224
|
const request = "req" in requestOrEvent ? requestOrEvent.req : requestOrEvent;
|
|
174
225
|
if (request.context?.["c8y_user_tenant_client"]) return request.context["c8y_user_tenant_client"];
|
|
175
|
-
const tenantId =
|
|
226
|
+
const tenantId = await getCurrentUserTenantId(requestOrEvent);
|
|
176
227
|
const creds = await useSubscribedTenantCredentials();
|
|
177
228
|
if (!creds[tenantId]) throw new HTTPError({
|
|
178
229
|
message: `No subscribed tenant credentials found for user tenant '${tenantId}'`,
|
|
@@ -281,7 +332,7 @@ function hasUserRequiredRole(roleOrRoles) {
|
|
|
281
332
|
function isUserFromAllowedTenant(tenantIdOrIds) {
|
|
282
333
|
return defineHandler(async (event) => {
|
|
283
334
|
const allowedTenants = Array.isArray(tenantIdOrIds) ? tenantIdOrIds : [tenantIdOrIds];
|
|
284
|
-
const userTenantId =
|
|
335
|
+
const userTenantId = await getCurrentUserTenantId(event);
|
|
285
336
|
if (!allowedTenants.includes(userTenantId)) throw new HTTPError({
|
|
286
337
|
status: 403,
|
|
287
338
|
statusText: "Forbidden",
|
|
@@ -306,7 +357,7 @@ function isUserFromAllowedTenant(tenantIdOrIds) {
|
|
|
306
357
|
*/
|
|
307
358
|
function isUserFromDeployedTenant() {
|
|
308
359
|
return defineHandler(async (event) => {
|
|
309
|
-
const userTenantId =
|
|
360
|
+
const userTenantId = await getCurrentUserTenantId(event);
|
|
310
361
|
const deployedTenantId = process.env.C8Y_BOOTSTRAP_TENANT;
|
|
311
362
|
if (!deployedTenantId) throw new HTTPError({
|
|
312
363
|
status: 500,
|