feat: trust peer

This commit is contained in:
2026-02-07 03:17:37 +08:00
parent d8ffc5eea5
commit f3adb56bd0
19 changed files with 438 additions and 155 deletions

View File

@@ -66,12 +66,10 @@ onMounted(async () => {
// --- 后端集成 & 事件监听 ---
onMounted(async () => {
peers.value = await GetPeers();
peers.value = peers.value.sort((a, b) => a.name.localeCompare(b.name));
});
Events.On("peers:update", (event) => {
peers.value = event.data;
peers.value = peers.value.sort((a, b) => a.name.localeCompare(b.name));
});
Events.On("transfer:refreshList", async () => {

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
// --- Vue 核心 ---
import { computed, ref, watch } from "vue";
import { computed, ref, watch, onMounted } from "vue";
// --- 组件 ---
import FileSendModal from "./modals/FileSendModal.vue";
@@ -13,6 +13,20 @@ import {
SendText,
} from "../../bindings/mesh-drop/internal/transfer/service";
import { Peer } from "../../bindings/mesh-drop/internal/discovery/models";
import {
IsTrustedPeer,
AddTrustedPeer,
RemoveTrustedPeer,
} from "../../bindings/mesh-drop/internal/config/config";
// --- 生命周期 ---
onMounted(async () => {
try {
isTrusted.value = await IsTrustedPeer(props.peer.id);
} catch (err) {
console.error("Failed to check trusted peer status:", err);
}
});
// --- 属性 & 事件 ---
const props = defineProps<{
@@ -27,6 +41,7 @@ const emit = defineEmits<{
const selectedIp = ref<string>("");
const showFileModal = ref(false);
const showTextModal = ref(false);
const isTrusted = ref(false);
const sendOptions = [
{
@@ -136,10 +151,20 @@ const handleSendClipboard = async () => {
});
emit("transferStarted");
};
const handleTrust = () => {
AddTrustedPeer(props.peer.id, props.peer.pk);
isTrusted.value = true;
};
const handleUntrust = () => {
RemoveTrustedPeer(props.peer.id);
isTrusted.value = false;
};
</script>
<template>
<v-card hover link class="peer-card pa-2">
<v-card hover link class="peer-card pa-2" :ripple="false">
<template #title>
<div class="d-flex align-center">
<v-icon :icon="osIcon" size="24" class="mr-2"></v-icon>
@@ -187,12 +212,25 @@ const handleSendClipboard = async () => {
</div>
</template>
<template #actions>
<v-menu>
<v-card-actions>
<!-- Trust Mismatch Warning -->
<v-btn
v-if="peer.trust_mismatch"
class="flex-grow-1"
color="warning"
variant="tonal"
prepend-icon="mdi-alert"
:ripple="false"
style="pointer-events: none"
>
Mismatch
</v-btn>
<v-menu v-else>
<template #activator="{ props }">
<v-btn
v-bind="props"
block
class="flex-grow-1"
color="primary"
variant="tonal"
:disabled="ips.length === 0"
@@ -218,7 +256,32 @@ const handleSendClipboard = async () => {
</v-list-item>
</v-list>
</v-menu>
</template>
<!-- Trust Mismatch Reset Override -->
<v-btn
v-if="peer.trust_mismatch"
variant="tonal"
color="error"
@click="handleUntrust"
>
<v-icon icon="mdi-delete"></v-icon>
<v-tooltip activator="parent" location="bottom">Reset Trust</v-tooltip>
</v-btn>
<v-btn
v-else-if="!isTrusted"
variant="tonal"
color="primary"
@click="handleTrust"
>
<v-icon icon="mdi-star-outline"></v-icon>
<v-tooltip activator="parent" location="bottom">Trust peer</v-tooltip>
</v-btn>
<v-btn v-else variant="tonal" color="primary" @click="handleUntrust">
<v-icon icon="mdi-star"></v-icon>
<v-tooltip activator="parent" location="bottom">Untrust peer</v-tooltip>
</v-btn>
</v-card-actions>
</v-card>
<!-- Modals -->

View File

@@ -187,9 +187,23 @@ const handleCopy = async () => {
v-if="
props.transfer.sender.name && props.transfer.type === 'receive'
"
prepend-icon="mdi-account"
:color="
props.transfer.sender.trust_mismatch ? 'warning' : undefined
"
:prepend-icon="
props.transfer.sender.trust_mismatch
? 'mdi-alert'
: 'mdi-account'
"
>
{{ props.transfer.sender.name }}
<v-tooltip
v-if="props.transfer.sender.trust_mismatch"
activator="parent"
location="bottom"
>
Security Alert: Key Mismatch
</v-tooltip>
</v-chip>
<v-chip

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
// --- Vue 核心 ---
import { computed, ref } from "vue";
import { computed, ref, watch, nextTick } from "vue";
// --- Wails & 后端绑定 ---
import { SendText } from "../../../bindings/mesh-drop/internal/transfer/service";
@@ -20,6 +20,7 @@ const emit = defineEmits<{
// --- 状态 ---
const textContent = ref("");
const textareaRef = ref();
// --- 计算属性 ---
const show = computed({
@@ -27,6 +28,14 @@ const show = computed({
set: (value) => emit("update:modelValue", value),
});
// --- 监听 ---
watch(show, async (val) => {
if (val) {
await nextTick();
textareaRef.value?.focus();
}
});
// --- 方法 ---
const executeSendText = async () => {
if (!props.selectedIp || !textContent.value) return;
@@ -48,6 +57,7 @@ const executeSendText = async () => {
<v-card title="Send Text">
<v-card-text>
<v-textarea
ref="textareaRef"
v-model="textContent"
label="Content"
placeholder="Type something to send..."