mirror of
				https://github.com/therootcompany/acme.js.git
				synced 2024-11-16 17:29:00 +00:00 
			
		
		
		
	v1.0.2
This commit is contained in:
		
							parent
							
								
									9cdac50dbc
								
							
						
					
					
						commit
						a88486c313
					
				
							
								
								
									
										58
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								README.md
									
									
									
									
									
								
							| @ -1,11 +1,59 @@ | ||||
| acme-v2.js (draft 11) | ||||
| ========== | ||||
| 
 | ||||
| | [acme-v2.js](https://git.coolaj86.com/coolaj86/acme-v2.js) | ||||
| | [acme-v2-cli.js](https://git.coolaj86.com/coolaj86/acme-v2-cli.js) | ||||
| | [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js) | ||||
| | [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js) | ||||
| 
 | ||||
| | Sponsored by [ppl](https://ppl.family) | ||||
| 
 | ||||
| A framework for building letsencrypt v2 (IETF ACME draft 11) clients, successor to `le-acme-core.js`. | ||||
| A framework for building Let's Encrypt v2 (ACME draft 11) clients, successor to `le-acme-core.js`. | ||||
| Built [by request](https://git.coolaj86.com/coolaj86/greenlock.js/issues/5#issuecomment-8). | ||||
| 
 | ||||
| Summary of spec that I'm working off of here: https://git.coolaj86.com/coolaj86/greenlock.js/issues/5#issuecomment-8 | ||||
| ## Looking for Quick 'n' Easy™? | ||||
| 
 | ||||
| If you're looking for an *ACME-enabled webserver*, try [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js). | ||||
| If you're looking to *build a webserver*, try [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js). | ||||
| 
 | ||||
| * [greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js) | ||||
| * [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js) | ||||
| 
 | ||||
| ## How to build ACME clients | ||||
| 
 | ||||
| As this is intended to build ACME clients, there is not a simple 2-line example. | ||||
| 
 | ||||
| I'd recommend first running the example CLI client with a test domain and then investigating the files used for that example: | ||||
| 
 | ||||
| ```bash | ||||
| node examples/cli.js | ||||
| ``` | ||||
| 
 | ||||
| The example cli has the following prompts: | ||||
| 
 | ||||
| ``` | ||||
| What web address(es) would you like to get certificates for? (ex: example.com,*.example.com) | ||||
| What challenge will you be testing today? http-01 or dns-01? [http-01] | ||||
| What email should we use? (optional) | ||||
| What API style would you like to test? v1-compat or promise? [v1-compat] | ||||
| 
 | ||||
| Put the string 'mBfh0SqaAV3MOK3B6cAhCbIReAyDuwuxlO1Sl70x6bM.VNAzCR4THe4czVzo9piNn73B1ZXRLaB2CESwJfKkvRM' into a file at 'example.com/.well-known/acme-challenge/mBfh0SqaAV3MOK3B6cAhCbIReAyDuwuxlO1Sl70x6bM' | ||||
| 
 | ||||
| echo 'mBfh0SqaAV3MOK3B6cAhCbIReAyDuwuxlO1Sl70x6bM.VNAzCR4THe4czVzo9piNn73B1ZXRLaB2CESwJfKkvRM' > 'example.com/.well-known/acme-challenge/mBfh0SqaAV3MOK3B6cAhCbIReAyDuwuxlO1Sl70x6bM' | ||||
| 
 | ||||
| Then hit the 'any' key to continue... | ||||
| ``` | ||||
| 
 | ||||
| When you've completed the challenge you can hit a key to continue the process. | ||||
| 
 | ||||
| If you place the certificate you receive back in `tests/fullchain.pem` | ||||
| you can then test it with `examples/https-server.js`. | ||||
| 
 | ||||
| ``` | ||||
| examples/cli.js | ||||
| examples/genkeypair.js | ||||
| tests/compat.js | ||||
| ``` | ||||
| 
 | ||||
| ## Let's Encrypt Directory URLs | ||||
| 
 | ||||
| @ -136,7 +184,11 @@ Todo | ||||
| Changelog | ||||
| --------- | ||||
| 
 | ||||
| * v1.0.0 | ||||
| * v1.0.2 | ||||
|   * use `options.contact` to provide raw contact array | ||||
|   * made `options.email` optional | ||||
|   * file cleanup | ||||
| * v1.0.1 | ||||
|   * Compat API is ready for use | ||||
|   * Eliminate debug logging | ||||
| * Apr 10, 2018 - tested backwards-compatibility using greenlock.js | ||||
|  | ||||
| @ -7,6 +7,8 @@ var rl = readline.createInterface({ | ||||
|   output: process.stdout | ||||
| }); | ||||
| 
 | ||||
| require('./genkeypair.js'); | ||||
| 
 | ||||
| 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); | ||||
| @ -35,12 +37,31 @@ function getEmail(web, chType) { | ||||
|     email = (email||'').trim(); | ||||
|     if (!email) { email = null; } | ||||
| 
 | ||||
|     getApiStyle(web, chType, email); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| function getApiStyle(web, chType, email) { | ||||
|   var defaultStyle = 'compat'; | ||||
|   rl.question('What API style would you like to test? v1-compat or promise? [v1-compat] ', function (apiStyle) { | ||||
|     apiStyle = (apiStyle||'').trim(); | ||||
|     if (!apiStyle) { apiStyle = 'v1-compat'; } | ||||
| 
 | ||||
|     rl.close(); | ||||
|     var accountKeypair = RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/account.privkey.pem') }); | ||||
|     var domainKeypair = RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/privkey.pem') }); | ||||
|     //require('./test.compat.js').run(web, chType, email, accountKeypair, domainKeypair);
 | ||||
|     //require('./test.cb.js').run(web, chType, email, accountKeypair, domainKeypair);
 | ||||
|     require('./test.promise.js').run(web, chType, email, accountKeypair, domainKeypair); | ||||
| 
 | ||||
|     var RSA = require('rsa-compat').RSA; | ||||
|     var accountKeypair = RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/../tests/account.privkey.pem') }); | ||||
|     var domainKeypair = RSA.import({ privateKeyPem: require('fs').readFileSync(__dirname + '/../tests/privkey.pem') }); | ||||
|     var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory'; | ||||
| 
 | ||||
|     if ('promise' === apiStyle) { | ||||
|       require('../tests/promise.js').run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair); | ||||
|     } else if ('cb' === apiStyle) { | ||||
|       require('../tests/cb.js').run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair); | ||||
|     } else { | ||||
|       if ('v1-compat' !== apiStyle) { console.warn("Didn't understand '" + apiStyle + "', using 'v1-compat' instead..."); } | ||||
|       require('../tests/compat.js').run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair); | ||||
|     } | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										22
									
								
								examples/genkeypair.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								examples/genkeypair.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| var RSA = require('rsa-compat').RSA; | ||||
| var fs = require('fs'); | ||||
| 
 | ||||
| if (!fs.existsSync(__dirname + '/../tests/account.privkey.pem')) { | ||||
|   RSA.generateKeypair(2048, 65537, {}, function (err, keypair) { | ||||
|     console.log(keypair); | ||||
|     var privkeyPem = RSA.exportPrivatePem(keypair) | ||||
|     console.log(privkeyPem); | ||||
| 
 | ||||
|     fs.writeFileSync(__dirname + '/../tests/account.privkey.pem', privkeyPem); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| if (!fs.existsSync(__dirname + '/../tests/privkey.pem')) { | ||||
|   RSA.generateKeypair(2048, 65537, {}, function (err, keypair) { | ||||
|     console.log(keypair); | ||||
|     var privkeyPem = RSA.exportPrivatePem(keypair) | ||||
|     console.log(privkeyPem); | ||||
| 
 | ||||
|     fs.writeFileSync(__dirname + '/../tests/privkey.pem', privkeyPem); | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										7
									
								
								examples/http-server.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								examples/http-server.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var http = require('http'); | ||||
| var express = require('express'); | ||||
| var server = http.createServer(express.static('../tests')).listen(80, function () { | ||||
|   console.log('Listening on', this.address()); | ||||
| }); | ||||
							
								
								
									
										11
									
								
								examples/https-server.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								examples/https-server.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var https = require('https'); | ||||
| var server = https.createServer({ | ||||
|   key: require('fs').readFileSync('../tests/privkey.pem') | ||||
| , cert: require('fs').readFileSync('../tests/fullchain.pem') | ||||
| }, function (req, res) { | ||||
|   res.end("Hello, World!"); | ||||
| }).listen(443, function () { | ||||
|   console.log('Listening on', this.address()); | ||||
| }); | ||||
| @ -1,18 +0,0 @@ | ||||
| var RSA = require('rsa-compat').RSA; | ||||
| var fs = require('fs'); | ||||
| 
 | ||||
| RSA.generateKeypair(2048, 65537, {}, function (err, keypair) { | ||||
| 	console.log(keypair); | ||||
| 	var privkeyPem = RSA.exportPrivatePem(keypair) | ||||
| 	console.log(privkeyPem); | ||||
| 
 | ||||
| 	fs.writeFileSync(__dirname + '/account.privkey.pem', privkeyPem); | ||||
| }); | ||||
| 
 | ||||
| RSA.generateKeypair(2048, 65537, {}, function (err, keypair) { | ||||
| 	console.log(keypair); | ||||
| 	var privkeyPem = RSA.exportPrivatePem(keypair) | ||||
| 	console.log(privkeyPem); | ||||
| 
 | ||||
| 	fs.writeFileSync(__dirname + '/privkey.pem', privkeyPem); | ||||
| }); | ||||
							
								
								
									
										30
									
								
								node.js
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								node.js
									
									
									
									
									
								
							| @ -112,10 +112,16 @@ ACME._registerAccount = function (me, options) { | ||||
|         } | ||||
| 
 | ||||
|         var jwk = me.RSA.exportPublicJwk(options.accountKeypair); | ||||
|         var contact; | ||||
|         if (options.contact) { | ||||
|           contact = options.contact.slice(0); | ||||
|         } else if (options.email) { | ||||
|           contact = [ 'mailto:' + options.email ] | ||||
|         } | ||||
|         var body = { | ||||
|           termsOfServiceAgreed: tosUrl === me._tos | ||||
|         , onlyReturnExisting: false | ||||
|         , contact: [ 'mailto:' + options.email ] | ||||
|         , contact: contact | ||||
|         }; | ||||
|         if (options.externalAccount) { | ||||
|           body.externalAccountBinding = me.RSA.signJws( | ||||
| @ -150,6 +156,8 @@ ACME._registerAccount = function (me, options) { | ||||
|         , headers: { 'Content-Type': 'application/jose+json' } | ||||
|         , json: jws | ||||
|         }).then(function (resp) { | ||||
|           var account = resp.body; | ||||
| 
 | ||||
|           me._nonce = resp.toJSON().headers['replay-nonce']; | ||||
|           var location = resp.toJSON().headers.location; | ||||
|           // the account id url
 | ||||
| @ -157,15 +165,33 @@ ACME._registerAccount = function (me, options) { | ||||
|           if (me.debug) console.debug('[DEBUG] new account location:'); | ||||
|           if (me.debug) console.debug(location); | ||||
|           if (me.debug) console.debug(resp.toJSON()); | ||||
|           return resp.body; | ||||
|            | ||||
|           /* | ||||
|           { | ||||
|             id: 5925245, | ||||
|             key: | ||||
|              { kty: 'RSA', | ||||
|                n: 'tBr7m1hVaUNQjUeakznGidnrYyegVUQrsQjNrcipljI9Vxvxd0baHc3vvRZWFyFO5BlS7UDl-KHQdbdqb-MQzfP6T2sNXsOHARQ41pCGY5BYzIPRJF0nD48-CY717is-7BKISv8rf9yx5iSjvK1wZ3Ke3YIpxzK2fWRqccVxXQ92VYioxOfGObACgEUSvdoEttWV2B0Uv4Sdi6zZbk5eo2zALvyGb1P4fKVfQycGLXC41AyhHOAuTqzNCyIkiWEkbfh2lZNcYClP2epS0pHRFXYyjJN6-c8InfM3PISo4k6Qew65HZ-oqUow0tTIgNwuen9q5O6Hc73GvU-2npGJVQ', | ||||
|                e: 'AQAB' }, | ||||
|             contact: [], | ||||
|             initialIp: '198.199.82.211', | ||||
|             createdAt: '2018-04-16T00:41:00.720584972Z', | ||||
|             status: 'valid' | ||||
|           } | ||||
|           */ | ||||
|           if (!account) { account = { _emptyResponse: true, key: {} }; } | ||||
|           account.key.kid = me._kid; | ||||
|           return account; | ||||
|         }).then(resolve, reject); | ||||
|       } | ||||
| 
 | ||||
|       if (me.debug) console.debug('[acme-v2] agreeToTerms'); | ||||
|       if (1 === options.agreeToTerms.length) { | ||||
|         // newer promise API
 | ||||
|         return options.agreeToTerms(me._tos).then(agree, reject); | ||||
|       } | ||||
|       else if (2 === options.agreeToTerms.length) { | ||||
|         // backwards compat cb API
 | ||||
|         return options.agreeToTerms(me._tos, function (err, tosUrl) { | ||||
|           if (!err) { agree(tosUrl); return; } | ||||
|           reject(err); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "acme-v2", | ||||
|   "version": "1.0.1", | ||||
|   "version": "1.0.2", | ||||
|   "description": "Free SSL. A framework for building Let's Encrypt v2 clients, and other ACME v2 (draft 11) clients. Successor to le-acme-core.js", | ||||
|   "homepage": "https://git.coolaj86.com/coolaj86/acme-v2.js", | ||||
|   "main": "node.js", | ||||
|  | ||||
| @ -1,10 +1,8 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| module.exports.run = function run(web, chType, email, accountKeypair, domainKeypair) { | ||||
|   var RSA = require('rsa-compat').RSA; | ||||
|   var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory'; | ||||
|   var acme2 = require('./').ACME.create({ RSA: RSA }); | ||||
| module.exports.run = function run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair) { | ||||
|   // [ 'test.ppl.family' ] 'coolaj86@gmail.com''http-01'
 | ||||
|   var acme2 = require('../').ACME.create({ RSA: RSA }); | ||||
|   acme2.init(directoryUrl).then(function () { | ||||
|     var options = { | ||||
|       agreeToTerms: function (tosUrl, agree) { | ||||
| @ -1,11 +1,9 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| var RSA = require('rsa-compat').RSA; | ||||
| 
 | ||||
| module.exports.run = function (web, chType, email, accountKeypair, domainKeypair) { | ||||
| module.exports.run = function (directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair) { | ||||
|   console.log('[DEBUG] run', web, chType, email); | ||||
| 
 | ||||
|   var acme2 = require('./compat.js').ACME.create({ RSA: RSA }); | ||||
|   var acme2 = require('../compat.js').ACME.create({ RSA: RSA }); | ||||
|   acme2.getAcmeUrls(acme2.stagingServerUrl, function (err/*, directoryUrls*/) { | ||||
|     if (err) { console.log('err 1'); throw err; } | ||||
| 
 | ||||
| @ -44,8 +42,8 @@ module.exports.run = function (web, chType, email, accountKeypair, domainKeypair | ||||
| 
 | ||||
|     acme2.registerNewAccount(options, function (err, account) { | ||||
|       if (err) { console.log('err 2'); throw err; } | ||||
|       console.log('account:'); | ||||
|       console.log(account); | ||||
|       if (options.debug) console.debug('account:'); | ||||
|       if (options.debug) console.log(account); | ||||
| 
 | ||||
|       acme2.getCertificate(options, function (err, fullchainPem) { | ||||
|         if (err) { console.log('err 3'); throw err; } | ||||
| @ -1,10 +1,8 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| /* global Promise */ | ||||
| module.exports.run = function run(web, chType, email, accountKeypair, domainKeypair) { | ||||
|   var RSA = require('rsa-compat').RSA; | ||||
|   var directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory'; | ||||
|   var acme2 = require('./').ACME.create({ RSA: RSA }); | ||||
| module.exports.run = function run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair) { | ||||
|   var acme2 = require('../').ACME.create({ RSA: RSA }); | ||||
|   // [ 'test.ppl.family' ] 'coolaj86@gmail.com''http-01'
 | ||||
|   acme2.init(directoryUrl).then(function () { | ||||
|     var options = { | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user