Files
LinkPort/web/tests/decryption.spec.ts

153 lines
9.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect, type Locator } from '@playwright/test';
import { createCipheriv } from 'node:crypto';
async function expectChoice(panel: Locator, name: string, value: string) {
await expect(selectControl(panel, name)).toContainText(value);
}
function selectControl(panel: Locator, name: string) {
return panel.locator('.el-select').filter({ has: panel.page().getByRole('combobox', { name, exact: true }) });
}
test('Navicat 两种密码格式、输入校验、清空与离开页面', async ({ page }) => {
// Verify the clipboard payload without depending on desktop clipboard access.
await page.addInitScript(() => {
Object.defineProperty(navigator, 'clipboard', { value: {
writeText: async (text: string) => { (window as Window & { copiedPassword?: string }).copiedPassword = text; },
} });
});
await page.goto('/');
const navigation = page.getByRole('navigation');
await navigation.getByRole('button', { name: '密码解密', exact: true }).click();
const panel = page.getByRole('region', { name: '密码解密工具', exact: true });
await expectChoice(panel, '解密算法', 'AES');
await expectChoice(panel, '分组模式', 'CBC');
await expectChoice(panel, '填充方式', 'PKCS7');
await expect(panel.getByRole('textbox', { name: 'Key 密钥', exact: true })).toHaveValue('libcckeylibcckey');
await expect(panel.getByRole('textbox', { name: 'IV 向量', exact: true })).toHaveValue('libcciv libcciv ');
await expect(panel.getByTestId('iv-length')).toContainText('16 字节');
const ciphertext = panel.getByRole('textbox', { name: '十六进制密文', exact: true });
const result = panel.getByRole('textbox', { name: '解密结果', exact: true });
await ciphertext.fill(' \nf03a1418eb2928a948cc8c71d92edf1c\n');
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(result).toHaveValue('密码🔑 test');
await panel.getByRole('button', { name: '复制密码', exact: true }).click();
await expect(page.getByText('解密密码已复制', { exact: true })).toBeVisible();
expect(await page.evaluate(() => (window as Window & { copiedPassword?: string }).copiedPassword)).toBe('密码🔑 test');
await page.screenshot({ path: 'test-results/navicat-desktop.png', fullPage: true });
await panel.getByText('Navicat 11(Blowfish)', { exact: true }).click();
await expect(result).toHaveCount(0);
await ciphertext.fill('9AA92D8A5BDCB3F746');
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(result).toHaveValue('123456789');
await ciphertext.fill('xyz');
await expect(result).toHaveCount(0);
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('alert')).toContainText('十六进制字符');
await ciphertext.fill('a');
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('alert')).toContainText('偶数');
await panel.getByRole('button', { name: '清空', exact: true }).click();
await expect(ciphertext).toHaveValue('');
await expect(panel.getByRole('alert')).toHaveCount(0);
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByText('解密成功:密码为空。')).toBeVisible();
await panel.getByText('Navicat 12(AES)', { exact: true }).click();
await ciphertext.fill('0'.repeat(32));
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('alert')).toContainText('解密失败');
await navigation.getByRole('button', { name: '网关服务', exact: false }).click();
await navigation.getByRole('button', { name: '密码解密', exact: true }).click();
await expect(ciphertext).toHaveValue('');
await expect(result).toHaveCount(0);
for (const viewport of [{ width: 320, height: 568 }, { width: 390, height: 844 }, { width: 768, height: 640 }, { width: 1920, height: 1080 }]) {
await page.setViewportSize(viewport);
await expect(panel).toBeVisible();
const choices = panel.getByRole('radiogroup');
expect(await choices.evaluate(el => el.scrollWidth <= el.clientWidth)).toBe(true);
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true);
await navigation.getByRole('button', { name: '密码解密', exact: true }).click();
if (viewport.width === 390) await page.screenshot({ path: 'test-results/navicat-mobile.png', fullPage: true });
}
});
test('修改或清空输入后忽略迟到的解密结果', async ({ page }) => {
let release!: () => void;
const gate = new Promise<void>(resolve => { release = resolve; });
await page.route('**/api/v1/tools/decrypt', async route => {
await gate;
await route.fulfill({ json: { plaintext: 'stale-result' } });
});
await page.goto('/');
await page.getByRole('navigation').getByRole('button', { name: '密码解密', exact: true }).click();
const panel = page.getByRole('region', { name: '密码解密工具' });
await panel.getByRole('textbox', { name: '十六进制密文' }).fill('e191af42327478cc5f143ef279ec4d81');
const requested = page.waitForRequest('**/api/v1/tools/decrypt');
await panel.getByRole('button', { name: '解密', exact: true }).click();
await requested;
await panel.getByRole('button', { name: '清空', exact: true }).click();
const completed = page.waitForResponse('**/api/v1/tools/decrypt');
release();
await completed;
await expect(panel.getByRole('textbox', { name: '解密结果' })).toHaveCount(0);
});
test('自定义参数真实参与解密,切换 Navicat 12 恢复预设', async ({ page }) => {
const key = 'custom-key-12345';
const iv = 'custom-iv-123456';
const cipher = createCipheriv('aes-128-cbc', Buffer.from(key), Buffer.from(iv));
const encrypted = Buffer.concat([cipher.update('自定义参数 test'), cipher.final()]).toString('base64');
await page.goto('/');
const navigation = page.getByRole('navigation');
await navigation.getByRole('button', { name: '密码解密', exact: true }).click();
const panel = page.getByRole('region', { name: '密码解密工具' });
const select = async (name: string, option: string) => {
await selectControl(panel, name).click();
const listbox = await panel.getByRole('combobox', { name, exact: true }).getAttribute('aria-controls');
await page.locator(`[id="${listbox}"]`).getByRole('option', { name: option, exact: true }).click();
};
await panel.getByRole('textbox', { name: 'Key 密钥', exact: true }).fill(key);
await expect(panel.getByRole('radio', { name: '自定义', exact: true })).toBeChecked();
await panel.getByRole('textbox', { name: 'IV 向量', exact: true }).fill(iv);
await select('密文编码', 'Base64');
await panel.getByRole('textbox', { name: 'Base64 密文', exact: true }).fill(encrypted);
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('textbox', { name: '解密结果', exact: true })).toHaveValue('自定义参数 test');
await panel.getByRole('textbox', { name: 'IV 向量', exact: true }).fill('short');
await expect(panel.getByRole('textbox', { name: '解密结果', exact: true })).toHaveCount(0);
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('alert')).toContainText('IV 必须为 16 字节');
await select('分组模式', 'CTR');
await expectChoice(panel, '填充方式', 'NoPadding(无填充)');
await select('Key 编码', 'Hex(十六进制)');
await select('IV 编码', 'Hex(十六进制)');
await select('密文编码', 'Hex(十六进制)');
await select('结果编码', 'Hex(十六进制)');
await panel.getByRole('textbox', { name: 'Key 密钥', exact: true }).fill('2b7e151628aed2a6abf7158809cf4f3c');
await panel.getByRole('textbox', { name: 'IV 向量', exact: true }).fill('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff');
await panel.getByRole('textbox', { name: '十六进制密文', exact: true }).fill('874d6191b620e3261bef6864990db6ce');
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('textbox', { name: '解密结果', exact: true })).toHaveValue('6bc1bee22e409f96e93d7e117393172a');
await select('分组模式', 'ECB');
await expect(panel.getByRole('textbox', { name: 'IV 向量', exact: true })).toHaveCount(0);
await panel.getByRole('textbox', { name: '十六进制密文', exact: true }).fill('3ad77bb40d7a3660a89ecaf32466ef97');
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('textbox', { name: '解密结果', exact: true })).toHaveValue('6bc1bee22e409f96e93d7e117393172a');
await panel.getByText('Navicat 12(AES)', { exact: true }).click();
await expectChoice(panel, '分组模式', 'CBC');
await expectChoice(panel, '填充方式', 'PKCS7');
await expect(panel.getByRole('textbox', { name: 'Key 密钥', exact: true })).toHaveValue('libcckeylibcckey');
await expect(panel.getByRole('textbox', { name: 'IV 向量', exact: true })).toHaveValue('libcciv libcciv ');
await panel.getByRole('textbox', { name: '十六进制密文', exact: true }).fill('f03a1418eb2928a948cc8c71d92edf1c');
await panel.getByRole('button', { name: '解密', exact: true }).click();
await expect(panel.getByRole('textbox', { name: '解密结果', exact: true })).toHaveValue('密码🔑 test');
expect(await page.evaluate(() => JSON.stringify(localStorage))).not.toContain(key);
await panel.getByRole('textbox', { name: 'Key 密钥', exact: true }).fill(key);
await navigation.getByRole('button', { name: /网关服务/ }).click();
await navigation.getByRole('button', { name: '密码解密', exact: true }).click();
await expect(panel.getByRole('textbox', { name: 'Key 密钥', exact: true })).toHaveValue('libcckeylibcckey');
});