| 
									
										
										
										
											2019-05-06 03:45:11 -06:00
										 |  |  | /*global Promise*/ | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  | (function () { | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |   'use strict'; | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |   var Keypairs = window.Keypairs; | 
					
						
							| 
									
										
										
										
											2019-04-27 00:34:49 -06:00
										 |  |  |   var Rasha = window.Rasha; | 
					
						
							|  |  |  |   var Eckles = window.Eckles; | 
					
						
							|  |  |  |   var x509 = window.x509; | 
					
						
							| 
									
										
										
										
											2019-05-06 03:45:11 -06:00
										 |  |  |   var CSR = window.CSR; | 
					
						
							|  |  |  |   var ACME = window.ACME; | 
					
						
							|  |  |  |   var accountStuff = {}; | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |   function $(sel) { | 
					
						
							|  |  |  |     return document.querySelector(sel); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   function $$(sel) { | 
					
						
							|  |  |  |     return Array.prototype.slice.call(document.querySelectorAll(sel)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 01:52:33 -06:00
										 |  |  |   function checkTos(tos) { | 
					
						
							|  |  |  |     if ($('input[name="tos"]:checked')) { | 
					
						
							|  |  |  |       return tos; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       return ''; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |   function run() { | 
					
						
							|  |  |  |     console.log('hello'); | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |     // Show different options for ECDSA vs RSA
 | 
					
						
							|  |  |  |     $$('input[name="kty"]').forEach(function ($el) { | 
					
						
							|  |  |  |       $el.addEventListener('change', function (ev) { | 
					
						
							|  |  |  |         console.log(this); | 
					
						
							|  |  |  |         console.log(ev); | 
					
						
							|  |  |  |         if ("RSA" === ev.target.value) { | 
					
						
							|  |  |  |           $('.js-rsa-opts').hidden = false; | 
					
						
							|  |  |  |           $('.js-ec-opts').hidden = true; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           $('.js-rsa-opts').hidden = true; | 
					
						
							|  |  |  |           $('.js-ec-opts').hidden = false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |     // Generate a key on submit
 | 
					
						
							|  |  |  |     $('form.js-keygen').addEventListener('submit', function (ev) { | 
					
						
							|  |  |  |       ev.preventDefault(); | 
					
						
							|  |  |  |       ev.stopPropagation(); | 
					
						
							|  |  |  |       $('.js-loading').hidden = false; | 
					
						
							|  |  |  |       $('.js-jwk').hidden = true; | 
					
						
							| 
									
										
										
										
											2019-04-27 01:24:37 -04:00
										 |  |  |       $('.js-toc-der-public').hidden = true; | 
					
						
							|  |  |  |       $('.js-toc-der-private').hidden = true; | 
					
						
							| 
									
										
										
										
											2019-04-27 00:34:49 -06:00
										 |  |  |       $$('.js-toc-pem').forEach(function ($el) { | 
					
						
							|  |  |  |         $el.hidden = true; | 
					
						
							|  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |       $$('input').map(function ($el) { $el.disabled = true; }); | 
					
						
							|  |  |  |       $$('button').map(function ($el) { $el.disabled = true; }); | 
					
						
							|  |  |  |       var opts = { | 
					
						
							|  |  |  |         kty: $('input[name="kty"]:checked').value | 
					
						
							| 
									
										
										
										
											2019-04-29 00:56:40 -06:00
										 |  |  |       , namedCurve: $('input[name="ec-crv"]:checked').value | 
					
						
							|  |  |  |       , modulusLength: $('input[name="rsa-len"]:checked').value | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |       }; | 
					
						
							| 
									
										
										
										
											2019-05-06 03:45:11 -06:00
										 |  |  |       var then = Date.now(); | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |       console.log('opts', opts); | 
					
						
							|  |  |  |       Keypairs.generate(opts).then(function (results) { | 
					
						
							| 
									
										
										
										
											2019-05-06 03:45:11 -06:00
										 |  |  |         console.log("Key generation time:", (Date.now() - then) + "ms"); | 
					
						
							| 
									
										
										
										
											2019-04-27 00:34:49 -06:00
										 |  |  |         var pubDer; | 
					
						
							|  |  |  |         var privDer; | 
					
						
							|  |  |  |         if (/EC/i.test(opts.kty)) { | 
					
						
							|  |  |  |           privDer = x509.packPkcs8(results.private); | 
					
						
							|  |  |  |           pubDer = x509.packSpki(results.public); | 
					
						
							|  |  |  |           Eckles.export({ jwk: results.private, format: 'sec1' }).then(function (pem) { | 
					
						
							|  |  |  |             $('.js-input-pem-sec1-private').innerText = pem; | 
					
						
							|  |  |  |             $('.js-toc-pem-sec1-private').hidden = false; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           Eckles.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) { | 
					
						
							|  |  |  |             $('.js-input-pem-pkcs8-private').innerText = pem; | 
					
						
							|  |  |  |             $('.js-toc-pem-pkcs8-private').hidden = false; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           Eckles.export({ jwk: results.public, public: true }).then(function (pem) { | 
					
						
							|  |  |  |             $('.js-input-pem-spki-public').innerText = pem; | 
					
						
							|  |  |  |             $('.js-toc-pem-spki-public').hidden = false; | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2019-04-27 00:31:16 -04:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2019-04-27 00:34:49 -06:00
										 |  |  |           privDer = x509.packPkcs8(results.private); | 
					
						
							|  |  |  |           pubDer = x509.packSpki(results.public); | 
					
						
							|  |  |  |           Rasha.export({ jwk: results.private, format: 'pkcs1' }).then(function (pem) { | 
					
						
							|  |  |  |             $('.js-input-pem-pkcs1-private').innerText = pem; | 
					
						
							|  |  |  |             $('.js-toc-pem-pkcs1-private').hidden = false; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           Rasha.export({ jwk: results.private, format: 'pkcs8' }).then(function (pem) { | 
					
						
							|  |  |  |             $('.js-input-pem-pkcs8-private').innerText = pem; | 
					
						
							|  |  |  |             $('.js-toc-pem-pkcs8-private').hidden = false; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           Rasha.export({ jwk: results.public, format: 'pkcs1' }).then(function (pem) { | 
					
						
							|  |  |  |             $('.js-input-pem-pkcs1-public').innerText = pem; | 
					
						
							|  |  |  |             $('.js-toc-pem-pkcs1-public').hidden = false; | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |           Rasha.export({ jwk: results.public, format: 'spki' }).then(function (pem) { | 
					
						
							|  |  |  |             $('.js-input-pem-spki-public').innerText = pem; | 
					
						
							|  |  |  |             $('.js-toc-pem-spki-public').hidden = false; | 
					
						
							|  |  |  |           }); | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:34:49 -06:00
										 |  |  |         $('.js-der-public').innerText = pubDer; | 
					
						
							| 
									
										
										
										
											2019-04-27 01:24:37 -04:00
										 |  |  |         $('.js-toc-der-public').hidden = false; | 
					
						
							| 
									
										
										
										
											2019-04-27 00:34:49 -06:00
										 |  |  |         $('.js-der-private').innerText = privDer; | 
					
						
							| 
									
										
										
										
											2019-04-27 01:24:37 -04:00
										 |  |  |         $('.js-toc-der-private').hidden = false; | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |         $('.js-jwk').innerText = JSON.stringify(results, null, 2); | 
					
						
							|  |  |  |         $('.js-loading').hidden = true; | 
					
						
							|  |  |  |         $('.js-jwk').hidden = false; | 
					
						
							|  |  |  |         $$('input').map(function ($el) { $el.disabled = false; }); | 
					
						
							|  |  |  |         $$('button').map(function ($el) { $el.disabled = false; }); | 
					
						
							|  |  |  |         $('.js-toc-jwk').hidden = false; | 
					
						
							| 
									
										
										
										
											2019-05-06 03:45:11 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $('.js-create-account').hidden = false; | 
					
						
							|  |  |  |         $('.js-create-csr').hidden = false; | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |       }); | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 01:52:33 -06:00
										 |  |  |     $('form.js-acme-account').addEventListener('submit', function (ev) { | 
					
						
							|  |  |  |       ev.preventDefault(); | 
					
						
							|  |  |  |       ev.stopPropagation(); | 
					
						
							|  |  |  |       $('.js-loading').hidden = false; | 
					
						
							|  |  |  |       var acme = ACME.create({ | 
					
						
							|  |  |  |         Keypairs: Keypairs | 
					
						
							|  |  |  |       , CSR: CSR | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       acme.init('https://acme-staging-v02.api.letsencrypt.org/directory').then(function (result) { | 
					
						
							|  |  |  |         console.log('acme result', result); | 
					
						
							|  |  |  |         var privJwk = JSON.parse($('.js-jwk').innerText).private; | 
					
						
							|  |  |  |         var email = $('.js-email').value; | 
					
						
							|  |  |  |         return acme.accounts.create({ | 
					
						
							|  |  |  |           email: email | 
					
						
							|  |  |  |         , agreeToTerms: checkTos | 
					
						
							|  |  |  |         , accountKeypair: { privateKeyJwk: privJwk } | 
					
						
							|  |  |  |         }).then(function (account) { | 
					
						
							|  |  |  |           console.log("account created result:", account); | 
					
						
							|  |  |  |           accountStuff.account = account; | 
					
						
							|  |  |  |           accountStuff.privateJwk = privJwk; | 
					
						
							|  |  |  |           accountStuff.email = email; | 
					
						
							|  |  |  |           accountStuff.acme = acme; | 
					
						
							|  |  |  |           $('.js-create-order').hidden = false; | 
					
						
							|  |  |  |           $('.js-toc-acme-account-response').hidden = false; | 
					
						
							|  |  |  |           $('.js-acme-account-response').innerText = JSON.stringify(account, null, 2); | 
					
						
							|  |  |  |         }).catch(function (err) { | 
					
						
							|  |  |  |           console.error("A bad thing happened:"); | 
					
						
							|  |  |  |           console.error(err); | 
					
						
							|  |  |  |           window.alert(err.message || JSON.stringify(err, null, 2)); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $('form.js-csr').addEventListener('submit', function (ev) { | 
					
						
							|  |  |  |       ev.preventDefault(); | 
					
						
							|  |  |  |       ev.stopPropagation(); | 
					
						
							|  |  |  |       generateCsr(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $('form.js-acme-order').addEventListener('submit', function (ev) { | 
					
						
							|  |  |  |       ev.preventDefault(); | 
					
						
							|  |  |  |       ev.stopPropagation(); | 
					
						
							|  |  |  |       var account = accountStuff.account; | 
					
						
							|  |  |  |       var privJwk = accountStuff.privateJwk; | 
					
						
							|  |  |  |       var email = accountStuff.email; | 
					
						
							|  |  |  |       var acme = accountStuff.acme; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var domains = ($('.js-domains').value||'example.com').split(/[, ]+/g); | 
					
						
							|  |  |  |       return getDomainPrivkey().then(function (domainPrivJwk) { | 
					
						
							|  |  |  |         console.log('Has CSR already?'); | 
					
						
							|  |  |  |         console.log(accountStuff.csr); | 
					
						
							|  |  |  |         return acme.certificates.create({ | 
					
						
							|  |  |  |           accountKeypair: { privateKeyJwk: privJwk } | 
					
						
							|  |  |  |         , account: account | 
					
						
							|  |  |  |         , serverKeypair: { privateKeyJwk: domainPrivJwk } | 
					
						
							|  |  |  |         , csr: accountStuff.csr | 
					
						
							|  |  |  |         , domains: domains | 
					
						
							|  |  |  |         , skipDryRun: $('input[name="skip-dryrun"]:checked') && true | 
					
						
							|  |  |  |         , agreeToTerms: checkTos | 
					
						
							|  |  |  |         , challenges: { | 
					
						
							|  |  |  |             'dns-01': { | 
					
						
							|  |  |  |               set: function (opts) { | 
					
						
							|  |  |  |                 console.info('dns-01 set challenge:'); | 
					
						
							|  |  |  |                 console.info('TXT', opts.dnsHost); | 
					
						
							|  |  |  |                 console.info(opts.dnsAuthorization); | 
					
						
							|  |  |  |                 return new Promise(function (resolve) { | 
					
						
							|  |  |  |                   while (!window.confirm("Did you set the challenge?")) {} | 
					
						
							|  |  |  |                   resolve(); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             , remove: function (opts) { | 
					
						
							|  |  |  |                 console.log('dns-01 remove challenge:'); | 
					
						
							|  |  |  |                 console.info('TXT', opts.dnsHost); | 
					
						
							|  |  |  |                 console.info(opts.dnsAuthorization); | 
					
						
							|  |  |  |                 return new Promise(function (resolve) { | 
					
						
							|  |  |  |                   while (!window.confirm("Did you delete the challenge?")) {} | 
					
						
							|  |  |  |                   resolve(); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           , 'http-01': { | 
					
						
							|  |  |  |               set: function (opts) { | 
					
						
							|  |  |  |                 console.info('http-01 set challenge:'); | 
					
						
							|  |  |  |                 console.info(opts.challengeUrl); | 
					
						
							|  |  |  |                 console.info(opts.keyAuthorization); | 
					
						
							|  |  |  |                 return new Promise(function (resolve) { | 
					
						
							|  |  |  |                   while (!window.confirm("Did you set the challenge?")) {} | 
					
						
							|  |  |  |                   resolve(); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             , remove: function (opts) { | 
					
						
							|  |  |  |                 console.log('http-01 remove challenge:'); | 
					
						
							|  |  |  |                 console.info(opts.challengeUrl); | 
					
						
							|  |  |  |                 console.info(opts.keyAuthorization); | 
					
						
							|  |  |  |                 return new Promise(function (resolve) { | 
					
						
							|  |  |  |                   while (!window.confirm("Did you delete the challenge?")) {} | 
					
						
							|  |  |  |                   resolve(); | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         , challengeTypes: [$('input[name="acme-challenge-type"]:checked').value] | 
					
						
							|  |  |  |         }).then(function (results) { | 
					
						
							|  |  |  |           console.log('Got Certificates:'); | 
					
						
							|  |  |  |           console.log(results); | 
					
						
							|  |  |  |           $('.js-toc-acme-order-response').hidden = false; | 
					
						
							|  |  |  |           $('.js-acme-order-response').innerText = JSON.stringify(results, null, 2); | 
					
						
							|  |  |  |         }).catch(function (err) { | 
					
						
							|  |  |  |           console.error("challenge failed:"); | 
					
						
							|  |  |  |           console.error(err); | 
					
						
							|  |  |  |           window.alert("failed! " + err.message || JSON.stringify(err)); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |     $('.js-generate').hidden = false; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-07 01:52:33 -06:00
										 |  |  |   function getDomainPrivkey() { | 
					
						
							|  |  |  |     if (accountStuff.domainPrivateJwk) { return Promise.resolve(accountStuff.domainPrivateJwk); } | 
					
						
							|  |  |  |     return Keypairs.generate({ | 
					
						
							|  |  |  |       kty: $('input[name="kty"]:checked').value | 
					
						
							|  |  |  |     , namedCurve: $('input[name="ec-crv"]:checked').value | 
					
						
							|  |  |  |     , modulusLength: $('input[name="rsa-len"]:checked').value | 
					
						
							|  |  |  |     }).then(function (pair) { | 
					
						
							|  |  |  |       console.log('domain keypair:', pair); | 
					
						
							|  |  |  |       accountStuff.domainPrivateJwk = pair.private; | 
					
						
							|  |  |  |       return pair.private; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function generateCsr() { | 
					
						
							|  |  |  |     var domains = ($('.js-domains').value||'example.com').split(/[, ]+/g); | 
					
						
							|  |  |  |     //var privJwk = JSON.parse($('.js-jwk').innerText).private;
 | 
					
						
							|  |  |  |     return getDomainPrivkey().then(function (privJwk) { | 
					
						
							|  |  |  |       accountStuff.domainPrivateJwk = privJwk; | 
					
						
							|  |  |  |       return CSR({ jwk: privJwk, domains: domains }).then(function (pem) { | 
					
						
							|  |  |  |         // Verify with https://www.sslshopper.com/csr-decoder.html
 | 
					
						
							|  |  |  |         accountStuff.csr = pem; | 
					
						
							|  |  |  |         console.log('Created CSR:'); | 
					
						
							|  |  |  |         console.log(pem); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         console.log('CSR info:'); | 
					
						
							|  |  |  |         console.log(CSR._info(pem)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return pem; | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-27 00:09:57 -04:00
										 |  |  |   window.addEventListener('load', run); | 
					
						
							| 
									
										
										
										
											2019-04-18 00:20:51 -06:00
										 |  |  | }()); |