@lievclouds/dsh-cortex 0.3.6 → 0.3.9
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/client.js +91 -91
- package/package.json +1 -1
- package/src/cortex-ui/renderer/components/asset/DeleteAssetDialog.tsx +3 -2
- package/src/cortex-ui/renderer/components/poc/PocConfigPanel.tsx +3 -2
- package/src/cortex-ui/renderer/components/retest/RetestProxyDialog.tsx +3 -2
- package/src/cortex-ui/renderer/components/snapshot/DeleteSnapshotDialog.tsx +4 -2
- package/src/cortex-ui/renderer/components/vuln/BulkDeleteDialog.tsx +3 -2
- package/src/cortex-ui/renderer/components/vuln/ConfirmDeleteDialog.tsx +3 -2
- package/src/host/cortex/index.js +14 -9
- package/src/host/http.js +8 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lievclouds/dsh-cortex",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"description": "Cortex workbench for DeepSeek Harness: the original Cortex UI (vulnerabilities, assets, internal operations, Memory Nebula, snapshots, retest) as a native DSH panel, plus 12 native agent tools so DSH conversations use the local Cortex SQLite without MCP.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -2,6 +2,7 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|
|
2
2
|
import { Loader2, Trash2 } from 'lucide-react'
|
|
3
3
|
import { Button } from '@renderer/components/ui/button'
|
|
4
4
|
import { useI18n } from '@renderer/i18n'
|
|
5
|
+
import { getPortalContainer } from '../../../dsh/portal'
|
|
5
6
|
|
|
6
7
|
interface DeleteAssetDialogProps {
|
|
7
8
|
open: boolean
|
|
@@ -27,8 +28,8 @@ export function DeleteAssetDialog({
|
|
|
27
28
|
const { t } = useI18n()
|
|
28
29
|
|
|
29
30
|
return (
|
|
30
|
-
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
|
31
|
-
<DialogPrimitive.Portal>
|
|
31
|
+
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange} modal={false}>
|
|
32
|
+
<DialogPrimitive.Portal container={getPortalContainer()}>
|
|
32
33
|
<DialogPrimitive.Overlay className="sheet-overlay fixed inset-0 z-[70] bg-[hsl(224_18%_10%/0.3)]" />
|
|
33
34
|
<DialogPrimitive.Content className="fixed left-1/2 top-1/2 z-[70] w-[min(420px,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-border bg-background p-5 shadow-panel focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring">
|
|
34
35
|
<DialogPrimitive.Title className="text-[16px] font-medium tracking-tight text-foreground">
|
|
@@ -37,6 +37,7 @@ import { usePocErrorMessage } from '@renderer/components/poc/usePocErrorMessage'
|
|
|
37
37
|
import { getApi } from '@renderer/lib/api'
|
|
38
38
|
import { useI18n } from '@renderer/i18n'
|
|
39
39
|
import { cn } from '@renderer/lib/utils'
|
|
40
|
+
import { getPortalContainer } from '../../../dsh/portal'
|
|
40
41
|
|
|
41
42
|
interface PocConfigPanelProps {
|
|
42
43
|
open: boolean
|
|
@@ -122,8 +123,8 @@ export function PocConfigPanel({
|
|
|
122
123
|
: null
|
|
123
124
|
|
|
124
125
|
return (
|
|
125
|
-
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
|
126
|
-
<DialogPrimitive.Portal>
|
|
126
|
+
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange} modal={false}>
|
|
127
|
+
<DialogPrimitive.Portal container={getPortalContainer()}>
|
|
127
128
|
<DialogPrimitive.Overlay className="sheet-overlay fixed inset-0 z-[85] bg-[hsl(224_18%_10%/0.3)]" />
|
|
128
129
|
<DialogPrimitive.Content
|
|
129
130
|
data-testid="retest-config-panel"
|
|
@@ -5,6 +5,7 @@ import type { PocConfigView } from '@shared/poc'
|
|
|
5
5
|
import { ProxySection } from '@renderer/components/poc/PocConfigPanel'
|
|
6
6
|
import { useI18n } from '@renderer/i18n'
|
|
7
7
|
import { getApi } from '@renderer/lib/api'
|
|
8
|
+
import { getPortalContainer } from '../../../dsh/portal'
|
|
8
9
|
|
|
9
10
|
interface RetestProxyDialogProps {
|
|
10
11
|
open: boolean
|
|
@@ -43,8 +44,8 @@ export function RetestProxyDialog({ open, onOpenChange }: RetestProxyDialogProps
|
|
|
43
44
|
}, [open, t])
|
|
44
45
|
|
|
45
46
|
return (
|
|
46
|
-
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
|
47
|
-
<DialogPrimitive.Portal>
|
|
47
|
+
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange} modal={false}>
|
|
48
|
+
<DialogPrimitive.Portal container={getPortalContainer()}>
|
|
48
49
|
<DialogPrimitive.Overlay className="sheet-overlay fixed inset-0 z-[85] bg-[hsl(224_18%_10%/0.3)]" />
|
|
49
50
|
<DialogPrimitive.Content className="sheet-content fixed left-1/2 top-1/2 z-[90] flex max-h-[88vh] w-[calc(100vw-32px)] max-w-[560px] -translate-x-1/2 -translate-y-1/2 flex-col overflow-hidden rounded-xl border border-border bg-background">
|
|
50
51
|
<div className="flex shrink-0 items-start justify-between gap-3 border-b border-border px-5 py-4">
|
|
@@ -6,6 +6,7 @@ import type { SnapshotSession } from '@shared/types'
|
|
|
6
6
|
import { Button } from '@renderer/components/ui/button'
|
|
7
7
|
import { apiUnavailableMessage, getApi, toErrorMessage } from '@renderer/lib/api'
|
|
8
8
|
import { useI18n } from '@renderer/i18n'
|
|
9
|
+
import { getPortalContainer } from '../../../dsh/portal'
|
|
9
10
|
|
|
10
11
|
interface DeleteSnapshotDialogProps {
|
|
11
12
|
open: boolean
|
|
@@ -56,13 +57,14 @@ export function DeleteSnapshotDialog({
|
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
return (
|
|
59
|
-
<DialogPrimitive.Root
|
|
60
|
+
<DialogPrimitive.Root
|
|
61
|
+
modal={false}
|
|
60
62
|
open={open}
|
|
61
63
|
onOpenChange={(next) => {
|
|
62
64
|
if (!pending) onOpenChange(next)
|
|
63
65
|
}}
|
|
64
66
|
>
|
|
65
|
-
<DialogPrimitive.Portal>
|
|
67
|
+
<DialogPrimitive.Portal container={getPortalContainer()}>
|
|
66
68
|
<DialogPrimitive.Overlay className="sheet-overlay fixed inset-0 z-[70] bg-[hsl(224_18%_10%/0.3)]" />
|
|
67
69
|
<DialogPrimitive.Content className="fixed left-1/2 top-1/2 z-[70] w-[min(440px,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-border bg-background p-5 shadow-panel focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring">
|
|
68
70
|
<DialogPrimitive.Title className="text-[16px] font-medium tracking-tight text-foreground">
|
|
@@ -2,6 +2,7 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|
|
2
2
|
import { Loader2, Trash2 } from 'lucide-react'
|
|
3
3
|
import { Button } from '@renderer/components/ui/button'
|
|
4
4
|
import { useI18n } from '@renderer/i18n'
|
|
5
|
+
import { getPortalContainer } from '../../../dsh/portal'
|
|
5
6
|
|
|
6
7
|
interface BulkDeleteDialogProps {
|
|
7
8
|
open: boolean
|
|
@@ -22,8 +23,8 @@ export function BulkDeleteDialog({
|
|
|
22
23
|
const { t } = useI18n()
|
|
23
24
|
|
|
24
25
|
return (
|
|
25
|
-
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
|
26
|
-
<DialogPrimitive.Portal>
|
|
26
|
+
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange} modal={false}>
|
|
27
|
+
<DialogPrimitive.Portal container={getPortalContainer()}>
|
|
27
28
|
<DialogPrimitive.Overlay className="sheet-overlay fixed inset-0 z-[70] bg-[hsl(224_18%_10%/0.3)]" />
|
|
28
29
|
<DialogPrimitive.Content className="fixed left-1/2 top-1/2 z-[70] w-[min(420px,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-border bg-background p-5 shadow-panel focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring">
|
|
29
30
|
<DialogPrimitive.Title className="text-[16px] font-medium tracking-tight text-foreground">
|
|
@@ -2,6 +2,7 @@ import * as DialogPrimitive from '@radix-ui/react-dialog'
|
|
|
2
2
|
import { Loader2, Trash2 } from 'lucide-react'
|
|
3
3
|
import { Button } from '@renderer/components/ui/button'
|
|
4
4
|
import { useI18n } from '@renderer/i18n'
|
|
5
|
+
import { getPortalContainer } from '../../../dsh/portal'
|
|
5
6
|
|
|
6
7
|
interface ConfirmDeleteDialogProps {
|
|
7
8
|
open: boolean
|
|
@@ -22,8 +23,8 @@ export function ConfirmDeleteDialog({
|
|
|
22
23
|
const { t } = useI18n()
|
|
23
24
|
|
|
24
25
|
return (
|
|
25
|
-
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>
|
|
26
|
-
<DialogPrimitive.Portal>
|
|
26
|
+
<DialogPrimitive.Root open={open} onOpenChange={onOpenChange} modal={false}>
|
|
27
|
+
<DialogPrimitive.Portal container={getPortalContainer()}>
|
|
27
28
|
<DialogPrimitive.Overlay className="sheet-overlay fixed inset-0 z-[70] bg-[hsl(224_18%_10%/0.3)]" />
|
|
28
29
|
<DialogPrimitive.Content className="fixed left-1/2 top-1/2 z-[70] w-[min(420px,calc(100vw-2rem))] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-border bg-background p-5 shadow-panel focus:outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring">
|
|
29
30
|
<DialogPrimitive.Title className="text-[16px] font-medium tracking-tight text-foreground">
|
package/src/host/cortex/index.js
CHANGED
|
@@ -85,6 +85,9 @@ const ROUTES = [
|
|
|
85
85
|
|
|
86
86
|
{ pattern: /^\/snapshots$/, methods: { GET: snapshots.handleList } },
|
|
87
87
|
{ pattern: /^\/snapshots\/([^/]+)\/archive$/, methods: { POST: snapshots.handleArchive } },
|
|
88
|
+
// Both spellings exist: the vendored renderer's original Web API uses
|
|
89
|
+
// `/restore`, while the desktop contract names it `restore-previous`.
|
|
90
|
+
{ pattern: /^\/snapshots\/([^/]+)\/restore$/, methods: { POST: snapshots.handleRestorePrevious } },
|
|
88
91
|
{
|
|
89
92
|
pattern: /^\/snapshots\/([^/]+)\/restore-previous$/,
|
|
90
93
|
methods: { POST: snapshots.handleRestorePrevious },
|
|
@@ -132,19 +135,21 @@ function assertWriteFence(req, method) {
|
|
|
132
135
|
}
|
|
133
136
|
const headers = (req && req.headers) || {}
|
|
134
137
|
const origin = headers.origin
|
|
138
|
+
const fetchSite = String(headers['sec-fetch-site'] || '').trim().toLowerCase()
|
|
135
139
|
if (origin !== undefined && origin !== null && String(origin).trim().length > 0) {
|
|
136
140
|
if (!isLoopbackOrigin(String(origin))) {
|
|
137
|
-
|
|
141
|
+
// DSH renders the plugin from the custom `dsh-app://app` origin; its
|
|
142
|
+
// same-origin DELETE carries `Sec-Fetch-Site: same-origin`, which is the
|
|
143
|
+
// signal we trust (a cross-site page would report cross-site).
|
|
144
|
+
if (fetchSite !== 'same-origin' && fetchSite !== 'none') {
|
|
145
|
+
throw forbidden('FORBIDDEN_ORIGIN', 'write request origin is not allowed')
|
|
146
|
+
}
|
|
138
147
|
}
|
|
139
148
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
throw forbidden('FORBIDDEN_ORIGIN', 'cross-site write requests are not allowed', {
|
|
145
|
-
header: 'Sec-Fetch-Site',
|
|
146
|
-
})
|
|
147
|
-
}
|
|
149
|
+
if (fetchSite.length > 0 && fetchSite !== 'same-origin' && fetchSite !== 'none') {
|
|
150
|
+
throw forbidden('FORBIDDEN_ORIGIN', 'cross-site write requests are not allowed', {
|
|
151
|
+
header: 'Sec-Fetch-Site',
|
|
152
|
+
})
|
|
148
153
|
}
|
|
149
154
|
}
|
|
150
155
|
|
package/src/host/http.js
CHANGED
|
@@ -135,7 +135,14 @@ export function assertSameOriginWrite(req) {
|
|
|
135
135
|
const origin = headers.origin
|
|
136
136
|
if (origin !== undefined && origin !== null && String(origin).trim().length > 0) {
|
|
137
137
|
if (!isLoopbackOrigin(String(origin))) {
|
|
138
|
-
|
|
138
|
+
// The DSH page origin is the custom `dsh-app://app` scheme, not a
|
|
139
|
+
// loopback http(s) origin. Its same-origin fetch still carries
|
|
140
|
+
// `Sec-Fetch-Site: same-origin`; trust that rather than the scheme, so
|
|
141
|
+
// UI writes are not rejected while cross-site pages stay blocked.
|
|
142
|
+
const site = String(headers['sec-fetch-site'] || '').trim().toLowerCase()
|
|
143
|
+
if (site !== 'same-origin' && site !== 'none') {
|
|
144
|
+
throw forbidden('FORBIDDEN_ORIGIN', 'write request origin is not allowed')
|
|
145
|
+
}
|
|
139
146
|
}
|
|
140
147
|
}
|
|
141
148
|
|