From 8fd2eb1adf6ba26ea2818b237fb8937a67a86e7c Mon Sep 17 00:00:00 2001 From: William Harrison Date: Fri, 27 Jan 2023 18:09:44 +0800 Subject: [PATCH] init --- .github/CODEOWNERS | 4 + .github/workflows/deploy-records.yml | 28 ++++++ .github/workflows/validation.yml | 34 ++++++++ dnsconfig.js | 96 +++++++++++++++++++++ domains/reserved/*.is-a-backend.dev.json | 12 +++ domains/reserved/*.is-a-frontend.dev.json | 12 +++ domains/reserved/is-a-backend.dev.json | 24 ++++++ domains/reserved/is-a-frontend.dev.json | 24 ++++++ domains/reserved/www.is-a-backend.dev.json | 12 +++ domains/reserved/www.is-a-frontend.dev.json | 12 +++ domains/william.is-a-backend.dev.json | 16 ++++ domains/william.is-a-frontend.dev.json | 16 ++++ schemas/domain.json | 81 +++++++++++++++++ schemas/reserved-domain.json | 71 +++++++++++++++ 14 files changed, 442 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/workflows/deploy-records.yml create mode 100644 .github/workflows/validation.yml create mode 100644 dnsconfig.js create mode 100644 domains/reserved/*.is-a-backend.dev.json create mode 100644 domains/reserved/*.is-a-frontend.dev.json create mode 100644 domains/reserved/is-a-backend.dev.json create mode 100644 domains/reserved/is-a-frontend.dev.json create mode 100644 domains/reserved/www.is-a-backend.dev.json create mode 100644 domains/reserved/www.is-a-frontend.dev.json create mode 100644 domains/william.is-a-backend.dev.json create mode 100644 domains/william.is-a-frontend.dev.json create mode 100644 schemas/domain.json create mode 100644 schemas/reserved-domain.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..db971b4 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +* @free-domains/owners + +# Domains +/domains/* @free-domains/maintainers diff --git a/.github/workflows/deploy-records.yml b/.github/workflows/deploy-records.yml new file mode 100644 index 0000000..993d7fc --- /dev/null +++ b/.github/workflows/deploy-records.yml @@ -0,0 +1,28 @@ +name: Deploy Records + +on: + workflow_dispatch: {} + push: + branches: [main] + paths: [domains/**, .github/workflows/deploy-records.yml] + +concurrency: + group: ${{ github.ref }}-deploy + cancel-in-progress: false + +jobs: + check: + name: DNS + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: gacts/install-dnscontrol@v1 + + - name: Create credentials file + run: echo '{"cloudflare":{"TYPE":"CLOUDFLAREAPI","accountid":"$CF_ID","apitoken":"$CF_TOKEN"}}' > ./creds.json + + - run: dnscontrol push + env: + CF_ID: ${{ secrets.CF_ACCOUNT_ID }} + CF_TOKEN: ${{ secrets.CF_API_TOKEN }} diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml new file mode 100644 index 0000000..4d40449 --- /dev/null +++ b/.github/workflows/validation.yml @@ -0,0 +1,34 @@ +name: Validation + +on: + workflow_dispatch: {} + push: + branches: [main] + tags-ignore: ["**"] + paths-ignore: ["**.md"] + pull_request: + paths-ignore: ["**.md"] + +concurrency: + group: ${{ github.ref }}-tests + cancel-in-progress: true + +jobs: + gitleaks: + name: GitLeaks + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: { fetch-depth: 0 } + + - uses: gacts/gitleaks@v1 + + check: + name: DNSControl Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: gacts/install-dnscontrol@v1 + + - run: dnscontrol check diff --git a/dnsconfig.js b/dnsconfig.js new file mode 100644 index 0000000..c0c21f1 --- /dev/null +++ b/dnsconfig.js @@ -0,0 +1,96 @@ +var regNone = NewRegistrar("none"); +var providerCf = DnsProvider(NewDnsProvider("cloudflare")); + +var proxy = { + // https://stackexchange.github.io/dnscontrol/providers/cloudflare + off: { cloudflare_proxy: "off" }, + on: { cloudflare_proxy: "on" } +}; + +/** + * Note: glob() is only an internal undocumented helper function (maybe risky). + * + * @param {String} filesPath + * @returns {{ + * name: string, + * data: { + * domain: string, + * subdomain: string, + * owner?: { email?: string }, + * record: { A?: string[], AAAA?: string[], CNAME?: string, TXT?: string[] }, + * proxied: boolean + * }}[]} + */ + +function getDomainsList(filesPath) { + var result = []; + var files = glob.apply(null, [filesPath, true, ".json"]); + + for (var i = 0; i < files.length; i++) { + var basename = files[i].split("/").reverse()[0]; + var name = basename.split(".")[0]; + + result.push({ name: name, data: require(files[i]) }); + } + + return result; +} + +var domains = getDomainsList("./domains"); + +/** + * @type {{}} + */ + +var commit = {}; + +for (var idx in domains) { + var domainData = domains[idx].data; + var proxyState = proxy.off; // Disabled by default + + if (!commit[domainData.domain]) { + commit[domainData.domain] = []; + } + + if (domainData.proxy === true) { + proxyState = proxy.on; + } + + if (domainData.record.A) { + for (var a in domainData.record.A) { + commit[domainData.domain].push( + A(domainData.subdomain, IP(domainData.record.A[a]), proxyState) // https://stackexchange.github.io/dnscontrol/js#A + ); + } + } + + if (domainData.record.AAAA) { + for (var aaaa in domainData.record.AAAA) { + commit[domainData.domain].push( + AAAA( + domainData.subdomain, + domainData.record.AAAA[aaaa], + proxyState + ) // https://stackexchange.github.io/dnscontrol/js#AAAA + ); + } + } + + if (domainData.record.CNAME) { + commit[domainData.domain].push( + CNAME(domainData.subdomain, domainData.record.CNAME, proxyState) // https://stackexchange.github.io/dnscontrol/js#CNAME + ); + } + + if (domainData.record.TXT) { + for (var txt in domainData.record.TXT) { + commit[domainData.domain].push( + TXT(domainData.subdomain, domainData.record.TXT[txt]) // https://stackexchange.github.io/dnscontrol/js#TXT + ); + } + } +} + +for (var domainName in commit) { + D(domainName, regNone, providerCf, commit[domainName]); +} diff --git a/domains/reserved/*.is-a-backend.dev.json b/domains/reserved/*.is-a-backend.dev.json new file mode 100644 index 0000000..5403b38 --- /dev/null +++ b/domains/reserved/*.is-a-backend.dev.json @@ -0,0 +1,12 @@ +{ + "$schema": "../../schemas/reserved-domain.json", + + "domain": "is-a-backend.dev", + "subdomain": "*", + + "records": { + "CNAME": "wdhdns.com." + }, + + "proxied": false +} \ No newline at end of file diff --git a/domains/reserved/*.is-a-frontend.dev.json b/domains/reserved/*.is-a-frontend.dev.json new file mode 100644 index 0000000..8dce6f5 --- /dev/null +++ b/domains/reserved/*.is-a-frontend.dev.json @@ -0,0 +1,12 @@ +{ + "$schema": "../../schemas/reserved-domain.json", + + "domain": "is-a-frontend.dev", + "subdomain": "*", + + "records": { + "CNAME": "wdhdns.com." + }, + + "proxied": false +} \ No newline at end of file diff --git a/domains/reserved/is-a-backend.dev.json b/domains/reserved/is-a-backend.dev.json new file mode 100644 index 0000000..6cc4445 --- /dev/null +++ b/domains/reserved/is-a-backend.dev.json @@ -0,0 +1,24 @@ +{ + "$schema": "../../schemas/reserved-domain.json", + + "domain": "is-a-backend.dev", + "subdomain": "@", + + "records": { + "A": [ + "185.199.108.153", + "185.199.109.153", + "185.199.110.153", + "185.199.111.153" + ], + + "AAAA": [ + "2606:50c0:8000::153", + "2606:50c0:8001::153", + "2606:50c0:8002::153", + "2606:50c0:8003::153" + ] + }, + + "proxied": false +} \ No newline at end of file diff --git a/domains/reserved/is-a-frontend.dev.json b/domains/reserved/is-a-frontend.dev.json new file mode 100644 index 0000000..67c87b7 --- /dev/null +++ b/domains/reserved/is-a-frontend.dev.json @@ -0,0 +1,24 @@ +{ + "$schema": "../../schemas/reserved-domain.json", + + "domain": "is-a-frontend.dev", + "subdomain": "@", + + "records": { + "A": [ + "185.199.108.153", + "185.199.109.153", + "185.199.110.153", + "185.199.111.153" + ], + + "AAAA": [ + "2606:50c0:8000::153", + "2606:50c0:8001::153", + "2606:50c0:8002::153", + "2606:50c0:8003::153" + ] + }, + + "proxied": false +} \ No newline at end of file diff --git a/domains/reserved/www.is-a-backend.dev.json b/domains/reserved/www.is-a-backend.dev.json new file mode 100644 index 0000000..8e5b8fb --- /dev/null +++ b/domains/reserved/www.is-a-backend.dev.json @@ -0,0 +1,12 @@ +{ + "$schema": "../../schemas/reserved-domain.json", + + "domain": "is-a-backend.dev", + "subdomain": "www", + + "records": { + "CNAME": "is-a-backend.dev." + }, + + "proxied": false +} \ No newline at end of file diff --git a/domains/reserved/www.is-a-frontend.dev.json b/domains/reserved/www.is-a-frontend.dev.json new file mode 100644 index 0000000..7f1f237 --- /dev/null +++ b/domains/reserved/www.is-a-frontend.dev.json @@ -0,0 +1,12 @@ +{ + "$schema": "../../schemas/reserved-domain.json", + + "domain": "is-a-frontend.dev", + "subdomain": "www", + + "records": { + "CNAME": "is-a-frontend.dev." + }, + + "proxied": false +} \ No newline at end of file diff --git a/domains/william.is-a-backend.dev.json b/domains/william.is-a-backend.dev.json new file mode 100644 index 0000000..797e18c --- /dev/null +++ b/domains/william.is-a-backend.dev.json @@ -0,0 +1,16 @@ +{ + "$schema": "../schemas/domain.json", + + "domain": "is-a-backend.dev", + "subdomain": "william", + + "owner": { + "email": "william@williamharrison.dev" + }, + + "records": { + "CNAME": "wdhdns.com." + }, + + "proxied": false +} \ No newline at end of file diff --git a/domains/william.is-a-frontend.dev.json b/domains/william.is-a-frontend.dev.json new file mode 100644 index 0000000..ecb3a14 --- /dev/null +++ b/domains/william.is-a-frontend.dev.json @@ -0,0 +1,16 @@ +{ + "$schema": "../schemas/domain.json", + + "domain": "is-a-frontend.dev", + "subdomain": "william", + + "owner": { + "email": "william@williamharrison.dev" + }, + + "records": { + "CNAME": "wdhdns.com." + }, + + "proxied": false +} \ No newline at end of file diff --git a/schemas/domain.json b/schemas/domain.json new file mode 100644 index 0000000..3b183c8 --- /dev/null +++ b/schemas/domain.json @@ -0,0 +1,81 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "type": "string", + "description": "Path to the schema file" + }, + "domain": { + "type": "string", + "enum": ["is-a-backend.dev", "is-a-frontend.dev"] + }, + "subdomain": { + "type": "string", + "pattern": "^([a-z0-9_*.-]{1,}|@)$" + }, + "owner": { + "type": "object", + "additionalProperties": false, + "properties": { + "email": { + "type": "string", + "description": "Email Address" + } + } + }, + "records": { + "type": "object", + "additionalProperties": false, + "properties": { + "A": { + "type": "array", + "items": { + "type": "string", + "pattern": "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$" + } + }, + "AAAA": { + "type": "array", + "items": { + "type": "string", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))$" + } + }, + "CNAME": { + "type": "string", + "minLength": 1, + "pattern": "^[a-z0-9_./-]*\\.$" + }, + "TXT": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + }, + "anyOf": [ + { + "required": ["A"] + }, + { + "required": ["AAAA"] + }, + { + "required": ["CNAME"] + }, + { + "required": ["TXT"] + } + ] + }, + "proxied": { + "type": "boolean", + "default": false + } + }, + "required": ["$schema", "domain", "subdomain", "owner", "records", "proxied"] +} diff --git a/schemas/reserved-domain.json b/schemas/reserved-domain.json new file mode 100644 index 0000000..cb2fbe0 --- /dev/null +++ b/schemas/reserved-domain.json @@ -0,0 +1,71 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "additionalProperties": false, + "properties": { + "$schema": { + "type": "string", + "description": "Path to the schema file" + }, + "domain": { + "type": "string", + "enum": ["is-a-backend.dev", "is-a-frontend.dev"] + }, + "subdomain": { + "type": "string", + "pattern": "^([a-z0-9_*.-]{1,}|@)$" + }, + "records": { + "type": "object", + "additionalProperties": false, + "properties": { + "A": { + "type": "array", + "items": { + "type": "string", + "pattern": "^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$" + } + }, + "AAAA": { + "type": "array", + "items": { + "type": "string", + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))$" + } + }, + "CNAME": { + "type": "string", + "minLength": 1, + "pattern": "^[a-z0-9_./-]*\\.$" + }, + "TXT": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 255 + } + } + }, + "anyOf": [ + { + "required": ["A"] + }, + { + "required": ["AAAA"] + }, + { + "required": ["CNAME"] + }, + { + "required": ["TXT"] + } + ] + }, + "proxied": { + "type": "boolean", + "default": false + } + }, + "required": ["$schema", "domain", "subdomain", "records", "proxied"] +}