@voyantjs/hono 0.31.1 → 0.31.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.
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAI7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAA;AAsCpB,wBAAgB,WAAW,CAAC,SAAS,SAAS,cAAc,EAC1D,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,EAC/B,IAAI,CAAC,EAAE;IACL,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,IAAI,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAA;CACxC,GACA,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAC,CAqJD"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/middleware/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAI7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAA;AAoBpB,wBAAgB,WAAW,CAAC,SAAS,SAAS,cAAc,EAC1D,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,EAC/B,IAAI,CAAC,EAAE;IACL,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,IAAI,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAA;CACxC,GACA,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAC,CAqJD"}
@@ -1,27 +1,9 @@
1
1
  import { apikeyTable } from "@voyantjs/db/schema/iam";
2
+ import { permissionsToStrings } from "@voyantjs/types/api-keys";
2
3
  import { and, eq } from "drizzle-orm";
3
4
  import { sha256Base64Url } from "../auth/crypto.js";
4
5
  import { extractBearerToken, verifySession } from "../auth/session-jwt.js";
5
6
  import { resolveDbFactoryResult, } from "../types.js";
6
- function permissionsToScopes(permissions) {
7
- if (!permissions)
8
- return [];
9
- try {
10
- const parsed = JSON.parse(permissions);
11
- const scopes = [];
12
- for (const [resource, actions] of Object.entries(parsed)) {
13
- if (Array.isArray(actions)) {
14
- for (const action of actions) {
15
- scopes.push(`${resource}:${action}`);
16
- }
17
- }
18
- }
19
- return scopes;
20
- }
21
- catch {
22
- return [];
23
- }
24
- }
25
7
  const API_KEY_PREFIX = "voy_";
26
8
  function applyAuthContext(c, auth) {
27
9
  if (auth.userId)
@@ -113,7 +95,7 @@ export function requireAuth(dbFactory, opts) {
113
95
  .then(() => { })
114
96
  .catch(() => { }));
115
97
  }
