@logictan/dsh-imagegen 2.0.3 → 2.0.4

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/lib/index.js CHANGED
@@ -135,7 +135,7 @@ function installSettingsSectionCompat(ctx, ns, schema, entry, hooks) {
135
135
  */
136
136
  /** Settings namespace this plugin owns (host settings seam + bridge). */
137
137
  const IMAGEGEN_SETTINGS_NAMESPACE = "imagegen";
138
- /** Same-origin route family (loopback-only, mirroring the dsh-ssh fence). */
138
+ /** Same-origin route family (fenced by the composition's connection service). */
139
139
  const SETTINGS_API = {
140
140
  describe: "/api/dsh-imagegen/settings/describe",
141
141
  mutate: "/api/dsh-imagegen/settings/mutate"
@@ -189,7 +189,7 @@ const PROMPT_ENHANCE_API = {
189
189
  const IMAGE_MODEL_API = { models: "/api/dsh-imagegen/image-models" };
190
190
  /** Host-served built-in provider catalog (channels the user can instantiate). */
191
191
  const PRESETS_API = "/api/dsh-imagegen/presets";
192
- /** Loopback-only image reader for Agent tool-result previews. */
192
+ /** Image reader for Agent tool-result previews (fenced by the connection service). */
193
193
  const AGENT_IMAGE_API = "/api/dsh-imagegen/agent-image";
194
194
  /** Store the current composer image for the direct edit_image command. */
195
195
  const CONVERSATION_IMAGE_API = "/api/dsh-imagegen/conversation-image";
@@ -1967,27 +1967,33 @@ function presetById(id) {
1967
1967
  //#region src/routes.ts
1968
1968
  /** Cap on JSON request bodies (settings ops and generate payloads are small). */
1969
1969
  const MAX_JSON_BODY_BYTES = 24 * 1024 * 1024;
1970
- /** Loopback literal check plus browser same-origin markers (mirrors dsh-ssh). */
1971
- function isLoopbackRequest(request) {
1972
- const address = request.socket.remoteAddress;
1973
- if (address !== "127.0.0.1" && address !== "::1" && address !== "::ffff:127.0.0.1") return false;
1974
- const host = request.headers.host;
1975
- if (typeof host !== "string") return false;
1976
- let hostUrl;
1977
- try {
1978
- hostUrl = new URL(`http://${host}`);
1979
- } catch {
1980
- return false;
1981
- }
1982
- if (hostUrl.hostname !== "127.0.0.1" && hostUrl.hostname !== "localhost" && hostUrl.hostname !== "[::1]") return false;
1983
- if (request.headers["sec-fetch-site"] === "cross-site") return false;
1984
- const origin = request.headers.origin;
1985
- if (origin === void 0) return true;
1986
- try {
1987
- return new URL(origin).host === hostUrl.host;
1988
- } catch {
1989
- return false;
1970
+ /**
1971
+ * Ask the composition whether one request may be served.
1972
+ *
1973
+ * `connection.requestRejection` is the deployment's single trust fence: it
1974
+ * applies the Host/Origin checks (loopback plus the LAN authorities the
1975
+ * deployment declares) and the browser authentication that rides with them.
1976
+ * This plugin answers with the verdict instead of re-deriving it, because the
1977
+ * declared LAN authorities live in `connection`'s config and a local check
1978
+ * cannot see them.
1979
+ *
1980
+ * A missing `connection` refuses rather than serves: these routes sit in front
1981
+ * of Connection's `/api` prefix route, so serving them without its fence would
1982
+ * serve them unfenced.
1983
+ * @param connection - the composition's Connection service, when it is up.
1984
+ * @param req - the incoming request.
1985
+ * @param res - the response, written to when the request is refused.
1986
+ * @returns whether the request was refused.
1987
+ */
1988
+ function refuseUntrusted(connection, req, res) {
1989
+ if (connection === void 0) {
1990
+ writeJson(res, 403, { error: "forbidden" });
1991
+ return true;
1990
1992
  }
1993
+ const rejection = connection.requestRejection(req);
1994
+ if (rejection === void 0) return false;
1995
+ writeJson(res, rejection, { error: rejection === 401 ? "unauthorized" : "forbidden" });
1996
+ return true;
1991
1997
  }
1992
1998
  /** One JSON response. */
1993
1999
  function writeJson(res, status, body) {
@@ -2277,10 +2283,7 @@ function makeRoutes(deps) {
2277
2283
  };
2278
2284
  };
2279
2285
  const guard = (req, res, method) => {
2280
- if (!isLoopbackRequest(req)) {
2281
- writeJson(res, 403, { error: "forbidden: loopback-only" });
2282
- return false;
2283
- }
2286
+ if (refuseUntrusted(deps.connection(), req, res)) return false;
2284
2287
  if (req.method !== method) {
2285
2288
  writeJson(res, 405, { error: `method not allowed: ${req.method}` });
2286
2289
  return false;
@@ -2325,10 +2328,7 @@ function makeRoutes(deps) {
2325
2328
  kind: "prefix",
2326
2329
  path: AGENT_IMAGE_API,
2327
2330
  handler: async (req, res) => {
2328
- if (!isLoopbackRequest(req)) {
2329
- writeJson(res, 403, { error: "forbidden: loopback-only" });
2330
- return;
2331
- }
2331
+ if (refuseUntrusted(deps.connection(), req, res)) return;
2332
2332
  if (req.method !== "GET") {
2333
2333
  writeJson(res, 405, { error: `method not allowed: ${req.method}` });
2334
2334
  return;
@@ -3476,6 +3476,7 @@ function apply(ctx, config) {
3476
3476
  };
3477
3477
  sctx.effect(() => {
3478
3478
  const disposers = makeRoutes({
3479
+ connection: () => sctx.get("connection"),
3479
3480
  settings: seam,
3480
3481
  credentials: credentialsSeam,
3481
3482
  resolve: () => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@logictan/dsh-imagegen",
3
3
  "description": "Chat-invoked AI image generation for the dsh web GUI: text-to-image and image-to-image through configurable provider channels (gpt-image-2 / grok-imagine-image / nanobanana series / seedream-5.0-pro / dall-e-3, with native xAI Grok Imagine, Google Nano Banana and ByteDance Seedream request shaping) and per-channel model catalogs.",
4
- "version": "2.0.3",
4
+ "version": "2.0.4",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -31,6 +31,14 @@
31
31
  "dependencies": {
32
32
  "@deepseek-ai/schemastery": "^3.18.4"
33
33
  },
34
+ "peerDependencies": {
35
+ "@deepseek-ai/dsh-client-connection": "^0.1.5-alpha.1 || ^0.1.6-alpha.1 || ^0.1.7-alpha.1 || ^0.1.7-rc.1 || ^0.2.0-rc.1 || ^0.2.0-rc.2"
36
+ },
37
+ "peerDependenciesMeta": {
38
+ "@deepseek-ai/dsh-client-connection": {
39
+ "optional": true
40
+ }
41
+ },
34
42
  "devDependencies": {
35
43
  "@deepseek-ai/cordis": "^4.0.2",
36
44
  "@deepseek-ai/dsh-api-remotes": "^0.2.0-rc.2",