fix(dns): разрешить вложенный wildcard в имени DNS-записи
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 8s
quality / changes (push) Successful in 12s
quality / docker-check (push) Skipped
quality / web (push) Successful in 1m9s
quality / api (push) Successful in 1m3s
CD / quality (push) Successful in 2m29s
CD / publish (push) Successful in 1m49s
quality / commitlint (push) Skipped
CD / update-wiki (push) Successful in 8s
quality / changes (push) Successful in 12s
quality / docker-check (push) Skipped
quality / web (push) Successful in 1m9s
quality / api (push) Successful in 1m3s
CD / quality (push) Successful in 2m29s
CD / publish (push) Successful in 1m49s
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Vendored
+5
-1
@@ -19,7 +19,10 @@ var CERT_MONITORING_VALUES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
// src/validators.ts
|
// src/validators.ts
|
||||||
var NAME_RE = /^(@|\*|[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])?(\.[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])?)*)$/;
|
var LABEL_RE = "[a-zA-Z0-9_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?";
|
||||||
|
var NAME_RE = new RegExp(
|
||||||
|
`^(@|\\*|(\\*\\.)?${LABEL_RE}(?:\\.${LABEL_RE})*)$`
|
||||||
|
);
|
||||||
var IPV4_RE = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
|
var IPV4_RE = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
|
||||||
var IPV6_RE = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
|
var IPV6_RE = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
|
||||||
var ALLOWED_TYPES = ["A", "AAAA", "CNAME", "TXT", "MX", "NS", "SRV", "CAA"];
|
var ALLOWED_TYPES = ["A", "AAAA", "CNAME", "TXT", "MX", "NS", "SRV", "CAA"];
|
||||||
@@ -106,6 +109,7 @@ function dnsNameToSubdomainLabel(recordName, zoneName) {
|
|||||||
const prefix = rn.slice(0, rn.length - zoneSuffix.length);
|
const prefix = rn.slice(0, rn.length - zoneSuffix.length);
|
||||||
return prefix || "@";
|
return prefix || "@";
|
||||||
}
|
}
|
||||||
|
if (rn.startsWith("*.")) return rn;
|
||||||
if (!rn.includes(".")) return rn;
|
if (!rn.includes(".")) return rn;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ import {
|
|||||||
} from "./constants.js";
|
} from "./constants.js";
|
||||||
import type { ServiceGroup } from "./types.js";
|
import type { ServiceGroup } from "./types.js";
|
||||||
|
|
||||||
const NAME_RE =
|
const LABEL_RE = "[a-zA-Z0-9_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?";
|
||||||
/^(@|\*|[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])?(\.[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])?)*)$/;
|
/** Apex `@`, zone `*`, labels, or nested wildcard (`*.ndns`, `*.ndns.shnt.top`). */
|
||||||
|
const NAME_RE = new RegExp(
|
||||||
|
`^(@|\\*|(\\*\\.)?${LABEL_RE}(?:\\.${LABEL_RE})*)$`,
|
||||||
|
);
|
||||||
const IPV4_RE =
|
const IPV4_RE =
|
||||||
/^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
|
/^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;
|
||||||
const IPV6_RE = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
|
const IPV6_RE = /^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$/;
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { validateDnsRecord, ValidationError } from "../src/validators.js";
|
||||||
|
|
||||||
|
function assertValidName(name: string): void {
|
||||||
|
expect(() =>
|
||||||
|
validateDnsRecord("A", name, "1.2.3.4", 1, false),
|
||||||
|
).not.toThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertInvalidName(name: string): void {
|
||||||
|
expect(() => validateDnsRecord("A", name, "1.2.3.4", 1, false)).toThrow(
|
||||||
|
ValidationError,
|
||||||
|
);
|
||||||
|
expect(() => validateDnsRecord("A", name, "1.2.3.4", 1, false)).toThrow(
|
||||||
|
`invalid record name: ${name}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("validateDnsRecord name", () => {
|
||||||
|
it("accepts apex and zone wildcard", () => {
|
||||||
|
assertValidName("@");
|
||||||
|
assertValidName("*");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepts regular labels and FQDN", () => {
|
||||||
|
assertValidName("ndns");
|
||||||
|
assertValidName("ndns.shnt.top");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepts nested wildcard relative name and FQDN", () => {
|
||||||
|
assertValidName("*.ndns");
|
||||||
|
assertValidName("*.ndns.shnt.top");
|
||||||
|
assertValidName("*.mdns");
|
||||||
|
assertValidName("*.mdns.rkns.top");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects wildcard not as leftmost label", () => {
|
||||||
|
assertInvalidName("foo.*.bar");
|
||||||
|
assertInvalidName("ndns.*");
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user