feat(mobile): bind device identities and bound voice usage in 0.1.4 dev
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { normalizeFingerprint, assertRemoteIdentity, loadDeviceIdentity } from './peer-identity.mjs'
|
||||
export const GATEWAY = 'https://turkservis.online'
|
||||
async function accountFetch(url, options) {
|
||||
const plugin = globalThis.Capacitor?.Plugins?.MobileSecrets
|
||||
@@ -103,10 +104,21 @@ export function rtcConfiguration(iceServers = []) {
|
||||
}
|
||||
|
||||
export async function openPhoneConnection(account, desktopId, onEvent, iceServers = []) {
|
||||
// Never obtain this trust anchor from the signaling response. It came from
|
||||
// the QR physically displayed by the desktop and is stored in the phone vault.
|
||||
const trusted = account.credentials?.desktopFingerprints
|
||||
if (!trusted || !Object.hasOwn(trusted, desktopId))
|
||||
throw new Error('Bu bilgisayarın güvenilen cihaz kimliği yok. Bilgisayarda yeni QR oluşturup yeniden eşleştirin.')
|
||||
const fingerprint = normalizeFingerprint(trusted[desktopId])
|
||||
const identity = await loadDeviceIdentity(account.credentials.deviceId, account.credentials.localFingerprint)
|
||||
if (!iceServers.length) iceServers = (await account.call('/v1/aiturk/mobile/ice')).iceServers
|
||||
const pc = new RTCPeerConnection(rtcConfiguration(iceServers))
|
||||
const pc = new RTCPeerConnection({ ...rtcConfiguration(iceServers), certificates: [identity.certificate] })
|
||||
const channel = pc.createDataChannel('aiturk-mobile-v1', { ordered: true })
|
||||
const requests = new DataRequests(channel, onEvent)
|
||||
let established = false
|
||||
const requests = new DataRequests(channel, frame => {
|
||||
// Failed handshakes surface their actual error, not a later generic close.
|
||||
if (established || frame.event !== 'disconnected') onEvent(frame)
|
||||
})
|
||||
const id = crypto.randomUUID()
|
||||
let heartbeat, closed = false
|
||||
const close = () => { closed = true; clearInterval(heartbeat); channel.close(); pc.close() }
|
||||
@@ -115,7 +127,10 @@ export async function openPhoneConnection(account, desktopId, onEvent, iceServer
|
||||
await account.call('/v1/aiturk/mobile/channels', { channel_id: id, desktop_id: desktopId, sdp: pc.localDescription.sdp })
|
||||
for (let attempt = 0; attempt < 35 && !closed; attempt++) {
|
||||
const answer = await account.call(`/v1/aiturk/mobile/channels/${id}`)
|
||||
if (answer.sdp) { await pc.setRemoteDescription({ type: 'answer', sdp: answer.sdp }); break }
|
||||
if (answer.sdp) {
|
||||
assertRemoteIdentity(answer.sdp, fingerprint)
|
||||
await pc.setRemoteDescription({ type: 'answer', sdp: answer.sdp }); break
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 1500))
|
||||
}
|
||||
await new Promise((resolve, reject) => {
|
||||
@@ -125,6 +140,7 @@ export async function openPhoneConnection(account, desktopId, onEvent, iceServer
|
||||
channel.addEventListener('close', () => { clearTimeout(timer); reject(new Error('Bağlantı kapandı.')) }, { once: true })
|
||||
})
|
||||
heartbeat = setInterval(() => { void account.call(`/v1/aiturk/mobile/channels/${id}/heartbeat`, {}).catch(close) }, 15000)
|
||||
established = true
|
||||
return { requests, close, pc, id }
|
||||
} catch (error) { close(); throw error }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user