mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
fix(mobile): use paired ports in firewall help (#36130)
* fix(mobile): use paired ports in firewall help * fix(mobile): use a namespace type in diagnostics test
This commit is contained in:
@@ -104,6 +104,23 @@ The mobile terminal has a dedicated **Terminal settings** screen (Settings → T
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Firewalls and Orca Relay
|
||||
|
||||
For Orca Relay and sign-in, allow outbound TCP port `443` from the desktop and phone to these hosts:
|
||||
|
||||
| Host | Purpose | Protocol |
|
||||
| -------------------------------------------------------------------------------- | --------------------------------------------- | --------------------------------- |
|
||||
| `login.onorca.dev` | Orca sign-in and Relay credentials | HTTPS |
|
||||
| `auth.onorca.dev` | Hosted sign-in pages | HTTPS |
|
||||
| `relay.onorca.dev` | Relay director, which assigns a regional cell | HTTPS and secure WebSockets (WSS) |
|
||||
| `*.relay.onorca.dev`, including `c1.relay.onorca.dev` and `c27.relay.onorca.dev` | Regional Relay cells | HTTPS and secure WebSockets (WSS) |
|
||||
|
||||
Allow WebSocket upgrades and long-lived connections to both `relay.onorca.dev` and the Relay cells. Cell assignments can change, so allow the cell hostname pattern as well as the director. Relay uses outbound connections; it does not need an inbound port or router port forwarding.
|
||||
|
||||
For a direct LAN or Tailscale connection, allow the paired desktop's listening port instead. The default is `6768`, but a desktop using another port needs that port allowed. **Settings → Troubleshooting** shows the paired endpoint's port in its firewall advice.
|
||||
|
||||
### Common issues
|
||||
|
||||
- **Stuck spinner on a worktree** — the phone tracks a heartbeat from the desktop agent process. If the desktop says idle but the phone shows working, force-refresh the worktree row to sync state.
|
||||
- **Pairing fails** — make sure your desktop and phone are signed into the same Orca account. Pairing codes expire after a few minutes; generate a fresh one if it's been sitting on the screen.
|
||||
- **Authentication failed / pairing invalid** — the desktop no longer accepts this device token (for example after desktop cleared paired devices). Try **Retry** on the banner first (transient rejections can recover without re-pairing). If it keeps failing, use **Re-pair** from desktop, or **Remove** the host and pair again.
|
||||
|
||||
@@ -10,12 +10,14 @@ const isDevelopmentBuild = typeof __DEV__ !== 'undefined' && __DEV__
|
||||
|
||||
export default function NativeTroubleshootRoute() {
|
||||
const router = useRouter()
|
||||
const { rootRef, diagnosticStatus, checks, runDiagnostics } = useTroubleshootDiagnostics()
|
||||
const { rootRef, diagnosticStatus, checks, hostEndpoints, runDiagnostics } =
|
||||
useTroubleshootDiagnostics()
|
||||
return (
|
||||
<TroubleshootView
|
||||
rootRef={rootRef}
|
||||
diagnosticStatus={diagnosticStatus}
|
||||
checks={checks}
|
||||
hostEndpoints={hostEndpoints}
|
||||
runDiagnostics={() => void runDiagnostics()}
|
||||
onBack={() => router.back()}
|
||||
onConnectionLog={() => router.push('/connection-log')}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { SUPPORTED_UI_LOCALES } from '../../../src/shared/ui-locale'
|
||||
import { activateMobileUiLocale, translate } from '../i18n/mobile-i18n'
|
||||
import { troubleshootCommonIssues } from './troubleshoot-common-issues'
|
||||
|
||||
vi.mock('lucide-react-native', () => ({
|
||||
WifiOff: () => null,
|
||||
Shield: () => null,
|
||||
Monitor: () => null,
|
||||
Clock: () => null,
|
||||
Globe: () => null,
|
||||
Bell: () => null
|
||||
}))
|
||||
|
||||
afterEach(() => activateMobileUiLocale('en'))
|
||||
|
||||
describe('troubleshooting firewall advice', () => {
|
||||
it.each([
|
||||
{ endpoints: ['ws://192.168.1.10:6769'], ports: ['6769'] },
|
||||
{ endpoints: ['ws://[fd7a:115c:a1e0::1]:7777'], ports: ['7777'] },
|
||||
{ endpoints: ['wss://desktop.example', 'ws://desktop.local'], ports: ['443', '80'] },
|
||||
{ endpoints: [], ports: ['6768'] },
|
||||
{ endpoints: ['invalid endpoint'], ports: ['6768'] },
|
||||
{
|
||||
endpoints: ['ws://first.local:6769', 'ws://second.local:7777', 'ws://third.local:6769'],
|
||||
ports: ['6769', '7777']
|
||||
}
|
||||
])('uses paired ports for $endpoints', ({ endpoints, ports }) => {
|
||||
const sections = troubleshootCommonIssues(translate, endpoints).filter((section) =>
|
||||
section.id.startsWith('firewall')
|
||||
)
|
||||
expect(sections.map((section) => section.title)).toEqual(
|
||||
ports.map((port) => `Firewall Blocking Port ${port}`)
|
||||
)
|
||||
expect(sections.map((section) => section.steps.find((step) => step.includes('ufw')))).toEqual(
|
||||
ports.map((port) => `Linux: sudo ufw allow ${port}`)
|
||||
)
|
||||
expect(new Set(sections.map((section) => section.id)).size).toBe(ports.length)
|
||||
})
|
||||
|
||||
it.each(SUPPORTED_UI_LOCALES)('interpolates the paired port in %s', async (locale) => {
|
||||
await activateMobileUiLocale(locale)
|
||||
const section = troubleshootCommonIssues(translate, ['ws://desktop.local:6769']).find((entry) =>
|
||||
entry.id.startsWith('firewall')
|
||||
)
|
||||
expect(section?.title).toContain('6769')
|
||||
expect(section?.title).not.toContain('6768')
|
||||
expect(section?.steps.some((step) => step.includes('sudo ufw allow 6769'))).toBe(true)
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,6 @@
|
||||
import { WifiOff, Shield, Monitor, Clock, Globe, Bell, type LucideIcon } from 'lucide-react-native'
|
||||
import type { Translate } from '../i18n/mobile-i18n'
|
||||
import { endpointPort } from '../transport/host-endpoint'
|
||||
|
||||
export type TroubleshootSection = {
|
||||
id: string
|
||||
@@ -8,7 +9,33 @@ export type TroubleshootSection = {
|
||||
steps: string[]
|
||||
}
|
||||
|
||||
export function troubleshootCommonIssues(t: Translate): TroubleshootSection[] {
|
||||
export function troubleshootCommonIssues(
|
||||
t: Translate,
|
||||
endpoints: readonly string[] = []
|
||||
): TroubleshootSection[] {
|
||||
const ports = new Set(
|
||||
endpoints.map((endpoint) => {
|
||||
const port = endpointPort(endpoint)
|
||||
if (port) {
|
||||
return port
|
||||
}
|
||||
try {
|
||||
const url = new URL(endpoint)
|
||||
if (url.protocol === 'wss:') {
|
||||
return '443'
|
||||
}
|
||||
if (url.protocol === 'ws:') {
|
||||
return '80'
|
||||
}
|
||||
} catch {
|
||||
// Unreadable legacy endpoints keep the default firewall advice.
|
||||
}
|
||||
return '6768'
|
||||
})
|
||||
)
|
||||
if (ports.size === 0) {
|
||||
ports.add('6768')
|
||||
}
|
||||
return [
|
||||
{
|
||||
id: 'notifications',
|
||||
@@ -45,10 +72,16 @@ export function troubleshootCommonIssues(t: Translate): TroubleshootSection[] {
|
||||
)
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'firewall',
|
||||
...Array.from(ports, (port) => ({
|
||||
id: `firewall-${port}`,
|
||||
icon: Shield,
|
||||
title: t('diagnostics.troubleshootCommonIssues.firewallTitle', 'Firewall Blocking Port 6768'),
|
||||
title: t(
|
||||
'diagnostics.troubleshootCommonIssues.firewallTitle',
|
||||
'Firewall Blocking Port {{port}}',
|
||||
{
|
||||
port
|
||||
}
|
||||
),
|
||||
steps: [
|
||||
t(
|
||||
'diagnostics.troubleshootCommonIssues.macosFirewall',
|
||||
@@ -58,13 +91,15 @@ export function troubleshootCommonIssues(t: Translate): TroubleshootSection[] {
|
||||
'diagnostics.troubleshootCommonIssues.windowsFirewall',
|
||||
'Windows: Defender Firewall → Allow app — enable Orca for Private networks.'
|
||||
),
|
||||
'Linux: sudo ufw allow 6768',
|
||||
t('diagnostics.troubleshootCommonIssues.linuxFirewall', 'Linux: sudo ufw allow {{port}}', {
|
||||
port
|
||||
}),
|
||||
t(
|
||||
'diagnostics.troubleshootCommonIssues.restrictedNetwork',
|
||||
'Corporate/school networks may block P2P — try a personal hotspot.'
|
||||
)
|
||||
]
|
||||
},
|
||||
})),
|
||||
{
|
||||
id: 'desktop',
|
||||
icon: Monitor,
|
||||
|
||||
@@ -40,6 +40,7 @@ export function TroubleshootView({
|
||||
rootRef,
|
||||
diagnosticStatus,
|
||||
checks,
|
||||
hostEndpoints,
|
||||
runDiagnostics,
|
||||
onBack,
|
||||
onConnectionLog,
|
||||
@@ -48,6 +49,7 @@ export function TroubleshootView({
|
||||
rootRef?: (node: View | null) => void
|
||||
diagnosticStatus: DiagnosticStatus
|
||||
checks: CheckResult[]
|
||||
hostEndpoints: readonly string[]
|
||||
runDiagnostics: () => void
|
||||
onBack: () => void
|
||||
onConnectionLog: () => void
|
||||
@@ -146,7 +148,7 @@ export function TroubleshootView({
|
||||
</Text>
|
||||
|
||||
<View style={styles.section}>
|
||||
{troubleshootCommonIssues(t).map((section, i) => (
|
||||
{troubleshootCommonIssues(t, hostEndpoints).map((section, i) => (
|
||||
<View key={section.id}>
|
||||
{i > 0 && <View style={styles.separator} />}
|
||||
<Pressable
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { createElement } from 'react'
|
||||
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type * as HostReachability from './host-reachability'
|
||||
|
||||
const hosts = vi.hoisted(() => ({
|
||||
catalog: vi.fn<() => Promise<{ endpoint: string }[]>>(),
|
||||
profiles: vi.fn<() => Promise<{ name: string; endpoint: string }[]>>()
|
||||
}))
|
||||
vi.mock('react-native', () => ({ Platform: { OS: 'ios', Version: '27' } }))
|
||||
vi.mock('../transport/host-store', () => ({
|
||||
loadHostCatalog: hosts.catalog,
|
||||
loadHosts: hosts.profiles
|
||||
}))
|
||||
vi.mock('./host-reachability', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof HostReachability>()),
|
||||
testHostReachability: async () => true
|
||||
}))
|
||||
|
||||
import { useTroubleshootDiagnostics } from './use-troubleshoot-diagnostics'
|
||||
|
||||
let tree: ReactTestRenderer | undefined
|
||||
const state: { current: ReturnType<typeof useTroubleshootDiagnostics> | null } = { current: null }
|
||||
function Harness() {
|
||||
state.current = useTroubleshootDiagnostics()
|
||||
return null
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
await act(async () => tree?.unmount())
|
||||
state.current = null
|
||||
vi.resetAllMocks()
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
describe('troubleshooting paired endpoints', () => {
|
||||
it('loads endpoint advice before the user runs diagnostics', async () => {
|
||||
hosts.catalog.mockResolvedValue([{ endpoint: 'ws://desktop.local:6769' }])
|
||||
await act(async () => {
|
||||
tree = create(createElement(Harness))
|
||||
})
|
||||
expect(state.current?.diagnosticStatus).toBe('idle')
|
||||
expect(state.current?.hostEndpoints).toEqual(['ws://desktop.local:6769'])
|
||||
})
|
||||
|
||||
it('keeps the newly probed endpoints when the initial catalog read finishes later', async () => {
|
||||
let finishCatalog: (value: { endpoint: string }[]) => void = () => {}
|
||||
hosts.catalog
|
||||
.mockReturnValueOnce(
|
||||
new Promise((resolve) => {
|
||||
finishCatalog = resolve
|
||||
})
|
||||
)
|
||||
.mockResolvedValue([{ endpoint: 'ws://desktop.local:7777' }])
|
||||
hosts.profiles.mockResolvedValue([{ name: 'Desktop', endpoint: 'ws://desktop.local:7777' }])
|
||||
vi.stubGlobal('fetch', async () => ({ ok: true }))
|
||||
await act(async () => {
|
||||
tree = create(createElement(Harness))
|
||||
})
|
||||
await act(async () => {
|
||||
await state.current?.runDiagnostics()
|
||||
})
|
||||
await act(async () => {
|
||||
finishCatalog([{ endpoint: 'ws://desktop.local:6769' }])
|
||||
})
|
||||
expect(state.current?.hostEndpoints).toEqual(['ws://desktop.local:7777'])
|
||||
expect(state.current?.checks).toContainEqual({
|
||||
label: 'Desktop',
|
||||
status: 'pass',
|
||||
detail: 'Reachable at desktop.local:7777'
|
||||
})
|
||||
})
|
||||
|
||||
it('retains saved port advice after a run when the host credential is unavailable', async () => {
|
||||
hosts.catalog.mockResolvedValue([{ endpoint: 'ws://desktop.local:6769' }])
|
||||
hosts.profiles.mockResolvedValue([])
|
||||
vi.stubGlobal('fetch', async () => ({ ok: true }))
|
||||
await act(async () => {
|
||||
tree = create(createElement(Harness))
|
||||
})
|
||||
expect(state.current?.hostEndpoints).toEqual(['ws://desktop.local:6769'])
|
||||
await act(async () => {
|
||||
await state.current?.runDiagnostics()
|
||||
})
|
||||
expect(state.current?.hostEndpoints).toEqual(['ws://desktop.local:6769'])
|
||||
})
|
||||
})
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import type { View } from 'react-native'
|
||||
import { Platform } from 'react-native'
|
||||
import { useMobileTranslation } from '../i18n/use-mobile-translation'
|
||||
import { loadHosts } from '../transport/host-store'
|
||||
import { loadHostCatalog, loadHosts } from '../transport/host-store'
|
||||
import {
|
||||
startDiagnosticFetchTimeout,
|
||||
type DiagnosticFetchTimeout
|
||||
@@ -14,10 +14,29 @@ export function useTroubleshootDiagnostics() {
|
||||
const t = useMobileTranslation()
|
||||
const [diagnosticStatus, setDiagnosticStatus] = useState<DiagnosticStatus>('idle')
|
||||
const [checks, setChecks] = useState<CheckResult[]>([])
|
||||
const [hostEndpoints, setHostEndpoints] = useState<string[]>([])
|
||||
const abortRef = useRef(false)
|
||||
const diagnosticRunRef = useRef(0)
|
||||
const activeInternetCheckRef = useRef<DiagnosticFetchTimeout | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
let disposed = false
|
||||
const initialRunId = diagnosticRunRef.current
|
||||
void loadHostCatalog().then(
|
||||
(hosts) => {
|
||||
if (!disposed && diagnosticRunRef.current === initialRunId) {
|
||||
setHostEndpoints(hosts.map((host) => host.endpoint))
|
||||
}
|
||||
},
|
||||
() => {
|
||||
// Keep default advice when the saved host catalog cannot be read.
|
||||
}
|
||||
)
|
||||
return () => {
|
||||
disposed = true
|
||||
}
|
||||
}, [])
|
||||
|
||||
const rootRef = useCallback((node: View | null): void => {
|
||||
if (node !== null) {
|
||||
return
|
||||
@@ -42,7 +61,11 @@ export function useTroubleshootDiagnostics() {
|
||||
const isCurrentRun = () => !abortRef.current && diagnosticRunRef.current === runId
|
||||
|
||||
try {
|
||||
const hosts = await loadHosts()
|
||||
const [hosts, catalog] = await Promise.all([loadHosts(), loadHostCatalog()])
|
||||
if (!isCurrentRun()) {
|
||||
return
|
||||
}
|
||||
setHostEndpoints(catalog.map((host) => host.endpoint))
|
||||
results.push(
|
||||
hosts.length > 0
|
||||
? {
|
||||
@@ -166,5 +189,5 @@ export function useTroubleshootDiagnostics() {
|
||||
setDiagnosticStatus('done')
|
||||
}, [t])
|
||||
|
||||
return { rootRef, diagnosticStatus, checks, runDiagnostics }
|
||||
return { rootRef, diagnosticStatus, checks, hostEndpoints, runDiagnostics }
|
||||
}
|
||||
|
||||
@@ -1102,7 +1102,8 @@
|
||||
"checkTailnet": "Prüfen, ob der Computer nicht im Ruhezustand ist und im Tailnet als verbunden angezeigt wird.",
|
||||
"desktopTitle": "Desktop-App läuft nicht",
|
||||
"disableVpn": "Dieses VPN deaktivieren oder Split-Tunneling / „Allow LAN“ aktivieren.",
|
||||
"firewallTitle": "Firewall blockiert Port 6768",
|
||||
"firewallTitle": "Firewall blockiert Port {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "Host-Adressen wie 100.x.x.x oder *.ts.net nutzen Tailscale – Tailscale eingeschaltet lassen.",
|
||||
"macosFirewall": "macOS: System Settings → Network → Firewall – Orca zulassen.",
|
||||
"notificationNetwork": "Mobilfunk oder ein anderes WLAN ausprobieren. Treffen Benachrichtigungen nach dem Wechsel ein, verzögert das ursprüngliche Netzwerk möglicherweise die Zustellung.",
|
||||
|
||||
@@ -361,7 +361,8 @@
|
||||
"sameNetwork": "Both devices must be on the same LAN (unless connected through Tailscale).",
|
||||
"sameSubnet": "Ethernet and WiFi must share the same subnet.",
|
||||
"reconnectWifi": "Try reconnecting WiFi on both devices.",
|
||||
"firewallTitle": "Firewall Blocking Port 6768",
|
||||
"firewallTitle": "Firewall Blocking Port {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"macosFirewall": "macOS: System Settings → Network → Firewall — allow Orca.",
|
||||
"windowsFirewall": "Windows: Defender Firewall → Allow app — enable Orca for Private networks.",
|
||||
"restrictedNetwork": "Corporate/school networks may block P2P — try a personal hotspot.",
|
||||
|
||||
@@ -1145,7 +1145,8 @@
|
||||
"checkTailnet": "Comprueba que el escritorio esté activo y aparezca conectado en tu red de Tailscale.",
|
||||
"desktopTitle": "App de escritorio cerrada",
|
||||
"disableVpn": "Desactiva esa VPN o activa la tunelización dividida / \"Allow LAN\".",
|
||||
"firewallTitle": "El cortafuegos bloquea el puerto 6768",
|
||||
"firewallTitle": "El cortafuegos bloquea el puerto {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "Las direcciones de host como 100.x.x.x o *.ts.net se conectan a través de Tailscale — mantenlo ACTIVADO.",
|
||||
"macosFirewall": "macOS: Ajustes del Sistema → Red → Firewall — permite las conexiones de Orca.",
|
||||
"notificationNetwork": "Prueba con datos móviles u otra red Wi-Fi. Si las alertas llegan tras cambiar de red, es posible que tu red esté retrasando la entrega.",
|
||||
|
||||
@@ -1145,7 +1145,8 @@
|
||||
"checkTailnet": "Vérifiez que l'ordinateur n'est pas en veille et apparaît connecté à votre tailnet.",
|
||||
"desktopTitle": "Application de bureau arrêtée",
|
||||
"disableVpn": "Désactivez ce VPN ou activez le routage fractionné / « Autoriser le LAN ».",
|
||||
"firewallTitle": "Pare-feu bloquant le port 6768",
|
||||
"firewallTitle": "Pare-feu bloquant le port {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "Les adresses d'hôte comme 100.x.x.x ou *.ts.net passent par Tailscale — laissez-le ACTIVÉ.",
|
||||
"macosFirewall": "macOS : Réglages Système → Réseau → Pare-feu — autorisez Orca.",
|
||||
"notificationNetwork": "Essayez les données mobiles ou un autre réseau Wi-Fi. Si les alertes arrivent après ce changement, votre réseau retarde peut-être leur réception.",
|
||||
|
||||
@@ -1098,7 +1098,8 @@
|
||||
"checkTailnet": "デスクトップがスリープ状態になっておらず、tailnet 内で接続済みと表示されていることを確認してください。",
|
||||
"desktopTitle": "デスクトップアプリが未起動",
|
||||
"disableVpn": "その VPN を無効にするか、スプリットトンネリングまたは「LAN を許可」を有効にしてください。",
|
||||
"firewallTitle": "ファイアウォールがポート 6768 をブロック",
|
||||
"firewallTitle": "ファイアウォールがポート {{port}} をブロック",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "100.x.x.x や *.ts.net のようなホストアドレスには Tailscale 経由で接続します。Tailscale をオンにしておいてください。",
|
||||
"macosFirewall": "macOS: 「システム設定」→「ネットワーク」→「ファイアウォール」で Orca を許可してください。",
|
||||
"notificationNetwork": "モバイルデータ通信か別の Wi-Fi ネットワークを試してください。切り替え後に通知が届く場合は、元のネットワークで配信が遅れている可能性があります。",
|
||||
|
||||
@@ -1098,7 +1098,8 @@
|
||||
"checkTailnet": "데스크톱이 절전 모드가 아니며 tailnet에 연결된 상태로 표시되는지 확인하세요.",
|
||||
"desktopTitle": "데스크톱 앱이 실행되지 않음",
|
||||
"disableVpn": "해당 VPN을 끄거나 분할 터널링 / \"LAN 허용\"을 켜세요.",
|
||||
"firewallTitle": "방화벽에서 포트 6768 차단",
|
||||
"firewallTitle": "방화벽에서 포트 {{port}} 차단",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "100.x.x.x나 *.ts.net 같은 호스트 주소는 Tailscale을 통해 연결되므로 Tailscale을 켜 두세요.",
|
||||
"macosFirewall": "macOS: 시스템 설정 → 네트워크 → 방화벽에서 Orca를 허용하세요.",
|
||||
"notificationNetwork": "모바일 데이터나 다른 Wi-Fi 네트워크를 사용해 보세요. 전환 후 알림이 도착한다면 기존 네트워크에서 알림 전달이 지연되고 있을 수 있습니다.",
|
||||
|
||||
@@ -1145,7 +1145,8 @@
|
||||
"checkTailnet": "Verifique se o desktop está fora do modo de suspensão e aparece como conectado na sua tailnet.",
|
||||
"desktopTitle": "App desktop não está em execução",
|
||||
"disableVpn": "Desative essa VPN ou ative o tunelamento dividido / \"Permitir LAN\".",
|
||||
"firewallTitle": "Firewall bloqueando a porta 6768",
|
||||
"firewallTitle": "Firewall bloqueando a porta {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "Hosts com endereços como 100.x.x.x ou *.ts.net se conectam via Tailscale — mantenha-o ATIVADO.",
|
||||
"macosFirewall": "macOS: Ajustes do Sistema → Rede → Firewall — permita o Orca.",
|
||||
"notificationNetwork": "Tente usar os dados móveis ou outra rede Wi-Fi. Se os alertas chegarem após a troca, sua rede pode estar atrasando a entrega.",
|
||||
|
||||
@@ -1188,7 +1188,8 @@
|
||||
"checkTailnet": "Убедитесь, что компьютер не спит и отображается как подключённый в вашей сети tailnet.",
|
||||
"desktopTitle": "Приложение на компьютере не запущено",
|
||||
"disableVpn": "Отключите этот VPN или включите раздельное туннелирование / «Разрешить LAN».",
|
||||
"firewallTitle": "Брандмауэр блокирует порт 6768",
|
||||
"firewallTitle": "Брандмауэр блокирует порт {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "Адреса серверов вида 100.x.x.x или *.ts.net доступны через Tailscale — оставьте его ВКЛЮЧЁННЫМ.",
|
||||
"macosFirewall": "macOS: Системные настройки → Сеть → Брандмауэр — разрешите подключения для Orca.",
|
||||
"notificationNetwork": "Переключитесь на мобильную сеть или другую сеть Wi-Fi. Если уведомления начнут приходить, возможно, ваша сеть задерживает их доставку.",
|
||||
|
||||
@@ -1102,7 +1102,8 @@
|
||||
"checkTailnet": "Bilgisayarınızın uyku modunda olmadığını ve tailnet ağınızda bağlı göründüğünü kontrol edin.",
|
||||
"desktopTitle": "Masaüstü Uygulaması Çalışmıyor",
|
||||
"disableVpn": "Bu VPN'i devre dışı bırakın veya bölünmüş tünellemeyi / \"Allow LAN\" seçeneğini etkinleştirin.",
|
||||
"firewallTitle": "Güvenlik Duvarı 6768 Portunu Engelliyor",
|
||||
"firewallTitle": "Güvenlik Duvarı {{port}} Portunu Engelliyor",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "100.x.x.x veya *.ts.net gibi sunucu adreslerine Tailscale üzerinden bağlanılır — Tailscale'i AÇIK tutun.",
|
||||
"macosFirewall": "macOS: System Settings → Network → Firewall — Orca'ya izin verin.",
|
||||
"notificationNetwork": "Hücresel bağlantıyı veya başka bir Wi-Fi ağını deneyin. Ağ değiştirdikten sonra bildirimler geliyorsa ağınız iletimi geciktiriyor olabilir.",
|
||||
|
||||
@@ -1098,7 +1098,8 @@
|
||||
"checkTailnet": "確認電腦未進入睡眠,且在您的 tailnet 中顯示為已連線。",
|
||||
"desktopTitle": "桌面版應用程式未執行",
|
||||
"disableVpn": "停用該 VPN,或啟用分割通道/「允許 LAN」。",
|
||||
"firewallTitle": "防火牆封鎖連接埠 6768",
|
||||
"firewallTitle": "防火牆封鎖連接埠 {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "100.x.x.x 或 *.ts.net 等主機位址會透過 Tailscale 連線,請保持 Tailscale 開啟。",
|
||||
"macosFirewall": "macOS:「系統設定」→「網路」→「防火牆」,允許 Orca 連線。",
|
||||
"notificationNetwork": "試著改用行動網路或其他 Wi-Fi 網路。若切換後能收到通知,原本的網路可能導致通知延遲送達。",
|
||||
|
||||
@@ -1098,7 +1098,8 @@
|
||||
"checkTailnet": "确认桌面未休眠,并在 tailnet 中显示为已连接。",
|
||||
"desktopTitle": "桌面应用未运行",
|
||||
"disableVpn": "关闭该 VPN,或启用分流功能/“允许 LAN”选项。",
|
||||
"firewallTitle": "防火墙拦截端口 6768",
|
||||
"firewallTitle": "防火墙拦截端口 {{port}}",
|
||||
"linuxFirewall": "Linux: sudo ufw allow {{port}}",
|
||||
"keepTailscaleOn": "100.x.x.x 或 *.ts.net 等主机地址通过 Tailscale 连接,请保持 Tailscale 开启。",
|
||||
"macosFirewall": "macOS:系统设置 → 网络 → 防火墙,允许 Orca 通过。",
|
||||
"notificationNetwork": "尝试切换到蜂窝网络或其他 Wi-Fi 网络。如果切换后能收到通知,则原网络可能导致通知延迟。",
|
||||
|
||||
Reference in New Issue
Block a user