diff --git a/examples/app.js b/examples/app.js index 9c2d661..4328cb8 100644 --- a/examples/app.js +++ b/examples/app.js @@ -1,274 +1,340 @@ /*global Promise*/ -(function () { - 'use strict'; +(function() { + 'use strict'; - var Keypairs = window.Keypairs; - var Rasha = window.Rasha; - var Eckles = window.Eckles; - var x509 = window.x509; - var CSR = window.CSR; - var ACME = window.ACME; - var accountStuff = {}; + var Keypairs = window.Keypairs; + var Rasha = window.Rasha; + var Eckles = window.Eckles; + var x509 = window.x509; + var CSR = window.CSR; + var ACME = window.ACME; + var accountStuff = {}; - function $(sel) { - return document.querySelector(sel); - } - function $$(sel) { - return Array.prototype.slice.call(document.querySelectorAll(sel)); - } + function $(sel) { + return document.querySelector(sel); + } + function $$(sel) { + return Array.prototype.slice.call(document.querySelectorAll(sel)); + } - function checkTos(tos) { - if ($('input[name="tos"]:checked')) { - return tos; - } else { - return ''; - } - } + function checkTos(tos) { + if ($('input[name="tos"]:checked')) { + return tos; + } else { + return ''; + } + } - function run() { - console.log('hello'); + function run() { + console.log('hello'); - // 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; - } - }); - }); + // 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; + } + }); + }); - // Generate a key on submit - $('form.js-keygen').addEventListener('submit', function (ev) { - ev.preventDefault(); - ev.stopPropagation(); - $('.js-loading').hidden = false; - $('.js-jwk').hidden = true; - $('.js-toc-der-public').hidden = true; - $('.js-toc-der-private').hidden = true; - $$('.js-toc-pem').forEach(function ($el) { - $el.hidden = true; - }); - $$('input').map(function ($el) { $el.disabled = true; }); - $$('button').map(function ($el) { $el.disabled = true; }); - var opts = { - kty: $('input[name="kty"]:checked').value - , namedCurve: $('input[name="ec-crv"]:checked').value - , modulusLength: $('input[name="rsa-len"]:checked').value - }; - var then = Date.now(); - console.log('opts', opts); - Keypairs.generate(opts).then(function (results) { - console.log("Key generation time:", (Date.now() - then) + "ms"); - 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; - }); - } else { - 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; - }); - } + // Generate a key on submit + $('form.js-keygen').addEventListener('submit', function(ev) { + ev.preventDefault(); + ev.stopPropagation(); + $('.js-loading').hidden = false; + $('.js-jwk').hidden = true; + $('.js-toc-der-public').hidden = true; + $('.js-toc-der-private').hidden = true; + $$('.js-toc-pem').forEach(function($el) { + $el.hidden = true; + }); + $$('input').map(function($el) { + $el.disabled = true; + }); + $$('button').map(function($el) { + $el.disabled = true; + }); + var opts = { + kty: $('input[name="kty"]:checked').value, + namedCurve: $('input[name="ec-crv"]:checked').value, + modulusLength: $('input[name="rsa-len"]:checked').value + }; + var then = Date.now(); + console.log('opts', opts); + Keypairs.generate(opts).then(function(results) { + console.log('Key generation time:', Date.now() - then + 'ms'); + 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; + } + ); + } else { + 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; + } + ); + } - $('.js-der-public').innerText = pubDer; - $('.js-toc-der-public').hidden = false; - $('.js-der-private').innerText = privDer; - $('.js-toc-der-private').hidden = false; - $('.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; + $('.js-der-public').innerText = pubDer; + $('.js-toc-der-public').hidden = false; + $('.js-der-private').innerText = privDer; + $('.js-toc-der-private').hidden = false; + $('.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; - $('.js-create-account').hidden = false; - $('.js-create-csr').hidden = false; - }); - }); + $('.js-create-account').hidden = false; + $('.js-create-csr').hidden = false; + }); + }); - $('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-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-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; + $('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) + ); + }); + }); + }); - 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)); - }); - }); - }); + $('.js-generate').hidden = false; + } - $('.js-generate').hidden = false; - } + 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 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); - 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)); - console.log('CSR info:'); - console.log(CSR._info(pem)); + return pem; + }); + }); + } - return pem; - }); - }); - } - - window.addEventListener('load', run); -}()); + window.addEventListener('load', run); +})(); diff --git a/examples/example.env b/examples/example.env new file mode 100644 index 0000000..540ca23 --- /dev/null +++ b/examples/example.env @@ -0,0 +1,6 @@ +ENV=DEV +SUBSCRIBER_EMAIL=letsencrypt+staging@example.com +BASE_DOMAIN=test.example.com +CHALLENGE_TYPE=dns-01 +CHALLENGE_PLUGIN=digitalocean +CHALLENGE_OPTIONS='{"token":"xxxxxxxxxxxx"}' diff --git a/examples/index.html b/examples/index.html index a176e70..4113d78 100644 --- a/examples/index.html +++ b/examples/index.html @@ -1,153 +1,238 @@ - - Bluecrypt ACME - A Root Project - - - -

@bluecrypt/acme: Let's Encrypt for the Browser

+ + Bluecrypt ACME - A Root Project + + + + +

+ @bluecrypt/acme: Let's Encrypt for the Browser +

-

This is intended to be explored with your JavaScript console open.

-
<script src="https://rootprojects.org/acme/bluecrypt-acme.js"></script>
-
<script src="https://rootprojects.org/acme/bluecrypt-acme.min.js"></script>
- Documentation +

+ This is intended to be explored with your JavaScript console open. +

+
<script src="https://rootprojects.org/acme/bluecrypt-acme.js"></script>
+
<script src="https://rootprojects.org/acme/bluecrypt-acme.min.js"></script>
+ Documentation -

1. Keypair Generation

-
-

Key Type:

-
- - - - -
-
-

EC Options:

- - - -
- - -
+ + + + -

2. ACME Account

-
- - -
- -
- -
+

2. ACME Account

+
+ + +
+ +
+ +
-

3. (optional) Certificate Signing Request

-
- - -
- -
+

3. (optional) Certificate Signing Request

+
+ + +
+ +
-

4. ACME Certificate Order

-
- Challenge type: - - -
- -
- -
+

4. ACME Certificate Order

+
+ Challenge type: + + +
+ +
+ +
- + - - - - - - - - - - + + + + + + + + + + -
-

Bluecrypt™ is a collection of lightweight, zero-dependency, libraries written in VanillaJS. - They are fast, tiny, and secure, using the native features of modern browsers where possible. - This means it's easy-to-use crypto in kilobytes, not megabytes.

-
- +
+

+ Bluecrypt™ is a collection of lightweight, zero-dependency, + libraries written in VanillaJS. They are fast, tiny, and secure, + using the native features of modern browsers where possible. This + means it's easy-to-use crypto in kilobytes, not megabytes. +

+
+ - - - - - - - - - - - + + + + + + + + + + +