116
- const scopes = permissionsToScopes(row.permissions);
98
+ const scopes = permissionsToStrings(row.permissions);
117
99
  applyAuthContext(c, {
118
100
  organizationId: row.referenceId,
119
101
  scopes,
@@ -1 +1 @@
1
- {"version":3,"file":"require-actor.d.ts","sourceRoot":"","sources":["../../src/middleware/require-actor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAC3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,SAAS,SAAS,cAAc,GAAG,cAAc,EAC5E,GAAG,OAAO,EAAE,KAAK,EAAE,GAClB,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAC,CA+BD"}
1
+ {"version":3,"file":"require-actor.d.ts","sourceRoot":"","sources":["../../src/middleware/require-actor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAkClE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,SAAS,SAAS,cAAc,GAAG,cAAc,EAC5E,GAAG,OAAO,EAAE,KAAK,EAAE,GAClB,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAC,CA0CD"}
@@ -1,3 +1,30 @@
1
+ import { hasApiKeyPermission, permissionStringsToPermissions } from "@voyantjs/types/api-keys";
2
+ function apiKeyResourceFromPath(pathname) {
3
+ const match = pathname.match(/^\/v1\/(?:admin|public)\/([^/]+)/);
4
+ return match?.[1] ?? null;
5
+ }
6
+ function apiKeyPermissionActionsForMethod(method) {
7
+ switch (method.toUpperCase()) {
8
+ case "GET":
9
+ case "HEAD":
10
+ return ["read", "search"];
11
+ case "POST":
12
+ return ["write", "trigger", "relay"];
13
+ case "PUT":
14
+ case "PATCH":
15
+ return ["write"];
16
+ case "DELETE":
17
+ return ["delete"];
18
+ default:
19
+ return [];
20
+ }
21
+ }
22
+ function hasAnyApiKeyPermission(scopes, resource, actions) {
23
+ if (!scopes || scopes.length === 0)
24
+ return false;
25
+ const permissions = permissionStringsToPermissions(scopes);
26
+ return actions.some((action) => hasApiKeyPermission(permissions, resource, action));
27
+ }
1
28
  /**
2
29
  * Guards a route surface by actor type.
3
30
  *
@@ -30,6 +57,14 @@ export function requireActor(...allowed) {
30
57
  if (c.get("isInternalRequest")) {
31
58
  return next();
32
59
  }
60
+ if (c.get("callerType") === "api_key") {
61
+ const resource = apiKeyResourceFromPath(new URL(c.req.url).pathname);
62
+ const actions = apiKeyPermissionActionsForMethod(c.req.method);
63
+ if (resource && hasAnyApiKeyPermission(c.get("scopes"), resource, actions)) {
64
+ return next();
65
+ }
66
+ return c.json({ error: "Forbidden: API key missing required permission" }, 403);
67
+ }
33
68
  const actor = c.get("actor");
34
69
  if (!actor) {
35
70
  return c.json({
@@ -1 +1 @@
1
- {"version":3,"file":"require-permission.d.ts","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAG7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EAEnB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAA;AAqBpB,wBAAgB,iBAAiB,CAAC,SAAS,SAAS,cAAc,EAChE,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;IACL,IAAI,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAA;CACxC,GACA,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAC,CAiED"}
1
+ {"version":3,"file":"require-permission.d.ts","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAG7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EAEnB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAA;AASpB,wBAAgB,iBAAiB,CAAC,SAAS,SAAS,cAAc,EAChE,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;IACL,IAAI,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAA;CACxC,GACA,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,eAAe,CAAA;CAC3B,CAAC,CAwED"}
@@ -1,15 +1,7 @@
1
+ import { hasApiKeyPermission, permissionStringsToPermissions } from "@voyantjs/types/api-keys";
1
2
  import { requireUserId } from "../auth/require-user.js";
2
3
  import { isDisposableDb, } from "../types.js";
3
4
  import { ForbiddenApiError, UnauthorizedApiError } from "../validation.js";
4
- function hasScope(scopes, permission) {
5
- if (!scopes || scopes.length === 0)
6
- return false;
7
- const { resource, action } = permission;
8
- return (scopes.includes("*") ||
9
- scopes.includes(`${resource}:${action}`) ||
10
- scopes.includes(`${resource}:*`) ||
11
- scopes.includes(`*:${action}`));
12
- }
13
5
  export function requirePermission(dbFactory, resource, action, opts) {
14
6
  return async (c, next) => {
15
7
  const permission = { resource, action };
@@ -17,7 +9,8 @@ export function requirePermission(dbFactory, resource, action, opts) {
17
9
  return next();
18
10
  }
19
11
  const scopes = c.get("scopes");
20
- if (hasScope(scopes, permission)) {
12
+ if (scopes &&
13
+ hasApiKeyPermission(permissionStringsToPermissions(scopes), permission.resource, permission.action)) {
21
14
  return next();
22
15
  }
23
16
  const userId = requireUserId(c);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/hono",
3
- "version": "0.31.1",
3
+ "version": "0.31.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -94,18 +94,18 @@
94
94
  "drizzle-orm": "^0.45.2",
95
95
  "hono": "^4.12.10",
96
96
  "zod": "^4.3.6",
97
- "@voyantjs/core": "0.31.1",
98
- "@voyantjs/db": "0.31.1",
99
- "@voyantjs/types": "0.31.1",
100
- "@voyantjs/utils": "0.31.1",
101
- "@voyantjs/workflows": "0.31.1"
97
+ "@voyantjs/core": "0.31.2",
98
+ "@voyantjs/db": "0.31.2",
99
+ "@voyantjs/types": "0.31.2",
100
+ "@voyantjs/utils": "0.31.2",
101
+ "@voyantjs/workflows": "0.31.2"
102
102
  },
103
103
  "devDependencies": {
104
104
  "@cloudflare/workers-types": "^4.20260426.1",
105
105
  "typescript": "^6.0.2",
106
106
  "vitest": "^4.1.2",
107
107
  "@voyantjs/voyant-typescript-config": "0.1.0",
108
- "@voyantjs/workflows-orchestrator": "0.31.1"
108
+ "@voyantjs/workflows-orchestrator": "0.31.2"
109
109
  },
110
110
  "files": [
111
111
  "dist"