Files
orca/src/shared/ssh-pty-id.ts
T

55 lines
1.7 KiB
TypeScript

const SSH_PTY_ID_PREFIX = 'ssh:'
const SSH_PTY_ID_SEPARATOR = '@@'
// Why: SSH relays allocate target-local ids like "pty-1"; app-wide routing
// needs the target id embedded so two relays cannot collide after restore.
export type ParsedSshPtyId = {
connectionId: string
relayPtyId: string
}
export function parseAppSshPtyId(ptyId: string): ParsedSshPtyId | null {
if (!ptyId.startsWith(SSH_PTY_ID_PREFIX)) {
return null
}
const separatorIndex = ptyId.indexOf(SSH_PTY_ID_SEPARATOR, SSH_PTY_ID_PREFIX.length)
if (separatorIndex === -1) {
return null
}
const encodedConnectionId = ptyId.slice(SSH_PTY_ID_PREFIX.length, separatorIndex)
const relayPtyId = ptyId.slice(separatorIndex + SSH_PTY_ID_SEPARATOR.length)
if (!encodedConnectionId || !relayPtyId) {
return null
}
try {
return {
connectionId: decodeURIComponent(encodedConnectionId),
relayPtyId
}
} catch {
return null
}
}
export function toAppSshPtyId(connectionId: string, relayPtyId: string): string {
const parsed = parseAppSshPtyId(relayPtyId)
if (parsed) {
if (parsed.connectionId !== connectionId) {
throw new Error(`PTY ${relayPtyId} belongs to SSH connection "${parsed.connectionId}"`)
}
return relayPtyId
}
return `${SSH_PTY_ID_PREFIX}${encodeURIComponent(connectionId)}${SSH_PTY_ID_SEPARATOR}${relayPtyId}`
}
export function toRelaySshPtyId(connectionId: string, ptyId: string): string {
const parsed = parseAppSshPtyId(ptyId)
if (!parsed) {
return ptyId
}
if (parsed.connectionId !== connectionId) {
throw new Error(`PTY ${ptyId} belongs to SSH connection "${parsed.connectionId}"`)
}
return parsed.relayPtyId
}