mirror of
https://github.com/outline/outline.git
synced 2026-06-13 11:25:03 +03:00
57b6e9aca4
closes #6930
203 lines
7.9 KiB
TypeScript
203 lines
7.9 KiB
TypeScript
import { generatePasskeyName } from "./passkeys";
|
|
|
|
describe("generatePasskeyName", () => {
|
|
describe("AAGUID-based brand detection", () => {
|
|
it("detects 1Password", () => {
|
|
const aaguid = "bada5566-a7aa-401f-bd96-45619a55120d";
|
|
const name = generatePasskeyName(aaguid);
|
|
expect(name).toBe("1Password");
|
|
});
|
|
|
|
it("detects Google Password Manager", () => {
|
|
const aaguid = "ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4";
|
|
const name = generatePasskeyName(aaguid);
|
|
expect(name).toBe("Google Password Manager");
|
|
});
|
|
|
|
it("detects Windows Hello", () => {
|
|
const aaguid = "08987058-cadc-4b81-b6e1-30de50dcbe96";
|
|
const name = generatePasskeyName(aaguid);
|
|
expect(name).toBe("Windows Hello");
|
|
});
|
|
|
|
it("detects iCloud Keychain (Managed)", () => {
|
|
const aaguid = "dd4ec289-e01d-41c9-bb89-70fa845d4bf2";
|
|
const name = generatePasskeyName(aaguid);
|
|
expect(name).toBe("iCloud Keychain (Managed)");
|
|
});
|
|
|
|
it("detects Bitwarden", () => {
|
|
const aaguid = "d548826e-79b4-db40-a3d8-11116f7e8349";
|
|
const name = generatePasskeyName(aaguid);
|
|
expect(name).toBe("Bitwarden");
|
|
});
|
|
|
|
it("prefers AAGUID over user agent", () => {
|
|
const aaguid = "bada5566-a7aa-401f-bd96-45619a55120d";
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(aaguid, ua, ["internal"]);
|
|
expect(name).toBe("1Password");
|
|
expect(name).not.toContain("Chrome");
|
|
});
|
|
|
|
it("falls back to user agent when AAGUID is unknown", () => {
|
|
const aaguid = "00000000-0000-0000-0000-000000000000";
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(aaguid, ua, ["internal"]);
|
|
expect(name).toBe("Chrome on macOS");
|
|
});
|
|
});
|
|
|
|
describe("browser detection", () => {
|
|
it("detects Chrome on macOS", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Chrome on macOS");
|
|
});
|
|
|
|
it("detects Safari on macOS", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Safari on macOS");
|
|
});
|
|
|
|
it("detects Firefox on Windows", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Firefox on Windows");
|
|
});
|
|
|
|
it("detects Edge on Windows", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Edge on Windows");
|
|
});
|
|
|
|
it("detects Opera on Linux", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 OPR/106.0.0.0";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Opera on Linux");
|
|
});
|
|
});
|
|
|
|
describe("device detection", () => {
|
|
it("detects iPhone", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("iPhone");
|
|
});
|
|
|
|
it("detects iPad", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (iPad; CPU OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("iPad");
|
|
});
|
|
|
|
it("detects Android Phone", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Android Phone");
|
|
});
|
|
|
|
it("detects Android Tablet", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Linux; Android 13; Pixel Tablet) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Android Tablet");
|
|
});
|
|
});
|
|
|
|
describe("OS detection", () => {
|
|
it("detects Chrome OS", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Chrome on Chrome OS");
|
|
});
|
|
|
|
it("detects Linux", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:120.0) Gecko/20100101 Firefox/120.0";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("Firefox on Linux");
|
|
});
|
|
});
|
|
|
|
describe("authenticator type detection", () => {
|
|
it("detects security key (USB)", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["usb"]);
|
|
expect(name).toContain("Security Key");
|
|
});
|
|
|
|
it("detects security key (NFC)", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["nfc"]);
|
|
expect(name).toContain("Security Key");
|
|
});
|
|
|
|
it("detects security key (BLE)", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["ble"]);
|
|
expect(name).toContain("Security Key");
|
|
});
|
|
|
|
it("detects hybrid authenticator (phone)", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, ["hybrid"]);
|
|
expect(name).toContain("Phone");
|
|
});
|
|
});
|
|
|
|
describe("edge cases", () => {
|
|
it("handles missing user agent", () => {
|
|
const name = generatePasskeyName(undefined, undefined, ["internal"]);
|
|
expect(name).toBe("Passkey");
|
|
});
|
|
|
|
it("handles empty user agent", () => {
|
|
const name = generatePasskeyName(undefined, "", ["usb"]);
|
|
expect(name).toBe("Security Key");
|
|
});
|
|
|
|
it("handles unknown user agent", () => {
|
|
const name = generatePasskeyName(undefined, "Unknown/1.0");
|
|
expect(name).toBe("Passkey");
|
|
});
|
|
|
|
it("handles missing transports", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36";
|
|
const name = generatePasskeyName(undefined, ua, []);
|
|
expect(name).toBe("Chrome on macOS");
|
|
});
|
|
|
|
it("handles no parameters", () => {
|
|
const name = generatePasskeyName();
|
|
expect(name).toBe("Passkey");
|
|
});
|
|
|
|
it("prioritizes device name over browser/OS", () => {
|
|
const ua =
|
|
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1";
|
|
const name = generatePasskeyName(undefined, ua, ["internal"]);
|
|
expect(name).toBe("iPhone");
|
|
expect(name).not.toContain("Safari");
|
|
});
|
|
});
|
|
});
|