fix: handle registration keys on headscale 0.29+

Closes HP-555.
This commit is contained in:
Aarnav Tale
2026-07-04 00:07:53 -04:00
parent 990e1e9ff5
commit 948cfad58c
11 changed files with 206 additions and 15 deletions
@@ -82,6 +82,7 @@ describe("capabilitiesFor", () => {
preAuthKeysHaveStableIds: true,
nodeTagsAreFlat: true,
nodeOwnerIsImmutable: true,
registerKeyIncludesAuthReqPrefix: false,
});
});
@@ -91,10 +92,16 @@ describe("capabilitiesFor", () => {
);
});
test("0.29.0 enables the prefixed AuthID register key", () => {
const caps = capabilitiesFor(parseServerVersion("0.29.0"));
expect(caps.registerKeyIncludesAuthReqPrefix).toBe(true);
});
test("0.27.1 lacks every 0.28-gated capability", () => {
const caps = capabilitiesFor(parseServerVersion("0.27.1"));
expect(caps.preAuthKeysHaveStableIds).toBe(false);
expect(caps.nodeTagsAreFlat).toBe(false);
expect(caps.nodeOwnerIsImmutable).toBe(false);
expect(caps.registerKeyIncludesAuthReqPrefix).toBe(false);
});
});
+57
View File
@@ -0,0 +1,57 @@
import { describe, expect, test } from "vitest";
import { normalizeRegistrationKey } from "~/utils/register-key";
const suffix = "ABCDEFGHIJKLMNOPQRSTUVWX";
const key = `hskey-authreq-${suffix}`;
const legacyKey = "mkey:0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
describe("normalizeRegistrationKey", () => {
test("keeps full registration keys", () => {
expect(normalizeRegistrationKey(key)).toBe(key);
});
test("keeps legacy machine keys", () => {
expect(normalizeRegistrationKey(legacyKey)).toBe(legacyKey);
});
test("trims surrounding whitespace", () => {
expect(normalizeRegistrationKey(` ${key}\n`)).toBe(key);
});
test("extracts keys from registration URLs", () => {
expect(normalizeRegistrationKey(`https://headscale.example.com/register/${key}`)).toBe(key);
});
test("extracts legacy machine keys from registration URLs", () => {
expect(normalizeRegistrationKey(`https://headscale.example.com/register/${legacyKey}`)).toBe(
legacyKey,
);
});
test("extracts keys from registration URLs with trailing URL parts", () => {
expect(normalizeRegistrationKey(`https://headscale.example.com/register/${key}?foo=bar`)).toBe(
key,
);
});
test("extracts auth request keys from URLs with trailing punctuation", () => {
expect(normalizeRegistrationKey(`https://headscale.example.com/register/${key}.`)).toBe(key);
});
test("accepts suffix-only input as a fallback", () => {
expect(normalizeRegistrationKey(suffix)).toBe(key);
});
test("does not require an exact suffix length for full keys", () => {
const longerKey = `${key}YZ12`;
expect(normalizeRegistrationKey(longerKey)).toBe(longerKey);
});
test("rejects empty or unrelated input", () => {
expect(normalizeRegistrationKey(" ")).toBeNull();
expect(normalizeRegistrationKey("not-a-registration-key")).toBeNull();
expect(normalizeRegistrationKey("hskey-authreq-short")).toBeNull();
expect(normalizeRegistrationKey("https://headscale.example.com/register/not-a-key")).toBeNull();
});
});