FIX - share phone contacts through EasyShare

Load the server-canonical own contact instead of constructing an unsupported profile payload in the Phone app. Move canonical contact resolution before payload sanitization so self-contact transfers are validated and received correctly, with a regression contract test.
This commit is contained in:
smx.pusha
2026-08-14 19:51:15 +02:00
parent adaa2a3eef
commit 6cdbe753ad
3 changed files with 46 additions and 30 deletions
@@ -0,0 +1,15 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
const source = readFileSync(new URL('./PhoneApp.vue', import.meta.url), 'utf8')
describe('PhoneApp EasyShare contract', () => {
it('loads the server-canonical own contact instead of creating a profile payload', () => {
expect(source).toContain(
"nuiCall<EasySharePayload>('easyshare:own-contact')",
)
expect(source).toContain('easyShare.open(response.data)')
expect(source).not.toContain("kind: 'profile'")
})
})
+12 -11
View File
@@ -49,7 +49,9 @@ import { useEasyShareStore } from '@/stores/easyshare'
import { useMessageMediaStore } from '@/stores/messageMedia'
import { useMessagesStore } from '@/stores/messages'
import { usePhoneStore } from '@/stores/phone'
import type { EasySharePayload } from '@/types/easyshare'
import type { PhoneContact, RecentCall } from '@/types/phone'
import { nuiCall } from '@/utils/nui'
import { formatPhoneNumber, normalizePhoneNumber } from '@/utils/phone'
type PhoneTab = 'recents' | 'contacts' | 'keypad'
@@ -526,17 +528,16 @@ function shareSelectedContact(): void {
})
}
function shareOwnProfile(): void {
const number = phone.device?.sim?.number
if (!number) return
easyShare.open({
appId: 'phone',
copyText: `${phone.t('Apps.phone.myCard')}\n${number}`,
kind: 'profile',
link: `skyphone://phone/${number}`,
subtitle: formatPhoneNumber(number),
title: phone.t('Apps.phone.myCard'),
})
async function shareOwnProfile(): Promise<void> {
const response = await nuiCall<EasySharePayload>('easyshare:own-contact')
if (!response.success || !response.data) {
error.value = phone.t(
`Apps.easyShare.errors.${response.error ?? 'request_failed'}`,
)
return
}
error.value = ''
easyShare.open(response.data)
}
function messageActiveCaller(): void {
+19 -19
View File
@@ -598,6 +598,25 @@ local function nearby_targets(source, device)
return targets
end
local function canonical_own_contact(source, device)
if not device.phone_number then
return nil
end
local name = display_name(source)
return {
appId = "phone",
kind = "contact",
id = "self",
title = name,
subtitle = device.phone_number,
copyText = ("%s\n%s"):format(name, device.phone_number),
meta = {
name = name,
phoneNumber = device.phone_number,
},
}
end
local function sanitize_payload(source, device, data)
if type(data) ~= "table" or not valid_kinds[data.kind] then
return nil, "invalid_payload"
@@ -882,25 +901,6 @@ local function apply_received_payload(transfer)
return true
end
local function canonical_own_contact(source, device)
if not device.phone_number then
return nil
end
local name = display_name(source)
return {
appId = "phone",
kind = "contact",
id = "self",
title = name,
subtitle = device.phone_number,
copyText = ("%s\n%s"):format(name, device.phone_number),
meta = {
name = name,
phoneNumber = device.phone_number,
},
}
end
local function advance_transfer(id)
local transfer = active_transfers[id]
if not transfer or transfer.status ~= "transferring" then