feat(mesh): native-unicast DMs, contact import/remove, reachability, contact search
- DMs now use native meshcore unicast (CMD_SEND_TXT_MSG) instead of @DM2 channel broadcasts: private (E2E-encrypted to the recipient pubkey by firmware), off the public channel, and decodable by stock clients. Plain text (split, not MC-chunked) to non-archipelago contacts; typed envelopes to archy peers. - !ai replies now DM the asker privately (RadioDm) instead of broadcasting on ch0. - Auto contact-import: a heard advert (PUSH_CONTACT_ADVERT/0x80, 32-byte pubkey) is added via CMD_ADD_UPDATE_CONTACT (0x09) so contacts appear without a flood advert. - clear-all now DELETES firmware contacts via CMD_REMOVE_CONTACT (0x0F) instead of blocklisting; blocking filter removed entirely. Wiped contacts return when reachable. - Contact reachability: MeshPeer carries last_advert + reachable (path-based); UI shows a reachability dot. - Peers list: contact search box (filter by name/DID/npub/pubkey) with a clear button. - send_message routes stock contacts as plain native text (fixes garbled envelopes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9f2edf6b7a
commit
f0fdc23cc9
@@ -62,6 +62,32 @@ function toggleAllowed(pubkey: string) {
|
||||
apply({ allowed_contacts: allowedContacts.value })
|
||||
}
|
||||
|
||||
// Manually pasting a raw ed25519 pubkey (hex) — for an allowed asker that
|
||||
// isn't in the contact list yet (e.g. a phone/meshcore device).
|
||||
const newPubkey = ref('')
|
||||
const pubkeyError = ref('')
|
||||
// Allowlisted keys that aren't one of our known contacts (manually added).
|
||||
const extraAllowed = computed(() =>
|
||||
allowedContacts.value.filter(
|
||||
(k) => !contactOptions.value.some((c) => c.pubkey.toLowerCase() === k.toLowerCase()),
|
||||
),
|
||||
)
|
||||
function addPubkey() {
|
||||
const pk = newPubkey.value.trim().toLowerCase()
|
||||
pubkeyError.value = ''
|
||||
if (!/^[0-9a-f]{64}$/.test(pk)) {
|
||||
pubkeyError.value = 'Enter a 64-character hex ed25519 public key.'
|
||||
return
|
||||
}
|
||||
if (allowedContacts.value.some((k) => k.toLowerCase() === pk)) {
|
||||
newPubkey.value = ''
|
||||
return
|
||||
}
|
||||
allowedContacts.value = [...allowedContacts.value, pk]
|
||||
newPubkey.value = ''
|
||||
apply({ allowed_contacts: allowedContacts.value })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
mesh.fetchAssistantStatus()
|
||||
})
|
||||
@@ -206,7 +232,28 @@ function onPolicy() {
|
||||
<input type="checkbox" :checked="isAllowed(c.pubkey)" @change="toggleAllowed(c.pubkey)" />
|
||||
<span class="mesh-assistant-allow-name">{{ c.name }}</span>
|
||||
</label>
|
||||
<!-- Manually-added pubkeys not in the contact list -->
|
||||
<label
|
||||
v-for="pk in extraAllowed"
|
||||
:key="pk"
|
||||
class="mesh-assistant-allow-row"
|
||||
>
|
||||
<input type="checkbox" checked @change="toggleAllowed(pk)" />
|
||||
<span class="mesh-assistant-allow-name" :title="pk">{{ pk.slice(0, 10) }}… (added)</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Add an arbitrary pubkey directly -->
|
||||
<div class="mesh-assistant-addkey">
|
||||
<input
|
||||
v-model="newPubkey"
|
||||
class="mesh-bitcoin-input mesh-bitcoin-input-sm"
|
||||
placeholder="Paste an ed25519 pubkey (64 hex) to allow"
|
||||
@keyup.enter="addPubkey"
|
||||
/>
|
||||
<button type="button" class="glass-button mesh-bitcoin-input-sm" @click="addPubkey">Add</button>
|
||||
</div>
|
||||
<p v-if="pubkeyError" class="text-xs mt-1" style="color:#f87171">{{ pubkeyError }}</p>
|
||||
</div>
|
||||
|
||||
<p class="text-xs text-white/50 mt-2">
|
||||
|
||||
Reference in New Issue
Block a user