feat(plugins): bridge clipboard reads with consent gate
This commit is contained in:
1 parent
1335ec032c
commit
92f92f6cdb
18 files changed
+424
-12
No files matched your search
@@ -2,6 +2,7 @@
|
||||
import { computed, defineComponent, h, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
import { ArrowUp, BadgeCheck, Check, ChevronRight, CircleAlert, Download, ExternalLink, FileUp, FolderTree, Globe, Info, LayoutGrid, Link2, List, Loader2, PackageCheck, Pencil, Pin, PinOff, Plus, RefreshCw, RotateCcw, Search, Settings2, ShieldCheck, Store, Trash2 } from "@lucide/vue";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { isSensitivePluginPermission } from "@/lib/plugins/pluginPermissions";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
@@ -1039,7 +1040,16 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<div class="mt-3 flex flex-wrap gap-1.5">
|
||||
<Badge v-for="tag in listing.plugin.tags.slice(0, 3)" :key="tag" variant="outline" class="h-5 px-1.5 text-[10px]">{{ tag }}</Badge>
|
||||
<Badge v-if="listing.plugin.permissions.length" variant="outline" class="h-5 px-1.5 text-[10px]">{{ t("pluginPlatform.permissionsCount", { count: listing.plugin.permissions.length }) }}</Badge>
|
||||
<!-- Real permission strings, not a count badge: sensitive ones (clipboard read, …)
|
||||
highlight in the destructive variant so a user sees the risk surface before
|
||||
installing; the rest stay muted. -->
|
||||
<Tooltip :delay-duration="300">
|
||||
<TooltipTrigger as-child>
|
||||
<Badge v-if="listing.plugin.permissions.length" variant="outline" class="h-5 px-1.5 font-mono text-[10px]">{{ listing.plugin.permissions.join(" · ") }}</Badge>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" class="max-w-md break-all font-mono text-[11px]">{{ listing.plugin.permissions.join("\n") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Badge v-for="permission in listing.plugin.permissions" :key="permission" v-show="isSensitivePluginPermission(permission)" variant="destructive" class="h-5 px-1.5 font-mono text-[10px]" :data-sensitive-permission="permission">{{ permission }}</Badge>
|
||||
</div>
|
||||
<Tooltip :delay-duration="700">
|
||||
<TooltipTrigger as-child>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { computed, inject, nextTick, onBeforeUnmount, onMounted, ref, watch } fr
|
||||
import { AlertTriangle, Loader2 } from "@lucide/vue";
|
||||
import * as api from "@/lib/backend/api";
|
||||
import { isTauriRuntime } from "@/lib/backend/tauriRuntime";
|
||||
import { copyToClipboard } from "@/lib/common/clipboard";
|
||||
import { copyToClipboard, readTextFromClipboard } from "@/lib/common/clipboard";
|
||||
import {
|
||||
PluginHostBridge,
|
||||
pluginSandboxDocument,
|
||||
@@ -404,6 +404,15 @@ function createBridge() {
|
||||
downloadFile: isTauriRuntime() ? downloadPluginFile : undefined,
|
||||
cancelDownload: isTauriRuntime() ? cancelPluginDownload : undefined,
|
||||
copyText: (_pluginId, text) => copyToClipboard(text),
|
||||
// Permission-gated in the bridge (host.clipboard:read); the helper
|
||||
// prefers the Tauri clipboard plugin and falls back to the Web Clipboard.
|
||||
clipboardRead: (_pluginId) => readTextFromClipboard(),
|
||||
// Session consent for the first clipboard read: a native ask dialog naming
|
||||
// the plugin, so reads always have a human in the loop. On the web host
|
||||
// (no dialog surface) the callback is omitted and the bridge denies.
|
||||
confirmClipboardRead: isTauriRuntime()
|
||||
? (_pluginId, pluginName) => import("@tauri-apps/plugin-dialog").then(({ ask }) => ask(t("pluginPlatform.clipboardReadConsent", { name: pluginName }), { title: t("pluginPlatform.clipboardReadConsentTitle"), kind: "warning" }).then((allowed) => allowed === true))
|
||||
: undefined,
|
||||
pickFiles: (pluginId, options) => pickPluginFiles(pluginId, options),
|
||||
readFileChunk: (pluginId, handleId, offset, length) => readPluginFileChunkById(pluginId, handleId, offset, length),
|
||||
beginFileSave: (pluginId, request) => beginPluginFileSave(pluginId, request),
|
||||
|
||||
Reference in new issue
Block a user