diff --git a/.gitignore b/.gitignore index 19f9ce180..209d4adc4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ *.env.production *.log +is-a-dev-cert/ diff --git a/domains/akshay.json b/domains/akshay.json index 130700660..095fe26f3 100644 --- a/domains/akshay.json +++ b/domains/akshay.json @@ -6,6 +6,7 @@ "email": "phenax5@gmail.com" }, "record": { - "URL": "https://phenax.github.io" + "URL": "https://phenax.github.io", + "TXT": [ "Hello there!", "It's me, Akshay" ] } } diff --git a/domains/bogdan.json b/domains/bogdan.json new file mode 100644 index 000000000..052d58fbe --- /dev/null +++ b/domains/bogdan.json @@ -0,0 +1,11 @@ +{ + "owner": { + "username": "MrBogdanYT", + "email": "hysbskyblockgod@gmail.com" + }, + "record": { + "A": ["217.174.245.249"], + "MX": ["hosts.is-a.dev"], + "TXT": "v=spf1 a mx ip4:217.174.245.249 ~all" + } +} \ No newline at end of file diff --git a/domains/christian.json b/domains/christian.json new file mode 100644 index 000000000..5a1ce84c4 --- /dev/null +++ b/domains/christian.json @@ -0,0 +1,11 @@ +{ + "owner": { + "username": "DenDanskeMine", + "email": "christianhrose@outlook.dk" + }, + "record": { + "A": ["217.174.245.249"], + "MX": ["hosts.is-a.dev"], + "TXT": "v=spf1 a mx ip4:217.174.245.249 ~all" + } +} \ No newline at end of file diff --git a/domains/noah.json b/domains/noah.json new file mode 100644 index 000000000..211aab7f6 --- /dev/null +++ b/domains/noah.json @@ -0,0 +1,10 @@ +{ + "owner": { + "username": "NoahPrm", + "email": "noah.parmentier@icloud.com" + }, + + "record": { + "A": ["185.143.241.106"] + } +} diff --git a/domains/npc.json b/domains/npc.json new file mode 100644 index 000000000..5eb5e5abe --- /dev/null +++ b/domains/npc.json @@ -0,0 +1,11 @@ +{ + "owner": { + "username": "npc-123", + "email": "aziznasrul85@gmail.com" + }, + "record": { + "A": ["217.174.245.249"], + "MX": ["hosts.is-a.dev"], + "TXT": "v=spf1 a mx ip4:217.174.245.249 ~all" + } +} \ No newline at end of file diff --git a/domains/saumon.json b/domains/saumon.json index ef3e4714b..2040d27f0 100644 --- a/domains/saumon.json +++ b/domains/saumon.json @@ -3,8 +3,9 @@ "username": "saumonarcenciel", "email": "viala38000@gmail.com" }, - "record": { - "A": ["185.143.241.106"] + "A": ["217.174.245.249"], + "MX": ["hosts.is-a.dev"], + "TXT": "v=spf1 a mx ip4:217.174.245.249 ~all" } -} +} \ No newline at end of file diff --git a/scripts/certbot-auth.sh b/scripts/certbot-auth.sh index fd0245777..6b4ee8bc7 100755 --- a/scripts/certbot-auth.sh +++ b/scripts/certbot-auth.sh @@ -6,10 +6,12 @@ echo "AUTH ::[$CERTBOT_VALIDATION]::[$CERTBOT_TOKEN]::[$CERTBOT_REMAINING_CHALLE echo "[$CERTBOT_DOMAIN]"; sleep 1; - ./scripts/certbot.sh acme_txt "$CERTBOT_VALIDATION"; -sleep $((5*60)); +echo "Going to sleep for a few minutes..."; + +# TODO: Check if $CERTBOT_VALIDATION == $(./scripts/certbot.sh get-acme)? +sleep $((3*60)); ./scripts/certbot.sh check; diff --git a/scripts/certbot.sh b/scripts/certbot.sh index 451df74b6..2ab0447ae 100755 --- a/scripts/certbot.sh +++ b/scripts/certbot.sh @@ -18,7 +18,6 @@ generate_certificate() { -m 'phenax5@gmail.com' \ -d '*.is-a.dev,is-a.dev' \ --agree-tos \ - --dry-run \ $(if_dry_run "--dry-run" ""); echo "+-----------------------------------------------+"; @@ -68,10 +67,14 @@ update_acme_txt_record() { reset_acme() { sleep 1; update_record remove TXT '_acme-challenge' ''; + update_record remove TXT '_acme-challenge' ''; } +get_acme() { dig +noall +answer _acme-challenge.is-a.dev TXT | awk '{print $5}'; } + case "$1" in - check) echo "TXT record:: $(dig +noall +answer _acme-challenge.is-a.dev TXT | awk '{print $5}')" ;; + check) echo "TXT record:: $(get_acme)" ;; + get-acme) get_acme ;; cert) generate_certificate ;; acme_txt) update_acme_txt_record "$2" ;; reset) reset_acme ;; diff --git a/tests/register.test.js b/tests/register.test.js index ef6e8247c..bd967a298 100644 --- a/tests/register.test.js +++ b/tests/register.test.js @@ -1,9 +1,18 @@ -const R = require('ramda'); -const { toHostList, registerDomains } = require('../scripts/register-domains'); -const { TTL, DOMAIN_DOMAIN } = require('../utils/constants'); -const { getDomainService } = require('../utils/domain-service'); +const R = require('ramda') +const { toHostList, registerDomains } = require('../scripts/register-domains') +const { TTL, DOMAIN_DOMAIN } = require('../utils/constants') +const { getDomainService } = require('../utils/domain-service') -const getCpanel = ({ zone, addZone, removeZone, redir, addRedir, removeRedir } = {}) => ({ +const getCpanel = ({ + zone, + addZone, + removeZone, + redir, + addRedir, + removeRedir, + addEmail, + removeEmail, +} = {}) => ({ zone: { fetch: (_) => zone(), add: (rec) => addZone(rec), @@ -18,7 +27,7 @@ const getCpanel = ({ zone, addZone, removeZone, redir, addRedir, removeRedir } = add: (rec) => addEmail(rec), remove: (rec) => removeEmail(rec), }, -}); +}) describe('toHostList', () => { it('should flatten domain data to list of hosts (without https)', () => { @@ -27,7 +36,7 @@ describe('toHostList', () => { { name: 'foobar', record: { CNAME: 'v.io' } }, { name: 'xx', record: { A: ['1.2.3.4', '5.6.3.2', '1.2.31.1'] } }, { name: 'xx', record: { CNAME: 'foobar.com', MX: ['as.com', 'f.com'] } }, - ]); + ]) expect(res).toEqual([ { name: 'akshay', type: 'CNAME', address: 'phenax.github.io', ttl: TTL }, @@ -38,83 +47,163 @@ describe('toHostList', () => { { name: 'xx', type: 'CNAME', address: 'foobar.com', ttl: TTL }, { name: 'xx', type: 'MX', address: 'as.com', priority: 20, ttl: TTL }, { name: 'xx', type: 'MX', address: 'f.com', priority: 21, ttl: TTL }, - ]); - }); -}); + ]) + }) +}) describe('registerDomains', () => { - const addZone = jest.fn(async () => ({})); - const removeZone = jest.fn(async () => ({})); - const addRedir = jest.fn(async () => ({})); - const removeRedir = jest.fn(async () => ({})); - const addEmail = jest.fn(async () => ({})); - const removeEmail = jest.fn(async () => ({})); + const addZone = jest.fn(async () => ({})) + const removeZone = jest.fn(async () => ({})) + const addRedir = jest.fn(async () => ({})) + const removeRedir = jest.fn(async () => ({})) + const addEmail = jest.fn(async () => ({})) + const removeEmail = jest.fn(async () => ({})) - const mockDS = ({ zones, redirections }) => getDomainService({ - cpanel: getCpanel({ - zone: async () => zones, - redir: async () => redirections, - addZone, - addEmail, - addRedir, - removeZone, - removeRedir, - removeEmail, + const mockDS = ({ zones, redirections }) => + getDomainService({ + cpanel: getCpanel({ + zone: async () => zones, + redir: async () => redirections, + addZone, + addEmail, + addRedir, + removeZone, + removeRedir, + removeEmail, + }), }) - }); beforeEach(() => { - addZone.mockClear(); - removeZone.mockClear(); - addRedir.mockClear(); - removeRedir.mockClear(); - addEmail.mockClear(); - removeEmail.mockClear(); - }); + addZone.mockClear() + removeZone.mockClear() + addRedir.mockClear() + removeRedir.mockClear() + addEmail.mockClear() + removeEmail.mockClear() + }) it('should register the new set of hosts generated from domains list', async () => { const localHosts = [ { name: 'a', record: { CNAME: 'hello' } }, { name: 'b', record: { CNAME: 'xaa' } }, - ]; + ] const remoteHosts = [ { line: 1, name: 'a', type: 'CNAME', address: 'hello' }, { line: 2, name: 'b', type: 'CNAME', address: 'goo' }, { line: 3, name: 'b', type: 'CNAME', address: 'xaa' }, - ]; - const remoteRedirections = []; + ] + const remoteRedirections = [] - const domainService = mockDS({ zones: remoteHosts, redirections: remoteRedirections }); - await registerDomains({ getDomains: async () => localHosts, domainService }); + const domainService = mockDS({ + zones: remoteHosts, + redirections: remoteRedirections, + }) + await registerDomains({ getDomains: async () => localHosts, domainService }) - expect(addZone).toHaveBeenCalledTimes(0); - expect(removeZone).toHaveBeenCalledTimes(1); - expect(addRedir).toHaveBeenCalledTimes(0); - expect(removeRedir).toHaveBeenCalledTimes(0); - }); + expect(addZone).toHaveBeenCalledTimes(0) + expect(removeZone).toHaveBeenCalledTimes(1) + expect(addRedir).toHaveBeenCalledTimes(0) + expect(removeRedir).toHaveBeenCalledTimes(0) + }) it('should add the new set hosts', async () => { const localHosts = [ - { name: 'a', record: { CNAME: 'boo', URL: 'z' } }, - { name: 'b', record: { CNAME: 'xaa', URL: 'x' } }, - { name: 'c', record: { CNAME: 'yello', URL: 'https://google.com' } }, - ]; + { name: 'a', record: { CNAME: 'boo' } }, + { + name: 'b', + record: { A: ['1.1.1.1', '1.1.1.2'], MX: 'somemx', TXT: 'some txt' }, + }, + { name: 'c', record: { URL: 'https://google.com' } }, + { name: 'd', record: { CNAME: 'foobar' } }, + { name: 'e', record: { A: ['2.2.2.2'], TXT: ['some', 'extra', 'txt'] } }, + ] const remoteHosts = [ { line: 1, name: 'a', type: 'CNAME', address: 'boo' }, - { line: 2, name: 'b', type: 'CNAME', address: 'xaa' }, - ]; + { line: 2, name: 'b', type: 'MX', address: 'othermx' }, + { line: 3, name: 'd', type: 'CNAME', address: 'foobaz' }, + ] const remoteRedirections = [ { domain: `b.${DOMAIN_DOMAIN}`, destination: 'x' }, { domain: `a.${DOMAIN_DOMAIN}`, destination: 'y' }, - ]; + ] - const domainService = mockDS({ zones: remoteHosts, redirections: remoteRedirections }); - await registerDomains({ getDomains: async () => localHosts, domainService }); + const domainService = mockDS({ + zones: remoteHosts, + redirections: remoteRedirections, + }) + await registerDomains({ getDomains: async () => localHosts, domainService }) - expect(addZone).toHaveBeenCalledTimes(1); - expect(removeZone).toHaveBeenCalledTimes(0); - expect(addRedir).toHaveBeenCalledTimes(2); - expect(removeRedir).toHaveBeenCalledTimes(1); - }); -}); + expect(addZone).toHaveBeenCalledTimes(8) + expect(addZone.mock.calls).toEqual([ + [{ name: 'b', type: 'A', address: '1.1.1.1', line: undefined }], + [{ name: 'b', type: 'A', address: '1.1.1.2', line: undefined }], + [ + { + name: 'b', + type: 'TXT', + address: 'some txt', + txtdata: 'some txt', + line: undefined, + }, + ], + [ + { + name: 'd', + type: 'CNAME', + cname: 'foobar', + address: 'foobar', + line: undefined, + }, + ], + [{ name: 'e', type: 'A', address: '2.2.2.2', line: undefined }], + [ + { + name: 'e', + type: 'TXT', + address: 'some', + txtdata: 'some', + line: undefined, + }, + ], + [ + { + name: 'e', + type: 'TXT', + address: 'extra', + txtdata: 'extra', + line: undefined, + }, + ], + [ + { + name: 'e', + type: 'TXT', + address: 'txt', + txtdata: 'txt', + line: undefined, + }, + ], + ]) + expect(removeZone).toHaveBeenCalledTimes(1) + expect(removeZone.mock.calls).toEqual([[{ line: 3 }]]) + + expect(addRedir).toHaveBeenCalledTimes(1) + expect(addRedir.mock.calls).toEqual([ + [ + { + domain: 'c.booboo.xyz', + redirect: 'https://google.com', + redirect_wildcard: 1, + redirect_www: 1, + type: 'permanent', + }, + ], + ]) + + expect(addEmail).toHaveBeenCalledTimes(1) + expect(addEmail.mock.calls).toEqual([ + [{ domain: 'b.is-a.dev', exchanger: 'somemx', priority: 20 }], + ]) + }) +}) diff --git a/tests/validations.test.js b/tests/validations.test.js index b06f8f5fb..a2484d581 100644 --- a/tests/validations.test.js +++ b/tests/validations.test.js @@ -54,7 +54,6 @@ describe('validateDomainData', () => { { ...defaultDomain, record: { CNAME: 'foobar.com', A: ['11.22.22.33'] } }, { ...defaultDomain, record: { CNAME: 'foobar.com', MX: ['ALT4.ASPMX.L.GOOGLE.COM'] } }, ...INVALID_NAMES.map(name => ({ ...defaultDomain, name })).slice(0, 1), - { ...defaultDomain, record: { TXT: ['foobar wow nice!!!'] } }, { ...defaultDomain, name: 'a.b' }, { ...defaultDomain, name: 'ww2.baa' }, { ...defaultDomain, name: 'help.baa' }, @@ -90,6 +89,7 @@ describe('validateDomainData', () => { { ...defaultDomain, name: '_github-challenge-phenax.akshay' }, { ...defaultDomain, name: '_github-challenge-hello01-ga' }, { ...defaultDomain, name: '_github-challenge-hello01_ga' }, + { ...defaultDomain, record: { TXT: ['foobar wow nice!!!', 'more text'] } }, { ...defaultDomain, record: { AAAA: ['::1', '2001:db8:3333:4444:5555:6666:7777:8888'] } }, { ...defaultDomain, record: { A: ['122.222.222.222'] } }, ]; diff --git a/utils/validations.js b/utils/validations.js index e4e6206cf..be2973343 100644 --- a/utils/validations.js +++ b/utils/validations.js @@ -2,7 +2,7 @@ const R = require('ramda'); const { VALID_RECORD_TYPES } = require('./constants'); const { or, and, validate, between, testRegex, withLengthEq, withLengthGte } = require('./helpers'); const INVALID_NAMES = require('./invalid-domains.json'); -const { default: ipRegex } = require('ip-regex'); +const ipRegex = require('ip-regex'); const isValidURL = and([R.is(String), testRegex(/^https?:\/\//ig)]); @@ -82,7 +82,7 @@ const validateDomainData = validate({ [R.has('A'), validateARecord('A')], [R.has('URL'), R.propSatisfies(isValidURL, 'URL')], [R.has('MX'), validateMXRecord('MX')], - [R.has('TXT'), R.propSatisfies(R.is(String), 'TXT')], + [R.has('TXT'), R.propSatisfies(or([ R.is(String), R.is(Array) ]), 'TXT')], [R.has('AAAA'), validateAAAARecord('AAAA')], [R.T, R.T], ]),