forked from root/acme.js
		
	yay for backwards compat tested and working
This commit is contained in:
		
							parent
							
								
									27fb85ed9c
								
							
						
					
					
						commit
						fe5a48764b
					
				
							
								
								
									
										42
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								README.md
									
									
									
									
									
								
							@ -31,27 +31,52 @@ Todo
 | 
			
		||||
* export http and dns challenge tests
 | 
			
		||||
* support ECDSA keys
 | 
			
		||||
 | 
			
		||||
## Let's Encrypt Directory URLs
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
# Production URL
 | 
			
		||||
https://acme-v02.api.letsencrypt.org/directory
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
# Staging URL
 | 
			
		||||
https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## API
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
var ACME = require('acme-v2.js').ACME.create({
 | 
			
		||||
var ACME = require('acme-v2').ACME.create({
 | 
			
		||||
  RSA: require('rsa-compat').RSA
 | 
			
		||||
 | 
			
		||||
  // other overrides
 | 
			
		||||
, request: require('request')
 | 
			
		||||
, promisify: require('util').promisify
 | 
			
		||||
 | 
			
		||||
  // used for constructing user-agent
 | 
			
		||||
, os: require('os')
 | 
			
		||||
, process: require('process')
 | 
			
		||||
 | 
			
		||||
  // used for overriding the default user-agent
 | 
			
		||||
, userAgent: 'My custom UA String'
 | 
			
		||||
, getUserAgentString: function (deps) { return 'My custom UA String'; }
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
// Accounts
 | 
			
		||||
ACME.registerNewAccount(options, cb)        // returns "regr" registration data
 | 
			
		||||
ACME.accounts.create(options)                 // returns Promise<regr> registration data
 | 
			
		||||
 | 
			
		||||
    { email: '<email>'                        //    valid email (server checks MX records)
 | 
			
		||||
    , accountKeypair: {                       //    privateKeyPem or privateKeyJwt
 | 
			
		||||
        privateKeyPem: '<ASCII PEM>'
 | 
			
		||||
      }
 | 
			
		||||
    , agreeToTerms: fn (tosUrl, cb) {}        //    must specify agree=tosUrl to continue (or falsey to end)
 | 
			
		||||
    , agreeToTerms: fn (tosUrl) {}            //    returns Promise with tosUrl
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Registration
 | 
			
		||||
ACME.getCertificate(options, cb)            // returns (err, pems={ privkey (key), cert, chain (ca) })
 | 
			
		||||
ACME.certificates.create(options)             // returns Promise<pems={ privkey (key), cert, chain (ca) }>
 | 
			
		||||
 | 
			
		||||
    { newAuthzUrl: '<url>'                    //    specify acmeUrls.newAuthz
 | 
			
		||||
    , newCertUrl: '<url>'                     //    specify acmeUrls.newCert
 | 
			
		||||
@ -64,20 +89,19 @@ ACME.getCertificate(options, cb)            // returns (err, pems={ privkey (key
 | 
			
		||||
      }
 | 
			
		||||
    , domains: [ 'example.com' ]
 | 
			
		||||
 | 
			
		||||
    , setChallenge: fn (hostname, key, val, cb)
 | 
			
		||||
    , removeChallenge: fn (hostname, key, cb)
 | 
			
		||||
    , setChallenge: fn (hostname, key, val)   // return Promise
 | 
			
		||||
    , removeChallenge: fn (hostname, key)     // return Promise
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Discovery URLs
 | 
			
		||||
ACME.getAcmeUrls(acmeDiscoveryUrl, cb)      // returns (err, acmeUrls={newReg,newAuthz,newCert,revokeCert})
 | 
			
		||||
ACME.init(acmeDirectoryUrl)                   // returns Promise<acmeUrls={keyChange,meta,newAccount,newNonce,newOrder,revokeCert}>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Helpers & Stuff
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
// Constants
 | 
			
		||||
ACME.productionServerUrl                // https://acme-v02.api.letsencrypt.org/directory
 | 
			
		||||
ACME.stagingServerUrl                   // https://acme-staging-v02.api.letsencrypt.org/directory
 | 
			
		||||
ACME.acmeChallengePrefix                // /.well-known/acme-challenge/
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										53
									
								
								compat.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								compat.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var ACME2 = require('./').ACME;
 | 
			
		||||
 | 
			
		||||
function resolveFn(cb) {
 | 
			
		||||
  return function (val) {
 | 
			
		||||
    // nextTick to get out of Promise chain
 | 
			
		||||
    process.nextTick(function () { cb(null, val); });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
function rejectFn(cb) {
 | 
			
		||||
  return function (err) {
 | 
			
		||||
    console.log('reject something or other:');
 | 
			
		||||
    console.log(err.stack);
 | 
			
		||||
    // nextTick to get out of Promise chain
 | 
			
		||||
    process.nextTick(function () { cb(err); });
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function create(deps) {
 | 
			
		||||
  deps.LeCore = {};
 | 
			
		||||
  var acme2 = ACME2.create(deps);
 | 
			
		||||
  acme2.registerNewAccount = function (options, cb) {
 | 
			
		||||
    acme2.accounts.create(options).then(resolveFn(cb), rejectFn(cb));
 | 
			
		||||
  };
 | 
			
		||||
  acme2.getCertificate = function (options, cb) {
 | 
			
		||||
    acme2.certificates.create(options).then(resolveFn(cb), rejectFn(cb));
 | 
			
		||||
  };
 | 
			
		||||
  acme2.getAcmeUrls = function (options, cb) {
 | 
			
		||||
    acme2.init(options).then(resolveFn(cb), rejectFn(cb));
 | 
			
		||||
  };
 | 
			
		||||
  acme2.stagingServerUrl = module.exports.defaults.stagingServerUrl;
 | 
			
		||||
  acme2.productionServerUrl = module.exports.defaults.productionServerUrl;
 | 
			
		||||
  return acme2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.ACME = { };
 | 
			
		||||
module.exports.defaults = {
 | 
			
		||||
  productionServerUrl:    'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, stagingServerUrl:       'https://acme-staging-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, knownEndpoints:         [ 'keyChange', 'meta', 'newAccount', 'newNonce', 'newOrder', 'revokeCert' ]
 | 
			
		||||
, challengeTypes:         [ 'http-01', 'dns-01' ]
 | 
			
		||||
, challengeType:          'http-01'
 | 
			
		||||
, keyType:                'rsa' // ecdsa
 | 
			
		||||
, keySize:                2048 // 256
 | 
			
		||||
};
 | 
			
		||||
Object.keys(module.exports.defaults).forEach(function (key) {
 | 
			
		||||
  module.exports.ACME[key] = module.exports.defaults[key];
 | 
			
		||||
});
 | 
			
		||||
Object.keys(ACME2).forEach(function (key) {
 | 
			
		||||
  module.exports.ACME[key] = ACME2[key];
 | 
			
		||||
  module.exports.ACME.create = create;
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										860
									
								
								node.js
									
									
									
									
									
								
							
							
						
						
									
										860
									
								
								node.js
									
									
									
									
									
								
							@ -6,463 +6,487 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
/* globals Promise */
 | 
			
		||||
 | 
			
		||||
var defaults = {
 | 
			
		||||
  productionServerUrl:    'https://acme-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, stagingServerUrl:       'https://acme-staging-v02.api.letsencrypt.org/directory'
 | 
			
		||||
, acmeChallengePrefix:    '/.well-known/acme-challenge/'
 | 
			
		||||
, knownEndpoints:         [ 'keyChange', 'meta', 'newAccount', 'newNonce', 'newOrder', 'revokeCert' ]
 | 
			
		||||
, challengeType:          'http-01' // dns-01
 | 
			
		||||
, keyType:                'rsa' // ecdsa
 | 
			
		||||
, keySize:                2048 // 256
 | 
			
		||||
};
 | 
			
		||||
var ACME = module.exports.ACME = {};
 | 
			
		||||
 | 
			
		||||
function create(deps) {
 | 
			
		||||
  if (!deps) { deps = {}; }
 | 
			
		||||
  deps.LeCore = {};
 | 
			
		||||
  deps.pkg = deps.pkg || require('./package.json');
 | 
			
		||||
  deps.os = deps.os || require('os');
 | 
			
		||||
  deps.process = deps.process || require('process');
 | 
			
		||||
ACME.acmeChallengePrefix = '/.well-known/acme-challenge/';
 | 
			
		||||
 | 
			
		||||
ACME._getUserAgentString = function (deps) {
 | 
			
		||||
  var uaDefaults = {
 | 
			
		||||
      pkg: "Greenlock/" + deps.pkg.version
 | 
			
		||||
    , os: " (" + deps.os.type() + "; " + deps.process.arch + " " + deps.os.platform() + " " + deps.os.release() + ")"
 | 
			
		||||
    , node: " Node.js/" + deps.process.version
 | 
			
		||||
    , os: "(" + deps.os.type() + "; " + deps.process.arch + " " + deps.os.platform() + " " + deps.os.release() + ")"
 | 
			
		||||
    , node: "Node.js/" + deps.process.version
 | 
			
		||||
    , user: ''
 | 
			
		||||
  };
 | 
			
		||||
  //var currentUAProps;
 | 
			
		||||
 | 
			
		||||
  function getUaString() {
 | 
			
		||||
    var userAgent = '';
 | 
			
		||||
  var userAgent = [];
 | 
			
		||||
 | 
			
		||||
    //Object.keys(currentUAProps)
 | 
			
		||||
    Object.keys(uaDefaults).forEach(function (key) {
 | 
			
		||||
      userAgent += uaDefaults[key];
 | 
			
		||||
      //userAgent += currentUAProps[key];
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return userAgent.trim();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getRequest(opts) {
 | 
			
		||||
    if (!opts) { opts = {}; }
 | 
			
		||||
 | 
			
		||||
    return deps.request.defaults({
 | 
			
		||||
      headers: {
 | 
			
		||||
        'User-Agent': opts.userAgent || getUaString()
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  var RSA = deps.RSA || require('rsa-compat').RSA;
 | 
			
		||||
  deps.request = deps.request || require('request');
 | 
			
		||||
  deps.promisify = deps.promisify || require('util').promisify;
 | 
			
		||||
 | 
			
		||||
  var directoryUrl = deps.directoryUrl || defaults.stagingServerUrl;
 | 
			
		||||
  var request = deps.promisify(getRequest({}));
 | 
			
		||||
 | 
			
		||||
  var acme2 = {
 | 
			
		||||
    getAcmeUrls: function (_directoryUrl) {
 | 
			
		||||
      var me = this;
 | 
			
		||||
      return request({ url: _directoryUrl || directoryUrl, json: true }).then(function (resp) {
 | 
			
		||||
        me._directoryUrls = resp.body;
 | 
			
		||||
        me._tos = me._directoryUrls.meta.termsOfService;
 | 
			
		||||
        return me._directoryUrls;
 | 
			
		||||
      });
 | 
			
		||||
  //Object.keys(currentUAProps)
 | 
			
		||||
  Object.keys(uaDefaults).forEach(function (key) {
 | 
			
		||||
    if (uaDefaults[key]) {
 | 
			
		||||
      userAgent.push(uaDefaults[key]);
 | 
			
		||||
    }
 | 
			
		||||
  , getNonce: function () {
 | 
			
		||||
      var me = this;
 | 
			
		||||
      if (me._nonce) { return new Promise(function (resolve) { resolve(me._nonce); return; }); }
 | 
			
		||||
      return request({ method: 'HEAD', url: me._directoryUrls.newNonce }).then(function (resp) {
 | 
			
		||||
        me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
        return me._nonce;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    // ACME RFC Section 7.3 Account Creation
 | 
			
		||||
    /*
 | 
			
		||||
     {
 | 
			
		||||
       "protected": base64url({
 | 
			
		||||
         "alg": "ES256",
 | 
			
		||||
         "jwk": {...},
 | 
			
		||||
         "nonce": "6S8IqOGY7eL2lsGoTZYifg",
 | 
			
		||||
         "url": "https://example.com/acme/new-account"
 | 
			
		||||
       }),
 | 
			
		||||
       "payload": base64url({
 | 
			
		||||
         "termsOfServiceAgreed": true,
 | 
			
		||||
         "onlyReturnExisting": false,
 | 
			
		||||
         "contact": [
 | 
			
		||||
           "mailto:cert-admin@example.com",
 | 
			
		||||
           "mailto:admin@example.com"
 | 
			
		||||
         ]
 | 
			
		||||
       }),
 | 
			
		||||
       "signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
 | 
			
		||||
     }
 | 
			
		||||
    */
 | 
			
		||||
  , registerNewAccount: function (options) {
 | 
			
		||||
      var me = this;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
      console.log('[acme-v2] registerNewAccount');
 | 
			
		||||
  return userAgent.join(' ').trim();
 | 
			
		||||
};
 | 
			
		||||
ACME._directory = function (me) {
 | 
			
		||||
  return me._request({ url: me.directoryUrl, json: true });
 | 
			
		||||
};
 | 
			
		||||
ACME._getNonce = function (me) {
 | 
			
		||||
  if (me._nonce) { return new Promise(function (resolve) { resolve(me._nonce); return; }); }
 | 
			
		||||
  return me._request({ method: 'HEAD', url: me._directoryUrls.newNonce }).then(function (resp) {
 | 
			
		||||
    me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
    return me._nonce;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
// ACME RFC Section 7.3 Account Creation
 | 
			
		||||
/*
 | 
			
		||||
 {
 | 
			
		||||
   "protected": base64url({
 | 
			
		||||
     "alg": "ES256",
 | 
			
		||||
     "jwk": {...},
 | 
			
		||||
     "nonce": "6S8IqOGY7eL2lsGoTZYifg",
 | 
			
		||||
     "url": "https://example.com/acme/new-account"
 | 
			
		||||
   }),
 | 
			
		||||
   "payload": base64url({
 | 
			
		||||
     "termsOfServiceAgreed": true,
 | 
			
		||||
     "onlyReturnExisting": false,
 | 
			
		||||
     "contact": [
 | 
			
		||||
       "mailto:cert-admin@example.com",
 | 
			
		||||
       "mailto:admin@example.com"
 | 
			
		||||
     ]
 | 
			
		||||
   }),
 | 
			
		||||
   "signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
 | 
			
		||||
 }
 | 
			
		||||
*/
 | 
			
		||||
ACME._registerAccount = function (me, options) {
 | 
			
		||||
  console.log('[acme-v2] accounts.create');
 | 
			
		||||
 | 
			
		||||
      return me.getNonce().then(function () {
 | 
			
		||||
        return new Promise(function (resolve, reject) {
 | 
			
		||||
  return ACME._getNonce(me).then(function () {
 | 
			
		||||
    return new Promise(function (resolve, reject) {
 | 
			
		||||
 | 
			
		||||
          function agree(err, tosUrl) {
 | 
			
		||||
            if (err) { reject(err); return; }
 | 
			
		||||
            if (me._tos !== tosUrl) {
 | 
			
		||||
              err = new Error("You must agree to the ToS at '" + me._tos + "'");
 | 
			
		||||
              err.code = "E_AGREE_TOS";
 | 
			
		||||
              reject(err);
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var jwk = RSA.exportPublicJwk(options.accountKeypair);
 | 
			
		||||
            var body = {
 | 
			
		||||
              termsOfServiceAgreed: tosUrl === me._tos
 | 
			
		||||
            , onlyReturnExisting: false
 | 
			
		||||
            , contact: [ 'mailto:' + options.email ]
 | 
			
		||||
            };
 | 
			
		||||
            if (options.externalAccount) {
 | 
			
		||||
              body.externalAccountBinding = RSA.signJws(
 | 
			
		||||
                options.externalAccount.secret
 | 
			
		||||
              , undefined
 | 
			
		||||
              , { alg: "HS256"
 | 
			
		||||
                , kid: options.externalAccount.id
 | 
			
		||||
                , url: me._directoryUrls.newAccount
 | 
			
		||||
                }
 | 
			
		||||
              , new Buffer(JSON.stringify(jwk))
 | 
			
		||||
              );
 | 
			
		||||
            }
 | 
			
		||||
            var payload = JSON.stringify(body);
 | 
			
		||||
            var jws = RSA.signJws(
 | 
			
		||||
              options.accountKeypair
 | 
			
		||||
            , undefined
 | 
			
		||||
            , { nonce: me._nonce
 | 
			
		||||
              , alg: 'RS256'
 | 
			
		||||
              , url: me._directoryUrls.newAccount
 | 
			
		||||
              , jwk: jwk
 | 
			
		||||
              }
 | 
			
		||||
            , new Buffer(payload)
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            console.log('[acme-v2] registerNewAccount JSON body:');
 | 
			
		||||
            delete jws.header;
 | 
			
		||||
            console.log(jws);
 | 
			
		||||
            me._nonce = null;
 | 
			
		||||
            return request({
 | 
			
		||||
              method: 'POST'
 | 
			
		||||
            , url: me._directoryUrls.newAccount
 | 
			
		||||
            , headers: { 'Content-Type': 'application/jose+json' }
 | 
			
		||||
            , json: jws
 | 
			
		||||
            }).then(function (resp) {
 | 
			
		||||
              me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
              var location = resp.toJSON().headers.location;
 | 
			
		||||
              console.log('[DEBUG] new account location:'); // the account id url
 | 
			
		||||
              console.log(location); // the account id url
 | 
			
		||||
              console.log(resp.toJSON());
 | 
			
		||||
              me._kid = location;
 | 
			
		||||
              return resp.body;
 | 
			
		||||
            }).then(resolve);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          console.log('[acme-v2] agreeToTerms');
 | 
			
		||||
          options.agreeToTerms(me._tos, agree);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
     POST /acme/new-order HTTP/1.1
 | 
			
		||||
     Host: example.com
 | 
			
		||||
     Content-Type: application/jose+json
 | 
			
		||||
 | 
			
		||||
     {
 | 
			
		||||
       "protected": base64url({
 | 
			
		||||
         "alg": "ES256",
 | 
			
		||||
         "kid": "https://example.com/acme/acct/1",
 | 
			
		||||
         "nonce": "5XJ1L3lEkMG7tR6pA00clA",
 | 
			
		||||
         "url": "https://example.com/acme/new-order"
 | 
			
		||||
       }),
 | 
			
		||||
       "payload": base64url({
 | 
			
		||||
         "identifiers": [{"type:"dns","value":"example.com"}],
 | 
			
		||||
         "notBefore": "2016-01-01T00:00:00Z",
 | 
			
		||||
         "notAfter": "2016-01-08T00:00:00Z"
 | 
			
		||||
       }),
 | 
			
		||||
       "signature": "H6ZXtGjTZyUnPeKn...wEA4TklBdh3e454g"
 | 
			
		||||
     }
 | 
			
		||||
    */
 | 
			
		||||
  , _getChallenges: function (options, auth) {
 | 
			
		||||
      console.log('\n[DEBUG] getChallenges\n');
 | 
			
		||||
      return request({ method: 'GET', url: auth, json: true }).then(function (resp) {
 | 
			
		||||
        return resp.body;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    // https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.5.1
 | 
			
		||||
  , _postChallenge: function (options, identifier, ch) {
 | 
			
		||||
      var me = this;
 | 
			
		||||
 | 
			
		||||
      var body = { };
 | 
			
		||||
 | 
			
		||||
      var payload = JSON.stringify(body);
 | 
			
		||||
 | 
			
		||||
      var thumbprint = RSA.thumbprint(options.accountKeypair);
 | 
			
		||||
      var keyAuthorization = ch.token + '.' + thumbprint;
 | 
			
		||||
      //   keyAuthorization = token || '.' || base64url(JWK_Thumbprint(accountKey))
 | 
			
		||||
      //   /.well-known/acme-challenge/:token
 | 
			
		||||
 | 
			
		||||
      return new Promise(function (resolve, reject) {
 | 
			
		||||
        if (options.setupChallenge) {
 | 
			
		||||
          options.setupChallenge(
 | 
			
		||||
            { identifier: identifier
 | 
			
		||||
            , hostname: identifier.value
 | 
			
		||||
            , type: ch.type
 | 
			
		||||
            , token: ch.token
 | 
			
		||||
            , thumbprint: thumbprint
 | 
			
		||||
            , keyAuthorization: keyAuthorization
 | 
			
		||||
            , dnsAuthorization: RSA.utils.toWebsafeBase64(
 | 
			
		||||
                require('crypto').createHash('sha256').update(keyAuthorization).digest('base64')
 | 
			
		||||
              )
 | 
			
		||||
            }
 | 
			
		||||
          , testChallenge
 | 
			
		||||
          );
 | 
			
		||||
        } else {
 | 
			
		||||
          options.setChallenge(identifier.value, ch.token, keyAuthorization, testChallenge);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function testChallenge(err) {
 | 
			
		||||
          if (err) { reject(err); return; }
 | 
			
		||||
 | 
			
		||||
          // TODO put check dns / http checks here?
 | 
			
		||||
          // http-01: GET https://example.org/.well-known/acme-challenge/{{token}} => {{keyAuth}}
 | 
			
		||||
          // dns-01: TXT _acme-challenge.example.org. => "{{urlSafeBase64(sha256(keyAuth))}}"
 | 
			
		||||
 | 
			
		||||
          function wait(ms) {
 | 
			
		||||
            return new Promise(function (resolve) {
 | 
			
		||||
              setTimeout(resolve, (ms || 1100));
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          function pollStatus() {
 | 
			
		||||
            console.log('\n[DEBUG] statusChallenge\n');
 | 
			
		||||
            return request({ method: 'GET', url: ch.url, json: true }).then(function (resp) {
 | 
			
		||||
              console.error('poll: resp.body:');
 | 
			
		||||
              console.error(resp.body);
 | 
			
		||||
 | 
			
		||||
              if ('pending' === resp.body.status) {
 | 
			
		||||
                console.log('poll: again');
 | 
			
		||||
                return wait().then(pollStatus);
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              if ('valid' === resp.body.status) {
 | 
			
		||||
                console.log('poll: valid');
 | 
			
		||||
                try {
 | 
			
		||||
                  if (options.teardownChallenge) {
 | 
			
		||||
                    options.teardownChallenge(
 | 
			
		||||
                      { identifier: identifier
 | 
			
		||||
                      , type: ch.type
 | 
			
		||||
                      , token: ch.token
 | 
			
		||||
                      }
 | 
			
		||||
                    , function () {}
 | 
			
		||||
                    );
 | 
			
		||||
                  } else {
 | 
			
		||||
                    options.removeChallenge(identifier.value, ch.token, function () {});
 | 
			
		||||
                  }
 | 
			
		||||
                } catch(e) {}
 | 
			
		||||
                return resp.body;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              if (!resp.body.status) {
 | 
			
		||||
                console.error("[acme-v2] (y) bad challenge state:");
 | 
			
		||||
              }
 | 
			
		||||
              else if ('invalid' === resp.body.status) {
 | 
			
		||||
                console.error("[acme-v2] (x) invalid challenge state:");
 | 
			
		||||
              }
 | 
			
		||||
              else {
 | 
			
		||||
                console.error("[acme-v2] (z) bad challenge state:");
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              return Promise.reject(new Error("[acme-v2] bad challenge state"));
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          console.log('\n[DEBUG] postChallenge\n');
 | 
			
		||||
          //console.log('\n[DEBUG] stop to fix things\n'); return;
 | 
			
		||||
 | 
			
		||||
          function post() {
 | 
			
		||||
            var jws = RSA.signJws(
 | 
			
		||||
              options.accountKeypair
 | 
			
		||||
            , undefined
 | 
			
		||||
            , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
 | 
			
		||||
            , new Buffer(payload)
 | 
			
		||||
            );
 | 
			
		||||
            me._nonce = null;
 | 
			
		||||
            return request({
 | 
			
		||||
              method: 'POST'
 | 
			
		||||
            , url: ch.url
 | 
			
		||||
            , headers: { 'Content-Type': 'application/jose+json' }
 | 
			
		||||
            , json: jws
 | 
			
		||||
            }).then(function (resp) {
 | 
			
		||||
              me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
              console.log('respond to challenge: resp.body:');
 | 
			
		||||
              console.log(resp.body);
 | 
			
		||||
              return wait().then(pollStatus).then(resolve, reject);
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          return wait(20 * 1000).then(post);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  , _finalizeOrder: function (options, validatedDomains) {
 | 
			
		||||
      console.log('finalizeOrder:');
 | 
			
		||||
      var me = this;
 | 
			
		||||
 | 
			
		||||
      var csr = RSA.generateCsrWeb64(options.domainKeypair, validatedDomains);
 | 
			
		||||
      var body = { csr: csr };
 | 
			
		||||
      var payload = JSON.stringify(body);
 | 
			
		||||
 | 
			
		||||
      function wait(ms) {
 | 
			
		||||
        return new Promise(function (resolve) {
 | 
			
		||||
          setTimeout(resolve, (ms || 1100));
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function pollCert() {
 | 
			
		||||
        var jws = RSA.signJws(
 | 
			
		||||
          options.accountKeypair
 | 
			
		||||
        , undefined
 | 
			
		||||
        , { nonce: me._nonce, alg: 'RS256', url: me._finalize, kid: me._kid }
 | 
			
		||||
        , new Buffer(payload)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        console.log('finalize:', me._finalize);
 | 
			
		||||
        me._nonce = null;
 | 
			
		||||
        return request({
 | 
			
		||||
          method: 'POST'
 | 
			
		||||
        , url: me._finalize
 | 
			
		||||
        , headers: { 'Content-Type': 'application/jose+json' }
 | 
			
		||||
        , json: jws
 | 
			
		||||
        }).then(function (resp) {
 | 
			
		||||
          me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
 | 
			
		||||
          console.log('order finalized: resp.body:');
 | 
			
		||||
          console.log(resp.body);
 | 
			
		||||
 | 
			
		||||
          if ('processing' === resp.body.status) {
 | 
			
		||||
            return wait().then(pollCert);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if ('valid' === resp.body.status) {
 | 
			
		||||
            me._expires = resp.body.expires;
 | 
			
		||||
            me._certificate = resp.body.certificate;
 | 
			
		||||
 | 
			
		||||
            return resp.body;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if ('invalid' === resp.body.status) {
 | 
			
		||||
            console.error('cannot finalize: badness');
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          console.error('(x) cannot finalize: badness');
 | 
			
		||||
      function agree(tosUrl) {
 | 
			
		||||
        var err;
 | 
			
		||||
        if (me._tos !== tosUrl) {
 | 
			
		||||
          err = new Error("You must agree to the ToS at '" + me._tos + "'");
 | 
			
		||||
          err.code = "E_AGREE_TOS";
 | 
			
		||||
          reject(err);
 | 
			
		||||
          return;
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return pollCert();
 | 
			
		||||
    }
 | 
			
		||||
  , _getCertificate: function () {
 | 
			
		||||
      var me = this;
 | 
			
		||||
      return request({ method: 'GET', url: me._certificate, json: true }).then(function (resp) {
 | 
			
		||||
        console.log('Certificate:');
 | 
			
		||||
        console.log(resp.body);
 | 
			
		||||
        return resp.body;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  , getCertificate: function (options, cb) {
 | 
			
		||||
      console.log('[acme-v2] DEBUG get cert 1');
 | 
			
		||||
      var me = this;
 | 
			
		||||
 | 
			
		||||
      if (!options.challengeTypes) {
 | 
			
		||||
        if (!options.challengeType) {
 | 
			
		||||
          cb(new Error("challenge type must be specified"));
 | 
			
		||||
          return Promise.reject(new Error("challenge type must be specified"));
 | 
			
		||||
        }
 | 
			
		||||
        options.challengeTypes = [ options.challengeType ];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      console.log('[acme-v2] getCertificate');
 | 
			
		||||
      return me.getNonce().then(function () {
 | 
			
		||||
        var jwk = me.RSA.exportPublicJwk(options.accountKeypair);
 | 
			
		||||
        var body = {
 | 
			
		||||
          identifiers: options.domains.map(function (hostname) {
 | 
			
		||||
            return { type: "dns" , value: hostname };
 | 
			
		||||
          })
 | 
			
		||||
          //, "notBefore": "2016-01-01T00:00:00Z"
 | 
			
		||||
          //, "notAfter": "2016-01-08T00:00:00Z"
 | 
			
		||||
          termsOfServiceAgreed: tosUrl === me._tos
 | 
			
		||||
        , onlyReturnExisting: false
 | 
			
		||||
        , contact: [ 'mailto:' + options.email ]
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (options.externalAccount) {
 | 
			
		||||
          body.externalAccountBinding = me.RSA.signJws(
 | 
			
		||||
            options.externalAccount.secret
 | 
			
		||||
          , undefined
 | 
			
		||||
          , { alg: "HS256"
 | 
			
		||||
            , kid: options.externalAccount.id
 | 
			
		||||
            , url: me._directoryUrls.newAccount
 | 
			
		||||
            }
 | 
			
		||||
          , new Buffer(JSON.stringify(jwk))
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
        var payload = JSON.stringify(body);
 | 
			
		||||
        var jws = RSA.signJws(
 | 
			
		||||
        var jws = me.RSA.signJws(
 | 
			
		||||
          options.accountKeypair
 | 
			
		||||
        , undefined
 | 
			
		||||
        , { nonce: me._nonce, alg: 'RS256', url: me._directoryUrls.newOrder, kid: me._kid }
 | 
			
		||||
        , { nonce: me._nonce
 | 
			
		||||
          , alg: 'RS256'
 | 
			
		||||
          , url: me._directoryUrls.newAccount
 | 
			
		||||
          , jwk: jwk
 | 
			
		||||
          }
 | 
			
		||||
        , new Buffer(payload)
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        console.log('\n[DEBUG] newOrder\n');
 | 
			
		||||
        console.log('[acme-v2] accounts.create JSON body:');
 | 
			
		||||
        delete jws.header;
 | 
			
		||||
        console.log(jws);
 | 
			
		||||
        me._nonce = null;
 | 
			
		||||
        return request({
 | 
			
		||||
        return me._request({
 | 
			
		||||
          method: 'POST'
 | 
			
		||||
        , url: me._directoryUrls.newOrder
 | 
			
		||||
        , url: me._directoryUrls.newAccount
 | 
			
		||||
        , headers: { 'Content-Type': 'application/jose+json' }
 | 
			
		||||
        , json: jws
 | 
			
		||||
        }).then(function (resp) {
 | 
			
		||||
          me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
          var location = resp.toJSON().headers.location;
 | 
			
		||||
          console.log('[DEBUG] new account location:'); // the account id url
 | 
			
		||||
          console.log(location); // the account id url
 | 
			
		||||
          console.log(resp.toJSON());
 | 
			
		||||
          me._authorizations = resp.body.authorizations;
 | 
			
		||||
          me._order = location;
 | 
			
		||||
          me._finalize = resp.body.finalize;
 | 
			
		||||
          //console.log('[DEBUG] finalize:', me._finalize); return;
 | 
			
		||||
          me._kid = location;
 | 
			
		||||
          return resp.body;
 | 
			
		||||
        }).then(resolve, reject);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
          //return resp.body;
 | 
			
		||||
          return Promise.all(me._authorizations.map(function (authUrl) {
 | 
			
		||||
            return me._getChallenges(options, authUrl).then(function (results) {
 | 
			
		||||
              // var domain = options.domains[i]; // results.identifier.value
 | 
			
		||||
              var chType = options.challengeTypes.filter(function (chType) {
 | 
			
		||||
                return results.challenges.some(function (ch) {
 | 
			
		||||
                  return ch.type === chType;
 | 
			
		||||
                });
 | 
			
		||||
              })[0];
 | 
			
		||||
              var challenge = results.challenges.filter(function (ch) {
 | 
			
		||||
                if (chType === ch.type) {
 | 
			
		||||
                  return ch;
 | 
			
		||||
                }
 | 
			
		||||
              })[0];
 | 
			
		||||
      console.log('[acme-v2] agreeToTerms');
 | 
			
		||||
      if (1 === options.agreeToTerms.length) {
 | 
			
		||||
        return options.agreeToTerms(me._tos).then(agree, reject);
 | 
			
		||||
      }
 | 
			
		||||
      else if (2 === options.agreeToTerms.length) {
 | 
			
		||||
        return options.agreeToTerms(me._tos, function (err, tosUrl) {
 | 
			
		||||
          if (!err) { agree(tosUrl); return; }
 | 
			
		||||
          reject(err);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        reject(new Error('agreeToTerms has incorrect function signature.'
 | 
			
		||||
          + ' Should be fn(tos) { return Promise<tos>; }'));
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
/*
 | 
			
		||||
 POST /acme/new-order HTTP/1.1
 | 
			
		||||
 Host: example.com
 | 
			
		||||
 Content-Type: application/jose+json
 | 
			
		||||
 | 
			
		||||
              if (!challenge) {
 | 
			
		||||
                return Promise.reject(new Error("Server didn't offer any challenge we can handle."));
 | 
			
		||||
 {
 | 
			
		||||
   "protected": base64url({
 | 
			
		||||
     "alg": "ES256",
 | 
			
		||||
     "kid": "https://example.com/acme/acct/1",
 | 
			
		||||
     "nonce": "5XJ1L3lEkMG7tR6pA00clA",
 | 
			
		||||
     "url": "https://example.com/acme/new-order"
 | 
			
		||||
   }),
 | 
			
		||||
   "payload": base64url({
 | 
			
		||||
     "identifiers": [{"type:"dns","value":"example.com"}],
 | 
			
		||||
     "notBefore": "2016-01-01T00:00:00Z",
 | 
			
		||||
     "notAfter": "2016-01-08T00:00:00Z"
 | 
			
		||||
   }),
 | 
			
		||||
   "signature": "H6ZXtGjTZyUnPeKn...wEA4TklBdh3e454g"
 | 
			
		||||
 }
 | 
			
		||||
*/
 | 
			
		||||
ACME._getChallenges = function (me, options, auth) {
 | 
			
		||||
  console.log('\n[DEBUG] getChallenges\n');
 | 
			
		||||
  return me._request({ method: 'GET', url: auth, json: true }).then(function (resp) {
 | 
			
		||||
    return resp.body;
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
ACME._wait = function wait(ms) {
 | 
			
		||||
  return new Promise(function (resolve) {
 | 
			
		||||
    setTimeout(resolve, (ms || 1100));
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
// https://tools.ietf.org/html/draft-ietf-acme-acme-10#section-7.5.1
 | 
			
		||||
ACME._postChallenge = function (me, options, identifier, ch) {
 | 
			
		||||
  var body = { };
 | 
			
		||||
 | 
			
		||||
  var payload = JSON.stringify(body);
 | 
			
		||||
 | 
			
		||||
  var thumbprint = me.RSA.thumbprint(options.accountKeypair);
 | 
			
		||||
  var keyAuthorization = ch.token + '.' + thumbprint;
 | 
			
		||||
  //   keyAuthorization = token || '.' || base64url(JWK_Thumbprint(accountKey))
 | 
			
		||||
  //   /.well-known/acme-challenge/:token
 | 
			
		||||
 | 
			
		||||
  return new Promise(function (resolve, reject) {
 | 
			
		||||
    function failChallenge(err) {
 | 
			
		||||
      if (err) { reject(err); return; }
 | 
			
		||||
      testChallenge();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function testChallenge() {
 | 
			
		||||
      // TODO put check dns / http checks here?
 | 
			
		||||
      // http-01: GET https://example.org/.well-known/acme-challenge/{{token}} => {{keyAuth}}
 | 
			
		||||
      // dns-01: TXT _acme-challenge.example.org. => "{{urlSafeBase64(sha256(keyAuth))}}"
 | 
			
		||||
 | 
			
		||||
      function pollStatus() {
 | 
			
		||||
        console.log('\n[DEBUG] statusChallenge\n');
 | 
			
		||||
        return me._request({ method: 'GET', url: ch.url, json: true }).then(function (resp) {
 | 
			
		||||
          console.error('poll: resp.body:');
 | 
			
		||||
          console.error(resp.body);
 | 
			
		||||
 | 
			
		||||
          if ('pending' === resp.body.status) {
 | 
			
		||||
            console.log('poll: again');
 | 
			
		||||
            return ACME._wait(1 * 1000).then(pollStatus);
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          if ('valid' === resp.body.status) {
 | 
			
		||||
            console.log('poll: valid');
 | 
			
		||||
            try {
 | 
			
		||||
              if (1 === options.removeChallenge.length) {
 | 
			
		||||
                options.removeChallenge(
 | 
			
		||||
                  { identifier: identifier
 | 
			
		||||
                  , type: ch.type
 | 
			
		||||
                  , token: ch.token
 | 
			
		||||
                  }
 | 
			
		||||
                ).then(function () {}, function () {});
 | 
			
		||||
              } else if (2 === options.removeChallenge.length) {
 | 
			
		||||
                options.removeChallenge(
 | 
			
		||||
                  { identifier: identifier
 | 
			
		||||
                  , type: ch.type
 | 
			
		||||
                  , token: ch.token
 | 
			
		||||
                  }
 | 
			
		||||
                , function (err) { return err; }
 | 
			
		||||
                );
 | 
			
		||||
              } else {
 | 
			
		||||
                options.removeChallenge(identifier.value, ch.token, function () {});
 | 
			
		||||
              }
 | 
			
		||||
            } catch(e) {}
 | 
			
		||||
            return resp.body;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
              return me._postChallenge(options, results.identifier, challenge);
 | 
			
		||||
            });
 | 
			
		||||
          })).then(function () {
 | 
			
		||||
            var validatedDomains = body.identifiers.map(function (ident) {
 | 
			
		||||
              return ident.value;
 | 
			
		||||
            });
 | 
			
		||||
          if (!resp.body.status) {
 | 
			
		||||
            console.error("[acme-v2] (y) bad challenge state:");
 | 
			
		||||
          }
 | 
			
		||||
          else if ('invalid' === resp.body.status) {
 | 
			
		||||
            console.error("[acme-v2] (x) invalid challenge state:");
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            console.error("[acme-v2] (z) bad challenge state:");
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
            return me._finalizeOrder(options, validatedDomains);
 | 
			
		||||
          }).then(function () {
 | 
			
		||||
            return me._getCertificate().then(function (result) { cb(null, result); return result; }, cb);
 | 
			
		||||
          });
 | 
			
		||||
          return Promise.reject(new Error("[acme-v2] bad challenge state"));
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      console.log('\n[DEBUG] postChallenge\n');
 | 
			
		||||
      //console.log('\n[DEBUG] stop to fix things\n'); return;
 | 
			
		||||
 | 
			
		||||
      function post() {
 | 
			
		||||
        var jws = me.RSA.signJws(
 | 
			
		||||
          options.accountKeypair
 | 
			
		||||
        , undefined
 | 
			
		||||
        , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
 | 
			
		||||
        , new Buffer(payload)
 | 
			
		||||
        );
 | 
			
		||||
        me._nonce = null;
 | 
			
		||||
        return me._request({
 | 
			
		||||
          method: 'POST'
 | 
			
		||||
        , url: ch.url
 | 
			
		||||
        , headers: { 'Content-Type': 'application/jose+json' }
 | 
			
		||||
        , json: jws
 | 
			
		||||
        }).then(function (resp) {
 | 
			
		||||
          me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
          console.log('respond to challenge: resp.body:');
 | 
			
		||||
          console.log(resp.body);
 | 
			
		||||
          return ACME._wait(1 * 1000).then(pollStatus).then(resolve, reject);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return ACME._wait(1 * 1000).then(post);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      if (1 === options.setChallenge.length) {
 | 
			
		||||
        options.setChallenge(
 | 
			
		||||
          { identifier: identifier
 | 
			
		||||
          , hostname: identifier.value
 | 
			
		||||
          , type: ch.type
 | 
			
		||||
          , token: ch.token
 | 
			
		||||
          , thumbprint: thumbprint
 | 
			
		||||
          , keyAuthorization: keyAuthorization
 | 
			
		||||
          , dnsAuthorization: me.RSA.utils.toWebsafeBase64(
 | 
			
		||||
              require('crypto').createHash('sha256').update(keyAuthorization).digest('base64')
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
        ).then(testChallenge, reject);
 | 
			
		||||
      } else if (2 === options.setChallenge.length) {
 | 
			
		||||
        options.setChallenge(
 | 
			
		||||
          { identifier: identifier
 | 
			
		||||
          , hostname: identifier.value
 | 
			
		||||
          , type: ch.type
 | 
			
		||||
          , token: ch.token
 | 
			
		||||
          , thumbprint: thumbprint
 | 
			
		||||
          , keyAuthorization: keyAuthorization
 | 
			
		||||
          , dnsAuthorization: me.RSA.utils.toWebsafeBase64(
 | 
			
		||||
              require('crypto').createHash('sha256').update(keyAuthorization).digest('base64')
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
        , failChallenge
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        options.setChallenge(identifier.value, ch.token, keyAuthorization, failChallenge);
 | 
			
		||||
      }
 | 
			
		||||
    } catch(e) {
 | 
			
		||||
      reject(e);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
ACME._finalizeOrder = function (me, options, validatedDomains) {
 | 
			
		||||
  console.log('finalizeOrder:');
 | 
			
		||||
  var csr = me.RSA.generateCsrWeb64(options.domainKeypair, validatedDomains);
 | 
			
		||||
  var body = { csr: csr };
 | 
			
		||||
  var payload = JSON.stringify(body);
 | 
			
		||||
 | 
			
		||||
  function pollCert() {
 | 
			
		||||
    var jws = me.RSA.signJws(
 | 
			
		||||
      options.accountKeypair
 | 
			
		||||
    , undefined
 | 
			
		||||
    , { nonce: me._nonce, alg: 'RS256', url: me._finalize, kid: me._kid }
 | 
			
		||||
    , new Buffer(payload)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    console.log('finalize:', me._finalize);
 | 
			
		||||
    me._nonce = null;
 | 
			
		||||
    return me._request({
 | 
			
		||||
      method: 'POST'
 | 
			
		||||
    , url: me._finalize
 | 
			
		||||
    , headers: { 'Content-Type': 'application/jose+json' }
 | 
			
		||||
    , json: jws
 | 
			
		||||
    }).then(function (resp) {
 | 
			
		||||
      me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
 | 
			
		||||
      console.log('order finalized: resp.body:');
 | 
			
		||||
      console.log(resp.body);
 | 
			
		||||
 | 
			
		||||
      if ('processing' === resp.body.status) {
 | 
			
		||||
        return ACME._wait().then(pollCert);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if ('valid' === resp.body.status) {
 | 
			
		||||
        me._expires = resp.body.expires;
 | 
			
		||||
        me._certificate = resp.body.certificate;
 | 
			
		||||
 | 
			
		||||
        return resp.body;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if ('invalid' === resp.body.status) {
 | 
			
		||||
        console.error('cannot finalize: badness');
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      console.error('(x) cannot finalize: badness');
 | 
			
		||||
      return;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return pollCert();
 | 
			
		||||
};
 | 
			
		||||
ACME._getCertificate = function (me, options) {
 | 
			
		||||
  console.log('[acme-v2] DEBUG get cert 1');
 | 
			
		||||
 | 
			
		||||
  if (!options.challengeTypes) {
 | 
			
		||||
    if (!options.challengeType) {
 | 
			
		||||
      return Promise.reject(new Error("challenge type must be specified"));
 | 
			
		||||
    }
 | 
			
		||||
    options.challengeTypes = [ options.challengeType ];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  console.log('[acme-v2] certificates.create');
 | 
			
		||||
  return ACME._getNonce(me).then(function () {
 | 
			
		||||
    var body = {
 | 
			
		||||
      identifiers: options.domains.map(function (hostname) {
 | 
			
		||||
        return { type: "dns" , value: hostname };
 | 
			
		||||
      })
 | 
			
		||||
      //, "notBefore": "2016-01-01T00:00:00Z"
 | 
			
		||||
      //, "notAfter": "2016-01-08T00:00:00Z"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    var payload = JSON.stringify(body);
 | 
			
		||||
    var jws = me.RSA.signJws(
 | 
			
		||||
      options.accountKeypair
 | 
			
		||||
    , undefined
 | 
			
		||||
    , { nonce: me._nonce, alg: 'RS256', url: me._directoryUrls.newOrder, kid: me._kid }
 | 
			
		||||
    , new Buffer(payload)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    console.log('\n[DEBUG] newOrder\n');
 | 
			
		||||
    me._nonce = null;
 | 
			
		||||
    return me._request({
 | 
			
		||||
      method: 'POST'
 | 
			
		||||
    , url: me._directoryUrls.newOrder
 | 
			
		||||
    , headers: { 'Content-Type': 'application/jose+json' }
 | 
			
		||||
    , json: jws
 | 
			
		||||
    }).then(function (resp) {
 | 
			
		||||
      me._nonce = resp.toJSON().headers['replay-nonce'];
 | 
			
		||||
      var location = resp.toJSON().headers.location;
 | 
			
		||||
      console.log(location); // the account id url
 | 
			
		||||
      console.log(resp.toJSON());
 | 
			
		||||
      me._authorizations = resp.body.authorizations;
 | 
			
		||||
      me._order = location;
 | 
			
		||||
      me._finalize = resp.body.finalize;
 | 
			
		||||
      //console.log('[DEBUG] finalize:', me._finalize); return;
 | 
			
		||||
 | 
			
		||||
      //return resp.body;
 | 
			
		||||
      return Promise.all(me._authorizations.map(function (authUrl, i) {
 | 
			
		||||
        console.log("Authorizations map #" + i);
 | 
			
		||||
        return ACME._getChallenges(me, options, authUrl).then(function (results) {
 | 
			
		||||
          // var domain = options.domains[i]; // results.identifier.value
 | 
			
		||||
          var chType = options.challengeTypes.filter(function (chType) {
 | 
			
		||||
            return results.challenges.some(function (ch) {
 | 
			
		||||
              return ch.type === chType;
 | 
			
		||||
            });
 | 
			
		||||
          })[0];
 | 
			
		||||
 | 
			
		||||
          var challenge = results.challenges.filter(function (ch) {
 | 
			
		||||
            if (chType === ch.type) {
 | 
			
		||||
              return ch;
 | 
			
		||||
            }
 | 
			
		||||
          })[0];
 | 
			
		||||
 | 
			
		||||
          if (!challenge) {
 | 
			
		||||
            return Promise.reject(new Error("Server didn't offer any challenge we can handle."));
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          return ACME._postChallenge(me, options, results.identifier, challenge);
 | 
			
		||||
        });
 | 
			
		||||
      })).then(function () {
 | 
			
		||||
        var validatedDomains = body.identifiers.map(function (ident) {
 | 
			
		||||
          return ident.value;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return ACME._finalizeOrder(me, options, validatedDomains);
 | 
			
		||||
      }).then(function () {
 | 
			
		||||
        return me._request({ method: 'GET', url: me._certificate, json: true }).then(function (resp) {
 | 
			
		||||
          console.log('Certificate:');
 | 
			
		||||
          console.log(resp.body);
 | 
			
		||||
          return resp.body;
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ACME.create = function create(me) {
 | 
			
		||||
  if (!me) { me = {}; }
 | 
			
		||||
  me.acmeChallengePrefix = ACME.acmeChallengePrefix;
 | 
			
		||||
  me.RSA = me.RSA || require('rsa-compat').RSA;
 | 
			
		||||
  me.request = me.request || require('request');
 | 
			
		||||
  me.promisify = me.promisify || require('util').promisify;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  if ('function' !== typeof me.getUserAgentString) {
 | 
			
		||||
    me.pkg = me.pkg || require('./package.json');
 | 
			
		||||
    me.os = me.os || require('os');
 | 
			
		||||
    me.process = me.process || require('process');
 | 
			
		||||
    me.userAgent = ACME._getUserAgentString(me);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function getRequest(opts) {
 | 
			
		||||
    if (!opts) { opts = {}; }
 | 
			
		||||
 | 
			
		||||
    return me.request.defaults({
 | 
			
		||||
      headers: {
 | 
			
		||||
        'User-Agent': opts.userAgent || me.userAgent || me.getUserAgentString(me)
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ('function' !== typeof me._request) {
 | 
			
		||||
    me._request = me.promisify(getRequest({}));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  me.init = function (_directoryUrl) {
 | 
			
		||||
    me.directoryUrl = me.directoryUrl || _directoryUrl;
 | 
			
		||||
    return ACME._directory(me).then(function (resp) {
 | 
			
		||||
      me._directoryUrls = resp.body;
 | 
			
		||||
      me._tos = me._directoryUrls.meta.termsOfService;
 | 
			
		||||
      return me._directoryUrls;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  me.accounts = {
 | 
			
		||||
    create: function (options) {
 | 
			
		||||
      return ACME._registerAccount(me, options);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  return acme2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports.ACME = {
 | 
			
		||||
  create: create
 | 
			
		||||
  me.certificates = {
 | 
			
		||||
    create: function (options) {
 | 
			
		||||
      return ACME._getCertificate(me, options);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
  return me;
 | 
			
		||||
};
 | 
			
		||||
Object.keys(defaults).forEach(function (key) {
 | 
			
		||||
  module.exports.ACME[key] = defaults[key];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										75
									
								
								test.cb.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								test.cb.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
module.exports.run = function run(web, chType, email) {
 | 
			
		||||
  var RSA = require('rsa-compat').RSA;
 | 
			
		||||
  var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory';
 | 
			
		||||
  var acme2 = require('./compat').ACME.create({ RSA: RSA });
 | 
			
		||||
  // [ 'test.ppl.family' ] 'coolaj86@gmail.com''http-01'
 | 
			
		||||
	console.log(web, chType, email);
 | 
			
		||||
	return;
 | 
			
		||||
  acme2.init(directoryUrl).then(function (body) {
 | 
			
		||||
    console.log(body);
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
      agreeToTerms: function (tosUrl, agree) {
 | 
			
		||||
        agree(null, tosUrl);
 | 
			
		||||
      }
 | 
			
		||||
    , setChallenge: function (opts, cb) {
 | 
			
		||||
 | 
			
		||||
        console.log("");
 | 
			
		||||
        console.log('identifier:');
 | 
			
		||||
        console.log(opts.identifier);
 | 
			
		||||
        console.log('hostname:');
 | 
			
		||||
        console.log(opts.hostname);
 | 
			
		||||
        console.log('type:');
 | 
			
		||||
        console.log(opts.type);
 | 
			
		||||
        console.log('token:');
 | 
			
		||||
        console.log(opts.token);
 | 
			
		||||
        console.log('thumbprint:');
 | 
			
		||||
        console.log(opts.thumbprint);
 | 
			
		||||
        console.log('keyAuthorization:');
 | 
			
		||||
        console.log(opts.keyAuthorization);
 | 
			
		||||
        console.log('dnsAuthorization:');
 | 
			
		||||
        console.log(opts.dnsAuthorization);
 | 
			
		||||
        console.log("");
 | 
			
		||||
 | 
			
		||||
        console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + opts.hostname + "/" + opts.token + "'");
 | 
			
		||||
        console.log("\nThen hit the 'any' key to continue (must be specifically the 'any' key)...");
 | 
			
		||||
 | 
			
		||||
        function onAny() {
 | 
			
		||||
          process.stdin.pause();
 | 
			
		||||
          process.stdin.removeEventListener('data', onAny);
 | 
			
		||||
          process.stdin.setRawMode(false);
 | 
			
		||||
          cb();
 | 
			
		||||
        }
 | 
			
		||||
        process.stdin.setRawMode(true);
 | 
			
		||||
        process.stdin.resume();
 | 
			
		||||
        process.stdin.on('data', onAny);
 | 
			
		||||
      }
 | 
			
		||||
    , removeChallenge: function (opts, cb) {
 | 
			
		||||
				// hostname, key
 | 
			
		||||
        console.log('[DEBUG] remove challenge', hostname, key);
 | 
			
		||||
        setTimeout(cb, 1 * 1000);
 | 
			
		||||
      }
 | 
			
		||||
    , challengeType: chType
 | 
			
		||||
    , email: email
 | 
			
		||||
    , accountKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/account.privkey.pem') })
 | 
			
		||||
    , domainKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/privkey.pem') })
 | 
			
		||||
    , domains: web
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    acme2.registerNewAccount(options).then(function (account) {
 | 
			
		||||
      console.log('account:');
 | 
			
		||||
      console.log(account);
 | 
			
		||||
 | 
			
		||||
      acme2.getCertificate(options, function (fullchainPem) {
 | 
			
		||||
        console.log('[acme-v2] A fullchain.pem:');
 | 
			
		||||
        console.log(fullchainPem);
 | 
			
		||||
      }).then(function (fullchainPem) {
 | 
			
		||||
        console.log('[acme-v2] B fullchain.pem:');
 | 
			
		||||
        console.log(fullchainPem);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										57
									
								
								test.compat.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								test.compat.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var RSA = require('rsa-compat').RSA;
 | 
			
		||||
 | 
			
		||||
module.exports.run = function (web, chType, email) {
 | 
			
		||||
  console.log('[DEBUG] run', web, chType, email);
 | 
			
		||||
 | 
			
		||||
  var acme2 = require('./compat.js').ACME.create({ RSA: RSA });
 | 
			
		||||
  acme2.getAcmeUrls(acme2.stagingServerUrl, function (err, body) {
 | 
			
		||||
    if (err) { console.log('err 1'); throw err; }
 | 
			
		||||
    console.log(body);
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
      agreeToTerms: function (tosUrl, agree) {
 | 
			
		||||
        agree(null, tosUrl);
 | 
			
		||||
      }
 | 
			
		||||
    , setChallenge: function (hostname, token, val, cb) {
 | 
			
		||||
        console.log("Put the string '" + val + "' into a file at '" + hostname + "/" + acme2.acmeChallengePrefix + "/" + token + "'");
 | 
			
		||||
        console.log("echo '" + val + "' > '" + hostname + "/" + acme2.acmeChallengePrefix + "/" + token + "'");
 | 
			
		||||
        console.log("\nThen hit the 'any' key to continue (must be specifically the 'any' key)...");
 | 
			
		||||
 | 
			
		||||
        function onAny() {
 | 
			
		||||
          console.log("'any' key was hit");
 | 
			
		||||
          process.stdin.pause();
 | 
			
		||||
          process.stdin.removeListener('data', onAny);
 | 
			
		||||
          process.stdin.setRawMode(false);
 | 
			
		||||
          cb();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        process.stdin.setRawMode(true);
 | 
			
		||||
        process.stdin.resume();
 | 
			
		||||
        process.stdin.on('data', onAny);
 | 
			
		||||
      }
 | 
			
		||||
    , removeChallenge: function (hostname, key, cb) {
 | 
			
		||||
        console.log('[DEBUG] remove challenge', hostname, key);
 | 
			
		||||
        setTimeout(cb, 1 * 1000);
 | 
			
		||||
      }
 | 
			
		||||
    , challengeType: chType
 | 
			
		||||
    , email: email
 | 
			
		||||
    , accountKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/account.privkey.pem') })
 | 
			
		||||
    , domainKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/privkey.pem') })
 | 
			
		||||
    , domains: web
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    acme2.registerNewAccount(options, function (err, account) {
 | 
			
		||||
      if (err) { console.log('err 2'); throw err; }
 | 
			
		||||
      console.log('account:');
 | 
			
		||||
      console.log(account);
 | 
			
		||||
 | 
			
		||||
      acme2.getCertificate(options, function (err, fullchainPem) {
 | 
			
		||||
        if (err) { console.log('err 3'); throw err; }
 | 
			
		||||
        console.log('[acme-v2] A fullchain.pem:');
 | 
			
		||||
        console.log(fullchainPem);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										95
									
								
								test.js
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								test.js
									
									
									
									
									
								
							@ -1,56 +1,45 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
var RSA = require('rsa-compat').RSA;
 | 
			
		||||
var acme2 = require('./').ACME.create({ RSA: RSA });
 | 
			
		||||
 | 
			
		||||
acme2.getAcmeUrls(acme2.stagingServerUrl).then(function (body) {
 | 
			
		||||
  console.log(body);
 | 
			
		||||
 | 
			
		||||
  var options = {
 | 
			
		||||
    agreeToTerms: function (tosUrl, agree) {
 | 
			
		||||
      agree(null, tosUrl);
 | 
			
		||||
    }
 | 
			
		||||
    /*
 | 
			
		||||
  , setupChallenge: function (opts) {
 | 
			
		||||
      console.log('type:');
 | 
			
		||||
      console.log(ch.type);
 | 
			
		||||
      console.log('ch.token:');
 | 
			
		||||
      console.log(ch.token);
 | 
			
		||||
      console.log('thumbprint:');
 | 
			
		||||
      console.log(thumbprint);
 | 
			
		||||
      console.log('keyAuthorization:');
 | 
			
		||||
      console.log(keyAuthorization);
 | 
			
		||||
      console.log('dnsAuthorization:');
 | 
			
		||||
      console.log(dnsAuthorization);
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
    // teardownChallenge
 | 
			
		||||
  , setChallenge: function (hostname, key, val, cb) {
 | 
			
		||||
      console.log('[DEBUG] set challenge', hostname, key, val);
 | 
			
		||||
      console.log("You have 20 seconds to put the string '" + val + "' into a file at '" + hostname + "/" + key + "'");
 | 
			
		||||
      setTimeout(cb, 20 * 1000);
 | 
			
		||||
    }
 | 
			
		||||
  , removeChallenge: function (hostname, key, cb) {
 | 
			
		||||
      console.log('[DEBUG] remove challenge', hostname, key);
 | 
			
		||||
      setTimeout(cb, 1 * 1000);
 | 
			
		||||
    }
 | 
			
		||||
  , challengeType: 'http-01'
 | 
			
		||||
  , email: 'coolaj86@gmail.com'
 | 
			
		||||
  , accountKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/account.privkey.pem') })
 | 
			
		||||
  , domainKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/privkey.pem') })
 | 
			
		||||
  , domains: [ 'test.ppl.family' ]
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  acme2.registerNewAccount(options).then(function (account) {
 | 
			
		||||
    console.log('account:');
 | 
			
		||||
    console.log(account);
 | 
			
		||||
 | 
			
		||||
    acme2.getCertificate(options, function (fullchainPem) {
 | 
			
		||||
      console.log('[acme-v2] A fullchain.pem:');
 | 
			
		||||
      console.log(fullchainPem);
 | 
			
		||||
    }).then(function (fullchainPem) {
 | 
			
		||||
      console.log('[acme-v2] B fullchain.pem:');
 | 
			
		||||
      console.log(fullchainPem);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
var readline = require('readline');
 | 
			
		||||
var rl = readline.createInterface({
 | 
			
		||||
  input: process.stdin,
 | 
			
		||||
  output: process.stdout
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function getWeb() {
 | 
			
		||||
	rl.question('What web address(es) would you like to get certificates for? (ex: example.com,*.example.com) ', function (web) {
 | 
			
		||||
		web = (web||'').trim().split(/,/g);
 | 
			
		||||
		if (!web[0]) { getWeb(); return; }
 | 
			
		||||
 | 
			
		||||
    if (web.some(function (w) { return '*' === w[0]; })) {
 | 
			
		||||
      console.log('Wildcard domains must use dns-01');
 | 
			
		||||
      getEmail(web, 'dns-01');
 | 
			
		||||
    } else {
 | 
			
		||||
      getChallengeType(web);
 | 
			
		||||
    }
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getChallengeType(web) {
 | 
			
		||||
	rl.question('What challenge will you be testing today? http-01 or dns-01? [http-01] ', function (chType) {
 | 
			
		||||
		chType = (chType||'').trim();
 | 
			
		||||
		if (!chType) { chType = 'http-01'; }
 | 
			
		||||
 | 
			
		||||
		getEmail(web, chType);
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getEmail(web, chType) {
 | 
			
		||||
	rl.question('What email should we use? (optional) ', function (email) {
 | 
			
		||||
		email = (email||'').trim();
 | 
			
		||||
		if (!email) { email = null; }
 | 
			
		||||
 | 
			
		||||
    rl.close();
 | 
			
		||||
    console.log("[DEBUG] rl blah blah");
 | 
			
		||||
    require('./test.compat.js').run(web, chType, email);
 | 
			
		||||
    //require('./test.cb.js').run(web, chType, email);
 | 
			
		||||
    //require('./test.promise.js').run(web, chType, email);
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
getWeb();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										84
									
								
								test.promise.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								test.promise.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,84 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
/* global Promise */
 | 
			
		||||
 | 
			
		||||
module.exports.run = function run(web, chType, email) {
 | 
			
		||||
  var RSA = require('rsa-compat').RSA;
 | 
			
		||||
  var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory';
 | 
			
		||||
  var acme2 = require('./compat').ACME.create({ RSA: RSA });
 | 
			
		||||
  // [ 'test.ppl.family' ] 'coolaj86@gmail.com''http-01'
 | 
			
		||||
	console.log(web, chType, email);
 | 
			
		||||
	return;
 | 
			
		||||
  acme2.init(directoryUrl).then(function (body) {
 | 
			
		||||
    console.log(body);
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
    var options = {
 | 
			
		||||
      agreeToTerms: function (tosUrl, agree) {
 | 
			
		||||
        agree(null, tosUrl);
 | 
			
		||||
      }
 | 
			
		||||
    , setChallenge: function (opts) {
 | 
			
		||||
 | 
			
		||||
        console.log("");
 | 
			
		||||
        console.log('identifier:');
 | 
			
		||||
        console.log(opts.identifier);
 | 
			
		||||
        console.log('hostname:');
 | 
			
		||||
        console.log(opts.hostname);
 | 
			
		||||
        console.log('type:');
 | 
			
		||||
        console.log(opts.type);
 | 
			
		||||
        console.log('token:');
 | 
			
		||||
        console.log(opts.token);
 | 
			
		||||
        console.log('thumbprint:');
 | 
			
		||||
        console.log(opts.thumbprint);
 | 
			
		||||
        console.log('keyAuthorization:');
 | 
			
		||||
        console.log(opts.keyAuthorization);
 | 
			
		||||
        console.log('dnsAuthorization:');
 | 
			
		||||
        console.log(opts.dnsAuthorization);
 | 
			
		||||
        console.log("");
 | 
			
		||||
 | 
			
		||||
        console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + opts.hostname + "/" + opts.token + "'");
 | 
			
		||||
        console.log("\nThen hit the 'any' key to continue (must be specifically the 'any' key)...");
 | 
			
		||||
 | 
			
		||||
        return new Promise(function (resolve) {
 | 
			
		||||
          function onAny() {
 | 
			
		||||
            process.stdin.pause();
 | 
			
		||||
            process.stdin.removeEventListener('data', onAny);
 | 
			
		||||
            process.stdin.setRawMode(false);
 | 
			
		||||
 | 
			
		||||
            resolve();
 | 
			
		||||
          }
 | 
			
		||||
          process.stdin.setRawMode(true);
 | 
			
		||||
          process.stdin.resume();
 | 
			
		||||
          process.stdin.on('data', onAny);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    , removeChallenge: function (opts) {
 | 
			
		||||
				// hostname, key
 | 
			
		||||
        console.log('[DEBUG] remove challenge', opts.hostname, opts.keyAuthorization);
 | 
			
		||||
        console.log("Remove the file '" + opts.hostname + "/" + opts.token + "'");
 | 
			
		||||
 | 
			
		||||
        return new Promise(function (resolve) {
 | 
			
		||||
          setTimeout(resolve, 1 * 1000);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    , challengeType: chType
 | 
			
		||||
    , email: email
 | 
			
		||||
    , accountKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/account.privkey.pem') })
 | 
			
		||||
    , domainKeypair: RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/privkey.pem') })
 | 
			
		||||
    , domains: web
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    acme2.registerNewAccount(options).then(function (account) {
 | 
			
		||||
      console.log('account:');
 | 
			
		||||
      console.log(account);
 | 
			
		||||
 | 
			
		||||
      acme2.getCertificate(options, function (fullchainPem) {
 | 
			
		||||
        console.log('[acme-v2] A fullchain.pem:');
 | 
			
		||||
        console.log(fullchainPem);
 | 
			
		||||
      }).then(function (fullchainPem) {
 | 
			
		||||
        console.log('[acme-v2] B fullchain.pem:');
 | 
			
		||||
        console.log(fullchainPem);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user