support new services key

This commit is contained in:
William Harrison committed 2025-05-13 14:11:23 +08:00
1 parent d792791995
commit 229d821881
8 files changed
+148 -31

No files matched your search

+13
View File
@@ -133,6 +133,19 @@ for (var subdomain in domains) {
if (data.records.URL) {
records.push(A(subdomainName, IP("192.0.2.1"), CF_PROXY_ON));
}
// Manage service records
// Discord TXT verification
if (data.services.discord) {
if (Array.isArray(data.services.discord)) {
for (var txt in data.services.discord) {
records.push(TXT("_discord." + subdomainName, data.services.discord[txt]));
}
} else {
records.push(TXT("_discord." + subdomainName, data.services.discord));
}
}
}
var reserved = require("./util/reserved.json");
+3
View File
@@ -11,5 +11,8 @@
"/github": "https://github.com/wdhdev"
},
"redirect_paths": true
},
"services": {
"discord": "dh=4e444050c7f0e742327d027ebdf50a39f1203acd"
}
}
+13
View File
@@ -105,3 +105,16 @@ t("Users are limited to one single character subdomain", (t) => {
t.pass();
});
t("Disallow nested subdomains when parent has specific service records", (t) => {
files.forEach((file) => {
const subdomain = file.replace(/\.json$/, "");
const data = getDomainData(subdomain);
if(data?.services?.discord) {
t.false(files.includes(`_discord.${file}`), `${file}: Nested subdomain "_discord.${subdomain}" should not exist when services.discord is present`);
}
});
t.pass();
});
+13 -11
View File
@@ -11,7 +11,8 @@ const requiredFields = {
const optionalFields = {
proxied: "boolean",
redirect_config: "object"
redirect_config: "object",
services: "object"
};
const requiredOwnerFields = {
@@ -27,12 +28,7 @@ const optionalRedirectConfigFields = {
redirect_paths: "boolean"
};
const blockedFields = [
"domain",
"internal",
"reserved",
"subdomain"
];
const blockedFields = ["domain", "internal", "reserved", "subdomain"];
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
const hostnameRegex = /^(?=.{1,253}$)(?:(?:[_a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)\.)+[a-zA-Z]{2,63}$/;
@@ -117,10 +113,7 @@ async function validateFileName(t, file) {
!internalDomains.some((i) => subdomain.endsWith(`.${i}`)),
`${file}: Subdomain name is registered internally`
);
t.true(
!reservedDomains.some((r) => subdomain.endsWith(`.${r}`)),
`${file}: Subdomain name is reserved`
);
t.true(!reservedDomains.some((r) => subdomain.endsWith(`.${r}`)), `${file}: Subdomain name is reserved`);
const rootSubdomain = subdomain.split(".").pop();
t.false(rootSubdomain.startsWith("_"), `${file}: Root subdomains should not start with an underscore`);
@@ -157,6 +150,15 @@ async function processFile(file, t) {
validateFields(t, data.redirect_config, optionalRedirectConfigFields, file, "redirect_config");
}
if (data.services) {
if (data.services.discord) {
t.true(
Array.isArray(data.services.discord) || typeof data.services.discord === "string",
`${file}: Discord service should be an array or string`
);
}
}
for (const field of blockedFields) {
t.true(!data.hasOwnProperty(field), `${file}: Disallowed field: ${field}`);
}
+27 -10
View File
@@ -3,7 +3,10 @@ const fs = require("fs-extra");
const path = require("path");
const requiredEnvVars = ["PR_AUTHOR", "PR_AUTHOR_ID"];
const trustedUsers = require("../util/trusted.json").map((u) => u.id.toString());
const trustedUsers = require("../util/trusted.json");
const trusted = trustedUsers.map((u) => u.id.toString());
const admins = trustedUsers.filter((u) => u.admin).map((u) => u.id.toString());
function getDomainData(subdomain) {
try {
@@ -28,17 +31,24 @@ t("Users can only update their own subdomains", (t) => {
.filter((file) => file.name.startsWith("domains/"))
.map((file) => path.basename(file.name));
if ((!changedJSONFiles && !deletedFiles) || trustedUsers.includes(prAuthorId)) return t.pass();
if (!changedJSONFiles && !deletedFiles) return t.pass();
if (process.env.PR_LABELS && process.env.PR_LABELS.includes("ci: bypass-owner-check")) return t.pass();
changedJSONFiles.forEach((file) => {
const subdomain = file.replace(/\.json$/, "");
const data = getDomainData(subdomain);
t.true(
data.owner.username.toLowerCase() === prAuthor,
`${subdomain}: ${prAuthor} is not authorized to update ${subdomain}.is-a.dev`
);
if (data.owner.username === "is-a-dev") {
t.true(
admins.includes(prAuthorId),
`${subdomain}: ${prAuthor} is not authorized to update ${subdomain}.is-a.dev`
);
} else {
t.true(
data.owner.username.toLowerCase() === prAuthor || trusted.includes(prAuthorId),
`${file}: ${prAuthor} is not authorized to update ${subdomain}.is-a.dev`
);
}
});
deletedJSONFiles.forEach((file) => {
@@ -52,10 +62,17 @@ t("Users can only update their own subdomains", (t) => {
.join("\n")
);
t.true(
data.owner.username.toLowerCase() === prAuthor,
`${file}: ${prAuthor} is not authorized to delete ${subdomain}.is-a.dev`
);
if (data.owner.username === "is-a-dev") {
t.true(
admins.includes(prAuthorId),
`${subdomain}: ${prAuthor} is not authorized to delete ${subdomain}.is-a.dev`
);
} else {
t.true(
data.owner.username.toLowerCase() === prAuthor || trusted.includes(prAuthorId),
`${file}: ${prAuthor} is not authorized to delete ${subdomain}.is-a.dev`
);
}
});
}
+24 -1
View File
@@ -268,7 +268,7 @@ function validateRecordValues(t, data, file) {
}
}
t("All files should have valid record types", (t) => {
t("All files should have valid records", (t) => {
files.forEach((file) => {
const data = getDomainData(file);
const recordKeys = Object.keys(data.records);
@@ -328,3 +328,26 @@ t("Root subdomains should have at least one usable record", (t) => {
);
});
});
t("All files should have valid service records", (t) => {
files.forEach((file) => {
const data = getDomainData(file);
if (data?.services?.discord) {
const discord = Array.isArray(data.services.discord) ? data.services.discord : [data.services.discord];
discord.forEach((value) => {
const token = value.split("=")[1];
t.true(value.startsWith("dh="), `${file}: Discord service record should start with "dh="`);
t.true(token.length === 40, `${file}: Discord service token should be 40 characters long`);
t.true(
isValidHexadecimal(token),
`${file}: Discord service token should be a valid hexadecimal string`
);
});
}
});
t.pass();
});
+26
View File
@@ -110,6 +110,32 @@ fs.readdir(directoryPath, function (err, files) {
v1.push(itemV1);
v2.push(itemV2);
if (item.services) {
if (item.services.discord) {
const discord = Array.isArray(item.services.discord)
? item.services.discord
: [item.services.discord];
v1.push({
domain: `_discord.${item.domain}`,
subdomain: `_discord.${item.subdomain}`,
owner: item.owner,
record: {
TXT: discord
}
});
v2.push({
domain: `_discord.${item.domain}`,
subdomain: `_discord.${item.subdomain}`,
owner: item.owner,
records: {
TXT: discord
}
});
}
}
processedCount++;
if (processedCount === files.length) {
fs.writeFile("raw-api/index.json", JSON.stringify(v1), (err) => {
+29 -9
View File
@@ -1,11 +1,31 @@
[
{ "username": "21Z", "id": 69188068 },
{ "username": "DEV-DIBSTER", "id": 76603072 },
{ "username": "iostpa", "id": 69630113 },
{ "username": "is-a-dev-bot", "id": 106927495 },
{ "username": "orangci", "id": 90866414 },
{ "username": "Stef-00012", "id": 81536172 },
{ "username": "SX-9", "id": 90962949 },
{ "username": "WDH-2", "id": 115670568 },
{ "username": "wdhdev", "id": 87287585 }
{
"username": "21Z",
"id": 69188068
},
{
"username": "DEV-DIBSTER",
"id": 76603072
},
{
"username": "iostpa",
"id": 69630113
},
{
"username": "orangci",
"id": 90866414
},
{
"username": "Stef-00012",
"id": 81536172
},
{
"username": "SX-9",
"id": 90962949
},
{
"username": "wdhdev",
"id": 87287585,
"admin": true
}
]