fix(pairing): warn that pairing links grant daemon access (#3734)

A pairing offer remains valid across daemon restarts, so remove the incorrect rotation guidance and warn users where the durable credential is displayed.
This commit is contained in:
Mohamed Boudra
2026-08-23 12:32:21 +02:00
committed by GitHub
parent 5123b23f41
commit 8d92e1cc17
14 changed files with 27 additions and 3 deletions
@@ -113,6 +113,11 @@ export async function enableRelayAndExpectOffer(page: Page): Promise<void> {
export async function expectPairingOffer(page: Page): Promise<void> {
await expect(page.getByRole("img", { name: "Pairing QR code" })).toBeVisible();
await expect(page.getByRole("textbox", { name: "Pairing link" })).toHaveValue(/#offer=/);
await expect(
page.getByRole("alert").filter({
hasText: "Treat this pairing link like a password. Anyone with it can access this daemon.",
}),
).toBeVisible();
await expect(page.getByRole("button", { name: "Copy", exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Enable relay", exact: true })).toHaveCount(0);
}
@@ -262,6 +262,7 @@ function PairingOffer(props: PairDeviceBodyProps & { offer: { url: string } }) {
{props.copied ? t("pairing.device.copied") : t("pairing.device.copy")}
</Button>
</View>
<Alert variant="warning" description={t("pairing.device.securityWarning")} />
</View>
);
}
+2
View File
@@ -1630,6 +1630,8 @@ export const ar: TranslationResources = {
updateRequired: "حدّث المضيف لتمكين التتابع من Paseo Desktop.",
unavailable: "عرض الاقتران غير متاح.",
hint: "قم بمسح رمز QR هذا باستخدام Paseo على هاتفك، أو انسخ الرابط أدناه.",
securityWarning:
"تعامل مع رابط الاقتران هذا ككلمة مرور. يمكن لأي شخص يملكه الوصول إلى هذا البرنامج الخفي.",
qrUnavailable: "رمز QR غير متاح.",
qrAccessibility: "رمز QR للإقران",
retry: "أعد المحاولة",
+2
View File
@@ -1640,6 +1640,8 @@ export const en = {
updateRequired: "Update the host to enable relay from Paseo Desktop.",
unavailable: "Pairing offer unavailable.",
hint: "Scan this QR code with Paseo on your phone, or copy the link below.",
securityWarning:
"Treat this pairing link like a password. Anyone with it can access this daemon.",
qrUnavailable: "QR code unavailable.",
qrAccessibility: "Pairing QR code",
retry: "Retry",
+2
View File
@@ -1676,6 +1676,8 @@ export const es: TranslationResources = {
updateRequired: "Actualice el host para habilitar el relé desde Paseo Desktop.",
unavailable: "Oferta de maridaje no disponible.",
hint: "Escanee este códigoQRconPaseoen su teléfono o copie el enlace a continuación.",
securityWarning:
"Trata este enlace de emparejamiento como una contraseña. Cualquiera que lo tenga puede acceder a este daemon.",
qrUnavailable: "CódigoQRno disponible.",
qrAccessibility: "Código QR de emparejamiento",
retry: "Rever",
+2
View File
@@ -1680,6 +1680,8 @@ export const fr: TranslationResources = {
updateRequired: "Mettez à jour l’hôte pour activer le relais depuis Paseo Desktop.",
unavailable: "Offre de jumelage indisponible.",
hint: "Scannez ce codeQRavecPaseosur votre téléphone ou copiez le lien ci-dessous.",
securityWarning:
"Traitez ce lien d’association comme un mot de passe. Toute personne qui le possède peut accéder à ce daemon.",
qrUnavailable: "CodeQRindisponible.",
qrAccessibility: "Code QR de couplage",
retry: "Réessayer",
+2
View File
@@ -1647,6 +1647,8 @@ export const ja: TranslationResources = {
updateRequired: "Paseo Desktop からリレーを有効にするにはホストを更新してください。",
unavailable: "ペアリングオファーが利用できません。",
hint: "スマートフォンのPaseoでこのQRコードをスキャンするか、以下のリンクをコピーしてください。",
securityWarning:
"このペアリングリンクはパスワードと同様に扱ってください。リンクを知っている人は誰でもこのデーモンにアクセスできます。",
qrUnavailable: "QRコードが利用できません。",
qrAccessibility: "ペアリング QR コード",
retry: "再試行",
+2
View File
@@ -1640,6 +1640,8 @@ export const ko: TranslationResources = {
updateRequired: "Paseo 데스크톱에서 릴레이를 활성화하려면 호스트를 업데이트하세요.",
unavailable: "페어링 정보를 사용할 수 없습니다.",
hint: "휴대폰의 Paseo로 이 QR 코드를 스캔하거나 아래 링크를 복사하세요.",
securityWarning:
"이 페어링 링크는 비밀번호처럼 취급하세요. 링크를 가진 사람은 누구나 이 데몬에 접근할 수 있습니다.",
qrUnavailable: "QR 코드를 사용할 수 없습니다.",
qrAccessibility: "페어링 QR 코드",
retry: "다시 시도",
+2
View File
@@ -1662,6 +1662,8 @@ export const ptBR: TranslationResources = {
updateRequired: "Atualize o host para ativar o relay pelo Paseo Desktop.",
unavailable: "Oferta de pareamento indisponível.",
hint: "Escaneie este QR code com o Paseo no seu celular ou copie o link abaixo.",
securityWarning:
"Trate este link de pareamento como uma senha. Qualquer pessoa com o link pode acessar este daemon.",
qrUnavailable: "QR code indisponível.",
qrAccessibility: "Código QR de pareamento",
retry: "Tentar novamente",
+2
View File
@@ -1660,6 +1660,8 @@ export const ru: TranslationResources = {
updateRequired: "Обновите хост, чтобы включить ретранслятор из Paseo Desktop.",
unavailable: "Данные для сопряжения недоступны.",
hint: "Отсканируйте этот QR-код с помощью Paseo на телефоне или скопируйте ссылку ниже.",
securityWarning:
"Обращайтесь с этой ссылкой для сопряжения как с паролем. Любой, у кого она есть, может получить доступ к этому демону.",
qrUnavailable: "QR-код недоступен.",
qrAccessibility: "QR-код сопряжения",
retry: "Повторить попытку",
+1
View File
@@ -1610,6 +1610,7 @@ export const zhCN: TranslationResources = {
updateRequired: "请更新主机,以便从 Paseo Desktop 启用中继。",
unavailable: "配对 offer 不可用。",
hint: "用手机上的 Paseo 扫描此二维码,或复制下方链接。",
securityWarning: "请像保管密码一样保管此配对链接。任何获得此链接的人都可以访问此守护进程。",
qrUnavailable: "二维码不可用。",
qrAccessibility: "配对二维码",
retry: "重试",
+3
View File
@@ -10,6 +10,9 @@ describe("formatPairingInstructions", () => {
expect(output).toContain(QR);
expect(output.split("\n")).toContain(URL);
expect(output).toContain(
"Treat this pairing link like a password. Anyone with it can access this daemon.",
);
});
it("does not print a QR that would reach the terminal edge", () => {
+1 -1
View File
@@ -33,5 +33,5 @@ function formatQr(qr: string | null, columns: number | undefined): string {
}
export function formatPairingInstructions({ url, qr, columns }: PairingInstructions): string {
return `\nScan to pair:\n${formatQr(qr, columns)}\n\nPairing link:\n${url}\n`;
return `\nScan to pair:\n${formatQr(qr, columns)}\n\nPairing link:\n${url}\n\nTreat this pairing link like a password. Anyone with it can access this daemon.\n`;
}