85 lines
3.8 KiB
JavaScript
85 lines
3.8 KiB
JavaScript
// Certificate key selection mirrors XCA's unused-key filtering.
|
|
const { test, expect } = require("@playwright/test");
|
|
|
|
function unique(prefix) {
|
|
return `${prefix}-${Date.now()}-${Math.floor(Math.random() * 1000)}`;
|
|
}
|
|
|
|
async function field(page, label) {
|
|
return page.locator("label").filter({ hasText: label }).first().locator("..").locator("input, select, textarea").first();
|
|
}
|
|
|
|
async function login(page, username) {
|
|
await page.goto("/login");
|
|
await page.getByRole("link", { name: "Sign in with default" }).click();
|
|
await page.getByPlaceholder("Enter any user/subject").fill(username);
|
|
await page.getByRole("button", { name: "Sign-in" }).click();
|
|
await expect(page.getByRole("heading", { name: "Vaults" })).toBeVisible();
|
|
}
|
|
|
|
function existingKeySelect(page) {
|
|
return page.locator("label").filter({ hasText: "Existing key" }).locator("xpath=following-sibling::select[1]");
|
|
}
|
|
|
|
test("certificate key selection hides used keys unless requested", async ({ page }) => {
|
|
const user = unique("key-selection");
|
|
const vaultName = unique("Key Selection Vault");
|
|
const usedKeyName = unique("used-key");
|
|
const unusedKeyName = unique("unused-key");
|
|
const certName = unique("key-selection.example");
|
|
|
|
await login(page, user);
|
|
await page.getByRole("button", { name: "New vault" }).click();
|
|
await page.getByPlaceholder("Production PKI").fill(vaultName);
|
|
await page.getByRole("button", { name: "Create vault" }).click();
|
|
await page.getByRole("link", { name: vaultName }).click();
|
|
const vaultUrl = page.url();
|
|
|
|
for (const keyName of [usedKeyName, unusedKeyName]) {
|
|
await page.goto(`${vaultUrl}/keys/new`);
|
|
await (await field(page, "Internal name")).fill(keyName);
|
|
await page.getByRole("button", { name: "Generate key" }).click();
|
|
await expect(page.getByRole("heading", { name: keyName })).toBeVisible();
|
|
}
|
|
|
|
// Use one key in a certificate so subsequent forms can distinguish it.
|
|
await page.goto(`${vaultUrl}/certificates/new`);
|
|
let keySelect = existingKeySelect(page);
|
|
const usedKeyOption = keySelect.locator("option", { hasText: usedKeyName });
|
|
await expect(usedKeyOption).toHaveCount(1);
|
|
const usedKeyId = await usedKeyOption.getAttribute("value");
|
|
expect(usedKeyId).toBeTruthy();
|
|
await keySelect.selectOption(usedKeyId);
|
|
await (await field(page, "Internal name")).fill(certName);
|
|
await (await field(page, "Common name (CN)")).fill(certName);
|
|
await page.getByRole("button", { name: "Create certificate" }).click();
|
|
await expect(page.getByRole("heading", { name: certName })).toBeVisible();
|
|
const certUrl = page.url();
|
|
|
|
// Copying a certificate includes used keys and retains the original key.
|
|
await page.goto(`${certUrl}/similar`);
|
|
keySelect = existingKeySelect(page);
|
|
let includeUsed = page.getByLabel("Include used keys", { exact: true });
|
|
await expect(includeUsed).toBeChecked();
|
|
await expect(keySelect).toHaveValue(usedKeyId);
|
|
await expect(keySelect.locator("option", { hasText: usedKeyName })).toHaveCount(1);
|
|
|
|
// New certificates show only unused private keys by default.
|
|
await page.goto(`${vaultUrl}/certificates/new`);
|
|
keySelect = existingKeySelect(page);
|
|
includeUsed = page.getByLabel("Include used keys", { exact: true });
|
|
await expect(includeUsed).not.toBeChecked();
|
|
await expect(keySelect.locator("option", { hasText: unusedKeyName })).toHaveCount(1);
|
|
await expect(keySelect.locator("option", { hasText: usedKeyName })).toHaveCount(0);
|
|
|
|
await includeUsed.check();
|
|
await expect(keySelect.locator("option", { hasText: usedKeyName })).toHaveCount(1);
|
|
await expect(keySelect.locator("option", { hasText: unusedKeyName })).toHaveCount(1);
|
|
|
|
// Hiding a selected used key also clears the form value.
|
|
await keySelect.selectOption(usedKeyId);
|
|
await includeUsed.uncheck();
|
|
await expect(keySelect).toHaveValue("");
|
|
await expect(keySelect.locator("option", { hasText: usedKeyName })).toHaveCount(0);
|
|
});
|