Compare commits

..
1 Commits
Author SHA1 Message Date
DenozordecandCursor 7f06466058 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
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-31 16:02:20 +07:00
3 changed files with 51 additions and 3 deletions
+5 -1
View File
@@ -19,7 +19,10 @@ var CERT_MONITORING_VALUES = [
];
// 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 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"];
@@ -106,6 +109,7 @@ function dnsNameToSubdomainLabel(recordName, zoneName) {
const prefix = rn.slice(0, rn.length - zoneSuffix.length);
return prefix || "@";
}
if (rn.startsWith("*.")) return rn;
if (!rn.includes(".")) return rn;
return null;
}
+5 -2
View File
@@ -5,8 +5,11 @@ import {
} from "./constants.js";
import type { ServiceGroup } from "./types.js";
const 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_])?)*)$/;
const LABEL_RE = "[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 =
/^((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}$/;
+41
View File
@@ -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.*");
});
});