From 0ce509a0fedaddf98e4da9c02ffcf438f58bc969 Mon Sep 17 00:00:00 2001 From: eezd Date: Wed, 21 Oct 2026 16:34:29 +0800 Subject: [PATCH] Finish shortcut dispatch and verify file operation safeguards --- internal/api/export_test.go | 14 ++++++++++++++ internal/vault/export.go | 3 +++ web/src/app/Sidebar.vue | 5 +++-- web/src/app/TabBar.vue | 5 +++-- web/src/app/commands.ts | 11 ++++++++++- web/src/app/workspace.test.ts | 21 ++++++++++++++++++++- 6 files changed, 53 insertions(+), 6 deletions(-) diff --git a/internal/api/export_test.go b/internal/api/export_test.go index 2840861..967da01 100644 --- a/internal/api/export_test.go +++ b/internal/api/export_test.go @@ -71,3 +71,17 @@ func TestExportRejectsMissingAssetsAndSymlinks(t *testing.T) { t.Fatalf("应拒绝符号链接:%d", response.StatusCode) } } + +func TestReadTokenMayExportButCannotWrite(t *testing.T) { + f := newFixture(t) + f.write("文章.md", "原文") + token := decode[struct{ Token string }](t, f.do(f.admin, "POST", "/api/v1/tokens", `{"name":"只读导出","scope":"read"}`, nil)) + headers := map[string]string{"Authorization": "Bearer " + token.Token} + guest := newClient() + if code := f.status(guest, "POST", "/api/v1/export", `{"paths":["文章.md"]}`, headers); code != 200 { + t.Fatalf("只读导出被拒绝:%d", code) + } + if code := f.status(guest, "POST", "/api/v1/move", `{"from":"文章.md","to":"其他.md"}`, headers); code != 403 { + t.Fatalf("只读令牌获得写权限:%d", code) + } +} diff --git a/internal/vault/export.go b/internal/vault/export.go index 5f9675c..a9c40bd 100644 --- a/internal/vault/export.go +++ b/internal/vault/export.go @@ -63,6 +63,9 @@ func (v *Vault) Export(ctx context.Context, paths []string) (result *os.File, na } var linkError error transformMarkdownLines(content, importRef, func(line []byte) []byte { + if linkError != nil { + return line + } return transformOutsideCode(line, func(text []byte) []byte { for _, span := range importLinkSpans(text) { target := string(text[span.start:span.end]) diff --git a/web/src/app/Sidebar.vue b/web/src/app/Sidebar.vue index 621dc35..6830cd5 100644 --- a/web/src/app/Sidebar.vue +++ b/web/src/app/Sidebar.vue @@ -2,6 +2,7 @@ import { computed, ref, watch } from 'vue' import Icon from './Icon.vue' import { basename } from './paths' +import { commandTitle } from './commands' import { tree } from './tree' import TreeNode from './TreeNode.vue' import SearchPanel from './SearchPanel.vue' @@ -40,7 +41,7 @@ function onRootDrop(e: DragEvent) {
RawMark - @@ -64,7 +65,7 @@ function onRootDrop(e: DragEvent) {
- +
diff --git a/web/src/app/TabBar.vue b/web/src/app/TabBar.vue index ae789de..bad06cf 100644 --- a/web/src/app/TabBar.vue +++ b/web/src/app/TabBar.vue @@ -1,5 +1,6 @@