v3.0.0: Name.com DNS + Let's Encrypt for Node.js
This commit is contained in:
parent
c19b850d6e
commit
18fcf2ce31
30
README.md
30
README.md
@ -8,7 +8,7 @@ Handles ACME dns-01 challenges. Compatible with ACME.js and Greenlock.js. Passes
|
|||||||
|
|
||||||
- Compatible
|
- Compatible
|
||||||
- Let’s Encrypt v2.1 / ACME draft 18 (2019)
|
- Let’s Encrypt v2.1 / ACME draft 18 (2019)
|
||||||
- Name.com API
|
- Name.com v4 API
|
||||||
- ACME.js, Greenlock.js, and others
|
- ACME.js, Greenlock.js, and others
|
||||||
- Quality
|
- Quality
|
||||||
- node v6 compatible VanillaJS
|
- node v6 compatible VanillaJS
|
||||||
@ -21,10 +21,22 @@ Handles ACME dns-01 challenges. Compatible with ACME.js and Greenlock.js. Passes
|
|||||||
npm install --save acme-dns-01-namedotcom
|
npm install --save acme-dns-01-namedotcom
|
||||||
```
|
```
|
||||||
|
|
||||||
Name.com Token:
|
## Name.com API Token
|
||||||
|
|
||||||
- Login to your account at: {{ Service URL }}
|
- Login to your account at: <https://www.name.com/>
|
||||||
- {{ Instructions to generate token }}
|
- Generate a token at <https://www.name.com/account/settings/api>
|
||||||
|
- **Important** Enable API Access, _again_ at <https://www.name.com/account/settings/security>
|
||||||
|
|
||||||
|
The following error is what you may get if you have Two-Factor Auth and don't _Enable API Access_ the second time:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "Permission Denied",
|
||||||
|
"details": "Authentication Error - Account Has Namesafe Enabled"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're using the Whitelist IPs feature, don't forget to add your test environment!
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
@ -32,7 +44,8 @@ First you create an instance with your credentials:
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
var dns01 = require('acme-dns-01-namedotcom').create({
|
var dns01 = require('acme-dns-01-namedotcom').create({
|
||||||
baseUrl: '{{ api url }}', // default
|
baseUrl: 'http://api.name.com/v4/', // default
|
||||||
|
username: 'johndoe',
|
||||||
token: 'xxxx'
|
token: 'xxxx'
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
@ -51,7 +64,8 @@ var greenlock = Greenlock.create({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
See [Greenlock Express](https://git.rootprojects.org/root/greenlock-express.js) and/or [Greenlock.js](https://git.rootprojects.org/root/greenlock.js) documentation for more details.
|
See [Greenlock Express](https://git.rootprojects.org/root/greenlock-express.js)
|
||||||
|
and/or [Greenlock.js](https://git.rootprojects.org/root/greenlock.js) documentation for more details.
|
||||||
|
|
||||||
## ACME.js
|
## ACME.js
|
||||||
|
|
||||||
@ -93,8 +107,8 @@ See acme-dns-01-test for more implementation details.
|
|||||||
# Tests
|
# Tests
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# node ./test.js domain-zone api-token
|
# node ./test.js domain-zone username api-token
|
||||||
node ./test.js example.com xxxxxx
|
node ./test.js example.com me xxxxxx
|
||||||
```
|
```
|
||||||
|
|
||||||
# Authors
|
# Authors
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
ZONE=example.co.uk
|
ZONE=example.co.uk
|
||||||
TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
# Used for HTTP Basic Auth
|
||||||
|
USERNAME=johndoe
|
||||||
|
TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||||
|
132
lib/index.js
132
lib/index.js
@ -1,29 +1,137 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var request;
|
var request;
|
||||||
var defaults = {};
|
var defaults = {
|
||||||
|
baseUrl: 'https://api.name.com/v4/'
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.create = function(config) {
|
module.exports.create = function(config) {
|
||||||
return {
|
var baseUrl = (config.baseUrl || defaults.baseUrl).replace(/\/$/, '');
|
||||||
|
var token = config.token;
|
||||||
|
var username = config.username;
|
||||||
|
|
||||||
|
var plugin = {
|
||||||
init: function(opts) {
|
init: function(opts) {
|
||||||
request = opts.request;
|
request = opts.request;
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// We must list all zones (domains) in the account
|
||||||
zones: function(data) {
|
zones: function(data) {
|
||||||
//console.info('List Zones', data);
|
return api({
|
||||||
throw Error('listing zones not implemented');
|
url: baseUrl + '/domains'
|
||||||
|
}).then(function(resp) {
|
||||||
|
return resp.body.domains.map(function(d) {
|
||||||
|
//#console.log("Domain Name:", d.domainName);
|
||||||
|
return d.domainName;
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// We must set each record as required
|
||||||
set: function(data) {
|
set: function(data) {
|
||||||
// console.info('Add TXT', data);
|
// console.log('Add TXT', data);
|
||||||
throw Error('setting TXT not implemented');
|
var ch = data.challenge;
|
||||||
},
|
if (!ch.dnsZone) {
|
||||||
remove: function(data) {
|
throw new Error(
|
||||||
// console.info('Remove TXT', data);
|
'[Name.com Plugin] Unknown domain: ',
|
||||||
throw Error('removing TXT not implemented');
|
data.domain || data.dnsHost
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return api({
|
||||||
|
method: 'POST',
|
||||||
|
url: baseUrl + '/domains/' + ch.dnsZone + '/records',
|
||||||
|
json: {
|
||||||
|
host: ch.dnsPrefix,
|
||||||
|
type: 'TXT',
|
||||||
|
answer: ch.dnsAuthorization,
|
||||||
|
ttl: 300 // minimum allowed value
|
||||||
|
}
|
||||||
|
}).then(function(resp) {
|
||||||
|
if (!resp.body.id) {
|
||||||
|
throw Error('[Name.com API] [set] ' + resp.body);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// We must be able to confirm that the appropriate records were set
|
||||||
get: function(data) {
|
get: function(data) {
|
||||||
// console.info('List TXT', data);
|
// console.log('List TXT', data);
|
||||||
throw Error('listing TXTs not implemented');
|
var ch = data.challenge;
|
||||||
|
if (!ch.dnsZone) {
|
||||||
|
throw new Error(
|
||||||
|
'[Name.com Plugin] Unknown domain: ',
|
||||||
|
data.domain || data.dnsHost
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return api({
|
||||||
|
url: baseUrl + '/domains/' + ch.dnsZone + '/records'
|
||||||
|
}).then(function(resp) {
|
||||||
|
var value = resp.body.records.filter(function(r) {
|
||||||
|
return (
|
||||||
|
r.host === ch.dnsPrefix &&
|
||||||
|
'TXT' === r.type &&
|
||||||
|
ch.dnsAuthorization === r.answer
|
||||||
|
);
|
||||||
|
})[0];
|
||||||
|
if (!value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// adding id to make re-usable for remove
|
||||||
|
return { id: value.id, dnsAuthorization: value.answer };
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// We must delete junk records once we're done
|
||||||
|
remove: function(data) {
|
||||||
|
// console.log('Remove TXT', data);
|
||||||
|
var ch = data.challenge;
|
||||||
|
return plugin.get(data).then(function(r) {
|
||||||
|
if (!r.id) {
|
||||||
|
throw new Error(
|
||||||
|
'[Name.com Plugin] [del] Did not find TXT record for ' +
|
||||||
|
ch.dnsHost
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return api({
|
||||||
|
method: 'DELETE',
|
||||||
|
url: baseUrl + '/domains/' + ch.dnsZone + '/records/' + r.id
|
||||||
|
}).then(function(resp) {
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Authentication and Error handling here
|
||||||
|
function api(opts) {
|
||||||
|
opts.auth = {
|
||||||
|
user: username,
|
||||||
|
pass: token,
|
||||||
|
sendImmediately: true
|
||||||
|
};
|
||||||
|
if (!opts.json) {
|
||||||
|
opts.json = true;
|
||||||
|
}
|
||||||
|
return request(opts).then(function(resp) {
|
||||||
|
if (!resp.body.message) {
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.error(opts.method + ' ' + opts.url);
|
||||||
|
console.error(resp.headers);
|
||||||
|
console.error(resp.body);
|
||||||
|
throw new Error(
|
||||||
|
'[Name.com API] ' +
|
||||||
|
(opts.method || 'GET') +
|
||||||
|
' ' +
|
||||||
|
opts.url +
|
||||||
|
' : ' +
|
||||||
|
resp.body.message
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugin;
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "acme-dns-01-namedotcom",
|
"name": "acme-dns-01-namedotcom",
|
||||||
"version": "0.0.1",
|
"version": "3.0.0",
|
||||||
"description": "Name.com + Let's Encrypt for Node.js - ACME dns-01 challenges w/ ACME.js and Greenlock.js",
|
"description": "Name.com + Let's Encrypt for Node.js - ACME dns-01 challenges w/ ACME.js and Greenlock.js",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"files": [
|
"files": [
|
||||||
@ -26,9 +26,9 @@
|
|||||||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||||
"license": "MPL-2.0",
|
"license": "MPL-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"acme-challenge-test": "^3.3.2",
|
||||||
"dotenv": "^8.0.0"
|
"dotenv": "^8.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"acme-challenge-test": "^3.3.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
test.js
6
test.js
@ -5,10 +5,12 @@
|
|||||||
var tester = require('acme-challenge-test');
|
var tester = require('acme-challenge-test');
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
// Usage: node ./test.js example.com xxxxxxxxx
|
// Usage: node ./test.js example.com username xxxxxxxxx
|
||||||
var zone = process.argv[2] || process.env.ZONE;
|
var zone = process.argv[2] || process.env.ZONE;
|
||||||
var challenger = require('./index.js').create({
|
var challenger = require('./index.js').create({
|
||||||
token: process.argv[3] || process.env.TOKEN
|
//baseUrl: 'http://api.dev.name.com/v4/', // sandbox url
|
||||||
|
username: process.argv[3] || process.env.USERNAME,
|
||||||
|
token: process.argv[4] || process.env.TOKEN
|
||||||
});
|
});
|
||||||
|
|
||||||
// The dry-run tests can pass on, literally, 'example.com'
|
// The dry-run tests can pass on, literally, 'example.com'
|
||||||
|
9
token-test.sh
Normal file
9
token-test.sh
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Before assuming there's something wrong with this plugin,
|
||||||
|
# you should test that you can use your token with curl first.
|
||||||
|
|
||||||
|
echo "USERNAME: '$USERNAME'"
|
||||||
|
echo "TOKEN: '$TOKEN'"
|
||||||
|
curl -f -u "$USERNAME:$TOKEN" https://api.name.com/v4/domains
|
Loading…
x
Reference in New Issue
Block a user