diff --git a/express-server/LICENSE b/express-server/LICENSE
new file mode 100644
index 00000000..b9ef4d36
--- /dev/null
+++ b/express-server/LICENSE
@@ -0,0 +1,41 @@
+Copyright 2017 AJ ONeal
+
+This is open source software; you can redistribute it and/or modify it under the
+terms of either:
+
+ a) the "MIT License"
+ b) the "Apache-2.0 License"
+
+MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+Apache-2.0 License Summary
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/express-server/examples/demo.js b/express-server/examples/demo.js
new file mode 100644
index 00000000..d9bee690
--- /dev/null
+++ b/express-server/examples/demo.js
@@ -0,0 +1,75 @@
+'use strict';
+
+// npm install spdy@3.x
+
+//var Greenlock = require('greenlock-express')
+var Greenlock = require('../');
+
+var greenlock = Greenlock.create({
+
+ // Let's Encrypt v2 is ACME draft 11
+ version: 'draft-11'
+
+, server: 'https://acme-v02.api.letsencrypt.org/directory'
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+
+ // You MUST change this to a valid email address
+, email: 'jon@example.com'
+
+ // You MUST NOT build clients that accept the ToS without asking the user
+, agreeTos: true
+
+ // You MUST change these to valid domains
+ // NOTE: all domains will validated and listed on the certificate
+, approvedDomains: [ 'example.com', 'www.example.com' ]
+
+ // You MUST have access to write to directory where certs are saved
+ // ex: /home/foouser/acme/etc
+, configDir: '~/.config/acme/'
+
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+
+//, debug: true
+
+});
+
+
+
+////////////////////////
+// http-01 Challenges //
+////////////////////////
+
+// http-01 challenge happens over http/1.1, not http2
+var redirectHttps = require('redirect-https')();
+var acmeChallengeHandler = greenlock.middleware(function (req, res) {
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
+ res.end('
Hello, ⚠️ Insecure World!
Visit Secure Site'
+ + ''
+ );
+});
+require('http').createServer(acmeChallengeHandler).listen(80, function () {
+ console.log("Listening for ACME http-01 challenges on", this.address());
+});
+
+
+
+////////////////////////
+// http2 via SPDY h2 //
+////////////////////////
+
+// spdy is a drop-in replacement for the https API
+var spdyOptions = Object.assign({}, greenlock.tlsOptions);
+spdyOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false };
+var server = require('spdy').createServer(spdyOptions, require('express')().use('/', function (req, res) {
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
+ res.end('
Hello, 🔐 Secure World!
');
+}));
+server.on('error', function (err) {
+ console.error(err);
+});
+server.on('listening', function () {
+ console.log("Listening for SPDY/http2/https requests on", this.address());
+});
+server.listen(443);
diff --git a/express-server/examples/force-renew.js b/express-server/examples/force-renew.js
new file mode 100644
index 00000000..8c8f4638
--- /dev/null
+++ b/express-server/examples/force-renew.js
@@ -0,0 +1,29 @@
+'use strict';
+
+//require('greenlock-express')
+require('../').create({
+
+ // Let's Encrypt v2 is ACME draft 11
+ version: 'draft-11'
+
+, server: 'https://acme-v02.api.letsencrypt.org/directory'
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+
+, email: 'john.doe@example.com'
+
+, agreeTos: true
+
+, approvedDomains: [ 'example.com', 'www.example.com' ]
+
+, app: require('express')().use('/', function (req, res) {
+ res.end('Hello, World!');
+ })
+
+, renewWithin: (91 * 24 * 60 * 60 * 1000)
+, renewBy: (90 * 24 * 60 * 60 * 1000)
+
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+, debug: true
+}).listen(80, 443);
diff --git a/express-server/examples/http2.js b/express-server/examples/http2.js
new file mode 100644
index 00000000..5b30c65e
--- /dev/null
+++ b/express-server/examples/http2.js
@@ -0,0 +1,74 @@
+'use strict';
+
+//var Greenlock = require('greenlock-express')
+var Greenlock = require('../');
+
+var greenlock = Greenlock.create({
+
+ // Let's Encrypt v2 is ACME draft 11
+ version: 'draft-11'
+
+, server: 'https://acme-v02.api.letsencrypt.org/directory'
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+
+ // You MUST change this to a valid email address
+, email: 'jon@example.com'
+
+ // You MUST NOT build clients that accept the ToS without asking the user
+, agreeTos: true
+
+ // You MUST change these to valid domains
+ // NOTE: all domains will validated and listed on the certificate
+, approvedDomains: [ 'example.com', 'www.example.com' ]
+
+ // You MUST have access to write to directory where certs are saved
+ // ex: /home/foouser/acme/etc
+, configDir: '~/.config/acme/'
+
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+
+//, debug: true
+
+});
+
+
+
+////////////////////////
+// http-01 Challenges //
+////////////////////////
+
+// http-01 challenge happens over http/1.1, not http2
+var redirectHttps = require('redirect-https')();
+var acmeChallengeHandler = greenlock.middleware(redirectHttps);
+require('http').createServer(acmeChallengeHandler).listen(80, function () {
+ console.log("Listening for ACME http-01 challenges on", this.address());
+});
+
+
+
+////////////////////////
+// node.js' http2 api //
+////////////////////////
+
+// http2 is a new API with which you would use hapi or koa, not express
+var server = require('http2').createSecureServer(greenlock.tlsOptions);
+server.on('error', function (err) {
+ console.error(err);
+});
+// WARNING: Because the middleware don't handle this API style,
+// the Host headers are unmodified and potentially dangerous
+// (ex: Host: Robert'); DROP TABLE Students;)
+server.on('stream', function (stream, headers) {
+ console.log(headers);
+ stream.respond({
+ 'content-type': 'text/html'
+ , ':status': 200
+ });
+ stream.end('Hello, HTTP2 World!');
+});
+server.on('listening', function () {
+ console.log("Listening for http2 requests on", this.address());
+});
+server.listen(443);
diff --git a/express-server/examples/my-express-app.js b/express-server/examples/my-express-app.js
new file mode 100644
index 00000000..04da0987
--- /dev/null
+++ b/express-server/examples/my-express-app.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var express = require('express');
+var app = express();
+
+app.use('/', function (req, res) {
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
+ res.end('Hello, World!\n\n💚 🔒.js');
+});
+
+// DO NOT DO app.listen() unless we're testing this directly
+if (require.main === module) { app.listen(3000); }
+
+// Instead do export the app:
+module.exports = app;
diff --git a/express-server/examples/production.js b/express-server/examples/production.js
new file mode 100644
index 00000000..08ee7efc
--- /dev/null
+++ b/express-server/examples/production.js
@@ -0,0 +1,90 @@
+'use strict';
+
+//
+// My Secure Server
+//
+//var greenlock = require('greenlock-express')
+var greenlock = require('../').create({
+
+ // Let's Encrypt v2 is ACME draft 11
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+ server: 'https://acme-v02.api.letsencrypt.org/directory'
+, version: 'draft-11'
+ // You MUST have write access to save certs
+, configDir: '~/.config/acme/'
+
+// The previous 'simple' example set these values statically,
+// but this example uses approveDomains() to set them dynamically
+//, email: 'none@see.note.above'
+//, agreeTos: false
+
+ // approveDomains is the right place to check a database for
+ // email addresses with domains and agreements and such
+, approveDomains: approveDomains
+
+, app: require('./my-express-app.js')
+
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+
+//, debug: true
+
+});
+
+var server = greenlock.listen(80, 443);
+
+
+//
+// My Secure Database Check
+//
+function approveDomains(opts, certs, cb) {
+
+ // Only one domain is listed with *automatic* registration via SNI
+ // (it's an array because managed registration allows for multiple domains,
+ // which was the case in the simple example)
+ console.log(opts.domains);
+
+ // The domains being approved for the first time are listed in opts.domains
+ // Certs being renewed are listed in certs.altnames
+ if (certs) {
+ opts.domains = [certs.subject].concat(certs.altnames);
+ }
+
+ fooCheckDb(opts.domains, function (err, agree, email) {
+ if (err) { cb(err); return; }
+
+ // Services SHOULD automatically accept the ToS and use YOUR email
+ // Clients MUST NOT accept the ToS without asking the user
+ opts.agreeTos = agree;
+ opts.email = email;
+
+ // NOTE: you can also change other options such as `challengeType` and `challenge`
+ // (this would be helpful if you decided you wanted wildcard support as a domain altname)
+ // opts.challengeType = 'http-01';
+ // opts.challenge = require('le-challenge-fs').create({});
+
+ cb(null, { options: opts, certs: certs });
+ });
+}
+
+
+//
+// My User / Domain Database
+//
+function fooCheckDb(domains, cb) {
+ // This is an oversimplified example of how we might implement a check in
+ // our database if we have different rules for different users and domains
+ var domains = [ 'example.com', 'www.example.com' ];
+ var userEmail = 'john.doe@example.com';
+ var userAgrees = true;
+ var passCheck = opts.domains.every(function (domain) {
+ return -1 !== domains.indexOf(domain);
+ });
+
+ if (!passCheck) {
+ cb(new Error('domain not allowed'));
+ } else {
+ cb(null, userAgrees, userEmail);
+ }
+}
diff --git a/express-server/examples/quickstart.js b/express-server/examples/quickstart.js
new file mode 100644
index 00000000..322f7ecf
--- /dev/null
+++ b/express-server/examples/quickstart.js
@@ -0,0 +1,36 @@
+'use strict';
+
+var app = require('../app');
+
+//require('greenlock-express')
+require('../').create({
+
+ // Let's Encrypt v2 is ACME draft 11
+ version: 'draft-11'
+
+, server: 'https://acme-v02.api.letsencrypt.org/directory'
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+
+ // You MUST change this to a valid email address
+, email: 'lukas.n912@gmail.com'
+
+ // You MUST NOT build clients that accept the ToS without asking the user
+, agreeTos: true
+
+ // You MUST change these to valid domains
+ // NOTE: all domains will validated and listed on the certificate
+, approvedDomains: [ 'www.smartshopper.cf', 'smartshopper.cf']
+
+ // You MUST have access to write to directory where certs are saved
+ // ex: /home/foouser/acme/etc
+, configDir: '~/.config/acme/'
+
+, app: app
+
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+
+//, debug: true
+
+}).listen(7000, 443);
diff --git a/express-server/examples/remote-access.js b/express-server/examples/remote-access.js
new file mode 100644
index 00000000..87676d6f
--- /dev/null
+++ b/express-server/examples/remote-access.js
@@ -0,0 +1,95 @@
+'use strict';
+
+//
+// WARNING: Not for noobs
+// Try the simple example first
+//
+
+//
+// This demo is used with tunnel-server.js and tunnel-client.js
+//
+
+var email = 'john.doe@gmail.com';
+var domains = [ 'example.com' ];
+var agreeLeTos = true;
+//var secret = "My Little Brony";
+var secret = require('crypto').randomBytes(16).toString('hex');
+
+require('../').create({
+ version: 'draft-11'
+
+, server: 'https://acme-v02.api.letsencrypt.org/directory'
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+
+, email: email
+, agreeTos: agreeLeTos
+, approveDomains: domains
+, configDir: '~/.config/acme/'
+, app: remoteAccess(secret)
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+//, debug: true
+}).listen(3000, 8443);
+
+
+function remoteAccess(secret) {
+ var express = require('express');
+ var basicAuth = require('express-basic-auth');
+ var serveIndex = require('serve-index');
+
+ var rootIndex = serveIndex('/', { hidden: true, icons: true, view: 'details' });
+ var rootFs = express.static('/', { dotfiles: 'allow', redirect: true, index: false });
+
+ var userIndex = serveIndex(require('os').homedir(), { hidden: true, icons: true, view: 'details' });
+ var userFs = express.static(require('os').homedir(), { dotfiles: 'allow', redirect: true, index: false });
+
+ var app = express();
+ var realm = 'Login Required';
+
+ var myAuth = basicAuth({
+ users: { 'root': secret, 'user': secret }
+ , challenge: true
+ , realm: realm
+ , unauthorizedResponse: function (/*req*/) {
+ return 'Unauthorized Home';
+ }
+ });
+
+ app.get('/', function (req, res) {
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
+ res.end(
+ 'View Files'
+ + ' | '
+ + 'Logout'
+ );
+ });
+ app.use('/logout', function (req, res) {
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
+ res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
+ res.statusCode = 401;
+ //res.setHeader('Location', '/');
+ res.end('Logged out | Home');
+ });
+ app.use('/browse', myAuth);
+ app.use('/browse', function (req, res, next) {
+ if ('root' === req.auth.user) { rootFs(req, res, function () { rootIndex(req, res, next); }); return; }
+ if ('user' === req.auth.user) { userFs(req, res, function () { userIndex(req, res, next); }); return; }
+ res.end('Sad Panda');
+ });
+
+ console.log('');
+ console.log('');
+ console.log('Usernames are\n');
+ console.log('\troot');
+ console.log('\tuser');
+ console.log('');
+ console.log('Password (for both) is\n');
+ console.log('\t' + secret);
+ console.log('');
+ console.log("Shhhh... It's a secret to everybody!");
+ console.log('');
+ console.log('');
+
+ return app;
+}
diff --git a/express-server/examples/spdy.js b/express-server/examples/spdy.js
new file mode 100644
index 00000000..0af24704
--- /dev/null
+++ b/express-server/examples/spdy.js
@@ -0,0 +1,68 @@
+'use strict';
+
+// npm install spdy@3.x
+
+//var Greenlock = require('greenlock-express')
+var Greenlock = require('../');
+
+var greenlock = Greenlock.create({
+
+ // Let's Encrypt v2 is ACME draft 11
+ version: 'draft-11'
+
+, server: 'https://acme-v02.api.letsencrypt.org/directory'
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+
+ // You MUST change this to a valid email address
+, email: 'jon@example.com'
+
+ // You MUST NOT build clients that accept the ToS without asking the user
+, agreeTos: true
+
+ // You MUST change these to valid domains
+ // NOTE: all domains will validated and listed on the certificate
+, approvedDomains: [ 'example.com', 'www.example.com' ]
+
+ // You MUST have access to write to directory where certs are saved
+ // ex: /home/foouser/acme/etc
+, configDir: '~/.config/acme/' // MUST have write access
+
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+
+//, debug: true
+
+});
+
+
+
+////////////////////////
+// http-01 Challenges //
+////////////////////////
+
+// http-01 challenge happens over http/1.1, not http2
+var redirectHttps = require('redirect-https')();
+var acmeChallengeHandler = greenlock.middleware(redirectHttps);
+require('http').createServer(acmeChallengeHandler).listen(80, function () {
+ console.log("Listening for ACME http-01 challenges on", this.address());
+});
+
+
+
+////////////////////////
+// http2 via SPDY h2 //
+////////////////////////
+
+// spdy is a drop-in replacement for the https API
+var spdyOptions = Object.assign({}, greenlock.tlsOptions);
+spdyOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false };
+var myApp = require('./my-express-app.js');
+var server = require('spdy').createServer(spdyOptions, myApp);
+server.on('error', function (err) {
+ console.error(err);
+});
+server.on('listening', function () {
+ console.log("Listening for SPDY/http2/https requests on", this.address());
+});
+server.listen(443);
diff --git a/express-server/examples/vhost.js b/express-server/examples/vhost.js
new file mode 100644
index 00000000..977b7633
--- /dev/null
+++ b/express-server/examples/vhost.js
@@ -0,0 +1,114 @@
+#!/usr/bin/env node
+'use strict';
+
+///////////////////
+// vhost example //
+///////////////////
+
+//
+// virtual hosting example
+//
+
+// The prefix where sites go by name.
+// For example: whatever.com may live in /srv/www/whatever.com, thus /srv/www is our path
+var srv = '/srv/www/';
+
+var path = require('path');
+var fs = require('fs');
+var finalhandler = require('finalhandler');
+var serveStatic = require('serve-static');
+
+//var glx = require('greenlock-express')
+var glx = require('../').create({
+
+ version: 'draft-11' // Let's Encrypt v2 is ACME draft 11
+
+, server: 'https://acme-v02.api.letsencrypt.org/directory' // If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+
+, configDir: '~/.config/acme/' // You MUST have access to write to directory where certs
+ // are saved. ex: /home/foouser/.config/acme
+
+, approveDomains: myApproveDomains // Greenlock's wraps around tls.SNICallback. Check the
+ // domain name here and reject invalid ones
+
+, app: myVhostApp // Any node-style http app (i.e. express, koa, hapi, rill)
+
+ /* CHANGE TO A VALID EMAIL */
+, email:'jon@example.com' // Email for Let's Encrypt account and Greenlock Security
+, agreeTos: true // Accept Let's Encrypt ToS
+, communityMember: true // Join Greenlock to get important updates, no spam
+
+//, debug: true
+
+});
+
+var server = glx.listen(80, 443);
+server.on('listening', function () {
+ console.info(server.type + " listening on", server.address());
+});
+
+// [SECURITY]
+// Since v2.4.0+ Greenlock proactively protects against
+// SQL injection and timing attacks by rejecting invalid domain names,
+// but it's up to you to make sure that you accept opts.domain BEFORE
+// an attempt is made to issue a certificate for it.
+function myApproveDomains(opts, certs, cb) {
+
+ // In this example the filesystem is our "database".
+ // We check in /srv/www/ for opts.domain (i.e. "example.com") and only proceed if it exists.
+ console.log(opts.domain);
+
+ // Check that the hosting domain exists on the file system.
+ var hostdir = path.join(srv, opts.domain);
+ fs.readdir(hostdir, function (err, nodes) {
+ var e;
+ if (err || !nodes) {
+ e = new Error("rejecting '" + opts.domains[0] + "' because '" + hostdir + "' could not be read");
+ console.error(e);
+ console.error(err);
+ cb(e);
+ return;
+ }
+
+ // You could put a variety of configuration details alongside the vhost folder
+ // For example, /srv/www/example.com.json could describe the following:
+
+ // If you have multiple domains grouped together, you can list them on the same certificate
+ // opts.domains = [ 'example.com', 'www.example.com', 'api.example.com', 'sso.example.com' ]
+
+ // You can also change other options on-the-fly
+ // (approveDomains is called after the in-memory certificates cache is checked, but before any ACME requests)
+
+ // opts.email = "jon@example.com"
+ // opts.agreeTos = true;
+ // opts.challengeType = 'http-01';
+ // opts.challenge = require('le-challenge-fs').create({});
+ cb(null, { options: opts, certs: certs });
+ });
+
+}
+
+// [SECURITY]
+// Since v2.4.0+ Greenlock Express will proactively protect against
+// SQL injection and timing attacks by rejecting invalid domain names
+// in Host headers.
+// It will also make them lowercase and protect against "domain fronting".
+// However, it's up to you to make sure you actually have a domain to serve :)
+var servers = {};
+function myVhostApp(req, res) {
+ var hostname = req.headers.host;
+ var srvpath = path.join(srv, hostname);
+ console.log('vhost for', req.headers.host);
+
+ if (!servers[hostname]) {
+ try {
+ fs.accessSync(srvpath);
+ servers[hostname] = serveStatic(srvpath, { redirect: true });
+ } catch(e) {
+ finalhandler(req, res);
+ }
+ }
+
+ servers[hostname](req, res, finalhandler(req, res));
+}
diff --git a/express-server/examples/websockets.js b/express-server/examples/websockets.js
new file mode 100644
index 00000000..54a69da3
--- /dev/null
+++ b/express-server/examples/websockets.js
@@ -0,0 +1,40 @@
+'use strict';
+
+
+////////////////////////
+// Greenlock Setup //
+////////////////////////
+
+//var Greenlock = require('greenlock-express');
+var Greenlock = require('../');
+var greenlock = Greenlock.create({
+
+ // Let's Encrypt v2 is ACME draft 11
+ // Note: If at first you don't succeed, stop and switch to staging
+ // https://acme-staging-v02.api.letsencrypt.org/directory
+ server: 'https://acme-v02.api.letsencrypt.org/directory'
+, version: 'draft-11'
+, configDir: '~/.config/acme/'
+, app: require('./my-express-app.js')
+
+ // You MUST change these to a valid email and domains
+, email: 'john.doe@example.com'
+, approvedDomains: [ 'example.com', 'www.example.com' ]
+, agreeTos: true
+
+ // Get notified of important updates and help me make greenlock better
+, communityMember: true
+, telemetry: true
+//, debug: true
+});
+
+var server = greenlock.listen(80, 443);
+
+var WebSocket = require('ws');
+var ws = new WebSocket.Server({ server: server });
+ws.on('connection', function (ws, req) {
+ // inspect req.headers.authorization (or cookies) for session info
+ ws.send("[Secure Echo Server] Hello!\nAuth: '" + (req.headers.authorization || 'none') + "'\n"
+ + "Cookie: '" + (req.headers.cookie || 'none') + "'\n");
+ ws.on('message', function (data) { ws.send(data); });
+});
diff --git a/express-server/index.js b/express-server/index.js
new file mode 100644
index 00000000..cbab69fe
--- /dev/null
+++ b/express-server/index.js
@@ -0,0 +1,159 @@
+'use strict';
+
+var PromiseA;
+try {
+ PromiseA = require('bluebird');
+} catch(e) {
+ PromiseA = global.Promise;
+}
+
+// opts.approveDomains(options, certs, cb)
+module.exports.create = function (opts) {
+ // accept all defaults for greenlock.challenges, greenlock.store, greenlock.middleware
+ if (!opts._communityPackage) {
+ opts._communityPackage = 'greenlock-express.js';
+ opts._communityPackageVersion = require('./package.json').version;
+ }
+
+ function explainError(e) {
+ console.error('Error:' + e.message);
+ if ('EACCES' === e.errno) {
+ console.error("You don't have prmission to access '" + e.address + ":" + e.port + "'.");
+ console.error("You probably need to use \"sudo\" or \"sudo setcap 'cap_net_bind_service=+ep' $(which node)\"");
+ return;
+ }
+ if ('EADDRINUSE' === e.errno) {
+ console.error("'" + e.address + ":" + e.port + "' is already being used by some other program.");
+ console.error("You probably need to stop that program or restart your computer.");
+ return;
+ }
+ console.error(e.code + ": '" + e.address + ":" + e.port + "'");
+ }
+
+ function _listen(plainPort, plain) {
+ if (!plainPort) { plainPort = 80; }
+
+ var parts = String(plainPort).split(':');
+ var p = parts.pop();
+ var addr = parts.join(':').replace(/^\[/, '').replace(/\]$/, '');
+ var args = [];
+ var httpType;
+ var server;
+ var validHttpPort = (parseInt(p, 10) >= 0);
+
+ function tryPlain() {
+ server = require('http').createServer(
+ greenlock.middleware.sanitizeHost(greenlock.middleware(require('redirect-https')()))
+ );
+ httpType = 'http';
+ }
+
+ function trySecure() {
+ var https;
+ try {
+ https = require('spdy');
+ greenlock.tlsOptions.spdy = { protocols: [ 'h2', 'http/1.1' ], plain: false };
+ httpType = 'http2 (spdy/h2)';
+ } catch(e) {
+ https = require('https');
+ httpType = 'https';
+ }
+ server = https.createServer(
+ greenlock.tlsOptions
+ , greenlock.middleware.sanitizeHost(function (req, res) {
+ try {
+ greenlock.app(req, res);
+ } catch(e) {
+ console.error("[error] [greenlock.app] Your HTTP handler had an uncaught error:");
+ console.error(e);
+ try {
+ res.statusCode = 500;
+ res.end("Internal Server Error: [Greenlock] HTTP exception logged for user-provided handler.");
+ } catch(e) {
+ // ignore
+ // (headers may have already been sent, etc)
+ }
+ }
+ })
+ );
+ server.type = httpType;
+ }
+
+ if (addr) { args[1] = addr; }
+ if (!validHttpPort && !/(\/)|(\\\\)/.test(p)) {
+ console.warn("'" + p + "' doesn't seem to be a valid port number, socket path, or pipe");
+ }
+ if (plain) { tryPlain(); } else { trySecure(); }
+
+ var promise = new PromiseA(function (resolve) {
+ args[0] = p;
+ args.push(function () { resolve(server); });
+ server.listen.apply(server, args).on('error', function (e) {
+ if (server.listenerCount('error') < 2) {
+ console.warn("Did not successfully create http server and bind to port '" + p + "':");
+ explainError(e);
+ process.exit(41);
+ }
+ });
+ });
+
+ promise.server = server;
+ return promise;
+ }
+
+ // NOTE: 'greenlock' is just 'opts' renamed
+ var greenlock = require('greenlock').create(opts);
+
+ if (!opts.app) {
+ opts.app = function (req, res) {
+ res.end("Hello, World!\nWith Love,\nGreenlock for Express.js");
+ };
+ }
+
+ opts.listen = function (plainPort, port, fnPlain, fn) {
+ var promises = [];
+ var server;
+ var plainServer;
+
+ // If there is only one handler for the `listening` (i.e. TCP bound) event
+ // then we want to use it as HTTPS (backwards compat)
+ if (!fn) {
+ fn = fnPlain;
+ fnPlain = null;
+ }
+
+ promises.push(_listen(plainPort, true));
+ promises.push(_listen(port, false));
+
+ server = promises[1].server;
+ plainServer = promises[0].server;
+
+ PromiseA.all(promises).then(function () {
+ // Report plain http status
+ if ('function' === typeof fnPlain) {
+ fnPlain.apply(plainServer);
+ } else if (!fn && !plainServer.listenerCount('listening') && !server.listenerCount('listening')) {
+ console.info('[:' + (plainServer.address().port || plainServer.address())
+ + "] Handling ACME challenges and redirecting to " + server.type);
+ }
+
+ // Report h2/https status
+ if ('function' === typeof fn) {
+ fn.apply(server);
+ } else if (!server.listenerCount('listening')) {
+ console.info('[:' + (server.address().port || server.address()) + "] Serving " + server.type);
+ }
+ });
+
+ server.unencrypted = plainServer;
+ return server;
+ };
+ opts.middleware.acme = function (opts) {
+ return greenlock.middleware.sanitizeHost(greenlock.middleware(require('redirect-https')(opts)));
+ };
+ opts.middleware.secure = function (app) {
+ return greenlock.middleware.sanitizeHost(app);
+ };
+
+ return greenlock;
+};
diff --git a/express-server/node_modules/.bin/certpem b/express-server/node_modules/.bin/certpem
new file mode 100644
index 00000000..a5f556fb
--- /dev/null
+++ b/express-server/node_modules/.bin/certpem
@@ -0,0 +1,52 @@
+#!/usr/bin/env node
+
+'use strict';
+
+var certpem = require('../').certpem;
+var path = require('path');
+var filepath = (process.cwd() + path.sep + 'cert.pem');
+var debug = false;
+var json;
+var cert;
+
+if (/--debug/.test(process.argv[2]) || /--debug/.test(process.argv[3])) {
+ debug = true;
+}
+if (/--json/.test(process.argv[2]) || /--json/.test(process.argv[3])) {
+ json = true;
+}
+if (process.argv[2] && !/^--/.test(process.argv[2])) {
+ filepath = process.argv[2];
+}
+if (process.argv[3] && !/^--/.test(process.argv[3])) {
+ filepath = process.argv[3];
+}
+
+if (filepath.length > 256) {
+ cert = filepath;
+}
+else {
+ cert = require('fs').readFileSync(filepath, 'ascii');
+}
+
+if (debug) {
+ console.info(JSON.stringify(certpem.debug(cert), null, ' '));
+} else {
+ var c = certpem.info(cert);
+
+ if (json) {
+ console.info(JSON.stringify(c, null, ' '));
+ return;
+ }
+
+ console.info('');
+
+ console.info('Certificate for', c.subject);
+ console.info('');
+ console.info('Altnames:', c.altnames.join(', '));
+ console.info('');
+ console.info('Issued at', new Date(c.issuedAt));
+ console.info('Expires at', new Date(c.expiresAt));
+
+ console.info('');
+}
diff --git a/express-server/node_modules/.bin/mkdirp b/express-server/node_modules/.bin/mkdirp
new file mode 100644
index 00000000..d95de15a
--- /dev/null
+++ b/express-server/node_modules/.bin/mkdirp
@@ -0,0 +1,33 @@
+#!/usr/bin/env node
+
+var mkdirp = require('../');
+var minimist = require('minimist');
+var fs = require('fs');
+
+var argv = minimist(process.argv.slice(2), {
+ alias: { m: 'mode', h: 'help' },
+ string: [ 'mode' ]
+});
+if (argv.help) {
+ fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
+ return;
+}
+
+var paths = argv._.slice();
+var mode = argv.mode ? parseInt(argv.mode, 8) : undefined;
+
+(function next () {
+ if (paths.length === 0) return;
+ var p = paths.shift();
+
+ if (mode === undefined) mkdirp(p, cb)
+ else mkdirp(p, mode, cb)
+
+ function cb (err) {
+ if (err) {
+ console.error(err.message);
+ process.exit(1);
+ }
+ else next();
+ }
+})();
diff --git a/express-server/node_modules/.bin/rsa-keygen-js b/express-server/node_modules/.bin/rsa-keygen-js
new file mode 100644
index 00000000..e65176f5
--- /dev/null
+++ b/express-server/node_modules/.bin/rsa-keygen-js
@@ -0,0 +1,35 @@
+#!/usr/bin/env node
+'use strict';
+
+var RSA = require('../').RSA;
+var path = require('path');
+var fs = require('fs');
+
+var bitlen = 2048;
+var exp = 65537;
+var opts = { public: true, pem: true };
+var cwd = process.cwd();
+var privkeyPath = path.join(cwd, 'privkey.pem');
+var pubkeyPath = path.join(cwd, 'pubkey.pem');
+
+if (fs.existsSync(privkeyPath)) {
+ console.error(privkeyPath, "already exists");
+ process.exit(1);
+}
+
+RSA.generateKeypair(bitlen, exp, opts, function (err, keypair) {
+ console.info('');
+ console.info('');
+
+ fs.writeFileSync(privkeyPath, keypair.privateKeyPem, 'ascii');
+ console.info(privkeyPath + ':');
+ console.info('');
+ console.info(keypair.privateKeyPem);
+
+ console.info('');
+
+ fs.writeFileSync(pubkeyPath, keypair.publicKeyPem, 'ascii');
+ console.info(pubkeyPath + ':');
+ console.info('');
+ console.info(keypair.publicKeyPem);
+});
diff --git a/express-server/node_modules/@coolaj86/urequest/LICENSE b/express-server/node_modules/@coolaj86/urequest/LICENSE
new file mode 100644
index 00000000..693448ab
--- /dev/null
+++ b/express-server/node_modules/@coolaj86/urequest/LICENSE
@@ -0,0 +1,41 @@
+Copyright 2018 AJ ONeal
+
+This is open source software; you can redistribute it and/or modify it under the
+terms of either:
+
+ a) the "MIT License"
+ b) the "Apache-2.0 License"
+
+MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+Apache-2.0 License Summary
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/express-server/node_modules/@coolaj86/urequest/README.md b/express-server/node_modules/@coolaj86/urequest/README.md
new file mode 100644
index 00000000..304e6b2d
--- /dev/null
+++ b/express-server/node_modules/@coolaj86/urequest/README.md
@@ -0,0 +1,339 @@
+# µRequest - Minimalist HTTP client
+
+A lightweight alternative to (and drop-in replacement for) request.
+
+Written from scratch.
+
+## Super simple to use
+
+µRequest is designed to be a drop-in replacement for request. It supports HTTPS and follows redirects by default.
+
+```bash
+npm install --save @coolaj86/urequest
+```
+
+```js
+var request = require('@coolaj86/urequest');
+request('http://www.google.com', function (error, response, body) {
+ console.log('error:', error); // Print the error if one occurred
+ console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
+ console.log('body:', body); // Print the HTML for the Google homepage.
+});
+```
+
+## Table of contents
+
+- [Forms](#forms)
+- [HTTP Authentication](#http-authentication)
+- [Custom HTTP Headers](#custom-http-headers)
+- [Unix Domain Sockets](#unix-domain-sockets)
+- [**All Available Options**](#requestoptions-callback)
+
+## Forms
+
+`urequest` supports `application/x-www-form-urlencoded` and `multipart/form-data` form uploads.
+
+
+#### application/x-www-form-urlencoded (URL-Encoded Forms)
+
+URL-encoded forms are simple.
+
+```js
+request.post('http://service.com/upload', {form:{key:'value'}})
+// or
+request.post({url:'http://service.com/upload', form: {key:'value'}}, function(err,httpResponse,body){ /* ... */ })
+```
+
+
+
+#### multipart/form-data (Multipart Form Uploads)
+
+For `multipart/form-data` we use the [form-data](https://github.com/form-data/form-data) library by [@felixge](https://github.com/felixge). For the most cases, you can pass your upload form data via the `formData` option.
+
+
+```js
+var formData = {
+ // Pass a simple key-value pair
+ my_field: 'my_value',
+ // Pass data via Buffers
+ my_buffer: Buffer.from([1, 2, 3]),
+ // Pass data via Streams
+ my_file: fs.createReadStream(__dirname + '/unicycle.jpg'),
+ // Pass multiple values /w an Array
+ attachments: [
+ fs.createReadStream(__dirname + '/attachment1.jpg'),
+ fs.createReadStream(__dirname + '/attachment2.jpg')
+ ],
+ // Pass optional meta-data with an 'options' object with style: {value: DATA, options: OPTIONS}
+ // Use case: for some types of streams, you'll need to provide "file"-related information manually.
+ // See the `form-data` README for more information about options: https://github.com/form-data/form-data
+ custom_file: {
+ value: fs.createReadStream('/dev/urandom'),
+ options: {
+ filename: 'topsecret.jpg',
+ contentType: 'image/jpeg'
+ }
+ }
+};
+request.post({url:'http://service.com/upload', formData: formData}, function optionalCallback(err, httpResponse, body) {
+ if (err) {
+ return console.error('upload failed:', err);
+ }
+ console.log('Upload successful! Server responded with:', body);
+});
+```
+
+
+See the [form-data README](https://github.com/form-data/form-data) for more information & examples.
+
+---
+
+## HTTP Authentication
+
+
+```js
+request.get('http://some.server.com/', {
+ 'auth': {
+ 'user': 'username',
+ 'pass': 'password',
+ 'sendImmediately': false
+ }
+});
+// or
+request.get('http://some.server.com/', {
+ 'auth': {
+ 'bearer': 'bearerToken'
+ }
+});
+```
+
+If passed as an option, `auth` should be a hash containing values:
+
+- `user` || `username`
+- `pass` || `password`
+- `bearer` (optional)
+
+
+
+Note that you can also specify basic authentication using the URL itself, as
+detailed in [RFC 1738](http://www.ietf.org/rfc/rfc1738.txt). Simply pass the
+`user:password` before the host with an `@` sign:
+
+```js
+var username = 'username',
+ password = 'password',
+ url = 'http://' + username + ':' + password + '@some.server.com';
+
+request({url: url}, function (error, response, body) {
+ // Do more stuff with 'body' here
+});
+```
+
+
+
+Bearer authentication is supported, and is activated when the `bearer` value is
+available. The value may be either a `String` or a `Function` returning a
+`String`. Using a function to supply the bearer token is particularly useful if
+used in conjunction with `defaults` to allow a single function to supply the
+last known token at the time of sending a request, or to compute one on the fly.
+
+[back to top](#table-of-contents)
+
+---
+
+## Custom HTTP Headers
+
+HTTP Headers, such as `User-Agent`, can be set in the `options` object.
+In the example below, we call the github API to find out the number
+of stars and forks for the request repository. This requires a
+custom `User-Agent` header as well as https.
+
+```js
+var request = require('request');
+
+var options = {
+ url: 'https://api.github.com/repos/request/request',
+ headers: {
+ 'User-Agent': 'request'
+ }
+};
+
+function callback(error, response, body) {
+ if (!error && response.statusCode == 200) {
+ var info = JSON.parse(body);
+ console.log(info.stargazers_count + " Stars");
+ console.log(info.forks_count + " Forks");
+ }
+}
+
+request(options, callback);
+```
+
+[back to top](#table-of-contents)
+
+---
+
+## UNIX Domain Sockets
+
+`urequest` supports making requests to [UNIX Domain Sockets](https://en.wikipedia.org/wiki/Unix_domain_socket). To make one, use the following URL scheme:
+
+```js
+/* Pattern */ 'http://unix:SOCKET:PATH'
+/* Example */ request.get('http://unix:/absolute/path/to/unix.socket:/request/path')
+```
+
+Note: The `SOCKET` path is assumed to be absolute to the root of the host file system.
+
+[back to top](#table-of-contents)
+
+---
+
+## request(options, callback)
+
+The first argument can be either a `url` or an `options` object. The only required option is `uri`; all others are optional.
+
+- `uri` || `url` - fully qualified uri or a parsed url object from `url.parse()`
+- `method` - http method (default: `"GET"`)
+- `headers` - http headers (default: `{}`)
+
+
+
+---
+
+- `body` - entity body for PATCH, POST and PUT requests. Must be a `Buffer`, `String` or `ReadStream`. If `json` is `true`, then `body` must be a JSON-serializable object.
+- `json` - sets `body` to JSON representation of value and adds `Content-type: application/json` header. Additionally, parses the response body as JSON.
+
+
+
+---
+
+- `followRedirect` - follow HTTP 3xx responses as redirects (default: `true`). This property can also be implemented as function which gets `response` object as a single argument and should return `true` if redirects should continue or `false` otherwise.
+- `followAllRedirects` - follow non-GET HTTP 3xx responses as redirects (default: `false`)
+- `followOriginalHttpMethod` - by default we redirect to HTTP method GET. you can enable this property to redirect to the original HTTP method (default: `false`)
+- `maxRedirects` - the maximum number of redirects to follow (default: `10`)
+- `removeRefererHeader` - removes the referer header when a redirect happens (default: `false`). **Note:** if true, referer header set in the initial request is preserved during redirect chain.
+
+---
+
+- `encoding` - encoding to be used on `setEncoding` of response data. If `null`, the `body` is returned as a `Buffer`. Anything else **(including the default value of `undefined`)** will be passed as the [encoding](http://nodejs.org/api/buffer.html#buffer_buffer) parameter to `toString()` (meaning this is effectively `utf8` by default). (**Note:** if you expect binary data, you should set `encoding: null`.)
+
+
+
+---
+
+## Convenience methods
+
+There are also shorthand methods for different HTTP METHODs and some other conveniences.
+
+### request.defaults(options)
+
+This method **returns a wrapper** around the normal request API that defaults
+to whatever options you pass to it.
+
+**Note:** `request.defaults()` **does not** modify the global request API;
+instead, it **returns a wrapper** that has your default settings applied to it.
+
+**Note:** You can call `.defaults()` on the wrapper that is returned from
+`request.defaults` to add/override defaults that were previously defaulted.
+
+For example:
+```js
+//requests using baseRequest() will set the 'x-token' header
+var baseRequest = request.defaults({
+ headers: {'x-token': 'my-token'}
+})
+
+//requests using specialRequest() will include the 'x-token' header set in
+//baseRequest and will also include the 'special' header
+var specialRequest = baseRequest.defaults({
+ headers: {special: 'special value'}
+})
+```
+
+### request.METHOD()
+
+These HTTP method convenience functions act just like `request()` but with a default method already set for you:
+
+- *request.get()*: Defaults to `method: "GET"`.
+- *request.post()*: Defaults to `method: "POST"`.
+- *request.put()*: Defaults to `method: "PUT"`.
+- *request.patch()*: Defaults to `method: "PATCH"`.
+- *request.del() / request.delete()*: Defaults to `method: "DELETE"`.
+- *request.head()*: Defaults to `method: "HEAD"`.
+- *request.options()*: Defaults to `method: "OPTIONS"`.
+
+---
+
+## Debugging
+
+There are at least two ways to debug the operation of `request`:
+
+1. Launch the node process like `NODE_DEBUG=urequest node script.js`
+ (`lib,request,otherlib` works too).
+
+2. Set `require('@coolaj86/urequest').debug = true` at any time (this does the same thing
+ as #1).
+
+
+
+[back to top](#table-of-contents)
diff --git a/express-server/node_modules/@coolaj86/urequest/index.js b/express-server/node_modules/@coolaj86/urequest/index.js
new file mode 100644
index 00000000..c4a71fde
--- /dev/null
+++ b/express-server/node_modules/@coolaj86/urequest/index.js
@@ -0,0 +1,425 @@
+'use strict';
+
+var http = require('http');
+var https = require('https');
+var url = require('url');
+
+function debug() {
+ if (module.exports.debug) {
+ console.log.apply(console, arguments);
+ }
+}
+
+function mergeOrDelete(defaults, updates) {
+ Object.keys(defaults).forEach(function (key) {
+ if (!(key in updates)) {
+ updates[key] = defaults[key];
+ return;
+ }
+
+ // neither accept the prior default nor define an explicit value
+ // CRDT probs...
+ if ('undefined' === typeof updates[key]) {
+ delete updates[key];
+ } else if ('object' === typeof defaults[key] && 'object' === typeof updates[key]) {
+ updates[key] = mergeOrDelete(defaults[key], updates[key]);
+ }
+ });
+
+ return updates;
+}
+
+// retrieves an existing header, case-sensitive
+function getHeaderName(reqOpts, header) {
+ var headerNames = {};
+ Object.keys(reqOpts.headers).forEach(function (casedName) {
+ headerNames[casedName.toLowerCase()] = casedName;
+ });
+ // returns the key, which in erroneous cases could be an empty string
+ return headerNames[header.toLowerCase()];
+}
+// returns whether or not a header exists, case-insensitive
+function hasHeader(reqOpts, header) {
+ return 'undefined' !== typeof getHeaderName(reqOpts, header);
+}
+
+function toJSONifier(keys) {
+
+ return function () {
+ var obj = {};
+ var me = this;
+
+ keys.forEach(function (key) {
+ if (me[key] && 'function' === typeof me[key].toJSON) {
+ obj[key] = me[key].toJSON();
+ } else {
+ obj[key] = me[key];
+ }
+ });
+
+ return obj;
+ };
+}
+
+function setDefaults(defs) {
+ defs = defs || {};
+
+ function urequestHelper(opts, cb) {
+ debug("\n[urequest] processed options:");
+ debug(opts);
+
+ function onResponse(resp) {
+ var followRedirect;
+
+ Object.keys(defs).forEach(function (key) {
+ if (key in opts && 'undefined' !== typeof opts[key]) {
+ return;
+ }
+ opts[key] = defs[key];
+ });
+ followRedirect = opts.followRedirect;
+
+ resp.toJSON = toJSONifier([ 'statusCode', 'body', 'headers', 'request' ]);
+
+ resp.request = req;
+ resp.request.uri = url.parse(opts.url);
+ //resp.request.method = opts.method;
+ resp.request.headers = finalOpts.headers;
+ resp.request.toJSON = toJSONifier([ 'uri', 'method', 'headers' ]);
+
+ if (followRedirect && resp.headers.location && -1 !== [ 301, 302, 307, 308 ].indexOf(resp.statusCode)) {
+ debug('Following redirect: ' + resp.headers.location);
+ if ('GET' !== opts.method && !opts.followAllRedirects) {
+ followRedirect = false;
+ }
+ if (opts._redirectCount >= opts.maxRedirects) {
+ followRedirect = false;
+ }
+ if ('function' === opts.followRedirect) {
+ if (!opts.followRedirect(resp)) {
+ followRedirect = false;
+ }
+ }
+ if (followRedirect) {
+ if (!opts.followOriginalHttpMethod) {
+ opts.method = 'GET';
+ opts.body = null;
+ delete opts.headers[getHeaderName(opts, 'Content-Length')];
+ delete opts.headers[getHeaderName(opts, 'Transfer-Encoding')];
+ }
+ if (opts.removeRefererHeader && opts.headers) {
+ delete opts.headers.referer;
+ }
+ // TODO needs baseUrl, maybe test for host / socketPath?
+ opts.url = resp.headers.location;
+ opts.uri = url.parse(opts.url);
+ return urequestHelper(opts, cb);
+ }
+ }
+ if (null === opts.encoding) {
+ resp._body = [];
+ } else {
+ resp.body = '';
+ }
+ resp._bodyLength = 0;
+ resp.on('data', function (chunk) {
+ if ('string' === typeof resp.body) {
+ resp.body += chunk.toString(opts.encoding);
+ } else {
+ resp._body.push(chunk);
+ resp._bodyLength += chunk.length;
+ }
+ });
+ resp.on('end', function () {
+ if ('string' !== typeof resp.body) {
+ if (1 === resp._body.length) {
+ resp.body = resp._body[0];
+ } else {
+ resp.body = Buffer.concat(resp._body, resp._bodyLength);
+ }
+ resp._body = null;
+ }
+ if (opts.json && 'string' === typeof resp.body) {
+ // TODO I would parse based on Content-Type
+ // but request.js doesn't do that.
+ try {
+ resp.body = JSON.parse(resp.body);
+ } catch(e) {
+ // ignore
+ }
+ }
+
+ debug("\n[urequest] resp.toJSON():");
+ debug(resp.toJSON());
+ cb(null, resp, resp.body);
+ });
+ }
+
+ var req;
+ var finalOpts = {};
+ var _body;
+ var MyFormData;
+ var form;
+ var formHeaders;
+ var requester;
+
+ if (opts.body) {
+ if (true === opts.json) {
+ _body = JSON.stringify(opts.body);
+ } else {
+ _body = opts.body;
+ }
+ } else if (opts.json && true !== opts.json) {
+ _body = JSON.stringify(opts.json);
+ } else if (opts.form) {
+ _body = Object.keys(opts.form).filter(function (key) {
+ if ('undefined' !== typeof opts.form[key]) {
+ return true;
+ }
+ }).map(function (key) {
+ return encodeURIComponent(key) + '=' + encodeURIComponent(String(opts.form[key]));
+ }).join('&');
+ opts.headers['Content-Type'] = 'application/x-www-form-urlencoded';
+ }
+ if ('string' === typeof _body) {
+ _body = Buffer.from(_body);
+ }
+
+ Object.keys(opts.uri).forEach(function (key) {
+ finalOpts[key] = opts.uri[key];
+ });
+ finalOpts.method = opts.method;
+ finalOpts.headers = JSON.parse(JSON.stringify(opts.headers));
+ if (_body) {
+ // Most APIs expect (or require) Content-Length except in the case of multipart uploads
+ // Transfer-Encoding: Chunked (the default) is generally only well-supported downstream
+ finalOpts.headers['Content-Length'] = _body.byteLength || _body.length;
+ }
+ if (opts.auth) {
+ // if opts.uri specifies auth it will be parsed by url.parse and passed directly to the http module
+ if ('string' !== typeof opts.auth) {
+ opts.auth = (opts.auth.user||opts.auth.username||'') + ':' + (opts.auth.pass||opts.auth.password||'');
+ }
+ if ('string' === typeof opts.auth) {
+ finalOpts.auth = opts.auth;
+ }
+ if (false === opts.sendImmediately) {
+ console.warn("[Warn] setting `sendImmediately: false` is not yet supported. Please open an issue if this is an important feature that you need.");
+ }
+ if (opts.bearer) {
+ // having a shortcut for base64 encoding makes sense, but this? Eh, whatevs...
+ finalOpts.header.Authorization = 'Bearer: ' + opts.bearer;
+ }
+ }
+ if (opts.formData) {
+ try {
+ MyFormData = opts.FormData || require('form-data');
+ // potential options https://github.com/felixge/node-combined-stream/blob/master/lib/combined_stream.js#L7-L15
+ } catch(e) {
+ console.error("urequest does not include extra dependencies by default");
+ console.error("if you need to use 'form-data' you may install it, like so:");
+ console.error(" npm install --save form-data");
+ cb(e);
+ return;
+ }
+ try {
+ form = new MyFormData();
+ Object.keys(opts.formData).forEach(function (key) {
+ function add(key, data, opts) {
+ if (data.value) { opts = data.options; data = data.value; }
+ form.append(key, data, opts);
+ }
+ if (Array.isArray(opts.formData[key])) {
+ opts.formData[key].forEach(function (data) {
+ add(key, data);
+ });
+ } else {
+ add(key, opts.formData[key]);
+ }
+ });
+ } catch(e) {
+ cb(e);
+ return;
+ }
+ formHeaders = form.getHeaders();
+ Object.keys(formHeaders).forEach(function (header) {
+ finalOpts.headers[header] = formHeaders[header];
+ });
+ }
+
+ // TODO support unix sockets
+ if ('https:' === finalOpts.protocol) {
+ // https://nodejs.org/api/https.html#https_https_request_options_callback
+ debug("\n[urequest] https.request(opts):");
+ debug(finalOpts);
+ requester = https;
+ } else if ('http:' === finalOpts.protocol) {
+ // https://nodejs.org/api/http.html#http_http_request_options_callback
+ debug("\n[urequest] http.request(opts):");
+ debug(finalOpts);
+ requester = http;
+ } else {
+ cb(new Error("unknown protocol: '" + opts.uri.protocol + "'"));
+ return;
+ }
+
+ if (form) {
+ debug("\n[urequest] '" + finalOpts.method + "' (request) form");
+ debug(formHeaders);
+ // generally uploads don't use Chunked Encoding (some systems have issues with it)
+ // and I don't want to do the work to calculate the content-lengths. This seems to work.
+ req = form.submit(finalOpts, function (err, resp) {
+ if (err) { cb(err); return; }
+ onResponse(resp);
+ resp.resume();
+ });
+ //req = requester.request(finalOpts, onResponse);
+ //req.on('error', cb);
+ //form.pipe(req);
+ return;
+ }
+
+ req = requester.request(finalOpts, onResponse);
+ req.on('error', cb);
+
+ if (_body) {
+ debug("\n[urequest] '" + finalOpts.method + "' (request) body");
+ debug(_body);
+ // used for chunked encoding
+ //req.write(_body);
+ // used for known content-length
+ req.end(_body);
+ } else {
+ req.end();
+ }
+ }
+
+ function parseUrl(str) {
+ var obj = url.parse(str);
+ var paths;
+ if ('unix' !== (obj.hostname||obj.host||'').toLowerCase()) {
+ return obj;
+ }
+
+ obj.href = null;
+ obj.hostname = obj.host = null;
+
+ paths = (obj.pathname||obj.path||'').split(':');
+
+ obj.socketPath = paths.shift();
+ obj.pathname = obj.path = paths.join(':');
+
+ return obj;
+ }
+
+ function urequest(opts, cb) {
+ debug("\n[urequest] received options:");
+ debug(opts);
+ var reqOpts = {};
+ // request.js behavior:
+ // encoding: null + json ? unknown
+ // json => attempt to parse, fail silently
+ // encoding => buffer.toString(encoding)
+ // null === encoding => Buffer.concat(buffers)
+ if ('string' === typeof opts) {
+ opts = { url: opts };
+ }
+
+ module.exports._keys.forEach(function (key) {
+ if (key in opts && 'undefined' !== typeof opts[key]) {
+ reqOpts[key] = opts[key];
+ } else if (key in defs) {
+ reqOpts[key] = defs[key];
+ }
+ });
+
+ // TODO url.resolve(defs.baseUrl, opts.url);
+ if ('string' === typeof opts.url || 'string' === typeof opts.uri) {
+ if ('string' === typeof opts.url) {
+ reqOpts.url = opts.url;
+ reqOpts.uri = parseUrl(opts.url);
+ } else if ('string' === typeof opts.uri) {
+ reqOpts.url = opts.uri;
+ reqOpts.uri = parseUrl(opts.uri);
+ }
+ } else {
+ if ('object' === typeof opts.uri) {
+ reqOpts.url = url.format(opts.uri);
+ reqOpts.uri = opts.uri;
+ //reqOpts.uri = url.parse(reqOpts.uri);
+ } else if ('object' === typeof opts.url) {
+ reqOpts.url = url.format(opts.url);
+ reqOpts.uri = opts.url;
+ //reqOpts.uri = url.parse(reqOpts.url);
+ }
+ }
+
+ if (opts.body || 'string' === typeof opts.json || opts.form || opts.formData) {
+ // TODO this is probably a deviation from request's API
+ // need to check and probably eliminate it
+ reqOpts.method = (reqOpts.method || 'POST').toUpperCase();
+ } else {
+ reqOpts.method = (reqOpts.method || 'GET').toUpperCase();
+ }
+ if (!reqOpts.headers) {
+ reqOpts.headers = {};
+ }
+
+ // crazy case for easier testing
+ if (!hasHeader(reqOpts, 'CoNTeNT-TyPe')) {
+ if ((true === reqOpts.json && reqOpts.body)
+ || (true !== reqOpts.json && reqOpts.json)) {
+ reqOpts.headers['Content-Type'] = 'application/json';
+ }
+ }
+
+ return urequestHelper(reqOpts, cb);
+ }
+
+ urequest.defaults = function (_defs) {
+ _defs = mergeOrDelete(defs, _defs);
+ return setDefaults(_defs);
+ };
+ [ 'get', 'put', 'post', 'patch', 'delete', 'head', 'options' ].forEach(function (method) {
+ urequest[method] = function (obj) {
+ if ('string' === typeof obj) {
+ obj = { url: obj };
+ }
+ obj.method = method.toUpperCase();
+ urequest(obj);
+ };
+ });
+ urequest.del = urequest.delete;
+
+ return urequest;
+}
+
+var _defaults = {
+ sendImmediately: true
+, method: 'GET'
+, headers: {}
+, useQuerystring: false
+, followRedirect: true
+, followAllRedirects: false
+, followOriginalHttpMethod: false
+, maxRedirects: 10
+, removeRefererHeader: false
+//, encoding: undefined
+, gzip: false
+//, body: undefined
+//, json: undefined
+};
+module.exports = setDefaults(_defaults);
+
+module.exports._keys = Object.keys(_defaults).concat([
+ 'encoding'
+, 'body'
+, 'json'
+, 'form'
+, 'auth'
+, 'formData'
+, 'FormData'
+]);
+module.exports.debug = (-1 !== (process.env.NODE_DEBUG||'').split(/\s+/g).indexOf('urequest'));
+
+debug("DEBUG ON for urequest");
diff --git a/express-server/node_modules/@coolaj86/urequest/package.json b/express-server/node_modules/@coolaj86/urequest/package.json
new file mode 100644
index 00000000..902bae88
--- /dev/null
+++ b/express-server/node_modules/@coolaj86/urequest/package.json
@@ -0,0 +1,90 @@
+{
+ "_args": [
+ [
+ "@coolaj86/urequest@^1.3.6",
+ "/nodeapps/https-test/greenlock-express.js/node_modules/acme-v2"
+ ]
+ ],
+ "_from": "@coolaj86/urequest@>=1.3.6 <2.0.0",
+ "_id": "@coolaj86/urequest@1.3.6",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/@coolaj86/urequest",
+ "_nodeVersion": "10.6.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/urequest_1.3.6_1531386792567_0.12131716051599817"
+ },
+ "_npmUser": {
+ "email": "coolaj86@gmail.com",
+ "name": "coolaj86"
+ },
+ "_npmVersion": "6.1.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "@coolaj86/urequest",
+ "raw": "@coolaj86/urequest@^1.3.6",
+ "rawSpec": "^1.3.6",
+ "scope": "@coolaj86",
+ "spec": ">=1.3.6 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/acme-v2"
+ ],
+ "_resolved": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.6.tgz",
+ "_shasum": "e962d62000d7786a3920e5ef2c863223353b2e7f",
+ "_shrinkwrap": null,
+ "_spec": "@coolaj86/urequest@^1.3.6",
+ "_where": "/nodeapps/https-test/greenlock-express.js/node_modules/acme-v2",
+ "author": {
+ "email": "coolaj86@gmail.com",
+ "name": "AJ ONeal",
+ "url": "https://coolaj86.com/"
+ },
+ "dependencies": {},
+ "description": "A lightweight drop-in replacement for request",
+ "devDependencies": {},
+ "directories": {
+ "example": "examples"
+ },
+ "dist": {
+ "fileCount": 4,
+ "integrity": "sha512-9rBXLFSb5D19opGeXdD/WuiFJsA4Pk2r8VUGEAeUZUxB1a2zB47K85BKAx3Gy9i4nZwg22ejlJA+q9DVrpQlbA==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbRxuoCRA9TVsSAnZWagAApwoP/1j5hEoPiQ8KUaczLwxA\ndecbvvUHz5ePW/gpccAfZkjlQzJozZx+PUlpJGFE2ees6lmSjtoW3kq8bAQU\n/BOtmSGUy1VLmDsj1hJ2NVRXSxa9B7ujUzfbxUgL8zOe0/c/rnx3/gEsRg0I\nML9GyogGHbvVx86EdFLYvAo5Gnc6xpFnid/a5Dr7F60C4ACUakDt1jyeEVug\n6CqgU3I/Zw+7NUKWJebPvo7XxLuHi39ScrSMCNRfwEpXWTMpNW+Doz/2PTxv\nTuCXxktRyOjV6tGTv/aMaNqVVdkm2KQEmFfnukrspzEmopmovBMoIhalE0c9\nRwkuGANODSa6Fy6Fu1wU/RbNwgllTxHp+jYFKstenSw8b8/BOqz4P5kWHIAU\nZTd0vLXzY6yTWX7kPEMmq1wt3ydQmckcUzh3+3jIQSjoVZ2aNL+4y1ng/42P\nxQBktUzEUEawl2vSupTN7W6oFcTRHlQxbtQezZjeT5wyz5HWQF7j9s7JQIOO\nnha56Z22hQrmvkXqzDv9cOD3d/lWVWVYOx/PEEVyQVb+ITf21jWLpYu6XCUO\n5LwfK4c+bwJIjyB9I7cYUvxEPhDoXgS0/mft3jqo/WjS+zAOGQA2896PCCrf\n709nMBUAO1cmO2RXpJVU3iqXsfaT5F1IUJl7P0Wgo3bG0ZlCKJ+89z8WPY+h\nyhQm\r\n=ibEw\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "e962d62000d7786a3920e5ef2c863223353b2e7f",
+ "tarball": "https://registry.npmjs.org/@coolaj86/urequest/-/urequest-1.3.6.tgz",
+ "unpackedSize": 28820
+ },
+ "files": [
+ "lib"
+ ],
+ "gitHead": "49daa68225e6f53685125ef9ccd0183221ed1b68",
+ "keywords": [
+ "alternative",
+ "call",
+ "http",
+ "https",
+ "lightweight",
+ "request"
+ ],
+ "license": "(MIT OR Apache-2.0)",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "coolaj86",
+ "email": "coolaj86@gmail.com"
+ }
+ ],
+ "name": "@coolaj86/urequest",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "https://git.ppl.family/ppl/urequest.js.git"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "version": "1.3.6"
+}
diff --git a/express-server/node_modules/acme-v2/.jshintrc b/express-server/node_modules/acme-v2/.jshintrc
new file mode 100644
index 00000000..0bcd7880
--- /dev/null
+++ b/express-server/node_modules/acme-v2/.jshintrc
@@ -0,0 +1,18 @@
+{ "node": true
+, "browser": true
+, "jquery": true
+, "globals": { "angular": true, "Promise": true }
+
+, "indent": 2
+, "onevar": true
+, "laxcomma": true
+, "laxbreak": true
+, "curly": true
+, "nonbsp": true
+
+, "eqeqeq": true
+, "immed": true
+, "undef": true
+, "unused": true
+, "latedef": true
+}
\ No newline at end of file
diff --git a/express-server/node_modules/acme-v2/LICENSE b/express-server/node_modules/acme-v2/LICENSE
new file mode 100644
index 00000000..693448ab
--- /dev/null
+++ b/express-server/node_modules/acme-v2/LICENSE
@@ -0,0 +1,41 @@
+Copyright 2018 AJ ONeal
+
+This is open source software; you can redistribute it and/or modify it under the
+terms of either:
+
+ a) the "MIT License"
+ b) the "Apache-2.0 License"
+
+MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+Apache-2.0 License Summary
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/express-server/node_modules/acme-v2/README.md b/express-server/node_modules/acme-v2/README.md
new file mode 100644
index 00000000..f37bea65
--- /dev/null
+++ b/express-server/node_modules/acme-v2/README.md
@@ -0,0 +1,221 @@
+| Sponsored by [ppl](https://ppl.family)
+| **acme-v2.js** ([npm](https://www.npmjs.com/package/acme-v2))
+| [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)
+|
+
+acme-v2.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).
+
+## 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
+examples/https-server.js
+examples/http-server.js
+```
+
+## Let's Encrypt Directory URLs
+
+```
+# Production URL
+https://acme-v02.api.letsencrypt.org/directory
+```
+
+```
+# Staging URL
+https://acme-staging-v02.api.letsencrypt.org/directory
+```
+
+## Two API versions, Two Implementations
+
+This library (acme-v2.js) supports ACME [*draft 11*](https://tools.ietf.org/html/draft-ietf-acme-acme-11),
+otherwise known as Let's Encrypt v2 (or v02).
+
+ * ACME draft 11
+ * Let's Encrypt v2
+ * Let's Encrypt v02
+
+The predecessor (le-acme-core) supports Let's Encrypt v1 (or v01), which was a
+[hodge-podge of various drafts](https://github.com/letsencrypt/boulder/blob/master/docs/acme-divergences.md)
+of the ACME spec early on.
+
+ * ACME early draft
+ * Let's Encrypt v1
+ * Let's Encrypt v01
+
+This library maintains compatibility with le-acme-core so that it can be used as a **drop-in replacement**
+and requires **no changes to existing code**,
+but also provides an updated API more congruent with draft 11.
+
+## le-acme-core-compatible API (recommended)
+
+Status: Stable, Locked, Bugfix-only
+
+See Full Documentation at
+
+```
+var RSA = require('rsa-compat').RSA;
+var acme = require('acme-v2/compat.js').ACME.create({ RSA: RSA });
+
+//
+// Use exactly the same as le-acme-core
+//
+```
+
+## Promise API (dev)
+
+Status: Almost stable, but **not semver locked**
+
+This API is a simple evolution of le-acme-core,
+but tries to provide a better mapping to the new draft 11 APIs.
+
+```
+// Create Instance (Dependency Injection)
+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'; }
+
+
+ // don't try to validate challenges locally
+, skipChallengeTest: false
+ // ask if the certificate can be issued up to 10 times before failing
+, retryPoll: 8
+ // ask if the certificate has been validated up to 6 times before cancelling
+, retryPending: 4
+ // Wait 1000ms between retries
+, retryInterval: 1000
+ // Wait 10,000ms after deauthorizing a challenge before retrying
+, deauthWait: 10 * 1000
+});
+
+
+// Discover Directory URLs
+ACME.init(acmeDirectoryUrl) // returns Promise
+
+
+// Accounts
+ACME.accounts.create(options) // returns Promise registration data
+
+ { email: '' // valid email (server checks MX records)
+ , accountKeypair: { // privateKeyPem or privateKeyJwt
+ privateKeyPem: ''
+ }
+ , agreeToTerms: fn (tosUrl) {} // returns Promise with tosUrl
+ }
+
+
+// Registration
+ACME.certificates.create(options) // returns Promise
+
+ { newAuthzUrl: '' // specify acmeUrls.newAuthz
+ , newCertUrl: '' // specify acmeUrls.newCert
+
+ , domainKeypair: {
+ privateKeyPem: ''
+ }
+ , accountKeypair: {
+ privateKeyPem: ''
+ }
+ , domains: [ 'example.com' ]
+
+ , setChallenge: fn (hostname, key, val) // return Promise
+ , removeChallenge: fn (hostname, key) // return Promise
+ }
+```
+
+Helpers & Stuff
+
+```javascript
+// Constants
+ACME.challengePrefixes['http-01'] // '/.well-known/acme-challenge'
+ACME.challengePrefixes['dns-01'] // '_acme-challenge'
+```
+
+Changelog
+---------
+
+* v1.0.5 - cleanup logging
+* v1.0.4 - v6- compat use `promisify` from node's util or bluebird
+* v1.0.3 - documentation cleanup
+* 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
+* Apr 5, 2018 - export http and dns challenge tests
+* Apr 5, 2018 - test http and dns challenges (success and failure)
+* Apr 5, 2018 - test subdomains and its wildcard
+* Apr 5, 2018 - test two subdomains
+* Apr 5, 2018 - test wildcard
+* Apr 5, 2018 - completely match api for acme v1 (le-acme-core.js)
+* Mar 21, 2018 - *mostly* matches le-acme-core.js API
+* Mar 21, 2018 - can now accept values (not hard coded)
+* Mar 20, 2018 - SUCCESS - got a test certificate (hard-coded)
+* Mar 20, 2018 - download certificate
+* Mar 20, 2018 - poll for status
+* Mar 20, 2018 - finalize order (submit csr)
+* Mar 20, 2018 - generate domain keypair
+* Mar 20, 2018 - respond to challenges
+* Mar 16, 2018 - get challenges
+* Mar 16, 2018 - new order
+* Mar 15, 2018 - create account
+* Mar 15, 2018 - generate account keypair
+* Mar 15, 2018 - get nonce
+* Mar 15, 2018 - get directory
diff --git a/express-server/node_modules/acme-v2/compat.js b/express-server/node_modules/acme-v2/compat.js
new file mode 100644
index 00000000..674c0284
--- /dev/null
+++ b/express-server/node_modules/acme-v2/compat.js
@@ -0,0 +1,77 @@
+'use strict';
+/* global Promise */
+
+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.error('[acme-v2] handled(?) rejection as errback:');
+ console.error(err.stack);
+
+ // nextTick to get out of Promise chain
+ process.nextTick(function () { cb(err); });
+
+ // do not resolve promise further
+ return new Promise(function () {});
+ };
+}
+
+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) {
+ options.agreeToTerms = options.agreeToTerms || function (tos) {
+ return Promise.resolve(tos);
+ };
+ acme2.certificates.create(options).then(function (certs) {
+ var privkeyPem = acme2.RSA.exportPrivatePem(options.domainKeypair);
+ certs.privkey = privkeyPem;
+ resolveFn(cb)(certs);
+ }, rejectFn(cb));
+ };
+ acme2.getAcmeUrls = function (options, cb) {
+ acme2.init(options).then(resolveFn(cb), rejectFn(cb));
+ };
+ acme2.getOptions = function () {
+ var defs = {};
+
+ Object.keys(module.exports.defaults).forEach(function (key) {
+ defs[key] = defs[deps] || module.exports.defaults[key];
+ });
+
+ return defs;
+ };
+ acme2.stagingServerUrl = module.exports.defaults.stagingServerUrl;
+ acme2.productionServerUrl = module.exports.defaults.productionServerUrl;
+ acme2.acmeChallengePrefix = module.exports.defaults.acmeChallengePrefix;
+ 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
+, rsaKeySize: 2048 // 256
+, acmeChallengePrefix: '/.well-known/acme-challenge/'
+};
+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;
diff --git a/express-server/node_modules/acme-v2/examples/cli.js b/express-server/node_modules/acme-v2/examples/cli.js
new file mode 100644
index 00000000..f26354a5
--- /dev/null
+++ b/express-server/node_modules/acme-v2/examples/cli.js
@@ -0,0 +1,68 @@
+'use strict';
+
+var RSA = require('rsa-compat').RSA;
+var readline = require('readline');
+var rl = readline.createInterface({
+ input: process.stdin,
+ 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);
+ 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; }
+
+ 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 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);
+ }
+ });
+}
+
+getWeb();
diff --git a/express-server/node_modules/acme-v2/examples/genkeypair.js b/express-server/node_modules/acme-v2/examples/genkeypair.js
new file mode 100644
index 00000000..2c7e3c62
--- /dev/null
+++ b/express-server/node_modules/acme-v2/examples/genkeypair.js
@@ -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);
+ });
+}
diff --git a/express-server/node_modules/acme-v2/examples/http-server.js b/express-server/node_modules/acme-v2/examples/http-server.js
new file mode 100644
index 00000000..4195455d
--- /dev/null
+++ b/express-server/node_modules/acme-v2/examples/http-server.js
@@ -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());
+});
diff --git a/express-server/node_modules/acme-v2/examples/https-server.js b/express-server/node_modules/acme-v2/examples/https-server.js
new file mode 100644
index 00000000..5dd2c2c9
--- /dev/null
+++ b/express-server/node_modules/acme-v2/examples/https-server.js
@@ -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());
+});
diff --git a/express-server/node_modules/acme-v2/node.js b/express-server/node_modules/acme-v2/node.js
new file mode 100644
index 00000000..b0b1c8e3
--- /dev/null
+++ b/express-server/node_modules/acme-v2/node.js
@@ -0,0 +1,719 @@
+/*!
+ * acme-v2.js
+ * Copyright(c) 2018 AJ ONeal https://ppl.family
+ * Apache-2.0 OR MIT (and hence also MPL 2.0)
+ */
+'use strict';
+/* globals Promise */
+
+var ACME = module.exports.ACME = {};
+
+ACME.formatPemChain = function formatPemChain(str) {
+ return str.trim().replace(/[\r\n]+/g, '\n').replace(/\-\n\-/g, '-\n\n-') + '\n';
+};
+ACME.splitPemChain = function splitPemChain(str) {
+ return str.trim().split(/[\r\n]{2,}/g).map(function (str) {
+ return str + '\n';
+ });
+};
+
+ACME.challengePrefixes = {
+ 'http-01': '/.well-known/acme-challenge'
+, 'dns-01': '_acme-challenge'
+};
+ACME.challengeTests = {
+ 'http-01': function (me, auth) {
+ var url = 'http://' + auth.hostname + ACME.challengePrefixes['http-01'] + '/' + auth.token;
+ return me._request({ url: url }).then(function (resp) {
+ var err;
+
+ if (auth.keyAuthorization === resp.body.toString('utf8').trim()) {
+ return true;
+ }
+
+ err = new Error(
+ "Error: Failed HTTP-01 Dry Run.\n"
+ + "curl '" + url + "' does not return '" + auth.keyAuthorization + "'\n"
+ + "See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4"
+ );
+ err.code = 'E_FAIL_DRY_CHALLENGE';
+ return Promise.reject(err);
+ });
+ }
+, 'dns-01': function (me, auth) {
+ var hostname = ACME.challengePrefixes['dns-01'] + '.' + auth.hostname;
+ return me._dig({
+ type: 'TXT'
+ , name: hostname
+ }).then(function (ans) {
+ var err;
+
+ if (ans.answer.some(function (txt) {
+ return auth.dnsAuthorization === txt.data[0];
+ })) {
+ return true;
+ }
+
+ err = new Error(
+ "Error: Failed DNS-01 Dry Run.\n"
+ + "dig TXT '" + hostname + "' does not return '" + auth.dnsAuthorization + "'\n"
+ + "See https://git.coolaj86.com/coolaj86/acme-v2.js/issues/4"
+ );
+ err.code = 'E_FAIL_DRY_CHALLENGE';
+ return Promise.reject(err);
+ });
+ }
+};
+
+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
+ , user: ''
+ };
+
+ var userAgent = [];
+
+ //Object.keys(currentUAProps)
+ Object.keys(uaDefaults).forEach(function (key) {
+ if (uaDefaults[key]) {
+ userAgent.push(uaDefaults[key]);
+ }
+ });
+
+ 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) {
+ if (me.debug) { console.debug('[acme-v2] accounts.create'); }
+
+ return ACME._getNonce(me).then(function () {
+ return new Promise(function (resolve, reject) {
+
+ 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;
+ }
+
+ 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: contact
+ };
+ if (options.externalAccount) {
+ body.externalAccountBinding = me.RSA.signJws(
+ options.externalAccount.secret
+ , undefined
+ , { alg: "HS256"
+ , kid: options.externalAccount.id
+ , url: me._directoryUrls.newAccount
+ }
+ , Buffer.from(JSON.stringify(jwk))
+ );
+ }
+ var payload = JSON.stringify(body);
+ var jws = me.RSA.signJws(
+ options.accountKeypair
+ , undefined
+ , { nonce: me._nonce
+ , alg: 'RS256'
+ , url: me._directoryUrls.newAccount
+ , jwk: jwk
+ }
+ , Buffer.from(payload)
+ );
+
+ delete jws.header;
+ if (me.debug) { console.debug('[acme-v2] accounts.create JSON body:'); }
+ if (me.debug) { console.debug(jws); }
+ me._nonce = null;
+ return me._request({
+ method: 'POST'
+ , url: me._directoryUrls.newAccount
+ , headers: { 'Content-Type': 'application/jose+json' }
+ , json: jws
+ }).then(function (resp) {
+ var account = resp.body;
+
+ if (2 !== Math.floor(resp.statusCode / 100)) {
+ throw new Error('account error: ' + JSON.stringify(body));
+ }
+
+ me._nonce = resp.toJSON().headers['replay-nonce'];
+ var location = resp.toJSON().headers.location;
+ // the account id url
+ me._kid = location;
+ if (me.debug) { console.debug('[DEBUG] new account location:'); }
+ if (me.debug) { console.debug(location); }
+ if (me.debug) { console.debug(resp.toJSON()); }
+
+ /*
+ {
+ contact: ["mailto:jon@example.com"],
+ orders: "https://some-url",
+ status: 'valid'
+ }
+ */
+ if (!account) { account = { _emptyResponse: true, key: {} }; }
+ // https://git.coolaj86.com/coolaj86/acme-v2.js/issues/8
+ if (!account.key) { account.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);
+ });
+ }
+ else {
+ reject(new Error('agreeToTerms has incorrect function signature.'
+ + ' Should be fn(tos) { return Promise; }'));
+ }
+ });
+ });
+};
+/*
+ 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"
+ }
+*/
+ACME._getChallenges = function (me, options, auth) {
+ if (me.debug) { console.debug('\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 RETRY_INTERVAL = me.retryInterval || 1000;
+ var DEAUTH_INTERVAL = me.deauthWait || 10 * 1000;
+ var MAX_POLL = me.retryPoll || 8;
+ var MAX_PEND = me.retryPending || 4;
+ var count = 0;
+
+ var thumbprint = me.RSA.thumbprint(options.accountKeypair);
+ var keyAuthorization = ch.token + '.' + thumbprint;
+ // keyAuthorization = token || '.' || base64url(JWK_Thumbprint(accountKey))
+ // /.well-known/acme-challenge/:token
+ var auth = {
+ 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')
+ )
+ };
+
+ return new Promise(function (resolve, reject) {
+ /*
+ POST /acme/authz/1234 HTTP/1.1
+ Host: example.com
+ Content-Type: application/jose+json
+
+ {
+ "protected": base64url({
+ "alg": "ES256",
+ "kid": "https://example.com/acme/acct/1",
+ "nonce": "xWCM9lGbIyCgue8di6ueWQ",
+ "url": "https://example.com/acme/authz/1234"
+ }),
+ "payload": base64url({
+ "status": "deactivated"
+ }),
+ "signature": "srX9Ji7Le9bjszhu...WTFdtujObzMtZcx4"
+ }
+ */
+ function deactivate() {
+ var jws = me.RSA.signJws(
+ options.accountKeypair
+ , undefined
+ , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
+ , Buffer.from(JSON.stringify({ "status": "deactivated" }))
+ );
+ me._nonce = null;
+ return me._request({
+ method: 'POST'
+ , url: ch.url
+ , headers: { 'Content-Type': 'application/jose+json' }
+ , json: jws
+ }).then(function (resp) {
+ if (me.debug) { console.debug('[acme-v2.js] deactivate:'); }
+ if (me.debug) { console.debug(resp.headers); }
+ if (me.debug) { console.debug(resp.body); }
+ if (me.debug) { console.debug(); }
+
+ me._nonce = resp.toJSON().headers['replay-nonce'];
+ if (me.debug) { console.debug('deactivate challenge: resp.body:'); }
+ if (me.debug) { console.debug(resp.body); }
+ return ACME._wait(DEAUTH_INTERVAL);
+ });
+ }
+
+ function pollStatus() {
+ if (count >= MAX_POLL) {
+ return Promise.reject(new Error("[acme-v2] stuck in bad pending/processing state"));
+ }
+
+ count += 1;
+
+ if (me.debug) { console.debug('\n[DEBUG] statusChallenge\n'); }
+ return me._request({ method: 'GET', url: ch.url, json: true }).then(function (resp) {
+
+ if ('processing' === resp.body.status) {
+ if (me.debug) { console.debug('poll: again'); }
+ return ACME._wait(RETRY_INTERVAL).then(pollStatus);
+ }
+
+ // This state should never occur
+ if ('pending' === resp.body.status) {
+ if (count >= MAX_PEND) {
+ return ACME._wait(RETRY_INTERVAL).then(deactivate).then(testChallenge);
+ }
+ if (me.debug) { console.debug('poll: again'); }
+ return ACME._wait(RETRY_INTERVAL).then(testChallenge);
+ }
+
+ if ('valid' === resp.body.status) {
+ if (me.debug) { console.debug('poll: valid'); }
+
+ try {
+ if (1 === options.removeChallenge.length) {
+ options.removeChallenge(auth).then(function () {}, function () {});
+ } else if (2 === options.removeChallenge.length) {
+ options.removeChallenge(auth, function (err) { return err; });
+ } else {
+ options.removeChallenge(identifier.value, ch.token, function () {});
+ }
+ } catch(e) {}
+ return resp.body;
+ }
+
+ if (!resp.body.status) {
+ console.error("[acme-v2] (E_STATE_EMPTY) empty challenge state:");
+ }
+ else if ('invalid' === resp.body.status) {
+ console.error("[acme-v2] (E_STATE_INVALID) challenge state: '" + resp.body.status + "'");
+ }
+ else {
+ console.error("[acme-v2] (E_STATE_UKN) challenge state: '" + resp.body.status + "'");
+ }
+
+ return Promise.reject(new Error("[acme-v2] [error] unacceptable challenge state '" + resp.body.status + "'"));
+ });
+ }
+
+ function respondToChallenge() {
+ var jws = me.RSA.signJws(
+ options.accountKeypair
+ , undefined
+ , { nonce: me._nonce, alg: 'RS256', url: ch.url, kid: me._kid }
+ , Buffer.from(JSON.stringify({ }))
+ );
+ me._nonce = null;
+ return me._request({
+ method: 'POST'
+ , url: ch.url
+ , headers: { 'Content-Type': 'application/jose+json' }
+ , json: jws
+ }).then(function (resp) {
+ if (me.debug) { console.debug('[acme-v2.js] challenge accepted!'); }
+ if (me.debug) { console.debug(resp.headers); }
+ if (me.debug) { console.debug(resp.body); }
+ if (me.debug) { console.debug(); }
+
+ me._nonce = resp.toJSON().headers['replay-nonce'];
+ if (me.debug) { console.debug('respond to challenge: resp.body:'); }
+ if (me.debug) { console.debug(resp.body); }
+ return ACME._wait(RETRY_INTERVAL).then(pollStatus);
+ });
+ }
+
+ 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))}}"
+
+ if (me.debug) {console.debug('\n[DEBUG] postChallenge\n'); }
+ //if (me.debug) console.debug('\n[DEBUG] stop to fix things\n'); return;
+
+ return ACME._wait(RETRY_INTERVAL).then(function () {
+ if (!me.skipChallengeTest) {
+ return ACME.challengeTests[ch.type](me, auth);
+ }
+ }).then(respondToChallenge);
+ }
+
+ try {
+ if (1 === options.setChallenge.length) {
+ options.setChallenge(auth).then(testChallenge).then(resolve, reject);
+ } else if (2 === options.setChallenge.length) {
+ options.setChallenge(auth, function (err) {
+ if(err) {
+ reject(err);
+ } else {
+ testChallenge().then(resolve, reject);
+ }
+ });
+ } else {
+ var challengeCb = function(err) {
+ if(err) {
+ reject(err);
+ } else {
+ testChallenge().then(resolve, reject);
+ }
+ };
+ Object.keys(auth).forEach(function (key) {
+ challengeCb[key] = auth[key];
+ });
+ options.setChallenge(identifier.value, ch.token, keyAuthorization, challengeCb);
+ }
+ } catch(e) {
+ reject(e);
+ }
+ });
+};
+ACME._finalizeOrder = function (me, options, validatedDomains) {
+ if (me.debug) { console.debug('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 }
+ , Buffer.from(payload)
+ );
+
+ if (me.debug) { console.debug('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) {
+ // https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.1.3
+ // Possible values are: "pending" => ("invalid" || "ready") => "processing" => "valid"
+ me._nonce = resp.toJSON().headers['replay-nonce'];
+
+ if (me.debug) { console.debug('order finalized: resp.body:'); }
+ if (me.debug) { console.debug(resp.body); }
+
+ if ('valid' === resp.body.status) {
+ me._expires = resp.body.expires;
+ me._certificate = resp.body.certificate;
+
+ return resp.body; // return order
+ }
+
+ if ('processing' === resp.body.status) {
+ return ACME._wait().then(pollCert);
+ }
+
+ if (me.debug) { console.debug("Error: bad status:\n" + JSON.stringify(resp.body, null, 2)); }
+
+ if ('pending' === resp.body.status) {
+ return Promise.reject(new Error(
+ "Did not finalize order: status 'pending'."
+ + " Best guess: You have not accepted at least one challenge for each domain." + "\n\n"
+ + JSON.stringify(resp.body, null, 2)
+ ));
+ }
+
+ if ('invalid' === resp.body.status) {
+ return Promise.reject(new Error(
+ "Did not finalize order: status 'invalid'."
+ + " Best guess: One or more of the domain challenges could not be verified"
+ + " (or the order was canceled)." + "\n\n"
+ + JSON.stringify(resp.body, null, 2)
+ ));
+ }
+
+ if ('ready' === resp.body.status) {
+ return Promise.reject(new Error(
+ "Did not finalize order: status 'ready'."
+ + " Hmmm... this state shouldn't be possible here. That was the last state."
+ + " This one should at least be 'processing'." + "\n\n"
+ + JSON.stringify(resp.body, null, 2) + "\n\n"
+ + "Please open an issue at https://git.coolaj86.com/coolaj86/acme-v2.js"
+ ));
+ }
+
+ return Promise.reject(new Error(
+ "Didn't finalize order: Unhandled status '" + resp.body.status + "'."
+ + " This is not one of the known statuses...\n\n"
+ + JSON.stringify(resp.body, null, 2) + "\n\n"
+ + "Please open an issue at https://git.coolaj86.com/coolaj86/acme-v2.js"
+ ));
+ });
+ }
+
+ return pollCert();
+};
+ACME._getCertificate = function (me, options) {
+ if (me.debug) { console.debug('[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 ];
+ }
+
+ if (!me._kid) {
+ if (options.accountKid) {
+ me._kid = options.accountKid;
+ } else {
+ //return Promise.reject(new Error("must include KeyID"));
+ return ACME._registerAccount(me, options).then(function () {
+ return ACME._getCertificate(me, options);
+ });
+ }
+ }
+
+ if (me.debug) { console.debug('[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 }
+ , Buffer.from(payload)
+ );
+
+ if (me.debug) { console.debug('\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;
+ var auths;
+ if (me.debug) { console.debug(location); } // the account id url
+ if (me.debug) { console.debug(resp.toJSON()); }
+ me._authorizations = resp.body.authorizations;
+ me._order = location;
+ me._finalize = resp.body.finalize;
+ //if (me.debug) console.debug('[DEBUG] finalize:', me._finalize); return;
+
+ if (!me._authorizations) {
+ console.error("[acme-v2.js] authorizations were not fetched:");
+ console.error(resp.body);
+ return Promise.reject(new Error("authorizations were not fetched"));
+ }
+ if (me.debug) { console.debug("[acme-v2] POST newOrder has authorizations"); }
+
+ //return resp.body;
+ auths = me._authorizations.slice(0);
+
+ function next() {
+ var authUrl = auths.shift();
+ if (!authUrl) { return; }
+
+ 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 () {
+ return next();
+ });
+ }
+
+ return next().then(function () {
+ if (me.debug) { console.debug("[getCertificate] next.then"); }
+ var validatedDomains = body.identifiers.map(function (ident) {
+ return ident.value;
+ });
+
+ return ACME._finalizeOrder(me, options, validatedDomains);
+ }).then(function (order) {
+ if (me.debug) { console.debug('acme-v2: order was finalized'); }
+ return me._request({ method: 'GET', url: me._certificate, json: true }).then(function (resp) {
+ if (me.debug) { console.debug('acme-v2: csr submitted and cert received:'); }
+ // https://github.com/certbot/certbot/issues/5721
+ var certsarr = ACME.splitPemChain(ACME.formatPemChain((resp.body||'')));
+ // cert, chain, fullchain, privkey, /*TODO, subject, altnames, issuedAt, expiresAt */
+ var certs = {
+ expires: order.expires
+ , identifiers: order.identifiers
+ //, authorizations: order.authorizations
+ , cert: certsarr.shift()
+ //, privkey: privkeyPem
+ , chain: certsarr.join('\n')
+ };
+ if (me.debug) { console.debug(certs); }
+ return certs;
+ });
+ });
+ });
+ });
+};
+
+ACME.create = function create(me) {
+ if (!me) { me = {}; }
+ // me.debug = true;
+ me.challengePrefixes = ACME.challengePrefixes;
+ me.RSA = me.RSA || require('rsa-compat').RSA;
+ me.request = me.request || require('@coolaj86/urequest');
+ me._dig = function (query) {
+ // TODO use digd.js
+ return new Promise(function (resolve, reject) {
+ var dns = require('dns');
+ dns.resolveTxt(query.name, function (err, records) {
+ if (err) { reject(err); return; }
+
+ resolve({
+ answer: records.map(function (rr) {
+ return {
+ data: rr
+ };
+ })
+ });
+ });
+ });
+ };
+ me.promisify = me.promisify || require('util').promisify /*node v8+*/ || require('bluebird').promisify /*node v6*/;
+
+
+ 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);
+ }
+ };
+ me.certificates = {
+ create: function (options) {
+ return ACME._getCertificate(me, options);
+ }
+ };
+ return me;
+};
diff --git a/express-server/node_modules/acme-v2/package.json b/express-server/node_modules/acme-v2/package.json
new file mode 100644
index 00000000..dc00cdbf
--- /dev/null
+++ b/express-server/node_modules/acme-v2/package.json
@@ -0,0 +1,102 @@
+{
+ "_args": [
+ [
+ "acme-v2@^1.2.0",
+ "/nodeapps/https-test/greenlock-express.js/node_modules/greenlock"
+ ]
+ ],
+ "_from": "acme-v2@>=1.2.0 <2.0.0",
+ "_id": "acme-v2@1.2.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/acme-v2",
+ "_nodeVersion": "10.6.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/acme-v2_1.2.1_1534465950183_0.44524737605461473"
+ },
+ "_npmUser": {
+ "email": "coolaj86@gmail.com",
+ "name": "coolaj86"
+ },
+ "_npmVersion": "6.1.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "acme-v2",
+ "raw": "acme-v2@^1.2.0",
+ "rawSpec": "^1.2.0",
+ "scope": null,
+ "spec": ">=1.2.0 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/acme",
+ "/greenlock"
+ ],
+ "_resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.2.1.tgz",
+ "_shasum": "15ef5063b45172e900cfa6f05d608bde590860cc",
+ "_shrinkwrap": null,
+ "_spec": "acme-v2@^1.2.0",
+ "_where": "/nodeapps/https-test/greenlock-express.js/node_modules/greenlock",
+ "author": {
+ "email": "coolaj86@gmail.com",
+ "name": "AJ ONeal",
+ "url": "https://coolaj86.com/"
+ },
+ "dependencies": {
+ "@coolaj86/urequest": "^1.3.6",
+ "rsa-compat": "^1.5.1"
+ },
+ "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",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "fileCount": 14,
+ "integrity": "sha512-7FRl/vgZpcm7VCOiiAU6ntkclHkkEdCk1uNAkuEA0sZ8R0YX3pBjh066y/QqzEAfmDbbiYr+DYlVhZoHTbmXEQ==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbdhefCRA9TVsSAnZWagAA/XcQAKMNjyd4wCZzld6wlDfC\nr+Mo1CfUugIko2fW6MZ7TGhxPIiVhedC7v/jUxwsZV3oYDdrttTbflkxxoUB\n6ivIdPaTXp/9JXfg0u+2cWrCZufy4d5PQtDDdfrp0GugsUHz/+wrrC2jpCjM\nPRCzGYbwJ7NvEnY5AYU28XI9WL1voCxxxLSjYkPqDjBtGrvcUrghJUsfeqOw\n0gOd3LhSdFunnIV44PTHV4GknAkTUffbpigcfGAtiXfigJ/3xbrjV0k5dpBb\n55q6l+i6Vdvjb8xhYkUO+V7zE/3zZWAaVKHLI+oeVnX/1OrA7tLU05GYj03c\nFaEm57/uS3OQ4atHAy8X6vjXOjuGOoCXpmmNUKZ2whiUHDvsrzEVXhgFAGxb\n9iWghhgwCTn7zPQQKIJdviNEbQXmY+phbG+5mmg2+Z/EHceCi+4t4m/sEoIe\nAzBUTNouU8mMxfWFFDcT8c02LyFanHHsQGC+mtICORZxU8GlCwz7LTU5YLl3\nfkswVaLIYr2Qvlswyf/sJCWCccHgX2j6qlbdNhdV1LBvS1jYmgN83OkmcGTD\nmVyM+lDYqmBkycw29NEAkdZ3LvHsb1t4GOnqDboTOFZll2TSSiaOaLf3yveq\n6beSy/HNuCYzmTxXTeaGPnc1ZwY7iTYZcjTLitzNvKyCwO3Vjiyrtc9Onqx5\n/Yyp\r\n=dHr8\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "15ef5063b45172e900cfa6f05d608bde590860cc",
+ "tarball": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.2.1.tgz",
+ "unpackedSize": 50763
+ },
+ "gitHead": "ca15b8faf0a11b15d9973a9786c652c117d2547d",
+ "homepage": "https://git.coolaj86.com/coolaj86/acme-v2.js",
+ "keywords": [
+ "ACME",
+ "Let's Encrypt",
+ "automated https",
+ "draft-11",
+ "draft-12",
+ "free ssl",
+ "letsencrypt",
+ "tls",
+ "v02",
+ "v2"
+ ],
+ "license": "(MIT OR Apache-2.0)",
+ "main": "node.js",
+ "maintainers": [
+ {
+ "name": "coolaj86",
+ "email": "coolaj86@gmail.com"
+ },
+ {
+ "name": "ppl",
+ "email": "npm@ppl.family"
+ },
+ {
+ "name": "thejshaver",
+ "email": "john@jshaver.net"
+ }
+ ],
+ "name": "acme-v2",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "ssh://gitea@git.coolaj86.com:22042/coolaj86/acme-v2.js.git"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "version": "1.2.1"
+}
diff --git a/express-server/node_modules/acme-v2/tests/cb.js b/express-server/node_modules/acme-v2/tests/cb.js
new file mode 100644
index 00000000..550c285e
--- /dev/null
+++ b/express-server/node_modules/acme-v2/tests/cb.js
@@ -0,0 +1,79 @@
+'use strict';
+
+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) {
+ agree(null, tosUrl);
+ }
+ , setChallenge: function (opts, cb) {
+ var pathname;
+
+ 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("");
+
+ if ('http-01' === opts.type) {
+ pathname = opts.hostname + acme2.challengePrefixes['http-01'] + "/" + opts.token;
+ console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + pathname + "'");
+ console.log("echo '" + opts.keyAuthorization + "' > '" + pathname + "'");
+ } else if ('dns-01' === opts.type) {
+ pathname = acme2.challengePrefixes['dns-01'] + "." + opts.hostname.replace(/^\*\./, '');
+ console.log("Put the string '" + opts.dnsAuthorization + "' into the TXT record '" + pathname + "'");
+ console.log("ddig TXT " + pathname + " '" + opts.dnsAuthorization + "'");
+ } else {
+ cb(new Error("[acme-v2] unrecognized challenge type"));
+ return;
+ }
+ console.log("\nThen hit the 'any' key to continue...");
+
+ 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 (opts, cb) {
+ // hostname, key
+ console.log('[acme-v2] remove challenge', opts.hostname, opts.keyAuthorization);
+ setTimeout(cb, 1 * 1000);
+ }
+ , challengeType: chType
+ , email: email
+ , accountKeypair: accountKeypair
+ , domainKeypair: domainKeypair
+ , domains: web
+ };
+
+ acme2.accounts.create(options).then(function (account) {
+ console.log('[acme-v2] account:');
+ console.log(account);
+
+ acme2.certificates.create(options).then(function (fullchainPem) {
+ console.log('[acme-v2] fullchain.pem:');
+ console.log(fullchainPem);
+ });
+ });
+ });
+};
diff --git a/express-server/node_modules/acme-v2/tests/compat.js b/express-server/node_modules/acme-v2/tests/compat.js
new file mode 100644
index 00000000..e643e2e6
--- /dev/null
+++ b/express-server/node_modules/acme-v2/tests/compat.js
@@ -0,0 +1,68 @@
+'use strict';
+
+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 });
+ acme2.getAcmeUrls(acme2.stagingServerUrl, function (err/*, directoryUrls*/) {
+ if (err) { console.log('err 1'); throw err; }
+
+ var options = {
+ agreeToTerms: function (tosUrl, agree) {
+ agree(null, tosUrl);
+ }
+ , setChallenge: function (hostname, token, val, cb) {
+ var pathname;
+
+ if ('http-01' === cb.type) {
+ pathname = hostname + acme2.acmeChallengePrefix + token;
+ console.log("Put the string '" + val /*keyAuthorization*/ + "' into a file at '" + pathname + "'");
+ console.log("echo '" + val /*keyAuthorization*/ + "' > '" + pathname + "'");
+ console.log("\nThen hit the 'any' key to continue...");
+ } else if ('dns-01' === cb.type) {
+ // forwards-backwards compat
+ pathname = acme2.challengePrefixes['dns-01'] + "." + hostname.replace(/^\*\./, '');
+ console.log("Put the string '" + cb.dnsAuthorization + "' into the TXT record '" + pathname + "'");
+ console.log("dig TXT " + pathname + " '" + cb.dnsAuthorization + "'");
+ console.log("\nThen hit the 'any' key to continue...");
+ } else {
+ cb(new Error("[acme-v2] unrecognized challenge type: " + cb.type));
+ return;
+ }
+
+ 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: accountKeypair
+ , domainKeypair: domainKeypair
+ , domains: web
+ };
+
+ acme2.registerNewAccount(options, function (err, account) {
+ if (err) { console.log('err 2'); throw err; }
+ 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; }
+ console.log('[acme-v2] A fullchain.pem:');
+ console.log(fullchainPem);
+ });
+ });
+ });
+};
diff --git a/express-server/node_modules/acme-v2/tests/fullchain-formats.js b/express-server/node_modules/acme-v2/tests/fullchain-formats.js
new file mode 100644
index 00000000..cb4f67cf
--- /dev/null
+++ b/express-server/node_modules/acme-v2/tests/fullchain-formats.js
@@ -0,0 +1,77 @@
+'use strict';
+
+/*
+-----BEGIN CERTIFICATE-----LF
+xxxLF
+yyyLF
+-----END CERTIFICATE-----LF
+LF
+-----BEGIN CERTIFICATE-----LF
+xxxLF
+yyyLF
+-----END CERTIFICATE-----LF
+
+Rules
+ * Only Unix LF (\n) Line endings
+ * Each PEM's lines are separated with \n
+ * Each PEM ends with \n
+ * Each PEM is separated with a \n (just like commas separating an array)
+*/
+
+// https://github.com/certbot/certbot/issues/5721#issuecomment-402362709
+var expected = "----\nxxxx\nyyyy\n----\n\n----\nxxxx\nyyyy\n----\n";
+var tests = [
+ "----\r\nxxxx\r\nyyyy\r\n----\r\n\r\n----\r\nxxxx\r\nyyyy\r\n----\r\n"
+, "----\r\nxxxx\r\nyyyy\r\n----\r\n----\r\nxxxx\r\nyyyy\r\n----\r\n"
+, "----\nxxxx\nyyyy\n----\n\n----\r\nxxxx\r\nyyyy\r\n----"
+, "----\nxxxx\nyyyy\n----\n----\r\nxxxx\r\nyyyy\r\n----"
+, "----\nxxxx\nyyyy\n----\n----\nxxxx\nyyyy\n----"
+, "----\nxxxx\nyyyy\n----\n----\nxxxx\nyyyy\n----\n"
+, "----\nxxxx\nyyyy\n----\n\n----\nxxxx\nyyyy\n----\n"
+, "----\nxxxx\nyyyy\n----\r\n----\nxxxx\ryyyy\n----\n"
+];
+
+function formatPemChain(str) {
+ return str.trim().replace(/[\r\n]+/g, '\n').replace(/\-\n\-/g, '-\n\n-') + '\n';
+}
+function splitPemChain(str) {
+ return str.trim().split(/[\r\n]{2,}/g).map(function (str) {
+ return str + '\n';
+ });
+}
+
+tests.forEach(function (str) {
+ var actual = formatPemChain(str);
+ if (expected !== actual) {
+ console.error('input: ', JSON.stringify(str));
+ console.error('expected:', JSON.stringify(expected));
+ console.error('actual: ', JSON.stringify(actual));
+ throw new Error("did not pass");
+ }
+});
+
+if (
+ "----\nxxxx\nyyyy\n----\n"
+ !==
+ formatPemChain("\n\n----\r\nxxxx\r\nyyyy\r\n----\n\n")
+) {
+ throw new Error("Not proper for single cert in chain");
+}
+
+if (
+ "--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n"
+ !==
+ formatPemChain("\n\n\n--B--\nxxxx\nyyyy\n--E--\n\n\n\n--B--\nxxxx\nyyyy\n--E--\n\n\n--B--\nxxxx\nyyyy\n--E--\n\n\n")
+) {
+ throw new Error("Not proper for three certs in chain");
+}
+
+splitPemChain(
+ "--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n\n--B--\nxxxx\nyyyy\n--E--\n"
+).forEach(function (str) {
+ if ("--B--\nxxxx\nyyyy\n--E--\n" !== str) {
+ throw new Error("bad thingy");
+ }
+});
+
+console.info('PASS');
diff --git a/express-server/node_modules/acme-v2/tests/promise.js b/express-server/node_modules/acme-v2/tests/promise.js
new file mode 100644
index 00000000..7c1c17f1
--- /dev/null
+++ b/express-server/node_modules/acme-v2/tests/promise.js
@@ -0,0 +1,85 @@
+'use strict';
+
+/* global Promise */
+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 = {
+ agreeToTerms: function (tosUrl) {
+ return Promise.resolve(tosUrl);
+ }
+ , setChallenge: function (opts) {
+ return new Promise(function (resolve, reject) {
+ var pathname;
+
+ 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("");
+
+ if ('http-01' === opts.type) {
+ pathname = opts.hostname + acme2.challengePrefixes['http-01'] + "/" + opts.token;
+ console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + pathname + "'");
+ console.log("echo '" + opts.keyAuthorization + "' > '" + pathname + "'");
+ } else if ('dns-01' === opts.type) {
+ pathname = acme2.challengePrefixes['dns-01'] + "." + opts.hostname.replace(/^\*\./, '');
+ console.log("Put the string '" + opts.dnsAuthorization + "' into the TXT record '" + pathname + "'");
+ console.log("dig TXT " + pathname + " '" + opts.dnsAuthorization + "'");
+ } else {
+ reject(new Error("[acme-v2] unrecognized challenge type"));
+ return;
+ }
+ console.log("\nThen hit the 'any' key to continue...");
+
+ function onAny() {
+ console.log("'any' key was hit");
+ process.stdin.pause();
+ process.stdin.removeListener('data', onAny);
+ process.stdin.setRawMode(false);
+ resolve();
+ return;
+ }
+
+ process.stdin.setRawMode(true);
+ process.stdin.resume();
+ process.stdin.on('data', onAny);
+ });
+ }
+ , removeChallenge: function (opts) {
+ console.log('[acme-v2] remove challenge', opts.hostname, opts.keyAuthorization);
+ return new Promise(function (resolve) {
+ // hostname, key
+ setTimeout(resolve, 1 * 1000);
+ });
+ }
+ , challengeType: chType
+ , email: email
+ , accountKeypair: accountKeypair
+ , domainKeypair: domainKeypair
+ , domains: web
+ };
+
+ acme2.accounts.create(options).then(function (account) {
+ console.log('[acme-v2] account:');
+ console.log(account);
+
+ acme2.certificates.create(options).then(function (fullchainPem) {
+ console.log('[acme-v2] fullchain.pem:');
+ console.log(fullchainPem);
+ });
+ });
+ });
+};
diff --git a/express-server/node_modules/acme/LICENSE b/express-server/node_modules/acme/LICENSE
new file mode 100644
index 00000000..693448ab
--- /dev/null
+++ b/express-server/node_modules/acme/LICENSE
@@ -0,0 +1,41 @@
+Copyright 2018 AJ ONeal
+
+This is open source software; you can redistribute it and/or modify it under the
+terms of either:
+
+ a) the "MIT License"
+ b) the "Apache-2.0 License"
+
+MIT License
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in all
+ copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+Apache-2.0 License Summary
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/express-server/node_modules/acme/README.md b/express-server/node_modules/acme/README.md
new file mode 100644
index 00000000..30d73ba8
--- /dev/null
+++ b/express-server/node_modules/acme/README.md
@@ -0,0 +1,233 @@
+acme.js
+==========
+
+Free SSL for everybody. The bare essentials of the Let's Encrypt v2 (ACME) API.
+Built for [Greenlock](https://git.coolaj86.com/coolaj86/greenlock-express.js),
+[by request](https://git.coolaj86.com/coolaj86/greenlock.js/issues/5#issuecomment-8).
+
+| Sponsored by [ppl](https://ppl.family) |
+
+
+
+Looking for Quick 'n' Easy™?
+=======
+
+This is intented for building ACME API clients in node.js. It is **not** a high-level, fully-integrated solution.
+
+You may be more interested in one of these:
+
+* Instant SSL Certificates in your Browser
+* [Greenlock for Web Browsers](https://git.coolaj86.com/coolaj86/greenlock.html) (Browser JavaScript)
+* [Greenlock for Web Servers](https://git.coolaj86.com/coolaj86/greenlock-cli.js) (Command line, like certbot)
+* [Greenlock for Express.js](https://git.coolaj86.com/coolaj86/greenlock-express.js) (Automated HTTPS for Express.js apps)
+* [Greenlock for node.js](https://git.coolaj86.com/coolaj86/greenlock.js) (Automated HTTPS for Proxies, Load-Balances, Servers, CLIs)
+* [goldilocks.js](https://git.coolaj86.com/coolaj86/goldilocks.js) (A Full-Blown WebServer)
+
+Demonstration
+=============
+
+As this is intended to *build* ACME clients, there is not a simple 2-line example.
+
+I'd recommend first trying out one of the [Greenlock for Web Servers](https://git.coolaj86.com/coolaj86/greenlock-cli.js)
+examples, which are guaranteed to work and have great error checking to help you debug.
+
+Then I'd recommend running the example CLI client with a test domain and then investigating the files used for that example:
+
+```bash
+git clone https://git.coolaj86.com/coolaj86/acme.js.git
+pushd acme.js/
+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 directoryUrl should we use? [https://acme-staging-v02.api.letsencrypt.org/directory]
+
+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`
+then you can test it with `examples/https-server.js`.
+
+```
+examples/cli.js
+examples/genkeypair.js
+examples/https-server.js
+examples/http-server.js
+```
+
+Let's Encrypt v2 / ACME draft 11 Support
+========
+
+This library (acme.js) supports ACME [*draft 11*](https://tools.ietf.org/html/draft-ietf-acme-acme-11),
+otherwise known as Let's Encrypt v2 (or v02).
+
+ * ACME draft 11
+ * Let's Encrypt v2
+ * Let's Encrypt v02
+
+```
+# Production URL
+https://acme-v02.api.letsencrypt.org/directory
+```
+
+```
+# Staging URL
+https://acme-staging-v02.api.letsencrypt.org/directory
+```
+
+Install
+=======
+
+Install via npm
+
+```bash
+npm install --save acme
+```
+
+Install via git
+
+```bash
+npm install https://git.coolaj86.com/coolaj86/acme.js.git
+```
+
+API
+===
+
+This API is an evolution of le-acme-core,
+but tries to provide a better mapping to the new draft 11 APIs.
+
+Status: Almost stable, but **not semver locked**.
+
+Patch versions will not introduce breaking changes,
+but may introduce lower-level APIs.
+Minor versions may change return values to include more information.
+
+### Overview
+
+```
+var ACME = require('acme').ACME;
+
+ACME.create(opts)
+
+acme.init(acmeDirectoryUrl)
+acme.accounts.create(opts)
+acme.certificates.create(opts)
+```
+
+### Detailed Explanation
+
+```
+var ACME = require('acme').ACME;
+
+// Create Instance (Dependency Injection)
+var acme = 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'; }
+
+ // don't try to validate challenges locally
+, skipChallengeTest: false
+});
+
+
+// Discover Directory URLs
+acme.init(acmeDirectoryUrl) // returns Promise
+
+
+// Accounts
+acme.accounts.create(options) // returns Promise registration data
+
+ { email: '' // valid email (server checks MX records)
+ , accountKeypair: { // privateKeyPem or privateKeyJwt
+ privateKeyPem: ''
+ }
+ , agreeToTerms: fn (tosUrl) {} // returns Promise with tosUrl
+ }
+
+
+// Registration
+acme.certificates.create(options) // returns Promise
+
+ { newAuthzUrl: '' // specify acmeUrls.newAuthz
+ , newCertUrl: '' // specify acmeUrls.newCert
+
+ , domainKeypair: {
+ privateKeyPem: ''
+ }
+ , accountKeypair: {
+ privateKeyPem: ''
+ }
+ , domains: [ 'example.com' ]
+
+ , setChallenge: fn (hostname, key, val) // return Promise
+ , removeChallenge: fn (hostname, key) // return Promise
+ }
+```
+
+Helpers & Stuff
+
+```javascript
+// Constants
+ACME.challengePrefixes['http-01'] // '/.well-known/acme-challenge'
+ACME.challengePrefixes['dns-01'] // '_acme-challenge'
+```
+
+Changelog
+---------
+
+* v1.0.9 - update docs
+* v1.0.8 - rename to acme.js, remove backwards compat
+* v1.0.7 - improved error handling again, after user testing
+* v1.0.6 - improved error handling
+* v1.0.5 - cleanup logging
+* v1.0.4 - v6- compat use `promisify` from node's util or bluebird
+* v1.0.3 - documentation cleanup
+* 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
+* Apr 5, 2018 - export http and dns challenge tests
+* Apr 5, 2018 - test http and dns challenges (success and failure)
+* Apr 5, 2018 - test subdomains and its wildcard
+* Apr 5, 2018 - test two subdomains
+* Apr 5, 2018 - test wildcard
+* Apr 5, 2018 - completely match api for acme v1 (le-acme-core.js)
+* Mar 21, 2018 - *mostly* matches le-acme-core.js API
+* Mar 21, 2018 - can now accept values (not hard coded)
+* Mar 20, 2018 - SUCCESS - got a test certificate (hard-coded)
+* Mar 20, 2018 - download certificate
+* Mar 20, 2018 - poll for status
+* Mar 20, 2018 - finalize order (submit csr)
+* Mar 20, 2018 - generate domain keypair
+* Mar 20, 2018 - respond to challenges
+* Mar 16, 2018 - get challenges
+* Mar 16, 2018 - new order
+* Mar 15, 2018 - create account
+* Mar 15, 2018 - generate account keypair
+* Mar 15, 2018 - get nonce
+* Mar 15, 2018 - get directory
diff --git a/express-server/node_modules/acme/examples/cli.js b/express-server/node_modules/acme/examples/cli.js
new file mode 100644
index 00000000..0dd7a15e
--- /dev/null
+++ b/express-server/node_modules/acme/examples/cli.js
@@ -0,0 +1,64 @@
+'use strict';
+
+var readline = require('readline');
+var inquisitor = {};
+var rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout
+});
+
+require('./genkeypair.js');
+
+inquisitor.getWeb = 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]) { inquisitor.getWeb(); return; }
+
+ if (web.some(function (w) { return '*' === w[0]; })) {
+ console.log('Wildcard domains must use dns-01');
+ inquisitor.getEmail(web, 'dns-01');
+ } else {
+ inquisitor.getChallengeType(web);
+ }
+ });
+};
+
+inquisitor.getChallengeType = 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'; }
+
+ inquisitor.getEmail(web, chType);
+ });
+};
+
+inquisitor.getEmail = function getEmail(web, chType) {
+ rl.question('What email should we use? (optional) ', function (email) {
+ email = (email||'').trim();
+ if (!email) { email = null; }
+
+ inquisitor.getDirectoryUrl(web, chType, email);
+ });
+};
+
+inquisitor.getDirectoryUrl = function getDirectoryUrl(web, chType, email) {
+ var defaultDirectoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory';
+ rl.question('What directoryUrl should we use? [' + defaultDirectoryUrl + '] ', function (directoryUrl) {
+ directoryUrl = (directoryUrl||'').trim();
+ if (!directoryUrl) { directoryUrl = 'https://acme-staging-v02.api.letsencrypt.org/directory'; }
+
+ inquisitor.run(directoryUrl, web, chType, email);
+ });
+};
+
+inquisitor.run = function run(directoryUrl, web, chType, email) {
+ rl.close();
+
+ 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') });
+
+ require('../tests/promise.js').run(directoryUrl, RSA, web, chType, email, accountKeypair, domainKeypair);
+};
+
+inquisitor.getWeb();
diff --git a/express-server/node_modules/acme/examples/genkeypair.js b/express-server/node_modules/acme/examples/genkeypair.js
new file mode 100644
index 00000000..2c7e3c62
--- /dev/null
+++ b/express-server/node_modules/acme/examples/genkeypair.js
@@ -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);
+ });
+}
diff --git a/express-server/node_modules/acme/examples/http-server.js b/express-server/node_modules/acme/examples/http-server.js
new file mode 100644
index 00000000..4195455d
--- /dev/null
+++ b/express-server/node_modules/acme/examples/http-server.js
@@ -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());
+});
diff --git a/express-server/node_modules/acme/examples/https-server.js b/express-server/node_modules/acme/examples/https-server.js
new file mode 100644
index 00000000..5dd2c2c9
--- /dev/null
+++ b/express-server/node_modules/acme/examples/https-server.js
@@ -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());
+});
diff --git a/express-server/node_modules/acme/node.js b/express-server/node_modules/acme/node.js
new file mode 100644
index 00000000..b346c956
--- /dev/null
+++ b/express-server/node_modules/acme/node.js
@@ -0,0 +1,3 @@
+// For the time being I'm still pulling in my acme-v2 module until I transition over
+// I export as ".ACME" rather than bare so that this can be compatible with the browser version too
+module.exports.ACME = require('acme-v2').ACME;
diff --git a/express-server/node_modules/acme/package.json b/express-server/node_modules/acme/package.json
new file mode 100644
index 00000000..849bd1f4
--- /dev/null
+++ b/express-server/node_modules/acme/package.json
@@ -0,0 +1,109 @@
+{
+ "_args": [
+ [
+ "acme@^1.0.6",
+ "/nodeapps/https-test/greenlock-express.js/node_modules/greenlock"
+ ]
+ ],
+ "_from": "acme@>=1.0.6 <2.0.0",
+ "_id": "acme@1.1.1",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/acme",
+ "_nodeVersion": "10.2.1",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/acme_1.1.1_1530693806508_0.5374627943153449"
+ },
+ "_npmUser": {
+ "email": "coolaj86@gmail.com",
+ "name": "coolaj86"
+ },
+ "_npmVersion": "5.6.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "acme",
+ "raw": "acme@^1.0.6",
+ "rawSpec": "^1.0.6",
+ "scope": null,
+ "spec": ">=1.0.6 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/greenlock"
+ ],
+ "_resolved": "https://registry.npmjs.org/acme/-/acme-1.1.1.tgz",
+ "_shasum": "8831797657303336eb3d3d06f42d6152081f42bf",
+ "_shrinkwrap": null,
+ "_spec": "acme@^1.0.6",
+ "_where": "/nodeapps/https-test/greenlock-express.js/node_modules/greenlock",
+ "author": {
+ "email": "coolaj86@gmail.com",
+ "name": "AJ ONeal",
+ "url": "https://coolaj86.com/"
+ },
+ "dependencies": {
+ "acme-v2": "^1.1.0"
+ },
+ "description": "The bare essentials of the ACME (Let's Encrypt v2) API. This is a low-level library for building high-level clients.",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "fileCount": 9,
+ "integrity": "sha512-CZFTpD2hGSE8dd63vHtvdhabondEhgmpL0wH0weV0pk+I1WH9RVcJbdR6MgoalsUtJW/SaC+OxUDrcjINur1ow==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbPIiuCRA9TVsSAnZWagAAFEcP/34ebMMxTtSVjlKkNxZQ\n80AmVT4ESDenhRX3buCUgWuUAiK0q9K5eTel+Mj7ijElXLFzmA56VdwbaZKr\ng+5WRm3DfXA2/rGOHztLlbBXwO3Gcn6X28SUIg8R6xLrC9Z/KVd5smygOiIY\nqgmjhaDZcMxE9Wehkl6v0fYjsP0KQF6OT19f8YMHOw9m9dIJBLaJFxPVONuT\nu9XLzMnCWmsMhc2T/a+dZAHTZmZYMS0PqnJJ7S8x14+kvEiCaVME1XqSgwHv\nIagQUVICle3CLvyJaS5XnTjbxC6swd8S79IG2lrko6r8bnieonvFdUKg8AHH\n7ejyPyLw6jcruUWn6sf5U/lv0pzMyD3aldDY5udYfkLVUDrJW+xratvGCWgZ\nxwIsk9nQrnft6zhiHSuF/J7c+MRcG0i1DkXmm8gQxph4lI4KlQcfhHz1b8QI\nvGbAhk4qAphaOch0HSmFwPRv3cfEPZ03/IXQanGov2D0OLm2Zf9+BnE3Jq27\nkmrFSKbsm2LZEGK+ei7jPiXErVGP1HQx5oS59+ZAhT1QhaI/J1bha33iiyGg\nsWi5QGCxrIXY8wLgH20e4boOqUMAAkL1m3SPChCVHWl6Z2Xv9is/02oYrSmN\n5d/yb8yO34SykrrnsKx2Sj3z3xXOebdNqCob1pwL1mZC2+ccMEUsTj8GiFSQ\nQNJX\r\n=v/wZ\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "8831797657303336eb3d3d06f42d6152081f42bf",
+ "tarball": "https://registry.npmjs.org/acme/-/acme-1.1.1.tgz",
+ "unpackedSize": 17077
+ },
+ "gitHead": "71ae7393cbf816aa9eef85bfb9722bcee82feefb",
+ "homepage": "https://git.coolaj86.com/coolaj86/acme.js",
+ "keywords": [
+ "11",
+ "Let's Encrypt",
+ "acme",
+ "acme-draft-11",
+ "acme-draft11",
+ "acme-v02",
+ "acme-v2",
+ "acme11",
+ "acme2",
+ "acmev02",
+ "acmev2",
+ "draft",
+ "greenlock",
+ "greenlock2",
+ "https",
+ "letsencrypt",
+ "letsencrypt-v02",
+ "letsencrypt-v2",
+ "letsencrypt2",
+ "letsencryptv02",
+ "letsencryptv2",
+ "ssl",
+ "tls"
+ ],
+ "license": "(MIT OR Apache-2.0)",
+ "main": "node.js",
+ "maintainers": [
+ {
+ "name": "coolaj86",
+ "email": "coolaj86@gmail.com"
+ },
+ {
+ "name": "thejshaver",
+ "email": "john@jshaver.net"
+ }
+ ],
+ "name": "acme",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "ssh://gitea@git.coolaj86.com:22042/coolaj86/acme.js.git"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "version": "1.1.1"
+}
diff --git a/express-server/node_modules/acme/tests/promise.js b/express-server/node_modules/acme/tests/promise.js
new file mode 100644
index 00000000..ee2a0287
--- /dev/null
+++ b/express-server/node_modules/acme/tests/promise.js
@@ -0,0 +1,85 @@
+'use strict';
+
+/* global Promise */
+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 = {
+ agreeToTerms: function (tosUrl) {
+ return Promise.resolve(tosUrl);
+ }
+ , setChallenge: function (opts) {
+ return new Promise(function (resolve, reject) {
+ var pathname;
+
+ 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("");
+
+ if ('http-01' === opts.type) {
+ pathname = opts.hostname + acme2.challengePrefixes['http-01'] + "/" + opts.token;
+ console.log("Put the string '" + opts.keyAuthorization + "' into a file at '" + pathname + "'");
+ console.log("echo '" + opts.keyAuthorization + "' > '" + pathname + "'");
+ } else if ('dns-01' === opts.type) {
+ pathname = acme2.challengePrefixes['dns-01'] + "." + opts.hostname.replace(/^\*\./, '');;
+ console.log("Put the string '" + opts.dnsAuthorization + "' into the TXT record '" + pathname + "'");
+ console.log("ddig TXT " + pathname + " '" + opts.dnsAuthorization + "'");
+ } else {
+ reject(new Error("[acme-v2] unrecognized challenge type"));
+ return;
+ }
+ console.log("\nThen hit the 'any' key to continue...");
+
+ function onAny() {
+ console.log("'any' key was hit");
+ process.stdin.pause();
+ process.stdin.removeListener('data', onAny);
+ process.stdin.setRawMode(false);
+ resolve();
+ return;
+ }
+
+ process.stdin.setRawMode(true);
+ process.stdin.resume();
+ process.stdin.on('data', onAny);
+ });
+ }
+ , removeChallenge: function (opts) {
+ console.log('[acme-v2] remove challenge', opts.hostname, opts.keyAuthorization);
+ return new Promise(function (resolve) {
+ // hostname, key
+ setTimeout(resolve, 1 * 1000);
+ });
+ }
+ , challengeType: chType
+ , email: email
+ , accountKeypair: accountKeypair
+ , domainKeypair: domainKeypair
+ , domains: web
+ };
+
+ acme2.accounts.create(options).then(function (account) {
+ console.log('[acme-v2] account:');
+ console.log(account);
+
+ acme2.certificates.create(options).then(function (fullchainPem) {
+ console.log('[acme-v2] fullchain.pem:');
+ console.log(fullchainPem);
+ });
+ });
+ });
+};
diff --git a/express-server/node_modules/asn1js/.gitattributes b/express-server/node_modules/asn1js/.gitattributes
new file mode 100644
index 00000000..1ff0c423
--- /dev/null
+++ b/express-server/node_modules/asn1js/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/express-server/node_modules/asn1js/.npmignore b/express-server/node_modules/asn1js/.npmignore
new file mode 100644
index 00000000..1bc915c5
--- /dev/null
+++ b/express-server/node_modules/asn1js/.npmignore
@@ -0,0 +1,156 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+build/
+[Bb]in/
+[Oo]bj/
+
+# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
+!packages/*/build/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+#packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+
+#LightSwitch generated files
+GeneratedArtifacts/
+_Pvt_Extensions/
+ModelManifest.xml
+
+# =========================
+# Windows detritus
+# =========================
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac desktop service store files
+.DS_Store
diff --git a/express-server/node_modules/asn1js/CNAME b/express-server/node_modules/asn1js/CNAME
new file mode 100644
index 00000000..769f43cf
--- /dev/null
+++ b/express-server/node_modules/asn1js/CNAME
@@ -0,0 +1 @@
+asn1js.org
diff --git a/express-server/node_modules/asn1js/LICENSE b/express-server/node_modules/asn1js/LICENSE
new file mode 100644
index 00000000..4f71696a
--- /dev/null
+++ b/express-server/node_modules/asn1js/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, GMO GlobalSign
+Copyright (c) 2015, Peculiar Ventures
+All rights reserved.
+
+Author 2014-2015, Yury Strozhevsky
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice, this
+ list of conditions and the following disclaimer in the documentation and/or
+ other materials provided with the distribution.
+
+* Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/express-server/node_modules/asn1js/README.md b/express-server/node_modules/asn1js/README.md
new file mode 100644
index 00000000..75b50978
--- /dev/null
+++ b/express-server/node_modules/asn1js/README.md
@@ -0,0 +1,212 @@
+## ASN1js
+
+[](https://raw.githubusercontent.com/GlobalSign/ASN1.js/master/LICENSE)
+
+Abstract Syntax Notation One (ASN.1) is a standard and notation that describes rules and structures for representing, encoding, transmitting, and decoding data in telecommunications and computer networking. [ASN1js][] is a pure JavaScript library implementing this standard. ASN.1 is the basis of all X.509 related data structures and numerous other protocols used on the web.
+
+## Introduction
+
+[ASN1js][] is the first library for [BER][] encoding/decoding in Javascript designed for browser use. [BER][] is the basic encoding rules for [ASN.1][] that all others are based on, [DER][] is the encoding rules used by PKI applications - it is a subset of [BER][]. The [ASN1js][] library was tested against [freely available ASN.1:2008 test suite], with some limitations related to JavaScript language.
+
+## Features of the library
+
+* [ASN1js][] is a "base layer" for full-featured JS library [PKIjs][], which is using Web Cryptography API and has all classes, neccessary to work with PKI-related data;
+* Fully object-oriented library. Inhiritence is using everywhere inside the lib;
+* Working with HTML5 data objects (ArrayBuffer, Uint8Array etc.);
+* Working with all ASN.1:2008 types;
+* Working with [BER][] encoded data;
+* All types inside the library constantly stores information about all ASN.1 sub blocks (tag block, length block or value block);
+* User may have access to any byte inside any ASN.1 sub-block;
+* Any sub-block may have unlimited length, as it described in ASN.1 standard (even "tag block");
+* Ability to work with ASN.1 string date types (intcluding all "international" strings like UniversalString, BMPString, UTF8String) by passing native JavaScript strings into constuctors. And vice versa - all initially parsed data of ASN.1 string types right after decoding automatically converts into native JavaScript strings;
+* Same with ASN.1 date-time types: for major types like UTCTime and GeneralizedTime there are automatic convertion between "JS date type - ASN.1 date-time type" + vice versa;
+* Same with ASN.1 OBJECT-IDENTIFIER (OID) data-type: you can initialize OID by JavaScript string and can get string representation via calling "oid.value_block.toString()";
+* Working with "easy-to-understand" ASN.1 schemas (pre-defined or built by user);
+* Has special types to work with ASN.1 schemas:
+ * ANY
+ * CHOICE
+ * REPEATED
+* User can name any block inside ASN.1 schema and easily get information by name;
+* Ability to parse internal data inside a primitively encoded data types and automatically validate it against special schema;
+* All types inside library are dynamic;
+* All types can be initialized in static or dynamic ways.
+
+## Examples
+
+```javascript
+ // #region How to create new ASN. structures
+ var sequence = new org.pkijs.asn1.SEQUENCE();
+ sequence.value_block.value.push(new org.pkijs.asn1.INTEGER({ value: 1 }));
+
+ var sequence_buffer = sequence.toBER(false); // Encode current sequence to BER (in ArrayBuffer)
+ var current_size = sequence_buffer.byteLength;
+
+ var integer_data = new ArrayBuffer(8);
+ var integer_view = new Uint8Array(integer_data);
+ integer_view[0] = 0x01;
+ integer_view[1] = 0x01;
+ integer_view[2] = 0x01;
+ integer_view[3] = 0x01;
+ integer_view[4] = 0x01;
+ integer_view[5] = 0x01;
+ integer_view[6] = 0x01;
+ integer_view[7] = 0x01;
+
+ sequence.value_block.value.push(new org.pkijs.asn1.INTEGER({
+ is_hex_only: true,
+ value_hex: integer_data
+ })); // Put too long for decoding INTEGER value
+
+ sequence_buffer = sequence.toBER(false);
+ current_size = sequence_buffer.byteLength;
+ // #endregion
+```
+
+```javascript
+ // #region How to create new ASN.1 structures by calling constuctors with parameters
+ var sequence2 = new org.pkijs.asn1.SEQUENCE({
+ value: [
+ new org.pkijs.asn1.INTEGER({ value: 1 }),
+ new org.pkijs.asn1.INTEGER({
+ is_hex_only: true,
+ value_hex: integer_data
+ }),
+ ]
+ });
+ // #endregion
+```
+
+```javascript
+ // #region How to validate ASN.1 against pre-defined schema
+ var asn1_schema = new org.pkijs.asn1.SEQUENCE({
+ name: "block1",
+ value: [
+ new org.pkijs.asn1.NULL({
+ name: "block2"
+ }),
+ new org.pkijs.asn1.INTEGER({
+ name: "block3",
+ optional: true // This block is absent inside data, but it's "optional". Hence verification against the schema will be passed.
+ })
+ ]
+ });
+ // #endregion
+
+ var variant1 = org.pkijs.verifySchema(encoded_sequence, asn1_schema); // Verify schema together with decoding of raw data
+ var variant1_verified = variant1.verified;
+ var variant1_result = variant1.result; // Verified decoded data with all block names inside
+```
+
+```javascript
+ // #region How to use "internal schemas" for primitevely encoded data types
+ var primitive_octetstring = new org.pkijs.asn1.OCTETSTRING({ value_hex: encoded_sequence }); // Create a primitively encoded OCTETSTRING where internal data is an encoded SEQUENCE
+
+ var asn1_schema_internal = new org.pkijs.asn1.OCTETSTRING({
+ name: "outer_block",
+ primitive_schema: new org.pkijs.asn1.SEQUENCE({
+ name: "block1",
+ value: [
+ new org.pkijs.asn1.NULL({
+ name: "block2"
+ })
+ ]
+ })
+ });
+
+ var variant6 = org.pkijs.compareSchema(primitive_octetstring, primitive_octetstring, asn1_schema_internal);
+ var variant6_verified = variant4.verified;
+ var variant6_block1_tag_num = variant6.result.block1.id_block.tag_number;
+ var variant6_block2_tag_num = variant6.result.block2.id_block.tag_number;
+ // #endregion
+```
+
+More examples could be found in "examples" directory or inside [PKIjs][] library.
+
+## Related source code
+
+* [C++ ASN1:2008 BER coder/decoder](https://github.com/YuryStrozhevsky/C-plus-plus-ASN.1-2008-coder-decoder) - the "father" of [ASN1js][] project;
+* [Freely available ASN.1:2008 test suite](https://github.com/YuryStrozhevsky/ASN1-2008-free-test-suite) - the suite which can help you to validate (and better understand) any ASN.1 coder/decoder;
+
+## Suitability
+At this time this library should be considered suitable for research and experimentation, futher code and security review is needed before utilization in a production application.
+
+## How to use ASN1js and PKIjs with Node.js
+
+**!!! WARNING !!! **
+**Currently there is no "polyfill" of WebCrypto in Node.js. Thus you will not be able to use signature / verification features of PKIjs in Node.js programs.**
+
+In order to use [PKIjs][] you will also need [ASN1js][] plus [node.extend](https://www.npmjs.com/package/node.extend) package.
+```javascript
+ var merge = require("node.extend");
+
+ var common = require("asn1js/org/pkijs/common");
+ var _asn1js = require("asn1js");
+ var _pkijs = require("pkijs");
+ var _x509schema = require("pkijs/org/pkijs/x509_schema");
+
+ // #region Merging function/object declarations for ASN1js and PKIjs
+ var asn1js = merge(true, _asn1js, common);
+
+ var x509schema = merge(true, _x509schema, asn1js);
+
+ var pkijs_1 = merge(true, _pkijs, asn1js);
+ var pkijs = merge(true, pkijs_1, x509schema);
+ // #endregion
+```
+
+After that you will ba able to use ASN1js and PKIjs via common way:
+```javascript
+ // #region Decode and parse X.509 cert
+ var asn1 = pkijs.org.pkijs.fromBER(certBuffer);
+ var cert;
+ try
+ {
+ cert = new pkijs.org.pkijs.simpl.CERT({ schema: asn1.result });
+ }
+ catch(ex)
+ {
+ return;
+ }
+ // #endregion
+```
+
+## License
+
+Copyright (c) 2014, [GMO GlobalSign](http://www.globalsign.com/)
+Copyright (c) 2015, [Peculiar Ventures](http://peculiarventures.com/)
+All rights reserved.
+
+Author 2014-2015, [Yury Strozhevsky](http://www.strozhevsky.com/).
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+ may be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+OF SUCH DAMAGE.
+
+
+[ASN.1]: http://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One
+[ASN1js]: http://asn1js.org/
+[PKIjs]: http://pkijs.org/
+[BER]: http://en.wikipedia.org/wiki/X.690#BER_encoding
+[DER]: http://en.wikipedia.org/wiki/X.690#DER_encoding
+[freely available ASN.1:2008 test suite]: http://www.strozhevsky.com/free_docs/free_asn1_testsuite_descr.pdf
diff --git a/express-server/node_modules/asn1js/examples/ASN.1 usage/asn1_usage.js b/express-server/node_modules/asn1js/examples/ASN.1 usage/asn1_usage.js
new file mode 100644
index 00000000..2e3ac557
--- /dev/null
+++ b/express-server/node_modules/asn1js/examples/ASN.1 usage/asn1_usage.js
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2014, GMO GlobalSign
+ * Copyright (c) 2015, Peculiar Ventures
+ * All rights reserved.
+ *
+ * Author 2014-2015, Yury Strozhevsky .
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+//**************************************************************************************
+function test()
+{
+ // #region How to create new ASN. structures
+ var sequence = new org.pkijs.asn1.SEQUENCE();
+ sequence.value_block.value.push(new org.pkijs.asn1.INTEGER({ value: 1 }));
+
+ var sequence_buffer = sequence.toBER(false); // Encode current sequence to BER (in ArrayBuffer)
+ var current_size = sequence_buffer.byteLength;
+
+ var integer_data = new ArrayBuffer(8);
+ var integer_view = new Uint8Array(integer_data);
+ integer_view[0] = 0x01;
+ integer_view[1] = 0x01;
+ integer_view[2] = 0x01;
+ integer_view[3] = 0x01;
+ integer_view[4] = 0x01;
+ integer_view[5] = 0x01;
+ integer_view[6] = 0x01;
+ integer_view[7] = 0x01;
+
+ sequence.value_block.value.push(new org.pkijs.asn1.INTEGER({
+ is_hex_only: true,
+ value_hex: integer_data
+ })); // Put too long for decoding INTEGER value
+
+ sequence_buffer = sequence.toBER(false);
+ current_size = sequence_buffer.byteLength;
+ // #endregion
+
+ // #region How to create new ASN.1 structures by calling constuctors with parameters
+ var sequence2 = new org.pkijs.asn1.SEQUENCE({
+ value: [
+ new org.pkijs.asn1.INTEGER({ value: 1 }),
+ new org.pkijs.asn1.INTEGER({
+ is_hex_only: true,
+ value_hex: integer_data
+ }),
+ ]
+ });
+ // #endregion
+
+ // #region How to check that decoded value is too big
+ var big_integer_value;
+
+ var big_integer = new org.pkijs.asn1.INTEGER({
+ is_hex_only: true,
+ value_hex: integer_data
+ });
+
+ if(big_integer.value_block.is_hex_only === false)
+ big_integer_value = big_integer.value_block.value_dec; // Native integer value
+ else
+ big_integer_value = big_integer.value_block.value_hex; // ArrayBuffer
+ // #endregion
+
+ // #region How to get ASN.1 structures from raw data (ASN.1 decoding)
+ var encoded_sequence = new ArrayBuffer(4);
+ var encoded_sequence_view = new Uint8Array(encoded_sequence);
+ encoded_sequence_view[0] = 0x30;
+ encoded_sequence_view[1] = 0x02;
+ encoded_sequence_view[2] = 0x05;
+ encoded_sequence_view[3] = 0x00;
+
+ var decoded_asn1 = org.pkijs.fromBER(encoded_sequence);
+ if(decoded_asn1.offset === (-1))
+ return; // Error during decoding
+
+ var decoded_sequence = decoded_asn1.result;
+
+ var internal_value = decoded_sequence.value_block.value[0];
+ var internal_value_tag_number = internal_value.id_block.tag_number; // Value of "5" equal to ASN.1 NULL type
+ // #endregion
+
+ // #region How to work with ASN.1 strings
+ var bmp_string_encoded = new ArrayBuffer(16); // This ArrayBuffer consinsts of encoded ASN.1 BMPString with "abc_" + three first chars from Russian alphabet
+ var bmp_string_view = new Uint8Array(bmp_string_encoded);
+ bmp_string_view[0] = 0x1E;
+ bmp_string_view[1] = 0x0E;
+ bmp_string_view[2] = 0x00;
+ bmp_string_view[3] = 0x61;
+ bmp_string_view[4] = 0x00;
+ bmp_string_view[5] = 0x62;
+ bmp_string_view[6] = 0x00;
+ bmp_string_view[7] = 0x63;
+ bmp_string_view[8] = 0x00;
+ bmp_string_view[9] = 0x5F;
+ bmp_string_view[10] = 0x04;
+ bmp_string_view[11] = 0x30;
+ bmp_string_view[12] = 0x04;
+ bmp_string_view[13] = 0x31;
+ bmp_string_view[14] = 0x04;
+ bmp_string_view[15] = 0x32;
+
+ var bmp_string_decoded = org.pkijs.fromBER(bmp_string_encoded);
+ if(bmp_string_decoded.offset === (-1))
+ return; // Error during decoding
+
+ var javascript_string1 = bmp_string_decoded.result.value_block.value;
+
+ var bmp_string = new org.pkijs.asn1.BMPSTRING({ value: "abc_абв" }); // Same with initialization by static JavaScript string
+ var javascript_string2 = bmp_string.value_block.value;
+ // #endregion
+
+ // #region How to validate ASN.1 against pre-defined schema
+ var asn1_schema = new org.pkijs.asn1.SEQUENCE({
+ name: "block1",
+ value: [
+ new org.pkijs.asn1.NULL({
+ name: "block2"
+ }),
+ new org.pkijs.asn1.INTEGER({
+ name: "block3",
+ optional: true // This block is absent inside data, but it's "optional". Hence verification against the schema will be passed.
+ })
+ ]
+ });
+
+ var variant1 = org.pkijs.verifySchema(encoded_sequence, asn1_schema); // Verify schema together with decoding of raw data
+ var variant1_verified = variant1.verified;
+ var variant1_result = variant1.result; // Verified decoded data with all block names inside
+
+ var variant1_block1 = variant1_result.block1;
+ var variant1_block2 = variant1_result.block2;
+
+ var variant2 = org.pkijs.compareSchema(decoded_sequence, decoded_sequence, asn1_schema); // Compare already decoded ASN.1 against pre-defined schema
+ var variant2_verified = variant2.verified;
+ var variant2_result = variant2.result; // Verified decoded data with all block names inside
+
+ var variant2_block1 = variant2_result.block1;
+ var variant2_block2 = variant2_result.block2;
+
+ var asn1_schema_any = new org.pkijs.asn1.SEQUENCE({
+ name: "block1",
+ value: [
+ new org.pkijs.asn1.ANY({ // Special type, for ASN.1 schemas only - will validate schema against any ASN.1 type
+ name: "block2"
+ })
+ ]
+ });
+
+ decoded_sequence = org.pkijs.fromBER(encoded_sequence).result; // Re-setting "decoded_sequence"
+
+ var variant3 = org.pkijs.compareSchema(decoded_sequence, decoded_sequence, asn1_schema_any);
+ var variant3_verified = variant3.verified;
+
+ var asn1_schema_repeated = new org.pkijs.asn1.SEQUENCE({
+ name: "block1",
+ value: [
+ new org.pkijs.asn1.REPEATED({ // Special type, for ASN.1 schemas only - will check that inside decoded data there are sequence of values with one type only
+ name: "block2_array",
+ value: new org.pkijs.asn1.NULL()
+ })
+ ]
+ });
+
+ decoded_sequence = org.pkijs.fromBER(encoded_sequence).result; // Re-setting "decoded_sequence"
+
+ var variant4 = org.pkijs.compareSchema(decoded_sequence, decoded_sequence, asn1_schema_repeated);
+ var variant4_verified = variant4.verified;
+
+ var variant4_array = variant4.block2_array; // Array of internal blocks
+
+ var asn1_schema_choice = new org.pkijs.asn1.SEQUENCE({
+ name: "block1",
+ value: [
+ new org.pkijs.asn1.CHOICE({ // Special type, for ASN.1 schemas only - will check ASN.1 data has one of type
+ value: [
+ new org.pkijs.asn1.NULL({
+ name: "block2"
+ }),
+ new org.pkijs.asn1.INTEGER({
+ name: "block2"
+ }),
+ ]
+ })
+ ]
+ });
+
+ decoded_sequence = org.pkijs.fromBER(encoded_sequence).result; // Re-setting "decoded_sequence"
+
+ var variant5 = org.pkijs.compareSchema(decoded_sequence, decoded_sequence, asn1_schema_choice);
+ var variant5_verified = variant4.verified;
+ // #endregion
+
+ // #region How to use "internal schemas" for primitevely encoded data types
+ var primitive_octetstring = new org.pkijs.asn1.OCTETSTRING({ value_hex: encoded_sequence }); // Create a primitively encoded OCTETSTRING where internal data is an encoded SEQUENCE
+
+ var asn1_schema_internal = new org.pkijs.asn1.OCTETSTRING({
+ name: "outer_block",
+ primitive_schema: new org.pkijs.asn1.SEQUENCE({
+ name: "block1",
+ value: [
+ new org.pkijs.asn1.NULL({
+ name: "block2"
+ })
+ ]
+ })
+ });
+
+ var variant6 = org.pkijs.compareSchema(primitive_octetstring, primitive_octetstring, asn1_schema_internal);
+ var variant6_verified = variant4.verified;
+ var variant6_block1_tag_num = variant6.result.block1.id_block.tag_number;
+ var variant6_block2_tag_num = variant6.result.block2.id_block.tag_number;
+ // #endregion
+}
+//**************************************************************************************
diff --git a/express-server/node_modules/asn1js/org/pkijs/asn1.js b/express-server/node_modules/asn1js/org/pkijs/asn1.js
new file mode 100644
index 00000000..4c038a44
--- /dev/null
+++ b/express-server/node_modules/asn1js/org/pkijs/asn1.js
@@ -0,0 +1,5466 @@
+/*
+ * Copyright (c) 2014, GMO GlobalSign
+ * Copyright (c) 2015, Peculiar Ventures
+ * All rights reserved.
+ *
+ * Author 2014-2015, Yury Strozhevsky .
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+(
+function(in_window)
+{
+ //**************************************************************************************
+ // #region Declaration of global variables
+ //**************************************************************************************
+ // #region "org" namespace
+ if(typeof in_window.org === "undefined")
+ in_window.org = {};
+ else
+ {
+ if(typeof in_window.org !== "object")
+ throw new Error("Name org already exists and it's not an object");
+ }
+ // #endregion
+
+ // #region "org.pkijs" namespace
+ if(typeof in_window.org.pkijs === "undefined")
+ in_window.org.pkijs = {};
+ else
+ {
+ if(typeof in_window.org.pkijs !== "object")
+ throw new Error("Name org.pkijs already exists and it's not an object" + " but " + (typeof in_window.org.pkijs));
+ }
+ // #endregion
+
+ // #region "org.pkijs.asn1" namespace
+ if(typeof in_window.org.pkijs.asn1 === "undefined")
+ in_window.org.pkijs.asn1 = {};
+ else
+ {
+ if(typeof in_window.org.pkijs.asn1 !== "object")
+ throw new Error("Name org.pkijs.asn1 already exists and it's not an object" + " but " + (typeof in_window.org.pkijs.asn1));
+ }
+ // #endregion
+
+ // #region "local" namespace
+ var local = {};
+ // #endregion
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Aux-functions
+ //**************************************************************************************
+ function util_frombase(input_buffer, input_base)
+ {
+ /// Convert number from 2^base to 2^10
+ /// Array of bytes representing the number to convert
+ /// The base of initial number
+
+ var result = 0;
+
+ for(var i = (input_buffer.length - 1); i >= 0; i-- )
+ result += input_buffer[(input_buffer.length - 1) - i] * Math.pow(2, input_base * i);
+
+ return result;
+ }
+ //**************************************************************************************
+ function util_tobase(value, base, reserved)
+ {
+ /// Convert number from 2^10 to 2^base
+ /// The number to convert
+ /// The base for 2^base
+ /// Pre-defined number of bytes in output array (-1 = limited by function itself)
+
+ reserved = reserved || (-1);
+
+ var result = 0;
+ var biggest = Math.pow(2, base);
+
+ for(var i = 1; i < 8; i++)
+ {
+ if(value < biggest)
+ {
+ var ret_buf;
+
+ if( reserved < 0 )
+ {
+ ret_buf = new ArrayBuffer(i);
+ result = i;
+ }
+ else
+ {
+ if(reserved < i)
+ return (new ArrayBuffer(0));
+
+ ret_buf = new ArrayBuffer(reserved);
+
+ result = reserved;
+ }
+
+ var ret_view = new Uint8Array(ret_buf);
+
+ for(var j = ( i - 1 ); j >= 0; j-- )
+ {
+ var basis = Math.pow(2, j * base);
+
+ ret_view[ result - j - 1 ] = Math.floor( value / basis );
+ value -= ( ret_view[ result - j - 1 ] ) * basis;
+ }
+
+ return ret_buf;
+ }
+
+ biggest *= Math.pow(2, base);
+ }
+ }
+ //**************************************************************************************
+ function util_encode_tc(value)
+ {
+ /// Encode integer value to "two complement" format
+ /// Value to encode
+
+ var mod_value = (value < 0) ? (value * (-1)) : value;
+ var big_int = 128;
+
+ for(var i = 1; i < 8; i++)
+ {
+ if( mod_value <= big_int )
+ {
+ if( value < 0 )
+ {
+ var small_int = big_int - mod_value;
+
+ var ret_buf = util_tobase( small_int, 8, i );
+ var ret_view = new Uint8Array(ret_buf);
+
+ ret_view[ 0 ] |= 0x80;
+
+ return ret_buf;
+ }
+ else
+ {
+ var ret_buf = util_tobase( mod_value, 8, i );
+ var ret_view = new Uint8Array(ret_buf);
+
+ if( ret_view[ 0 ] & 0x80 )
+ {
+ var temp_buf = util_copybuf(ret_buf);
+ var temp_view = new Uint8Array(temp_buf);
+
+ ret_buf = new ArrayBuffer( ret_buf.byteLength + 1 );
+ ret_view = new Uint8Array(ret_buf);
+
+ for(var k = 0; k < temp_buf.byteLength; k++)
+ ret_view[k + 1] = temp_view[k];
+
+ ret_view[0] = 0x00;
+ }
+
+ return ret_buf;
+ }
+ }
+
+ big_int *= Math.pow(2, 8);
+ }
+
+ return (new ArrayBuffer(0));
+ }
+ //**************************************************************************************
+ function util_decode_tc()
+ {
+ /// Decoding of "two complement" values
+ /// The function must be called in scope of instance of "hex_block" class ("value_hex" and "warnings" properties must be present)
+
+ var buf = new Uint8Array(this.value_hex);
+
+ if(this.value_hex.byteLength >= 2)
+ {
+ var condition_1 = (buf[0] == 0xFF) && (buf[1] & 0x80);
+ var condition_2 = (buf[0] == 0x00) && ((buf[1] & 0x80) == 0x00);
+
+ if(condition_1 || condition_2)
+ this.warnings.push("Needlessly long format");
+ }
+
+ // #region Create big part of the integer
+ var big_int_buffer = new ArrayBuffer(this.value_hex.byteLength);
+ var big_int_view = new Uint8Array(big_int_buffer);
+ for(var i = 0; i < this.value_hex.byteLength; i++)
+ big_int_view[i] = 0;
+
+ big_int_view[0] = (buf[0] & 0x80); // mask only the biggest bit
+
+ var big_int = util_frombase(big_int_view, 8);
+ // #endregion
+
+ // #region Create small part of the integer
+ var small_int_buffer = new ArrayBuffer(this.value_hex.byteLength);
+ var small_int_view = new Uint8Array(small_int_buffer);
+ for(var j = 0; j < this.value_hex.byteLength; j++)
+ small_int_view[j] = buf[j];
+
+ small_int_view[0] &= 0x7F; // mask biggest bit
+
+ var small_int = util_frombase(small_int_view, 8);
+ // #endregion
+
+ return (small_int - big_int);
+ }
+ //**************************************************************************************
+ function util_copybuf(input_buffer)
+ {
+ /// Creating a copy of input ArrayBuffer
+ /// ArrayBuffer for coping
+
+ if(check_buffer_params(input_buffer, 0, input_buffer.byteLength) === false)
+ return (new ArrayBuffer(0));
+
+ var input_view = new Uint8Array(input_buffer);
+
+ var ret_buf = new ArrayBuffer(input_buffer.byteLength);
+ var ret_view = new Uint8Array(ret_buf);
+
+ for(var i = 0; i < input_buffer.byteLength; i++)
+ ret_view[i] = input_view[i];
+
+ return ret_buf;
+ }
+ //**************************************************************************************
+ function util_copybuf_offset(input_buffer, input_offset, input_length)
+ {
+ /// Creating a copy of input ArrayBuffer
+ /// ArrayBuffer for coping
+
+ if(check_buffer_params(input_buffer, input_offset, input_length) === false)
+ return (new ArrayBuffer(0));
+
+ var input_view = new Uint8Array(input_buffer, input_offset, input_length);
+
+ var ret_buf = new ArrayBuffer(input_length);
+ var ret_view = new Uint8Array(ret_buf);
+
+ for(var i = 0; i < input_length; i++)
+ ret_view[i] = input_view[i];
+
+ return ret_buf;
+ }
+ //**************************************************************************************
+ function util_concatbuf(input_buf1, input_buf2)
+ {
+ /// Concatenate two ArrayBuffers
+ /// First ArrayBuffer (first part of concatenated array)
+ /// Second ArrayBuffer (second part of concatenated array)
+
+ var input_view1 = new Uint8Array(input_buf1);
+ var input_view2 = new Uint8Array(input_buf2);
+
+ var ret_buf = new ArrayBuffer(input_buf1.byteLength + input_buf2.byteLength);
+ var ret_view = new Uint8Array(ret_buf);
+
+ for(var i = 0; i < input_buf1.byteLength; i++)
+ ret_view[i] = input_view1[i];
+
+ for(var j = 0; j < input_buf2.byteLength; j++)
+ ret_view[input_buf1.byteLength + j] = input_view2[j];
+
+ return ret_buf;
+ }
+ //**************************************************************************************
+ function check_buffer_params(input_buffer, input_offset, input_length)
+ {
+ if((input_buffer instanceof ArrayBuffer) === false)
+ {
+ this.error = "Wrong parameter: input_buffer must be \"ArrayBuffer\"";
+ return false;
+ }
+
+ if(input_buffer.byteLength === 0)
+ {
+ this.error = "Wrong parameter: input_buffer has zero length";
+ return false;
+ }
+
+ if(input_offset < 0)
+ {
+ this.error = "Wrong parameter: input_offset less than zero";
+ return false;
+ }
+
+ if(input_length < 0)
+ {
+ this.error = "Wrong parameter: input_length less than zero";
+ return false;
+ }
+
+ if((input_buffer.byteLength - input_offset - input_length) < 0)
+ {
+ this.error = "End of input reached before message was fully decoded (inconsistent offset and length values)";
+ return false;
+ }
+
+ return true;
+ }
+ //**************************************************************************************
+ function to_hex_codes(input_buffer, input_offset, input_lenght)
+ {
+ if(check_buffer_params(input_buffer, input_offset, input_lenght) === false)
+ return "";
+
+ var result = "";
+
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_lenght);
+
+ for(var i = 0; i < int_buffer.length; i++)
+ {
+ var str = int_buffer[i].toString(16).toUpperCase();
+ result = result + ((str.length === 1) ? " 0" : " ") + str;
+ }
+
+ return result;
+ }
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of base block class
+ //**************************************************************************************
+ local.base_block =
+ function()
+ {
+ /// General class of all ASN.1 blocks
+
+ if(arguments[0] instanceof Object)
+ {
+ this.block_length = in_window.org.pkijs.getValue(arguments[0], "block_length", 0);
+ this.error = in_window.org.pkijs.getValue(arguments[0], "error", new String());
+ this.warnings = in_window.org.pkijs.getValue(arguments[0], "warnings", new Array());
+ if("value_before_decode" in arguments[0])
+ this.value_before_decode = util_copybuf(arguments[0].value_before_decode);
+ else
+ this.value_before_decode = new ArrayBuffer(0);
+ }
+ else
+ {
+ this.block_length = 0;
+ this.error = new String();
+ this.warnings = new Array();
+ /// Copy of the value of incoming ArrayBuffer done before decoding
+ this.value_before_decode = new ArrayBuffer(0);
+ }
+ };
+ //**************************************************************************************
+ local.base_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "base_block";
+ };
+ //**************************************************************************************
+ local.base_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ return {
+ block_name: local.base_block.prototype.block_name.call(this),
+ block_length: this.block_length,
+ error: this.error,
+ warnings: this.warnings,
+ value_before_decode: in_window.org.pkijs.bufferToHexCodes(this.value_before_decode, 0, this.value_before_decode.byteLength)
+ };
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of hex block class
+ //**************************************************************************************
+ local.hex_block =
+ function()
+ {
+ /// Descendant of "base_block" with internal ArrayBuffer. Need to have it in case it is not possible to store ASN.1 value in native formats
+
+ local.base_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false);
+ if("value_hex" in arguments[0])
+ this.value_hex = util_copybuf(arguments[0].value_hex);
+ else
+ this.value_hex = new ArrayBuffer(0);
+ }
+ else
+ {
+ this.is_hex_only = false;
+ this.value_hex = new ArrayBuffer(0);
+ }
+ };
+ //**************************************************************************************
+ local.hex_block.prototype = new local.base_block();
+ local.hex_block.constructor = local.hex_block;
+ //**************************************************************************************
+ local.hex_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "hex_block";
+ };
+ //**************************************************************************************
+ local.hex_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ // #region Getting Uint8Array from ArrayBuffer
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+ // #endregion
+
+ // #region Initial checks
+ if(int_buffer.length == 0)
+ {
+ this.warnings.push("Zero buffer length");
+ return input_offset;
+ }
+ // #endregion
+
+ // #region Copy input buffer to internal buffer
+ this.value_hex = new ArrayBuffer(input_length);
+ var view = new Uint8Array(this.value_hex);
+
+ for(var i = 0; i < int_buffer.length; i++)
+ view[i] = int_buffer[i];
+ // #endregion
+
+ this.block_length = input_length;
+
+ return (input_offset + input_length);
+ };
+ //**************************************************************************************
+ local.hex_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ if(this.is_hex_only !== true)
+ {
+ this.error = "Flag \"is_hex_only\" is not set, abort";
+ return (new ArrayBuffer(0));
+ }
+
+ var ret_buf = new ArrayBuffer(this.value_hex.byteLength);
+
+ if(size_only === true)
+ return ret_buf;
+
+ var ret_view = new Uint8Array(ret_buf);
+ var cur_view = new Uint8Array(this.value_hex);
+
+ for(var i = 0; i < cur_view.length; i++)
+ ret_view[i] = cur_view[i];
+
+ return ret_buf;
+ };
+ //**************************************************************************************
+ local.hex_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.base_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.hex_block.prototype.block_name.call(this);
+ _object.is_hex_only = this.is_hex_only;
+ _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of identification block class
+ //**************************************************************************************
+ local.identification_block =
+ function()
+ {
+ /// Base class of ASN.1 "identification block"
+
+ local.hex_block.call(this, arguments[0]);
+
+ this.tag_class = (-1);
+ this.tag_number = (-1);
+ this.is_constructed = false;
+
+ if(arguments[0] instanceof Object)
+ {
+ if("id_block" in arguments[0])
+ {
+ // #region Properties from hex_block class
+ this.is_hex_only = in_window.org.pkijs.getValue(arguments[0].id_block, "is_hex_only", false);
+ this.value_hex = in_window.org.pkijs.getValue(arguments[0].id_block, "value_hex", new ArrayBuffer(0));
+ // #endregion
+
+ this.tag_class = in_window.org.pkijs.getValue(arguments[0].id_block, "tag_class", (-1));
+ this.tag_number = in_window.org.pkijs.getValue(arguments[0].id_block, "tag_number", (-1));
+ this.is_constructed = in_window.org.pkijs.getValue(arguments[0].id_block, "is_constructed", false);
+ }
+ }
+ };
+ //**************************************************************************************
+ local.identification_block.prototype = new local.hex_block();
+ local.identification_block.constructor = local.identification_block;
+ //**************************************************************************************
+ local.identification_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "identification_block";
+ };
+ //**************************************************************************************
+ local.identification_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ var first_octet = 0;
+
+ switch(this.tag_class)
+ {
+ case 1:
+ first_octet |= 0x00; // UNIVERSAL
+ break;
+ case 2:
+ first_octet |= 0x40; // APPLICATION
+ break;
+ case 3:
+ first_octet |= 0x80; // CONTEXT-SPECIFIC
+ break;
+ case 4:
+ first_octet |= 0xC0; // PRIVATE
+ break;
+ default:
+ this.error = "Unknown tag class";
+ return (new ArrayBuffer(0));
+ }
+
+ if(this.is_constructed)
+ first_octet |= 0x20;
+
+ if((this.tag_number < 31) && (!this.is_hex_only))
+ {
+ var ret_buf = new ArrayBuffer(1);
+ var ret_view = new Uint8Array(ret_buf);
+
+ if(!size_only)
+ {
+ var number = this.tag_number;
+ number &= 0x1F;
+ first_octet |= number;
+
+ ret_view[0] = first_octet;
+ }
+
+ return ret_buf;
+ }
+ else
+ {
+ if(this.is_hex_only === false)
+ {
+ var encoded_buf = util_tobase(this.tag_number, 7);
+ var encoded_view = new Uint8Array(encoded_buf);
+ var size = encoded_buf.byteLength;
+
+ var ret_buf = new ArrayBuffer(size + 1);
+ var ret_view = new Uint8Array(ret_buf);
+
+ ret_view[0] = (first_octet | 0x1F);
+
+ if(!size_only)
+ {
+ for(var i = 0; i < (size - 1) ; i++)
+ ret_view[i + 1] = encoded_view[i] | 0x80;
+
+ ret_view[size] = encoded_view[size - 1];
+ }
+
+ return ret_buf;
+ }
+ else
+ {
+ var ret_buf = new ArrayBuffer(this.value_hex.byteLength + 1);
+ var ret_view = new Uint8Array(ret_buf);
+
+ ret_view[0] = (first_octet | 0x1F);
+
+ if(size_only === false)
+ {
+ var cur_view = new Uint8Array(this.value_hex);
+
+ for(var i = 0; i < (cur_view.length - 1); i++)
+ ret_view[i + 1] = cur_view[i] | 0x80;
+
+ ret_view[this.value_hex.byteLength] = cur_view[cur_view.length - 1];
+ }
+
+ return ret_buf;
+ }
+ }
+ };
+ //**************************************************************************************
+ local.identification_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ // #region Getting Uint8Array from ArrayBuffer
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+ // #endregion
+
+ // #region Initial checks
+ if(int_buffer.length == 0)
+ {
+ this.error = "Zero buffer length";
+ return (-1);
+ }
+ // #endregion
+
+ // #region Find tag class
+ var tag_class_mask = int_buffer[0] & 0xC0;
+
+ switch(tag_class_mask)
+ {
+ case 0x00:
+ this.tag_class = (1); // UNIVERSAL
+ break;
+ case 0x40:
+ this.tag_class = (2); // APPLICATION
+ break;
+ case 0x80:
+ this.tag_class = (3); // CONTEXT-SPECIFIC
+ break;
+ case 0xC0:
+ this.tag_class = (4); // PRIVATE
+ break;
+ default:
+ this.error = "Unknown tag class";
+ return ( -1 );
+ }
+ // #endregion
+
+ // #region Find it's constructed or not
+ this.is_constructed = (int_buffer[0] & 0x20) == 0x20;
+ // #endregion
+
+ // #region Find tag number
+ this.is_hex_only = false;
+
+ var tag_number_mask = int_buffer[0] & 0x1F;
+
+ // #region Simple case (tag number < 31)
+ if(tag_number_mask != 0x1F)
+ {
+ this.tag_number = (tag_number_mask);
+ this.block_length = 1;
+ }
+ // #endregion
+ // #region Tag number bigger or equal to 31
+ else
+ {
+ var count = 1;
+
+ this.value_hex = new ArrayBuffer(255);
+ var tag_number_buffer_max_length = 255;
+ var int_tag_number_buffer = new Uint8Array(this.value_hex);
+
+ while(int_buffer[count] & 0x80)
+ {
+ int_tag_number_buffer[count - 1] = int_buffer[count] & 0x7F;
+ count++;
+
+ if(count >= int_buffer.length)
+ {
+ this.error = "End of input reached before message was fully decoded";
+ return (-1);
+ }
+
+ // #region In case if tag number length is greater than 255 bytes (rare but possible case)
+ if(count == tag_number_buffer_max_length)
+ {
+ tag_number_buffer_max_length += 255;
+
+ var temp_buffer = new ArrayBuffer(tag_number_buffer_max_length);
+ var temp_buffer_view = new Uint8Array(temp_buffer);
+
+ for(var i = 0; i < int_tag_number_buffer.length; i++)
+ temp_buffer_view[i] = int_tag_number_buffer[i];
+
+ this.value_hex = new ArrayBuffer(tag_number_buffer_max_length);
+ int_tag_number_buffer = new Uint8Array(this.value_hex);
+ }
+ // #endregion
+ }
+
+ this.block_length = (count + 1);
+ int_tag_number_buffer[count - 1] = int_buffer[count] & 0x7F; // Write last byte to buffer
+
+ // #region Cut buffer
+ var temp_buffer = new ArrayBuffer(count);
+ var temp_buffer_view = new Uint8Array(temp_buffer);
+ for(var i = 0; i < count; i++)
+ temp_buffer_view[i] = int_tag_number_buffer[i];
+
+ this.value_hex = new ArrayBuffer(count);
+ int_tag_number_buffer = new Uint8Array(this.value_hex);
+ int_tag_number_buffer.set(temp_buffer_view);
+ // #endregion
+
+ // #region Try to convert long tag number to short form
+ if(this.block_length <= 9)
+ this.tag_number = util_frombase(int_tag_number_buffer, 7);
+ else
+ {
+ this.is_hex_only = true;
+ this.warnings.push("Tag too long, represented as hex-coded");
+ }
+ // #endregion
+ }
+ // #endregion
+ // #endregion
+
+ // #region Check if constructed encoding was using for primitive type
+ if(((this.tag_class == 1)) &&
+ (this.is_constructed))
+ {
+ switch(this.tag_number)
+ {
+ case 1: // BOOLEAN
+ case 2: // REAL
+ case 5: // NULL
+ case 6: // OBJECT IDENTIFIER
+ case 9: // REAL
+ case 14: // TIME
+ case 23:
+ case 24:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ this.error = "Constructed encoding used for primitive type";
+ return (-1);
+ default:
+ ;
+ }
+ }
+ // #endregion
+
+ return ( input_offset + this.block_length ); // Return current offset in input buffer
+ };
+ //**************************************************************************************
+ local.identification_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.hex_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.identification_block.prototype.block_name.call(this);
+ _object.tag_class = this.tag_class;
+ _object.tag_number = this.tag_number;
+ _object.is_constructed = this.is_constructed;
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of length block class
+ //**************************************************************************************
+ local.length_block =
+ function()
+ {
+ /// Base class of ASN.1 "length block"
+
+ local.base_block.call(this, arguments[0]);
+
+ this.is_indefinite_form = false;
+ this.long_form_used = false;
+ this.length = (0);
+
+ if(arguments[0] instanceof Object)
+ {
+ if("len_block" in arguments[0])
+ {
+ this.is_indefinite_form = in_window.org.pkijs.getValue(arguments[0].len_block, "is_indefinite_form", false);
+ this.long_form_used = in_window.org.pkijs.getValue(arguments[0].len_block, "long_form_used", false);
+ this.length = in_window.org.pkijs.getValue(arguments[0].len_block, "length", 0);
+ }
+ }
+ };
+ //**************************************************************************************
+ local.length_block.prototype = new local.base_block();
+ local.length_block.constructor = local.length_block;
+ //**************************************************************************************
+ local.length_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "length_block";
+ };
+ //**************************************************************************************
+ local.length_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ // #region Getting Uint8Array from ArrayBuffer
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+ // #endregion
+
+ // #region Initial checks
+ if(int_buffer.length == 0)
+ {
+ this.error = "Zero buffer length";
+ return (-1);
+ }
+
+ if(int_buffer[0] == 0xFF)
+ {
+ this.error = "Length block 0xFF is reserved by standard";
+ return (-1);
+ }
+ // #endregion
+
+ // #region Check for length form type
+ this.is_indefinite_form = int_buffer[0] == 0x80;
+ // #endregion
+
+ // #region Stop working in case of indefinite length form
+ if(this.is_indefinite_form == true)
+ {
+ this.block_length = 1;
+ return (input_offset + this.block_length);
+ }
+ // #endregion
+
+ // #region Check is long form of length encoding using
+ this.long_form_used = !!(int_buffer[0] & 0x80);
+ // #endregion
+
+ // #region Stop working in case of short form of length value
+ if(this.long_form_used == false)
+ {
+ this.length = (int_buffer[0]);
+ this.block_length = 1;
+ return (input_offset + this.block_length);
+ }
+ // #endregion
+
+ // #region Calculate length value in case of long form
+ var count = int_buffer[0] & 0x7F;
+
+ if(count > 8) // Too big length value
+ {
+ this.error = "Too big integer";
+ return (-1);
+ }
+
+ if((count + 1) > int_buffer.length)
+ {
+ this.error = "End of input reached before message was fully decoded";
+ return (-1);
+ }
+
+ var length_buffer_view = new Uint8Array(count);
+
+ for(var i = 0; i < count; i++)
+ length_buffer_view[i] = int_buffer[i + 1];
+
+ if(length_buffer_view[count - 1] == 0x00)
+ this.warnings.push("Needlessly long encoded length");
+
+ this.length = util_frombase(length_buffer_view, 8);
+
+ if(this.long_form_used && (this.length <= 127))
+ this.warnings.push("Unneccesary usage of long length form");
+
+ this.block_length = count + 1;
+ // #endregion
+
+ return (input_offset + this.block_length); // Return current offset in input buffer
+ };
+ //**************************************************************************************
+ local.length_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ if(this.length > 127)
+ this.long_form_used = true;
+
+ if(this.is_indefinite_form)
+ {
+ var ret_buf = new ArrayBuffer(1);
+
+ if(size_only === false)
+ {
+ var ret_view = new Uint8Array(ret_buf);
+ ret_view[0] = 0x80;
+ }
+
+ return ret_buf;
+ }
+
+ if(this.long_form_used === true)
+ {
+ var encoded_buf = util_tobase(this.length, 8);
+
+ if(encoded_buf.byteLength > 127)
+ {
+ this.error = "Too big length";
+ return (new ArrayBuffer(0));
+ }
+
+ var ret_buf = new ArrayBuffer(encoded_buf.byteLength + 1);
+
+ if(size_only === true)
+ return ret_buf;
+
+ var encoded_view = new Uint8Array(encoded_buf);
+ var ret_view = new Uint8Array(ret_buf);
+
+ ret_view[0] = encoded_buf.byteLength | 0x80;
+
+ for(var i = 0; i < encoded_buf.byteLength; i++)
+ ret_view[i + 1] = encoded_view[i];
+
+ return ret_buf;
+ }
+ else
+ {
+ var ret_buf = new ArrayBuffer(1);
+
+ if(size_only === false)
+ {
+ var ret_view = new Uint8Array(ret_buf);
+
+ ret_view[0] = this.length;
+ }
+
+ return ret_buf;
+ }
+
+ return (new ArrayBuffer(0));
+ };
+ //**************************************************************************************
+ local.length_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.base_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.length_block.prototype.block_name.call(this);
+ _object.is_indefinite_form = this.is_indefinite_form;
+ _object.long_form_used = this.long_form_used;
+ _object.length = this.length;
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of value block class
+ //**************************************************************************************
+ local.value_block =
+ function()
+ {
+ /// Generic class of ASN.1 "value block"
+ local.base_block.call(this, arguments[0]);
+ };
+ //**************************************************************************************
+ local.value_block.prototype = new local.base_block();
+ local.value_block.constructor = local.value_block;
+ //**************************************************************************************
+ local.value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "value_block";
+ };
+ //**************************************************************************************
+ local.value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.base_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.value_block.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of basic ASN.1 block class
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_block =
+ function()
+ {
+ /// Base class of ASN.1 block (identification block + length block + value block)
+
+ local.base_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.name = in_window.org.pkijs.getValue(arguments[0], "name", "");
+ this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false);
+
+ if("primitive_schema" in arguments[0])
+ this.primitive_schema = arguments[0].primitive_schema;
+ }
+
+ this.id_block = new local.identification_block(arguments[0]);
+ this.len_block = new local.length_block(arguments[0]);
+ this.value_block = new local.value_block(arguments[0]);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_block.prototype = new local.base_block();
+ in_window.org.pkijs.asn1.ASN1_block.constructor = in_window.org.pkijs.asn1.ASN1_block;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "ASN1_block";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ var ret_buf;
+
+ var id_block_buf = this.id_block.toBER(size_only);
+ var value_block_size_buf = this.value_block.toBER(true);
+
+ this.len_block.length = value_block_size_buf.byteLength;
+ var len_block_buf = this.len_block.toBER(size_only);
+
+ ret_buf = util_concatbuf(id_block_buf, len_block_buf);
+
+ var value_block_buf;
+
+ if(size_only === false)
+ value_block_buf = this.value_block.toBER(size_only);
+ else
+ value_block_buf = new ArrayBuffer(this.len_block.length);
+
+ ret_buf = util_concatbuf(ret_buf, value_block_buf);
+
+ if(this.len_block.is_indefinite_form === true)
+ {
+ var indef_buf = new ArrayBuffer(2);
+
+ if(size_only === false)
+ {
+ var indef_view = new Uint8Array(indef_buf);
+
+ indef_view[0] = 0x00;
+ indef_view[1] = 0x00;
+ }
+
+ ret_buf = util_concatbuf(ret_buf, indef_buf);
+ }
+
+ return ret_buf;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.base_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.ASN1_block.prototype.block_name.call(this);
+ _object.id_block = this.id_block.toJSON();
+ _object.len_block = this.len_block.toJSON();
+ _object.value_block = this.value_block.toJSON();
+
+ if("name" in this)
+ _object.name = this.name;
+ if("optional" in this)
+ _object.optional = this.optional;
+ if("primitive_schema" in this)
+ _object.primitive_schema = this.primitive_schema.toJSON();
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of basic block for all PRIMITIVE types
+ //**************************************************************************************
+ local.ASN1_PRIMITIVE_value_block =
+ function()
+ {
+ /// Base class of ASN.1 value block for primitive values (non-constructive encoding)
+
+ local.value_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ // #region Variables from "hex_block" class
+ if("value_hex" in arguments[0])
+ this.value_hex = util_copybuf(arguments[0].value_hex);
+ else
+ this.value_hex = new ArrayBuffer(0);
+
+ this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", true);
+ // #endregion
+ }
+ else
+ {
+ // #region Variables from "hex_block" class
+ this.value_hex = new ArrayBuffer(0);
+ this.is_hex_only = true;
+ // #endregion
+ }
+ };
+ //**************************************************************************************
+ local.ASN1_PRIMITIVE_value_block.prototype = new local.value_block();
+ local.ASN1_PRIMITIVE_value_block.constructor = local.ASN1_PRIMITIVE_value_block;
+ //**************************************************************************************
+ local.ASN1_PRIMITIVE_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ // #region Getting Uint8Array from ArrayBuffer
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+ // #endregion
+
+ // #region Initial checks
+ if(int_buffer.length == 0)
+ {
+ this.warnings.push("Zero buffer length");
+ return input_offset;
+ }
+ // #endregion
+
+ // #region Copy input buffer into internal buffer
+ this.value_hex = new ArrayBuffer(int_buffer.length);
+ var value_hex_view = new Uint8Array(this.value_hex);
+
+ for(var i = 0; i < int_buffer.length; i++)
+ value_hex_view[i] = int_buffer[i];
+ // #endregion
+
+ this.block_length = input_length;
+
+ return (input_offset + input_length);
+ };
+ //**************************************************************************************
+ local.ASN1_PRIMITIVE_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ return util_copybuf(this.value_hex);
+ };
+ //**************************************************************************************
+ local.ASN1_PRIMITIVE_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "ASN1_PRIMITIVE_value_block";
+ };
+ //**************************************************************************************
+ local.ASN1_PRIMITIVE_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.ASN1_PRIMITIVE_value_block.prototype.block_name.call(this);
+ _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength);
+ _object.is_hex_only = this.is_hex_only;
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_PRIMITIVE =
+ function()
+ {
+ /// Base class of ASN.1 block for primitive values (non-constructive encoding)
+
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.id_block.is_constructed = false;
+ this.value_block = new local.ASN1_PRIMITIVE_value_block(arguments[0]);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.ASN1_PRIMITIVE.constructor = in_window.org.pkijs.asn1.ASN1_PRIMITIVE;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "PRIMITIVE";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.ASN1_PRIMITIVE.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of basic block for all CONSTRUCTED types
+ //**************************************************************************************
+ local.ASN1_CONSTRUCTED_value_block =
+ function()
+ {
+ /// Base class of ASN.1 value block for constructive values (constructive encoding)
+
+ local.value_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.value = in_window.org.pkijs.getValue(arguments[0], "value", new Array());
+ this.is_indefinite_form = in_window.org.pkijs.getValue(arguments[0], "is_indefinite_form", false);
+ }
+ else
+ {
+ this.value = new Array();
+ this.is_indefinite_form = false;
+ }
+ };
+ //**************************************************************************************
+ local.ASN1_CONSTRUCTED_value_block.prototype = new local.value_block();
+ local.ASN1_CONSTRUCTED_value_block.constructor = local.ASN1_CONSTRUCTED_value_block;
+ //**************************************************************************************
+ local.ASN1_CONSTRUCTED_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Store initial offset and length
+ var initial_offset = input_offset;
+ var initial_length = input_length;
+ // #endregion
+
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ // #region Getting Uint8Array from ArrayBuffer
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+ // #endregion
+
+ // #region Initial checks
+ if(int_buffer.length == 0)
+ {
+ this.warnings.push("Zero buffer length");
+ return input_offset;
+ }
+ // #endregion
+
+ // #region Aux function
+ function check_len(_indefinite_length, _length)
+ {
+ if(_indefinite_length == true)
+ return 1;
+
+ return _length;
+ }
+ // #endregion
+
+ var current_offset = input_offset;
+
+ while(check_len(this.is_indefinite_form, input_length) > 0)
+ {
+ var return_object = fromBER_raw(input_buffer, current_offset, input_length);
+ if(return_object.offset == (-1))
+ {
+ this.error = return_object.result.error;
+ this.warnings.concat(return_object.result.warnings);
+ return (-1);
+ }
+
+ current_offset = return_object.offset;
+
+ this.block_length += return_object.result.block_length;
+ input_length -= return_object.result.block_length;
+
+ this.value.push(return_object.result);
+
+ if((this.is_indefinite_form == true) && (return_object.result.block_name() == in_window.org.pkijs.asn1.EOC.prototype.block_name()))
+ break;
+ }
+
+ if(this.is_indefinite_form == true)
+ {
+ if(this.value[this.value.length - 1].block_name() == in_window.org.pkijs.asn1.EOC.prototype.block_name())
+ this.value.pop();
+ else
+ this.warnings.push("No EOC block encoded");
+ }
+
+ // #region Copy "input_buffer" to "value_before_decode"
+ this.value_before_decode = util_copybuf_offset(input_buffer, initial_offset, initial_length);
+ // #endregion
+
+ return current_offset;
+ };
+ //**************************************************************************************
+ local.ASN1_CONSTRUCTED_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ var ret_buf = new ArrayBuffer(0);
+
+ for(var i = 0; i < this.value.length; i++)
+ {
+ var value_buf = this.value[i].toBER(size_only);
+ ret_buf = util_concatbuf(ret_buf, value_buf);
+ }
+
+ return ret_buf;
+ };
+ //**************************************************************************************
+ local.ASN1_CONSTRUCTED_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "ASN1_CONSTRUCTED_value_block";
+ };
+ //**************************************************************************************
+ local.ASN1_CONSTRUCTED_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.ASN1_CONSTRUCTED_value_block.prototype.block_name.call(this);
+ _object.is_indefinite_form = this.is_indefinite_form;
+ _object.value = new Array();
+ for(var i = 0; i < this.value.length; i++)
+ _object.value.push(this.value[i].toJSON());
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED =
+ function()
+ {
+ /// Base class of ASN.1 block for constructive values (constructive encoding)
+
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.id_block.is_constructed = true;
+ this.value_block = new local.ASN1_CONSTRUCTED_value_block(arguments[0]);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.constructor = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "CONSTRUCTED";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ this.value_block.is_indefinite_form = this.len_block.is_indefinite_form;
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 EOC type class
+ //**************************************************************************************
+ local.EOC_value_block =
+ function()
+ {
+ local.value_block.call(this, arguments[0]);
+ };
+ //**************************************************************************************
+ local.EOC_value_block.prototype = new local.value_block();
+ local.EOC_value_block.constructor = local.EOC_value_block;
+ //**************************************************************************************
+ local.EOC_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region There is no "value block" for EOC type and we need to return the same offset
+ return input_offset;
+ // #endregion
+ };
+ //**************************************************************************************
+ local.EOC_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ return (new ArrayBuffer(0));
+ };
+ //**************************************************************************************
+ local.EOC_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "EOC_value_block";
+ };
+ //**************************************************************************************
+ local.EOC_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.EOC_value_block.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.EOC =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.EOC_value_block();
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 0; // EOC
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.EOC.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.EOC.constructor = local.EOC_value_block;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.EOC.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "END_OF_CONTENT";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.EOC.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.EOC.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 BOOLEAN type class
+ //**************************************************************************************
+ local.BOOLEAN_value_block =
+ function()
+ {
+ local.value_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.value = in_window.org.pkijs.getValue(arguments[0], "value", false);
+
+ // #region Variables from hex_block class
+ this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false);
+ if("value_hex" in arguments[0])
+ this.value_hex = util_copybuf(arguments[0].value_hex);
+ else
+ {
+ this.value_hex = new ArrayBuffer(1);
+ if(this.value === true)
+ {
+ var view = new Uint8Array(this.value_hex);
+ view[0] = 0xFF;
+ }
+ }
+ // #endregion
+ }
+ else
+ {
+ this.value = false;
+
+ // #region Variables from hex_block class
+ this.is_hex_only = false;
+ this.value_hex = new ArrayBuffer(1);
+ // #endregion
+ }
+ };
+ //**************************************************************************************
+ local.BOOLEAN_value_block.prototype = new local.value_block();
+ local.BOOLEAN_value_block.constructor = local.BOOLEAN_value_block;
+ //**************************************************************************************
+ local.BOOLEAN_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ // #region Getting Uint8Array from ArrayBuffer
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+ // #endregion
+
+ if(input_length > 1)
+ this.warnings.push("BOOLEAN value encoded in more then 1 octet");
+
+ this.value = int_buffer[0] != 0x00;
+
+ this.is_hex_only = true;
+
+ // #region Copy input buffer to internal array
+ this.value_hex = new ArrayBuffer(int_buffer.length);
+ var view = new Uint8Array(this.value_hex);
+
+ for(var i = 0; i < int_buffer.length; i++)
+ view[i] = int_buffer[i];
+ // #endregion
+
+ this.block_length = input_length;
+
+ return (input_offset + input_length);
+ };
+ //**************************************************************************************
+ local.BOOLEAN_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ return this.value_hex;
+ };
+ //**************************************************************************************
+ local.BOOLEAN_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "BOOLEAN_value_block";
+ };
+ //**************************************************************************************
+ local.BOOLEAN_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.BOOLEAN_value_block.prototype.block_name.call(this);
+ _object.value = this.value;
+ _object.is_hex_only = this.is_hex_only;
+ _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BOOLEAN =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.BOOLEAN_value_block(arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 1; // BOOLEAN
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BOOLEAN.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.BOOLEAN.constructor = local.BOOLEAN_value_block;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BOOLEAN.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "BOOLEAN";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BOOLEAN.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.BOOLEAN.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 SEQUENCE and SET type classes
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SEQUENCE =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 16; // SEQUENCE
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SEQUENCE.prototype = new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED();
+ in_window.org.pkijs.asn1.SEQUENCE.constructor = in_window.org.pkijs.asn1.SEQUENCE;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SEQUENCE.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "SEQUENCE";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SEQUENCE.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.SEQUENCE.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SET =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 17; // SET
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SET.prototype = new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED();
+ in_window.org.pkijs.asn1.SET.constructor = in_window.org.pkijs.asn1.SET;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SET.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "SET";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.SET.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.SET.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 NULL type class
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NULL =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 5; // NULL
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NULL.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.NULL.constructor = in_window.org.pkijs.asn1.NULL;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NULL.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "NULL";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NULL.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ if(this.len_block.length > 0)
+ this.warnings.push("Non-zero length of value block for NULL type");
+
+ if(this.id_block.error.length === 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length === 0)
+ this.block_length += this.len_block.block_length;
+
+ this.block_length += input_length;
+
+ return (input_offset + input_length);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NULL.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ var ret_buf = new ArrayBuffer(2);
+
+ if(size_only === true)
+ return ret_buf;
+
+ var ret_view = new Uint8Array(ret_buf);
+ ret_view[0] = 0x05;
+ ret_view[1] = 0x00;
+
+ return ret_buf;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NULL.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.NULL.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 OCTETSTRING type class
+ //**************************************************************************************
+ local.OCTETSTRING_value_block =
+ function()
+ {
+ ///
+ ///
+ ///
+ /// Value for the OCTETSTRING may be as hex, as well as a constructed value.
+ /// Constructed values consists of other OCTETSTRINGs
+
+ local.ASN1_CONSTRUCTED_value_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.is_constructed = in_window.org.pkijs.getValue(arguments[0], "is_constructed", false);
+
+ // #region Variables from hex_block type
+ this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false);
+ if("value_hex" in arguments[0])
+ this.value_hex = util_copybuf(arguments[0].value_hex);
+ else
+ this.value_hex = new ArrayBuffer(0);
+ // #endregion
+ }
+ else
+ {
+ this.is_constructed = false;
+
+ // #region Variables from hex_block type
+ this.is_hex_only = false;
+ this.value_hex = new ArrayBuffer(0);
+ // #endregion
+ }
+ };
+ //**************************************************************************************
+ local.OCTETSTRING_value_block.prototype = new local.ASN1_CONSTRUCTED_value_block();
+ local.OCTETSTRING_value_block.constructor = local.OCTETSTRING_value_block;
+ //**************************************************************************************
+ local.OCTETSTRING_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = 0;
+
+ if(this.is_constructed == true)
+ {
+ this.is_hex_only = false;
+
+ result_offset = local.ASN1_CONSTRUCTED_value_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length);
+ if(result_offset == (-1))
+ return result_offset;
+
+ for(var i = 0; i < this.value.length; i++)
+ {
+ var current_block_name = this.value[i].block_name();
+
+ if(current_block_name == in_window.org.pkijs.asn1.EOC.prototype.block_name())
+ {
+ if(this.is_indefinite_form == true)
+ break;
+ else
+ {
+ this.error = "EOC is unexpected, OCTET STRING may consists of OCTET STRINGs only";
+ return (-1);
+ }
+ }
+
+ if(current_block_name != in_window.org.pkijs.asn1.OCTETSTRING.prototype.block_name())
+ {
+ this.error = "OCTET STRING may consists of OCTET STRINGs only";
+ return (-1);
+ }
+ }
+ }
+ else
+ {
+ this.is_hex_only = true;
+
+ result_offset = local.hex_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length);
+ this.block_length = input_length;
+ }
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ local.OCTETSTRING_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ if(this.is_constructed === true)
+ return local.ASN1_CONSTRUCTED_value_block.prototype.toBER.call(this, size_only);
+ else
+ {
+ var ret_buf = new ArrayBuffer(this.value_hex.byteLength);
+
+ if(size_only === true)
+ return ret_buf;
+
+ if(this.value_hex.byteLength == 0)
+ return ret_buf;
+
+ ret_buf = util_copybuf(this.value_hex);
+
+ return ret_buf;
+ }
+
+ return (new ArrayBuffer(0));
+ };
+ //**************************************************************************************
+ local.OCTETSTRING_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "OCTETSTRING_value_block";
+ };
+ //**************************************************************************************
+ local.OCTETSTRING_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.ASN1_CONSTRUCTED_value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.OCTETSTRING_value_block.prototype.block_name.call(this);
+ _object.is_constructed = this.is_constructed;
+ _object.is_hex_only = this.is_hex_only;
+ _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OCTETSTRING =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.OCTETSTRING_value_block(arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 4; // OCTETSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OCTETSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.OCTETSTRING.constructor = in_window.org.pkijs.asn1.OCTETSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OCTETSTRING.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ this.value_block.is_constructed = this.id_block.is_constructed;
+ this.value_block.is_indefinite_form = this.len_block.is_indefinite_form;
+
+ // #region Ability to encode empty OCTET STRING
+ if(input_length == 0)
+ {
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ return input_offset;
+ }
+ // #endregion
+
+ return in_window.org.pkijs.asn1.ASN1_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OCTETSTRING.prototype.block_name =
+ function()
+ {
+ return "OCTETSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OCTETSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.OCTETSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OCTETSTRING.prototype.isEqual =
+ function(octetString)
+ {
+ ///
+ /// The OCTETSTRING to compare with
+
+ // #region Check input type
+ if((octetString instanceof in_window.org.pkijs.asn1.OCTETSTRING) == false)
+ return false;
+ // #endregion
+
+ // #region Compare two JSON strings
+ if(JSON.stringify(this) != JSON.stringify(octetString))
+ return false;
+ // #endregion
+
+ return true;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 BITSTRING type class
+ //**************************************************************************************
+ local.BITSTRING_value_block =
+ function()
+ {
+ local.ASN1_CONSTRUCTED_value_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.unused_bits = in_window.org.pkijs.getValue(arguments[0], "unused_bits", 0);
+ this.is_constructed = in_window.org.pkijs.getValue(arguments[0], "is_constructed", false);
+
+ // #region Variables from hex_block type
+ this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false);
+
+ if("value_hex" in arguments[0])
+ this.value_hex = util_copybuf(arguments[0].value_hex);
+ else
+ this.value_hex = new ArrayBuffer(0);
+
+ this.block_length = this.value_hex.byteLength;
+ // #endregion
+ }
+ else
+ {
+ this.unused_bits = 0;
+ this.is_constructed = false;
+
+ // #region Variables from hex_block type
+ this.is_hex_only = false;
+ this.value_hex = new ArrayBuffer(0);
+ // #endregion
+ }
+ };
+ //**************************************************************************************
+ local.BITSTRING_value_block.prototype = new local.ASN1_CONSTRUCTED_value_block();
+ local.BITSTRING_value_block.constructor = local.BITSTRING_value_block;
+ //**************************************************************************************
+ local.BITSTRING_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Ability to decode zero-length BITSTRING value
+ if(input_length == 0)
+ return input_offset;
+ // #endregion
+
+ var result_offset = (-1);
+
+ // #region If the BISTRING supposed to be a constructed value
+ if(this.is_constructed == true)
+ {
+ result_offset = local.ASN1_CONSTRUCTED_value_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length);
+ if(result_offset == (-1))
+ return result_offset;
+
+ for(var i = 0; i < this.value.length; i++)
+ {
+ var current_block_name = this.value[i].block_name();
+
+ if(current_block_name == in_window.org.pkijs.asn1.EOC.prototype.block_name())
+ {
+ if(this.is_indefinite_form == true)
+ break;
+ else
+ {
+ this.error = "EOC is unexpected, BIT STRING may consists of BIT STRINGs only";
+ return (-1);
+ }
+ }
+
+ if(current_block_name != in_window.org.pkijs.asn1.BITSTRING.prototype.block_name())
+ {
+ this.error = "BIT STRING may consists of BIT STRINGs only";
+ return (-1);
+ }
+
+ if((this.unused_bits > 0) && (this.value[i].unused_bits > 0))
+ {
+ this.error = "Usign of \"unused bits\" inside constructive BIT STRING allowed for least one only";
+ return (-1);
+ }
+ else
+ {
+ this.unused_bits = this.value[i].unused_bits;
+ if(this.unused_bits > 7)
+ {
+ this.error = "Unused bits for BITSTRING must be in range 0-7";
+ return (-1);
+ }
+ }
+ }
+
+ return result_offset;
+ }
+ // #endregion
+ // #region If the BITSTRING supposed to be a primitive value
+ else
+ {
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+
+ this.unused_bits = int_buffer[0];
+ if(this.unused_bits > 7)
+ {
+ this.error = "Unused bits for BITSTRING must be in range 0-7";
+ return (-1);
+ }
+
+ // #region Copy input buffer to internal buffer
+ this.value_hex = new ArrayBuffer(int_buffer.length - 1);
+ var view = new Uint8Array(this.value_hex);
+ for(var i = 0; i < (input_length - 1) ; i++)
+ view[i] = int_buffer[i + 1];
+ // #endregion
+
+ this.block_length = int_buffer.length;
+
+ return (input_offset + input_length);
+ }
+ // #endregion
+ };
+ //**************************************************************************************
+ local.BITSTRING_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ if(this.is_constructed === true)
+ return local.ASN1_CONSTRUCTED_value_block.prototype.toBER.call(this, size_only);
+ else
+ {
+ if(size_only === true)
+ return (new ArrayBuffer(this.value_hex.byteLength + 1));
+
+ if(this.value_hex.byteLength == 0)
+ return (new ArrayBuffer(0));
+
+ var cur_view = new Uint8Array(this.value_hex);
+
+ var ret_buf = new ArrayBuffer(this.value_hex.byteLength + 1);
+ var ret_view = new Uint8Array(ret_buf);
+
+ ret_view[0] = this.unused_bits;
+
+ for(var i = 0; i < this.value_hex.byteLength; i++)
+ ret_view[i + 1] = cur_view[i];
+
+ return ret_buf;
+ }
+
+ return (new ArrayBuffer(0));
+ };
+ //**************************************************************************************
+ local.BITSTRING_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "BITSTRING_value_block";
+ };
+ //**************************************************************************************
+ local.BITSTRING_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.ASN1_CONSTRUCTED_value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.BITSTRING_value_block.prototype.block_name.call(this);
+ _object.unused_bits = this.unused_bits;
+ _object.is_constructed = this.is_constructed;
+ _object.is_hex_only = this.is_hex_only;
+ _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BITSTRING =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.BITSTRING_value_block(arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 3; // BITSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BITSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.BITSTRING.constructor = in_window.org.pkijs.asn1.BITSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BITSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "BITSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BITSTRING.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ // #region Ability to encode empty BITSTRING
+ if(input_length == 0)
+ return input_offset;
+ // #endregion
+
+ this.value_block.is_constructed = this.id_block.is_constructed;
+ this.value_block.is_indefinite_form = this.len_block.is_indefinite_form;
+
+ return in_window.org.pkijs.asn1.ASN1_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BITSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.BITSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 INTEGER type class
+ //**************************************************************************************
+ local.INTEGER_value_block =
+ function()
+ {
+ local.value_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.value_dec = in_window.org.pkijs.getValue(arguments[0], "value", 0);
+
+ // #region Variables from hex_block type
+ this.is_hex_only = in_window.org.pkijs.getValue(arguments[0], "is_hex_only", false);
+ if("value_hex" in arguments[0])
+ {
+ this.value_hex = util_copybuf(arguments[0].value_hex);
+
+ if(this.value_hex.byteLength >= 4) // Dummy's protection
+ this.is_hex_only = true;
+ else
+ this.value_dec = util_decode_tc.call(this);
+ }
+ else
+ this.value_hex = util_encode_tc(this.value_dec);
+ // #endregion
+ }
+ else
+ {
+ this.value_dec = 0;
+
+ // #region Variables from hex_block type
+ this.is_hex_only = false;
+ this.value_hex = new ArrayBuffer(0);
+ // #endregion
+ }
+ };
+ //**************************************************************************************
+ local.INTEGER_value_block.prototype = new local.value_block();
+ local.INTEGER_value_block.constructor = local.INTEGER_value_block;
+ //**************************************************************************************
+ local.INTEGER_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = local.hex_block.prototype.fromBER.call(this, input_buffer, input_offset, input_length);
+ if(result_offset == (-1))
+ return result_offset;
+
+ if(this.value_hex.byteLength > 4) // In JavaScript we can effectively work with 32-bit integers only
+ {
+ this.warnings.push("Too big INTEGER for decoding, hex only");
+ this.is_hex_only = true;
+ }
+ else
+ this.value_dec = util_decode_tc.call(this);
+
+ this.block_length = input_length;
+
+ return (input_offset + input_length);
+ };
+ //**************************************************************************************
+ local.INTEGER_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ if(this.is_hex_only === false)
+ {
+ var encoded_buf = util_encode_tc(this.value_dec);
+ if(encoded_buf.byteLength == 0)
+ {
+ this.error = "Error during encoding INTEGER value";
+ return (new ArrayBuffer(0));
+ }
+
+ return util_copybuf(encoded_buf);
+ }
+ else
+ return util_copybuf(this.value_hex);
+
+ return (new ArrayBuffer(0));
+ };
+ //**************************************************************************************
+ local.INTEGER_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "INTEGER_value_block";
+ };
+ //**************************************************************************************
+ local.INTEGER_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.INTEGER_value_block.prototype.block_name.call(this);
+ _object.value_dec = this.value_dec;
+ _object.is_hex_only = this.is_hex_only;
+ _object.value_hex = in_window.org.pkijs.bufferToHexCodes(this.value_hex, 0, this.value_hex.byteLength);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.INTEGER =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.INTEGER_value_block(arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 2; // INTEGER
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.INTEGER.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.INTEGER.constructor = in_window.org.pkijs.asn1.INTEGER;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.INTEGER.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "INTEGER";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.INTEGER.prototype.isEqual =
+ function()
+ {
+ /// Compare two INTEGER object, or INTEGER and ArrayBuffer objects
+ ///
+
+ if(arguments[0] instanceof in_window.org.pkijs.asn1.INTEGER)
+ {
+ if(this.value_block.is_hex_only && arguments[0].value_block.is_hex_only) // Compare two ArrayBuffers
+ return in_window.org.pkijs.isEqual_buffer(this.value_block.value_hex, arguments[0].value_block.value_hex);
+ else
+ {
+ if(this.value_block.is_hex_only === arguments[0].value_block.is_hex_only)
+ return (this.value_block.value_dec == arguments[0].value_block.value_dec);
+ else
+ return false;
+ }
+ }
+ else
+ {
+ if(arguments[0] instanceof ArrayBuffer)
+ return in_window.org.pkijs.isEqual_buffer(this.value_block.value_hex, arguments[0]);
+ else
+ return false;
+ }
+
+ return false;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.INTEGER.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.INTEGER.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 ENUMERATED type class
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ENUMERATED =
+ function()
+ {
+ in_window.org.pkijs.asn1.INTEGER.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 10; // ENUMERATED
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ENUMERATED.prototype = new in_window.org.pkijs.asn1.INTEGER();
+ in_window.org.pkijs.asn1.ENUMERATED.constructor = in_window.org.pkijs.asn1.ENUMERATED;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ENUMERATED.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "ENUMERATED";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ENUMERATED.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.INTEGER.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.ENUMERATED.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of ASN.1 OBJECT IDENTIFIER type class
+ //**************************************************************************************
+ local.SID_value_block =
+ function()
+ {
+ local.hex_block.call(this, arguments[0]);
+
+ if(arguments[0] instanceof Object)
+ {
+ this.value_dec = in_window.org.pkijs.getValue(arguments[0], "value_dec", -1);
+ this.is_first_sid = in_window.org.pkijs.getValue(arguments[0], "is_first_sid", false);
+ }
+ else
+ {
+ this.value_dec = (-1);
+ this.is_first_sid = false;
+ }
+ };
+ //**************************************************************************************
+ local.SID_value_block.prototype = new local.hex_block();
+ local.SID_value_block.constructor = local.SID_value_block;
+ //**************************************************************************************
+ local.SID_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "sid_block";
+ };
+ //**************************************************************************************
+ local.SID_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ if(input_length == 0)
+ return input_offset;
+
+ // #region Basic check for parameters
+ if(check_buffer_params.call(this, input_buffer, input_offset, input_length) === false)
+ return (-1);
+ // #endregion
+
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+
+ this.value_hex = new ArrayBuffer(input_length);
+ var view = new Uint8Array(this.value_hex);
+
+ for(var i = 0; i < input_length; i++)
+ {
+ view[i] = int_buffer[i] & 0x7F;
+
+ this.block_length++;
+
+ if((int_buffer[i] & 0x80) == 0x00)
+ break;
+ }
+
+ // #region Ajust size of value_hex buffer
+ var temp_value_hex = new ArrayBuffer(this.block_length);
+ var temp_view = new Uint8Array(temp_value_hex);
+
+ for(var i = 0; i < this.block_length; i++)
+ temp_view[i] = view[i];
+
+ this.value_hex = util_copybuf(temp_value_hex);
+ view = new Uint8Array(this.value_hex);
+ // #endregion
+
+ if((int_buffer[this.block_length - 1] & 0x80) != 0x00)
+ {
+ this.error = "End of input reached before message was fully decoded";
+ return (-1);
+ }
+
+ if(view[0] == 0x00)
+ this.warnings.push("Needlessly long format of SID encoding");
+
+ if(this.block_length <= 8)
+ this.value_dec = util_frombase(view, 7);
+ else
+ {
+ this.is_hex_only = true;
+ this.warnings.push("Too big SID for decoding, hex only");
+ }
+
+ return (input_offset + this.block_length);
+ };
+ //**************************************************************************************
+ local.SID_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ if(this.is_hex_only)
+ {
+ if(size_only === true)
+ return (new ArrayBuffer(this.value_hex.byteLength));
+
+ var cur_view = new Uint8Array(this.value_hex);
+
+ var ret_buf = new ArrayBuffer(this.block_length);
+ var ret_view = new Uint8Array(ret_buf);
+
+ for(var i = 0; i < (this.block_length - 1) ; i++)
+ ret_view[i] = cur_view[i] | 0x80;
+
+ ret_view[this.block_length - 1] = cur_view[this.block_length - 1];
+
+ return ret_buf;
+ }
+ else
+ {
+ var encoded_buf = util_tobase(this.value_dec, 7);
+ if(encoded_buf.byteLength === 0)
+ {
+ this.error = "Error during encoding SID value";
+ return (new ArrayBuffer(0));
+ }
+
+ var ret_buf = new ArrayBuffer(encoded_buf.byteLength);
+
+ if(size_only === false)
+ {
+ var encoded_view = new Uint8Array(encoded_buf);
+ var ret_view = new Uint8Array(ret_buf);
+
+ for(var i = 0; i < (encoded_buf.byteLength - 1) ; i++)
+ ret_view[i] = encoded_view[i] | 0x80;
+
+ ret_view[encoded_buf.byteLength - 1] = encoded_view[encoded_buf.byteLength - 1];
+ }
+
+ return ret_buf;
+ }
+ };
+ //**************************************************************************************
+ local.SID_value_block.prototype.toString =
+ function()
+ {
+ var result = "";
+
+ if(this.is_hex_only === true)
+ result = to_hex_codes(this.value_hex);
+ else
+ {
+ if(this.is_first_sid)
+ {
+ var sid_value = this.value_dec;
+
+ if(this.value_dec <= 39)
+ result = "0.";
+ else
+ {
+ if(this.value_dec <= 79)
+ {
+ result = "1.";
+ sid_value -= 40;
+ }
+ else
+ {
+ result = "2.";
+ sid_value -= 80;
+ }
+ }
+
+ result = result + sid_value.toString();
+ }
+ else
+ result = this.value_dec.toString();
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ local.SID_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.hex_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.SID_value_block.prototype.block_name.call(this);
+ _object.value_dec = this.value_dec;
+ _object.is_first_sid = this.is_first_sid;
+
+ return _object;
+ };
+ //**************************************************************************************
+ local.OID_value_block =
+ function()
+ {
+ local.value_block.call(this, arguments[0]);
+
+ this.value = new Array();
+
+ if(arguments[0] instanceof Object)
+ this.fromString(in_window.org.pkijs.getValue(arguments[0], "value", ""));
+ };
+ //**************************************************************************************
+ local.OID_value_block.prototype = new local.value_block();
+ local.OID_value_block.constructor = local.OID_value_block;
+ //**************************************************************************************
+ local.OID_value_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = input_offset;
+
+ while(input_length > 0)
+ {
+ var sid_block = new local.SID_value_block();
+ result_offset = sid_block.fromBER(input_buffer, result_offset, input_length);
+ if(result_offset == (-1))
+ {
+ this.block_length = 0;
+ this.error = sid_block.error;
+ return result_offset;
+ }
+
+ if(this.value.length == 0)
+ sid_block.is_first_sid = true;
+
+ this.block_length += sid_block.block_length;
+ input_length -= sid_block.block_length;
+
+ this.value.push(sid_block);
+ }
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ local.OID_value_block.prototype.toBER =
+ function(size_only)
+ {
+ /// Encoding of current ASN.1 block into ASN.1 encoded array (BER rules)
+ /// Flag that we need only a size of encoding, not a real array of bytes
+
+ if(typeof size_only === "undefined")
+ size_only = false;
+
+ var ret_buf = new ArrayBuffer(0);
+
+ for(var i = 0; i < this.value.length; i++)
+ {
+ var value_buf = this.value[i].toBER(size_only);
+ if(value_buf.byteLength === 0)
+ {
+ this.error = this.value[i].error;
+ return (new ArrayBuffer(0));
+ }
+
+ ret_buf = util_concatbuf(ret_buf, value_buf);
+ }
+
+ return ret_buf;
+ };
+ //**************************************************************************************
+ local.OID_value_block.prototype.fromString =
+ function(str)
+ {
+ this.value = new Array(); // Clear existing SID values
+
+ var pos1 = 0;
+ var pos2 = 0;
+
+ var sid = "";
+
+ var flag = false;
+
+ do
+ {
+ pos2 = str.indexOf('.', pos1);
+ if(pos2 === (-1))
+ sid = str.substr(pos1);
+ else
+ sid = str.substr(pos1, pos2 - pos1);
+
+ pos1 = pos2 + 1;
+
+ if(flag)
+ {
+ var sid_block = this.value[0];
+
+ var plus = 0;
+
+ switch(sid_block.value_dec)
+ {
+ case 0:
+ break;
+ case 1:
+ plus = 40;
+ break;
+ case 2:
+ plus = 80;
+ break;
+ default:
+ this.value = new Array(); // clear SID array
+ return false; // ???
+ }
+
+ var parsedSID = parseInt(sid, 10);
+ if(isNaN(parsedSID))
+ return true;
+
+ sid_block.value_dec = parsedSID + plus;
+
+ flag = false;
+ }
+ else
+ {
+ var sid_block = new local.SID_value_block();
+ sid_block.value_dec = parseInt(sid, 10);
+ if(isNaN(sid_block.value_dec))
+ return true;
+
+ if(this.value.length === 0)
+ {
+ sid_block.is_first_sid = true;
+ flag = true;
+ }
+
+ this.value.push(sid_block);
+ }
+
+ } while(pos2 !== (-1));
+
+ return true;
+ };
+ //**************************************************************************************
+ local.OID_value_block.prototype.toString =
+ function()
+ {
+ var result = "";
+ var is_hex_only = false;
+
+ for(var i = 0; i < this.value.length; i++)
+ {
+ is_hex_only = this.value[i].is_hex_only;
+
+ var sid_str = this.value[i].toString();
+
+ if(i !== 0)
+ result = result + ".";
+
+ if(is_hex_only)
+ {
+ sid_str = "{" + sid_str + "}";
+
+ if(this.value[i].is_first_sid)
+ result = "2.{" + sid_str + " - 80}";
+ else
+ result = result + sid_str;
+ }
+ else
+ result = result + sid_str;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ local.OID_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "OID_value_block";
+ };
+ //**************************************************************************************
+ local.OID_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.value_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.OID_value_block.prototype.block_name.call(this);
+ _object.value = local.OID_value_block.prototype.toString.call(this);
+ _object.sid_array = new Array();
+ for(var i = 0; i < this.value.length; i++)
+ _object.sid_array.push(this.value[i].toJSON());
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OID =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.OID_value_block(arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 6; // OBJECT IDENTIFIER
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OID.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.OID.constructor = in_window.org.pkijs.asn1.OID;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OID.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "OID";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.OID.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.OID.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of all string's classes
+ //**************************************************************************************
+ local.UTF8STRING_value_block =
+ function()
+ {
+ local.hex_block.call(this, arguments[0]);
+
+ this.is_hex_only = true;
+ this.value = ""; // String representation of decoded ArrayBuffer
+ };
+ //**************************************************************************************
+ local.UTF8STRING_value_block.prototype = new local.hex_block();
+ local.UTF8STRING_value_block.constructor = local.UTF8STRING_value_block;
+ //**************************************************************************************
+ local.UTF8STRING_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "UTF8STRING_value_block";
+ };
+ //**************************************************************************************
+ local.UTF8STRING_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.hex_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.UTF8STRING_value_block.prototype.block_name.call(this);
+ _object.value = this.value;
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTF8STRING =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.UTF8STRING_value_block();
+
+ if(arguments[0] instanceof Object)
+ {
+ if("value" in arguments[0])
+ in_window.org.pkijs.asn1.UTF8STRING.prototype.fromString.call(this,arguments[0].value);
+ }
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 12; // UTF8STRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTF8STRING.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.UTF8STRING.constructor = in_window.org.pkijs.asn1.UTF8STRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTF8STRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "UTF8STRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTF8STRING.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ in_window.org.pkijs.asn1.UTF8STRING.prototype.fromBuffer.call(this, this.value_block.value_hex);
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTF8STRING.prototype.fromBuffer =
+ function(input_buffer)
+ {
+ /// Array with encoded string
+ this.value_block.value = String.fromCharCode.apply(null, new Uint8Array(input_buffer));
+
+ try
+ {
+ this.value_block.value = decodeURIComponent(escape(this.value_block.value));
+ }
+ catch(ex)
+ {
+ this.warnings.push("Error during \"decodeURIComponent\": " + ex + ", using raw string");
+ }
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTF8STRING.prototype.fromString =
+ function(input_string)
+ {
+ /// String with UNIVERSALSTRING value
+
+ var str = unescape(encodeURIComponent(input_string));
+ var str_len = str.length;
+
+ this.value_block.value_hex = new ArrayBuffer(str_len);
+ var view = new Uint8Array(this.value_block.value_hex);
+
+ for(var i = 0; i < str_len; i++)
+ view[i] = str.charCodeAt(i);
+
+ this.value_block.value = input_string;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.UTF8STRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ local.BMPSTRING_value_block =
+ function()
+ {
+ local.hex_block.call(this, arguments[0]);
+
+ this.is_hex_only = true;
+ this.value = "";
+ };
+ //**************************************************************************************
+ local.BMPSTRING_value_block.prototype = new local.hex_block();
+ local.BMPSTRING_value_block.constructor = local.BMPSTRING_value_block;
+ //**************************************************************************************
+ local.BMPSTRING_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "BMPSTRING_value_block";
+ };
+ //**************************************************************************************
+ local.BMPSTRING_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.hex_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.BMPSTRING_value_block.prototype.block_name.call(this);
+ _object.value = this.value;
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BMPSTRING =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.BMPSTRING_value_block();
+
+ if(arguments[0] instanceof Object)
+ {
+ if("value" in arguments[0])
+ in_window.org.pkijs.asn1.BMPSTRING.prototype.fromString.call(this, arguments[0].value);
+ }
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 30; // BMPSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BMPSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.BMPSTRING.constructor = in_window.org.pkijs.asn1.BMPSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BMPSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "BMPSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BMPSTRING.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ in_window.org.pkijs.asn1.BMPSTRING.prototype.fromBuffer.call(this, this.value_block.value_hex);
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BMPSTRING.prototype.fromBuffer =
+ function(input_buffer)
+ {
+ /// Array with encoded string
+
+ var copy_buffer = in_window.org.pkijs.copyBuffer(input_buffer);
+
+ var value_view = new Uint8Array(copy_buffer);
+
+ for(var i = 0; i < value_view.length; i = i + 2)
+ {
+ var temp = value_view[i];
+
+ value_view[i] = value_view[i + 1];
+ value_view[i + 1] = temp;
+ }
+
+ this.value_block.value = String.fromCharCode.apply(null, new Uint16Array(copy_buffer));
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BMPSTRING.prototype.fromString =
+ function(input_string)
+ {
+ /// String with UNIVERSALSTRING value
+
+ var str_length = input_string.length;
+
+ this.value_block.value_hex = new ArrayBuffer(str_length * 2);
+ var value_hex_view = new Uint8Array(this.value_block.value_hex);
+
+ for(var i = 0; i < str_length; i++)
+ {
+ var code_buf = util_tobase(input_string.charCodeAt(i), 8);
+ var code_view = new Uint8Array(code_buf);
+ if(code_view.length > 2)
+ continue;
+
+ var dif = 2 - code_view.length;
+
+ for(var j = (code_view.length - 1) ; j >= 0; j--)
+ value_hex_view[i * 2 + j + dif] = code_view[j];
+ }
+
+ this.value_block.value = input_string;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.BMPSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.BMPSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ local.UNIVERSALSTRING_value_block =
+ function()
+ {
+ local.hex_block.call(this, arguments[0]);
+
+ this.is_hex_only = true;
+ this.value = "";
+ };
+ //**************************************************************************************
+ local.UNIVERSALSTRING_value_block.prototype = new local.hex_block();
+ local.UNIVERSALSTRING_value_block.constructor = local.UNIVERSALSTRING_value_block;
+ //**************************************************************************************
+ local.UNIVERSALSTRING_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "UNIVERSALSTRING_value_block";
+ };
+ //**************************************************************************************
+ local.UNIVERSALSTRING_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.hex_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.UNIVERSALSTRING_value_block.prototype.block_name.call(this);
+ _object.value = this.value;
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UNIVERSALSTRING =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.UNIVERSALSTRING_value_block();
+
+ if(arguments[0] instanceof Object)
+ {
+ if("value" in arguments[0])
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromString.call(this, arguments[0].value);
+ }
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 28; // UNIVERSALSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.constructor = in_window.org.pkijs.asn1.UNIVERSALSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "UNIVERSALSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromBuffer.call(this, this.value_block.value_hex);
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromBuffer =
+ function(input_buffer)
+ {
+ /// Array with encoded string
+
+ var copy_buffer = in_window.org.pkijs.copyBuffer(input_buffer);
+
+ var value_view = new Uint8Array(copy_buffer);
+
+ for(var i = 0; i < value_view.length; i = i + 4)
+ {
+ value_view[i] = value_view[i + 3];
+ value_view[i + 1] = value_view[i + 2];
+ value_view[i + 2] = 0x00;
+ value_view[i + 3] = 0x00;
+ }
+
+ this.value_block.value = String.fromCharCode.apply(null, new Uint32Array(copy_buffer));
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.fromString =
+ function(input_string)
+ {
+ /// String with UNIVERSALSTRING value
+
+ var str_length = input_string.length;
+
+ this.value_block.value_hex = new ArrayBuffer(str_length * 4);
+ var value_hex_view = new Uint8Array(this.value_block.value_hex);
+
+ for(var i = 0; i < str_length; i++)
+ {
+ var code_buf = util_tobase(input_string.charCodeAt(i), 8);
+ var code_view = new Uint8Array(code_buf);
+ if(code_view.length > 4)
+ continue;
+
+ var dif = 4 - code_view.length;
+
+ for(var j = (code_view.length - 1) ; j >= 0; j--)
+ value_hex_view[i*4 + j + dif] = code_view[j];
+ }
+
+ this.value_block.value = input_string;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.UNIVERSALSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_value_block =
+ function()
+ {
+ local.hex_block.call(this, arguments[0]);
+
+ /// Native string representation
+ this.value = "";
+ this.is_hex_only = true;
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_value_block.prototype = new local.hex_block();
+ local.SIMPLESTRING_value_block.constructor = local.SIMPLESTRING_value_block;
+ //**************************************************************************************
+ local.SIMPLESTRING_value_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "SIMPLESTRING_value_block";
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_value_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.hex_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.SIMPLESTRING_value_block.prototype.block_name.call(this);
+ _object.value = this.value;
+
+ return _object;
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_block =
+ function()
+ {
+ in_window.org.pkijs.asn1.ASN1_block.call(this, arguments[0]);
+
+ this.value_block = new local.SIMPLESTRING_value_block();
+
+ if(arguments[0] instanceof Object)
+ {
+ if("value" in arguments[0])
+ local.SIMPLESTRING_block.prototype.fromString.call(this, arguments[0].value);
+ }
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_block.prototype = new in_window.org.pkijs.asn1.ASN1_block();
+ local.SIMPLESTRING_block.constructor = local.SIMPLESTRING_block;
+ //**************************************************************************************
+ local.SIMPLESTRING_block.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "SIMPLESTRING";
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_block.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ local.SIMPLESTRING_block.prototype.fromBuffer.call(this, this.value_block.value_hex);
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_block.prototype.fromBuffer =
+ function(input_buffer)
+ {
+ /// Array with encoded string
+
+ this.value_block.value = String.fromCharCode.apply(null, new Uint8Array(input_buffer));
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_block.prototype.fromString =
+ function(input_string)
+ {
+ /// String with UNIVERSALSTRING value
+ var str_len = input_string.length;
+
+ this.value_block.value_hex = new ArrayBuffer(str_len);
+ var view = new Uint8Array(this.value_block.value_hex);
+
+ for(var i = 0; i < str_len; i++)
+ view[i] = input_string.charCodeAt(i);
+
+ this.value_block.value = input_string;
+ };
+ //**************************************************************************************
+ local.SIMPLESTRING_block.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.ASN1_block.prototype.toJSON.call(this);
+
+ _object.block_name = local.SIMPLESTRING_block.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NUMERICSTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 18; // NUMERICSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NUMERICSTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.NUMERICSTRING.constructor = in_window.org.pkijs.asn1.NUMERICSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NUMERICSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "NUMERICSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.NUMERICSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.NUMERICSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.PRINTABLESTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 19; // PRINTABLESTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.PRINTABLESTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.PRINTABLESTRING.constructor = in_window.org.pkijs.asn1.PRINTABLESTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.PRINTABLESTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "PRINTABLESTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.PRINTABLESTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.PRINTABLESTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TELETEXSTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 20; // TELETEXSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TELETEXSTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.TELETEXSTRING.constructor = in_window.org.pkijs.asn1.TELETEXSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TELETEXSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "TELETEXSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TELETEXSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.TELETEXSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VIDEOTEXSTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 21; // VIDEOTEXSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.VIDEOTEXSTRING.constructor = in_window.org.pkijs.asn1.VIDEOTEXSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "VIDEOTEXSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.VIDEOTEXSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.IA5STRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 22; // IA5STRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.IA5STRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.IA5STRING.constructor = in_window.org.pkijs.asn1.IA5STRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.IA5STRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "IA5STRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.IA5STRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.IA5STRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GRAPHICSTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 25; // GRAPHICSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GRAPHICSTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.GRAPHICSTRING.constructor = in_window.org.pkijs.asn1.GRAPHICSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GRAPHICSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "GRAPHICSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GRAPHICSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.GRAPHICSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VISIBLESTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 26; // VISIBLESTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VISIBLESTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.VISIBLESTRING.constructor = in_window.org.pkijs.asn1.VISIBLESTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VISIBLESTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "VISIBLESTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.VISIBLESTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.VISIBLESTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALSTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 27; // GENERALSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALSTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.GENERALSTRING.constructor = in_window.org.pkijs.asn1.GENERALSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "GENERALSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.GENERALSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.CHARACTERSTRING =
+ function()
+ {
+ local.SIMPLESTRING_block.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 29; // CHARACTERSTRING
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.CHARACTERSTRING.prototype = new local.SIMPLESTRING_block();
+ in_window.org.pkijs.asn1.CHARACTERSTRING.constructor = in_window.org.pkijs.asn1.CHARACTERSTRING;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.CHARACTERSTRING.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "CHARACTERSTRING";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.CHARACTERSTRING.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = local.SIMPLESTRING_block.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.CHARACTERSTRING.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of all date and time classes
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME =
+ function()
+ {
+ in_window.org.pkijs.asn1.VISIBLESTRING.call(this, arguments[0]);
+
+ this.year = 0;
+ this.month = 0;
+ this.day = 0;
+ this.hour = 0;
+ this.minute = 0;
+ this.second = 0;
+
+ // #region Create UTCTIME from ASN.1 UTC string value
+ if((arguments[0] instanceof Object) && ("value" in arguments[0]))
+ {
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromString.call(this, arguments[0].value);
+
+ this.value_block.value_hex = new ArrayBuffer(arguments[0].value.length);
+ var view = new Uint8Array(this.value_block.value_hex);
+
+ for(var i = 0; i < arguments[0].value.length; i++)
+ view[i] = arguments[0].value.charCodeAt(i);
+ }
+ // #endregion
+ // #region Create UTCTIME from JavaScript Date type
+ if((arguments[0] instanceof Object) && ("value_date" in arguments[0]))
+ {
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromDate.call(this, arguments[0].value_date);
+ this.value_block.value_hex = in_window.org.pkijs.asn1.UTCTIME.prototype.toBuffer.call(this);
+ }
+ // #endregion
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 23; // UTCTIME
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype = new in_window.org.pkijs.asn1.VISIBLESTRING();
+ in_window.org.pkijs.asn1.UTCTIME.constructor = in_window.org.pkijs.asn1.UTCTIME;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromBuffer.call(this, this.value_block.value_hex);
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromBuffer =
+ function(input_buffer)
+ {
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromString.call(this, String.fromCharCode.apply(null, new Uint8Array(input_buffer)));
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.toBuffer =
+ function()
+ {
+ var str = in_window.org.pkijs.asn1.UTCTIME.prototype.toString.call(this);
+
+ var buffer = new ArrayBuffer(str.length);
+ var view = new Uint8Array(buffer);
+
+ for(var i = 0; i < str.length; i++)
+ view[i] = str.charCodeAt(i);
+
+ return buffer;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromDate =
+ function(input_date)
+ {
+ /// Create "UTCTime" ASN.1 type from JavaScript "Date" type
+
+ this.year = input_date.getUTCFullYear();
+ this.month = input_date.getUTCMonth() + 1;
+ this.day = input_date.getUTCDate();
+ this.hour = input_date.getUTCHours();
+ this.minute = input_date.getUTCMinutes();
+ this.second = input_date.getUTCSeconds();
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.toDate =
+ function()
+ {
+ return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second)));
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.fromString =
+ function(input_string)
+ {
+ /// Create "UTCTime" ASN.1 type from JavaScript "String" type
+
+ // #region Parse input string
+ var parser = /(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})Z/ig;
+ var parser_array = parser.exec(input_string);
+ if(parser_array === null)
+ {
+ this.error = "Wrong input string for convertion";
+ return;
+ }
+ // #endregion
+
+ // #region Store parsed values
+ var year = parseInt(parser_array[1], 10);
+ if(year >= 50)
+ this.year = 1900 + year;
+ else
+ this.year = 2000 + year;
+
+ this.month = parseInt(parser_array[2], 10);
+ this.day = parseInt(parser_array[3], 10);
+ this.hour = parseInt(parser_array[4], 10);
+ this.minute = parseInt(parser_array[5], 10);
+ this.second = parseInt(parser_array[6], 10);
+ // #endregion
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.toString =
+ function()
+ {
+ var output_array = new Array(7);
+
+ output_array[0] = in_window.org.pkijs.padNumber(((this.year < 2000) ? (this.year - 1900) : (this.year - 2000)), 2);
+ output_array[1] = in_window.org.pkijs.padNumber(this.month, 2);
+ output_array[2] = in_window.org.pkijs.padNumber(this.day, 2);
+ output_array[3] = in_window.org.pkijs.padNumber(this.hour, 2);
+ output_array[4] = in_window.org.pkijs.padNumber(this.minute, 2);
+ output_array[5] = in_window.org.pkijs.padNumber(this.second, 2);
+ output_array[6] = "Z";
+
+ return output_array.join('');
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "UTCTIME";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.UTCTIME.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.VISIBLESTRING.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.UTCTIME.prototype.block_name.call(this);
+ _object.year = this.year;
+ _object.month = this.month;
+ _object.day = this.day;
+ _object.hour = this.hour;
+ _object.minute = this.minute;
+ _object.second = this.second;
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME =
+ function()
+ {
+ in_window.org.pkijs.asn1.VISIBLESTRING.call(this, arguments[0]);
+
+ this.year = 0;
+ this.month = 0;
+ this.day = 0;
+ this.hour = 0;
+ this.minute = 0;
+ this.second = 0;
+ this.millisecond = 0;
+
+ // #region Create GeneralizedTime from ASN.1 string value
+ if((arguments[0] instanceof Object) && ("value" in arguments[0]))
+ {
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromString.call(this, arguments[0].value);
+
+ this.value_block.value_hex = new ArrayBuffer(arguments[0].value.length);
+ var view = new Uint8Array(this.value_block.value_hex);
+
+ for(var i = 0; i < arguments[0].value.length; i++)
+ view[i] = arguments[0].value.charCodeAt(i);
+ }
+ // #endregion
+ // #region Create GeneralizedTime from JavaScript Date type
+ if((arguments[0] instanceof Object) && ("value_date" in arguments[0]))
+ {
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromDate.call(this, arguments[0].value_date);
+ this.value_block.value_hex = in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toBuffer.call(this);
+ }
+ // #endregion
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 24; // GENERALIZEDTIME
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype = new in_window.org.pkijs.asn1.VISIBLESTRING();
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.constructor = in_window.org.pkijs.asn1.GENERALIZEDTIME;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromBER =
+ function(input_buffer, input_offset, input_length)
+ {
+ /// Base function for converting block from BER encoded array of bytes
+ /// ASN.1 BER encoded array
+ /// Offset in ASN.1 BER encoded array where decoding should be started
+ /// Maximum length of array of bytes which can be using in this function
+
+ var result_offset = this.value_block.fromBER(input_buffer, input_offset, (this.len_block.is_indefinite_form == true) ? input_length : this.len_block.length);
+ if(result_offset == (-1))
+ {
+ this.error = this.value_block.error;
+ return result_offset;
+ }
+
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromBuffer.call(this, this.value_block.value_hex);
+
+ if(this.id_block.error.length == 0)
+ this.block_length += this.id_block.block_length;
+
+ if(this.len_block.error.length == 0)
+ this.block_length += this.len_block.block_length;
+
+ if(this.value_block.error.length == 0)
+ this.block_length += this.value_block.block_length;
+
+ return result_offset;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromBuffer =
+ function(input_buffer)
+ {
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromString.call(this, String.fromCharCode.apply(null, new Uint8Array(input_buffer)));
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toBuffer =
+ function()
+ {
+ var str = in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toString.call(this);
+
+ var buffer = new ArrayBuffer(str.length);
+ var view = new Uint8Array(buffer);
+
+ for(var i = 0; i < str.length; i++)
+ view[i] = str.charCodeAt(i);
+
+ return buffer;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromDate =
+ function(input_date)
+ {
+ /// Create "GeneralizedTime" ASN.1 type from JavaScript "Date" type
+
+ this.year = input_date.getUTCFullYear();
+ this.month = input_date.getUTCMonth() + 1;
+ this.day = input_date.getUTCDate();
+ this.hour = input_date.getUTCHours();
+ this.minute = input_date.getUTCMinutes();
+ this.second = input_date.getUTCSeconds();
+ this.millisecond = input_date.getUTCMilliseconds();
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toDate =
+ function()
+ {
+ return (new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond)));
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.fromString =
+ function(input_string)
+ {
+ /// Create "GeneralizedTime" ASN.1 type from JavaScript "String" type
+
+ // #region Initial variables
+ var isUTC = false;
+
+ var timeString = "";
+ var dateTimeString = "";
+ var fractionPart = 0;
+
+ var parser;
+
+ var hourDifference = 0;
+ var minuteDifference = 0;
+ // #endregion
+
+ // #region Convert as UTC time
+ if(input_string[input_string.length - 1] == "Z")
+ {
+ timeString = input_string.substr(0, input_string.length - 1);
+
+ isUTC = true;
+ }
+ // #endregion
+ // #region Convert as local time
+ else
+ {
+ var number = new Number(input_string[input_string.length - 1]);
+
+ if(isNaN(number.valueOf()))
+ throw new Error("Wrong input string for convertion");
+
+ timeString = input_string;
+ }
+ // #endregion
+
+ // #region Check that we do not have a "+" and "-" symbols inside UTC time
+ if(isUTC)
+ {
+ if(timeString.indexOf("+") != (-1))
+ throw new Error("Wrong input string for convertion");
+
+ if(timeString.indexOf("-") != (-1))
+ throw new Error("Wrong input string for convertion");
+ }
+ // #endregion
+ // #region Get "UTC time difference" in case of local time
+ else
+ {
+ var multiplier = 1;
+ var differencePosition = timeString.indexOf("+");
+ var differenceString = "";
+
+ if(differencePosition == (-1))
+ {
+ differencePosition = timeString.indexOf("-");
+ multiplier = (-1);
+ }
+
+ if(differencePosition != (-1))
+ {
+ differenceString = timeString.substr(differencePosition + 1);
+ timeString = timeString.substr(0, differencePosition);
+
+ if((differenceString.length != 2) && (differenceString.length != 4))
+ throw new Error("Wrong input string for convertion");
+
+ var number = new Number(differenceString.substr(0, 2));
+
+ if(isNaN(number.valueOf()))
+ throw new Error("Wrong input string for convertion");
+
+ hourDifference = multiplier * number;
+
+ if(differenceString.length == 4)
+ {
+ number = new Number(differenceString.substr(2, 2));
+
+ if(isNaN(number.valueOf()))
+ throw new Error("Wrong input string for convertion");
+
+ minuteDifference = multiplier * number;
+ }
+ }
+ }
+ // #endregion
+
+ // #region Get position of fraction point
+ var fractionPointPosition = timeString.indexOf("."); // Check for "full stop" symbol
+ if(fractionPointPosition == (-1))
+ fractionPointPosition = timeString.indexOf(","); // Check for "comma" symbol
+ // #endregion
+
+ // #region Get fraction part
+ if(fractionPointPosition != (-1))
+ {
+ var fractionPartCheck = new Number("0" + timeString.substr(fractionPointPosition));
+
+ if(isNaN(fractionPartCheck.valueOf()))
+ throw new Error("Wrong input string for convertion");
+
+ fractionPart = fractionPartCheck.valueOf();
+
+ dateTimeString = timeString.substr(0, fractionPointPosition);
+ }
+ else
+ dateTimeString = timeString;
+ // #endregion
+
+ // #region Parse internal date
+ switch(true)
+ {
+ case (dateTimeString.length == 8): // "YYYYMMDD"
+ parser = /(\d{4})(\d{2})(\d{2})/ig;
+ if(fractionPointPosition !== (-1))
+ throw new Error("Wrong input string for convertion"); // Here we should not have a "fraction point"
+ break;
+ case (dateTimeString.length == 10): // "YYYYMMDDHH"
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})/ig;
+
+ if(fractionPointPosition !== (-1))
+ {
+ var fractionResult = 60 * fractionPart;
+ this.minute = Math.floor(fractionResult);
+
+ fractionResult = 60 * (fractionResult - this.minute);
+ this.second = Math.floor(fractionResult);
+
+ fractionResult = 1000 * (fractionResult - this.second);
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ case (dateTimeString.length == 12): // "YYYYMMDDHHMM"
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
+
+ if(fractionPointPosition !== (-1))
+ {
+ var fractionResult = 60 * fractionPart;
+ this.second = Math.floor(fractionResult);
+
+ fractionResult = 1000 * (fractionResult - this.second);
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ case (dateTimeString.length == 14): // "YYYYMMDDHHMMSS"
+ parser = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ig;
+
+ if(fractionPointPosition !== (-1))
+ {
+ var fractionResult = 1000 * fractionPart;
+ this.millisecond = Math.floor(fractionResult);
+ }
+ break;
+ default:
+ throw new Error("Wrong input string for convertion");
+ }
+ // #endregion
+
+ // #region Put parsed values at right places
+ var parser_array = parser.exec(dateTimeString);
+ if(parser_array == null)
+ throw new Error("Wrong input string for convertion");
+
+ for(var j = 1; j < parser_array.length; j++)
+ {
+ switch(j)
+ {
+ case 1:
+ this.year = parseInt(parser_array[j], 10);
+ break;
+ case 2:
+ this.month = parseInt(parser_array[j], 10);
+ break;
+ case 3:
+ this.day = parseInt(parser_array[j], 10);
+ break;
+ case 4:
+ this.hour = parseInt(parser_array[j], 10) + hourDifference;
+ break;
+ case 5:
+ this.minute = parseInt(parser_array[j], 10) + minuteDifference;
+ break;
+ case 6:
+ this.second = parseInt(parser_array[j], 10);
+ break;
+ default:
+ throw new Error("Wrong input string for convertion");
+ }
+ }
+ // #endregion
+
+ // #region Get final date
+ if(isUTC == false)
+ {
+ var tempDate = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
+
+ this.year = tempDate.getUTCFullYear();
+ this.month = tempDate.getUTCMonth();
+ this.day = tempDate.getUTCDay();
+ this.hour = tempDate.getUTCHours();
+ this.minute = tempDate.getUTCMinutes();
+ this.second = tempDate.getUTCSeconds();
+ this.millisecond = tempDate.getUTCMilliseconds();
+ }
+ // #endregion
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toString =
+ function()
+ {
+ var output_array = new Array();
+
+ output_array.push(in_window.org.pkijs.padNumber(this.year, 4));
+ output_array.push(in_window.org.pkijs.padNumber(this.month, 2));
+ output_array.push(in_window.org.pkijs.padNumber(this.day, 2));
+ output_array.push(in_window.org.pkijs.padNumber(this.hour, 2));
+ output_array.push(in_window.org.pkijs.padNumber(this.minute, 2));
+ output_array.push(in_window.org.pkijs.padNumber(this.second, 2));
+ if(this.millisecond != 0)
+ {
+ output_array.push(".");
+ output_array.push(in_window.org.pkijs.padNumber(this.millisecond, 3));
+ }
+ output_array.push("Z");
+
+ return output_array.join('');
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "GENERALIZEDTIME";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.VISIBLESTRING.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.GENERALIZEDTIME.prototype.block_name.call(this);
+ _object.year = this.year;
+ _object.month = this.month;
+ _object.day = this.day;
+ _object.hour = this.hour;
+ _object.minute = this.minute;
+ _object.second = this.second;
+ _object.millisecond = this.millisecond;
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATE =
+ function()
+ {
+ in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 31; // DATE
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATE.prototype = new in_window.org.pkijs.asn1.UTF8STRING();
+ in_window.org.pkijs.asn1.DATE.constructor = in_window.org.pkijs.asn1.DATE;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATE.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "DATE";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATE.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.DATE.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIMEOFDAY =
+ function()
+ {
+ in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 32; // TIMEOFDAY
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIMEOFDAY.prototype = new in_window.org.pkijs.asn1.UTF8STRING();
+ in_window.org.pkijs.asn1.TIMEOFDAY.constructor = in_window.org.pkijs.asn1.TIMEOFDAY;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIMEOFDAY.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "TIMEOFDAY";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIMEOFDAY.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.TIMEOFDAY.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATETIME =
+ function()
+ {
+ in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 33; // DATETIME
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATETIME.prototype = new in_window.org.pkijs.asn1.UTF8STRING();
+ in_window.org.pkijs.asn1.DATETIME.constructor = in_window.org.pkijs.asn1.DATETIME;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATETIME.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "DATETIME";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DATETIME.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.DATETIME.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DURATION =
+ function()
+ {
+ in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 34; // DURATION
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DURATION.prototype = new in_window.org.pkijs.asn1.UTF8STRING();
+ in_window.org.pkijs.asn1.DURATION.constructor = in_window.org.pkijs.asn1.DURATION;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DURATION.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "DURATION";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.DURATION.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.DURATION.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIME =
+ function()
+ {
+ in_window.org.pkijs.asn1.UTF8STRING.call(this, arguments[0]);
+
+ this.id_block.tag_class = 1; // UNIVERSAL
+ this.id_block.tag_number = 14; // TIME
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIME.prototype = new in_window.org.pkijs.asn1.UTF8STRING();
+ in_window.org.pkijs.asn1.TIME.constructor = in_window.org.pkijs.asn1.TIME;
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIME.prototype.block_name =
+ function()
+ {
+ /// Aux function, need to get a block name. Need to have it here for inhiritence
+
+ return "TIME";
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.TIME.prototype.toJSON =
+ function()
+ {
+ /// Convertion for the block to JSON object
+
+ var _object = in_window.org.pkijs.asn1.UTF8STRING.prototype.toJSON.call(this);
+
+ _object.block_name = in_window.org.pkijs.asn1.TIME.prototype.block_name.call(this);
+
+ return _object;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of special ASN.1 schema type CHOICE
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.CHOICE =
+ function()
+ {
+ if(arguments[0] instanceof Object)
+ {
+ this.value = in_window.org.pkijs.getValue(arguments[0], "value", new Array()); // Array of ASN.1 types for make a choice from
+ this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false);
+ }
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of special ASN.1 schema type ANY
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.ANY =
+ function()
+ {
+ if(arguments[0] instanceof Object)
+ {
+ this.name = in_window.org.pkijs.getValue(arguments[0], "name", "");
+ this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false);
+ }
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of special ASN.1 schema type REPEATED
+ //**************************************************************************************
+ in_window.org.pkijs.asn1.REPEATED =
+ function()
+ {
+ if(arguments[0] instanceof Object)
+ {
+ this.name = in_window.org.pkijs.getValue(arguments[0], "name", "");
+ this.optional = in_window.org.pkijs.getValue(arguments[0], "optional", false);
+ this.value = in_window.org.pkijs.getValue(arguments[0], "value", new in_window.org.pkijs.asn1.ANY());
+ this.local = in_window.org.pkijs.getValue(arguments[0], "local", false); // Could local or global array to store elements
+ }
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Major ASN.1 BER decoding function
+ //**************************************************************************************
+ function fromBER_raw(input_buffer, input_offset, input_length)
+ {
+ var incoming_offset = input_offset; // Need to store initial offset since "input_offset" is changing in the function
+
+ // #region Local function changing a type for ASN.1 classes
+ function local_change_type(input_object, new_type)
+ {
+ if(input_object instanceof new_type)
+ return input_object;
+
+ var new_object = new new_type();
+ new_object.id_block = input_object.id_block;
+ new_object.len_block = input_object.len_block;
+ new_object.warnings = input_object.warnings;
+ new_object.value_before_decode = util_copybuf(input_object.value_before_decode);
+
+ return new_object;
+ }
+ // #endregion
+
+ // #region Create a basic ASN.1 type since we need to return errors and warnings from the function
+ var return_object = new in_window.org.pkijs.asn1.ASN1_block();
+ // #endregion
+
+ // #region Basic check for parameters
+ if(check_buffer_params(input_buffer, input_offset, input_length) === false)
+ {
+ return_object.error = "Wrong input parameters";
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ }
+ // #endregion
+
+ // #region Getting Uint8Array from ArrayBuffer
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_length);
+ // #endregion
+
+ // #region Initial checks
+ if(int_buffer.length == 0)
+ {
+ this.error = "Zero buffer length";
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ }
+ // #endregion
+
+ // #region Decode indentifcation block of ASN.1 BER structure
+ var result_offset = return_object.id_block.fromBER(input_buffer, input_offset, input_length);
+ return_object.warnings.concat(return_object.id_block.warnings);
+ if(result_offset == (-1))
+ {
+ return_object.error = return_object.id_block.error;
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ }
+
+ input_offset = result_offset;
+ input_length -= return_object.id_block.block_length;
+ // #endregion
+
+ // #region Decode length block of ASN.1 BER structure
+ result_offset = return_object.len_block.fromBER(input_buffer, input_offset, input_length);
+ return_object.warnings.concat(return_object.len_block.warnings);
+ if(result_offset == (-1))
+ {
+ return_object.error = return_object.len_block.error;
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ }
+
+ input_offset = result_offset;
+ input_length -= return_object.len_block.block_length;
+ // #endregion
+
+ // #region Check for usign indefinite length form in encoding for primitive types
+ if((return_object.id_block.is_constructed == false) &&
+ (return_object.len_block.is_indefinite_form == true))
+ {
+ return_object.error = new String("Indefinite length form used for primitive encoding form");
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ }
+ // #endregion
+
+ // #region Switch ASN.1 block type
+ var new_asn1_type = in_window.org.pkijs.asn1.ASN1_block;
+
+ switch(return_object.id_block.tag_class)
+ {
+ // #region UNIVERSAL
+ case 1:
+ // #region Check for reserved tag numbers
+ if((return_object.id_block.tag_number >= 37) &&
+ (return_object.id_block.is_hex_only == false))
+ {
+ return_object.error = "UNIVERSAL 37 and upper tags are reserved by ASN.1 standard";
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ }
+ // #endregion
+
+ switch(return_object.id_block.tag_number)
+ {
+ // #region EOC type
+ case 0:
+ // #region Check for EOC type
+ if((return_object.id_block.is_constructed == true) &&
+ (return_object.len_block.length > 0))
+ {
+ return_object.error = "Type [UNIVERSAL 0] is reserved";
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ }
+ // #endregion
+
+ new_asn1_type = in_window.org.pkijs.asn1.EOC;
+
+ break;
+ // #endregion
+ // #region BOOLEAN type
+ case 1:
+ new_asn1_type = in_window.org.pkijs.asn1.BOOLEAN;
+ break;
+ // #endregion
+ // #region INTEGER type
+ case 2:
+ new_asn1_type = in_window.org.pkijs.asn1.INTEGER;
+ break;
+ // #endregion
+ // #region BITSTRING type
+ case 3:
+ new_asn1_type = in_window.org.pkijs.asn1.BITSTRING;
+ break;
+ // #endregion
+ // #region OCTETSTRING type
+ case 4:
+ new_asn1_type = in_window.org.pkijs.asn1.OCTETSTRING;
+ break;
+ // #endregion
+ // #region NULL type
+ case 5:
+ new_asn1_type = in_window.org.pkijs.asn1.NULL;
+ break;
+ // #endregion
+ // #region OBJECT IDENTIFIER type
+ case 6:
+ new_asn1_type = in_window.org.pkijs.asn1.OID;
+ break;
+ // #endregion
+ // #region ENUMERATED type
+ case 10:
+ new_asn1_type = in_window.org.pkijs.asn1.ENUMERATED;
+ break;
+ // #endregion
+ // #region UTF8STRING type
+ case 12:
+ new_asn1_type = in_window.org.pkijs.asn1.UTF8STRING;
+ break;
+ // #endregion
+ // #region TIME type
+ case 14:
+ new_asn1_type = in_window.org.pkijs.asn1.TIME;
+ break;
+ // #endregion
+ // #region ASN.1 reserved type
+ case 15:
+ return_object.error = "[UNIVERSAL 15] is reserved by ASN.1 standard";
+ return {
+ offset: (-1),
+ result: return_object
+ };
+ break;
+ // #endregion
+ // #region SEQUENCE type
+ case 16:
+ new_asn1_type = in_window.org.pkijs.asn1.SEQUENCE;
+ break;
+ // #endregion
+ // #region SET type
+ case 17:
+ new_asn1_type = in_window.org.pkijs.asn1.SET;
+ break;
+ // #endregion
+ // #region NUMERICSTRING type
+ case 18:
+ new_asn1_type = in_window.org.pkijs.asn1.NUMERICSTRING;
+ break;
+ // #endregion
+ // #region PRINTABLESTRING type
+ case 19:
+ new_asn1_type = in_window.org.pkijs.asn1.PRINTABLESTRING;
+ break;
+ // #endregion
+ // #region TELETEXSTRING type
+ case 20:
+ new_asn1_type = in_window.org.pkijs.asn1.TELETEXSTRING;
+ break;
+ // #endregion
+ // #region VIDEOTEXSTRING type
+ case 21:
+ new_asn1_type = in_window.org.pkijs.asn1.VIDEOTEXSTRING;
+ break;
+ // #endregion
+ // #region IA5STRING type
+ case 22:
+ new_asn1_type = in_window.org.pkijs.asn1.IA5STRING;
+ break;
+ // #endregion
+ // #region UTCTIME type
+ case 23:
+ new_asn1_type = in_window.org.pkijs.asn1.UTCTIME;
+ break;
+ // #endregion
+ // #region GENERALIZEDTIME type
+ case 24:
+ new_asn1_type = in_window.org.pkijs.asn1.GENERALIZEDTIME;
+ break;
+ // #endregion
+ // #region GRAPHICSTRING type
+ case 25:
+ new_asn1_type = in_window.org.pkijs.asn1.GRAPHICSTRING;
+ break;
+ // #endregion
+ // #region VISIBLESTRING type
+ case 26:
+ new_asn1_type = in_window.org.pkijs.asn1.VISIBLESTRING;
+ break;
+ // #endregion
+ // #region GENERALSTRING type
+ case 27:
+ new_asn1_type = in_window.org.pkijs.asn1.GENERALSTRING;
+ break;
+ // #endregion
+ // #region UNIVERSALSTRING type
+ case 28:
+ new_asn1_type = in_window.org.pkijs.asn1.UNIVERSALSTRING;
+ break;
+ // #endregion
+ // #region CHARACTERSTRING type
+ case 29:
+ new_asn1_type = in_window.org.pkijs.asn1.CHARACTERSTRING;
+ break;
+ // #endregion
+ // #region BMPSTRING type
+ case 30:
+ new_asn1_type = in_window.org.pkijs.asn1.BMPSTRING;
+ break;
+ // #endregion
+ // #region DATE type
+ case 31:
+ new_asn1_type = in_window.org.pkijs.asn1.DATE;
+ break;
+ // #endregion
+ // #region TIMEOFDAY type
+ case 32:
+ new_asn1_type = in_window.org.pkijs.asn1.TIMEOFDAY;
+ break;
+ // #endregion
+ // #region DATE-TIME type
+ case 33:
+ new_asn1_type = in_window.org.pkijs.asn1.DATETIME;
+ break;
+ // #endregion
+ // #region DURATION type
+ case 34:
+ new_asn1_type = in_window.org.pkijs.asn1.DURATION;
+ break;
+ // #endregion
+ // #region default
+ default:
+ {
+ var new_object;
+
+ if(return_object.id_block.is_constructed == true)
+ new_object = new in_window.org.pkijs.asn1.ASN1_CONSTRUCTED();
+ else
+ new_object = new in_window.org.pkijs.asn1.ASN1_PRIMITIVE();
+
+ new_object.id_block = return_object.id_block;
+ new_object.len_block = return_object.len_block;
+ new_object.warnings = return_object.warnings;
+
+ return_object = new_object;
+
+ result_offset = return_object.fromBER(input_buffer, input_offset, input_length);
+ }
+ // #endregion
+ }
+ break;
+ // #endregion
+ // #region All other tag classes
+ case 2: // APPLICATION
+ case 3: // CONTEXT-SPECIFIC
+ case 4: // PRIVATE
+ default:
+ {
+ if(return_object.id_block.is_constructed == true)
+ new_asn1_type = in_window.org.pkijs.asn1.ASN1_CONSTRUCTED;
+ else
+ new_asn1_type = in_window.org.pkijs.asn1.ASN1_PRIMITIVE;
+ }
+ // #endregion
+ }
+ // #endregion
+
+ // #region Change type and perform BER decoding
+ return_object = local_change_type(return_object, new_asn1_type);
+ result_offset = return_object.fromBER(input_buffer, input_offset, (return_object.len_block.is_indefinite_form == true) ? input_length : return_object.len_block.length);
+ // #endregion
+
+ // #region Coping incoming buffer for entire ASN.1 block
+ return_object.value_before_decode = util_copybuf_offset(input_buffer, incoming_offset, return_object.block_length);
+ // #endregion
+
+ return {
+ offset: result_offset,
+ result: return_object
+ };
+ }
+ //**************************************************************************************
+ in_window.org.pkijs.fromBER =
+ function(input_buffer)
+ {
+ /// Major function for decoding ASN.1 BER array into internal library structuries
+ /// ASN.1 BER encoded array of bytes
+
+ if(input_buffer.byteLength == 0)
+ {
+ var result = new in_window.org.pkijs.asn1.ASN1_block();
+ result.error = "Input buffer has zero length";
+
+ return {
+ offset: (-1),
+ result: result
+ };
+ }
+
+ return fromBER_raw(input_buffer, 0, input_buffer.byteLength);
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Major scheme verification function
+ //**************************************************************************************
+ in_window.org.pkijs.compareSchema =
+ function(root, input_asn1_data, input_asn1_schema)
+ {
+ // #region Special case for CHOICE schema element type
+ if(input_asn1_schema instanceof in_window.org.pkijs.asn1.CHOICE)
+ {
+ var choice_result = false;
+
+ for(var j = 0; j < input_asn1_schema.value.length; j++)
+ {
+ var result = in_window.org.pkijs.compareSchema(root, input_asn1_data, input_asn1_schema.value[j]);
+ if(result.verified === true)
+ return {
+ verified: true,
+ result: root
+ };
+ }
+
+ if(choice_result === false)
+ {
+ var _result = {
+ verified: false,
+ result: {
+ error: "Wrong values for CHOICE type"
+ }
+ };
+
+ if(input_asn1_schema.hasOwnProperty('name'))
+ _result.name = input_asn1_schema.name;
+
+ return _result;
+ }
+ }
+ // #endregion
+
+ // #region Special case for ANY schema element type
+ if(input_asn1_schema instanceof in_window.org.pkijs.asn1.ANY)
+ {
+ // #region Add named component of ASN.1 schema
+ if(input_asn1_schema.hasOwnProperty('name'))
+ root[input_asn1_schema.name] = input_asn1_data;
+ // #endregion
+
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ // #endregion
+
+ // #region Initial check
+ if((root instanceof Object) === false)
+ return {
+ verified: false,
+ result: { error: "Wrong root object" }
+ };
+
+ if((input_asn1_data instanceof Object) === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 data" }
+ };
+
+ if((input_asn1_schema instanceof Object) === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ if(('id_block' in input_asn1_schema) === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+ // #endregion
+
+ // #region Comparing id_block properties in ASN.1 data and ASN.1 schema
+ // #region Encode and decode ASN.1 schema id_block
+ /// This encoding/decoding is neccessary because could be an errors in schema definition
+ if(('fromBER' in input_asn1_schema.id_block) === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ if(('toBER' in input_asn1_schema.id_block) === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ var encoded_id = input_asn1_schema.id_block.toBER(false);
+ if(encoded_id.byteLength === 0)
+ return {
+ verified: false,
+ result: { error: "Error encoding id_block for ASN.1 schema" }
+ };
+
+ var decoded_offset = input_asn1_schema.id_block.fromBER(encoded_id, 0, encoded_id.byteLength);
+ if(decoded_offset === (-1))
+ return {
+ verified: false,
+ result: { error: "Error decoding id_block for ASN.1 schema" }
+ };
+ // #endregion
+
+ // #region tag_class
+ if(input_asn1_schema.id_block.hasOwnProperty('tag_class') === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ if(input_asn1_schema.id_block.tag_class !== input_asn1_data.id_block.tag_class)
+ return {
+ verified: false,
+ result: root
+ };
+ // #endregion
+ // #region tag_number
+ if(input_asn1_schema.id_block.hasOwnProperty('tag_number') === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ if(input_asn1_schema.id_block.tag_number !== input_asn1_data.id_block.tag_number)
+ return {
+ verified: false,
+ result: root
+ };
+ // #endregion
+ // #region is_constructed
+ if(input_asn1_schema.id_block.hasOwnProperty('is_constructed') === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ if(input_asn1_schema.id_block.is_constructed !== input_asn1_data.id_block.is_constructed)
+ return {
+ verified: false,
+ result: root
+ };
+ // #endregion
+ // #region is_hex_only
+ if(('is_hex_only' in input_asn1_schema.id_block) === false) // Since 'is_hex_only' is an inhirited property
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ if(input_asn1_schema.id_block.is_hex_only !== input_asn1_data.id_block.is_hex_only)
+ return {
+ verified: false,
+ result: root
+ };
+ // #endregion
+ // #region value_hex
+ if(input_asn1_schema.id_block.is_hex_only === true)
+ {
+ if(('value_hex' in input_asn1_schema.id_block) === false) // Since 'value_hex' is an inhirited property
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema" }
+ };
+
+ var schema_view = new Uint8Array(input_asn1_schema.id_block.value_hex);
+ var asn1_view = new Uint8Array(input_asn1_data.id_block.value_hex);
+
+ if(schema_view.length !== asn1_view.length)
+ return {
+ verified: false,
+ result: root
+ };
+
+ for(var i = 0; i < schema_view.length; i++)
+ {
+ if(schema_view[i] !== asn1_view[1])
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ }
+ // #endregion
+ // #endregion
+
+ // #region Add named component of ASN.1 schema
+ if(input_asn1_schema.hasOwnProperty('name'))
+ {
+ input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, '');
+ if(input_asn1_schema.name !== "")
+ root[input_asn1_schema.name] = input_asn1_data;
+ }
+ // #endregion
+
+ // #region Getting next ASN.1 block for comparition
+ if(input_asn1_schema.id_block.is_constructed === true)
+ {
+ var admission = 0;
+ var result = { verified: false };
+
+ var max_length = input_asn1_schema.value_block.value.length;
+
+ if(max_length > 0)
+ {
+ if(input_asn1_schema.value_block.value[0] instanceof in_window.org.pkijs.asn1.REPEATED)
+ max_length = input_asn1_data.value_block.value.length;
+ }
+
+ // #region Special case when constructive value has no elements
+ if(max_length === 0)
+ return {
+ verified: true,
+ result: root
+ };
+ // #endregion
+
+ // #region Special case when "input_asn1_data" has no values and "input_asn1_schema" has all optional values
+ if((input_asn1_data.value_block.value.length === 0) &&
+ (input_asn1_schema.value_block.value.length !== 0))
+ {
+ var _optional = true;
+
+ for(var i = 0; i < input_asn1_schema.value_block.value.length; i++)
+ _optional = _optional && (input_asn1_schema.value_block.value[i].optional || false);
+
+ if(_optional === true)
+ {
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ else
+ {
+ // #region Delete early added name of block
+ if(input_asn1_schema.hasOwnProperty('name'))
+ {
+ input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, '');
+ if(input_asn1_schema.name !== "")
+ delete root[input_asn1_schema.name];
+ }
+ // #endregion
+
+ root.error = "Inconsistent object length";
+
+ return {
+ verified: false,
+ result: root
+ };
+ }
+ }
+ // #endregion
+
+ for(var i = 0; i < max_length; i++)
+ {
+ // #region Special case when there is an "optional" element of ASN.1 schema at the end
+ if((i - admission) >= input_asn1_data.value_block.value.length)
+ {
+ if(input_asn1_schema.value_block.value[i].optional === false)
+ {
+ var _result = {
+ verified: false,
+ result: root
+ };
+
+ root.error = "Inconsistent length between ASN.1 data and schema";
+
+ // #region Delete early added name of block
+ if(input_asn1_schema.hasOwnProperty('name'))
+ {
+ input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, '');
+ if(input_asn1_schema.name !== "")
+ {
+ delete root[input_asn1_schema.name];
+ _result.name = input_asn1_schema.name;
+ }
+ }
+ // #endregion
+
+ return _result;
+ }
+ }
+ // #endregion
+ else
+ {
+ // #region Special case for REPEATED type of ASN.1 schema element
+ if(input_asn1_schema.value_block.value[0] instanceof in_window.org.pkijs.asn1.REPEATED)
+ {
+ result = in_window.org.pkijs.compareSchema(root, input_asn1_data.value_block.value[i], input_asn1_schema.value_block.value[0].value);
+ if(result.verified === false)
+ {
+ if(input_asn1_schema.value_block.value[0].optional === true)
+ admission++;
+ else
+ {
+ // #region Delete early added name of block
+ if(input_asn1_schema.hasOwnProperty('name'))
+ {
+ input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, '');
+ if(input_asn1_schema.name !== "")
+ delete root[input_asn1_schema.name];
+ }
+ // #endregion
+
+ return result;
+ }
+ }
+
+ if(("name" in input_asn1_schema.value_block.value[0]) && (input_asn1_schema.value_block.value[0].name.length > 0))
+ {
+ var array_root = {};
+
+ if(("local" in input_asn1_schema.value_block.value[0]) && (input_asn1_schema.value_block.value[0].local === true))
+ array_root = input_asn1_data;
+ else
+ array_root = root;
+
+ if(typeof array_root[input_asn1_schema.value_block.value[0].name] === "undefined")
+ array_root[input_asn1_schema.value_block.value[0].name] = new Array();
+
+ array_root[input_asn1_schema.value_block.value[0].name].push(input_asn1_data.value_block.value[i]);
+ }
+ }
+ // #endregion
+ else
+ {
+ result = in_window.org.pkijs.compareSchema(root, input_asn1_data.value_block.value[i - admission], input_asn1_schema.value_block.value[i]);
+ if(result.verified === false)
+ {
+ if(input_asn1_schema.value_block.value[i].optional === true)
+ admission++;
+ else
+ {
+ // #region Delete early added name of block
+ if(input_asn1_schema.hasOwnProperty('name'))
+ {
+ input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, '');
+ if(input_asn1_schema.name !== "")
+ delete root[input_asn1_schema.name];
+ }
+ // #endregion
+
+ return result;
+ }
+ }
+ }
+ }
+ }
+
+ if(result.verified === false) // The situation may take place if last element is "optional" and verification failed
+ {
+ var _result = {
+ verified: false,
+ result: root
+ };
+
+ // #region Delete early added name of block
+ if(input_asn1_schema.hasOwnProperty('name'))
+ {
+ input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, '');
+ if(input_asn1_schema.name !== "")
+ {
+ delete root[input_asn1_schema.name];
+ _result.name = input_asn1_schema.name;
+ }
+ }
+ // #endregion
+
+ return _result;
+ }
+
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ // #endregion
+ // #region Ability to parse internal value for primitive-encoded value (value of OCTETSTRING, for example)
+ else
+ {
+ if( ("primitive_schema" in input_asn1_schema) &&
+ ("value_hex" in input_asn1_data.value_block) )
+ {
+ // #region Decoding of raw ASN.1 data
+ var asn1 = in_window.org.pkijs.fromBER(input_asn1_data.value_block.value_hex);
+ if(asn1.offset === (-1))
+ {
+ var _result = {
+ verified: false,
+ result: asn1.result
+ };
+
+ // #region Delete early added name of block
+ if(input_asn1_schema.hasOwnProperty('name'))
+ {
+ input_asn1_schema.name = input_asn1_schema.name.replace(/^\s+|\s+$/g, '');
+ if(input_asn1_schema.name !== "")
+ {
+ delete root[input_asn1_schema.name];
+ _result.name = input_asn1_schema.name;
+ }
+ }
+ // #endregion
+
+ return _result;
+ }
+ // #endregion
+
+ return in_window.org.pkijs.compareSchema(root, asn1.result, input_asn1_schema.primitive_schema);
+ }
+ else
+ return {
+ verified: true,
+ result: root
+ };
+ }
+ // #endregion
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.verifySchema =
+ function(input_buffer, input_schema)
+ {
+ // #region Initial check
+ if((input_schema instanceof Object) === false)
+ return {
+ verified: false,
+ result: { error: "Wrong ASN.1 schema type" }
+ };
+ // #endregion
+
+ // #region Decoding of raw ASN.1 data
+ var asn1 = in_window.org.pkijs.fromBER(input_buffer);
+ if(asn1.offset === (-1))
+ return {
+ verified: false,
+ result: asn1.result
+ };
+ // #endregion
+
+ // #region Compare ASN.1 struct with input schema
+ return in_window.org.pkijs.compareSchema(asn1.result, asn1.result, input_schema);
+ // #endregion
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Major function converting JSON to ASN.1 objects
+ //**************************************************************************************
+ in_window.org.pkijs.fromJSON =
+ function(json)
+ {
+ /// Converting from JSON to ASN.1 objects
+ /// JSON string or object to convert to ASN.1 objects
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+}
+)(typeof exports !== "undefined" ? exports : window);
\ No newline at end of file
diff --git a/express-server/node_modules/asn1js/org/pkijs/common.js b/express-server/node_modules/asn1js/org/pkijs/common.js
new file mode 100644
index 00000000..4d7b2e11
--- /dev/null
+++ b/express-server/node_modules/asn1js/org/pkijs/common.js
@@ -0,0 +1,1541 @@
+/*
+ * Copyright (c) 2014, GMO GlobalSign
+ * Copyright (c) 2015, Peculiar Ventures
+ * All rights reserved.
+ *
+ * Author 2014-2015, Yury Strozhevsky .
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ */
+(
+function(in_window)
+{
+ //**************************************************************************************
+ // #region Declaration of global variables
+ //**************************************************************************************
+ // #region "org" namespace
+ if(typeof in_window.org === "undefined")
+ in_window.org = {};
+ else
+ {
+ if(typeof in_window.org !== "object")
+ throw new Error("Name org already exists and it's not an object");
+ }
+ // #endregion
+
+ // #region "org.pkijs" namespace
+ if(typeof in_window.org.pkijs === "undefined")
+ in_window.org.pkijs = {};
+ else
+ {
+ if(typeof in_window.org.pkijs !== "object")
+ throw new Error("Name org.pkijs already exists and it's not an object" + " but " + (typeof in_window.org.pkijs));
+ }
+ // #endregion
+
+ // #region "local" namespace
+ var local = {};
+ // #endregion
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Settings for "crypto engine"
+ //**************************************************************************************
+ local.engine = {
+ name: "none",
+ crypto: null,
+ subtle: null
+ };
+
+ if(typeof window != "undefined")
+ {
+ if("crypto" in window)
+ {
+ var engineName = "webcrypto";
+ var cryptoObject = window.crypto;
+ var subtleObject = null;
+
+ // Apple Safari support
+ if("webkitSubtle" in window.crypto)
+ subtleObject = window.crypto.webkitSubtle;
+
+ if("subtle" in window.crypto)
+ subtleObject = window.crypto.subtle;
+
+ local.engine = {
+ name: engineName,
+ crypto: cryptoObject,
+ subtle: subtleObject
+ };
+ }
+ }
+ //**************************************************************************************
+ in_window.org.pkijs.setEngine =
+ function(name, crypto, subtle)
+ {
+ /// Setting the global "crypto engine" parameters
+ /// Auxiliary name for "crypto engine"
+ /// Object handling all root cryptographic requests (in fact currently it must handle only "getRandomValues")
+ /// Object handling all main cryptographic requests
+
+ local.engine = {
+ name: name,
+ crypto: crypto,
+ subtle: subtle
+ };
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getEngine =
+ function()
+ {
+ return local.engine;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+ // #region Declaration of common functions
+ //**************************************************************************************
+ in_window.org.pkijs.emptyObject =
+ function()
+ {
+ this.toJSON = function()
+ {
+ return {};
+ };
+ this.toSchema = function()
+ {
+ return {};
+ };
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getNames =
+ function(arg)
+ {
+ /// Get correct "names" array for all "schema" objects
+
+ var names = {};
+
+ if(arg instanceof Object)
+ names = (arg.names || {});
+
+ return names;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.inheriteObjectFields =
+ function(from)
+ {
+ for(var i in from.prototype)
+ {
+ if(typeof from.prototype[i] === "function")
+ continue;
+
+ this[i] = from.prototype[i];
+ }
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getUTCDate =
+ function(date)
+ {
+ /// Making UTC date from local date
+ /// Date to convert from
+
+ var current_date = date;
+ return new Date(current_date.getTime() + (current_date.getTimezoneOffset() * 60000));
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.padNumber =
+ function(input_number, full_length)
+ {
+ var str = input_number.toString(10);
+ var dif = full_length - str.length;
+
+ var padding = new Array(dif);
+ for(var i = 0; i < dif; i++)
+ padding[i] = '0';
+
+ var padding_string = padding.join('');
+
+ return padding_string.concat(str);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getValue =
+ function(args, item, default_value)
+ {
+ if(item in args)
+ return args[item];
+ else
+ return default_value;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.isEqual_view =
+ function(input_view1, input_view2)
+ {
+ /// Compare two Uint8Arrays
+ /// First Uint8Array for comparision
+ /// Second Uint8Array for comparision
+
+ if(input_view1.length !== input_view2.length)
+ return false;
+
+ for(var i = 0; i < input_view1.length; i++)
+ {
+ if(input_view1[i] != input_view2[i])
+ return false;
+ }
+
+ return true;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.isEqual_buffer =
+ function(input_buffer1, input_buffer2)
+ {
+ /// Compare two array buffers
+ /// First ArrayBuffer for comparision
+ /// Second ArrayBuffer for comparision
+
+ if(input_buffer1.byteLength != input_buffer2.byteLength)
+ return false;
+
+ var view1 = new Uint8Array(input_buffer1);
+ var view2 = new Uint8Array(input_buffer2);
+
+ return in_window.org.pkijs.isEqual_view(view1, view2);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.concat_buffers =
+ function(input_buf1, input_buf2)
+ {
+ /// Concatenate two ArrayBuffers
+ /// First ArrayBuffer (first part of concatenated array)
+ /// Second ArrayBuffer (second part of concatenated array)
+
+ var input_view1 = new Uint8Array(input_buf1);
+ var input_view2 = new Uint8Array(input_buf2);
+
+ var ret_buf = new ArrayBuffer(input_buf1.byteLength + input_buf2.byteLength);
+ var ret_view = new Uint8Array(ret_buf);
+
+ for(var i = 0; i < input_buf1.byteLength; i++)
+ ret_view[i] = input_view1[i];
+
+ for(var j = 0; j < input_buf2.byteLength; j++)
+ ret_view[input_buf1.byteLength + j] = input_view2[j];
+
+ return ret_buf;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.copyBuffer =
+ function(input_buffer)
+ {
+ var result = new ArrayBuffer(input_buffer.byteLength);
+
+ var resultView = new Uint8Array(result);
+ var inputView = new Uint8Array(input_buffer);
+
+ for(var i = 0; i < inputView.length; i++)
+ resultView[i] = inputView[i];
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getCrypto =
+ function()
+ {
+ var crypto_temp;
+
+ if(local.engine.subtle !== null)
+ crypto_temp = local.engine.subtle;
+
+ return crypto_temp;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.stringPrep =
+ function(input_string)
+ {
+ /// String preparation function. In a future here will be realization of algorithm from RFC4518.
+ /// JavaScript string. As soon as for each ASN.1 string type we have a specific transformation function here we will work with pure JavaScript string
+ /// Formated string
+
+ var result = input_string.replace(/^\s+|\s+$/g, ""); // Trim input string
+ result = result.replace(/\s+/g, " "); // Change all sequence of SPACE down to SPACE char
+ result = result.toLowerCase();
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.bufferToHexCodes =
+ function(input_buffer, input_offset, input_lenght)
+ {
+ var result = "";
+
+ var int_buffer = new Uint8Array(input_buffer, input_offset, input_lenght);
+
+ for(var i = 0; i < int_buffer.length; i++)
+ {
+ var str = int_buffer[i].toString(16).toUpperCase();
+ result = result + ((str.length === 1) ? "0" : "") + str;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.bufferFromHexCodes =
+ function(hexString)
+ {
+ /// Create an ArrayBuffer from string having hexdecimal codes
+ /// String to create ArrayBuffer from
+
+ // #region Initial variables
+ var stringLength = hexString.length;
+
+ var resultBuffer = new ArrayBuffer(stringLength >> 1);
+ var resultView = new Uint8Array(resultBuffer);
+
+ var hex_map = {};
+
+ hex_map['0'] = 0x00;
+ hex_map['1'] = 0x01;
+ hex_map['2'] = 0x02;
+ hex_map['3'] = 0x03;
+ hex_map['4'] = 0x04;
+ hex_map['5'] = 0x05;
+ hex_map['6'] = 0x06;
+ hex_map['7'] = 0x07;
+ hex_map['8'] = 0x08;
+ hex_map['9'] = 0x09;
+ hex_map['A'] = 0x0A;
+ hex_map['a'] = 0x0A;
+ hex_map['B'] = 0x0B;
+ hex_map['b'] = 0x0B;
+ hex_map['C'] = 0x0C;
+ hex_map['c'] = 0x0C;
+ hex_map['D'] = 0x0D;
+ hex_map['d'] = 0x0D;
+ hex_map['E'] = 0x0E;
+ hex_map['e'] = 0x0E;
+ hex_map['F'] = 0x0F;
+ hex_map['f'] = 0x0F;
+
+ var j = 0;
+ var temp = 0x00;
+ // #endregion
+
+ // #region Convert char-by-char
+ for(var i = 0; i < stringLength; i++)
+ {
+ if(!(i % 2))
+ temp = hex_map[hexString.charAt(i)] << 4;
+ else
+ {
+ temp |= hex_map[hexString.charAt(i)];
+
+ resultView[j] = temp;
+ j++;
+ }
+ }
+ // #endregion
+
+ return resultBuffer;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getRandomValues =
+ function(view)
+ {
+ /// New array which gives a length for random value
+
+ if(local.engine.crypto !== null)
+ return local.engine.crypto.getRandomValues(view);
+ else
+ throw new Error("No support for Web Cryptography API");
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getAlgorithmParameters =
+ function(algorithmName, operation)
+ {
+ /// Algorithm name to get common parameters for
+ /// Kind of operation: "sign", "encrypt", "generatekey", "importkey", "exportkey", "verify"
+
+ var result = {
+ algorithm: {},
+ usages: []
+ };
+
+ switch(algorithmName.toUpperCase())
+ {
+ case "RSASSA-PKCS1-V1_5":
+ switch(operation.toLowerCase())
+ {
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "RSASSA-PKCS1-v1_5",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "verify":
+ case "sign":
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only
+ };
+ break;
+ case "exportkey":
+ default:
+ return {
+ algorithm: {
+ name: "RSASSA-PKCS1-v1_5"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "RSA-PSS":
+ switch(operation.toLowerCase())
+ {
+ case "sign":
+ case "verify":
+ result = {
+ algorithm: {
+ name: "RSA-PSS",
+ hash: {
+ name: "SHA-1"
+ },
+ saltLength: 20
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "RSA-PSS",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {
+ name: "SHA-1"
+ }
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "RSA-PSS",
+ hash: {
+ name: "SHA-1"
+ }
+ },
+ usages: ["verify"] // For importKey("pkcs8") usage must be "sign" only
+ };
+ break;
+ case "exportkey":
+ default:
+ return {
+ algorithm: {
+ name: "RSA-PSS"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "RSA-OAEP":
+ switch(operation.toLowerCase())
+ {
+ case "encrypt":
+ case "decrypt":
+ result = {
+ algorithm: {
+ name: "RSA-OAEP"
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ break;
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "RSA-OAEP",
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "RSA-OAEP",
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["encrypt"] // encrypt for "spki" and decrypt for "pkcs8"
+ };
+ break;
+ case "exportkey":
+ default:
+ return {
+ algorithm: {
+ name: "RSA-OAEP"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "ECDSA":
+ switch(operation.toLowerCase())
+ {
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "ECDSA",
+ namedCurve: "P-256"
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "importkey":
+ result = {
+ algorithm: {
+ name: "ECDSA",
+ namedCurve: "P-256"
+ },
+ usages: ["verify"] // "sign" for "pkcs8"
+ };
+ break;
+ case "verify":
+ case "sign":
+ result = {
+ algorithm: {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["sign"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "ECDSA"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "ECDH":
+ switch(operation.toLowerCase())
+ {
+ case "exportkey":
+ case "importkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "ECDH",
+ namedCurve: "P-256"
+ },
+ usages: ["deriveKey", "deriveBits"]
+ };
+ break;
+ case "derivekey":
+ case "derivebits":
+ result = {
+ algorithm: {
+ name: "ECDH",
+ namedCurve: "P-256",
+ public: [] // Must be a "publicKey"
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "ECDH"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-CTR":
+ switch(operation.toLowerCase())
+ {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "AES-CTR",
+ length: 256
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "decrypt":
+ case "encrypt":
+ result = {
+ algorithm: {
+ name: "AES-CTR",
+ counter: new Uint8Array(16),
+ length: 10
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-CTR"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-CBC":
+ switch(operation.toLowerCase())
+ {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "AES-CBC",
+ length: 256
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "decrypt":
+ case "encrypt":
+ result = {
+ algorithm: {
+ name: "AES-CBC",
+ iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-CBC"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-GCM":
+ switch(operation.toLowerCase())
+ {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "AES-GCM",
+ length: 256
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ case "decrypt":
+ case "encrypt":
+ result = {
+ algorithm: {
+ name: "AES-GCM",
+ iv: in_window.org.pkijs.getRandomValues(new Uint8Array(16)) // For "decrypt" the value should be replaced with value got on "encrypt" step
+ },
+ usages: ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-GCM"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "AES-KW":
+ switch(operation.toLowerCase())
+ {
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ case "wrapkey":
+ case "unwrapkey":
+ result = {
+ algorithm: {
+ name: "AES-KW",
+ length: 256
+ },
+ usages: ["wrapKey", "unwrapKey"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "AES-KW"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "HMAC":
+ switch(operation.toLowerCase())
+ {
+ case "sign":
+ case "verify":
+ result = {
+ algorithm: {
+ name: "HMAC"
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ case "importkey":
+ case "exportkey":
+ case "generatekey":
+ result = {
+ algorithm: {
+ name: "HMAC",
+ length: 32,
+ hash: {
+ name: "SHA-256"
+ }
+ },
+ usages: ["sign", "verify"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "HMAC"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "HKDF":
+ switch(operation.toLowerCase())
+ {
+ case "derivekey":
+ result = {
+ algorithm: {
+ name: "HKDF",
+ hash: "SHA-256",
+ salt: new Uint8Array(),
+ info: new Uint8Array()
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "HKDF"
+ },
+ usages: []
+ };
+ }
+ break;
+ case "PBKDF2":
+ switch(operation.toLowerCase())
+ {
+ case "derivekey":
+ result = {
+ algorithm: {
+ name: "PBKDF2",
+ hash: { name: "SHA-256" },
+ salt: new Uint8Array(),
+ iterations: 1000
+ },
+ usages: ["encrypt", "decrypt"]
+ };
+ break;
+ default:
+ return {
+ algorithm: {
+ name: "PBKDF2"
+ },
+ usages: []
+ };
+ }
+ break;
+ default:
+ ;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getOIDByAlgorithm =
+ function(algorithm)
+ {
+ /// Get OID for each specific WebCrypto algorithm
+ /// WebCrypto algorithm
+
+ var result = "";
+
+ switch(algorithm.name.toUpperCase())
+ {
+ case "RSASSA-PKCS1-V1_5":
+ switch(algorithm.hash.name.toUpperCase())
+ {
+ case "SHA-1":
+ result = "1.2.840.113549.1.1.5";
+ break;
+ case "SHA-256":
+ result = "1.2.840.113549.1.1.11";
+ break;
+ case "SHA-384":
+ result = "1.2.840.113549.1.1.12";
+ break;
+ case "SHA-512":
+ result = "1.2.840.113549.1.1.13";
+ break;
+ default:;
+ }
+ break;
+ case "RSA-PSS":
+ result = "1.2.840.113549.1.1.10";
+ break;
+ case "RSA-OAEP":
+ result = "1.2.840.113549.1.1.7";
+ break;
+ case "ECDSA":
+ switch(algorithm.hash.name.toUpperCase())
+ {
+ case "SHA-1":
+ result = "1.2.840.10045.4.1";
+ break;
+ case "SHA-256":
+ result = "1.2.840.10045.4.3.2";
+ break;
+ case "SHA-384":
+ result = "1.2.840.10045.4.3.3";
+ break;
+ case "SHA-512":
+ result = "1.2.840.10045.4.3.4";
+ break;
+ default:;
+ }
+ break;
+ case "ECDH":
+ switch(algorithm.kdf.toUpperCase()) // Non-standard addition - hash algorithm of KDF function
+ {
+ case "SHA-1":
+ result = "1.3.133.16.840.63.0.2"; // dhSinglePass-stdDH-sha1kdf-scheme
+ break;
+ case "SHA-256":
+ result = "1.3.132.1.11.1"; // dhSinglePass-stdDH-sha256kdf-scheme
+ break;
+ case "SHA-384":
+ result = "1.3.132.1.11.2"; // dhSinglePass-stdDH-sha384kdf-scheme
+ break;
+ case "SHA-512":
+ result = "1.3.132.1.11.3"; // dhSinglePass-stdDH-sha512kdf-scheme
+ break;
+ default:;
+ }
+ break;
+ case "AES-CTR":
+ break;
+ case "AES-CBC":
+ switch(algorithm.length)
+ {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.2";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.22";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.42";
+ break;
+ default:;
+ }
+ break;
+ case "AES-CMAC":
+ break;
+ case "AES-GCM":
+ switch(algorithm.length)
+ {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.6";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.26";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.46";
+ break;
+ default:;
+ }
+ break;
+ case "AES-CFB":
+ switch(algorithm.length)
+ {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.4";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.24";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.44";
+ break;
+ default:;
+ }
+ break;
+ case "AES-KW":
+ switch(algorithm.length)
+ {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.5";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.25";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.45";
+ break;
+ default:;
+ }
+ break;
+ case "HMAC":
+ switch(algorithm.hash.name.toUpperCase())
+ {
+ case "SHA-1":
+ result = "1.2.840.113549.2.7";
+ break;
+ case "SHA-256":
+ result = "1.2.840.113549.2.9";
+ break;
+ case "SHA-384":
+ result = "1.2.840.113549.2.10";
+ break;
+ case "SHA-512":
+ result = "1.2.840.113549.2.11";
+ break;
+ default:;
+ }
+ break;
+ case "DH":
+ result = "1.2.840.113549.1.9.16.3.5";
+ break;
+ case "SHA-1":
+ result = "1.3.14.3.2.26";
+ break;
+ case "SHA-256":
+ result = "2.16.840.1.101.3.4.2.1";
+ break;
+ case "SHA-384":
+ result = "2.16.840.1.101.3.4.2.2";
+ break;
+ case "SHA-512":
+ result = "2.16.840.1.101.3.4.2.3";
+ break;
+ case "CONCAT":
+ break;
+ case "HKDF":
+ break;
+ case "PBKDF2":
+ result = "1.2.840.113549.1.5.12";
+ break;
+ // #region Special case - OIDs for ECC curves
+ case "P-256":
+ result = "1.2.840.10045.3.1.7";
+ break;
+ case "P-384":
+ result = "1.3.132.0.34";
+ break;
+ case "P-521":
+ result = "1.3.132.0.35";
+ break;
+ // #endregion
+ default:;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getAlgorithmByOID =
+ function(oid)
+ {
+ /// Get WebCrypto algorithm by wel-known OID
+ /// Wel-known OID to search for
+
+ var result = {};
+
+ switch(oid)
+ {
+ case "1.2.840.113549.1.1.5":
+ result = {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-1"
+ }
+ };
+ break;
+ case "1.2.840.113549.1.1.11":
+ result = {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-256"
+ }
+ };
+ break;
+ case "1.2.840.113549.1.1.12":
+ result = {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-384"
+ }
+ };
+ break;
+ case "1.2.840.113549.1.1.13":
+ result = {
+ name: "RSASSA-PKCS1-v1_5",
+ hash: {
+ name: "SHA-512"
+ }
+ };
+ break;
+ case "1.2.840.113549.1.1.10":
+ result = {
+ name: "RSA-PSS"
+ };
+ break;
+ case "1.2.840.113549.1.1.7":
+ result = {
+ name: "RSA-OAEP"
+ };
+ break;
+ case "1.2.840.10045.4.1":
+ result = {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-1"
+ }
+ };
+ break;
+ case "1.2.840.10045.4.3.2":
+ result = {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-256"
+ }
+ };
+ break;
+ case "1.2.840.10045.4.3.3":
+ result = {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-384"
+ }
+ };
+ break;
+ case "1.2.840.10045.4.3.4":
+ result = {
+ name: "ECDSA",
+ hash: {
+ name: "SHA-512"
+ }
+ };
+ break;
+ case "1.3.133.16.840.63.0.2":
+ result = {
+ name: "ECDH",
+ kdf: "SHA-1"
+ };
+ break;
+ case "1.3.132.1.11.1":
+ result = {
+ name: "ECDH",
+ kdf: "SHA-256"
+ };
+ break;
+ case "1.3.132.1.11.2":
+ result = {
+ name: "ECDH",
+ kdf: "SHA-384"
+ };
+ break;
+ case "1.3.132.1.11.3":
+ result = {
+ name: "ECDH",
+ kdf: "SHA-512"
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.2":
+ result = {
+ name: "AES-CBC",
+ length: 128
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.22":
+ result = {
+ name: "AES-CBC",
+ length: 192
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.42":
+ result = {
+ name: "AES-CBC",
+ length: 256
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.6":
+ result = {
+ name: "AES-GCM",
+ length: 128
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.26":
+ result = {
+ name: "AES-GCM",
+ length: 192
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.46":
+ result = {
+ name: "AES-GCM",
+ length: 256
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.4":
+ result = {
+ name: "AES-CFB",
+ length: 128
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.24":
+ result = {
+ name: "AES-CFB",
+ length: 192
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.44":
+ result = {
+ name: "AES-CFB",
+ length: 256
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.5":
+ result = {
+ name: "AES-KW",
+ length: 128
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.25":
+ result = {
+ name: "AES-KW",
+ length: 192
+ };
+ break;
+ case "2.16.840.1.101.3.4.1.45":
+ result = {
+ name: "AES-KW",
+ length: 256
+ };
+ break;
+ case "1.2.840.113549.2.7":
+ result = {
+ name: "HMAC",
+ hash: {
+ name: "SHA-1"
+ }
+ };
+ break;
+ case "1.2.840.113549.2.9":
+ result = {
+ name: "HMAC",
+ hash: {
+ name: "SHA-256"
+ }
+ };
+ break;
+ case "1.2.840.113549.2.10":
+ result = {
+ name: "HMAC",
+ hash: {
+ name: "SHA-384"
+ }
+ };
+ break;
+ case "1.2.840.113549.2.11":
+ result = {
+ name: "HMAC",
+ hash: {
+ name: "SHA-512"
+ }
+ };
+ break;
+ case "1.2.840.113549.1.9.16.3.5":
+ result = {
+ name: "DH"
+ };
+ break;
+ case "1.3.14.3.2.26":
+ result = {
+ name: "SHA-1"
+ };
+ break;
+ case "2.16.840.1.101.3.4.2.1":
+ result = {
+ name: "SHA-256"
+ };
+ break;
+ case "2.16.840.1.101.3.4.2.2":
+ result = {
+ name: "SHA-384"
+ };
+ break;
+ case "2.16.840.1.101.3.4.2.3":
+ result = {
+ name: "SHA-512"
+ };
+ break;
+ case "1.2.840.113549.1.5.12":
+ result = {
+ name: "PBKDF2"
+ };
+ break;
+ // #region Special case - OIDs for ECC curves
+ case "1.2.840.10045.3.1.7":
+ result = {
+ name: "P-256"
+ };
+ break;
+ case "1.3.132.0.34":
+ result = {
+ name: "P-384"
+ };
+ break;
+ case "1.3.132.0.35":
+ result = {
+ name: "P-521"
+ };
+ break;
+ // #endregion
+ default:;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getHashAlgorithm =
+ function(signatureAlgorithm)
+ {
+ /// Getting hash algorithm by signature algorithm
+ /// Signature algorithm
+
+ var result = "";
+
+ switch(signatureAlgorithm.algorithm_id)
+ {
+ case "1.2.840.10045.4.1": // ecdsa-with-SHA1
+ case "1.2.840.113549.1.1.5":
+ result = "SHA-1";
+ break;
+ case "1.2.840.10045.4.3.2": // ecdsa-with-SHA256
+ case "1.2.840.113549.1.1.11":
+ result = "SHA-256";
+ break;
+ case "1.2.840.10045.4.3.3": // ecdsa-with-SHA384
+ case "1.2.840.113549.1.1.12":
+ result = "SHA-384";
+ break;
+ case "1.2.840.10045.4.3.4": // ecdsa-with-SHA512
+ case "1.2.840.113549.1.1.13":
+ result = "SHA-512";
+ break;
+ case "1.2.840.113549.1.1.10": // RSA-PSS
+ {
+ var params;
+
+ try
+ {
+ params = new in_window.org.pkijs.simpl.x509.RSASSA_PSS_params({ schema: signatureAlgorithm.algorithm_params });
+ if("hashAlgorithm" in params)
+ {
+ var algorithm = in_window.org.pkijs.getAlgorithmByOID(params.hashAlgorithm.algorithm_id);
+ if(("name" in algorithm) === false)
+ return "";
+
+ result = algorithm.name;
+ }
+ else
+ result = "SHA-1";
+ }
+ catch(ex)
+ {
+ }
+ }
+ break;
+ default:;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.createCMSECDSASignature =
+ function(signatureBuffer)
+ {
+ /// Create CMS ECDSA signature from WebCrypto ECDSA signature
+ /// WebCrypto result of "sign" function
+
+ // #region Initial check for correct length
+ if((signatureBuffer.byteLength % 2) != 0)
+ return new ArrayBuffer(0);
+ // #endregion
+
+ // #region Initial variables
+ var i = 0;
+ var length = signatureBuffer.byteLength / 2; // There are two equal parts inside incoming ArrayBuffer
+
+ var signatureView = new Uint8Array(signatureBuffer);
+
+ var r_buffer = new ArrayBuffer(length);
+ var r_view = new Uint8Array(r_buffer);
+ var r_corrected_buffer;
+ var r_corrected_view;
+
+ var s_buffer = new ArrayBuffer(length);
+ var s_view = new Uint8Array(s_buffer);
+ var s_corrected_buffer;
+ var s_corrected_view;
+ // #endregion
+
+ // #region Get "r" part of ECDSA signature
+ for(; i < length; i++)
+ r_view[i] = signatureView[i];
+
+ if(r_view[0] & 0x80)
+ {
+ r_corrected_buffer = new ArrayBuffer(length + 1);
+ r_corrected_view = new Uint8Array(r_corrected_buffer);
+
+ r_corrected_view[0] = 0x00;
+
+ for(var j = 0; j < length; j++)
+ r_corrected_view[j + 1] = r_view[j];
+ }
+ else
+ {
+ r_corrected_buffer = r_buffer;
+ r_corrected_view = r_view;
+ }
+ // #endregion
+
+ // #region Get "s" part of ECDSA signature
+ for(; i < signatureBuffer.byteLength; i++)
+ s_view[i - length] = signatureView[i];
+
+
+ if(s_view[0] & 0x80)
+ {
+ s_corrected_buffer = new ArrayBuffer(length + 1);
+ s_corrected_view = new Uint8Array(s_corrected_buffer);
+
+ s_corrected_view[0] = 0x00;
+
+ for(var j = 0; j < length; j++)
+ s_corrected_view[j + 1] = s_view[j];
+ }
+ else
+ {
+ s_corrected_buffer = s_buffer;
+ s_corrected_view = s_view;
+ }
+ // #endregion
+
+ // #region Create ASN.1 structure of CMS ECDSA signature
+ var r_integer = new in_window.org.pkijs.asn1.INTEGER();
+ r_integer.value_block.is_hex_only = true;
+ r_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(r_corrected_buffer);
+
+ var s_integer = new in_window.org.pkijs.asn1.INTEGER();
+ s_integer.value_block.is_hex_only = true;
+ s_integer.value_block.value_hex = in_window.org.pkijs.copyBuffer(s_corrected_buffer);
+
+ var asn1 = new in_window.org.pkijs.asn1.SEQUENCE({
+ value: [
+ r_integer,
+ s_integer
+ ]
+ });
+ // #endregion
+
+ return asn1.toBER(false);
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.createECDSASignatureFromCMS =
+ function(cmsSignature)
+ {
+ /// Create a single ArrayBuffer from CMS ECDSA signature
+ /// ASN.1 SEQUENCE contains CMS ECDSA signature
+
+ // #region Initial variables
+ var length = 0;
+
+ var r_start = 0;
+ var s_start = 0;
+
+ var r_length = cmsSignature.value_block.value[0].value_block.value_hex.byteLength;
+ var s_length = cmsSignature.value_block.value[1].value_block.value_hex.byteLength;
+ // #endregion
+
+ // #region Get length of final "ArrayBuffer"
+ var r_view = new Uint8Array(cmsSignature.value_block.value[0].value_block.value_hex);
+ if((r_view[0] === 0x00) && (r_view[1] & 0x80))
+ {
+ length = r_length - 1;
+ r_start = 1;
+ }
+ else
+ length = r_length;
+
+ var s_view = new Uint8Array(cmsSignature.value_block.value[1].value_block.value_hex);
+ if((s_view[0] === 0x00) && (s_view[1] & 0x80))
+ {
+ length += s_length - 1;
+ s_start = 1;
+ }
+ else
+ length += s_length;
+ // #endregion
+
+ // #region Copy values from CMS ECDSA signature
+ var result = new ArrayBuffer(length);
+ var result_view = new Uint8Array(result);
+
+ for(var i = r_start; i < r_length; i++)
+ result_view[i - r_start] = r_view[i];
+
+ for(var i = s_start; i < s_length; i++)
+ result_view[i - s_start + r_length - r_start] = s_view[i];
+ // #endregion
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getEncryptionAlgorithm =
+ function(algorithm)
+ {
+ /// Get encryption algorithm OID by WebCrypto algorithm's object
+ /// WebCrypto algorithm object
+
+ var result = "";
+
+ switch(algorithm.name.toUpperCase())
+ {
+ case "AES-CBC":
+ switch(algorithm.length)
+ {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.2";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.22";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.42";
+ break;
+ default:;
+ }
+ break;
+ case "AES-GCM":
+ switch(algorithm.length)
+ {
+ case 128:
+ result = "2.16.840.1.101.3.4.1.6";
+ break;
+ case 192:
+ result = "2.16.840.1.101.3.4.1.26";
+ break;
+ case 256:
+ result = "2.16.840.1.101.3.4.1.46";
+ break;
+ default:;
+ }
+ break;
+ default:;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ in_window.org.pkijs.getAlgorithmByEncryptionOID =
+ function(oid)
+ {
+ /// Get encryption algorithm name by OID
+ /// OID of encryption algorithm
+
+ var result = "";
+
+ switch(oid)
+ {
+ case "2.16.840.1.101.3.4.1.2":
+ case "2.16.840.1.101.3.4.1.22":
+ case "2.16.840.1.101.3.4.1.42":
+ result = "AES-CBC";
+ break;
+ case "2.16.840.1.101.3.4.1.6":
+ case "2.16.840.1.101.3.4.1.26":
+ case "2.16.840.1.101.3.4.1.46":
+ result = "AES-GCM";
+ break;
+ default:;
+ }
+
+ return result;
+ };
+ //**************************************************************************************
+ // #endregion
+ //**************************************************************************************
+}
+)(typeof exports !== "undefined" ? exports : window);
\ No newline at end of file
diff --git a/express-server/node_modules/asn1js/package.json b/express-server/node_modules/asn1js/package.json
new file mode 100644
index 00000000..4386aa36
--- /dev/null
+++ b/express-server/node_modules/asn1js/package.json
@@ -0,0 +1,94 @@
+{
+ "_args": [
+ [
+ "asn1js@^1.2.12",
+ "/nodeapps/https-test/greenlock-express.js/node_modules/certpem"
+ ]
+ ],
+ "_from": "asn1js@>=1.2.12 <2.0.0",
+ "_id": "asn1js@1.2.12",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/asn1js",
+ "_nodeVersion": "5.8.0",
+ "_npmOperationalInternal": {
+ "host": "packages-16-east.internal.npmjs.com",
+ "tmp": "tmp/asn1js-1.2.12.tgz_1460549801979_0.2164379085879773"
+ },
+ "_npmUser": {
+ "email": "yury@strozhevsky.com",
+ "name": "yury.strozhevsky"
+ },
+ "_npmVersion": "3.7.3",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "asn1js",
+ "raw": "asn1js@^1.2.12",
+ "rawSpec": "^1.2.12",
+ "scope": null,
+ "spec": ">=1.2.12 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/certpem"
+ ],
+ "_resolved": "https://registry.npmjs.org/asn1js/-/asn1js-1.2.12.tgz",
+ "_shasum": "87d5ee797596ae2d2a3cb0247220dc42ffc3f211",
+ "_shrinkwrap": null,
+ "_spec": "asn1js@^1.2.12",
+ "_where": "/nodeapps/https-test/greenlock-express.js/node_modules/certpem",
+ "author": {
+ "email": "yury@strozhevsky.com",
+ "name": "Yury Strozhevsky"
+ },
+ "bugs": {
+ "url": "https://github.com/GlobalSign/ASN1.js/issues"
+ },
+ "contributors": [
+ {
+ "name": "Ryan Hurst",
+ "email": "rmh@unmitigatedrisk.com"
+ }
+ ],
+ "dependencies": {},
+ "description": "ASN1js is a pure JavaScript library implementing this standard. ASN.1 is the basis of all X.509 related data structures and numerous other protocols used on the web",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "shasum": "87d5ee797596ae2d2a3cb0247220dc42ffc3f211",
+ "tarball": "https://registry.npmjs.org/asn1js/-/asn1js-1.2.12.tgz"
+ },
+ "gitHead": "766534d2109c0e9ccc72d9b094eef50efe007925",
+ "homepage": "https://github.com/GlobalSign/ASN1.js#readme",
+ "keywords": [
+ "asn.1",
+ "asn1",
+ "ber",
+ "bitstring",
+ "bmpstring",
+ "der",
+ "generalizedtime",
+ "octetstring",
+ "sequence",
+ "set",
+ "universalstring",
+ "utctime",
+ "utf8string"
+ ],
+ "main": "org/pkijs/asn1.js",
+ "maintainers": [
+ {
+ "name": "yury.strozhevsky",
+ "email": "yury@strozhevsky.com"
+ }
+ ],
+ "name": "asn1js",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/GlobalSign/ASN1.js.git"
+ },
+ "scripts": {},
+ "version": "1.2.12"
+}
diff --git a/express-server/node_modules/async-limiter/.travis.yml b/express-server/node_modules/async-limiter/.travis.yml
new file mode 100644
index 00000000..6cf4a7ad
--- /dev/null
+++ b/express-server/node_modules/async-limiter/.travis.yml
@@ -0,0 +1,7 @@
+language: node_js
+node_js:
+ - "6"
+ - "node"
+script: npm run travis
+cache:
+ yarn: true
diff --git a/express-server/node_modules/async-limiter/LICENSE b/express-server/node_modules/async-limiter/LICENSE
new file mode 100644
index 00000000..9c91fb26
--- /dev/null
+++ b/express-server/node_modules/async-limiter/LICENSE
@@ -0,0 +1,8 @@
+The MIT License (MIT)
+Copyright (c) 2017 Samuel Reed
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/express-server/node_modules/async-limiter/coverage/coverage.json b/express-server/node_modules/async-limiter/coverage/coverage.json
new file mode 100644
index 00000000..5b4a3584
--- /dev/null
+++ b/express-server/node_modules/async-limiter/coverage/coverage.json
@@ -0,0 +1 @@
+{"/Users/samuelreed/git/forks/async-throttle/index.js":{"path":"/Users/samuelreed/git/forks/async-throttle/index.js","s":{"1":1,"2":7,"3":1,"4":6,"5":6,"6":6,"7":6,"8":6,"9":6,"10":1,"11":1,"12":3,"13":13,"14":13,"15":13,"16":1,"17":19,"18":1,"19":45,"20":6,"21":39,"22":13,"23":13,"24":13,"25":13,"26":39,"27":18,"28":6,"29":6,"30":1,"31":6,"32":6,"33":6,"34":1,"35":13,"36":13,"37":1},"b":{"1":[1,6],"2":[6,5],"3":[6,5],"4":[6,39],"5":[13,26],"6":[18,21],"7":[6,0]},"f":{"1":7,"2":3,"3":13,"4":19,"5":45,"6":6,"7":13},"fnMap":{"1":{"name":"Queue","line":3,"loc":{"start":{"line":3,"column":0},"end":{"line":3,"column":24}}},"2":{"name":"(anonymous_2)","line":22,"loc":{"start":{"line":22,"column":24},"end":{"line":22,"column":41}}},"3":{"name":"(anonymous_3)","line":23,"loc":{"start":{"line":23,"column":28},"end":{"line":23,"column":39}}},"4":{"name":"(anonymous_4)","line":31,"loc":{"start":{"line":31,"column":7},"end":{"line":31,"column":18}}},"5":{"name":"(anonymous_5)","line":36,"loc":{"start":{"line":36,"column":23},"end":{"line":36,"column":34}}},"6":{"name":"(anonymous_6)","line":55,"loc":{"start":{"line":55,"column":25},"end":{"line":55,"column":38}}},"7":{"name":"done","line":62,"loc":{"start":{"line":62,"column":0},"end":{"line":62,"column":16}}}},"statementMap":{"1":{"start":{"line":3,"column":0},"end":{"line":14,"column":1}},"2":{"start":{"line":4,"column":2},"end":{"line":6,"column":3}},"3":{"start":{"line":5,"column":4},"end":{"line":5,"column":30}},"4":{"start":{"line":8,"column":2},"end":{"line":8,"column":26}},"5":{"start":{"line":9,"column":2},"end":{"line":9,"column":53}},"6":{"start":{"line":10,"column":2},"end":{"line":10,"column":19}},"7":{"start":{"line":11,"column":2},"end":{"line":11,"column":17}},"8":{"start":{"line":12,"column":2},"end":{"line":12,"column":16}},"9":{"start":{"line":13,"column":2},"end":{"line":13,"column":31}},"10":{"start":{"line":16,"column":0},"end":{"line":20,"column":2}},"11":{"start":{"line":22,"column":0},"end":{"line":28,"column":3}},"12":{"start":{"line":23,"column":2},"end":{"line":27,"column":4}},"13":{"start":{"line":24,"column":4},"end":{"line":24,"column":75}},"14":{"start":{"line":25,"column":4},"end":{"line":25,"column":16}},"15":{"start":{"line":26,"column":4},"end":{"line":26,"column":24}},"16":{"start":{"line":30,"column":0},"end":{"line":34,"column":3}},"17":{"start":{"line":32,"column":4},"end":{"line":32,"column":43}},"18":{"start":{"line":36,"column":0},"end":{"line":53,"column":2}},"19":{"start":{"line":37,"column":2},"end":{"line":39,"column":3}},"20":{"start":{"line":38,"column":4},"end":{"line":38,"column":11}},"21":{"start":{"line":40,"column":2},"end":{"line":45,"column":3}},"22":{"start":{"line":41,"column":4},"end":{"line":41,"column":32}},"23":{"start":{"line":42,"column":4},"end":{"line":42,"column":19}},"24":{"start":{"line":43,"column":4},"end":{"line":43,"column":20}},"25":{"start":{"line":44,"column":4},"end":{"line":44,"column":16}},"26":{"start":{"line":47,"column":2},"end":{"line":52,"column":3}},"27":{"start":{"line":48,"column":4},"end":{"line":51,"column":5}},"28":{"start":{"line":49,"column":6},"end":{"line":49,"column":30}},"29":{"start":{"line":50,"column":6},"end":{"line":50,"column":27}},"30":{"start":{"line":55,"column":0},"end":{"line":60,"column":2}},"31":{"start":{"line":56,"column":2},"end":{"line":59,"column":3}},"32":{"start":{"line":57,"column":4},"end":{"line":57,"column":22}},"33":{"start":{"line":58,"column":4},"end":{"line":58,"column":16}},"34":{"start":{"line":62,"column":0},"end":{"line":65,"column":1}},"35":{"start":{"line":63,"column":2},"end":{"line":63,"column":17}},"36":{"start":{"line":64,"column":2},"end":{"line":64,"column":14}},"37":{"start":{"line":67,"column":0},"end":{"line":67,"column":23}}},"branchMap":{"1":{"line":4,"type":"if","locations":[{"start":{"line":4,"column":2},"end":{"line":4,"column":2}},{"start":{"line":4,"column":2},"end":{"line":4,"column":2}}]},"2":{"line":8,"type":"binary-expr","locations":[{"start":{"line":8,"column":12},"end":{"line":8,"column":19}},{"start":{"line":8,"column":23},"end":{"line":8,"column":25}}]},"3":{"line":9,"type":"binary-expr","locations":[{"start":{"line":9,"column":21},"end":{"line":9,"column":40}},{"start":{"line":9,"column":44},"end":{"line":9,"column":52}}]},"4":{"line":37,"type":"if","locations":[{"start":{"line":37,"column":2},"end":{"line":37,"column":2}},{"start":{"line":37,"column":2},"end":{"line":37,"column":2}}]},"5":{"line":40,"type":"if","locations":[{"start":{"line":40,"column":2},"end":{"line":40,"column":2}},{"start":{"line":40,"column":2},"end":{"line":40,"column":2}}]},"6":{"line":47,"type":"if","locations":[{"start":{"line":47,"column":2},"end":{"line":47,"column":2}},{"start":{"line":47,"column":2},"end":{"line":47,"column":2}}]},"7":{"line":56,"type":"if","locations":[{"start":{"line":56,"column":2},"end":{"line":56,"column":2}},{"start":{"line":56,"column":2},"end":{"line":56,"column":2}}]}}}}
\ No newline at end of file
diff --git a/express-server/node_modules/async-limiter/coverage/lcov-report/async-throttle/index.html b/express-server/node_modules/async-limiter/coverage/lcov-report/async-throttle/index.html
new file mode 100644
index 00000000..198882b4
--- /dev/null
+++ b/express-server/node_modules/async-limiter/coverage/lcov-report/async-throttle/index.html
@@ -0,0 +1,73 @@
+
+
+
+ Code coverage report for async-throttle/
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/express-server/node_modules/async-limiter/coverage/lcov-report/prettify.css b/express-server/node_modules/async-limiter/coverage/lcov-report/prettify.css
new file mode 100644
index 00000000..b317a7cd
--- /dev/null
+++ b/express-server/node_modules/async-limiter/coverage/lcov-report/prettify.css
@@ -0,0 +1 @@
+.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
diff --git a/express-server/node_modules/async-limiter/coverage/lcov-report/prettify.js b/express-server/node_modules/async-limiter/coverage/lcov-report/prettify.js
new file mode 100644
index 00000000..ef51e038
--- /dev/null
+++ b/express-server/node_modules/async-limiter/coverage/lcov-report/prettify.js
@@ -0,0 +1 @@
+window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^`
+ * `http://localhost.pplwink.com:8080/';URL=http://example.com`
+ * `http://localhost.pplwink.com:8080/;URL=http://example.com`
diff --git a/express-server/node_modules/redirect-https/example.js b/express-server/node_modules/redirect-https/example.js
new file mode 100644
index 00000000..239c0189
--- /dev/null
+++ b/express-server/node_modules/redirect-https/example.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var http = require('http');
+var server = http.createServer();
+var port = process.argv[2] || 8080;
+
+server.on('request', require('./')({
+ port: 8443
+, body: 'Redirecting to {{HTML_URL}}'
+, trustProxy: true // default is false
+}));
+
+server.listen(port, function () {
+ console.log('Listening on http://localhost.daplie.com:' + server.address().port);
+});
diff --git a/express-server/node_modules/redirect-https/index.js b/express-server/node_modules/redirect-https/index.js
new file mode 100644
index 00000000..e3f3b9a2
--- /dev/null
+++ b/express-server/node_modules/redirect-https/index.js
@@ -0,0 +1,97 @@
+'use strict';
+
+module.exports = function (opts) {
+ var escapeHtml = require('escape-html');
+
+ if (!opts) {
+ opts = {};
+ }
+ if (!isFinite(opts.port)) {
+ opts.port = 443;
+ }
+ if (!opts.browsers) {
+ opts.browsers = 301;
+ }
+ if (!opts.apis) {
+ opts.apis = 'meta';
+ }
+ if (!Array.isArray(opts.paths)) {
+ opts.paths = [ { match: '/' } ];
+ }
+ if (!('body' in opts)) {
+ opts.body = "";
+ }
+ opts.body = opts.body.replace(/{{\s+PORT\s+}}/ig, opts.port);
+
+ return function (req, res, next) {
+ if (req.connection.encrypted
+ || 'https' === req.protocol
+ || (opts.trustProxy && 'https' === req.headers['x-forwarded-proto'])
+ ) {
+ next();
+ return;
+ }
+
+ var url = (req.originalUrl || req.url);
+ // We don't want chrome showing the "Not Secure" badge during the redirect.
+ var probablyBrowser = (0 === (req.headers['user-agent']||'').indexOf('Mozilla/'));
+ // But we don't want devs, APIs, or Bots to accidentally browse insecure.
+ var redirect = probablyBrowser ? opts.browsers : opts.apis;
+ var host = req.headers.host || '';
+ if (!/:\d+/.test(host) && 443 !== opts.port) {
+ // we are using standard port 80, but we aren't using standard port 443
+ host += ':80';
+ }
+ var newLocation = 'https://'
+ + host.replace(/:\d+/, ':' + opts.port) + url
+ ;
+
+ //var encodedLocation = encodeURI(newLocation);
+ var escapedLocation = escapeHtml(newLocation);
+ var decodedLocation;
+ try {
+ decodedLocation = decodeURIComponent(newLocation);
+ } catch(e) {
+ decodedLocation = newLocation; // "#/error/?error_message=" + e.toString();
+ }
+
+ var body = opts.body
+ .replace(/{{\s*HTML_URL\s*}}/ig, escapeHtml(decodedLocation))
+ .replace(/{{\s*URL\s*}}/ig, escapedLocation)
+ .replace(/{{\s*UNSAFE_URL\s*}}/ig, newLocation)
+ ;
+
+ var metaRedirect = ''
+ + '\n'
+ + '\n'
+ //+ ' \n'
+ + ' \n'
+ + '\n'
+ + '\n' + body + '\n\n'
+ + '\n'
+ ;
+ var pathMatch;
+
+ opts.paths.some(function (p) {
+ if (!p.match) {
+ // ignore
+ } else if ('string' === typeof p.match) {
+ pathMatch = (url === p.match) && (p.redirect || 301);
+ } else {
+ pathMatch = p.match.test && p.match.test(url) && (p.redirect || 301);
+ }
+ if (pathMatch) {
+ redirect = pathMatch;
+ }
+ return pathMatch;
+ });
+ // If it's not a non-0 number (because null is 0) then 'meta' is assumed.
+ if (redirect && isFinite(redirect)) {
+ res.statusCode = redirect;
+ res.setHeader('Location', newLocation);
+ }
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
+ res.end(metaRedirect);
+ };
+};
diff --git a/express-server/node_modules/redirect-https/package.json b/express-server/node_modules/redirect-https/package.json
new file mode 100644
index 00000000..c0c398d7
--- /dev/null
+++ b/express-server/node_modules/redirect-https/package.json
@@ -0,0 +1,93 @@
+{
+ "_args": [
+ [
+ "redirect-https@^1.1.5",
+ "/nodeapps/https-test/greenlock-express.js"
+ ]
+ ],
+ "_from": "redirect-https@>=1.1.5 <2.0.0",
+ "_hasShrinkwrap": false,
+ "_id": "redirect-https@1.3.0",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/redirect-https",
+ "_nodeVersion": "10.6.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/redirect-https_1.3.0_1538526323287_0.744062313082948"
+ },
+ "_npmUser": {
+ "email": "coolaj86@gmail.com",
+ "name": "coolaj86"
+ },
+ "_npmVersion": "6.1.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "redirect-https",
+ "raw": "redirect-https@^1.1.5",
+ "rawSpec": "^1.1.5",
+ "scope": null,
+ "spec": ">=1.1.5 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/"
+ ],
+ "_resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz",
+ "_shasum": "54a1bceacddad0c3178d435bcc8d6420b63f087a",
+ "_shrinkwrap": null,
+ "_spec": "redirect-https@^1.1.5",
+ "_where": "/nodeapps/https-test/greenlock-express.js",
+ "author": {
+ "email": "coolaj86@gmail.com",
+ "name": "AJ ONeal",
+ "url": "https://coolaj86.com/"
+ },
+ "bugs": {
+ "url": "https://git.coolaj86.com/coolaj86/redirect-https.js/issues"
+ },
+ "dependencies": {
+ "escape-html": "^1.0.3"
+ },
+ "description": "Redirect from HTTP to HTTPS using meta redirects",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "fileCount": 6,
+ "integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbtAxzCRA9TVsSAnZWagAAUHoP/Ah3a3Bh44ZUan+FgcpT\nT7TSSXiJN378hbnYNb0qUdlx2mevKhcGsmnXQvb11CILSjiUxHmqT7qyM/wj\nbyjxBMYM3809dJupBi+ut999bJZjO2Egdtn/MKTWEByQkeLNEPXOWwoaQHJJ\nw8GFvUi8u4gw6etlfCC/jIfPpVF2/V+5o7PwqsYBC6hipqyPWVCOfKDKZnSP\nhVSjtwMmUe3lGc3eAf75XWQsXDq7d13tcG7c9U+0IISE+6QAAS2gmb2e9ZNM\nh1OWlxFMhcqceSr2ocCuCR3O/K8lJp0WH5tYm8A/1XE96JvLSsm4kObCuHen\nkImwjNAwva9mn+4yrY3PhDO5h5zrpwVpgFQVb4Q7BCMXADSNP9Rx/kpHZF9z\nmApgxy+3cxk+fHYePgWVa7RWS3ZHpLoFc/9j9qXsr30lG/8Uxbk5kdRaa9iN\neuf26FoEqOIS9Fc49rA+t3F4YZBu0bRvn4t0KBoPt4eSDKl2sMkJabZqzFE6\nYB3NMvOctrgEwh+nQG4DplyL625P6OEE3wsmIRtbcDfNCdszmh6aLh87XbvE\ny2U7B0HNA026KJ+2xiZubSlHvePLrtDBoNC+1n/ttE+0daPw2PogxmPPtJ/L\n5QLKEKAbM6y5KgvfJifmYJPnby+7Yb2MWhf5y7MDrI4e99jEDQ8YhDko0BBm\nCoQH\r\n=64bZ\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "54a1bceacddad0c3178d435bcc8d6420b63f087a",
+ "tarball": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz",
+ "unpackedSize": 21004
+ },
+ "gitHead": "fd044d6467098ade85a6c8c3c563f4f1f5120455",
+ "homepage": "https://git.coolaj86.com/coolaj86/redirect-https.js#readme",
+ "keywords": [
+ "force",
+ "http",
+ "https",
+ "location",
+ "meta",
+ "redirect",
+ "upgrade"
+ ],
+ "license": "(MIT OR Apache-2.0)",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "coolaj86",
+ "email": "coolaj86@gmail.com"
+ }
+ ],
+ "name": "redirect-https",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://git.coolaj86.com/coolaj86/redirect-https.js.git"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "version": "1.3.0"
+}
diff --git a/express-server/node_modules/redirect-https/test.js b/express-server/node_modules/redirect-https/test.js
new file mode 100644
index 00000000..6ad687a4
--- /dev/null
+++ b/express-server/node_modules/redirect-https/test.js
@@ -0,0 +1,77 @@
+'use strict';
+
+var opts = { port: 0 };
+var redirect = require('./')(opts);
+
+function r80to443() {
+ // using port 80 and 443
+ opts.port = 443;
+ var req = { connection: {}, headers: { host: 'example.com' }, url: '/path/to/somewhere.html' };
+ var res = {
+ setHeader: function () {}
+ , end: function (body) {
+ if (!/:/.test(body)) {
+ throw new Error("test didn't pass with port 80 redirecting to 443");
+ }
+ console.log('PASS: 80 to 443');
+ }
+ };
+ var next = function () {};
+ redirect(req, res, next);
+}
+
+function r80to8443() {
+ // using port 80, but not 443
+ opts.port = 8443;
+ var req = { connection: {}, headers: { host: 'example.com' }, url: '/path/to/somewhere.html' };
+ var res = {
+ setHeader: function () {}
+ , end: function (body) {
+ if (!/:8443/.test(body)) {
+ throw new Error("test didn't pass with port 80 redirecting to non-443");
+ }
+ console.log('PASS: 80 to 8443');
+ }
+ };
+ var next = function () {};
+ redirect(req, res, next);
+}
+
+function r4080to8443() {
+ // using port 80 and 443
+ opts.port = 8443;
+ var req = { connection: {}, headers: { host: 'example.com:4080' }, url: '/path/to/somewhere.html' };
+ var res = {
+ setHeader: function () {}
+ , end: function (body) {
+ if (!/:8443/.test(body)) {
+ throw new Error("test didn't pass with port 4080 redirecting to 8443");
+ }
+ console.log('PASS: 4080 to 8443');
+ }
+ };
+ var next = function () {};
+ redirect(req, res, next);
+}
+
+function r4080to443() {
+ // using port 80 and 443
+ opts.port = 8443;
+ var req = { connection: {}, headers: { host: 'example.com:4080' }, url: '/path/to/somewhere.html' };
+ var res = {
+ setHeader: function () {}
+ , end: function (body) {
+ if (/:/.test(body)) {
+ throw new Error("test didn't pass with port 4080 redirecting to 8443");
+ }
+ console.log('PASS: 4080 to 8443');
+ }
+ };
+ var next = function () {};
+ redirect(req, res, next);
+}
+
+r80to443();
+r80to8443();
+r4080to8443();
+//r4080to443();
diff --git a/express-server/node_modules/rsa-compat/LICENSE b/express-server/node_modules/rsa-compat/LICENSE
new file mode 100644
index 00000000..c2128786
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/LICENSE
@@ -0,0 +1,375 @@
+Copyright 2016-2018 AJ ONeal
+
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/express-server/node_modules/rsa-compat/README.md b/express-server/node_modules/rsa-compat/README.md
new file mode 100644
index 00000000..2b72313c
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/README.md
@@ -0,0 +1,279 @@
+# rsa-compat.js
+
+
+
+
+| A [Root](https://therootcompany.com) Project.
+
+JavaScript RSA utils that work on Windows, Mac, and Linux with or without C compiler
+
+This now uses node-native RSA key generation and lightweight, zero-dependency solutions for key conversion.
+However, it also optionally depends on `ursa` and `forge` for backwards compatibility with older node versions.
+
+This was built for the [ACME.js](https://git.coolaj86.com/coolaj86/acme.js) and
+[Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js) **Let's Encrypt** clients
+and is particularly suitable for building **certbot**-like clients.
+
+(if you're looking for similar tools in the browser, consider [Bluecrypt](https://www.npmjs.com/search?q=bluecrypt))
+
+# Install
+
+node.js
+
+```bash
+npm install --save rsa-compat
+```
+
+### CLI
+
+```bash
+npm install --global rsa-compat
+```
+
+# Usage
+
+CLI
+---
+
+You can generate keypairs on Windows, Mac, and Linux using rsa-keygen-js:
+
+```bash
+# generates a new keypair in the current directory
+rsa-keypiar-js
+```
+
+Examples
+--------
+
+Generate an RSA Keypair:
+
+```javascript
+var RSA = require('rsa-compat').RSA;
+
+var options = { bitlen: 2048, exp: 65537, public: true, pem: true, internal: true };
+
+RSA.generateKeypair(options, function (err, keypair) {
+ console.log(keypair);
+});
+```
+
+Here's what the object might look like:
+
+`console.log(keypair)`:
+```javascript
+
+{ publicKeyPem: '-----BEGIN RSA PUBLIC KEY-----\n/*base64 pem-encoded string*/'
+, privateKeyPem: '-----BEGIN RSA PRIVATE KEY-----\n/*base64 pem-encoded string*/'
+, privateKeyJwk: {
+ kty: "RSA"
+ , n: '/*base64 modulus n = pq*/'
+ , e: '/*base64 exponent (usually 65537)*/'
+ , d: '/*base64 private exponent (d = e^−1 (mod ϕ(n))/'
+ , p: '/*base64 first prime*/'
+ , q: '/*base64 second prime*/'
+ , dp: '/*base64 first exponent for Chinese remainder theorem (dP = d (mod p−1))*/'
+ , dq: '/*base64 Second exponent, used for CRT (dQ = d (mod q−1))/'
+ , qi: '/*base64 Coefficient, used for CRT (qinv = q^−1 (mod p))*/'
+ }
+, publicKeyJwk: {
+ kty: "RSA"
+ , n: '/*base64 modulus n = pq*/'
+ , e: '/*base64 exponent (usually 65537)*/'
+ }
+
+, _ursa: '/*undefined or intermediate ursa object*/'
+, _ursaPublic: '/*undefined or intermediate ursa object*/'
+, _forge: '/*undefined or intermediate forge object*/'
+, _forgePublic: '/*undefined or intermediate forge object*/'
+}
+```
+
+NOTE: this object is JSON safe as _ursa and _forge will be ignored
+
+See http://crypto.stackexchange.com/questions/6593/what-data-is-saved-in-rsa-private-key to learn a little more about the meaning of the specific fields in the JWK.
+
+# API Summary
+
+* `RSA.generateKeypair(options, cb)`
+ * (deprecated `RSA.generateKeypair(bitlen, exp, options, cb)`)
+* `RSA.import(options)`
+ * (deprecated `RSA.import(keypair, options)`)
+* `RSA.exportPrivatePem(keypair)`
+* `RSA.exportPublicPem(keypair)`
+* `RSA.exportPrivateJwk(keypair)`
+* `RSA.exportPublicJwk(keypair)`
+* `RSA.signJws(keypair, header, protect, payload)`
+ * (deprecated `RSA.signJws(keypair, payload, nonce)`)
+* `RSA.generateCsrPem(keypair, names)`
+* `RSA.generateCsrDerWeb64(keypair, names)`
+
+`keypair` can be any object with any of these keys `publicKeyPem, privateKeyPem, publicKeyJwk, privateKeyJwk`
+
+### RSA.generateKeypair(options, cb)
+
+Create a private keypair and export it as PEM, JWK, and/or internal formats
+
+```javascript
+RSA.generateKeypair(null, function (keypair) { /*...*/ });
+
+RSA.generateKeypair({
+ bitlen: 2048, exp: 65537, pem: false, public: false, internal: false
+}, function (keypair) { /*...*/ });
+```
+
+`options`:
+```javascript
+{ public: false // export public keys
+, pem: false // export pems
+, jwk: true // export jwks
+, internal: false // preserve internal intermediate formats (_ursa, _forge)
+, thumbprint: false // JWK sha256 thumbprint
+, fingerprint: false // NOT IMPLEMENTED (RSA key fingerprint)
+}
+```
+
+### RSA.import(options)
+
+Imports keypair as JWKs and internal values `_ursa` and `_forge`.
+
+```javascript
+var keypair = RSA.import({ type: 'RSA', privateKeyPem: '...' });
+
+console.log(keypair);
+```
+
+```javascript
+{ privateKeyPem: ..., privateKeyJwk: ..., _ursa: ..., _forge: ... }
+```
+
+### RSA.export*(keypair)
+
+You put in an object like `{ privateKeyPem: '...' }` or `{ publicKeyJwk: {} }`
+and you get back the keys in the format you requested.
+
+Note:
+
+* Private keys **can** be used to export both private and public keys
+* Public keys can **NOT** be used to generate private keys
+
+Example:
+
+```javascript
+var keypair = { privateKeyPem: '...' };
+
+keypair.publicKeyJwk = RSA.exportPublicJwk(keypair);
+
+console.log(keypair);
+```
+
+### RSA.signJws(keypair, payload, nonce)
+
+Generates a signature in JWS format (necessary for **certbot**/**letsencrypt**).
+
+```javascript
+var message = "Hello, World!"
+var nonce = crypto.randomBytes(16).toString('hex');
+var jws = RSA.signJws(keypair, message, nonce);
+
+console.log(jws);
+```
+
+The result looks like this:
+
+```javascript
+{ "header": {
+ "alg": "RS256",
+ "jwk": {
+ "kty": "RSA",
+ "n": "AMJubTfOtAarnJytLE8fhNsEI8wnpjRvBXGK/Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocDUgukpfkY+2UPUS/GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdkom2FMhGxkLaEUGDSfsNznTTZNBBg9",
+ "e": "AQAB"
+ }
+ },
+ "protected": "eyJub25jZSI6IjhlZjU2MjRmNWVjOWQzZWYifQ",
+ "payload": "JLzF1NBNCV3kfbJ5sFaFyX94fJuL2H-IzaoBN-ciiHk",
+ "signature": "Wb2al5SDyh5gjmkV79MK9m3sfNBBPjntSKor-34BBoGwr6n8qEnBmqB1Y4zbo-5rmvsoPmJsnRlP_hRiUY86zSAQyfbisTGrGBl0IQ7ditpkfYVm0rBWJ8WnYNqYNp8K3qcD7NW72tsy-XoWEjNlz4lWJeRdEG2Nt4CJgnREH4Y"
+}
+```
+
+### RSA.generateCsr*(keypair, names)
+
+You can generate the CSR in human-readable or binary / base64 formats:
+
+`RSA.generateCsrPem(keypair, names)`:
+```javascript
+var pem = RSA.generateCsrPem(keypair, [ 'example.com', 'www.example.com' ]);
+
+console.log(pem);
+```
+
+web-safe base64 for **certbot**/**letsencrypt**:
+
+`RSA.generateCsrDerWeb64(keypair, names)`:
+```javascript
+var web64 = RSA.generateCsrDerWeb64(keypair, [ 'example.com', 'www.example.com' ]);
+
+console.log(web64);
+```
+
+# Old Node Versions
+
+In recent versions of node >= v10.12 native RSA key generation is fairly quick for 2048-bit keys
+(though it may still be too slow for some applications with 4096-bit keys).
+
+In old versions, however, and especially on ARM and/or MIPS procesors, RSA key generation can be
+very, very slow.
+
+In old node versions `ursa` can provide faster key generation, but it must be compiled.
+`ursa` will not compile for new node versions, but they already include the same openssl bindings anyawy.
+
+
+```bash
+npm install --save ursa
+```
+
+Also, if you need **Node < v6** support:
+
+```bash
+npm install --save buffer-v6-polyfill
+```
+
+## Security and Compatibility
+
+**TL;DR**: Use the default values 2048 and 65537 unless you have a really, really good reason to do otherwise.
+
+Various platforms *require* these values.
+
+Most security experts agree that 4096-bit is no more "secure" than 2048-bit -
+a fundamental vulnerability in the RSA algorithm which causes 2048 to be broken
+will most likely also cause 4096 to be broken
+(i.e. if someone can prove mathematically prove P=NP or a way to predict prime numbers).
+Also, many platforms
+only support 2048 bit keys due to the insecurity of 1024-bit keys (which are not 1/2 secure
+but rather 1/(2^1028) less secure) and the excess computational
+cost of 4096-bit keys (it's not a 2x increase, it's more like a 2^2048 increase).
+
+As to why 65537 is even optional as a prime exponent or why it matters... no idea,
+but it does matter.
+
+# ChangeLog:
+
+* v1.9.0
+ * consistently handle key generation across node crypto, ursa, and forge
+ * move all other operations to rasha.js and rsa-csr.js
+* v1.4.0
+ * remove ursa as dependency (just causes confusion), but note in docs
+ * drop node < v6 support
+
+# Legal
+
+rsa-compat.js directly includes code from
+[Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js)
+and
+[RSA-CSR.js](https://git.coolaj86.com/coolaj86/rsa-csr.js)
+(also [Root](https://therootcompany.com) projects),
+retrofitted for rsa-compat.
+
+[rsa-compat.js](https://git.coolaj86.com/coolaj86/rsa-compat.js) |
+MPL-2.0 |
+[Terms of Use](https://therootcompany.com/legal/#terms) |
+[Privacy Policy](https://therootcompany.com/legal/#privacy)
diff --git a/express-server/node_modules/rsa-compat/bin/rsa-keygen.js b/express-server/node_modules/rsa-compat/bin/rsa-keygen.js
new file mode 100644
index 00000000..e65176f5
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/bin/rsa-keygen.js
@@ -0,0 +1,35 @@
+#!/usr/bin/env node
+'use strict';
+
+var RSA = require('../').RSA;
+var path = require('path');
+var fs = require('fs');
+
+var bitlen = 2048;
+var exp = 65537;
+var opts = { public: true, pem: true };
+var cwd = process.cwd();
+var privkeyPath = path.join(cwd, 'privkey.pem');
+var pubkeyPath = path.join(cwd, 'pubkey.pem');
+
+if (fs.existsSync(privkeyPath)) {
+ console.error(privkeyPath, "already exists");
+ process.exit(1);
+}
+
+RSA.generateKeypair(bitlen, exp, opts, function (err, keypair) {
+ console.info('');
+ console.info('');
+
+ fs.writeFileSync(privkeyPath, keypair.privateKeyPem, 'ascii');
+ console.info(privkeyPath + ':');
+ console.info('');
+ console.info(keypair.privateKeyPem);
+
+ console.info('');
+
+ fs.writeFileSync(pubkeyPath, keypair.publicKeyPem, 'ascii');
+ console.info(pubkeyPath + ':');
+ console.info('');
+ console.info(keypair.publicKeyPem);
+});
diff --git a/express-server/node_modules/rsa-compat/fixtures/csr.pem b/express-server/node_modules/rsa-compat/fixtures/csr.pem
new file mode 100644
index 00000000..562c8b29
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/fixtures/csr.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBjzCB+QIBADAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwm5tN860BqucnK0sTx+E2wQjzCemNG8FcYr8qnTrvknX
+Q5HPHIwurMhkXe1ytSQoGu11zv27hfQahwNSC6Sl+Rj7ZQ9RL8bF6FRhtislhY4u
+SglbPGfvB+ij1fUmC8ExjrAdCdMq+fNl2SibYUyEbGQtoRQYNJ+w3OdNNk0EGD0C
+AwEAAaA6MDgGCSqGSIb3DQEJDjErMCkwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22C
+D3d3dy5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOBgQCv1nj7zL0vnP11GEDb
+TWlXPyT2XaFH9lYOm8By3BKrtk6rhGojlLppmNGaCEBqztebCY2T5LT6mi5lz0xc
+YHJ9YC4w1yKz94//gmEMYJ+7fuILexnaeZudp9GjR3OeRWIWr/+3H0U3XnZpazGP
+/qK4BCIl9HOOJbF5tyTd/CeeBg==
+-----END CERTIFICATE REQUEST-----
diff --git a/express-server/node_modules/rsa-compat/fixtures/csr.urlbase64 b/express-server/node_modules/rsa-compat/fixtures/csr.urlbase64
new file mode 100644
index 00000000..12dffac6
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/fixtures/csr.urlbase64
@@ -0,0 +1 @@
+MIIBjzCB-QIBADAWMRQwEgYDVQQDEwtleGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwm5tN860BqucnK0sTx-E2wQjzCemNG8FcYr8qnTrvknXQ5HPHIwurMhkXe1ytSQoGu11zv27hfQahwNSC6Sl-Rj7ZQ9RL8bF6FRhtislhY4uSglbPGfvB-ij1fUmC8ExjrAdCdMq-fNl2SibYUyEbGQtoRQYNJ-w3OdNNk0EGD0CAwEAAaA6MDgGCSqGSIb3DQEJDjErMCkwJwYDVR0RBCAwHoILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOBgQCv1nj7zL0vnP11GEDbTWlXPyT2XaFH9lYOm8By3BKrtk6rhGojlLppmNGaCEBqztebCY2T5LT6mi5lz0xcYHJ9YC4w1yKz94__gmEMYJ-7fuILexnaeZudp9GjR3OeRWIWr_-3H0U3XnZpazGP_qK4BCIl9HOOJbF5tyTd_CeeBg
diff --git a/express-server/node_modules/rsa-compat/fixtures/privkey.jwk.json b/express-server/node_modules/rsa-compat/fixtures/privkey.jwk.json
new file mode 100644
index 00000000..92180d01
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/fixtures/privkey.jwk.json
@@ -0,0 +1,11 @@
+{
+ "kty": "RSA",
+ "n": "wm5tN860BqucnK0sTx-E2wQjzCemNG8FcYr8qnTrvknXQ5HPHIwurMhkXe1ytSQoGu11zv27hfQahwNSC6Sl-Rj7ZQ9RL8bF6FRhtislhY4uSglbPGfvB-ij1fUmC8ExjrAdCdMq-fNl2SibYUyEbGQtoRQYNJ-w3OdNNk0EGD0",
+ "e": "AQAB",
+ "d": "HT8DCrv69G3n9uFNovE4yMEMqW7lX0m75eJkMze3Jj5xNOa_4qlrc-4IuuA2uuyfY72IVQRxqqqXOuvS8ZForZZk-kWSd6z45hrpbNAAHH2Rf7XwnwHY8VJrOQF3UtbktTWqHX36ITZb9Hmf18hWsIeEp8Ng7Ru9h7hNuVxKMjk",
+ "p": "42M69lUC-EIzYmcsZYkbf7kGhqvcwHk_h7N8TEOa7IYRP_DQL49LrSNuMHxOK9CxJ0RwajsY5o6WYBfoRC0B5w",
+ "q": "2uWWAmzLitMx9reZDnSQwhw1qGIQ55quEBwmBBQIe46O4SeFT0V8TED-bkVeOYQVCFHCS6GTRBoipMZtTPEYOw",
+ "dp": "u7Ec6lghq2p5n7AqJWWXHUZM7LzP6tAqcIjnAMyNBM9lTbIpJhjSDohAXCU_IUuR7ye-4vEFDMqFtawGPMAp4Q",
+ "dq": "XLhDAmPzE6rBzy-VtXnKl247jEd9wZzTfh9uOuwBa9TG0Lhcz2cvb11YaH0ZnGNGRW_cTQzzxDUN1531TlIRYQ",
+ "qi": "jZqnPoQJ8bCGy8hxTf7IW37cIDvwJRWxfg1S6XmbcKWzab7kxsZAbkrSEanGMMLc6ZdOrVjmCd6nnJRm9U9kjg"
+}
diff --git a/express-server/node_modules/rsa-compat/fixtures/privkey.pkcs1.pem b/express-server/node_modules/rsa-compat/fixtures/privkey.pkcs1.pem
new file mode 100644
index 00000000..8281814e
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/fixtures/privkey.pkcs1.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCbm03zrQGq5ycrSxPH4TbBCPMJ6Y0bwVxivyqdOu+SddDkc8c
+jC6syGRd7XK1JCga7XXO/buF9BqHA1ILpKX5GPtlD1EvxsXoVGG2KyWFji5KCVs8
+Z+8H6KPV9SYLwTGOsB0J0yr582XZKJthTIRsZC2hFBg0n7Dc5002TQQYPQIDAQAB
+AoGAHT8DCrv69G3n9uFNovE4yMEMqW7lX0m75eJkMze3Jj5xNOa/4qlrc+4IuuA2
+uuyfY72IVQRxqqqXOuvS8ZForZZk+kWSd6z45hrpbNAAHH2Rf7XwnwHY8VJrOQF3
+UtbktTWqHX36ITZb9Hmf18hWsIeEp8Ng7Ru9h7hNuVxKMjkCQQDjYzr2VQL4QjNi
+ZyxliRt/uQaGq9zAeT+Hs3xMQ5rshhE/8NAvj0utI24wfE4r0LEnRHBqOxjmjpZg
+F+hELQHnAkEA2uWWAmzLitMx9reZDnSQwhw1qGIQ55quEBwmBBQIe46O4SeFT0V8
+TED+bkVeOYQVCFHCS6GTRBoipMZtTPEYOwJBALuxHOpYIatqeZ+wKiVllx1GTOy8
+z+rQKnCI5wDMjQTPZU2yKSYY0g6IQFwlPyFLke8nvuLxBQzKhbWsBjzAKeECQFy4
+QwJj8xOqwc8vlbV5ypduO4xHfcGc034fbjrsAWvUxtC4XM9nL29dWGh9GZxjRkVv
+3E0M88Q1Dded9U5SEWECQQCNmqc+hAnxsIbLyHFN/shbftwgO/AlFbF+DVLpeZtw
+pbNpvuTGxkBuStIRqcYwwtzpl06tWOYJ3qeclGb1T2SO
+-----END RSA PRIVATE KEY-----
diff --git a/express-server/node_modules/rsa-compat/fixtures/privkey.pkcs8.pem b/express-server/node_modules/rsa-compat/fixtures/privkey.pkcs8.pem
new file mode 100644
index 00000000..cfecdc3c
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/fixtures/privkey.pkcs8.pem
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMJubTfOtAarnJyt
+LE8fhNsEI8wnpjRvBXGK/Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocD
+UgukpfkY+2UPUS/GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdko
+m2FMhGxkLaEUGDSfsNznTTZNBBg9AgMBAAECgYAdPwMKu/r0bef24U2i8TjIwQyp
+buVfSbvl4mQzN7cmPnE05r/iqWtz7gi64Da67J9jvYhVBHGqqpc669LxkWitlmT6
+RZJ3rPjmGuls0AAcfZF/tfCfAdjxUms5AXdS1uS1NaodffohNlv0eZ/XyFawh4Sn
+w2DtG72HuE25XEoyOQJBAONjOvZVAvhCM2JnLGWJG3+5Boar3MB5P4ezfExDmuyG
+ET/w0C+PS60jbjB8TivQsSdEcGo7GOaOlmAX6EQtAecCQQDa5ZYCbMuK0zH2t5kO
+dJDCHDWoYhDnmq4QHCYEFAh7jo7hJ4VPRXxMQP5uRV45hBUIUcJLoZNEGiKkxm1M
+8Rg7AkEAu7Ec6lghq2p5n7AqJWWXHUZM7LzP6tAqcIjnAMyNBM9lTbIpJhjSDohA
+XCU/IUuR7ye+4vEFDMqFtawGPMAp4QJAXLhDAmPzE6rBzy+VtXnKl247jEd9wZzT
+fh9uOuwBa9TG0Lhcz2cvb11YaH0ZnGNGRW/cTQzzxDUN1531TlIRYQJBAI2apz6E
+CfGwhsvIcU3+yFt+3CA78CUVsX4NUul5m3Cls2m+5MbGQG5K0hGpxjDC3OmXTq1Y
+5gnep5yUZvVPZI4=
+-----END PRIVATE KEY-----
diff --git a/express-server/node_modules/rsa-compat/fixtures/signed.jwk.json b/express-server/node_modules/rsa-compat/fixtures/signed.jwk.json
new file mode 100644
index 00000000..509867b5
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/fixtures/signed.jwk.json
@@ -0,0 +1,13 @@
+{
+ "header": {
+ "alg": "RS256",
+ "jwk": {
+ "kty": "RSA",
+ "n": "AMJubTfOtAarnJytLE8fhNsEI8wnpjRvBXGK_Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocDUgukpfkY-2UPUS_GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdkom2FMhGxkLaEUGDSfsNznTTZNBBg9",
+ "e": "AQAB"
+ }
+ },
+ "protected": "eyJub25jZSI6IjhlZjU2MjRmNWVjOWQzZWYifQ",
+ "payload": "JLzF1NBNCV3kfbJ5sFaFyX94fJuL2H-IzaoBN-ciiHk",
+ "signature": "Wb2al5SDyh5gjmkV79MK9m3sfNBBPjntSKor-34BBoGwr6n8qEnBmqB1Y4zbo-5rmvsoPmJsnRlP_hRiUY86zSAQyfbisTGrGBl0IQ7ditpkfYVm0rBWJ8WnYNqYNp8K3qcD7NW72tsy-XoWEjNlz4lWJeRdEG2Nt4CJgnREH4Y"
+}
diff --git a/express-server/node_modules/rsa-compat/index.js b/express-server/node_modules/rsa-compat/index.js
new file mode 100644
index 00000000..de048279
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/index.js
@@ -0,0 +1,7 @@
+// Copyright 2016-2018 AJ ONeal. All rights reserved
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+module.exports.RSA = require('./lib/rsa.js');
diff --git a/express-server/node_modules/rsa-compat/lib/generate-privkey-forge.js b/express-server/node_modules/rsa-compat/lib/generate-privkey-forge.js
new file mode 100644
index 00000000..a11def9a
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/generate-privkey-forge.js
@@ -0,0 +1,57 @@
+// Copyright 2016-2018 AJ ONeal. All rights reserved
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+var Rasha = require('./rasha');
+
+module.exports = function (bitlen, exp) {
+ var k = require('node-forge').pki.rsa
+ .generateKeyPair({ bits: bitlen || 2048, e: exp || 0x10001 }).privateKey;
+ var jwk = {
+ kty: "RSA"
+ , n: _toUrlBase64(k.n)
+ , e: _toUrlBase64(k.e)
+ , d: _toUrlBase64(k.d)
+ , p: _toUrlBase64(k.p)
+ , q: _toUrlBase64(k.q)
+ , dp: _toUrlBase64(k.dP)
+ , dq: _toUrlBase64(k.dQ)
+ , qi: _toUrlBase64(k.qInv)
+ };
+ return {
+ publicKeyPem: Rasha.exportSync({ jwk: jwk, public: true })
+ , privateKeyPem: Rasha.exportSync({ jwk: jwk })
+ , privateKeyJwk: jwk
+ , publicKeyJwk: {
+ kty: jwk.kty
+ , n: jwk.n
+ , e: jwk.e
+ }
+ };
+};
+
+function _toUrlBase64(fbn) {
+ var hex = fbn.toRadix(16);
+ if (hex.length % 2) {
+ // Invalid hex string
+ hex = '0' + hex;
+ }
+ while ('00' === hex.slice(0, 2)) {
+ hex = hex.slice(2);
+ }
+ return Buffer.from(hex, 'hex').toString('base64')
+ .replace(/\+/g, "-")
+ .replace(/\//g, "_")
+ .replace(/=/g,"")
+ ;
+}
+
+if (require.main === module) {
+ var keypair = module.exports(2048, 0x10001);
+ console.info(keypair.privateKeyPem);
+ console.warn(keypair.publicKeyPem);
+ //console.info(keypair.privateKeyJwk);
+ //console.warn(keypair.publicKeyJwk);
+}
diff --git a/express-server/node_modules/rsa-compat/lib/generate-privkey-node.js b/express-server/node_modules/rsa-compat/lib/generate-privkey-node.js
new file mode 100644
index 00000000..cfc3c8b3
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/generate-privkey-node.js
@@ -0,0 +1,39 @@
+// Copyright 2016-2018 AJ ONeal. All rights reserved
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+var Rasha = require('./rasha');
+
+module.exports = function (bitlen, exp) {
+ var keypair = require('crypto').generateKeyPairSync(
+ 'rsa'
+ , { modulusLength: bitlen
+ , publicExponent: exp
+ , privateKeyEncoding: {
+ type: 'pkcs1'
+ , format: 'pem'
+ }
+ , publicKeyEncoding: {
+ type: 'pkcs1'
+ , format: 'pem'
+ }
+ }
+ );
+ var result = {
+ publicKeyPem: keypair.publicKey.trim()
+ , privateKeyPem: keypair.privateKey.trim()
+ };
+ result.publicKeyJwk = Rasha.importSync({ pem: result.publicKeyPem, public: true });
+ result.privateKeyJwk = Rasha.importSync({ pem: result.privateKeyPem });
+ return result;
+};
+
+if (require.main === module) {
+ var keypair = module.exports(2048, 0x10001);
+ console.info(keypair.privateKeyPem);
+ console.warn(keypair.publicKeyPem);
+ //console.info(keypair.privateKeyJwk);
+ //console.warn(keypair.publicKeyJwk);
+}
diff --git a/express-server/node_modules/rsa-compat/lib/generate-privkey-ursa.js b/express-server/node_modules/rsa-compat/lib/generate-privkey-ursa.js
new file mode 100644
index 00000000..22672331
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/generate-privkey-ursa.js
@@ -0,0 +1,32 @@
+// Copyright 2016-2018 AJ ONeal. All rights reserved
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+var Rasha = require('./rasha');
+
+module.exports = function (bitlen, exp) {
+ var ursa;
+ try {
+ ursa = require('ursa');
+ } catch(e) {
+ ursa = require('ursa-optional');
+ }
+ var keypair = ursa.generatePrivateKey(bitlen, exp);
+ var result = {
+ publicKeyPem: keypair.toPublicPem().toString('ascii').trim()
+ , privateKeyPem: keypair.toPrivatePem().toString('ascii').trim()
+ };
+ result.publicKeyJwk = Rasha.importSync({ pem: result.publicKeyPem, public: true });
+ result.privateKeyJwk = Rasha.importSync({ pem: result.privateKeyPem });
+ return result;
+};
+
+if (require.main === module) {
+ var keypair = module.exports(2048, 0x10001);
+ console.info(keypair.privateKeyPem);
+ console.warn(keypair.publicKeyPem);
+ //console.info(keypair.privateKeyJwk);
+ //console.warn(keypair.publicKeyJwk);
+}
diff --git a/express-server/node_modules/rsa-compat/lib/generate-privkey.js b/express-server/node_modules/rsa-compat/lib/generate-privkey.js
new file mode 100644
index 00000000..3f71b2bb
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/generate-privkey.js
@@ -0,0 +1,66 @@
+// Copyright 2016-2018 AJ ONeal. All rights reserved
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+var oldver = false;
+
+module.exports = function (bitlen, exp) {
+ bitlen = parseInt(bitlen, 10) || 2048;
+ exp = parseInt(exp, 10) || 65537;
+
+ try {
+ return require('./generate-privkey-node.js')(bitlen, exp);
+ } catch(e) {
+ if (!/generateKeyPairSync is not a function/.test(e.message)) {
+ throw e;
+ }
+ try {
+ return require('./generate-privkey-ursa.js')(bitlen, exp);
+ } catch(e) {
+ if (e.code !== 'MODULE_NOT_FOUND') {
+ throw e;
+ }
+ if (!oldver) {
+ oldver = true;
+ console.warn("[WARN] rsa-compat: Your version of node does not have crypto.generateKeyPair()");
+ console.warn("[WARN] rsa-compat: Please update to node >= v10.12 or 'npm install ursa'");
+ console.warn("[WARN] rsa-compat: Using node-forge as a fallback, but it may be unacceptably slow.");
+ if (/arm|mips/i.test(require('os').arch)) {
+ console.warn("================================================================");
+ console.warn(" WARNING");
+ console.warn("================================================================");
+ console.warn("");
+ console.warn("WARNING: You are generating an RSA key using pure JavaScript on");
+ console.warn(" a VERY SLOW cpu. This could take DOZENS of minutes!");
+ console.warn("");
+ console.warn(" We recommend installing node >= v10.12, or 'gcc' and 'ursa'");
+ console.warn("");
+ console.warn("EXAMPLE:");
+ console.warn("");
+ console.warn(" sudo apt-get install build-essential && npm install ursa");
+ console.warn("");
+ console.warn("================================================================");
+ }
+ }
+ try {
+ return require('./generate-privkey-forge.js')(bitlen, exp);
+ } catch(e) {
+ if (e.code !== 'MODULE_NOT_FOUND') {
+ throw e;
+ }
+ console.error("[ERROR] rsa-compat: could not generate a private key.");
+ console.error("None of crypto.generateKeyPair, ursa, nor node-forge are present");
+ }
+ }
+ }
+};
+
+if (require.main === module) {
+ var keypair = module.exports(2048, 0x10001);
+ console.info(keypair.privateKeyPem);
+ console.warn(keypair.publicKeyPem);
+ //console.info(keypair.privateKeyJwk);
+ //console.warn(keypair.publicKeyJwk);
+}
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/README.md b/express-server/node_modules/rsa-compat/lib/rasha/README.md
new file mode 100644
index 00000000..e2d5fb27
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/README.md
@@ -0,0 +1,218 @@
+[Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js) · [](https://strong-emu-11.telebit.io/coolaj86/rasha.js)
+=========
+
+Sponsored by [Root](https://therootcompany.com).
+Built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
+and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock.js)
+
+
+
+| ~550 lines of code | 3kb gzipped | 10kb minified | 18kb with comments |
+
+RSA tools. Lightweight. Zero Dependencies. Universal compatibility.
+
+* [x] Fast and Easy RSA Key Generation
+* [x] PEM-to-JWK
+* [x] JWK-to-PEM
+* [x] SSH "pub" format
+* [ ] ECDSA
+ * **Need EC or ECDSA tools?** Check out [Eckles.js](https://git.coolaj86.com/coolaj86/eckles.js)
+
+
+## Generate RSA Key
+
+Achieves the *fastest possible key generation* using node's native RSA bindings to OpenSSL,
+then converts to JWK for ease-of-use.
+
+```
+Rasha.generate({ format: 'jwk' }).then(function (keypair) {
+ console.log(keypair.private);
+ console.log(keypair.public);
+});
+```
+
+**options**
+
+* `format` defaults to `'jwk'`
+ * `'pkcs1'` (traditional)
+ * `'pkcs8'`
+* `modulusLength` defaults to 2048 (must not be lower)
+ * generally you shouldn't pick a larger key size - they're slow
+ * **2048** is more than sufficient
+ * 3072 is way, way overkill and takes a few seconds to generate
+ * 4096 can take about a minute to generate and is just plain wasteful
+
+**advanced options**
+
+These options are provided for debugging and should not be used.
+
+* `publicExponent` defaults to 65537 (`0x10001`)
+
+## PEM-to-JWK
+
+* [x] PKCS#1 (traditional)
+* [x] PKCS#8, SPKI/PKIX
+* [x] 2048-bit, 3072-bit, 4096-bit (and ostensibily all others)
+* [x] SSH (RFC4716), (RFC 4716/SSH2)
+
+```js
+var Rasha = require('rasha');
+var pem = require('fs')
+ .readFileSync('./node_modles/rasha/fixtures/privkey-rsa-2048.pkcs1.pem', 'ascii');
+
+Rasha.import({ pem: pem }).then(function (jwk) {
+ console.log(jwk);
+});
+```
+
+```js
+{
+ "kty": "RSA",
+ "n": "m2ttVBxPlWw06ZmGBWVDl...QlEz7UNNj9RGps_50-CNw",
+ "e": "AQAB",
+ "d": "Cpfo7Mm9Nu8YMC_xrZ54W...Our1IdDzJ_YfHPt9sHMQQ",
+ "p": "ynG-t9HwKCN3MWRYFdnFz...E9S4DsGcAarIuOT2TsTCE",
+ "q": "xIkAjgUzB1zaUzJtW2Zgv...38ahSrBFEVnxjpnPh1Q1c",
+ "dp": "tzDGjECFOU0ehqtuqhcu...dVGAXJoGOdv5VpaZ7B1QE",
+ "dq": "kh5dyDk7YCz7sUFbpsmu...aX9PKa12HFlny6K1daL48",
+ "qi": "AlHWbx1gp6Z9pbw_1hlS...lhmIOgRApS0t9VoXtHhFU"
+}
+```
+
+## JWK-to-PEM
+
+* [x] PKCS#1 (traditional)
+* [x] PKCS#8, SPKI/PKIX
+* [x] 2048-bit, 4096-bit (and ostensibily all others)
+* [x] SSH (RFC4716), (RFC 4716/SSH2)
+
+```js
+var Rasha = require('rasha');
+var jwk = require('rasha/fixtures/privkey-rsa-2048.jwk.json');
+
+Rasha.export({ jwk: jwk }).then(function (pem) {
+ // PEM in PKCS1 (traditional) format
+ console.log(pem);
+});
+```
+
+```
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhD
+NzUJefLukC+xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ
+38P8LdAIlb0pqDHxEJ9adWomjuFf.....5cCBahfsiNtNR6WV1/iCSuINYs6uPdA
+Jlw7hm9m8TAmFWWyfL0s7wiRvAYkQvpxetorTwHJVLabBDJ+WBOAY2enOLHIRQv+
+atAvHrLXjkUdzF96o0icyF6n7QzGfUPmeWGYg6BEClLS31Whe0eEVQ==
+-----END RSA PRIVATE KEY-----
+```
+
+### Advanced Options
+
+`format: 'pkcs8'`:
+
+The default output format `pkcs1` (RSA-specific format) is used for private keys.
+Use `format: 'pkcs8'` to output in PKCS#8 format instead.
+
+```js
+Rasha.export({ jwk: jwk, format: 'pkcs8' }).then(function (pem) {
+ // PEM in PKCS#8 format
+ console.log(pem);
+});
+```
+
+```
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCba21UHE+VbDTp
+mYYFZUOV+OQ8AngOCdjROsPC0KiEfMvEaEM3NQl58u6QL7G7QsErKViiNPm9OTFo
+6HF5JijfWzK7haHFuRMEsgI4VwIY.....LorV1ovjwKBgAJR1m8dYKemfaW8P9YZ
+Uux7lwIFqF+yI201HpZXX+IJK4g1izq490AmXDuGb2bxMCYVZbJ8vSzvCJG8BiRC
++nF62itPAclUtpsEMn5YE4BjZ6c4schFC/5q0C8esteORR3MX3qjSJzIXqftDMZ9
+Q+Z5YZiDoEQKUtLfVaF7R4RV
+-----END PRIVATE KEY-----
+```
+
+`format: 'ssh'`:
+
+Although SSH uses PKCS#1 for private keys, it uses ts own special non-ASN1 format
+(affectionately known as rfc4716) for public keys. I got curious and then decided
+to add this format as well.
+
+To get the same format as you
+would get with `ssh-keygen`, pass `ssh` as the format option:
+
+```js
+Rasha.export({ jwk: jwk, format: 'ssh' }).then(function (pub) {
+ // Special SSH2 Public Key format (RFC 4716)
+ console.log(pub);
+});
+```
+
+```
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCba21UHE.....Q02P1Eamz/nT4I3 rsa@localhost
+```
+
+`public: 'true'`:
+
+If a private key is used as input, a private key will be output.
+
+If you'd like to output a public key instead you can pass `public: true`.
+
+or `format: 'spki'`.
+
+```js
+Rasha.export({ jwk: jwk, public: true }).then(function (pem) {
+ // PEM in SPKI/PKIX format
+ console.log(pem);
+});
+```
+
+```
+-----BEGIN PUBLIC KEY-----
+MIIBCgKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJ
+efLukC+xu0LBKylYojT5vTkxaOhx.....TmzCh2ikrwTMja7mUdBJf2bK3By5AB0
+Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQAB
+-----END PUBLIC KEY-----
+```
+
+Testing
+-------
+
+All cases are tested in `test.sh`.
+
+You can compare these keys to the ones that you get from OpenSSL, OpenSSH/ssh-keygen, and WebCrypto:
+
+```bash
+# Generate 2048-bit RSA Keypair
+openssl genrsa -out privkey-rsa-2048.pkcs1.pem 2048
+
+# Convert PKCS1 (traditional) RSA Keypair to PKCS8 format
+openssl rsa -in privkey-rsa-2048.pkcs1.pem -pubout -out pub-rsa-2048.spki.pem
+
+# Export Public-only RSA Key in PKCS1 (traditional) format
+openssl pkcs8 -topk8 -nocrypt -in privkey-rsa-2048.pkcs1.pem -out privkey-rsa-2048.pkcs8.pem
+
+# Convert PKCS1 (traditional) RSA Public Key to SPKI/PKIX format
+openssl rsa -in pub-rsa-2048.spki.pem -pubin -RSAPublicKey_out -out pub-rsa-2048.pkcs1.pem
+
+# Convert RSA public key to SSH format
+ssh-keygen -f ./pub-rsa-2048.spki.pem -i -mPKCS8 > ./pub-rsa-2048.ssh.pub
+```
+
+Goals of this project
+-----
+
+* Focused support for 2048-bit and 4096-bit RSA keypairs (although any size is technically supported)
+* Zero Dependencies
+* VanillaJS
+* Quality Code: Good comments and tests
+* Convert both ways: PEM-to-JWK and JWK-to-PEM (also supports SSH pub files)
+* Browser support as well (TODO)
+* OpenSSL, ssh-keygen, and WebCrypto compatibility
+
+Legal
+-----
+
+[Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js) |
+MPL-2.0 |
+[Terms of Use](https://therootcompany.com/legal/#terms) |
+[Privacy Policy](https://therootcompany.com/legal/#privacy)
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/bin/rasha.js b/express-server/node_modules/rsa-compat/lib/rasha/bin/rasha.js
new file mode 100644
index 00000000..4ffed3c5
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/bin/rasha.js
@@ -0,0 +1,97 @@
+#!/usr/bin/env node
+'use strict';
+
+var fs = require('fs');
+var Rasha = require('../index.js');
+var PEM = require('../lib/pem.js');
+var ASN1 = require('../lib/asn1.js');
+
+var infile = process.argv[2];
+var format = process.argv[3];
+var msg = process.argv[4];
+var sign;
+if ('sign' === format) {
+ sign = true;
+ format = 'pkcs8';
+}
+
+if (!infile) {
+ infile = 'jwk';
+}
+
+if (-1 !== [ 'jwk', 'pem', 'json', 'der', 'pkcs1', 'pkcs8', 'spki' ].indexOf(infile)) {
+ console.log("Generating new key...");
+ Rasha.generate({
+ format: infile
+ , modulusLength: parseInt(format, 10) || 2048
+ , encoding: parseInt(format, 10) ? null : format
+ }).then(function (key) {
+ if ('der' === infile || 'der' === format) {
+ key.private = key.private.toString('binary');
+ key.public = key.public.toString('binary');
+ }
+ console.log(key.private);
+ console.log(key.public);
+ }).catch(function (err) {
+ console.error(err);
+ process.exit(1);
+ });
+ return;
+}
+var key = fs.readFileSync(infile, 'ascii');
+
+try {
+ key = JSON.parse(key);
+} catch(e) {
+ // ignore
+}
+
+if ('string' === typeof key) {
+ if ('tpl' === format) {
+ var block = PEM.parseBlock(key);
+ var asn1 = ASN1.parse(block.der);
+ ASN1.tpl(asn1);
+ return;
+ }
+ if (sign) { signMessage(key, msg); return; }
+
+ var pub = (-1 !== [ 'public', 'spki', 'pkix' ].indexOf(format));
+ Rasha.import({ pem: key, public: (pub || format) }).then(function (jwk) {
+ console.info(JSON.stringify(jwk, null, 2));
+ }).catch(function (err) {
+ console.error(err);
+ process.exit(1);
+ });
+} else {
+ Rasha.export({ jwk: key, format: format }).then(function (pem) {
+ if (sign) { signMessage(pem, msg); return; }
+ console.info(pem);
+ }).catch(function (err) {
+ console.error(err);
+ process.exit(2);
+ });
+}
+
+function signMessage(pem, name) {
+ var msg;
+ try {
+ msg = fs.readFileSync(name);
+ } catch(e) {
+ console.warn("[info] input string did not exist as a file, signing the string itself");
+ msg = Buffer.from(name, 'binary');
+ }
+ var crypto = require('crypto');
+ var sign = crypto.createSign('SHA256');
+ sign.write(msg)
+ sign.end()
+ var buf = sign.sign(pem, 'hex');
+ console.log(buf);
+ //console.log(buf.toString('base64'));
+ /*
+ Rasha.sign({ pem: pem, message: msg, alg: 'SHA256' }).then(function (sig) {
+ }).catch(function () {
+ console.error(err);
+ process.exit(3);
+ });
+ */
+}
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.jwk.json b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.jwk.json
new file mode 100644
index 00000000..f344c22f
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.jwk.json
@@ -0,0 +1,11 @@
+{
+ "kty": "RSA",
+ "n": "m2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJefLukC-xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjskocn2BOnTB57qAZM6-I70on0_iDZm7-jcqOPgADAmbWHhy67BXkk4yy_YzD4yOGZFXZcNp915_TW5bRd__AKPHUHxJasPiyEFqlNKBR2DSD-LbX5eTmzCh2ikrwTMja7mUdBJf2bK3By5AB0Qi49OykUCfNZeQlEz7UNNj9RGps_50-CNw",
+ "e": "AQAB",
+ "d": "Cpfo7Mm9Nu8YMC_xrZ54W9mKHPkCG9rZ93Ds9PNp-RXUgb-ljTbFPZWsYxGNKLllFz8LNosr1pT2ZDMrwNk0Af1iWNvD6gkyXaiQdCyiDPSBsJyNv2LJZon-e85X74nv53UlIkmo9SYxdLz2JaJ-iIWEe8Qh-7llLktrTJV_xr98_tbhgSppz_IeOymq3SEZaQHM8pTU7w7XvCj2pb9r8fN0M0XcgWZIaf3LGEfkhF_WtX67XJ0C6-LbkT51jtlLRNGX6haGdscXS0OWWjKOJzKGuV-NbthEn5rmRtVnjRZ3yaxQ0ud8vC-NONn7yvGUlOur1IdDzJ_YfHPt9sHMQQ",
+ "p": "ynG-t9HwKCN3MWRYFdnFzi9-02Qcy3p8B5pu3ary2E70hYn2pHlUG2a9BNE8c5xHQ3Hx43WoWf6s0zOunPV1G28LkU_UYEbAtPv_PxSmzpQp9n9XnYvBLBF8Y3z7gxgLn1vVFNARrQdRtj87qY3aw7E9S4DsGcAarIuOT2TsTCE",
+ "q": "xIkAjgUzB1zaUzJtW2Zgvp9cYYr1DmpH30ePZl3c_8397_DZDDo46fnFYjs6uPa03HpmKUnbjwr14QHlfXlntJBEuXxcqLjkdKdJ4ob7xueLTK4suo9V8LSrkLChVxlZQwnFD2E5ll0sVeeDeMJHQw38ahSrBFEVnxjpnPh1Q1c",
+ "dp": "tzDGjECFOU0ehqtuqhcuT63a7h8hj19-7MJqoFwY9HQ-ALkfXyYLXeBSGxHbyiIYuodZg6LsfMNgUJ3r3Eyhc_nAVfYPEC_2IdAG4WYmq7iXYF9LQV09qEsKbFykm7QekE3hO7wswo5k-q2tp3ieBYdVGAXJoGOdv5VpaZ7B1QE",
+ "dq": "kh5dyDk7YCz7sUFbpsmuAeuPjoH2ghooh2u3xN7iUVmAg-ToKjwbVnG5-7eXiC779rQVwnrD_0yh1AFJ8wjRPqDIR7ObXGHikIxT1VSQWqiJm6AfZzDsL0LUD4YS3iPdhob7-NxLKWzqao_u4lhnDQaX9PKa12HFlny6K1daL48",
+ "qi": "AlHWbx1gp6Z9pbw_1hlS7HuXAgWoX7IjbTUelldf4gkriDWLOrj3QCZcO4ZvZvEwJhVlsny9LO8IkbwGJEL6cXraK08ByVS2mwQyflgTgGNnpzixyEUL_mrQLx6y145FHcxfeqNInMhep-0Mxn1D5nlhmIOgRApS0t9VoXtHhFU"
+}
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.pkcs1.pem b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.pkcs1.pem
new file mode 100644
index 00000000..246bd35c
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.pkcs1.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhD
+NzUJefLukC+xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ
+38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjskocn2BOnTB57
+qAZM6+I70on0/iDZm7+jcqOPgADAmbWHhy67BXkk4yy/YzD4yOGZFXZcNp915/TW
+5bRd//AKPHUHxJasPiyEFqlNKBR2DSD+LbX5eTmzCh2ikrwTMja7mUdBJf2bK3By
+5AB0Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQABAoIBAAqX6OzJvTbvGDAv
+8a2eeFvZihz5Ahva2fdw7PTzafkV1IG/pY02xT2VrGMRjSi5ZRc/CzaLK9aU9mQz
+K8DZNAH9Yljbw+oJMl2okHQsogz0gbCcjb9iyWaJ/nvOV++J7+d1JSJJqPUmMXS8
+9iWifoiFhHvEIfu5ZS5La0yVf8a/fP7W4YEqac/yHjspqt0hGWkBzPKU1O8O17wo
+9qW/a/HzdDNF3IFmSGn9yxhH5IRf1rV+u1ydAuvi25E+dY7ZS0TRl+oWhnbHF0tD
+lloyjicyhrlfjW7YRJ+a5kbVZ40Wd8msUNLnfLwvjTjZ+8rxlJTrq9SHQ8yf2Hxz
+7fbBzEECgYEAynG+t9HwKCN3MWRYFdnFzi9+02Qcy3p8B5pu3ary2E70hYn2pHlU
+G2a9BNE8c5xHQ3Hx43WoWf6s0zOunPV1G28LkU/UYEbAtPv/PxSmzpQp9n9XnYvB
+LBF8Y3z7gxgLn1vVFNARrQdRtj87qY3aw7E9S4DsGcAarIuOT2TsTCECgYEAxIkA
+jgUzB1zaUzJtW2Zgvp9cYYr1DmpH30ePZl3c/8397/DZDDo46fnFYjs6uPa03Hpm
+KUnbjwr14QHlfXlntJBEuXxcqLjkdKdJ4ob7xueLTK4suo9V8LSrkLChVxlZQwnF
+D2E5ll0sVeeDeMJHQw38ahSrBFEVnxjpnPh1Q1cCgYEAtzDGjECFOU0ehqtuqhcu
+T63a7h8hj19+7MJqoFwY9HQ+ALkfXyYLXeBSGxHbyiIYuodZg6LsfMNgUJ3r3Eyh
+c/nAVfYPEC/2IdAG4WYmq7iXYF9LQV09qEsKbFykm7QekE3hO7wswo5k+q2tp3ie
+BYdVGAXJoGOdv5VpaZ7B1QECgYEAkh5dyDk7YCz7sUFbpsmuAeuPjoH2ghooh2u3
+xN7iUVmAg+ToKjwbVnG5+7eXiC779rQVwnrD/0yh1AFJ8wjRPqDIR7ObXGHikIxT
+1VSQWqiJm6AfZzDsL0LUD4YS3iPdhob7+NxLKWzqao/u4lhnDQaX9PKa12HFlny6
+K1daL48CgYACUdZvHWCnpn2lvD/WGVLse5cCBahfsiNtNR6WV1/iCSuINYs6uPdA
+Jlw7hm9m8TAmFWWyfL0s7wiRvAYkQvpxetorTwHJVLabBDJ+WBOAY2enOLHIRQv+
+atAvHrLXjkUdzF96o0icyF6n7QzGfUPmeWGYg6BEClLS31Whe0eEVQ==
+-----END RSA PRIVATE KEY-----
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.pkcs8.pem b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.pkcs8.pem
new file mode 100644
index 00000000..53dbf837
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/privkey-rsa-2048.pkcs8.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCba21UHE+VbDTp
+mYYFZUOV+OQ8AngOCdjROsPC0KiEfMvEaEM3NQl58u6QL7G7QsErKViiNPm9OTFo
+6HF5JijfWzK7haHFuRMEsgI4VwIYyhvqlJDfw/wt0AiVvSmoMfEQn1p1aiaO4V/R
+JSE3Vw/uz2bxiT22uSkSqOyShyfYE6dMHnuoBkzr4jvSifT+INmbv6Nyo4+AAMCZ
+tYeHLrsFeSTjLL9jMPjI4ZkVdlw2n3Xn9NbltF3/8Ao8dQfElqw+LIQWqU0oFHYN
+IP4ttfl5ObMKHaKSvBMyNruZR0El/ZsrcHLkAHRCLj07KRQJ81l5CUTPtQ02P1Ea
+mz/nT4I3AgMBAAECggEACpfo7Mm9Nu8YMC/xrZ54W9mKHPkCG9rZ93Ds9PNp+RXU
+gb+ljTbFPZWsYxGNKLllFz8LNosr1pT2ZDMrwNk0Af1iWNvD6gkyXaiQdCyiDPSB
+sJyNv2LJZon+e85X74nv53UlIkmo9SYxdLz2JaJ+iIWEe8Qh+7llLktrTJV/xr98
+/tbhgSppz/IeOymq3SEZaQHM8pTU7w7XvCj2pb9r8fN0M0XcgWZIaf3LGEfkhF/W
+tX67XJ0C6+LbkT51jtlLRNGX6haGdscXS0OWWjKOJzKGuV+NbthEn5rmRtVnjRZ3
+yaxQ0ud8vC+NONn7yvGUlOur1IdDzJ/YfHPt9sHMQQKBgQDKcb630fAoI3cxZFgV
+2cXOL37TZBzLenwHmm7dqvLYTvSFifakeVQbZr0E0TxznEdDcfHjdahZ/qzTM66c
+9XUbbwuRT9RgRsC0+/8/FKbOlCn2f1edi8EsEXxjfPuDGAufW9UU0BGtB1G2Pzup
+jdrDsT1LgOwZwBqsi45PZOxMIQKBgQDEiQCOBTMHXNpTMm1bZmC+n1xhivUOakff
+R49mXdz/zf3v8NkMOjjp+cViOzq49rTcemYpSduPCvXhAeV9eWe0kES5fFyouOR0
+p0nihvvG54tMriy6j1XwtKuQsKFXGVlDCcUPYTmWXSxV54N4wkdDDfxqFKsEURWf
+GOmc+HVDVwKBgQC3MMaMQIU5TR6Gq26qFy5PrdruHyGPX37swmqgXBj0dD4AuR9f
+Jgtd4FIbEdvKIhi6h1mDoux8w2BQnevcTKFz+cBV9g8QL/Yh0AbhZiaruJdgX0tB
+XT2oSwpsXKSbtB6QTeE7vCzCjmT6ra2neJ4Fh1UYBcmgY52/lWlpnsHVAQKBgQCS
+Hl3IOTtgLPuxQVumya4B64+OgfaCGiiHa7fE3uJRWYCD5OgqPBtWcbn7t5eILvv2
+tBXCesP/TKHUAUnzCNE+oMhHs5tcYeKQjFPVVJBaqImboB9nMOwvQtQPhhLeI92G
+hvv43EspbOpqj+7iWGcNBpf08prXYcWWfLorV1ovjwKBgAJR1m8dYKemfaW8P9YZ
+Uux7lwIFqF+yI201HpZXX+IJK4g1izq490AmXDuGb2bxMCYVZbJ8vSzvCJG8BiRC
++nF62itPAclUtpsEMn5YE4BjZ6c4schFC/5q0C8esteORR3MX3qjSJzIXqftDMZ9
+Q+Z5YZiDoEQKUtLfVaF7R4RV
+-----END PRIVATE KEY-----
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.jwk.json b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.jwk.json
new file mode 100644
index 00000000..333b300e
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.jwk.json
@@ -0,0 +1,5 @@
+{
+ "kty": "RSA",
+ "n": "m2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJefLukC-xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjskocn2BOnTB57qAZM6-I70on0_iDZm7-jcqOPgADAmbWHhy67BXkk4yy_YzD4yOGZFXZcNp915_TW5bRd__AKPHUHxJasPiyEFqlNKBR2DSD-LbX5eTmzCh2ikrwTMja7mUdBJf2bK3By5AB0Qi49OykUCfNZeQlEz7UNNj9RGps_50-CNw",
+ "e": "AQAB"
+}
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.pkcs1.pem b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.pkcs1.pem
new file mode 100644
index 00000000..e592fdad
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.pkcs1.pem
@@ -0,0 +1,8 @@
+-----BEGIN RSA PUBLIC KEY-----
+MIIBCgKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJ
+efLukC+xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ38P8
+LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjskocn2BOnTB57qAZM
+6+I70on0/iDZm7+jcqOPgADAmbWHhy67BXkk4yy/YzD4yOGZFXZcNp915/TW5bRd
+//AKPHUHxJasPiyEFqlNKBR2DSD+LbX5eTmzCh2ikrwTMja7mUdBJf2bK3By5AB0
+Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQAB
+-----END RSA PUBLIC KEY-----
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.spki.pem b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.spki.pem
new file mode 100644
index 00000000..465d1155
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.spki.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2ttVBxPlWw06ZmGBWVD
+lfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJefLukC+xu0LBKylYojT5vTkxaOhxeSYo
+31syu4WhxbkTBLICOFcCGMob6pSQ38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP
+7s9m8Yk9trkpEqjskocn2BOnTB57qAZM6+I70on0/iDZm7+jcqOPgADAmbWHhy67
+BXkk4yy/YzD4yOGZFXZcNp915/TW5bRd//AKPHUHxJasPiyEFqlNKBR2DSD+LbX5
+eTmzCh2ikrwTMja7mUdBJf2bK3By5AB0Qi49OykUCfNZeQlEz7UNNj9RGps/50+C
+NwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.ssh.pub b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.ssh.pub
new file mode 100644
index 00000000..a00fd4cb
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/fixtures/pub-rsa-2048.ssh.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCba21UHE+VbDTpmYYFZUOV+OQ8AngOCdjROsPC0KiEfMvEaEM3NQl58u6QL7G7QsErKViiNPm9OTFo6HF5JijfWzK7haHFuRMEsgI4VwIYyhvqlJDfw/wt0AiVvSmoMfEQn1p1aiaO4V/RJSE3Vw/uz2bxiT22uSkSqOyShyfYE6dMHnuoBkzr4jvSifT+INmbv6Nyo4+AAMCZtYeHLrsFeSTjLL9jMPjI4ZkVdlw2n3Xn9NbltF3/8Ao8dQfElqw+LIQWqU0oFHYNIP4ttfl5ObMKHaKSvBMyNruZR0El/ZsrcHLkAHRCLj07KRQJ81l5CUTPtQ02P1Eamz/nT4I3 rsa@localhost
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/index.js b/express-server/node_modules/rsa-compat/lib/rasha/index.js
new file mode 100644
index 00000000..c538483e
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/index.js
@@ -0,0 +1,2 @@
+'use strict';
+module.exports = require('./lib/rasha.js');
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/lib/asn1.js b/express-server/node_modules/rsa-compat/lib/rasha/lib/asn1.js
new file mode 100644
index 00000000..bce9568b
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/lib/asn1.js
@@ -0,0 +1,235 @@
+'use strict';
+
+//
+// A dumbed-down, minimal ASN.1 parser / packer combo
+//
+// Note: generally I like to write congruent code
+// (i.e. output can be used as input and vice-versa)
+// However, this seemed to be more readable and easier
+// to use written as-is, asymmetrically.
+// (I also generally prefer to export objects rather
+// functions but, yet again, asthetics one in this case)
+
+var Enc = require('./encoding.js');
+
+//
+// Packer
+//
+
+// Almost every ASN.1 type that's important for CSR
+// can be represented generically with only a few rules.
+var ASN1 = module.exports = function ASN1(/*type, hexstrings...*/) {
+ var args = Array.prototype.slice.call(arguments);
+ var typ = args.shift();
+ var str = args.join('').replace(/\s+/g, '').toLowerCase();
+ var len = (str.length/2);
+ var lenlen = 0;
+ var hex = typ;
+
+ // We can't have an odd number of hex chars
+ if (len !== Math.round(len)) {
+ throw new Error("invalid hex");
+ }
+
+ // The first byte of any ASN.1 sequence is the type (Sequence, Integer, etc)
+ // The second byte is either the size of the value, or the size of its size
+
+ // 1. If the second byte is < 0x80 (128) it is considered the size
+ // 2. If it is > 0x80 then it describes the number of bytes of the size
+ // ex: 0x82 means the next 2 bytes describe the size of the value
+ // 3. The special case of exactly 0x80 is "indefinite" length (to end-of-file)
+
+ if (len > 127) {
+ lenlen += 1;
+ while (len > 255) {
+ lenlen += 1;
+ len = len >> 8;
+ }
+ }
+
+ if (lenlen) { hex += Enc.numToHex(0x80 + lenlen); }
+ return hex + Enc.numToHex(str.length/2) + str;
+};
+
+// The Integer type has some special rules
+ASN1.UInt = function UINT() {
+ var str = Array.prototype.slice.call(arguments).join('');
+ var first = parseInt(str.slice(0, 2), 16);
+
+ // If the first byte is 0x80 or greater, the number is considered negative
+ // Therefore we add a '00' prefix if the 0x80 bit is set
+ if (0x80 & first) { str = '00' + str; }
+
+ return ASN1('02', str);
+};
+
+// The Bit String type also has a special rule
+ASN1.BitStr = function BITSTR() {
+ var str = Array.prototype.slice.call(arguments).join('');
+ // '00' is a mask of how many bits of the next byte to ignore
+ return ASN1('03', '00' + str);
+};
+
+
+//
+// Parser
+//
+
+ASN1.ELOOP = "uASN1.js Error: iterated over 15+ elements (probably a malformed file)";
+ASN1.EDEEP = "uASN1.js Error: element nested 20+ layers deep (probably a malformed file)";
+// Container Types are Sequence 0x30, Octect String 0x04, Array? (0xA0, 0xA1)
+// Value Types are Integer 0x02, Bit String 0x03, Null 0x05, Object ID 0x06,
+// Sometimes Bit String is used as a container (RSA Pub Spki)
+ASN1.VTYPES = [ 0x02, 0x03, 0x05, 0x06, 0x0c, 0x82 ];
+ASN1.parse = function parseAsn1(buf, depth, ws) {
+ if (!ws) { ws = ''; }
+ if (depth >= 20) { throw new Error(ASN1.EDEEP); }
+
+ var index = 2; // we know, at minimum, data starts after type (0) and lengthSize (1)
+ var asn1 = { type: buf[0], lengthSize: 0, length: buf[1] };
+ var child;
+ var iters = 0;
+ var adjust = 0;
+ var adjustedLen;
+
+ // Determine how many bytes the length uses, and what it is
+ if (0x80 & asn1.length) {
+ asn1.lengthSize = 0x7f & asn1.length;
+ // I think that buf->hex->int solves the problem of Endianness... not sure
+ asn1.length = parseInt(Enc.bufToHex(buf.slice(index, index + asn1.lengthSize)), 16);
+ index += asn1.lengthSize;
+ }
+
+ // High-order bit Integers have a leading 0x00 to signify that they are positive.
+ // Bit Streams use the first byte to signify padding, which x.509 doesn't use.
+ if (0x00 === buf[index] && (0x02 === asn1.type || 0x03 === asn1.type)) {
+ // However, 0x00 on its own is a valid number
+ if (asn1.length > 1) {
+ index += 1;
+ adjust = -1;
+ }
+ }
+ adjustedLen = asn1.length + adjust;
+
+ //console.warn(ws + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
+
+ // this is a primitive value type
+ if (-1 !== ASN1.VTYPES.indexOf(asn1.type)) {
+ asn1.value = buf.slice(index, index + adjustedLen);
+ return asn1;
+ }
+
+ asn1.children = [];
+ //console.warn('1 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', 0);
+ while (iters < 15 && index < (2 + asn1.length + asn1.lengthSize)) {
+ iters += 1;
+ child = ASN1.parse(buf.slice(index, index + adjustedLen), (depth || 0) + 1, ws + ' ');
+ // The numbers don't match up exactly and I don't remember why...
+ // probably something with adjustedLen or some such, but the tests pass
+ index += (2 + child.lengthSize + child.length);
+ //console.warn('2 len:', (2 + asn1.lengthSize + asn1.length), 'idx:', index, 'clen:', (2 + child.lengthSize + child.length));
+ if (index > (2 + asn1.lengthSize + asn1.length)) {
+ console.error(JSON.stringify(asn1, function (k, v) {
+ if ('value' === k) { return '0x' + Enc.bufToHex(v.data); } return v;
+ }, 2));
+ throw new Error("Parse error: child value length (" + child.length
+ + ") is greater than remaining parent length (" + (asn1.length - index)
+ + " = " + asn1.length + " - " + index + ")");
+ }
+ asn1.children.push(child);
+ //console.warn(ws + '0x' + Enc.numToHex(asn1.type), index, 'len:', asn1.length, asn1);
+ }
+ if (index !== (2 + asn1.lengthSize + asn1.length)) {
+ console.warn('index:', index, 'length:', (2 + asn1.lengthSize + asn1.length))
+ throw new Error("premature end-of-file");
+ }
+ if (iters >= 15) { throw new Error(ASN1.ELOOP); }
+
+ return asn1;
+};
+
+/*
+ASN1._stringify = function(asn1) {
+ //console.log(JSON.stringify(asn1, null, 2));
+ //console.log(asn1);
+ var ws = '';
+
+ function write(asn1) {
+ console.log(ws, 'ch', Enc.numToHex(asn1.type), asn1.length);
+ if (!asn1.children) {
+ return;
+ }
+ asn1.children.forEach(function (a) {
+ ws += '\t';
+ write(a);
+ ws = ws.slice(1);
+ });
+ }
+ write(asn1);
+};
+*/
+
+ASN1.tpl = function (asn1) {
+ //console.log(JSON.stringify(asn1, null, 2));
+ //console.log(asn1);
+ var sp = ' ';
+ var ws = sp;
+ var i = 0;
+ var vars = [];
+ var str = ws;
+
+ function write(asn1, k) {
+ str += "\n" + ws;
+ var val;
+ if ('number' !== typeof k) {
+ // ignore
+ } else {
+ str += ', ';
+ }
+ if (0x02 === asn1.type) {
+ str += "ASN1.UInt(";
+ } else if (0x03 === asn1.type) {
+ str += "ASN1.BitStr(";
+ } else {
+ str += "ASN1('" + Enc.numToHex(asn1.type) + "'";
+ }
+ if (!asn1.children) {
+ if (0x05 !== asn1.type) {
+ if (0x06 !== asn1.type) {
+ val = asn1.value || new Uint8Array(0);
+ vars.push("\n// 0x" + Enc.numToHex(val.byteLength) + " (" + val.byteLength + " bytes)\nopts.tpl" + i + " = '"
+ + Enc.bufToHex(val) + "';");
+ if (0x02 !== asn1.type && 0x03 !== asn1.type) {
+ str += ", ";
+ }
+ str += "Enc.bufToHex(opts.tpl" + i + ")";
+ } else {
+ str += ", '" + Enc.bufToHex(asn1.value) + "'";
+ }
+ } else {
+ console.warn("XXXXXXXXXXXXXXXXXXXXX");
+ }
+ str += ")";
+ return ;
+ }
+ asn1.children.forEach(function (a, j) {
+ i += 1;
+ ws += sp;
+ write(a, j);
+ ws = ws.slice(sp.length);
+ });
+ str += "\n" + ws + ")";
+ }
+
+ write(asn1);
+ console.log('var opts = {};');
+ console.log(vars.join('\n') + '\n');
+ console.log();
+ console.log('function buildSchema(opts) {');
+ console.log(sp + 'return Enc.hexToBuf(' + str.slice(3) + ');');
+ console.log('}');
+ console.log();
+ console.log('buildSchema(opts);');
+};
+
+module.exports = ASN1;
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/lib/encoding.js b/express-server/node_modules/rsa-compat/lib/rasha/lib/encoding.js
new file mode 100644
index 00000000..7ed4116d
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/lib/encoding.js
@@ -0,0 +1,104 @@
+'use strict';
+
+var Enc = module.exports;
+
+Enc.base64ToBuf = function (str) {
+ // always convert from urlsafe base64, just in case
+ //return Buffer.from(Enc.urlBase64ToBase64(str)).toString('base64');
+ // node handles urlBase64 automatically
+ return Buffer.from(str, 'base64');
+};
+
+Enc.base64ToHex = function (b64) {
+ return Enc.bufToHex(Enc.base64ToBuf(b64));
+};
+
+Enc.bufToBase64 = function (u8) {
+ // we want to maintain api compatability with browser APIs,
+ // so we assume that this could be a Uint8Array
+ return Buffer.from(u8).toString('base64');
+};
+
+/*
+Enc.bufToUint8 = function bufToUint8(buf) {
+ return new Uint8Array(buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength));
+};
+*/
+
+Enc.bufToUrlBase64 = function (u8) {
+ return Enc.bufToBase64(u8)
+ .replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
+};
+
+
+Enc.bufToHex = function (u8) {
+ var hex = [];
+ var i, h;
+ var len = (u8.byteLength || u8.length);
+
+ for (i = 0; i < len; i += 1) {
+ h = u8[i].toString(16);
+ if (2 !== h.length) { h = '0' + h; }
+ hex.push(h);
+ }
+
+ return hex.join('').toLowerCase();
+};
+
+Enc.hexToBase64 = function (hex) {
+ return Buffer.from(hex, 'hex').toString('base64');
+};
+
+Enc.hexToBuf = function (hex) {
+ return Buffer.from(hex, 'hex');
+};
+
+Enc.numToHex = function (d) {
+ d = d.toString(16);
+ if (d.length % 2) {
+ return '0' + d;
+ }
+ return d;
+};
+
+/*
+Enc.strToBase64 = function (str) {
+ // node automatically can tell the difference
+ // between uc2 (utf-8) strings and binary strings
+ // so we don't have to re-encode the strings
+ return Buffer.from(str).toString('base64');
+};
+*/
+
+/*
+Enc.strToBin = function (str) {
+ var escstr = encodeURIComponent(str);
+ // replaces any uri escape sequence, such as %0A,
+ // with binary escape, such as 0x0A
+ var binstr = escstr.replace(/%([0-9A-F]{2})/g, function(match, p1) {
+ return String.fromCharCode(parseInt(p1, 16));
+ });
+
+ return binstr;
+};
+*/
+
+Enc.strToBuf = function (str) {
+ return Buffer.from(str);
+};
+
+Enc.strToHex = function (str) {
+ return Buffer.from(str).toString('hex');
+};
+
+/*
+Enc.urlBase64ToBase64 = function (str) {
+ var r = str % 4;
+ if (2 === r) {
+ str += '==';
+ } else if (3 === r) {
+ str += '=';
+ }
+ return str.replace(/-/g, '+').replace(/_/g, '/');
+};
+*/
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/lib/pem.js b/express-server/node_modules/rsa-compat/lib/rasha/lib/pem.js
new file mode 100644
index 00000000..76aec964
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/lib/pem.js
@@ -0,0 +1,28 @@
+'use strict';
+
+var PEM = module.exports;
+var Enc = require('./encoding.js');
+
+PEM.parseBlock = function pemToDer(pem) {
+ var lines = pem.trim().split(/\n/);
+ var end = lines.length - 1;
+ var head = lines[0].match(/-----BEGIN (.*)-----/);
+ var foot = lines[end].match(/-----END (.*)-----/);
+
+ if (head) {
+ lines = lines.slice(1, end);
+ head = head[1];
+ if (head !== foot[1]) {
+ throw new Error("headers and footers do not match");
+ }
+ }
+
+ return { type: head, bytes: Enc.base64ToBuf(lines.join('')) };
+};
+
+PEM.packBlock = function (opts) {
+ return '-----BEGIN ' + opts.type + '-----\n'
+ + Enc.bufToBase64(opts.bytes).match(/.{1,64}/g).join('\n') + '\n'
+ + '-----END ' + opts.type + '-----'
+ ;
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/lib/rasha.js b/express-server/node_modules/rsa-compat/lib/rasha/lib/rasha.js
new file mode 100644
index 00000000..67d1d0b4
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/lib/rasha.js
@@ -0,0 +1,204 @@
+'use strict';
+
+var RSA = module.exports;
+var SSH = require('./ssh.js');
+var PEM = require('./pem.js');
+var x509 = require('./x509.js');
+var ASN1 = require('./asn1.js');
+
+/*global Promise*/
+RSA.generate = function (opts) {
+ return Promise.resolve().then(function () {
+ var typ = 'rsa';
+ var format = opts.format;
+ var encoding = opts.encoding;
+ var priv;
+ var pub;
+
+ if (!format) {
+ format = 'jwk';
+ }
+ if ('spki' === format || 'pkcs8' === format) {
+ format = 'pkcs8';
+ pub = 'spki';
+ }
+
+ if ('pem' === format) {
+ format = 'pkcs1';
+ encoding = 'pem';
+ } else if ('der' === format) {
+ format = 'pkcs1';
+ encoding = 'der';
+ }
+
+ if ('jwk' === format || 'json' === format) {
+ format = 'jwk';
+ encoding = 'json';
+ } else {
+ priv = format;
+ pub = pub || format;
+ }
+
+ if (!encoding) {
+ encoding = 'pem';
+ }
+
+ if (priv) {
+ priv = { type: priv, format: encoding };
+ pub = { type: pub, format: encoding };
+ } else {
+ // jwk
+ priv = { type: 'pkcs1', format: 'pem' };
+ pub = { type: 'pkcs1', format: 'pem' };
+ }
+
+ return new Promise(function (resolve, reject) {
+ return require('crypto').generateKeyPair(typ, {
+ modulusLength: opts.modulusLength || 2048
+ , publicExponent: opts.publicExponent || 0x10001
+ , privateKeyEncoding: priv
+ , publicKeyEncoding: pub
+ }, function (err, pubkey, privkey) {
+ if (err) { reject(err); }
+ resolve({
+ private: privkey
+ , public: pubkey
+ });
+ });
+ }).then(function (keypair) {
+ if ('jwk' !== format) {
+ return keypair;
+ }
+
+ return {
+ private: RSA.importSync({ pem: keypair.private, format: priv.type })
+ , public: RSA.importSync({ pem: keypair.public, format: pub.type, public: true })
+ };
+ });
+ });
+};
+
+RSA.importSync = function (opts) {
+ if (!opts || !opts.pem || 'string' !== typeof opts.pem) {
+ throw new Error("must pass { pem: pem } as a string");
+ }
+
+ var jwk = { kty: 'RSA', n: null, e: null };
+ if (0 === opts.pem.indexOf('ssh-rsa ')) {
+ return SSH.parse(opts.pem, jwk);
+ }
+ var pem = opts.pem;
+ var block = PEM.parseBlock(pem);
+ //var hex = toHex(u8);
+ var asn1 = ASN1.parse(block.bytes);
+
+ var meta = x509.guess(block.bytes, asn1);
+
+ if ('pkcs1' === meta.format) {
+ jwk = x509.parsePkcs1(block.bytes, asn1, jwk);
+ } else {
+ jwk = x509.parsePkcs8(block.bytes, asn1, jwk);
+ }
+
+ if (opts.public) {
+ jwk = RSA.nueter(jwk);
+ }
+ return jwk;
+};
+RSA.parse = function parseRsa(opts) {
+ // wrapped in a promise for API compatibility
+ // with the forthcoming browser version
+ // (and potential future native node capability)
+ return Promise.resolve().then(function () {
+ return RSA.importSync(opts);
+ });
+};
+RSA.toJwk = RSA.import = RSA.parse;
+
+/*
+RSAPrivateKey ::= SEQUENCE {
+ version Version,
+ modulus INTEGER, -- n
+ publicExponent INTEGER, -- e
+ privateExponent INTEGER, -- d
+ prime1 INTEGER, -- p
+ prime2 INTEGER, -- q
+ exponent1 INTEGER, -- d mod (p-1)
+ exponent2 INTEGER, -- d mod (q-1)
+ coefficient INTEGER, -- (inverse of q) mod p
+ otherPrimeInfos OtherPrimeInfos OPTIONAL
+}
+*/
+
+RSA.exportSync = function (opts) {
+ if (!opts || !opts.jwk || 'object' !== typeof opts.jwk) {
+ throw new Error("must pass { jwk: jwk }");
+ }
+ var jwk = JSON.parse(JSON.stringify(opts.jwk));
+ var format = opts.format;
+ var pub = opts.public;
+ if (pub || -1 !== [ 'spki', 'pkix', 'ssh', 'rfc4716' ].indexOf(format)) {
+ jwk = RSA.nueter(jwk);
+ }
+ if ('RSA' !== jwk.kty) {
+ throw new Error("options.jwk.kty must be 'RSA' for RSA keys");
+ }
+ if (!jwk.p) {
+ // TODO test for n and e
+ pub = true;
+ if (!format || 'pkcs1' === format) {
+ format = 'pkcs1';
+ } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
+ format = 'spki';
+ } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
+ format = 'ssh';
+ } else {
+ throw new Error("options.format must be 'spki', 'pkcs1', or 'ssh' for public RSA keys, not ("
+ + typeof format + ") " + format);
+ }
+ } else {
+ // TODO test for all necessary keys (d, p, q ...)
+ if (!format || 'pkcs1' === format) {
+ format = 'pkcs1';
+ } else if ('pkcs8' !== format) {
+ throw new Error("options.format must be 'pkcs1' or 'pkcs8' for private RSA keys");
+ }
+ }
+
+ if ('pkcs1' === format) {
+ if (jwk.d) {
+ return PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: x509.packPkcs1(jwk) });
+ } else {
+ return PEM.packBlock({ type: "RSA PUBLIC KEY", bytes: x509.packPkcs1(jwk) });
+ }
+ } else if ('pkcs8' === format) {
+ return PEM.packBlock({ type: "PRIVATE KEY", bytes: x509.packPkcs8(jwk) });
+ } else if (-1 !== [ 'spki', 'pkix' ].indexOf(format)) {
+ return PEM.packBlock({ type: "PUBLIC KEY", bytes: x509.packSpki(jwk) });
+ } else if (-1 !== [ 'ssh', 'rfc4716' ].indexOf(format)) {
+ return SSH.pack({ jwk: jwk, comment: opts.comment });
+ } else {
+ throw new Error("Sanity Error: reached unreachable code block with format: " + format);
+ }
+};
+RSA.pack = function (opts) {
+ // wrapped in a promise for API compatibility
+ // with the forthcoming browser version
+ // (and potential future native node capability)
+ return Promise.resolve().then(function () {
+ return RSA.exportSync(opts);
+ });
+};
+RSA.toPem = RSA.export = RSA.pack;
+
+// snip the _private_ parts... hAHAHAHA!
+RSA.nueter = function (jwk) {
+ // (snip rather than new object to keep potential extra data)
+ // otherwise we could just do this:
+ // return { kty: jwk.kty, n: jwk.n, e: jwk.e };
+ [ 'p', 'q', 'd', 'dp', 'dq', 'qi' ].forEach(function (key) {
+ if (key in jwk) { jwk[key] = undefined; }
+ return jwk;
+ });
+ return jwk;
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/lib/ssh.js b/express-server/node_modules/rsa-compat/lib/rasha/lib/ssh.js
new file mode 100644
index 00000000..63041714
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/lib/ssh.js
@@ -0,0 +1,80 @@
+'use strict';
+
+var SSH = module.exports;
+var Enc = require('./encoding.js');
+
+ // 7 s s h - r s a
+SSH.RSA = '00000007 73 73 68 2d 72 73 61'.replace(/\s+/g, '').toLowerCase();
+
+SSH.parse = function (pem, jwk) {
+
+ var parts = pem.split(/\s+/);
+ var buf = Enc.base64ToBuf(parts[1]);
+ var els = [];
+ var index = 0;
+ var len;
+ var i = 0;
+ var offset = (buf.byteOffset || 0);
+ // using dataview to be browser-compatible (I do want _some_ code reuse)
+ var dv = new DataView(buf.buffer.slice(offset, offset + buf.byteLength));
+ var el;
+
+ if (SSH.RSA !== Enc.bufToHex(buf.slice(0, SSH.RSA.length/2))) {
+ throw new Error("does not lead with ssh header");
+ }
+
+ while (index < buf.byteLength) {
+ i += 1;
+ if (i > 3) { throw new Error("15+ elements, probably not a public ssh key"); }
+ len = dv.getUint32(index, false);
+ index += 4;
+ el = buf.slice(index, index + len);
+ // remove BigUInt '00' prefix
+ if (0x00 === el[0]) {
+ el = el.slice(1);
+ }
+ els.push(el);
+ index += len;
+ }
+
+ jwk.n = Enc.bufToUrlBase64(els[2]);
+ jwk.e = Enc.bufToUrlBase64(els[1]);
+
+ return jwk;
+};
+
+SSH.pack = function (opts) {
+ var jwk = opts.jwk;
+ var header = 'ssh-rsa';
+ var comment = opts.comment || 'rsa@localhost';
+ var e = SSH._padHexInt(Enc.base64ToHex(jwk.e));
+ var n = SSH._padHexInt(Enc.base64ToHex(jwk.n));
+ var hex = [
+ SSH._numToUint32Hex(header.length)
+ , Enc.strToHex(header)
+ , SSH._numToUint32Hex(e.length/2)
+ , e
+ , SSH._numToUint32Hex(n.length/2)
+ , n
+ ].join('');
+ return [ header, Enc.hexToBase64(hex), comment ].join(' ');
+};
+
+SSH._numToUint32Hex = function (num) {
+ var hex = num.toString(16);
+ while (hex.length < 8) {
+ hex = '0' + hex;
+ }
+ return hex;
+};
+
+SSH._padHexInt = function (hex) {
+ // BigInt is negative if the high order bit 0x80 is set,
+ // so ASN1, SSH, and many other formats pad with '0x00'
+ // to signifiy a positive number.
+ var i = parseInt(hex.slice(0, 2), 16);
+ if (0x80 & i) {
+ return '00' + hex;
+ }
+ return hex;
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/lib/telemetry.js b/express-server/node_modules/rsa-compat/lib/rasha/lib/telemetry.js
new file mode 100644
index 00000000..9623b775
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/lib/telemetry.js
@@ -0,0 +1,111 @@
+'use strict';
+
+// We believe in a proactive approach to sustainable open source.
+// As part of that we make it easy for you to opt-in to following our progress
+// and we also stay up-to-date on telemetry such as operating system and node
+// version so that we can focus our efforts where they'll have the greatest impact.
+//
+// Want to learn more about our Terms, Privacy Policy, and Mission?
+// Check out https://therootcompany.com/legal/
+
+var os = require('os');
+var crypto = require('crypto');
+var https = require('https');
+var pkg = require('../package.json');
+
+// to help focus our efforts in the right places
+var data = {
+ package: pkg.name
+, version: pkg.version
+, node: process.version
+, arch: process.arch || os.arch()
+, platform: process.platform || os.platform()
+, release: os.release()
+};
+
+function addCommunityMember(opts) {
+ setTimeout(function () {
+ var req = https.request({
+ hostname: 'api.therootcompany.com'
+ , port: 443
+ , path: '/api/therootcompany.com/public/community'
+ , method: 'POST'
+ , headers: { 'Content-Type': 'application/json' }
+ }, function (resp) {
+ // let the data flow, so we can ignore it
+ resp.on('data', function () {});
+ //resp.on('data', function (chunk) { console.log(chunk.toString()); });
+ resp.on('error', function () { /*ignore*/ });
+ //resp.on('error', function (err) { console.error(err); });
+ });
+ var obj = JSON.parse(JSON.stringify(data));
+ obj.action = 'updates';
+ try {
+ obj.ppid = ppid(obj.action);
+ } catch(e) {
+ // ignore
+ //console.error(e);
+ }
+ obj.name = opts.name || undefined;
+ obj.address = opts.email;
+ obj.community = 'node.js@therootcompany.com';
+
+ req.write(JSON.stringify(obj, 2, null));
+ req.end();
+ req.on('error', function () { /*ignore*/ });
+ //req.on('error', function (err) { console.error(err); });
+ }, 50);
+}
+
+function ping(action) {
+ setTimeout(function () {
+ var req = https.request({
+ hostname: 'api.therootcompany.com'
+ , port: 443
+ , path: '/api/therootcompany.com/public/ping'
+ , method: 'POST'
+ , headers: { 'Content-Type': 'application/json' }
+ }, function (resp) {
+ // let the data flow, so we can ignore it
+ resp.on('data', function () { });
+ //resp.on('data', function (chunk) { console.log(chunk.toString()); });
+ resp.on('error', function () { /*ignore*/ });
+ //resp.on('error', function (err) { console.error(err); });
+ });
+ var obj = JSON.parse(JSON.stringify(data));
+ obj.action = action;
+ try {
+ obj.ppid = ppid(obj.action);
+ } catch(e) {
+ // ignore
+ //console.error(e);
+ }
+
+ req.write(JSON.stringify(obj, 2, null));
+ req.end();
+ req.on('error', function (/*e*/) { /*console.error('req.error', e);*/ });
+ }, 50);
+}
+
+// to help identify unique installs without getting
+// the personally identifiable info that we don't want
+function ppid(action) {
+ var parts = [ action, data.package, data.version, data.node, data.arch, data.platform, data.release ];
+ var ifaces = os.networkInterfaces();
+ Object.keys(ifaces).forEach(function (ifname) {
+ if (/^en/.test(ifname) || /^eth/.test(ifname) || /^wl/.test(ifname)) {
+ if (ifaces[ifname] && ifaces[ifname].length) {
+ parts.push(ifaces[ifname][0].mac);
+ }
+ }
+ });
+ return crypto.createHash('sha1').update(parts.join(',')).digest('base64');
+}
+
+module.exports.ping = ping;
+module.exports.joinCommunity = addCommunityMember;
+
+if (require.main === module) {
+ ping('install');
+ //addCommunityMember({ name: "AJ ONeal", email: 'coolaj86@gmail.com' });
+}
diff --git a/express-server/node_modules/rsa-compat/lib/rasha/lib/x509.js b/express-server/node_modules/rsa-compat/lib/rasha/lib/x509.js
new file mode 100644
index 00000000..fb193e16
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rasha/lib/x509.js
@@ -0,0 +1,153 @@
+'use strict';
+
+var x509 = module.exports;
+var ASN1 = require('./asn1.js');
+var Enc = require('./encoding.js');
+
+x509.guess = function (der, asn1) {
+ // accepting der for compatability with other usages
+
+ var meta = { kty: 'RSA', format: 'pkcs1', public: true };
+ //meta.asn1 = ASN1.parse(u8);
+
+ if (asn1.children.every(function(el) {
+ return 0x02 === el.type;
+ })) {
+ if (2 === asn1.children.length) {
+ // rsa pkcs1 public
+ return meta;
+ } else if (asn1.children.length >= 9) {
+ // the standard allows for "otherPrimeInfos", hence at least 9
+ meta.public = false;
+ // rsa pkcs1 private
+ return meta;
+ } else {
+ throw new Error("not an RSA PKCS#1 public or private key (wrong number of ints)");
+ }
+ } else {
+ meta.format = 'pkcs8';
+ }
+
+ return meta;
+};
+
+x509.parsePkcs1 = function parseRsaPkcs1(buf, asn1, jwk) {
+ if (!asn1.children.every(function(el) {
+ return 0x02 === el.type;
+ })) {
+ throw new Error("not an RSA PKCS#1 public or private key (not all ints)");
+ }
+
+ if (2 === asn1.children.length) {
+
+ jwk.n = Enc.bufToUrlBase64(asn1.children[0].value);
+ jwk.e = Enc.bufToUrlBase64(asn1.children[1].value);
+ return jwk;
+
+ } else if (asn1.children.length >= 9) {
+ // the standard allows for "otherPrimeInfos", hence at least 9
+
+ jwk.n = Enc.bufToUrlBase64(asn1.children[1].value);
+ jwk.e = Enc.bufToUrlBase64(asn1.children[2].value);
+ jwk.d = Enc.bufToUrlBase64(asn1.children[3].value);
+ jwk.p = Enc.bufToUrlBase64(asn1.children[4].value);
+ jwk.q = Enc.bufToUrlBase64(asn1.children[5].value);
+ jwk.dp = Enc.bufToUrlBase64(asn1.children[6].value);
+ jwk.dq = Enc.bufToUrlBase64(asn1.children[7].value);
+ jwk.qi = Enc.bufToUrlBase64(asn1.children[8].value);
+ return jwk;
+
+ } else {
+ throw new Error("not an RSA PKCS#1 public or private key (wrong number of ints)");
+ }
+};
+
+x509.parsePkcs8 = function parseRsaPkcs8(buf, asn1, jwk) {
+ if (2 === asn1.children.length
+ && 0x03 === asn1.children[1].type
+ && 0x30 === asn1.children[1].value[0]) {
+
+ asn1 = ASN1.parse(asn1.children[1].value);
+ jwk.n = Enc.bufToUrlBase64(asn1.children[0].value);
+ jwk.e = Enc.bufToUrlBase64(asn1.children[1].value);
+
+ } else if (3 === asn1.children.length
+ && 0x04 === asn1.children[2].type
+ && 0x30 === asn1.children[2].children[0].type
+ && 0x02 === asn1.children[2].children[0].children[0].type) {
+
+ asn1 = asn1.children[2].children[0];
+ jwk.n = Enc.bufToUrlBase64(asn1.children[1].value);
+ jwk.e = Enc.bufToUrlBase64(asn1.children[2].value);
+ jwk.d = Enc.bufToUrlBase64(asn1.children[3].value);
+ jwk.p = Enc.bufToUrlBase64(asn1.children[4].value);
+ jwk.q = Enc.bufToUrlBase64(asn1.children[5].value);
+ jwk.dp = Enc.bufToUrlBase64(asn1.children[6].value);
+ jwk.dq = Enc.bufToUrlBase64(asn1.children[7].value);
+ jwk.qi = Enc.bufToUrlBase64(asn1.children[8].value);
+
+ } else {
+ throw new Error("not an RSA PKCS#8 public or private key (wrong format)");
+ }
+ return jwk;
+};
+
+x509.packPkcs1 = function (jwk) {
+ var n = ASN1.UInt(Enc.base64ToHex(jwk.n));
+ var e = ASN1.UInt(Enc.base64ToHex(jwk.e));
+
+ if (!jwk.d) {
+ return Enc.hexToBuf(ASN1('30', n, e));
+ }
+
+ return Enc.hexToBuf(ASN1('30'
+ , ASN1.UInt('00')
+ , n
+ , e
+ , ASN1.UInt(Enc.base64ToHex(jwk.d))
+ , ASN1.UInt(Enc.base64ToHex(jwk.p))
+ , ASN1.UInt(Enc.base64ToHex(jwk.q))
+ , ASN1.UInt(Enc.base64ToHex(jwk.dp))
+ , ASN1.UInt(Enc.base64ToHex(jwk.dq))
+ , ASN1.UInt(Enc.base64ToHex(jwk.qi))
+ ));
+};
+
+x509.packPkcs8 = function (jwk) {
+ if (!jwk.d) {
+ // Public RSA
+ return Enc.hexToBuf(ASN1('30'
+ , ASN1('30'
+ , ASN1('06', '2a864886f70d010101')
+ , ASN1('05')
+ )
+ , ASN1.BitStr(ASN1('30'
+ , ASN1.UInt(Enc.base64ToHex(jwk.n))
+ , ASN1.UInt(Enc.base64ToHex(jwk.e))
+ ))
+ ));
+ }
+
+ // Private RSA
+ return Enc.hexToBuf(ASN1('30'
+ , ASN1.UInt('00')
+ , ASN1('30'
+ , ASN1('06', '2a864886f70d010101')
+ , ASN1('05')
+ )
+ , ASN1('04'
+ , ASN1('30'
+ , ASN1.UInt('00')
+ , ASN1.UInt(Enc.base64ToHex(jwk.n))
+ , ASN1.UInt(Enc.base64ToHex(jwk.e))
+ , ASN1.UInt(Enc.base64ToHex(jwk.d))
+ , ASN1.UInt(Enc.base64ToHex(jwk.p))
+ , ASN1.UInt(Enc.base64ToHex(jwk.q))
+ , ASN1.UInt(Enc.base64ToHex(jwk.dp))
+ , ASN1.UInt(Enc.base64ToHex(jwk.dq))
+ , ASN1.UInt(Enc.base64ToHex(jwk.qi))
+ )
+ )
+ ));
+};
+x509.packSpki = x509.packPkcs8;
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/README.md b/express-server/node_modules/rsa-compat/lib/rsa-csr/README.md
new file mode 100644
index 00000000..108d55ae
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/README.md
@@ -0,0 +1,214 @@
+[RSA-CSR.js](https://git.coolaj86.com/coolaj86/rsa-csr.js)
+==========
+
+Sponsored by [Root](https://therootcompany.com),
+built for [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
+and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock-express.js)
+
+A focused, **zero-dependency** library that can do exactly one thing really, really well:
+ * Generate a Certificate Signing Requests (CSR), and sign it!
+
+| < 300 lines of code | 1.7k gzipped | 4.7k minified | 8.5k with comments |
+
+Need JWK-to-PEM? Try [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js)
+
+Need to generate an EC CSR? Try [ECSDA-CSR.js](https://git.coolaj86.com/coolaj86/ecdsa-csr.js)
+
+Features
+========
+
+* [x] Universal CSR support (RSA signing) that Just Works™
+ * Common Name (CN) Subject
+ * Subject Alternative Names (SANs / altnames)
+ * 2048, 3072, and 4096 bit JWK RSA
+ * RSASSA PKCS1 v1.5
+* [x] Zero Dependencies
+ * (no ASN1.js, PKI.js, forge, jrsasign - not even elliptic.js!)
+* [x] Quality
+ * Focused
+ * Lightweight
+ * Well-Commented, Well-Documented
+ * Secure
+* [x] Vanilla Node.js
+ * no school like the old school
+ * easy to read and understand
+
+Usage
+-----
+
+Given an array of domains it uses the first for the Common Name (CN),
+also known as Subject, and all of them as the Subject Alternative Names (SANs or altnames).
+
+```js
+'use strict';
+
+var rsacsr = require('rsa-csr');
+var key = {
+ "kty": "RSA",
+ "n": "m2tt...-CNw",
+ "e": "AQAB",
+ "d": "Cpfo...HMQQ",
+ "p": "ynG-...sTCE",
+ "q": "xIkA...1Q1c",
+ "dp": "tzDG...B1QE",
+ "dq": "kh5d...aL48",
+ "qi": "AlHW...HhFU"
+};
+var domains = [ 'example.com', 'www.example.com' ];
+
+return rsacsr({ key: key, domains: domains }).then(function (csr) {
+ console.log('CSR PEM:');
+ console.log(csr);
+});
+```
+
+The output will look something like this (but much longer):
+
+```
+-----BEGIN CERTIFICATE REQUEST-----
+MIIClTCCAX0CAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCba21UHE+VbDTpmYYFZUOV+OQ8AngOCdjROsPC
+0KiEfMvEaEM3NQl58u6QL7G7QsEr.....3pIpUUkx5WbwJY6xDrCyFKG8ktpnee6
+WjpTOBnpgHUI1/5ydnf0v29L9N+ALIJGKQxhub3iqB6EhCl93iiQtf4e7M/lzX7l
+c1xqsSwVZ3RQVY9bRP9NdGuW4hVvscy5ypqRtXPXQpxMnYwfi9qW5Uo=
+-----END CERTIFICATE REQUEST-----
+```
+
+#### PEM-to-JWK
+
+If you need to convert a PEM to JWK first, do so:
+
+```js
+var Rasha = require('rasha');
+
+Rasha.import({ pem: "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAI..." }).then(function (jwk) {
+ console.log(jwk);
+})
+```
+
+#### CLI
+
+You're probably better off using OpenSSL for most commandline tasks,
+but the `rsa-csr` and `rasha` CLIs are useful for testing and debugging.
+
+```bash
+npm install -g rsa-csr
+npm install -g rasha
+
+rasha ./privkey.pem > ./privkey.jwk.json
+rsa-csr ./privkey.jwk.json example.com,www.example.com > csr.pem
+```
+
+### Options
+
+* `key` should be a JWK
+ * Need PEM support? Use [Rasha.js](https://git.coolaj86.com/coolaj86/rasha.js).
+ * (supports PEM, DER, PKCS#1 and PKCS#8)
+* `domains` must be a list of strings representing domain names
+ * correctly handles utf-8
+ * you may also use punycoded, if needed
+* `subject` will be `domains[0]` by default
+ * you shouldn't use this unless you need to
+ * you may need to if you need utf-8 for domains, but punycode for the subject
+
+### Testing
+
+You can double check that the CSR you get out is actually valid:
+
+```bash
+# Generate a key, if needed
+openssl genrsa -out ./privkey-rsa.pkcs1.pem $keysize
+
+# Convert to JWK
+rasha ./privkey-rsa.pkcs1.pem > ./privkey-rsa.jwk.json
+
+# Create a CSR with your domains
+npx rsa-csr ./privkey-rsa.jwk.json example.com,www.example.com > csr.pem
+
+# Verify
+openssl req -text -noout -verify -in csr.pem
+```
+
+New to Crypto?
+--------------
+
+Just a heads up in case you have no idea what you're doing:
+
+First of all, [don't panic](https://coolaj86.com/articles/dont-panic.html).
+
+Next:
+
+* RSA stands for... well, that doesn't matter, actually.
+* DSA stands for _Digital Signing Algorithm_.
+* RSA a separate standard from EC/ECDSA, but both are *asymmetric*
+* Private keys are actually keypairs (they contain the public key)
+
+In many cases the terms get used (and misused) interchangably,
+which can be confusing. You'll survive, I promise.
+
+* PEM is just a Base64-encoded DER (think JSON as hex or base64)
+* DER is an binary _object notation_ for ASN.1 (think actual stringified JSON or XML)
+* ASN.1 is _object notation_ standard (think JSON, the standard)
+* X.509 is a suite of schemas (think XLST or json-schema.org)
+* PKCS#8, PKIK, SPKI are all X.509 schemas (think defining `firstName` vs `first_name` vs `firstname`)
+
+Now forget about all that and just know this:
+
+**This library solves your problem if** you need RSA _something-or-other_ and CSR _something-or-other_
+in order to deal with SSL certificates in an internal organization.
+
+If that's not what you're doing, you may want HTTPS and SSL through
+[Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock-express.js),
+or you may be looking for something else entirely.
+
+Goals vs Non-Goals
+-----
+
+This was built for use by [ACME.js](https://git.coolaj86.com/coolaj86/acme.js)
+and [Greenlock.js](https://git.coolaj86.com/coolaj86/greenlock-express.js).
+
+Rather than trying to make a generic implementation that works with everything under the sun,
+this library is intentionally focused on around the use case of generating certificates for
+ACME services (such as Let's Encrypt).
+
+That said, [please tell me](https://git.coolaj86.com/coolaj86/rsa-csr.js/issues) if it doesn't
+do what you need, it may make sense to add it (or otherwise, perhaps to help you create a fork).
+
+The primary goal of this project is for this code to do exactly (and all of)
+what it needs to do - No more, no less.
+
+* Support RSA JWKs
+ * 2048-bit
+ * 3072-bit
+ * 4096-bit
+* Support PEM and DER via Rasha.js
+ * PKCS#1 (traditional)
+ * PKCS#8
+ * RSASSA-PKCS1-v1_5
+* Vanilla node.js (ECMAScript 5.1)
+ * No babel
+ * No dependencies
+
+However, there are a few areas where I'd be willing to stretch:
+
+* Type definition files for altscript languages
+
+It is not a goal of this project to support any RSA profiles
+except those that are universally supported by browsers and
+are sufficiently secure (overkill is overkill).
+
+> A little copying is better than a little dependency. - [Go Proverbs](https://go-proverbs.github.io) by Rob Pike
+
+This code is considered small and focused enough that,
+rather than making it a dependency in other small projects,
+I personally just copy over the code.
+
+Hence, all of these projects are MPL-2.0 licensed.
+
+Legal
+-----
+
+[RSA-CSR.js](https://git.coolaj86.com/coolaj86/rsa-csr.js) |
+MPL-2.0 |
+[Terms of Use](https://therootcompany.com/legal/#terms) |
+[Privacy Policy](https://therootcompany.com/legal/#privacy)
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/bin/rsa-csr.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/bin/rsa-csr.js
new file mode 100644
index 00000000..a9233305
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/bin/rsa-csr.js
@@ -0,0 +1,23 @@
+#!/usr/bin/env node
+'use strict';
+
+var fs = require('fs');
+var rsacsr = require('../index.js');
+
+var keyname = process.argv[2];
+var domains = process.argv[3].split(/,/);
+
+var key = fs.readFileSync(keyname, 'ascii');
+
+try {
+ key = JSON.parse(key);
+} catch(e) {
+ // ignore
+}
+
+rsacsr({ key: key, domains: domains }).then(function (csr) {
+ // Using error so that we can redirect stdout to file
+ //console.error("CN=" + domains[0]);
+ //console.error("subjectAltName=" + domains.join(','));
+ console.log(csr);
+});
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/example.com-www.csr.pem b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/example.com-www.csr.pem
new file mode 100644
index 00000000..d876ff8e
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/example.com-www.csr.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIIClTCCAX0CAQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCba21UHE+VbDTpmYYFZUOV+OQ8AngOCdjROsPC
+0KiEfMvEaEM3NQl58u6QL7G7QsErKViiNPm9OTFo6HF5JijfWzK7haHFuRMEsgI4
+VwIYyhvqlJDfw/wt0AiVvSmoMfEQn1p1aiaO4V/RJSE3Vw/uz2bxiT22uSkSqOyS
+hyfYE6dMHnuoBkzr4jvSifT+INmbv6Nyo4+AAMCZtYeHLrsFeSTjLL9jMPjI4ZkV
+dlw2n3Xn9NbltF3/8Ao8dQfElqw+LIQWqU0oFHYNIP4ttfl5ObMKHaKSvBMyNruZ
+R0El/ZsrcHLkAHRCLj07KRQJ81l5CUTPtQ02P1Eamz/nT4I3AgMBAAGgOjA4Bgkq
+hkiG9w0BCQ4xKzApMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29tgg93d3cuZXhhbXBs
+ZS5jb20wDQYJKoZIhvcNAQELBQADggEBAGOFydCZPtRqnEidrB3vkpPp1GmQVqrl
+XhqVM3X7UppsD3QDtJfgoSuBuVy3X/mPvy/Ly8WqEwJ7Ur+h76e7rgeFLvN5fQIr
+frlpfCXrKaxxl6vxqKJ8s3Mn2LT8VmSVNig34NCtn99/SHNAlr3aU9L3b1+R25VI
+FwFbOz/i92gOchT7Xat3fOiQ02k9GrHT33pIpUUkx5WbwJY6xDrCyFKG8ktpnee6
+WjpTOBnpgHUI1/5ydnf0v29L9N+ALIJGKQxhub3iqB6EhCl93iiQtf4e7M/lzX7l
+c1xqsSwVZ3RQVY9bRP9NdGuW4hVvscy5ypqRtXPXQpxMnYwfi9qW5Uo=
+-----END CERTIFICATE REQUEST-----
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/privkey-rsa-2048.jwk.json b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/privkey-rsa-2048.jwk.json
new file mode 100644
index 00000000..f344c22f
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/privkey-rsa-2048.jwk.json
@@ -0,0 +1,11 @@
+{
+ "kty": "RSA",
+ "n": "m2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhDNzUJefLukC-xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjskocn2BOnTB57qAZM6-I70on0_iDZm7-jcqOPgADAmbWHhy67BXkk4yy_YzD4yOGZFXZcNp915_TW5bRd__AKPHUHxJasPiyEFqlNKBR2DSD-LbX5eTmzCh2ikrwTMja7mUdBJf2bK3By5AB0Qi49OykUCfNZeQlEz7UNNj9RGps_50-CNw",
+ "e": "AQAB",
+ "d": "Cpfo7Mm9Nu8YMC_xrZ54W9mKHPkCG9rZ93Ds9PNp-RXUgb-ljTbFPZWsYxGNKLllFz8LNosr1pT2ZDMrwNk0Af1iWNvD6gkyXaiQdCyiDPSBsJyNv2LJZon-e85X74nv53UlIkmo9SYxdLz2JaJ-iIWEe8Qh-7llLktrTJV_xr98_tbhgSppz_IeOymq3SEZaQHM8pTU7w7XvCj2pb9r8fN0M0XcgWZIaf3LGEfkhF_WtX67XJ0C6-LbkT51jtlLRNGX6haGdscXS0OWWjKOJzKGuV-NbthEn5rmRtVnjRZ3yaxQ0ud8vC-NONn7yvGUlOur1IdDzJ_YfHPt9sHMQQ",
+ "p": "ynG-t9HwKCN3MWRYFdnFzi9-02Qcy3p8B5pu3ary2E70hYn2pHlUG2a9BNE8c5xHQ3Hx43WoWf6s0zOunPV1G28LkU_UYEbAtPv_PxSmzpQp9n9XnYvBLBF8Y3z7gxgLn1vVFNARrQdRtj87qY3aw7E9S4DsGcAarIuOT2TsTCE",
+ "q": "xIkAjgUzB1zaUzJtW2Zgvp9cYYr1DmpH30ePZl3c_8397_DZDDo46fnFYjs6uPa03HpmKUnbjwr14QHlfXlntJBEuXxcqLjkdKdJ4ob7xueLTK4suo9V8LSrkLChVxlZQwnFD2E5ll0sVeeDeMJHQw38ahSrBFEVnxjpnPh1Q1c",
+ "dp": "tzDGjECFOU0ehqtuqhcuT63a7h8hj19-7MJqoFwY9HQ-ALkfXyYLXeBSGxHbyiIYuodZg6LsfMNgUJ3r3Eyhc_nAVfYPEC_2IdAG4WYmq7iXYF9LQV09qEsKbFykm7QekE3hO7wswo5k-q2tp3ieBYdVGAXJoGOdv5VpaZ7B1QE",
+ "dq": "kh5dyDk7YCz7sUFbpsmuAeuPjoH2ghooh2u3xN7iUVmAg-ToKjwbVnG5-7eXiC779rQVwnrD_0yh1AFJ8wjRPqDIR7ObXGHikIxT1VSQWqiJm6AfZzDsL0LUD4YS3iPdhob7-NxLKWzqao_u4lhnDQaX9PKa12HFlny6K1daL48",
+ "qi": "AlHWbx1gp6Z9pbw_1hlS7HuXAgWoX7IjbTUelldf4gkriDWLOrj3QCZcO4ZvZvEwJhVlsny9LO8IkbwGJEL6cXraK08ByVS2mwQyflgTgGNnpzixyEUL_mrQLx6y145FHcxfeqNInMhep-0Mxn1D5nlhmIOgRApS0t9VoXtHhFU"
+}
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/privkey-rsa-2048.pkcs1.pem b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/privkey-rsa-2048.pkcs1.pem
new file mode 100644
index 00000000..246bd35c
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/privkey-rsa-2048.pkcs1.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrDwtCohHzLxGhD
+NzUJefLukC+xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLICOFcCGMob6pSQ
+38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjskocn2BOnTB57
+qAZM6+I70on0/iDZm7+jcqOPgADAmbWHhy67BXkk4yy/YzD4yOGZFXZcNp915/TW
+5bRd//AKPHUHxJasPiyEFqlNKBR2DSD+LbX5eTmzCh2ikrwTMja7mUdBJf2bK3By
+5AB0Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQABAoIBAAqX6OzJvTbvGDAv
+8a2eeFvZihz5Ahva2fdw7PTzafkV1IG/pY02xT2VrGMRjSi5ZRc/CzaLK9aU9mQz
+K8DZNAH9Yljbw+oJMl2okHQsogz0gbCcjb9iyWaJ/nvOV++J7+d1JSJJqPUmMXS8
+9iWifoiFhHvEIfu5ZS5La0yVf8a/fP7W4YEqac/yHjspqt0hGWkBzPKU1O8O17wo
+9qW/a/HzdDNF3IFmSGn9yxhH5IRf1rV+u1ydAuvi25E+dY7ZS0TRl+oWhnbHF0tD
+lloyjicyhrlfjW7YRJ+a5kbVZ40Wd8msUNLnfLwvjTjZ+8rxlJTrq9SHQ8yf2Hxz
+7fbBzEECgYEAynG+t9HwKCN3MWRYFdnFzi9+02Qcy3p8B5pu3ary2E70hYn2pHlU
+G2a9BNE8c5xHQ3Hx43WoWf6s0zOunPV1G28LkU/UYEbAtPv/PxSmzpQp9n9XnYvB
+LBF8Y3z7gxgLn1vVFNARrQdRtj87qY3aw7E9S4DsGcAarIuOT2TsTCECgYEAxIkA
+jgUzB1zaUzJtW2Zgvp9cYYr1DmpH30ePZl3c/8397/DZDDo46fnFYjs6uPa03Hpm
+KUnbjwr14QHlfXlntJBEuXxcqLjkdKdJ4ob7xueLTK4suo9V8LSrkLChVxlZQwnF
+D2E5ll0sVeeDeMJHQw38ahSrBFEVnxjpnPh1Q1cCgYEAtzDGjECFOU0ehqtuqhcu
+T63a7h8hj19+7MJqoFwY9HQ+ALkfXyYLXeBSGxHbyiIYuodZg6LsfMNgUJ3r3Eyh
+c/nAVfYPEC/2IdAG4WYmq7iXYF9LQV09qEsKbFykm7QekE3hO7wswo5k+q2tp3ie
+BYdVGAXJoGOdv5VpaZ7B1QECgYEAkh5dyDk7YCz7sUFbpsmuAeuPjoH2ghooh2u3
+xN7iUVmAg+ToKjwbVnG5+7eXiC779rQVwnrD/0yh1AFJ8wjRPqDIR7ObXGHikIxT
+1VSQWqiJm6AfZzDsL0LUD4YS3iPdhob7+NxLKWzqao/u4lhnDQaX9PKa12HFlny6
+K1daL48CgYACUdZvHWCnpn2lvD/WGVLse5cCBahfsiNtNR6WV1/iCSuINYs6uPdA
+Jlw7hm9m8TAmFWWyfL0s7wiRvAYkQvpxetorTwHJVLabBDJ+WBOAY2enOLHIRQv+
+atAvHrLXjkUdzF96o0icyF6n7QzGfUPmeWGYg6BEClLS31Whe0eEVQ==
+-----END RSA PRIVATE KEY-----
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/whatever.net-www-api.csr.pem b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/whatever.net-www-api.csr.pem
new file mode 100644
index 00000000..9275f2dd
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/fixtures/whatever.net-www-api.csr.pem
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE REQUEST-----
+MIICqjCCAZICAQAwFzEVMBMGA1UEAwwMd2hhdGV2ZXIubmV0MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2ttVBxPlWw06ZmGBWVDlfjkPAJ4DgnY0TrD
+wtCohHzLxGhDNzUJefLukC+xu0LBKylYojT5vTkxaOhxeSYo31syu4WhxbkTBLIC
+OFcCGMob6pSQ38P8LdAIlb0pqDHxEJ9adWomjuFf0SUhN1cP7s9m8Yk9trkpEqjs
+kocn2BOnTB57qAZM6+I70on0/iDZm7+jcqOPgADAmbWHhy67BXkk4yy/YzD4yOGZ
+FXZcNp915/TW5bRd//AKPHUHxJasPiyEFqlNKBR2DSD+LbX5eTmzCh2ikrwTMja7
+mUdBJf2bK3By5AB0Qi49OykUCfNZeQlEz7UNNj9RGps/50+CNwIDAQABoE4wTAYJ
+KoZIhvcNAQkOMT8wPTA7BgNVHREENDAyggx3aGF0ZXZlci5uZXSCEHd3dy53aGF0
+ZXZlci5uZXSCEGFwaS53aGF0ZXZlci5uZXQwDQYJKoZIhvcNAQELBQADggEBAB21
+KZYjarfd8nUAbwhH8dWZOo4rFcdYFo3xcXPQ11b1Wa79dtG67cgD/dplKFis5qD3
+6h4m818w9ESBA3Q1ZUy6HgDPMhCjg2fmCnSsZ5epo47wzvelYonfOX5DAwxgfYsa
+335olrXJ0qsTiNmaS7RxDT53vfMOp41NyEAkFmpIAkaHgW/+xFPUSCBXIUWbaCG+
+pK3FVNmK3VCVCAP6UvVKYQUWSC6FRG/Q8MHoecdo+bbMlr2s2GPxq9TKInwe8JqT
+E9pD7QMsN7uWpMaXNKCje4+Q88Br4URNcGAiYoy4/6hcF2Ki1saTYVIk/DG1P4hX
+G5f0ezDLtsC22xe6jHI=
+-----END CERTIFICATE REQUEST-----
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/index.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/index.js
new file mode 100644
index 00000000..a4b74e68
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/index.js
@@ -0,0 +1,2 @@
+'use strict';
+module.exports = require('./lib/csr.js');
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/asn1.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/asn1.js
new file mode 100644
index 00000000..c92c1c31
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/asn1.js
@@ -0,0 +1,72 @@
+'use strict';
+
+//
+// A dumbed-down, minimal ASN.1 parser / packer combo
+//
+// Note: generally I like to write congruent code
+// (i.e. output can be used as input and vice-versa)
+// However, this seemed to be more readable and easier
+// to use written as-is, asymmetrically.
+// (I also generally prefer to export objects rather
+// functions but, yet again, asthetics one in this case)
+
+var Enc = require('./encoding.js');
+
+//
+// Packer
+//
+
+// Almost every ASN.1 type that's important for CSR
+// can be represented generically with only a few rules.
+var ASN1 = module.exports = function ASN1(/*type, hexstrings...*/) {
+ var args = Array.prototype.slice.call(arguments);
+ var typ = args.shift();
+ var str = args.join('').replace(/\s+/g, '').toLowerCase();
+ var len = (str.length/2);
+ var lenlen = 0;
+ var hex = typ;
+
+ // We can't have an odd number of hex chars
+ if (len !== Math.round(len)) {
+ console.error(arguments);
+ throw new Error("invalid hex");
+ }
+
+ // The first byte of any ASN.1 sequence is the type (Sequence, Integer, etc)
+ // The second byte is either the size of the value, or the size of its size
+
+ // 1. If the second byte is < 0x80 (128) it is considered the size
+ // 2. If it is > 0x80 then it describes the number of bytes of the size
+ // ex: 0x82 means the next 2 bytes describe the size of the value
+ // 3. The special case of exactly 0x80 is "indefinite" length (to end-of-file)
+
+ if (len > 127) {
+ lenlen += 1;
+ while (len > 255) {
+ lenlen += 1;
+ len = len >> 8;
+ }
+ }
+
+ if (lenlen) { hex += Enc.numToHex(0x80 + lenlen); }
+ return hex + Enc.numToHex(str.length/2) + str;
+};
+
+// The Integer type has some special rules
+ASN1.UInt = function UINT() {
+ var str = Array.prototype.slice.call(arguments).join('');
+ var first = parseInt(str.slice(0, 2), 16);
+
+ // If the first byte is 0x80 or greater, the number is considered negative
+ // Therefore we add a '00' prefix if the 0x80 bit is set
+ if (0x80 & first) { str = '00' + str; }
+
+ return ASN1('02', str);
+};
+
+// The Bit String type also has a special rule
+ASN1.BitStr = function BITSTR() {
+ var str = Array.prototype.slice.call(arguments).join('');
+ // '00' is a mask of how many bits of the next byte to ignore
+ return ASN1('03', '00' + str);
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/csr.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/csr.js
new file mode 100644
index 00000000..219ab273
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/csr.js
@@ -0,0 +1,152 @@
+'use strict';
+
+var crypto = require('crypto');
+var ASN1 = require('./asn1.js');
+var Enc = require('./encoding.js');
+var PEM = require('./pem.js');
+var X509 = require('./x509.js');
+var RSA = {};
+
+/*global Promise*/
+var CSR = module.exports = function rsacsr(opts) {
+ // We're using a Promise here to be compatible with the browser version
+ // which will probably use the webcrypto API for some of the conversions
+ opts = CSR._prepare(opts);
+
+ return CSR.create(opts).then(function (bytes) {
+ return CSR._encode(opts, bytes);
+ });
+};
+
+CSR._prepare = function (opts) {
+ var Rasha;
+ opts = JSON.parse(JSON.stringify(opts));
+ var pem, jwk;
+
+ // We do a bit of extra error checking for user convenience
+ if (!opts) { throw new Error("You must pass options with key and domains to rsacsr"); }
+ if (!Array.isArray(opts.domains) || 0 === opts.domains.length) {
+ new Error("You must pass options.domains as a non-empty array");
+ }
+
+ // I need to check that 例.中国 is a valid domain name
+ if (!opts.domains.every(function (d) {
+ // allow punycode? xn--
+ if ('string' === typeof d /*&& /\./.test(d) && !/--/.test(d)*/) {
+ return true;
+ }
+ })) {
+ throw new Error("You must pass options.domains as strings");
+ }
+
+ if (opts.pem) {
+ pem = opts.pem;
+ } else if (opts.jwk) {
+ jwk = opts.jwk;
+ } else {
+ if (!opts.key) {
+ throw new Error("You must pass options.key as a JSON web key");
+ } else if (opts.key.kty) {
+ jwk = opts.key;
+ } else {
+ pem = opts.key;
+ }
+ }
+
+ if (pem) {
+ try {
+ Rasha = require('rasha');
+ } catch(e) {
+ throw new Error("Rasha.js is an optional dependency for PEM-to-JWK.\n"
+ + "Install it if you'd like to use it:\n"
+ + "\tnpm install --save rasha\n"
+ + "Otherwise supply a jwk as the private key."
+ );
+ }
+ jwk = Rasha.importSync({ pem: pem });
+ }
+
+ opts.jwk = jwk;
+ return opts;
+};
+CSR.sync = function (opts) {
+ opts = CSR._prepare(opts);
+ var bytes = CSR.createSync(opts);
+ return CSR._encode(opts, bytes);
+};
+CSR._encode = function (opts, bytes) {
+ if ('der' === (opts.encoding||'').toLowerCase()) {
+ return bytes;
+ }
+ return PEM.packBlock({
+ type: "CERTIFICATE REQUEST"
+ , bytes: bytes /* { jwk: jwk, domains: opts.domains } */
+ });
+};
+
+CSR.createSync = function createCsr(opts) {
+ var hex = CSR.request(opts.jwk, opts.domains);
+ var csr = CSR.signSync(opts.jwk, hex);
+ return Enc.hexToBuf(csr);
+};
+CSR.create = function createCsr(opts) {
+ var hex = CSR.request(opts.jwk, opts.domains);
+ return CSR.sign(opts.jwk, hex).then(function (csr) {
+ return Enc.hexToBuf(csr);
+ });
+};
+
+CSR.request = function createCsrBodyEc(jwk, domains) {
+ var asn1pub = X509.packCsrPublicKey(jwk);
+ return X509.packCsr(asn1pub, domains);
+};
+
+CSR.signSync = function csrEcSig(jwk, request) {
+ var keypem = PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: X509.packPkcs1(jwk) });
+ var sig = RSA.signSync(keypem, Enc.hexToBuf(request));
+ return CSR.toDer({ request: request, signature: sig });
+};
+CSR.sign = function csrEcSig(jwk, request) {
+ var keypem = PEM.packBlock({ type: "RSA PRIVATE KEY", bytes: X509.packPkcs1(jwk) });
+ return RSA.sign(keypem, Enc.hexToBuf(request)).then(function (sig) {
+ return CSR.toDer({ request: request, signature: sig });
+ });
+};
+CSR.toDer = function encode(opts) {
+ var sty = ASN1('30'
+ // 1.2.840.113549.1.1.11 sha256WithRSAEncryption (PKCS #1)
+ , ASN1('06', '2a864886f70d01010b')
+ , ASN1('05')
+ );
+ return ASN1('30'
+ // The Full CSR Request Body
+ , opts.request
+ // The Signature Type
+ , sty
+ // The Signature
+ , ASN1.BitStr(Enc.bufToHex(opts.signature))
+ );
+};
+
+//
+// RSA
+//
+
+// Took some tips from https://gist.github.com/codermapuche/da4f96cdb6d5ff53b7ebc156ec46a10a
+RSA.signSync = function signRsaSync(keypem, ab) {
+ // Signer is a stream
+ var sign = crypto.createSign('SHA256');
+ sign.write(new Uint8Array(ab));
+ sign.end();
+
+ // The signature is ASN1 encoded, as it turns out
+ var sig = sign.sign(keypem);
+
+ // Convert to a JavaScript ArrayBuffer just because
+ return new Uint8Array(sig.buffer.slice(sig.byteOffset, sig.byteOffset + sig.byteLength));
+};
+RSA.sign = function signRsa(keypem, ab) {
+ return Promise.resolve().then(function () {
+ return RSA.signSync(keypem, ab);
+ });
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/encoding.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/encoding.js
new file mode 100644
index 00000000..f6b6ab0a
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/encoding.js
@@ -0,0 +1,34 @@
+'use strict';
+
+var Enc = module.exports;
+
+Enc.base64ToHex = function base64ToHex(b64) {
+ return Buffer.from(b64, 'base64').toString('hex').toLowerCase();
+};
+
+Enc.bufToBase64 = function bufToBase64(u8) {
+ // we want to maintain api compatability with browser APIs,
+ // so we assume that this could be a Uint8Array
+ return Buffer.from(u8).toString('base64');
+};
+
+Enc.bufToHex = function toHex(u8) {
+ return Buffer.from(u8).toString('hex').toLowerCase();
+};
+
+Enc.hexToBuf = function (hex) {
+ return Buffer.from(hex, 'hex');
+};
+
+Enc.numToHex = function numToHex(d) {
+ d = d.toString(16);
+ if (d.length % 2) {
+ return '0' + d;
+ }
+ return d;
+};
+
+Enc.utf8ToHex = function utf8ToHex(str) {
+ // node can properly handle utf-8 strings
+ return Buffer.from(str).toString('hex').toLowerCase();
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/pem.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/pem.js
new file mode 100644
index 00000000..fb08dcc9
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/pem.js
@@ -0,0 +1,12 @@
+'use strict';
+
+var Enc = require('./encoding.js');
+var PEM = module.exports;
+
+PEM.packBlock = function (opts) {
+ // TODO allow for headers?
+ return '-----BEGIN ' + opts.type + '-----\n'
+ + Enc.bufToBase64(opts.bytes).match(/.{1,64}/g).join('\n') + '\n'
+ + '-----END ' + opts.type + '-----'
+ ;
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/telemetry.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/telemetry.js
new file mode 100644
index 00000000..9623b775
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/telemetry.js
@@ -0,0 +1,111 @@
+'use strict';
+
+// We believe in a proactive approach to sustainable open source.
+// As part of that we make it easy for you to opt-in to following our progress
+// and we also stay up-to-date on telemetry such as operating system and node
+// version so that we can focus our efforts where they'll have the greatest impact.
+//
+// Want to learn more about our Terms, Privacy Policy, and Mission?
+// Check out https://therootcompany.com/legal/
+
+var os = require('os');
+var crypto = require('crypto');
+var https = require('https');
+var pkg = require('../package.json');
+
+// to help focus our efforts in the right places
+var data = {
+ package: pkg.name
+, version: pkg.version
+, node: process.version
+, arch: process.arch || os.arch()
+, platform: process.platform || os.platform()
+, release: os.release()
+};
+
+function addCommunityMember(opts) {
+ setTimeout(function () {
+ var req = https.request({
+ hostname: 'api.therootcompany.com'
+ , port: 443
+ , path: '/api/therootcompany.com/public/community'
+ , method: 'POST'
+ , headers: { 'Content-Type': 'application/json' }
+ }, function (resp) {
+ // let the data flow, so we can ignore it
+ resp.on('data', function () {});
+ //resp.on('data', function (chunk) { console.log(chunk.toString()); });
+ resp.on('error', function () { /*ignore*/ });
+ //resp.on('error', function (err) { console.error(err); });
+ });
+ var obj = JSON.parse(JSON.stringify(data));
+ obj.action = 'updates';
+ try {
+ obj.ppid = ppid(obj.action);
+ } catch(e) {
+ // ignore
+ //console.error(e);
+ }
+ obj.name = opts.name || undefined;
+ obj.address = opts.email;
+ obj.community = 'node.js@therootcompany.com';
+
+ req.write(JSON.stringify(obj, 2, null));
+ req.end();
+ req.on('error', function () { /*ignore*/ });
+ //req.on('error', function (err) { console.error(err); });
+ }, 50);
+}
+
+function ping(action) {
+ setTimeout(function () {
+ var req = https.request({
+ hostname: 'api.therootcompany.com'
+ , port: 443
+ , path: '/api/therootcompany.com/public/ping'
+ , method: 'POST'
+ , headers: { 'Content-Type': 'application/json' }
+ }, function (resp) {
+ // let the data flow, so we can ignore it
+ resp.on('data', function () { });
+ //resp.on('data', function (chunk) { console.log(chunk.toString()); });
+ resp.on('error', function () { /*ignore*/ });
+ //resp.on('error', function (err) { console.error(err); });
+ });
+ var obj = JSON.parse(JSON.stringify(data));
+ obj.action = action;
+ try {
+ obj.ppid = ppid(obj.action);
+ } catch(e) {
+ // ignore
+ //console.error(e);
+ }
+
+ req.write(JSON.stringify(obj, 2, null));
+ req.end();
+ req.on('error', function (/*e*/) { /*console.error('req.error', e);*/ });
+ }, 50);
+}
+
+// to help identify unique installs without getting
+// the personally identifiable info that we don't want
+function ppid(action) {
+ var parts = [ action, data.package, data.version, data.node, data.arch, data.platform, data.release ];
+ var ifaces = os.networkInterfaces();
+ Object.keys(ifaces).forEach(function (ifname) {
+ if (/^en/.test(ifname) || /^eth/.test(ifname) || /^wl/.test(ifname)) {
+ if (ifaces[ifname] && ifaces[ifname].length) {
+ parts.push(ifaces[ifname][0].mac);
+ }
+ }
+ });
+ return crypto.createHash('sha1').update(parts.join(',')).digest('base64');
+}
+
+module.exports.ping = ping;
+module.exports.joinCommunity = addCommunityMember;
+
+if (require.main === module) {
+ ping('install');
+ //addCommunityMember({ name: "AJ ONeal", email: 'coolaj86@gmail.com' });
+}
diff --git a/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/x509.js b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/x509.js
new file mode 100644
index 00000000..33cb9c51
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa-csr/lib/x509.js
@@ -0,0 +1,66 @@
+'use strict';
+
+var ASN1 = require('./asn1.js');
+var Enc = require('./encoding.js');
+
+var X509 = module.exports;
+
+X509.packCsr = function (asn1pubkey, domains) {
+ return ASN1('30'
+ // Version (0)
+ , ASN1.UInt('00')
+
+ // 2.5.4.3 commonName (X.520 DN component)
+ , ASN1('30', ASN1('31', ASN1('30', ASN1('06', '550403'), ASN1('0c', Enc.utf8ToHex(domains[0])))))
+
+ // Public Key (RSA or EC)
+ , asn1pubkey
+
+ // Request Body
+ , ASN1('a0'
+ , ASN1('30'
+ // 1.2.840.113549.1.9.14 extensionRequest (PKCS #9 via CRMF)
+ , ASN1('06', '2a864886f70d01090e')
+ , ASN1('31'
+ , ASN1('30'
+ , ASN1('30'
+ // 2.5.29.17 subjectAltName (X.509 extension)
+ , ASN1('06', '551d11')
+ , ASN1('04'
+ , ASN1('30', domains.map(function (d) {
+ return ASN1('82', Enc.utf8ToHex(d));
+ }).join(''))))))))
+ );
+};
+
+X509.packPkcs1 = function (jwk) {
+ var n = ASN1.UInt(Enc.base64ToHex(jwk.n));
+ var e = ASN1.UInt(Enc.base64ToHex(jwk.e));
+
+ if (!jwk.d) {
+ return Enc.hexToBuf(ASN1('30', n, e));
+ }
+
+ return Enc.hexToBuf(ASN1('30'
+ , ASN1.UInt('00')
+ , n
+ , e
+ , ASN1.UInt(Enc.base64ToHex(jwk.d))
+ , ASN1.UInt(Enc.base64ToHex(jwk.p))
+ , ASN1.UInt(Enc.base64ToHex(jwk.q))
+ , ASN1.UInt(Enc.base64ToHex(jwk.dp))
+ , ASN1.UInt(Enc.base64ToHex(jwk.dq))
+ , ASN1.UInt(Enc.base64ToHex(jwk.qi))
+ ));
+};
+
+X509.packCsrPublicKey = function (jwk) {
+ // Sequence the key
+ var n = ASN1.UInt(Enc.base64ToHex(jwk.n));
+ var e = ASN1.UInt(Enc.base64ToHex(jwk.e));
+ var asn1pub = ASN1('30', n, e);
+ //var asn1pub = X509.packPkcs1({ kty: jwk.kty, n: jwk.n, e: jwk.e });
+
+ // Add the CSR pub key header
+ return ASN1('30', ASN1('30', ASN1('06', '2a864886f70d010101'), ASN1('05')), ASN1.BitStr(asn1pub));
+};
diff --git a/express-server/node_modules/rsa-compat/lib/rsa.js b/express-server/node_modules/rsa-compat/lib/rsa.js
new file mode 100644
index 00000000..d642cfd6
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/rsa.js
@@ -0,0 +1,213 @@
+// Copyright 2016-2018 AJ ONeal. All rights reserved
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+'use strict';
+
+var RSA = module.exports;
+RSA.utils = {};
+
+try {
+ require('buffer-v6-polyfill');
+} catch(e) {
+ /* ignore */
+}
+
+var Rasha = require('./rasha');
+var RSACSR = require('./rsa-csr');
+var NOBJ = {};
+var DEFAULT_BITLEN = 2048;
+var DEFAULT_EXPONENT = 0x10001;
+
+RSA.generateKeypair = function (options, cb, extra1, extra2) {
+ var length;
+ var exponent;
+ if ('function' === typeof extra2) {
+ length = options || DEFAULT_BITLEN;
+ exponent = cb || DEFAULT_EXPONENT;
+ options = extra1 || NOBJ;
+ cb = extra2;
+ } else {
+ if (!options) { options = NOBJ; }
+ length = options.bitlen || DEFAULT_BITLEN;
+ exponent = options.exp || DEFAULT_EXPONENT;
+ }
+
+ try {
+ var keypair = require('./generate-privkey.js')(length, exponent);
+ keypair.thumbprint = RSA.thumbprint(keypair);
+ cb(null, keypair);
+ } catch(e) {
+ cb(e);
+ }
+};
+
+RSA.import = function (options) {
+ options = JSON.parse(JSON.stringify(options));
+
+ // Private Keys
+ if (options.privateKeyPem) {
+ if (!options.privateKeyJwk) {
+ options.privateKeyJwk = Rasha.importSync({ pem: options.privateKeyPem });
+ }
+ }
+ if (options.privateKeyJwk) {
+ if (!options.privateKeyPem) {
+ options.privateKeyPem = Rasha.exportSync({
+ jwk: options.privateKeyJwk
+ , format: options.format || 'pkcs1'
+ , encoding: options.encoding || 'pem'
+ });
+ }
+ }
+
+ // Public Keys
+ if (options.publicKeyPem || options.privateKeyPem) {
+ if (!options.publicKeyJwk) {
+ options.publicKeyJwk = Rasha.importSync({
+ pem: options.publicKeyPem || options.privateKeyPem
+ , public: true
+ });
+ }
+ }
+ if (options.publicKeyJwk || options.privateKeyJwk) {
+ if (!options.publicKeyPem) {
+ options.publicKeyPem = Rasha.exportSync({
+ jwk: options.publicKeyJwk || options.privateKeyJwk
+ , format: options.format || 'pkcs1'
+ , encoding: options.encoding || 'pem'
+ , public: true
+ });
+ }
+ }
+ if (!options.publicKeyPem) {
+ throw new Error("Error: no keys were present to import");
+ }
+
+ // Consistent CRLF
+ if (options.privateKeyPem) {
+ options.privateKeyPem = options.privateKeyPem
+ .trim().replace(/[\r\n]+/g, '\r\n') + '\r\n';
+ }
+ options.publicKeyPem = options.publicKeyPem
+ .trim().replace(/[\r\n]+/g, '\r\n') + '\r\n';
+
+ // Thumbprint
+ if (!options.thumbprint) {
+ options.thumbprint = RSA._thumbprint(options);
+ }
+
+ return options;
+};
+
+RSA.exportPrivatePem = function (keypair) {
+ keypair = RSA.import(keypair);
+ return keypair.privateKeyPem;
+};
+RSA.exportPublicPem = function (keypair) {
+ keypair = RSA.import(keypair);
+ return keypair.publicKeyPem;
+};
+
+RSA.exportPrivateJwk = function (keypair) {
+ keypair = RSA.import(keypair);
+ return keypair.privateKeyJwk;
+};
+RSA.exportPublicJwk = function (keypair) {
+ if (!keypair.publicKeyJwk) {
+ keypair = RSA.import(keypair);
+ }
+ return keypair.publicKeyJwk;
+};
+
+RSA.signJws = RSA.generateJws = RSA.generateSignatureJws = RSA.generateSignatureJwk =
+function (keypair, header, protect, payload) {
+// old (keypair, payload, nonce)
+ var nonce;
+
+ keypair = RSA.import(keypair);
+ keypair.publicKeyJwk = RSA.exportPublicJwk(keypair);
+
+ if ('string' === typeof protect || ('undefined' === typeof protect && 'undefined' === typeof payload)) {
+ console.warn("deprecation notice: new signature for signJws(keypair, header, protect, payload)");
+ // old API
+ payload = header;
+ nonce = protect;
+ protect = undefined;
+ header = {
+ alg: "RS256"
+ , jwk: keypair.publicKeyJwk
+ };
+ protect = { nonce: nonce };
+ }
+
+ // Compute JWS signature
+ var protectedHeader = "";
+ if (protect) {
+ protectedHeader = JSON.stringify(protect); // { alg: prot.alg, nonce: prot.nonce, url: prot.url });
+ }
+ var protected64 = RSA.utils.toWebsafeBase64(Buffer.from(protectedHeader).toString('base64'));
+ var payload64 = RSA.utils.toWebsafeBase64(payload.toString('base64'));
+ var raw = protected64 + "." + payload64;
+ var pem = RSA.exportPrivatePem(keypair);
+ var signer = require('crypto').createSign("RSA-SHA256");
+ signer.update(raw);
+
+ return {
+ header: header
+ , protected: protected64
+ , payload: payload64
+ , signature: signer.sign(pem, 'base64')
+ .replace(/\+/g, '-')
+ .replace(/\//g, '_')
+ .replace(/=/g, '')
+ };
+};
+
+RSA.generateCsrPem = function (keypair, domains) {
+ keypair = RSA.import(keypair);
+ return RSACSR.sync({ jwk: keypair.privateKeyJwk, domains: domains });
+};
+RSA.generateCsrDer = function (keypair, domains) {
+ keypair = RSA.import(keypair);
+ return RSACSR.sync({
+ jwk: keypair.privateKeyJwk
+ , domains: domains
+ , encoding: 'der'
+ });
+};
+RSA.generateCsrDerWeb64 =RSA.generateCsrWeb64 = function (keypair, names) {
+ var buf = RSA.generateCsrDer(keypair, names);
+ var b64 = buf.toString('base64');
+ return RSA.utils.toWebsafeBase64(b64);
+};
+
+RSA._thumbprintInput = function (n, e) {
+ // #L147 const rsaThumbprintTemplate = `{"e":"%s","kty":"RSA","n":"%s"}`
+ return Buffer.from('{"e":"'+ e + '","kty":"RSA","n":"'+ n +'"}', 'ascii');
+};
+RSA._thumbprint = function (keypair) {
+ var publicKeyJwk = keypair.publicKeyJwk;
+
+ if (!publicKeyJwk.e || !publicKeyJwk.n) {
+ throw new Error("You must provide an RSA jwk with 'e' and 'n' (the public components)");
+ }
+
+ var input = RSA._thumbprintInput(publicKeyJwk.n, publicKeyJwk.e);
+ var base64Digest = require('crypto').createHash('sha256').update(input).digest('base64');
+
+ return RSA.utils.toWebsafeBase64(base64Digest);
+};
+RSA.thumbprint = function (keypair) {
+ if (!keypair.publicKeyJwk) {
+ keypair.publicKeyJwk = RSA.exportPublicJwk(keypair);
+ }
+ return RSA._thumbprint(keypair);
+};
+
+RSA.utils.toWebsafeBase64 = function (b64) {
+ return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g,"");
+};
+
+RSA.exportPrivateKey = RSA.exportPrivatePem;
+RSA.exportPublicKey = RSA.exportPublicPem;
diff --git a/express-server/node_modules/rsa-compat/lib/telemetry.js b/express-server/node_modules/rsa-compat/lib/telemetry.js
new file mode 100644
index 00000000..9623b775
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/lib/telemetry.js
@@ -0,0 +1,111 @@
+'use strict';
+
+// We believe in a proactive approach to sustainable open source.
+// As part of that we make it easy for you to opt-in to following our progress
+// and we also stay up-to-date on telemetry such as operating system and node
+// version so that we can focus our efforts where they'll have the greatest impact.
+//
+// Want to learn more about our Terms, Privacy Policy, and Mission?
+// Check out https://therootcompany.com/legal/
+
+var os = require('os');
+var crypto = require('crypto');
+var https = require('https');
+var pkg = require('../package.json');
+
+// to help focus our efforts in the right places
+var data = {
+ package: pkg.name
+, version: pkg.version
+, node: process.version
+, arch: process.arch || os.arch()
+, platform: process.platform || os.platform()
+, release: os.release()
+};
+
+function addCommunityMember(opts) {
+ setTimeout(function () {
+ var req = https.request({
+ hostname: 'api.therootcompany.com'
+ , port: 443
+ , path: '/api/therootcompany.com/public/community'
+ , method: 'POST'
+ , headers: { 'Content-Type': 'application/json' }
+ }, function (resp) {
+ // let the data flow, so we can ignore it
+ resp.on('data', function () {});
+ //resp.on('data', function (chunk) { console.log(chunk.toString()); });
+ resp.on('error', function () { /*ignore*/ });
+ //resp.on('error', function (err) { console.error(err); });
+ });
+ var obj = JSON.parse(JSON.stringify(data));
+ obj.action = 'updates';
+ try {
+ obj.ppid = ppid(obj.action);
+ } catch(e) {
+ // ignore
+ //console.error(e);
+ }
+ obj.name = opts.name || undefined;
+ obj.address = opts.email;
+ obj.community = 'node.js@therootcompany.com';
+
+ req.write(JSON.stringify(obj, 2, null));
+ req.end();
+ req.on('error', function () { /*ignore*/ });
+ //req.on('error', function (err) { console.error(err); });
+ }, 50);
+}
+
+function ping(action) {
+ setTimeout(function () {
+ var req = https.request({
+ hostname: 'api.therootcompany.com'
+ , port: 443
+ , path: '/api/therootcompany.com/public/ping'
+ , method: 'POST'
+ , headers: { 'Content-Type': 'application/json' }
+ }, function (resp) {
+ // let the data flow, so we can ignore it
+ resp.on('data', function () { });
+ //resp.on('data', function (chunk) { console.log(chunk.toString()); });
+ resp.on('error', function () { /*ignore*/ });
+ //resp.on('error', function (err) { console.error(err); });
+ });
+ var obj = JSON.parse(JSON.stringify(data));
+ obj.action = action;
+ try {
+ obj.ppid = ppid(obj.action);
+ } catch(e) {
+ // ignore
+ //console.error(e);
+ }
+
+ req.write(JSON.stringify(obj, 2, null));
+ req.end();
+ req.on('error', function (/*e*/) { /*console.error('req.error', e);*/ });
+ }, 50);
+}
+
+// to help identify unique installs without getting
+// the personally identifiable info that we don't want
+function ppid(action) {
+ var parts = [ action, data.package, data.version, data.node, data.arch, data.platform, data.release ];
+ var ifaces = os.networkInterfaces();
+ Object.keys(ifaces).forEach(function (ifname) {
+ if (/^en/.test(ifname) || /^eth/.test(ifname) || /^wl/.test(ifname)) {
+ if (ifaces[ifname] && ifaces[ifname].length) {
+ parts.push(ifaces[ifname][0].mac);
+ }
+ }
+ });
+ return crypto.createHash('sha1').update(parts.join(',')).digest('base64');
+}
+
+module.exports.ping = ping;
+module.exports.joinCommunity = addCommunityMember;
+
+if (require.main === module) {
+ ping('install');
+ //addCommunityMember({ name: "AJ ONeal", email: 'coolaj86@gmail.com' });
+}
diff --git a/express-server/node_modules/rsa-compat/package.json b/express-server/node_modules/rsa-compat/package.json
new file mode 100644
index 00000000..ad55a5af
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/package.json
@@ -0,0 +1,108 @@
+{
+ "_args": [
+ [
+ "rsa-compat@^1.5.0",
+ "/nodeapps/https-test/greenlock-express.js/node_modules/greenlock"
+ ]
+ ],
+ "_from": "rsa-compat@>=1.5.0 <2.0.0",
+ "_hasShrinkwrap": false,
+ "_id": "rsa-compat@1.9.0",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/rsa-compat",
+ "_nodeVersion": "10.13.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/rsa-compat_1.9.0_1544954189568_0.26195947533693653"
+ },
+ "_npmUser": {
+ "email": "coolaj86@gmail.com",
+ "name": "coolaj86"
+ },
+ "_npmVersion": "6.4.1",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "rsa-compat",
+ "raw": "rsa-compat@^1.5.0",
+ "rawSpec": "^1.5.0",
+ "scope": null,
+ "spec": ">=1.5.0 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/acme-v2",
+ "/greenlock"
+ ],
+ "_resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-1.9.0.tgz",
+ "_shasum": "cd2ffd70d0a02f126342951bc809d40a18a4c0ce",
+ "_shrinkwrap": null,
+ "_spec": "rsa-compat@^1.5.0",
+ "_where": "/nodeapps/https-test/greenlock-express.js/node_modules/greenlock",
+ "author": {
+ "email": "coolaj86@gmail.com",
+ "name": "AJ ONeal",
+ "url": "https://coolaj86.com/"
+ },
+ "bin": {
+ "rsa-keygen-js": "bin/rsa-keygen.js"
+ },
+ "bugs": {
+ "url": "https://git.coolaj86.com/coolaj86/rsa-compat.js/issues"
+ },
+ "dependencies": {
+ "node-forge": "^0.7.6",
+ "ursa-optional": "^0.9.10"
+ },
+ "description": "RSA utils that work on Windows, Mac, and Linux with or without C compiler",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "fileCount": 55,
+ "integrity": "sha512-0Qx/LE/n2ulCofM2H72CVBptMHcnUXZVKw7F1rOny+nFgTo2aEMFwVIEvS1WfnuT14U42RanuZEIzcYVScQcQA==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcFiFOCRA9TVsSAnZWagAAzzsP/ig2SAoTOUMLTgRRTBVp\nXXjZ4tGbgaW86shjrzfibZzt44svlvggJad5m4zzc8Oatm36RDVLrgUwbLeQ\nVLInLWiIZX+wJP5ToV4vAwpjfGubFyhi9jbj9YBGw6XJ/zxGHcaLD2/m8Nec\nqemjPASLPhGAbPmDOsyfzDsuJlGiTI89ysBFpyEkpjz00si0ZDZhY4r/0ISB\nvfaWn0ISTnDRVCvYH8Y+BUuCYUCNP/jn2tiXd+18kuCwrIeHsLxk7+mz58NH\nFvQTpk02diP8erkWxRoggWwazXVhq5zQBp5S14BVdLPimgW8ViHv0YUfOrRe\nxn0J1B0M2I0pmkGX2ROBn8AmQExDmYR1BzS22euVxvByEsLMa2zQSxFjPzVG\nZ3kpCta4FHCRQqgau5jI8GAHvogET1w7cANL8di9kiHi18k5C2SbUTmkqSSt\n9/WTzsIfuC7pGI2t211WbEfO313B9hs27B6wkGOO379ckeveVYJryU27VNm6\nBiMt7zR36vR2hvuFUhBSieXjMGup9yfHKq225VcZZDZg07mtx4lK32hNVTG1\n0ZfC09RDcKip9AN2w7eyyw7wd9yWSmVC20wb7ppOVBIl6pfbcu67RyuJWmJ1\nzDA95/JPgtRc1Pl/s99y36dJ7PgThTWNSHi528oYFkek1240UH4vqupLM/du\nmYC3\r\n=b4p+\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "cd2ffd70d0a02f126342951bc809d40a18a4c0ce",
+ "tarball": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-1.9.0.tgz",
+ "unpackedSize": 126979
+ },
+ "gitHead": "7580d700bfe9632abae30a4faefc2b3fd10b0b74",
+ "homepage": "https://git.coolaj86.com/coolaj86/rsa-compat.js#readme",
+ "keywords": [
+ "RSA",
+ "certificate",
+ "forge",
+ "jwk",
+ "key",
+ "linux",
+ "mac",
+ "ssl",
+ "tls",
+ "ursa",
+ "windows"
+ ],
+ "license": "MPL-2.0",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "coolaj86",
+ "email": "coolaj86@gmail.com"
+ }
+ ],
+ "name": "rsa-compat",
+ "optionalDependencies": {
+ "ursa-optional": "^0.9.10"
+ },
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "https://git.coolaj86.com/coolaj86/rsa-compat.js.git"
+ },
+ "scripts": {
+ "postinstall": "node lib/telemetry.js event:install",
+ "test": "bash test.sh"
+ },
+ "trulyOptionalDependencies": {
+ "buffer-v6-polyfill": "^1.0.3"
+ },
+ "version": "1.9.0"
+}
diff --git a/express-server/node_modules/rsa-compat/test.sh b/express-server/node_modules/rsa-compat/test.sh
new file mode 100644
index 00000000..27342ec8
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/test.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+set -e
+
+node tests/generate-csr.js
+node tests/generate-key.js
+node tests/generate-key-new.js
+node tests/generate-sig.js
+node tests/reciprocate.js
diff --git a/express-server/node_modules/rsa-compat/tests/generate-csr.js b/express-server/node_modules/rsa-compat/tests/generate-csr.js
new file mode 100644
index 00000000..f972ffae
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/tests/generate-csr.js
@@ -0,0 +1,26 @@
+'use strict';
+
+var RSA = require('../').RSA;
+
+var keypair = {
+ privateKeyJwk: {
+ "kty": "RSA",
+ "n": "AMJubTfOtAarnJytLE8fhNsEI8wnpjRvBXGK/Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocDUgukpfkY+2UPUS/GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdkom2FMhGxkLaEUGDSfsNznTTZNBBg9",
+ "e": "AQAB",
+ "d": "HT8DCrv69G3n9uFNovE4yMEMqW7lX0m75eJkMze3Jj5xNOa/4qlrc+4IuuA2uuyfY72IVQRxqqqXOuvS8ZForZZk+kWSd6z45hrpbNAAHH2Rf7XwnwHY8VJrOQF3UtbktTWqHX36ITZb9Hmf18hWsIeEp8Ng7Ru9h7hNuVxKMjk=",
+ "p": "AONjOvZVAvhCM2JnLGWJG3+5Boar3MB5P4ezfExDmuyGET/w0C+PS60jbjB8TivQsSdEcGo7GOaOlmAX6EQtAec=",
+ "q": "ANrllgJsy4rTMfa3mQ50kMIcNahiEOearhAcJgQUCHuOjuEnhU9FfExA/m5FXjmEFQhRwkuhk0QaIqTGbUzxGDs=",
+ "dp": "ALuxHOpYIatqeZ+wKiVllx1GTOy8z+rQKnCI5wDMjQTPZU2yKSYY0g6IQFwlPyFLke8nvuLxBQzKhbWsBjzAKeE=",
+ "dq": "XLhDAmPzE6rBzy+VtXnKl247jEd9wZzTfh9uOuwBa9TG0Lhcz2cvb11YaH0ZnGNGRW/cTQzzxDUN1531TlIRYQ==",
+ "qi": "AI2apz6ECfGwhsvIcU3+yFt+3CA78CUVsX4NUul5m3Cls2m+5MbGQG5K0hGpxjDC3OmXTq1Y5gnep5yUZvVPZI4="
+ }
+};
+
+var csrPem = RSA.generateCsrPem(keypair, ['example.com', 'www.example.com']);
+var csr64 = RSA.generateCsrDerWeb64(keypair, ['example.com', 'www.example.com']);
+console.log('');
+console.log('DEBUG csrPem');
+console.log(csrPem);
+console.log('');
+console.log('DEBUG csr64');
+console.log(csr64);
diff --git a/express-server/node_modules/rsa-compat/tests/generate-key-new.js b/express-server/node_modules/rsa-compat/tests/generate-key-new.js
new file mode 100644
index 00000000..bc04e793
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/tests/generate-key-new.js
@@ -0,0 +1,33 @@
+'use strict';
+
+var RSA = require('../').RSA;
+
+RSA.generateKeypair(null, function (err, keys) {
+ if (!keys || !keys.privateKeyJwk) {
+ throw new Error("Expected privateKeyJwk, but it is missing");
+ }
+
+ var options = {
+ public: true // export public keys
+ , pem: true // export pems
+ , jwk: false // export jwks
+ , internal: true // preserve internal intermediate formats (_ursa, _forge)
+ //, thumbprint: true // JWK sha256 thumbprint
+ , bitlen: 2048
+ , exp: 65537
+ };
+ RSA.generateKeypair(options, function (err, keys) {
+ if (
+ (keys.publicKeyJwk && !keys.thumbprint)
+ || !keys.privateKeyPem
+ || !keys.publicKeyPem
+ //|| !keys.thumbprint
+ ) {
+ console.error(Object.keys(keys));
+ throw new Error("Missing expected keys");
+ }
+
+ console.log('All is well!');
+ });
+
+});
diff --git a/express-server/node_modules/rsa-compat/tests/generate-key.js b/express-server/node_modules/rsa-compat/tests/generate-key.js
new file mode 100644
index 00000000..3911ac9c
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/tests/generate-key.js
@@ -0,0 +1,31 @@
+'use strict';
+
+var RSA = require('../').RSA;
+
+RSA.generateKeypair(null, null, null, function (err, keys) {
+ if (!keys.privateKeyJwk) {
+ throw new Error("Expected privateKeyJwk, but it is missing");
+ }
+
+ var options = {
+ public: true // export public keys
+ , pem: true // export pems
+ , jwk: false // export jwks
+ , internal: true // preserve internal intermediate formats (_ursa, _forge)
+ //, thumbprint: true // JWK sha256 thumbprint
+ };
+ RSA.generateKeypair(512, 65537, options, function (err, keys) {
+ if (
+ (keys.publicKeyJwk && !keys.thumbprint)
+ || !keys.privateKeyPem
+ || !keys.publicKeyPem
+ //|| !keys.thumbprint
+ ) {
+ console.error(Object.keys(keys));
+ throw new Error("Missing expected keys");
+ }
+
+ console.log('All is well!');
+ });
+
+});
diff --git a/express-server/node_modules/rsa-compat/tests/generate-sig.js b/express-server/node_modules/rsa-compat/tests/generate-sig.js
new file mode 100644
index 00000000..89a3b981
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/tests/generate-sig.js
@@ -0,0 +1,54 @@
+'use strict';
+
+var RSA = require('../').RSA;
+
+var keypair = {
+ privateKeyJwk: {
+ "kty": "RSA",
+ "n": "AMJubTfOtAarnJytLE8fhNsEI8wnpjRvBXGK_Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocDUgukpfkY-2UPUS_GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdkom2FMhGxkLaEUGDSfsNznTTZNBBg9",
+ "e": "AQAB",
+ "d": "HT8DCrv69G3n9uFNovE4yMEMqW7lX0m75eJkMze3Jj5xNOa_4qlrc-4IuuA2uuyfY72IVQRxqqqXOuvS8ZForZZk-kWSd6z45hrpbNAAHH2Rf7XwnwHY8VJrOQF3UtbktTWqHX36ITZb9Hmf18hWsIeEp8Ng7Ru9h7hNuVxKMjk=",
+ "p": "AONjOvZVAvhCM2JnLGWJG3-5Boar3MB5P4ezfExDmuyGET_w0C-PS60jbjB8TivQsSdEcGo7GOaOlmAX6EQtAec=",
+ "q": "ANrllgJsy4rTMfa3mQ50kMIcNahiEOearhAcJgQUCHuOjuEnhU9FfExA_m5FXjmEFQhRwkuhk0QaIqTGbUzxGDs=",
+ "dp": "ALuxHOpYIatqeZ-wKiVllx1GTOy8z-rQKnCI5wDMjQTPZU2yKSYY0g6IQFwlPyFLke8nvuLxBQzKhbWsBjzAKeE=",
+ "dq": "XLhDAmPzE6rBzy-VtXnKl247jEd9wZzTfh9uOuwBa9TG0Lhcz2cvb11YaH0ZnGNGRW_cTQzzxDUN1531TlIRYQ==",
+ "qi": "AI2apz6ECfGwhsvIcU3-yFt-3CA78CUVsX4NUul5m3Cls2m-5MbGQG5K0hGpxjDC3OmXTq1Y5gnep5yUZvVPZI4="
+ }
+};
+
+/*
+var ursaResult = {
+ "header": {
+ "alg": "RS256",
+ "jwk": {
+ "kty": "RSA",
+ "n": "AMJubTfOtAarnJytLE8fhNsEI8wnpjRvBXGK_Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocDUgukpfkY-2UPUS_GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdkom2FMhGxkLaEUGDSfsNznTTZNBBg9",
+ "e": "AQAB"
+ }
+ },
+ "protected": "eyJub25jZSI6IjhlZjU2MjRmNWVjOWQzZWYifQ",
+ "payload": "JLzF1NBNCV3kfbJ5sFaFyX94fJuL2H-IzaoBN-ciiHk",
+ "signature": "Wb2al5SDyh5gjmkV79MK9m3sfNBBPjntSKor-34BBoGwr6n8qEnBmqB1Y4zbo-5rmvsoPmJsnRlP_hRiUY86zSAQyfbisTGrGBl0IQ7ditpkfYVm0rBWJ8WnYNqYNp8K3qcD7NW72tsy-XoWEjNlz4lWJeRdEG2Nt4CJgnREH4Y"
+};
+var forgeResult = {
+ "header": {
+ "alg": "RS256",
+ "jwk": {
+ "kty": "RSA",
+ "n": "AMJubTfOtAarnJytLE8fhNsEI8wnpjRvBXGK_Kp0675J10ORzxyMLqzIZF3tcrUkKBrtdc79u4X0GocDUgukpfkY-2UPUS_GxehUYbYrJYWOLkoJWzxn7wfoo9X1JgvBMY6wHQnTKvnzZdkom2FMhGxkLaEUGDSfsNznTTZNBBg9",
+ "e": "AQAB"
+ }
+ },
+ "protected": "eyJub25jZSI6IjhlZjU2MjRmNWVjOWQzZWYifQ",
+ "payload": "JLzF1NBNCV3kfbJ5sFaFyX94fJuL2H-IzaoBN-ciiHk",
+ "signature": "Wb2al5SDyh5gjmkV79MK9m3sfNBBPjntSKor-34BBoGwr6n8qEnBmqB1Y4zbo-5rmvsoPmJsnRlP_hRiUY86zSAQyfbisTGrGBl0IQ7ditpkfYVm0rBWJ8WnYNqYNp8K3qcD7NW72tsy-XoWEjNlz4lWJeRdEG2Nt4CJgnREH4Y"
+};
+*/
+
+var jws = RSA.signJws(
+ keypair
+, Buffer.from('24bcc5d4d04d095de47db279b05685c97f787c9b8bd87f88cdaa0137e7228879', 'hex')
+, '8ef5624f5ec9d3ef'
+);
+
+console.log(JSON.stringify(jws, null, ' '));
diff --git a/express-server/node_modules/rsa-compat/tests/privkey.jwk b/express-server/node_modules/rsa-compat/tests/privkey.jwk
new file mode 100644
index 00000000..fcda91ce
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/tests/privkey.jwk
@@ -0,0 +1 @@
+{"kty":"RSA","n":"sdk_fKUwpygZjNuAt7804KFBZoeBXtJ5cMZyRDRCmPNZRjOqXSdMTY7We7W103Ivs97hz--quMg-R8smv3F1-4Quyfm5vXFQWPxYdrsfJzPkyku4lY8uWbZ8N0X1CM61NgQHOAwe8eHOM0zd-MECxrBASBzLuiq6Df-GpsridFivMYlFj7UTXm92ReFyOXZUZacXneCVWyUMIU6Faj8h2UVpaCCNsopT0fRoqoBIJ-qeXhDpbvfLfhbb25p79msutxN7mpGW9a3wL1LyoCTpMLqIlZSWKKDVCNyoTS9RH7lch-j8_DtL9VfNTPv1rw-n-N-LQDQH6z5j7ZanXiek0Q","e":"AQAB","d":"pQuaej8Gpql1BJ4TlvHvzWJ4wgCQk4G5x2myUw84mp6Cw75gpLA6hGNBMm8QPRjjogX-Ay1EftT9zzx9Sf6uYepqTW_d6ivFR79vDUhcAdKLyRx6QPkuJ31NSzI10qWZz3XviRjegtRtunfkKtxbii24ifOHMM5D-Yef2xu_Cf5RRZVSipZdLRlgttSW2t-lXCaFN1-F8ITPCEqaQGoHn5fk9eEhl2sd3r8BCN1xp_KTAyqxBt9inDr__YlYynXS9Y35Wu4Ofn9CszwiCrZxezWO6Mn0-T-woDYj3jsO7aRvWPOIcMSaL7KqbM1BIWKPJqtSXqc8uVs4ZcVEnB4pXQ","p":"6sx1OM-3ise7cQCOffWLxbB8xNfpQSpyC0_ZzNF-FNSpCfFiJ6GjhBhgddppdyLD8jR34ZO4sTM6ny575ez6XOVrSUHi4Cavnv7DH8PxWT3_IVGKYKbqQt63KdIKpxxC3EoG66VPCQvjJ-TgkjNhqPLFKDW9ihvHVQlsDrVcLss","q":"wehZNfic8h69BUp8ynQIqSaao--N4fKm_fOH8kvmsZQlns0Asiy2jTYnfZy0jN380x_A8Q2Bx15N5byokRzn3NzC3dni_Z87h-c0Upss7G4iIPDngUwAN0EnraXbzVAv1jWC7wdsYJgSOLxJ0QVcLN-yPPs12ESf3hTQS2XNS1M","dp":"OWt0w0bw8Mx1h2YGcsFIxDir2ouerGQP7bpCXjdhKQD0sczJHz4FOfmoJUobfpoO5z1zj8PLZ_JKRMFeZVU1yOAGA61MKVrsmepdl3gYnqVtrh09xPMs2NuUWXLXThS4OR0VYi1UDbdNfuUXEknkeSedlX7G8m5mqeIa_eHWQE8","dq":"P7zGBi2QOS3NZ_3SAyIc7qzXy-ckNg7ywSrZltVIITrXGtm7ztVPtB8G4A0wc9VME4GuhA2yiPwAkvFuXzSnKjwOeanzKPa8NLHUywpiu9x_r2BAWInI0GDEUBnipBwlfT3dqgBAqYeTBb8ubFxcrgthpRXV3x6_hdpFlWMDFi0","qi":"FnwWA6Flj9jp2vy_RL1WEDTSr2xCdVm3guNuUhwXIav5-tXm5kDca-4fJEGUiSYzh_MLApUT9U-97zV5Qfws-OAq6pDu1-34hU-w1xpKh1OKvKEOfvYGX1mdzu3FIaaB7RQSr_TW3AyOl29HP--lOcrsYmIK5xnuqc13MQ6Nss4"}
diff --git a/express-server/node_modules/rsa-compat/tests/privkey.pem b/express-server/node_modules/rsa-compat/tests/privkey.pem
new file mode 100644
index 00000000..25f54f02
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/tests/privkey.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAsdk/fKUwpygZjNuAt7804KFBZoeBXtJ5cMZyRDRCmPNZRjOq
+XSdMTY7We7W103Ivs97hz++quMg+R8smv3F1+4Quyfm5vXFQWPxYdrsfJzPkyku4
+lY8uWbZ8N0X1CM61NgQHOAwe8eHOM0zd+MECxrBASBzLuiq6Df+GpsridFivMYlF
+j7UTXm92ReFyOXZUZacXneCVWyUMIU6Faj8h2UVpaCCNsopT0fRoqoBIJ+qeXhDp
+bvfLfhbb25p79msutxN7mpGW9a3wL1LyoCTpMLqIlZSWKKDVCNyoTS9RH7lch+j8
+/DtL9VfNTPv1rw+n+N+LQDQH6z5j7ZanXiek0QIDAQABAoIBAQClC5p6PwamqXUE
+nhOW8e/NYnjCAJCTgbnHabJTDzianoLDvmCksDqEY0EybxA9GOOiBf4DLUR+1P3P
+PH1J/q5h6mpNb93qK8VHv28NSFwB0ovJHHpA+S4nfU1LMjXSpZnPde+JGN6C1G26
+d+Qq3FuKLbiJ84cwzkP5h5/bG78J/lFFlVKKll0tGWC21Jba36VcJoU3X4XwhM8I
+SppAagefl+T14SGXax3evwEI3XGn8pMDKrEG32KcOv/9iVjKddL1jfla7g5+f0Kz
+PCIKtnF7NY7oyfT5P7CgNiPeOw7tpG9Y84hwxJovsqpszUEhYo8mq1Jepzy5Wzhl
+xUScHildAoGBAOrMdTjPt4rHu3EAjn31i8WwfMTX6UEqcgtP2czRfhTUqQnxYieh
+o4QYYHXaaXciw/I0d+GTuLEzOp8ue+Xs+lzla0lB4uAmr57+wx/D8Vk9/yFRimCm
+6kLetynSCqccQtxKBuulTwkL4yfk4JIzYajyxSg1vYobx1UJbA61XC7LAoGBAMHo
+WTX4nPIevQVKfMp0CKkmmqPvjeHypv3zh/JL5rGUJZ7NALIsto02J32ctIzd/NMf
+wPENgcdeTeW8qJEc59zcwt3Z4v2fO4fnNFKbLOxuIiDw54FMADdBJ62l281QL9Y1
+gu8HbGCYEji8SdEFXCzfsjz7NdhEn94U0EtlzUtTAoGAOWt0w0bw8Mx1h2YGcsFI
+xDir2ouerGQP7bpCXjdhKQD0sczJHz4FOfmoJUobfpoO5z1zj8PLZ/JKRMFeZVU1
+yOAGA61MKVrsmepdl3gYnqVtrh09xPMs2NuUWXLXThS4OR0VYi1UDbdNfuUXEknk
+eSedlX7G8m5mqeIa/eHWQE8CgYA/vMYGLZA5Lc1n/dIDIhzurNfL5yQ2DvLBKtmW
+1UghOtca2bvO1U+0HwbgDTBz1UwTga6EDbKI/ACS8W5fNKcqPA55qfMo9rw0sdTL
+CmK73H+vYEBYicjQYMRQGeKkHCV9Pd2qAECph5MFvy5sXFyuC2GlFdXfHr+F2kWV
+YwMWLQKBgBZ8FgOhZY/Y6dr8v0S9VhA00q9sQnVZt4LjblIcFyGr+frV5uZA3Gvu
+HyRBlIkmM4fzCwKVE/VPve81eUH8LPjgKuqQ7tft+IVPsNcaSodTiryhDn72Bl9Z
+nc7txSGmge0UEq/01twMjpdvRz/vpTnK7GJiCucZ7qnNdzEOjbLO
+-----END RSA PRIVATE KEY-----
diff --git a/express-server/node_modules/rsa-compat/tests/reciprocate.js b/express-server/node_modules/rsa-compat/tests/reciprocate.js
new file mode 100644
index 00000000..dc7a756f
--- /dev/null
+++ b/express-server/node_modules/rsa-compat/tests/reciprocate.js
@@ -0,0 +1,86 @@
+'use strict';
+
+var RSA = require('../').RSA;
+var fs = require('fs');
+var path = require('path');
+
+var privkeyPemRef = fs.readFileSync(path.join(__dirname, 'privkey.pem'), 'ascii');
+var privkeyJwkRef = JSON.parse(fs.readFileSync(path.join(__dirname, 'privkey.jwk'), 'ascii'));
+
+var refs = {
+ privPem: RSA.exportPrivatePem({ privateKeyJwk: privkeyJwkRef })
+, privJwk: RSA.exportPrivateJwk({ privateKeyPem: privkeyPemRef })
+};
+
+var hasUrsa;
+var imported;
+
+try {
+ hasUrsa = require('ursa') && true;
+} catch(e) {
+ hasUrsa = false;
+}
+
+
+
+//
+//
+// PEM tests
+//
+//
+console.log('JWK -> PEM ?', privkeyPemRef === refs.privPem);
+if (privkeyPemRef !== refs.privPem) {
+ // Watch out for tricky whitespaces (\n instead of \r\n, trailing \r\n, etc)
+ console.log('REF:');
+ console.log(JSON.stringify(privkeyPemRef));
+ console.log('GEN:');
+ console.log(JSON.stringify(refs.privPem));
+ throw new Error("Failed to validate importedJwk against referencePem");
+}
+
+console.log('PEM -> _ -> PEM ?', privkeyPemRef === refs.privPem);
+if (hasUrsa) {
+ imported = RSA.import({ privateKeyPem: privkeyPemRef });
+ refs.privPem2 = RSA.exportPrivatePem({ _ursa: imported._ursa });
+}
+else {
+ imported = RSA.import({ privateKeyPem: privkeyPemRef });
+ refs.privPem2 = RSA.exportPrivatePem(imported);
+}
+if (privkeyPemRef !== refs.privPem2) {
+ console.log('REF:');
+ console.log(JSON.stringify(privkeyPemRef));
+ console.log('GEN:');
+ console.log(JSON.stringify(refs.privPem2));
+ throw new Error("Failed to validate importedPem against referencePem");
+}
+
+
+//
+//
+// JWK tests
+//
+//
+console.log('PEM -> JWK ?', privkeyJwkRef.n === refs.privJwk.n);
+if (![ 'kty', 'n', 'e', 'p', 'q', 'dp', 'dq', 'qi', 'd' ].every(function (k) {
+ return privkeyJwkRef[k] === refs.privJwk[k];
+})) {
+ console.log('REF:');
+ console.log(privkeyJwkRef);
+ console.log('GEN:');
+ console.log(refs.privJwk);
+ throw new Error("Failed to validate importedPem against referenceJwk");
+}
+
+imported = RSA.import({ privateKeyJwk: privkeyJwkRef });
+refs.privJwk2 = RSA.exportPrivateJwk(imported);
+console.log('JWK -> _ -> JWK ?', privkeyJwkRef.n === refs.privJwk2.n);
+if (privkeyJwkRef.n !== refs.privJwk2.n) {
+ console.log('REF:');
+ console.log(privkeyJwkRef);
+ console.log('GEN:');
+ console.log(refs.privJwk2);
+ throw new Error("Failed to validate importedJwk against referenceJwk");
+}
+
+console.log('');
diff --git a/express-server/node_modules/safe-replace/LICENSE b/express-server/node_modules/safe-replace/LICENSE
new file mode 100644
index 00000000..8f71f43f
--- /dev/null
+++ b/express-server/node_modules/safe-replace/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/express-server/node_modules/safe-replace/README.md b/express-server/node_modules/safe-replace/README.md
new file mode 100644
index 00000000..e60d24d1
--- /dev/null
+++ b/express-server/node_modules/safe-replace/README.md
@@ -0,0 +1,86 @@
+safe-replace
+============
+
+A micro-module for safely replacing a file.
+
+This is intended to be generally safe even when a function that writes a file
+is accidentally called twice (as may happen with node cluster).
+
+Commandline Reference
+---------------------
+
+If I want to safely replace a file with a new version, I would do so like this:
+
+```bash
+# create the new version
+touch keep.txt.RANDOM.tmp
+
+# remove the previous backup
+rm -f keep.txt.bak
+
+# move the current version to the backup
+mv keep.txt keep.txt.bak
+
+# move the new version to the current
+mv keep.txt.RANDOM.tmp keep.txt
+```
+
+If `keep.txt` became corrupt and I wanted to use the backup,
+I would do this:
+
+```bash
+# copy the backup to the new version
+rsync keep.txt.bak keep.txt
+```
+
+In Node
+-------
+
+I ported that proccess to node.
+
+```
+sfs.writeFileAsync
+sfs.stageAsync
+sfs.commitAsync
+sfs.revertAsync
+```
+
+```js
+// default behavior is to concat (filename + '.' + rnd() + '.tmp')
+var safeReplace = require('safe-replace').create({ tmp: 'tmp', bak: 'bak' });
+
+var data = new Buffer('A priceless document');
+safeReplace.writeFileAsync('keep.txt', data, 'ascii').then(function () {
+ fs.readdir('.', function (nodes) {
+ console.log('file system nodes', nodes);
+ // keep.txt
+ // keep.txt.bak
+ });
+});
+
+// let's say I want to write a tmp file and not commit it... weird
+safeReplace.stageAsync('keep.txt', data, 'ascii').then(function (tmpname) {
+ fs.readdir('.', function (nodes) {
+ console.log('file system nodes', nodes);
+ // keep.txt.ac71teh8mja.tmp
+ });
+});
+
+// let's say I wrote keep.txt.x7t7sq926.tmp with my own mechanism
+safeReplace.commitAsync('keep.txt.x7t7sq926.tmp', 'keep.txt').then(function () {
+ fs.readdir('.', function (nodes) {
+ console.log('file system nodes', nodes);
+ // keep.txt
+ // keep.txt.bak
+ });
+});
+
+// let's say I want to revert the file from the '.bak'
+safeReplace.revertAsync('keep.txt').then(function () {
+ fs.readdir('.', function (nodes) {
+ console.log('file system nodes', nodes);
+ // keep.txt
+ // keep.txt.bak
+ });
+});
+```
diff --git a/express-server/node_modules/safe-replace/index.js b/express-server/node_modules/safe-replace/index.js
new file mode 100644
index 00000000..63240b2e
--- /dev/null
+++ b/express-server/node_modules/safe-replace/index.js
@@ -0,0 +1,118 @@
+'use strict';
+
+var PromiseA;
+try {
+ PromiseA = require('bluebird');
+} catch(e) {
+ PromiseA = global.Promise;
+}
+
+var util = require('util');
+var promisify = util.promisify || PromiseA.promisify;
+if (!PromiseA || !promisify) {
+ throw new Error("DON'T PANIC. Everything is A-OK."
+ + " However, you're on a really old version of node. All you need to do is `npm install --save bluebird`"
+ + " (in your project directory, which is probably '" + require('path').dirname(require.main.filename) + "')"
+ + " and everything will work just fine.");
+}
+
+var fs = require('fs');
+var writeFileAsync = promisify(fs.writeFile);
+var unlinkAsync = promisify(fs.unlink);
+var renameAsync = promisify(fs.rename);
+var crypto = require('crypto');
+
+function noop() {
+}
+
+function create(options) {
+
+ if (!options) {
+ options = {};
+ }
+ if (!options.tmp) {
+ options.tmp = 'tmp';
+ }
+ if (!options.bak) {
+ options.bak = 'bak';
+ }
+ if (options.tmp === options.bak) {
+ throw new Error("'tmp' and 'bak' suffixes cannot be the same... duh");
+ }
+
+ var tmpnamefn = options.tmpnamefn || function (pathname) {
+ return pathname + '.' + crypto.randomBytes(8).toString('hex') + '.' + options.tmp;
+ };
+ var baknamefn = options.baknamefn || function (pathname) {
+ return pathname + '.' + options.bak;
+ };
+ /*
+ var namefn = options.namefn || function (pathname) {
+ return pathname;
+ };
+ */
+
+ var sfs = {
+ writeFileAsync: function (filename, data, options) {
+ return sfs.stage(filename, data, options).then(function (tmpname) {
+ //console.log(filename);
+ return sfs.commit(tmpname, filename);
+ });
+ }
+ , stageAsync: function (filename, data, options) {
+ var tmpname = tmpnamefn(filename);
+ //console.log(tmpname);
+ return writeFileAsync(tmpname, data, options).then(function () {
+ return tmpname;
+ });
+ }
+ , commitAsync: function (tmpname, filename) {
+ var bakname = baknamefn(filename);
+ // this may not exist
+ return unlinkAsync(bakname).then(noop, noop).then(function () {
+ // this may not exist
+ //console.log(namefn(filename), '->', bakname);
+ return renameAsync(filename, bakname).then(function () {
+ //console.log('created bak');
+ }, noop);
+ }).then(function () {
+ // this must be successful
+ //console.log(filename, '->', filename);
+ return renameAsync(tmpname, filename).then(noop, function (err) {
+ //console.error(err);
+ return sfs.revert(filename).then(function () {
+ return PromiseA.reject(err);
+ });
+ });
+ });
+ }
+ , revertAsync: function (filename) {
+ return new PromiseA(function (resolve, reject) {
+ var bakname = baknamefn(filename);
+ var tmpname = tmpnamefn(filename);
+
+ var reader = fs.createReadStream(bakname);
+ var writer = fs.createWriteStream(tmpname);
+
+ reader.on('error', reject);
+ writer.on('error', reject);
+
+ reader.pipe(writer);
+ writer.on('close', function () {
+ sfs.commit(tmpname, filename).then(resolve, reject);
+ });
+ });
+ }
+ , tmpnamefn: tmpnamefn
+ , baknamefn: baknamefn
+ , create: create
+ };
+ sfs.writeFile = sfs.writeFileAsync;
+ sfs.stage = sfs.stageAsync;
+ sfs.commit = sfs.commitAsync;
+ sfs.revert = sfs.revertAsync;
+
+ return sfs;
+}
+
+module.exports = create();
diff --git a/express-server/node_modules/safe-replace/package.json b/express-server/node_modules/safe-replace/package.json
new file mode 100644
index 00000000..377d062d
--- /dev/null
+++ b/express-server/node_modules/safe-replace/package.json
@@ -0,0 +1,93 @@
+{
+ "_args": [
+ [
+ "safe-replace@^1.0.3",
+ "/nodeapps/https-test/greenlock-express.js/node_modules/le-store-certbot"
+ ]
+ ],
+ "_from": "safe-replace@>=1.0.3 <2.0.0",
+ "_hasShrinkwrap": false,
+ "_id": "safe-replace@1.1.0",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/safe-replace",
+ "_nodeVersion": "10.6.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/safe-replace_1.1.0_1536002535947_0.38815297465919096"
+ },
+ "_npmUser": {
+ "email": "coolaj86@gmail.com",
+ "name": "coolaj86"
+ },
+ "_npmVersion": "6.1.0",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "safe-replace",
+ "raw": "safe-replace@^1.0.3",
+ "rawSpec": "^1.0.3",
+ "scope": null,
+ "spec": ">=1.0.3 <2.0.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/le-store-certbot",
+ "/pyconf"
+ ],
+ "_resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
+ "_shasum": "432821b5a8139a38b534678d712f0850fe3e5235",
+ "_shrinkwrap": null,
+ "_spec": "safe-replace@^1.0.3",
+ "_where": "/nodeapps/https-test/greenlock-express.js/node_modules/le-store-certbot",
+ "author": {
+ "email": "coolaj86@gmail.com",
+ "name": "AJ ONeal",
+ "url": "https://coolaj86.com/"
+ },
+ "bugs": {
+ "url": "https://git.coolaj86.com/coolaj86/fs-safe-replace.js/issues"
+ },
+ "dependencies": {},
+ "description": "A micro-module for safely replacing a file.",
+ "devDependencies": {},
+ "directories": {},
+ "dist": {
+ "fileCount": 5,
+ "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbjYnoCRA9TVsSAnZWagAArVUP/RJ9pBsnGovUfM9Nt1JO\nkPW7FsKanVR3HAhQw0qRWOJiuSnr3cH/Z0SqwpRlSLWIZI1QV9yYsg9sPWZJ\nHd/xYjFdrgGPl6T4XW7GfF6CQTmJePjTD7cvwdR73qzxGRglUk9xjOrXsMAA\nrRm2yltVxqmbrdlqd5nxiw8JurwIjipH85lP+1RFaeraOtk9vrxzlHPIhPQo\nrOIa0ivDAGQxLwS58RVEBjxcJI2ZonnWBfKrR0CP+nQC9IHiNglGkRvTB1QW\nHKpp6Yis2mAQThddKENsT5Gx8M1Im8HFMGMmKi9jZPHT9A4wTv2/eRKmZIqV\n09X3gLjjAhWRx6AWc9H2luK+O0aUdoRWT6y2BJqkxOm2afHy4NIHo539RPAJ\nfx5qDkfD2LOaFbUN6Cr7/zMNsTcJjklAoWC/eQoSjB2dJ/GONtZs83F43QhJ\nyd9bYOU8AWl+FNDlw0+QWzWUk3aDVLXhw29DHyYWjW5vTAzL5RKIGQHxLv8e\nVwa7LFoLc6aAnBOOtouTtdxuJGkJztrewwG6GSITJ/gUg8IUfH9CpqQvF7hP\ncazgE+qBcdlSQbcBSkEK3Jp6NemwH8vzE3nA1hYxRRP+UdzEEbxgkOzGEzj3\nMY09g0PBMW09heBpqGfGbDTWv/zrs5BzbF6uCmDgszpI+rMTnuAkCmL/xvT8\nyhmk\r\n=BtfS\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "432821b5a8139a38b534678d712f0850fe3e5235",
+ "tarball": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
+ "unpackedSize": 17811
+ },
+ "gitHead": "54b295422952af449286827a1f7846a425961851",
+ "homepage": "https://git.coolaj86.com/coolaj86/fs-safe-replace.jse",
+ "keywords": [
+ "cluster",
+ "condition",
+ "config",
+ "file",
+ "json",
+ "race",
+ "replace",
+ "write"
+ ],
+ "license": "(MIT OR Apache-2.0)",
+ "main": "index.js",
+ "maintainers": [
+ {
+ "name": "coolaj86",
+ "email": "coolaj86@gmail.com"
+ }
+ ],
+ "name": "safe-replace",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "https://git.coolaj86.com/coolaj86/fs-safe-replace.js.git"
+ },
+ "scripts": {
+ "test": "node test.js"
+ },
+ "version": "1.1.0"
+}
diff --git a/express-server/node_modules/safe-replace/test.js b/express-server/node_modules/safe-replace/test.js
new file mode 100644
index 00000000..caa86e11
--- /dev/null
+++ b/express-server/node_modules/safe-replace/test.js
@@ -0,0 +1,11 @@
+'use strict';
+
+var safeReplace = require('./'); //.create();
+//var safeReplace = require('safe-replace').create();
+var fs = require('fs');
+
+safeReplace.writeFile('keep.txt', 'my precious').then(function () {
+ fs.readdir('.', function (err, nodes) {
+ console.log('file system nodes', nodes);
+ });
+});
diff --git a/express-server/node_modules/serve-index/HISTORY.md b/express-server/node_modules/serve-index/HISTORY.md
new file mode 100644
index 00000000..4bc7d1a8
--- /dev/null
+++ b/express-server/node_modules/serve-index/HISTORY.md
@@ -0,0 +1,305 @@
+1.9.1 / 2017-09-28
+==================
+
+ * deps: accepts@~1.3.4
+ - deps: mime-types@~2.1.16
+ * deps: debug@2.6.9
+ * deps: http-errors@~1.6.2
+ - deps: depd@1.1.1
+ * deps: mime-types@~2.1.17
+ - Add new mime types
+ - deps: mime-db@~1.30.0
+ * deps: parseurl@~1.3.2
+ - perf: reduce overhead for full URLs
+ - perf: unroll the "fast-path" `RegExp`
+
+1.9.0 / 2017-05-25
+==================
+
+ * Set `X-Content-Type-Options: nosniff` header
+ * deps: batch@0.6.1
+ * deps: debug@2.6.8
+ - Allow colors in workers
+ - Deprecated `DEBUG_FD` environment variable set to `3` or higher
+ - Fix `DEBUG_MAX_ARRAY_LENGTH`
+ - Fix error when running under React Native
+ - Use same color for same namespace
+ - deps: ms@2.0.0
+ * deps: http-errors@~1.6.1
+ - Make `message` property enumerable for `HttpError`s
+ - deps: inherits@2.0.3
+ - deps: setprototypeof@1.0.3
+ - deps: statuses@'>= 1.3.1 < 2'
+ * deps: mime-types@~2.1.15
+ - Add new mime types
+ - Add `audio/mp3`
+
+1.8.0 / 2016-06-17
+==================
+
+ * Make inline file search case-insensitive
+ * deps: accepts@~1.3.3
+ - deps: mime-types@~2.1.11
+ - deps: negotiator@0.6.1
+ - perf: improve header parsing speed
+ * deps: http-errors@~1.5.0
+ - Use `setprototypeof` module to replace `__proto__` setting
+ - deps: inherits@2.0.1
+ - deps: statuses@'>= 1.3.0 < 2'
+ - perf: enable strict mode
+ * deps: mime-types@~2.1.11
+ - Add new mime types
+ - Update primary extension for `audio/mp4`
+ - deps: mime-db@~1.23.0
+
+1.7.3 / 2016-01-24
+==================
+
+ * deps: accepts@~1.2.13
+ - deps: mime-types@~2.1.6
+ * deps: batch@0.5.3
+ - Fix invalid dependency for browserify
+ * deps: escape-html@~1.0.3
+ - perf: enable strict mode
+ - perf: optimize string replacement
+ - perf: use faster string coercion
+ * deps: mime-types@~2.1.9
+ - Add new mime types
+ * deps: parseurl@~1.3.1
+ - perf: enable strict mode
+
+1.7.2 / 2015-07-30
+==================
+
+ * deps: accepts@~1.2.12
+ - deps: mime-types@~2.1.4
+ * deps: mime-types@~2.1.4
+ - Add new mime types
+
+1.7.1 / 2015-07-05
+==================
+
+ * deps: accepts@~1.2.10
+ - deps: mime-types@~2.1.2
+ * deps: mime-types@~2.1.2
+ - Add new mime types
+
+1.7.0 / 2015-06-15
+==================
+
+ * Accept `function` value for `template` option
+ * Send non-chunked response for `OPTIONS`
+ * Stat parent directory when necessary
+ * Use `Date.prototype.toLocaleDateString` to format date
+ * deps: accepts@~1.2.9
+ - deps: mime-types@~2.1.1
+ - deps: negotiator@0.5.3
+ - perf: avoid argument reassignment & argument slice
+ - perf: avoid negotiator recursive construction
+ - perf: enable strict mode
+ - perf: remove unnecessary bitwise operator
+ * deps: escape-html@1.0.2
+ * deps: mime-types@~2.1.1
+ - Add new mime types
+ * perf: enable strict mode
+ * perf: remove argument reassignment
+
+1.6.4 / 2015-05-12
+==================
+
+ * deps: accepts@~1.2.7
+ - deps: mime-types@~2.0.11
+ - deps: negotiator@0.5.3
+ * deps: debug@~2.2.0
+ - deps: ms@0.7.1
+ * deps: mime-types@~2.0.11
+ - Add new mime types
+
+1.6.3 / 2015-03-13
+==================
+
+ * Properly escape file names in HTML
+ * deps: accepts@~1.2.5
+ - deps: mime-types@~2.0.10
+ * deps: debug@~2.1.3
+ - Fix high intensity foreground color for bold
+ - deps: ms@0.7.0
+ * deps: escape-html@1.0.1
+ * deps: mime-types@~2.0.10
+ - Add new mime types
+
+1.6.2 / 2015-02-16
+==================
+
+ * deps: accepts@~1.2.4
+ - deps: mime-types@~2.0.9
+ - deps: negotiator@0.5.1
+ * deps: http-errors@~1.3.1
+ - Construct errors using defined constructors from `createError`
+ - Fix error names that are not identifiers
+ - Set a meaningful `name` property on constructed errors
+ * deps: mime-types@~2.0.9
+ - Add new mime types
+ - deps: mime-db@~1.7.0
+
+1.6.1 / 2015-01-31
+==================
+
+ * deps: accepts@~1.2.3
+ - deps: mime-types@~2.0.8
+ * deps: mime-types@~2.0.8
+ - Add new mime types
+ - deps: mime-db@~1.6.0
+
+1.6.0 / 2015-01-01
+==================
+
+ * Add link to root directory
+ * deps: accepts@~1.2.2
+ - deps: mime-types@~2.0.7
+ - deps: negotiator@0.5.0
+ * deps: batch@0.5.2
+ * deps: debug@~2.1.1
+ * deps: mime-types@~2.0.7
+ - Add new mime types
+ - Fix missing extensions
+ - Fix various invalid MIME type entries
+ - Remove example template MIME types
+ - deps: mime-db@~1.5.0
+
+1.5.3 / 2014-12-10
+==================
+
+ * deps: accepts@~1.1.4
+ - deps: mime-types@~2.0.4
+ * deps: http-errors@~1.2.8
+ - Fix stack trace from exported function
+ * deps: mime-types@~2.0.4
+ - Add new mime types
+ - deps: mime-db@~1.3.0
+
+1.5.2 / 2014-12-03
+==================
+
+ * Fix icon name background alignment on mobile view
+
+1.5.1 / 2014-11-22
+==================
+
+ * deps: accepts@~1.1.3
+ - deps: mime-types@~2.0.3
+ * deps: mime-types@~2.0.3
+ - Add new mime types
+ - deps: mime-db@~1.2.0
+
+1.5.0 / 2014-10-16
+==================
+
+ * Create errors with `http-errors`
+ * deps: debug@~2.1.0
+ - Implement `DEBUG_FD` env variable support
+ * deps: mime-types@~2.0.2
+ - deps: mime-db@~1.1.0
+
+1.4.1 / 2014-10-15
+==================
+
+ * deps: accepts@~1.1.2
+ - Fix error when media type has invalid parameter
+ - deps: negotiator@0.4.9
+
+1.4.0 / 2014-10-03
+==================
+
+ * Add `dir` argument to `filter` function
+ * Support using tokens multiple times
+
+1.3.1 / 2014-10-01
+==================
+
+ * Fix incorrect 403 on Windows and Node.js 0.11
+ * deps: accepts@~1.1.1
+ - deps: mime-types@~2.0.2
+ - deps: negotiator@0.4.8
+
+1.3.0 / 2014-09-20
+==================
+
+ * Add icon for mkv files
+ * Lookup icon by mime type for greater icon support
+
+1.2.1 / 2014-09-05
+==================
+
+ * deps: accepts@~1.1.0
+ * deps: debug@~2.0.0
+
+1.2.0 / 2014-08-25
+==================
+
+ * Add `debug` messages
+ * Resolve relative paths at middleware setup
+
+1.1.6 / 2014-08-10
+==================
+
+ * Fix URL parsing
+ * deps: parseurl@~1.3.0
+
+1.1.5 / 2014-07-27
+==================
+
+ * Fix Content-Length calculation for multi-byte file names
+ * deps: accepts@~1.0.7
+ - deps: negotiator@0.4.7
+
+1.1.4 / 2014-06-20
+==================
+
+ * deps: accepts@~1.0.5
+
+1.1.3 / 2014-06-20
+==================
+
+ * deps: accepts@~1.0.4
+ - use `mime-types`
+
+1.1.2 / 2014-06-19
+==================
+
+ * deps: batch@0.5.1
+
+1.1.1 / 2014-06-11
+==================
+
+ * deps: accepts@1.0.3
+
+1.1.0 / 2014-05-29
+==================
+
+ * Fix content negotiation when no `Accept` header
+ * Properly support all HTTP methods
+ * Support vanilla node.js http servers
+ * Treat `ENAMETOOLONG` as code 414
+ * Use accepts for negotiation
+
+1.0.3 / 2014-05-20
+==================
+
+ * Fix error from non-statable files in HTML view
+
+1.0.2 / 2014-04-28
+==================
+
+ * Add `stylesheet` option
+ * deps: negotiator@0.4.3
+
+1.0.1 / 2014-03-05
+==================
+
+ * deps: negotiator@0.4.2
+
+1.0.0 / 2014-03-05
+==================
+
+ * Genesis from connect
diff --git a/express-server/node_modules/serve-index/LICENSE b/express-server/node_modules/serve-index/LICENSE
new file mode 100644
index 00000000..d8cce679
--- /dev/null
+++ b/express-server/node_modules/serve-index/LICENSE
@@ -0,0 +1,25 @@
+(The MIT License)
+
+Copyright (c) 2010 Sencha Inc.
+Copyright (c) 2011 LearnBoost
+Copyright (c) 2011 TJ Holowaychuk
+Copyright (c) 2014-2015 Douglas Christopher Wilson
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/express-server/node_modules/serve-index/README.md b/express-server/node_modules/serve-index/README.md
new file mode 100644
index 00000000..c21db282
--- /dev/null
+++ b/express-server/node_modules/serve-index/README.md
@@ -0,0 +1,154 @@
+# serve-index
+
+[![NPM Version][npm-image]][npm-url]
+[![NPM Downloads][downloads-image]][downloads-url]
+[![Linux Build][travis-image]][travis-url]
+[![Windows Build][appveyor-image]][appveyor-url]
+[![Test Coverage][coveralls-image]][coveralls-url]
+[![Gratipay][gratipay-image]][gratipay-url]
+
+ Serves pages that contain directory listings for a given path.
+
+## Install
+
+This is a [Node.js](https://nodejs.org/en/) module available through the
+[npm registry](https://www.npmjs.com/). Installation is done using the
+[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
+
+```sh
+$ npm install serve-index
+```
+
+## API
+
+```js
+var serveIndex = require('serve-index')
+```
+
+### serveIndex(path, options)
+
+Returns middlware that serves an index of the directory in the given `path`.
+
+The `path` is based off the `req.url` value, so a `req.url` of `'/some/dir`
+with a `path` of `'public'` will look at `'public/some/dir'`. If you are using
+something like `express`, you can change the URL "base" with `app.use` (see
+the express example).
+
+#### Options
+
+Serve index accepts these properties in the options object.
+
+##### filter
+
+Apply this filter function to files. Defaults to `false`. The `filter` function
+is called for each file, with the signature `filter(filename, index, files, dir)`
+where `filename` is the name of the file, `index` is the array index, `files` is
+the array of files and `dir` is the absolute path the file is located (and thus,
+the directory the listing is for).
+
+##### hidden
+
+Display hidden (dot) files. Defaults to `false`.
+
+##### icons
+
+Display icons. Defaults to `false`.
+
+##### stylesheet
+
+Optional path to a CSS stylesheet. Defaults to a built-in stylesheet.
+
+##### template
+
+Optional path to an HTML template or a function that will render a HTML
+string. Defaults to a built-in template.
+
+When given a string, the string is used as a file path to load and then the
+following tokens are replaced in templates:
+
+ * `{directory}` with the name of the directory.
+ * `{files}` with the HTML of an unordered list of file links.
+ * `{linked-path}` with the HTML of a link to the directory.
+ * `{style}` with the specified stylesheet and embedded images.
+
+When given as a function, the function is called as `template(locals, callback)`
+and it needs to invoke `callback(error, htmlString)`. The following are the
+provided locals:
+
+ * `directory` is the directory being displayed (where `/` is the root).
+ * `displayIcons` is a Boolean for if icons should be rendered or not.
+ * `fileList` is a sorted array of files in the directory. The array contains
+ objects with the following properties:
+ - `name` is the relative name for the file.
+ - `stat` is a `fs.Stats` object for the file.
+ * `path` is the full filesystem path to `directory`.
+ * `style` is the default stylesheet or the contents of the `stylesheet` option.
+ * `viewName` is the view name provided by the `view` option.
+
+##### view
+
+Display mode. `tiles` and `details` are available. Defaults to `tiles`.
+
+## Examples
+
+### Serve directory indexes with vanilla node.js http server
+
+```js
+var finalhandler = require('finalhandler')
+var http = require('http')
+var serveIndex = require('serve-index')
+var serveStatic = require('serve-static')
+
+// Serve directory indexes for public/ftp folder (with icons)
+var index = serveIndex('public/ftp', {'icons': true})
+
+// Serve up public/ftp folder files
+var serve = serveStatic('public/ftp')
+
+// Create server
+var server = http.createServer(function onRequest(req, res){
+ var done = finalhandler(req, res)
+ serve(req, res, function onNext(err) {
+ if (err) return done(err)
+ index(req, res, done)
+ })
+})
+
+// Listen
+server.listen(3000)
+```
+
+### Serve directory indexes with express
+
+```js
+var express = require('express')
+var serveIndex = require('serve-index')
+
+var app = express()
+
+// Serve URLs like /ftp/thing as public/ftp/thing
+// The express.static serves the file contents
+// The serveIndex is this module serving the directory
+app.use('/ftp', express.static('public/ftp'), serveIndex('public/ftp', {'icons': true}))
+
+// Listen
+app.listen(3000)
+```
+
+## License
+
+[MIT](LICENSE). The [Silk](http://www.famfamfam.com/lab/icons/silk/) icons
+are created by/copyright of [FAMFAMFAM](http://www.famfamfam.com/).
+
+[npm-image]: https://img.shields.io/npm/v/serve-index.svg
+[npm-url]: https://npmjs.org/package/serve-index
+[travis-image]: https://img.shields.io/travis/expressjs/serve-index/master.svg?label=linux
+[travis-url]: https://travis-ci.org/expressjs/serve-index
+[appveyor-image]: https://img.shields.io/appveyor/ci/dougwilson/serve-index/master.svg?label=windows
+[appveyor-url]: https://ci.appveyor.com/project/dougwilson/serve-index
+[coveralls-image]: https://img.shields.io/coveralls/expressjs/serve-index/master.svg
+[coveralls-url]: https://coveralls.io/r/expressjs/serve-index?branch=master
+[downloads-image]: https://img.shields.io/npm/dm/serve-index.svg
+[downloads-url]: https://npmjs.org/package/serve-index
+[gratipay-image]: https://img.shields.io/gratipay/dougwilson.svg
+[gratipay-url]: https://www.gratipay.com/dougwilson/
diff --git a/express-server/node_modules/serve-index/index.js b/express-server/node_modules/serve-index/index.js
new file mode 100644
index 00000000..e3a619f9
--- /dev/null
+++ b/express-server/node_modules/serve-index/index.js
@@ -0,0 +1,646 @@
+/*!
+ * serve-index
+ * Copyright(c) 2011 Sencha Inc.
+ * Copyright(c) 2011 TJ Holowaychuk
+ * Copyright(c) 2014-2015 Douglas Christopher Wilson
+ * MIT Licensed
+ */
+
+'use strict';
+
+/**
+ * Module dependencies.
+ * @private
+ */
+
+var accepts = require('accepts');
+var createError = require('http-errors');
+var debug = require('debug')('serve-index');
+var escapeHtml = require('escape-html');
+var fs = require('fs')
+ , path = require('path')
+ , normalize = path.normalize
+ , sep = path.sep
+ , extname = path.extname
+ , join = path.join;
+var Batch = require('batch');
+var mime = require('mime-types');
+var parseUrl = require('parseurl');
+var resolve = require('path').resolve;
+
+/**
+ * Module exports.
+ * @public
+ */
+
+module.exports = serveIndex;
+
+/*!
+ * Icon cache.
+ */
+
+var cache = {};
+
+/*!
+ * Default template.
+ */
+
+var defaultTemplate = join(__dirname, 'public', 'directory.html');
+
+/*!
+ * Stylesheet.
+ */
+
+var defaultStylesheet = join(__dirname, 'public', 'style.css');
+
+/**
+ * Media types and the map for content negotiation.
+ */
+
+var mediaTypes = [
+ 'text/html',
+ 'text/plain',
+ 'application/json'
+];
+
+var mediaType = {
+ 'text/html': 'html',
+ 'text/plain': 'plain',
+ 'application/json': 'json'
+};
+
+/**
+ * Serve directory listings with the given `root` path.
+ *
+ * See Readme.md for documentation of options.
+ *
+ * @param {String} root
+ * @param {Object} options
+ * @return {Function} middleware
+ * @public
+ */
+
+function serveIndex(root, options) {
+ var opts = options || {};
+
+ // root required
+ if (!root) {
+ throw new TypeError('serveIndex() root path required');
+ }
+
+ // resolve root to absolute and normalize
+ var rootPath = normalize(resolve(root) + sep);
+
+ var filter = opts.filter;
+ var hidden = opts.hidden;
+ var icons = opts.icons;
+ var stylesheet = opts.stylesheet || defaultStylesheet;
+ var template = opts.template || defaultTemplate;
+ var view = opts.view || 'tiles';
+
+ return function (req, res, next) {
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
+ res.statusCode = 'OPTIONS' === req.method ? 200 : 405;
+ res.setHeader('Allow', 'GET, HEAD, OPTIONS');
+ res.setHeader('Content-Length', '0');
+ res.end();
+ return;
+ }
+
+ // parse URLs
+ var url = parseUrl(req);
+ var originalUrl = parseUrl.original(req);
+ var dir = decodeURIComponent(url.pathname);
+ var originalDir = decodeURIComponent(originalUrl.pathname);
+
+ // join / normalize from root dir
+ var path = normalize(join(rootPath, dir));
+
+ // null byte(s), bad request
+ if (~path.indexOf('\0')) return next(createError(400));
+
+ // malicious path
+ if ((path + sep).substr(0, rootPath.length) !== rootPath) {
+ debug('malicious path "%s"', path);
+ return next(createError(403));
+ }
+
+ // determine ".." display
+ var showUp = normalize(resolve(path) + sep) !== rootPath;
+
+ // check if we have a directory
+ debug('stat "%s"', path);
+ fs.stat(path, function(err, stat){
+ if (err && err.code === 'ENOENT') {
+ return next();
+ }
+
+ if (err) {
+ err.status = err.code === 'ENAMETOOLONG'
+ ? 414
+ : 500;
+ return next(err);
+ }
+
+ if (!stat.isDirectory()) return next();
+
+ // fetch files
+ debug('readdir "%s"', path);
+ fs.readdir(path, function(err, files){
+ if (err) return next(err);
+ if (!hidden) files = removeHidden(files);
+ if (filter) files = files.filter(function(filename, index, list) {
+ return filter(filename, index, list, path);
+ });
+ files.sort();
+
+ // content-negotiation
+ var accept = accepts(req);
+ var type = accept.type(mediaTypes);
+
+ // not acceptable
+ if (!type) return next(createError(406));
+ serveIndex[mediaType[type]](req, res, files, next, originalDir, showUp, icons, path, view, template, stylesheet);
+ });
+ });
+ };
+};
+
+/**
+ * Respond with text/html.
+ */
+
+serveIndex.html = function _html(req, res, files, next, dir, showUp, icons, path, view, template, stylesheet) {
+ var render = typeof template !== 'function'
+ ? createHtmlRender(template)
+ : template
+
+ if (showUp) {
+ files.unshift('..');
+ }
+
+ // stat all files
+ stat(path, files, function (err, stats) {
+ if (err) return next(err);
+
+ // combine the stats into the file list
+ var fileList = files.map(function (file, i) {
+ return { name: file, stat: stats[i] };
+ });
+
+ // sort file list
+ fileList.sort(fileSort);
+
+ // read stylesheet
+ fs.readFile(stylesheet, 'utf8', function (err, style) {
+ if (err) return next(err);
+
+ // create locals for rendering
+ var locals = {
+ directory: dir,
+ displayIcons: Boolean(icons),
+ fileList: fileList,
+ path: path,
+ style: style,
+ viewName: view
+ };
+
+ // render html
+ render(locals, function (err, body) {
+ if (err) return next(err);
+ send(res, 'text/html', body)
+ });
+ });
+ });
+};
+
+/**
+ * Respond with application/json.
+ */
+
+serveIndex.json = function _json(req, res, files) {
+ send(res, 'application/json', JSON.stringify(files))
+};
+
+/**
+ * Respond with text/plain.
+ */
+
+serveIndex.plain = function _plain(req, res, files) {
+ send(res, 'text/plain', (files.join('\n') + '\n'))
+};
+
+/**
+ * Map html `files`, returning an html unordered list.
+ * @private
+ */
+
+function createHtmlFileList(files, dir, useIcons, view) {
+ var html = '
+
+
\ No newline at end of file
diff --git a/express-server/node_modules/serve-index/public/icons/application_xp.png b/express-server/node_modules/serve-index/public/icons/application_xp.png
new file mode 100644
index 00000000..d22860a3
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/application_xp.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/application_xp_terminal.png b/express-server/node_modules/serve-index/public/icons/application_xp_terminal.png
new file mode 100644
index 00000000..c28dd638
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/application_xp_terminal.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/box.png b/express-server/node_modules/serve-index/public/icons/box.png
new file mode 100644
index 00000000..8443c23e
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/box.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/cd.png b/express-server/node_modules/serve-index/public/icons/cd.png
new file mode 100644
index 00000000..ef432235
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/cd.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/controller.png b/express-server/node_modules/serve-index/public/icons/controller.png
new file mode 100644
index 00000000..5cf76ed0
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/controller.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/drive.png b/express-server/node_modules/serve-index/public/icons/drive.png
new file mode 100644
index 00000000..37b7c9b2
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/drive.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/film.png b/express-server/node_modules/serve-index/public/icons/film.png
new file mode 100644
index 00000000..b0ce7bb1
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/film.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/folder.png b/express-server/node_modules/serve-index/public/icons/folder.png
new file mode 100644
index 00000000..698f3d30
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/folder.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/font.png b/express-server/node_modules/serve-index/public/icons/font.png
new file mode 100644
index 00000000..b7960db9
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/font.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/image.png b/express-server/node_modules/serve-index/public/icons/image.png
new file mode 100644
index 00000000..fc3c393c
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/image.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/map.png b/express-server/node_modules/serve-index/public/icons/map.png
new file mode 100644
index 00000000..f90ef25e
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/map.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page.png b/express-server/node_modules/serve-index/public/icons/page.png
new file mode 100644
index 00000000..03ddd799
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_add.png b/express-server/node_modules/serve-index/public/icons/page_add.png
new file mode 100644
index 00000000..d5bfa071
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_add.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_attach.png b/express-server/node_modules/serve-index/public/icons/page_attach.png
new file mode 100644
index 00000000..89ee2da0
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_attach.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_code.png b/express-server/node_modules/serve-index/public/icons/page_code.png
new file mode 100644
index 00000000..f7ea9041
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_code.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_copy.png b/express-server/node_modules/serve-index/public/icons/page_copy.png
new file mode 100644
index 00000000..195dc6d6
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_copy.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_delete.png b/express-server/node_modules/serve-index/public/icons/page_delete.png
new file mode 100644
index 00000000..3141467c
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_delete.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_edit.png b/express-server/node_modules/serve-index/public/icons/page_edit.png
new file mode 100644
index 00000000..046811ed
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_edit.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_error.png b/express-server/node_modules/serve-index/public/icons/page_error.png
new file mode 100644
index 00000000..f07f449a
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_error.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_excel.png b/express-server/node_modules/serve-index/public/icons/page_excel.png
new file mode 100644
index 00000000..eb6158eb
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_excel.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_find.png b/express-server/node_modules/serve-index/public/icons/page_find.png
new file mode 100644
index 00000000..2f193889
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_find.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_gear.png b/express-server/node_modules/serve-index/public/icons/page_gear.png
new file mode 100644
index 00000000..8e83281c
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_gear.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_go.png b/express-server/node_modules/serve-index/public/icons/page_go.png
new file mode 100644
index 00000000..80fe1ed0
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_go.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_green.png b/express-server/node_modules/serve-index/public/icons/page_green.png
new file mode 100644
index 00000000..de8e003f
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_green.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_key.png b/express-server/node_modules/serve-index/public/icons/page_key.png
new file mode 100644
index 00000000..d6626cb0
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_key.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_lightning.png b/express-server/node_modules/serve-index/public/icons/page_lightning.png
new file mode 100644
index 00000000..7e568703
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_lightning.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_link.png b/express-server/node_modules/serve-index/public/icons/page_link.png
new file mode 100644
index 00000000..312eab09
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_link.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_paintbrush.png b/express-server/node_modules/serve-index/public/icons/page_paintbrush.png
new file mode 100644
index 00000000..246a2f0b
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_paintbrush.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_paste.png b/express-server/node_modules/serve-index/public/icons/page_paste.png
new file mode 100644
index 00000000..968f073f
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_paste.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_red.png b/express-server/node_modules/serve-index/public/icons/page_red.png
new file mode 100644
index 00000000..0b18247d
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_red.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_refresh.png b/express-server/node_modules/serve-index/public/icons/page_refresh.png
new file mode 100644
index 00000000..cf347c7d
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_refresh.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_save.png b/express-server/node_modules/serve-index/public/icons/page_save.png
new file mode 100644
index 00000000..caea546a
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_save.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white.png b/express-server/node_modules/serve-index/public/icons/page_white.png
new file mode 100644
index 00000000..8b8b1ca0
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_acrobat.png b/express-server/node_modules/serve-index/public/icons/page_white_acrobat.png
new file mode 100644
index 00000000..8f8095e4
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_acrobat.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_actionscript.png b/express-server/node_modules/serve-index/public/icons/page_white_actionscript.png
new file mode 100644
index 00000000..159b2407
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_actionscript.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_add.png b/express-server/node_modules/serve-index/public/icons/page_white_add.png
new file mode 100644
index 00000000..aa23dde3
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_add.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_c.png b/express-server/node_modules/serve-index/public/icons/page_white_c.png
new file mode 100644
index 00000000..34a05ccc
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_c.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_camera.png b/express-server/node_modules/serve-index/public/icons/page_white_camera.png
new file mode 100644
index 00000000..f501a593
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_camera.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_cd.png b/express-server/node_modules/serve-index/public/icons/page_white_cd.png
new file mode 100644
index 00000000..848bdaf3
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_cd.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_code.png b/express-server/node_modules/serve-index/public/icons/page_white_code.png
new file mode 100644
index 00000000..0c76bd12
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_code.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_code_red.png b/express-server/node_modules/serve-index/public/icons/page_white_code_red.png
new file mode 100644
index 00000000..87a69145
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_code_red.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_coldfusion.png b/express-server/node_modules/serve-index/public/icons/page_white_coldfusion.png
new file mode 100644
index 00000000..c66011fb
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_coldfusion.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_compressed.png b/express-server/node_modules/serve-index/public/icons/page_white_compressed.png
new file mode 100644
index 00000000..2b6b1007
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_compressed.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_copy.png b/express-server/node_modules/serve-index/public/icons/page_white_copy.png
new file mode 100644
index 00000000..a9f31a27
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_copy.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_cplusplus.png b/express-server/node_modules/serve-index/public/icons/page_white_cplusplus.png
new file mode 100644
index 00000000..a87cf847
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_cplusplus.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_csharp.png b/express-server/node_modules/serve-index/public/icons/page_white_csharp.png
new file mode 100644
index 00000000..ffb8fc93
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_csharp.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_cup.png b/express-server/node_modules/serve-index/public/icons/page_white_cup.png
new file mode 100644
index 00000000..0a7d6f4a
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_cup.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_database.png b/express-server/node_modules/serve-index/public/icons/page_white_database.png
new file mode 100644
index 00000000..bddba1f9
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_database.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_delete.png b/express-server/node_modules/serve-index/public/icons/page_white_delete.png
new file mode 100644
index 00000000..af1ecaf2
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_delete.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_dvd.png b/express-server/node_modules/serve-index/public/icons/page_white_dvd.png
new file mode 100644
index 00000000..4cc537af
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_dvd.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_edit.png b/express-server/node_modules/serve-index/public/icons/page_white_edit.png
new file mode 100644
index 00000000..b93e7760
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_edit.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_error.png b/express-server/node_modules/serve-index/public/icons/page_white_error.png
new file mode 100644
index 00000000..9fc5a0a1
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_error.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_excel.png b/express-server/node_modules/serve-index/public/icons/page_white_excel.png
new file mode 100644
index 00000000..b977d7e5
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_excel.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_find.png b/express-server/node_modules/serve-index/public/icons/page_white_find.png
new file mode 100644
index 00000000..58184363
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_find.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_flash.png b/express-server/node_modules/serve-index/public/icons/page_white_flash.png
new file mode 100644
index 00000000..5769120b
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_flash.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_freehand.png b/express-server/node_modules/serve-index/public/icons/page_white_freehand.png
new file mode 100644
index 00000000..8d719df5
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_freehand.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_gear.png b/express-server/node_modules/serve-index/public/icons/page_white_gear.png
new file mode 100644
index 00000000..106f5aa3
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_gear.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_get.png b/express-server/node_modules/serve-index/public/icons/page_white_get.png
new file mode 100644
index 00000000..e4a1ecba
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_get.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_go.png b/express-server/node_modules/serve-index/public/icons/page_white_go.png
new file mode 100644
index 00000000..7e62a924
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_go.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_h.png b/express-server/node_modules/serve-index/public/icons/page_white_h.png
new file mode 100644
index 00000000..e902abb0
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_h.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_horizontal.png b/express-server/node_modules/serve-index/public/icons/page_white_horizontal.png
new file mode 100644
index 00000000..1d2d0a49
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_horizontal.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_key.png b/express-server/node_modules/serve-index/public/icons/page_white_key.png
new file mode 100644
index 00000000..d6164845
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_key.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_lightning.png b/express-server/node_modules/serve-index/public/icons/page_white_lightning.png
new file mode 100644
index 00000000..7215d1e8
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_lightning.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_link.png b/express-server/node_modules/serve-index/public/icons/page_white_link.png
new file mode 100644
index 00000000..bf7bd1c9
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_link.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_magnify.png b/express-server/node_modules/serve-index/public/icons/page_white_magnify.png
new file mode 100644
index 00000000..f6b74cc4
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_magnify.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_medal.png b/express-server/node_modules/serve-index/public/icons/page_white_medal.png
new file mode 100644
index 00000000..d3fffb6d
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_medal.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_office.png b/express-server/node_modules/serve-index/public/icons/page_white_office.png
new file mode 100644
index 00000000..a65bcb3e
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_office.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_paint.png b/express-server/node_modules/serve-index/public/icons/page_white_paint.png
new file mode 100644
index 00000000..23a37b89
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_paint.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_paintbrush.png b/express-server/node_modules/serve-index/public/icons/page_white_paintbrush.png
new file mode 100644
index 00000000..f907e44b
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_paintbrush.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_paste.png b/express-server/node_modules/serve-index/public/icons/page_white_paste.png
new file mode 100644
index 00000000..5b2cbb3f
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_paste.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_php.png b/express-server/node_modules/serve-index/public/icons/page_white_php.png
new file mode 100644
index 00000000..7868a259
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_php.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_picture.png b/express-server/node_modules/serve-index/public/icons/page_white_picture.png
new file mode 100644
index 00000000..134b6693
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_picture.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_powerpoint.png b/express-server/node_modules/serve-index/public/icons/page_white_powerpoint.png
new file mode 100644
index 00000000..c4eff038
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_powerpoint.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_put.png b/express-server/node_modules/serve-index/public/icons/page_white_put.png
new file mode 100644
index 00000000..884ffd6f
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_put.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_ruby.png b/express-server/node_modules/serve-index/public/icons/page_white_ruby.png
new file mode 100644
index 00000000..f59b7c43
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_ruby.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_stack.png b/express-server/node_modules/serve-index/public/icons/page_white_stack.png
new file mode 100644
index 00000000..44084add
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_stack.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_star.png b/express-server/node_modules/serve-index/public/icons/page_white_star.png
new file mode 100644
index 00000000..3a1441c9
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_star.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_swoosh.png b/express-server/node_modules/serve-index/public/icons/page_white_swoosh.png
new file mode 100644
index 00000000..e7708292
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_swoosh.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_text.png b/express-server/node_modules/serve-index/public/icons/page_white_text.png
new file mode 100644
index 00000000..813f712f
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_text.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_text_width.png b/express-server/node_modules/serve-index/public/icons/page_white_text_width.png
new file mode 100644
index 00000000..d9cf1325
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_text_width.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_tux.png b/express-server/node_modules/serve-index/public/icons/page_white_tux.png
new file mode 100644
index 00000000..52699bfe
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_tux.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_vector.png b/express-server/node_modules/serve-index/public/icons/page_white_vector.png
new file mode 100644
index 00000000..4a05955b
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_vector.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_visualstudio.png b/express-server/node_modules/serve-index/public/icons/page_white_visualstudio.png
new file mode 100644
index 00000000..a0a433df
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_visualstudio.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_width.png b/express-server/node_modules/serve-index/public/icons/page_white_width.png
new file mode 100644
index 00000000..1eb88094
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_width.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_word.png b/express-server/node_modules/serve-index/public/icons/page_white_word.png
new file mode 100644
index 00000000..ae8ecbf4
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_word.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_world.png b/express-server/node_modules/serve-index/public/icons/page_white_world.png
new file mode 100644
index 00000000..6ed2490e
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_world.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_wrench.png b/express-server/node_modules/serve-index/public/icons/page_white_wrench.png
new file mode 100644
index 00000000..fecadd08
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_wrench.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_white_zip.png b/express-server/node_modules/serve-index/public/icons/page_white_zip.png
new file mode 100644
index 00000000..fd4bbccd
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_white_zip.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_word.png b/express-server/node_modules/serve-index/public/icons/page_word.png
new file mode 100644
index 00000000..834cdfaf
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_word.png differ
diff --git a/express-server/node_modules/serve-index/public/icons/page_world.png b/express-server/node_modules/serve-index/public/icons/page_world.png
new file mode 100644
index 00000000..b8895dde
Binary files /dev/null and b/express-server/node_modules/serve-index/public/icons/page_world.png differ
diff --git a/express-server/node_modules/serve-index/public/style.css b/express-server/node_modules/serve-index/public/style.css
new file mode 100644
index 00000000..eb99dc9b
--- /dev/null
+++ b/express-server/node_modules/serve-index/public/style.css
@@ -0,0 +1,257 @@
+* {
+ margin: 0;
+ padding: 0;
+ outline: 0;
+}
+
+body {
+ padding: 80px 100px;
+ font: 13px "Helvetica Neue", "Lucida Grande", "Arial";
+ background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9));
+ background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9);
+ background-repeat: no-repeat;
+ color: #555;
+ -webkit-font-smoothing: antialiased;
+}
+h1, h2, h3 {
+ font-size: 22px;
+ color: #343434;
+}
+h1 em, h2 em {
+ padding: 0 5px;
+ font-weight: normal;
+}
+h1 {
+ font-size: 60px;
+}
+h2 {
+ margin-top: 10px;
+}
+h3 {
+ margin: 5px 0 10px 0;
+ padding-bottom: 5px;
+ border-bottom: 1px solid #eee;
+ font-size: 18px;
+}
+ul li {
+ list-style: none;
+}
+ul li:hover {
+ cursor: pointer;
+ color: #2e2e2e;
+}
+ul li .path {
+ padding-left: 5px;
+ font-weight: bold;
+}
+ul li .line {
+ padding-right: 5px;
+ font-style: italic;
+}
+ul li:first-child .path {
+ padding-left: 0;
+}
+p {
+ line-height: 1.5;
+}
+a {
+ color: #555;
+ text-decoration: none;
+}
+a:hover {
+ color: #303030;
+}
+#stacktrace {
+ margin-top: 15px;
+}
+.directory h1 {
+ margin-bottom: 15px;
+ font-size: 18px;
+}
+ul#files {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+ul#files li {
+ float: left;
+ width: 30%;
+ line-height: 25px;
+ margin: 1px;
+}
+ul#files li a {
+ display: block;
+ height: 25px;
+ border: 1px solid transparent;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ overflow: hidden;
+ white-space: nowrap;
+}
+ul#files li a:focus,
+ul#files li a:hover {
+ background: rgba(255,255,255,0.65);
+ border: 1px solid #ececec;
+}
+ul#files li a.highlight {
+ -webkit-transition: background .4s ease-in-out;
+ background: #ffff4f;
+ border-color: #E9DC51;
+}
+#search {
+ display: block;
+ position: fixed;
+ top: 20px;
+ right: 20px;
+ width: 90px;
+ -webkit-transition: width ease 0.2s, opacity ease 0.4s;
+ -moz-transition: width ease 0.2s, opacity ease 0.4s;
+ -webkit-border-radius: 32px;
+ -moz-border-radius: 32px;
+ -webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
+ -moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
+ -webkit-font-smoothing: antialiased;
+ text-align: left;
+ font: 13px "Helvetica Neue", Arial, sans-serif;
+ padding: 4px 10px;
+ border: none;
+ background: transparent;
+ margin-bottom: 0;
+ outline: none;
+ opacity: 0.7;
+ color: #888;
+}
+#search:focus {
+ width: 120px;
+ opacity: 1.0;
+}
+
+/*views*/
+#files span {
+ display: inline-block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ text-indent: 10px;
+}
+#files .name {
+ background-repeat: no-repeat;
+}
+#files .icon .name {
+ text-indent: 28px;
+}
+
+/*tiles*/
+.view-tiles .name {
+ width: 100%;
+ background-position: 8px 5px;
+}
+.view-tiles .size,
+.view-tiles .date {
+ display: none;
+}
+
+/*details*/
+ul#files.view-details li {
+ float: none;
+ display: block;
+ width: 90%;
+}
+ul#files.view-details li.header {
+ height: 25px;
+ background: #000;
+ color: #fff;
+ font-weight: bold;
+}
+.view-details .header {
+ border-radius: 5px;
+}
+.view-details .name {
+ width: 60%;
+ background-position: 8px 5px;
+}
+.view-details .size {
+ width: 10%;
+}
+.view-details .date {
+ width: 30%;
+}
+.view-details .size,
+.view-details .date {
+ text-align: right;
+ direction: rtl;
+}
+
+/*mobile*/
+@media (max-width: 768px) {
+ body {
+ font-size: 13px;
+ line-height: 16px;
+ padding: 0;
+ }
+ #search {
+ position: static;
+ width: 100%;
+ font-size: 2em;
+ line-height: 1.8em;
+ text-indent: 10px;
+ border: 0;
+ border-radius: 0;
+ padding: 10px 0;
+ margin: 0;
+ }
+ #search:focus {
+ width: 100%;
+ border: 0;
+ opacity: 1;
+ }
+ .directory h1 {
+ font-size: 2em;
+ line-height: 1.5em;
+ color: #fff;
+ background: #000;
+ padding: 15px 10px;
+ margin: 0;
+ }
+ ul#files {
+ border-top: 1px solid #cacaca;
+ }
+ ul#files li {
+ float: none;
+ width: auto !important;
+ display: block;
+ border-bottom: 1px solid #cacaca;
+ font-size: 2em;
+ line-height: 1.2em;
+ text-indent: 0;
+ margin: 0;
+ }
+ ul#files li:nth-child(odd) {
+ background: #e0e0e0;
+ }
+ ul#files li a {
+ height: auto;
+ border: 0;
+ border-radius: 0;
+ padding: 15px 10px;
+ }
+ ul#files li a:focus,
+ ul#files li a:hover {
+ border: 0;
+ }
+ #files .header,
+ #files .size,
+ #files .date {
+ display: none !important;
+ }
+ #files .name {
+ float: none;
+ display: inline-block;
+ width: 100%;
+ text-indent: 0;
+ background-position: 0 50%;
+ }
+ #files .icon .name {
+ text-indent: 41px;
+ }
+}
diff --git a/express-server/node_modules/ursa-optional/.travis.yml b/express-server/node_modules/ursa-optional/.travis.yml
new file mode 100644
index 00000000..d699c4eb
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/.travis.yml
@@ -0,0 +1,19 @@
+language: node_js
+sudo: false
+env:
+ - CXX=g++-4.8
+node_js:
+ - "0.12"
+ - "4"
+ - "5"
+ - "6"
+ - "7"
+ - "8"
+ - "9"
+ - "10"
+addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - g++-4.8
diff --git a/express-server/node_modules/ursa-optional/LICENSE.txt b/express-server/node_modules/ursa-optional/LICENSE.txt
new file mode 100644
index 00000000..55e332a8
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/LICENSE.txt
@@ -0,0 +1,194 @@
+Copyright 2012 The Obvious Corporation.
+http://obvious.com/
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
+-------------------------------------------------------------------------
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/express-server/node_modules/ursa-optional/README.md b/express-server/node_modules/ursa-optional/README.md
new file mode 100644
index 00000000..0663f13f
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/README.md
@@ -0,0 +1,596 @@
+URSA - RSA public/private key OpenSSL bindings for Node.js
+====
+
+
+[](https://travis-ci.org/JoshKaufman/ursa)
+
+> NOTE: This package was transfered from [Medium](https://github.com/Medium) and [NodePrime](https://github.com/NodePrime) to [quartzjer](https://github.com/quartzjer) to [JoshKaufman](https://github.com/joshkaufman) on 8-2017. Pull requests are welcomed to help maintain it.
+
+--
+
+This Node module provides a fairly complete set of wrappers for the
+RSA public/private key crypto functionality of OpenSSL.
+
+It is being actively developed for node.js 0.8.* through 0.12.* and io.js. If you find it doesn't work for you, please file a bug (see below).
+
+It has been tested on Windows by [SLaks](https://github.com/SLaks). (see [additional installation requirements](#windows-install))
+
+Table of Contents
+-----------------
+- [Simple Encrypt / Decrypt Example](#simple-encrypt--decrypt-example)
+- [Building and Installing](#building-and-installing)
+- [Usage](#usage)
+- [Top-level Exports](#top-level-exports)
+- [Public Key Methods](#public-key-methods)
+- [Private Key Methods](#private-key-methods)
+- [Signer Methods](#signer-methods)
+- [Verifier Methods](#verifier-methods)
+- [Constants](#constants)
+- [Contributing](#contributing)
+- [Authors](#authors)
+- [License](#license)
+- [Related Repos](#other-repos-that-may-be-of-interest)
+
+
+
+
+Simple Encrypt / Decrypt Example
+--------------------------------
+
+```javascript
+// openssl genrsa -out certs/server/my-server.key.pem 2048
+// openssl rsa -in certs/server/my-server.key.pem -pubout -out certs/client/my-server.pub
+
+'use strict';
+
+var fs = require('fs')
+ , ursa = require('ursa')
+ , crt
+ , key
+ , msg
+ ;
+
+key = ursa.createPrivateKey(fs.readFileSync('./certs/server/my-server.key.pem'));
+crt = ursa.createPublicKey(fs.readFileSync('./certs/client/my-server.pub'));
+
+console.log('Encrypt with Public');
+msg = crt.encrypt("Everything is going to be 200 OK", 'utf8', 'base64');
+console.log('encrypted', msg, '\n');
+
+console.log('Decrypt with Private');
+msg = key.decrypt(msg, 'base64', 'utf8');
+console.log('decrypted', msg, '\n');
+
+console.log('############################################');
+console.log('Reverse Public -> Private, Private -> Public');
+console.log('############################################\n');
+
+console.log('Encrypt with Private (called public)');
+msg = key.privateEncrypt("Everything is going to be 200 OK", 'utf8', 'base64');
+console.log('encrypted', msg, '\n');
+
+console.log('Decrypt with Public (called private)');
+msg = crt.publicDecrypt(msg, 'base64', 'utf8');
+console.log('decrypted', msg, '\n');
+```
+
+
+Building and Installing
+-----------------------
+
+```shell
+npm install ursa
+```
+
+Or grab the source and
+
+```shell
+npm install
+```
+
+Testing
+-------
+
+```shell
+npm test
+```
+
+Or
+
+```shell
+node ./test/test.js
+```
+
+On Windows, you'll need to install some dependencies first:
+ - [OpenSSL](http://slproweb.com/products/Win32OpenSSL.html) (normal, not light)
+in the same bitness as your Node.js installation.
+ - OpenSSL must be installed in the a specific install directory (`C:\OpenSSL-Win32` or `C:\OpenSSL-Win64`)
+ - If you get `Error: The specified module could not be found.`, copy `libeay32.dll` from the OpenSSL bin directory to this module's bin directory, or to Windows\System32. If you don't have `libeay32.dll`, you may have to install OpenSSL v1.0.2, not v1.1.x.
+ - [node-gyp](https://github.com/nodejs/node-gyp) (`npm install -g node-gyp`)
+ - You will need [python 2.7](http://www.python.org/download/releases/2.7.3#download) and a compatible version
+ Visual Studio installed first. Even with that, `node-gyp` installation or use can have
+ issues on Windows. The `node-gyp` [README file](https://github.com/nodejs/node-gyp) has detailed instructions
+ if you have difficulties. [This post](https://www.robertkehoe.com/2015/03/fix-node-gyp-rebuild-error-on-windows/)
+ is also a good reference.
+
+Usage
+-----
+
+This library aims to be convenient to use, allowing one to pass in and
+get back regular string objects. However, it is also meant to be reasonably
+easy to use efficiently, allowing one to pass in and get back Buffer
+objects. Using Buffers is always the more efficient option.
+
+All methods that can deal with strings take one or more arguments indicating
+the encoding to use when interpreting an argument or generating a result.
+These are limited to the usual encoding names that are valid for use with
+Buffers: `base64` `binary` `hex` and `utf8`. If an encoding is left undefined
+and the argument is a string, then the encoding is *always* assumed to be
+`utf8`. If an argument is a Buffer, then the encoding (if defined at all)
+is ignored. An undefined output encoding is *always* interpreted as a request
+for a Buffer result.
+
+The library knows how to read and output PEM format files for both
+public and private keys, and it can generate new private keys (aka
+keypairs).
+
+The usual public-encryption / private-decryption operations by default
+use padding mode `RSA_PKCS1_OAEP_PADDING`, which is the recommended
+mode for all new applications (as of this writing). Note that this mode
+builds-in a random element into every encryption operation, making it
+unnecessary to waste time or effort adding randomness in at a higher layer.
+This default may be overridden to use the older mode `RSA_PKCS1_PADDING`
+if needed.
+
+The less well-understood private-encryption / public-decryption operations
+(used for building signature mechanisms) by default use padding
+mode `RSA_PKCS1_PADDING`. This doesn't build in any randomness (but that's
+not usually a problem for applications that use these operations). This
+default may be overridden to use `RSA_NO_PADDING` if needed.
+
+See the doc comments and tests for the excruciating details, but here's
+a quick rundown of the available top-level exports and instance methods:
+
+Top-Level Exports
+-----------------
+
+### ursa.createPrivateKey(pem, password, encoding)
+
+Create and return a private key (aka a keypair) read in from the given
+PEM-format file. If defined, the given password is used to decrypt
+the PEM file.
+
+The encoding, if specified, applies to both other arguments.
+
+See "Public Key Methods" below for more details.
+
+### ursa.createPrivateKeyFromComponents(modulus, exponent, p, q, dp, dq, inverseQ, d)
+
+Create and return a private key from the given components.
+
+### ursa.createPublicKeyFromComponents(modulus, exponent)
+
+Create and return a public key from the given components.
+
+### ursa.assertKey(obj)
+
+Convenient shorthand for `assert(ursa.isKey(obj))`.
+
+### ursa.assertPrivateKey(obj)
+
+Convenient shorthand for `assert(ursa.isPrivateKey(obj))`.
+
+### ursa.assertPublicKey(obj)
+
+Convenient shorthand for `assert(ursa.isPublicKey(obj))`.
+
+### ursa.coerceKey(orig)
+
+Coerce the given key value into a key object (either public or
+private), returning it. If given a private key object, this just
+returns it as-is. If given a string or Buffer, it tries to parse it as
+PEM. Anything else will result in an error.
+
+### ursa.coercePrivateKey(orig)
+
+Coerce the given key value into a private key object, returning it. If
+given a private key object, this just returns it as-is. If given a
+string or Buffer, it tries to parse it as PEM. Anything else will
+result in an error.
+
+### ursa.coercePublicKey(orig)
+
+Coerce the given key value into a public key object, returning it. If
+given a private key object, this just returns it as-is. If given a
+string or Buffer, it tries to parse it as PEM. Anything else will
+result in an error.
+
+### ursa.createPublicKey(pem, encoding)
+
+Create and return a public key read in from the given PEM-format file.
+See "Public Key Methods" below for more details.
+
+### ursa.createSigner(algorithm)
+
+Create and return a signer which can sign a hash generated with the named
+algorithm (such as `"sha256"` or `"md5"`). See "Signer Methods" below
+for more details.
+
+This function is similar to `crypto.createSign()`, except this function
+takes a hash algorithm name (e.g., `"sha256"`) and not a crypto+hash name
+combination (e.g., `"RSA-SHA256"`).
+
+### ursa.createVerifier(algorithm)
+
+Create and return a verifier which can verify a hash generated with the
+named algorithm (such as `"sha256"` or `"md5"`). See "Verifier Methods" below
+for more details.
+
+This function is similar to `crypto.createVerify()`, except this function
+takes a hash algorithm name (e.g., `"sha256"`) and not a crypto+hash name
+combination (e.g., `"RSA-SHA256"`).
+
+### ursa.equalKeys(key1, key2)
+
+This returns `true` if and only if both arguments are key objects of
+the same type (public or private) and their contents match.
+
+### ursa.generatePrivateKey(modulusBits, exponent)
+
+Create and return a freshly-generated private key (aka a keypair).
+The first argument indicates the number of bits in the modulus (1024
+or more is generally considered secure). The second argument indicates
+the exponent value, which must be odd (65537 is the typical value; 3
+and 17 are also common). Both arguments are optional and default to
+2048 and 65537 (respectively).
+
+This method will throw if `modulusBits` is less than `512` (because
+it's pretty crazy to want a key with that few bits) or if `exponent`
+is even (because RSA only works for odd exponents).
+
+Using the command-line `openssl` tool, this operation is
+equivalent to:
+
+```shell
+openssl genrsa -out key-name.pem
+```
+
+for exponent 65537, or for exponent 3 with the additional option
+`-3`. (That tool doesn't support other exponents.)
+
+### ursa.isKey(obj)
+
+Return `true` if the given object is a key object (public or private) that
+was created by this module. Return `false` if not.
+
+### ursa.isPrivateKey(obj)
+
+Return `true` if the given object is a private key object that
+was created by this module. Return `false` if not.
+
+### ursa.isPublicKey(obj)
+
+Return `true` if the given object is a public key object that
+was created by this module. Return `false` if not.
+
+Note that, even though all the public key operations work on private
+keys, this function only returns true if the given object is a
+public key, per se.
+
+### ursa.matchingPublicKeys(key1, key2)
+
+This returns `true` if and only if both arguments are key objects of
+some sort (either can be public or private, and they don't have to
+be the same) and their public aspects match each other.
+
+### ursa.openSshPublicKey(key, encoding)
+
+This returns `publicKey` from ssh-rsa public key-string. First argument
+must be a string like `ssh-rsa AAAAB3Nz.... user@localhost` or Buffer of pubKey bits.
+
+### ursa.sshFingerprint(sshKey, sshEncoding, outEncoding)
+
+Return the SSH-style public key fingerprint of the given SSH-format
+public key (which was, perhaps, the result of a call to
+`toPublicSsh()` on a key object).
+
+This is no more and no less than an MD5 hash of the given SSH-format
+public key. This function doesn't actually check to see if the given
+key is valid (garbage in, garbage out).
+
+Using the command-line `ssh-keygen` tool, this operation is
+equivalent to:
+
+```shell
+ssh-keygen -l -f key-name.sshpub
+```
+
+This operation is also equivalent to this:
+
+```shell
+cat key-name.sshpub | awk '{print $2}' | base64 --decode | md5
+```
+
+Public Key Methods
+------------------
+
+These are all the methods available on public keys. These methods are
+*also* available on private keys (since private keys have all the
+underlying data necessary to perform the public-side operations).
+
+### encrypt(buf, bufEncoding, outEncoding, padding)
+
+This performs the "public encrypt" operation on the given buffer. The
+result is always a byte sequence that is the same size as the key
+associated with the instance. (For example, if the key is 2048 bits,
+then the result of this operation will be 2048 bits, aka 256 bytes.)
+
+The input buffer is limited to be no larger than the key size
+minus 41 bytes.
+
+If no padding mode is specified, the default, and recommended, mode
+is `ursa.RSA_PKCS1_OAEP_PADDING`. The mode
+`ursa.RSA_PKCS1_PADDING` is also supported.
+
+### getExponent(encoding)
+
+Get the public exponent as an unsigned big-endian byte sequence.
+
+### getModulus(encoding)
+
+Get the public modulus as an unsigned big-endian byte sequence.
+
+### hashAndVerify(algorithm, buf, sig, encoding, use\_pss\_padding, salt\_len)
+
+This is a friendly wrapper for verifying signatures. The given buffer
+is hashed using the named algorithm, and the result is verified
+against the given signature. This returns `true` if the hash and
+signature match and the signature was produced by the appropriate
+private key. This returns `false` if the signature is a valid signature
+(structurally) but doesn't match. This throws an exception in other
+cases.
+
+The encoding, if specified, applies to both buffer-like arguments. The
+algorithm must always be a string.
+
+If `use_pss_padding` is truthy then [RSASSA-PSS](http://tools.ietf.org/html/rfc3447#section-8.1)
+padding is used when verifying the signature. `salt_len`, if specified, is
+the length of the PSS salt (in bytes) or one of the following:
+
+- `RSA_PKCS1_SALT_LEN_HLEN` (the same as the hash length, default).
+- `RSA_PKCS1_SALT_LEN_MAX` (maximum permissable value).
+
+### publicDecrypt(buf, bufEncoding, outEncoding)
+
+This performs the "public decrypt" operation on the given buffer. The
+result is always a byte sequence that is no more than the size of the
+key associated with the instance. (For example, if the key is 2048
+bits, then the result of this operation will be no more than 2048
+bits, aka 256 bytes.)
+
+If no padding mode is specified, the default, and recommended, mode
+is `ursa.RSA_PKCS1_PADDING`. The mode `ursa.RSA_NO_PADDING` is also supported.
+
+### toPublicPem(encoding)
+
+This converts the public key data into a PEM-format file.
+
+### toPublicSsh(encoding)
+
+This converts the public key data into an SSH-format file. This is the
+file format one finds in SSH's `authorized_keys` and `known_hosts` files.
+When used in such files, the contents are base64-encoded and prefixed with
+the label `ssh-rsa`. Depending on context, the line a key appears on may
+also have a host name prefix (in `known_hosts`) or comment suffix
+(in `authorized_keys`).
+
+Using the command-line `ssh-keygen` tool, this operation is equivalent to:
+
+```shell
+ssh-keygen -y -f key-name.pem > key-name.sshpub
+```
+
+### toPublicSshFingerprint(encoding)
+
+Return the SSH-style public key fingerprint of this key. See
+`ursa.sshFingerprint()`, above, for more details.
+
+### verify(algorithm, hash, sig, encoding)
+
+This performs an RSA public-verify on the given hash buffer, which
+should be the result of performing the hash operation named by
+the algorithm (such as `"sha256"` or `"md5"`) on some data. The
+signature buffer is checked to see if it contains a private-signed
+statement of the algorithm and hash. The method returns `true` if
+the signature and hash match, or `false` if the signature and hash
+don't match but the signature is at least a valid signature of
+some sort. In any other situation, this throws an exception.
+
+The encoding, if specified, applies to both buffer-like arguments. The
+algorithm must always be a string.
+
+This method is the underlying one used as part of the implementation
+of the higher-level and much friendlier `ursa.createVerifier()` and
+`hashAndVerify()`.
+
+### ununseal(ununsealer)
+
+This is an internal method that is used in the implementation of
+`ursa.isKey()` `ursa.isPrivateKey()` `ursa.isPublicKey()` and
+associated assertion functions. When called externally, it will
+always return `undefined`.
+
+Private Key Methods
+-------------------
+
+These are the methods available on private keys, above and beyond
+what is available for public keys.
+
+### decrypt(buf, bufEncoding, outEncoding, padding)
+
+This performs the "private decrypt" operation on the given buffer. The
+result is always a byte sequence that is no more than the size of the
+key associated with the instance. (For example, if the key is 2048
+bits, then the result of this operation will be no more than 2048
+bits, aka 256 bytes.)
+
+If no padding mode is specified, the default, and recommended, mode
+is `ursa.RSA_PKCS1_OAEP_PADDING`. The mode
+`ursa.RSA_PKCS1_PADDING` is also supported.
+
+### getPrivateExponent(encoding)
+
+Get the private exponent as an unsigned big-endian byte sequence. The returned
+exponent is not encrypted in any way, so this method should be used with caution.
+
+### hashAndSign(algorithm, buf, bufEncoding, outEncoding, use\_pss\_padding, salt\_len)
+
+This is a friendly wrapper for producing signatures. The given buffer
+is hashed using the named algorithm, and the result is signed using
+the private key held by this instance. The return value of this method
+is the signature.
+
+If `use_pss_padding` is truthy then [RSASSA-PSS](http://tools.ietf.org/html/rfc3447#section-8.1)
+padding is used when generating the signature. The `salt_len`, if specified, is
+the length of the PSS salt (in bytes) or one of the following:
+
+- `RSA_PKCS1_SALT_LEN_HLEN` (the same as the hash length, default).
+- `RSA_PKCS1_SALT_LEN_RECOVER` (assume `RSA_PKCS1_SALT_LEN_MAX` was used when the padding was added).
+
+### privateEncrypt(buf, bufEncoding, outEncoding)
+
+This performs the "private encrypt" operation on the given buffer. The
+result is always a byte sequence that is the same size as the key
+associated with the instance. (For example, if the key is 2048 bits,
+then the result of this operation will be 2048 bits, aka 256 bytes.)
+
+The input buffer is limited to be no larger than the key size
+minus 12 bytes.
+
+If no padding mode is specified, the default, and recommended, mode
+is `ursa.RSA_PKCS1_PADDING`. The mode `ursa.RSA_NO_PADDING` is also supported.
+
+### sign(algorithm, hash, hashEncoding, outEncoding)
+
+This performs an RSA private-sign on the given hash buffer, which
+should be the result of performing the hash operation named by
+the algorithm (such as `"sha256"` or `"md5"`) on some data. The
+result of this operation may later be passed to `verify()` on the
+corresponding public key.
+
+This method is the underlying one used as part of the implementation
+of the higher-level and much friendlier `ursa.createSigner()` and
+`hashAndSign()`.
+
+### toPrivatePem(encoding)
+
+This converts the private key data into a PEM-format file. The result
+is not encrypted, so it behooves the user of this method to take care
+with the result if the key is sensitive from a security standpoint,
+which is often the case with such things. (YMMV of course.)
+
+
+Signer Methods
+--------------
+
+These are the methods available on signer objects, which are returned
+by `ursa.createSigner()`. These are similar to the objects returned
+from `crypto.createSign()`.
+
+### update(buf, bufEncoding)
+
+Update the hash in-progress with the given data.
+
+### sign(privateKey, outEncoding)
+
+Get the final hash of the data, and sign it using the private key. The
+return value is the signature, suitable for later verification.
+
+
+Verifier Methods
+----------------
+
+These are the methods available on verifier objects, which are returned
+by `ursa.createVerifier()`. These are similar to the objects returned
+from `crypto.createVerify()`.
+
+### update(buf, bufEncoding)
+
+Update the hash in-progress with the given data.
+
+### verify(publicKey, sig, sigEncoding)
+
+Get the final hash of the data, and verify that the given signature
+both matches it and was produced by the private key corresponding to
+the given public key.
+
+This returns `true` if the signature and hash match appropriately,
+or `false` if the signature appears to be generally valid (e.g.
+structurally) yet doesn't match. This throws an exception in all
+other cases.
+
+
+Constants
+---------
+
+Allowed padding modes for public/private encryption/decryption:
+
+* `ursa.RSA_PKCS1_PADDING`
+* `ursa.RSA_NO_PADDING`
+* `ursa.RSA_PKCS1_OAEP_PADDING`
+
+
+Contributing
+------------
+
+Questions, comments, bug reports, and pull requests are all welcome.
+Submit them at [the project on GitHub](https://github.com/quartzjer/ursa/).
+
+Bug reports that include steps-to-reproduce (including code) are the
+best. Even better, make them in the form of pull requests that update
+the test suite. Thanks!
+
+
+Authors
+-------
+
+Current (2015+) maintenance by [Jeremie Miller](https://github.com/quartzjer).
+
+Previous (2014) maintenance sponsored by [NodePrime](http://nodeprime.com).
+
+Original Author (2012): [Dan Bornstein](https://github.com/danfuzz)
+([personal website](http://www.milk.com/)), supported by
+[The Obvious Corporation](http://obvious.com/) (now [Medium](https://medium.com/)).
+
+With contribution from:
+
+* [C J Silverio](https://github.com/ceejbot)
+* [Tyler Neylon](https://github.com/tylerneylon)
+
+With thanks to:
+
+* [node-rsa](https://github.com/chrisa/node-rsa) by Chris Andrews,
+ for inspiration
+
+
+License
+-------
+
+Updates Copyright 2014 [NodePrime, Inc.](http://nodeprime.com/).
+Original Copyright 2012 [The Obvious Corporation](http://obvious.com/).
+
+Licensed under the Apache License, Version 2.0.
+See the top-level file `[LICENSE.txt](LICENSE.txt)` and
+(http://www.apache.org/licenses/LICENSE-2.0).
+
+Other Repos that may be of Interest:
+-----------------------
+
+* https://github.com/mal/forsake
+* https://github.com/rzcoder/node-rsa
+* https://github.com/roblabla/ursa-purejs
+* https://github.com/coolaj86/nodejs-self-signed-certificate-example
+* https://github.com/coolaj86/node-ssl-root-cas/wiki/Painless-Self-Signed-Certificates-in-node.js
+* https://github.com/coolaj86/node-ssl-root-cas
+* https://github.com/coolaj86/nodejs-ssl-trusted-peer-example
+* https://github.com/coolaj86/bitcrypt
diff --git a/express-server/node_modules/ursa-optional/binding.gyp b/express-server/node_modules/ursa-optional/binding.gyp
new file mode 100644
index 00000000..292279e1
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/binding.gyp
@@ -0,0 +1,27 @@
+{
+ "targets": [
+ {
+ 'target_name': 'ursaNative',
+ 'sources': [ 'src/ursaNative.cc' ],
+ 'conditions': [
+ [ 'OS=="win"', {
+ 'defines': [
+ 'uint=unsigned int',
+ ],
+ 'include_dirs': [
+ # use node's bundled openssl headers platforms
+ '<(node_root_dir)/deps/openssl/openssl/include',
+ "> $(depfile)
+# Add extra rules as in (2).
+# We remove slashes and replace spaces with new lines;
+# remove blank lines;
+# delete the first line and append a colon to the remaining lines.
+sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
+ grep -v '^$$' |\
+ sed -e 1d -e 's|$$|:|' \
+ >> $(depfile)
+rm $(depfile).raw
+endef
+
+# Command definitions:
+# - cmd_foo is the actual command to run;
+# - quiet_cmd_foo is the brief-output summary of the command.
+
+quiet_cmd_cc = CC($(TOOLSET)) $@
+cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_cxx = CXX($(TOOLSET)) $@
+cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_touch = TOUCH $@
+cmd_touch = touch $@
+
+quiet_cmd_copy = COPY $@
+# send stderr to /dev/null to ignore messages when linking directories.
+cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
+
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
+
+# Due to circular dependencies between libraries :(, we wrap the
+# special "figure out circular dependencies" flags around the entire
+# input list during linking.
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
+
+# We support two kinds of shared objects (.so):
+# 1) shared_library, which is just bundling together many dependent libraries
+# into a link line.
+# 2) loadable_module, which is generating a module intended for dlopen().
+#
+# They differ only slightly:
+# In the former case, we want to package all dependent code into the .so.
+# In the latter case, we want to package just the API exposed by the
+# outermost module.
+# This means shared_library uses --whole-archive, while loadable_module doesn't.
+# (Note that --whole-archive is incompatible with the --start-group used in
+# normal linking.)
+
+# Other shared-object link notes:
+# - Set SONAME to the library filename so our binaries don't reference
+# the local, absolute paths used on the link command-line.
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
+
+
+# Define an escape_quotes function to escape single quotes.
+# This allows us to handle quotes properly as long as we always use
+# use single quotes and escape_quotes.
+escape_quotes = $(subst ','\'',$(1))
+# This comment is here just to include a ' to unconfuse syntax highlighting.
+# Define an escape_vars function to escape '$' variable syntax.
+# This allows us to read/write command lines with shell variables (e.g.
+# $LD_LIBRARY_PATH), without triggering make substitution.
+escape_vars = $(subst $$,$$$$,$(1))
+# Helper that expands to a shell command to echo a string exactly as it is in
+# make. This uses printf instead of echo because printf's behaviour with respect
+# to escape sequences is more portable than echo's across different shells
+# (e.g., dash, bash).
+exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
+
+# Helper to compare the command we're about to run against the command
+# we logged the last time we ran the command. Produces an empty
+# string (false) when the commands match.
+# Tricky point: Make has no string-equality test function.
+# The kernel uses the following, but it seems like it would have false
+# positives, where one string reordered its arguments.
+# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+# $(filter-out $(cmd_$@), $(cmd_$(1))))
+# We instead substitute each for the empty string into the other, and
+# say they're equal if both substitutions produce the empty string.
+# .d files contain ? instead of spaces, take that into account.
+command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
+ $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
+
+# Helper that is non-empty when a prerequisite changes.
+# Normally make does this implicitly, but we force rules to always run
+# so we can check their command lines.
+# $? -- new prerequisites
+# $| -- order-only dependencies
+prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
+
+# Helper that executes all postbuilds until one fails.
+define do_postbuilds
+ @E=0;\
+ for p in $(POSTBUILDS); do\
+ eval $$p;\
+ E=$$?;\
+ if [ $$E -ne 0 ]; then\
+ break;\
+ fi;\
+ done;\
+ if [ $$E -ne 0 ]; then\
+ rm -rf "$@";\
+ exit $$E;\
+ fi
+endef
+
+# do_cmd: run a command via the above cmd_foo names, if necessary.
+# Should always run for a given target to handle command-line changes.
+# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
+# Third argument, if non-zero, makes it do POSTBUILDS processing.
+# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
+# spaces already and dirx strips the ? characters.
+define do_cmd
+$(if $(or $(command_changed),$(prereq_changed)),
+ @$(call exact_echo, $($(quiet)cmd_$(1)))
+ @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
+ $(if $(findstring flock,$(word 1,$(cmd_$1))),
+ @$(cmd_$(1))
+ @echo " $(quiet_cmd_$(1)): Finished",
+ @$(cmd_$(1))
+ )
+ @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
+ @$(if $(2),$(fixup_dep))
+ $(if $(and $(3), $(POSTBUILDS)),
+ $(call do_postbuilds)
+ )
+)
+endef
+
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
+.PHONY: all
+all:
+
+# make looks for ways to re-generate included makefiles, but in our case, we
+# don't have a direct way. Explicitly telling make that it has nothing to do
+# for them makes it go faster.
+%.d: ;
+
+# Use FORCE_DO_CMD to force a target to run. Should be coupled with
+# do_cmd.
+.PHONY: FORCE_DO_CMD
+FORCE_DO_CMD:
+
+TOOLSET := target
+# Suffix rules, putting all outputs into $(obj).
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# Try building from generated source, too.
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+
+ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
+ $(findstring $(join ^,$(prefix)),\
+ $(join ^,ursaNative.target.mk)))),)
+ include ursaNative.target.mk
+endif
+
+quiet_cmd_regen_makefile = ACTION Regenerating $@
+cmd_regen_makefile = cd $(srcdir); /usr/share/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/nodeapps/https-test/greenlock-express.js/node_modules/ursa-optional/build/config.gypi -I/usr/share/node-gyp/addon.gypi -I/usr/include/nodejs/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/usr/include/nodejs" "-Dnode_gyp_dir=/usr/share/node-gyp" "-Dnode_lib_file=/usr/include/nodejs/<(target_arch)/node.lib" "-Dmodule_root_dir=/nodeapps/https-test/greenlock-express.js/node_modules/ursa-optional" "-Dnode_engine=v8" binding.gyp
+Makefile: $(srcdir)/../../../../../usr/include/nodejs/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../usr/share/node-gyp/addon.gypi
+ $(call do_cmd,regen_makefile)
+
+# "all" is a concatenation of the "all" targets from all the included
+# sub-makefiles. This is just here to clarify.
+all:
+
+# Add in dependency-tracking rules. $(all_deps) is the list of every single
+# target in our tree. Only consider the ones with .d (dependency) info:
+d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
+ifneq ($(d_files),)
+ include $(d_files)
+endif
diff --git a/express-server/node_modules/ursa-optional/build/Release/.deps/Release/obj.target/ursaNative.node.d b/express-server/node_modules/ursa-optional/build/Release/.deps/Release/obj.target/ursaNative.node.d
new file mode 100644
index 00000000..fdc401c8
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/build/Release/.deps/Release/obj.target/ursaNative.node.d
@@ -0,0 +1 @@
+cmd_Release/obj.target/ursaNative.node := g++ -shared -pthread -rdynamic -m64 -Wl,-soname=ursaNative.node -o Release/obj.target/ursaNative.node -Wl,--start-group Release/obj.target/ursaNative/src/ursaNative.o -Wl,--end-group
diff --git a/express-server/node_modules/ursa-optional/build/Release/.deps/Release/obj.target/ursaNative/src/ursaNative.o.d b/express-server/node_modules/ursa-optional/build/Release/.deps/Release/obj.target/ursaNative/src/ursaNative.o.d
new file mode 100644
index 00000000..d80fdcca
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/build/Release/.deps/Release/obj.target/ursaNative/src/ursaNative.o.d
@@ -0,0 +1,53 @@
+cmd_Release/obj.target/ursaNative/src/ursaNative.o := g++ '-DNODE_GYP_MODULE_NAME=ursaNative' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I/usr/include/nodejs/deps/openssl/openssl/include -I../../nan -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -m64 -O3 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/ursaNative/src/ursaNative.o.d.raw -c -o Release/obj.target/ursaNative/src/ursaNative.o ../src/ursaNative.cc
+Release/obj.target/ursaNative/src/ursaNative.o: ../src/ursaNative.cc \
+ ../src/ursaNative.h /usr/include/nodejs/src/node.h \
+ /usr/include/nodejs/deps/v8/include/v8.h \
+ /usr/include/nodejs/deps/v8/include/v8-version.h \
+ /usr/include/nodejs/deps/v8/include/v8config.h \
+ /usr/include/nodejs/src/node_version.h ../../nan/nan.h \
+ /usr/include/nodejs/src/node_version.h \
+ /usr/include/nodejs/deps/uv/include/uv.h \
+ /usr/include/nodejs/deps/uv/include/uv-errno.h \
+ /usr/include/nodejs/deps/uv/include/uv-version.h \
+ /usr/include/nodejs/deps/uv/include/uv-unix.h \
+ /usr/include/nodejs/deps/uv/include/uv-threadpool.h \
+ /usr/include/nodejs/deps/uv/include/uv-linux.h \
+ /usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
+ /usr/include/nodejs/src/node_object_wrap.h ../../nan/nan_callbacks.h \
+ ../../nan/nan_callbacks_12_inl.h ../../nan/nan_maybe_43_inl.h \
+ ../../nan/nan_converters.h ../../nan/nan_converters_43_inl.h \
+ ../../nan/nan_new.h ../../nan/nan_implementation_12_inl.h \
+ ../../nan/nan_persistent_12_inl.h ../../nan/nan_weak.h \
+ ../../nan/nan_object_wrap.h ../../nan/nan_private.h \
+ ../../nan/nan_typedarray_contents.h ../../nan/nan_json.h
+../src/ursaNative.cc:
+../src/ursaNative.h:
+/usr/include/nodejs/src/node.h:
+/usr/include/nodejs/deps/v8/include/v8.h:
+/usr/include/nodejs/deps/v8/include/v8-version.h:
+/usr/include/nodejs/deps/v8/include/v8config.h:
+/usr/include/nodejs/src/node_version.h:
+../../nan/nan.h:
+/usr/include/nodejs/src/node_version.h:
+/usr/include/nodejs/deps/uv/include/uv.h:
+/usr/include/nodejs/deps/uv/include/uv-errno.h:
+/usr/include/nodejs/deps/uv/include/uv-version.h:
+/usr/include/nodejs/deps/uv/include/uv-unix.h:
+/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
+/usr/include/nodejs/deps/uv/include/uv-linux.h:
+/usr/include/nodejs/src/node_buffer.h:
+/usr/include/nodejs/src/node.h:
+/usr/include/nodejs/src/node_object_wrap.h:
+../../nan/nan_callbacks.h:
+../../nan/nan_callbacks_12_inl.h:
+../../nan/nan_maybe_43_inl.h:
+../../nan/nan_converters.h:
+../../nan/nan_converters_43_inl.h:
+../../nan/nan_new.h:
+../../nan/nan_implementation_12_inl.h:
+../../nan/nan_persistent_12_inl.h:
+../../nan/nan_weak.h:
+../../nan/nan_object_wrap.h:
+../../nan/nan_private.h:
+../../nan/nan_typedarray_contents.h:
+../../nan/nan_json.h:
diff --git a/express-server/node_modules/ursa-optional/build/Release/.deps/Release/ursaNative.node.d b/express-server/node_modules/ursa-optional/build/Release/.deps/Release/ursaNative.node.d
new file mode 100644
index 00000000..e567f0ef
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/build/Release/.deps/Release/ursaNative.node.d
@@ -0,0 +1 @@
+cmd_Release/ursaNative.node := ln -f "Release/obj.target/ursaNative.node" "Release/ursaNative.node" 2>/dev/null || (rm -rf "Release/ursaNative.node" && cp -af "Release/obj.target/ursaNative.node" "Release/ursaNative.node")
diff --git a/express-server/node_modules/ursa-optional/build/Release/obj.target/ursaNative.node b/express-server/node_modules/ursa-optional/build/Release/obj.target/ursaNative.node
new file mode 100644
index 00000000..0e9e18ae
Binary files /dev/null and b/express-server/node_modules/ursa-optional/build/Release/obj.target/ursaNative.node differ
diff --git a/express-server/node_modules/ursa-optional/build/Release/obj.target/ursaNative/src/ursaNative.o b/express-server/node_modules/ursa-optional/build/Release/obj.target/ursaNative/src/ursaNative.o
new file mode 100644
index 00000000..236e6b9d
Binary files /dev/null and b/express-server/node_modules/ursa-optional/build/Release/obj.target/ursaNative/src/ursaNative.o differ
diff --git a/express-server/node_modules/ursa-optional/build/Release/ursaNative.node b/express-server/node_modules/ursa-optional/build/Release/ursaNative.node
new file mode 100644
index 00000000..0e9e18ae
Binary files /dev/null and b/express-server/node_modules/ursa-optional/build/Release/ursaNative.node differ
diff --git a/express-server/node_modules/ursa-optional/build/binding.Makefile b/express-server/node_modules/ursa-optional/build/binding.Makefile
new file mode 100644
index 00000000..b11894c5
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/build/binding.Makefile
@@ -0,0 +1,6 @@
+# This file is generated by gyp; do not edit.
+
+export builddir_name ?= ./build/.
+.PHONY: all
+all:
+ $(MAKE) ursaNative
diff --git a/express-server/node_modules/ursa-optional/build/config.gypi b/express-server/node_modules/ursa-optional/build/config.gypi
new file mode 100644
index 00000000..f476d1cf
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/build/config.gypi
@@ -0,0 +1,153 @@
+# Do not edit. File was generated by node-gyp's "configure" step
+{
+ "target_defaults": {
+ "cflags": [],
+ "default_configuration": "Release",
+ "defines": [],
+ "include_dirs": [],
+ "libraries": []
+ },
+ "variables": {
+ "asan": 0,
+ "coverage": "false",
+ "debug_devtools": "node",
+ "debug_http2": "false",
+ "debug_nghttp2": "false",
+ "force_dynamic_crt": 0,
+ "host_arch": "x64",
+ "icu_gyp_path": "tools/icu/icu-system.gyp",
+ "icu_small": "false",
+ "llvm_version": 0,
+ "node_byteorder": "little",
+ "node_enable_d8": "false",
+ "node_enable_v8_vtunejit": "false",
+ "node_install_npm": "false",
+ "node_module_version": 57,
+ "node_no_browser_globals": "false",
+ "node_prefix": "/usr",
+ "node_release_urlbase": "",
+ "node_shared": "false",
+ "node_shared_cares": "true",
+ "node_shared_http_parser": "true",
+ "node_shared_libuv": "true",
+ "node_shared_nghttp2": "true",
+ "node_shared_openssl": "true",
+ "node_shared_zlib": "true",
+ "node_tag": "",
+ "node_use_bundled_v8": "true",
+ "node_use_dtrace": "false",
+ "node_use_etw": "false",
+ "node_use_lttng": "false",
+ "node_use_openssl": "true",
+ "node_use_perfctr": "false",
+ "node_use_v8_platform": "true",
+ "node_without_node_options": "false",
+ "openssl_fips": "",
+ "openssl_no_asm": 0,
+ "shlib_suffix": "so.57",
+ "target_arch": "x64",
+ "uv_parent_path": "/deps/uv/",
+ "uv_use_dtrace": "false",
+ "v8_enable_gdbjit": 0,
+ "v8_enable_i18n_support": 1,
+ "v8_enable_inspector": 1,
+ "v8_no_strict_aliasing": 1,
+ "v8_optimized_debug": 0,
+ "v8_promise_internal_field_count": 1,
+ "v8_random_seed": 0,
+ "v8_trace_maps": 0,
+ "v8_use_snapshot": "false",
+ "want_separate_host_toolset": 0,
+ "nodedir": "/usr/include/nodejs",
+ "standalone_static_library": 1,
+ "cache_lock_stale": "60000",
+ "legacy_bundling": "",
+ "sign_git_tag": "",
+ "user_agent": "npm/3.5.2 node/v8.10.0 linux x64",
+ "always_auth": "",
+ "bin_links": "true",
+ "key": "",
+ "description": "true",
+ "fetch_retries": "2",
+ "heading": "npm",
+ "init_version": "1.0.0",
+ "if_present": "",
+ "user": "",
+ "force": "",
+ "only": "",
+ "cache_min": "10",
+ "init_license": "ISC",
+ "editor": "vi",
+ "rollback": "true",
+ "tag_version_prefix": "v",
+ "cache_max": "Infinity",
+ "userconfig": "/root/.npmrc",
+ "tmp": "/tmp",
+ "engine_strict": "",
+ "init_author_name": "",
+ "init_author_url": "",
+ "depth": "Infinity",
+ "save_dev": "",
+ "usage": "",
+ "progress": "true",
+ "https_proxy": "",
+ "onload_script": "",
+ "rebuild_bundle": "true",
+ "shell": "/bin/bash",
+ "save_bundle": "",
+ "prefix": "/usr/local",
+ "dry_run": "",
+ "cache_lock_wait": "10000",
+ "registry": "https://registry.npmjs.org/",
+ "browser": "",
+ "save_optional": "",
+ "scope": "",
+ "searchopts": "",
+ "versions": "",
+ "cache": "/root/.npm",
+ "searchsort": "name",
+ "global_style": "",
+ "ignore_scripts": "",
+ "version": "",
+ "viewer": "man",
+ "local_address": "",
+ "color": "true",
+ "fetch_retry_mintimeout": "10000",
+ "umask": "0022",
+ "fetch_retry_maxtimeout": "60000",
+ "message": "%s",
+ "ca": "",
+ "cert": "",
+ "global": "",
+ "link": "",
+ "unicode": "true",
+ "access": "",
+ "also": "",
+ "save": "",
+ "long": "",
+ "production": "",
+ "unsafe_perm": "",
+ "node_version": "8.10.0",
+ "tag": "latest",
+ "git_tag_version": "true",
+ "shrinkwrap": "true",
+ "fetch_retry_factor": "10",
+ "proprietary_attribs": "true",
+ "strict_ssl": "true",
+ "npat": "",
+ "save_exact": "",
+ "globalconfig": "/etc/npmrc",
+ "init_module": "/root/.npm-init.js",
+ "dev": "",
+ "parseable": "",
+ "globalignorefile": "/etc/npmignore",
+ "cache_lock_retries": "10",
+ "save_prefix": "^",
+ "group": "",
+ "init_author_email": "",
+ "searchexclude": "",
+ "git": "git",
+ "optional": "true",
+ "json": ""
+ }
+}
diff --git a/express-server/node_modules/ursa-optional/build/ursaNative.target.mk b/express-server/node_modules/ursa-optional/build/ursaNative.target.mk
new file mode 100644
index 00000000..d60b668e
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/build/ursaNative.target.mk
@@ -0,0 +1,145 @@
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := ursaNative
+DEFS_Debug := \
+ '-DNODE_GYP_MODULE_NAME=ursaNative' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DV8_ENABLE_CHECKS'
+
+# Flags passed to all source files.
+CFLAGS_Debug := \
+ -fPIC \
+ -pthread \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -m64 \
+ -g \
+ -O0
+
+# Flags passed to only C files.
+CFLAGS_C_Debug :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := \
+ -fno-rtti \
+ -fno-exceptions \
+ -std=gnu++0x
+
+INCS_Debug := \
+ -I/usr/include/nodejs/include/node \
+ -I/usr/include/nodejs/src \
+ -I/usr/include/nodejs/deps/uv/include \
+ -I/usr/include/nodejs/deps/v8/include \
+ -I/usr/include/nodejs/deps/openssl/openssl/include \
+ -I$(srcdir)/../nan
+
+DEFS_Release := \
+ '-DNODE_GYP_MODULE_NAME=ursaNative' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION'
+
+# Flags passed to all source files.
+CFLAGS_Release := \
+ -fPIC \
+ -pthread \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -m64 \
+ -O3 \
+ -fno-omit-frame-pointer
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := \
+ -fno-rtti \
+ -fno-exceptions \
+ -std=gnu++0x
+
+INCS_Release := \
+ -I/usr/include/nodejs/include/node \
+ -I/usr/include/nodejs/src \
+ -I/usr/include/nodejs/deps/uv/include \
+ -I/usr/include/nodejs/deps/v8/include \
+ -I/usr/include/nodejs/deps/openssl/openssl/include \
+ -I$(srcdir)/../nan
+
+OBJS := \
+ $(obj).target/$(TARGET)/src/ursaNative.o
+
+# Add to the list of files we specially track dependencies for.
+all_deps += $(OBJS)
+
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.
+$(OBJS): TOOLSET := $(TOOLSET)
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+
+# Suffix rules, putting all outputs into $(obj).
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# Try building from generated source, too.
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# End of this set of suffix rules
+### Rules for final target.
+LDFLAGS_Debug := \
+ -pthread \
+ -rdynamic \
+ -m64
+
+LDFLAGS_Release := \
+ -pthread \
+ -rdynamic \
+ -m64
+
+LIBS :=
+
+$(obj).target/ursaNative.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
+$(obj).target/ursaNative.node: LIBS := $(LIBS)
+$(obj).target/ursaNative.node: TOOLSET := $(TOOLSET)
+$(obj).target/ursaNative.node: $(OBJS) FORCE_DO_CMD
+ $(call do_cmd,solink_module)
+
+all_deps += $(obj).target/ursaNative.node
+# Add target alias
+.PHONY: ursaNative
+ursaNative: $(builddir)/ursaNative.node
+
+# Copy this to the executable output path.
+$(builddir)/ursaNative.node: TOOLSET := $(TOOLSET)
+$(builddir)/ursaNative.node: $(obj).target/ursaNative.node FORCE_DO_CMD
+ $(call do_cmd,copy)
+
+all_deps += $(builddir)/ursaNative.node
+# Short alias for building this executable.
+.PHONY: ursaNative.node
+ursaNative.node: $(obj).target/ursaNative.node $(builddir)/ursaNative.node
+
+# Add executable to "all" target.
+.PHONY: all
+all: $(builddir)/ursaNative.node
+
diff --git a/express-server/node_modules/ursa-optional/lib/ursa.js b/express-server/node_modules/ursa-optional/lib/ursa.js
new file mode 100644
index 00000000..54a116b3
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/lib/ursa.js
@@ -0,0 +1,752 @@
+// Copyright 2012 The Obvious Corporation.
+
+/*
+ * "ursa": RSA crypto, with an emphasis on Buffer objects
+ */
+
+/*
+ * Modules used
+ */
+
+"use strict";
+
+// Note: This also forces OpenSSL to be initialized, which is important!
+var crypto = require("crypto");
+
+var assert = require("assert");
+
+var ursaNative = require("bindings")("ursaNative");
+var RsaWrap = ursaNative.RsaWrap;
+var textToNid = ursaNative.textToNid;
+
+
+/*
+ * Variable definitions
+ */
+
+/** encoding constant */
+var BASE64 = "base64";
+
+/** encoding constant */
+var BINARY = "binary";
+
+/** encoding constant */
+var HEX = "hex";
+
+/** type name */
+var STRING = "string";
+
+/** encoding constant */
+var UTF8 = "utf8";
+
+/** encoding constant */
+var UTF16 = "utf16le";
+
+/** hash algorithm constant */
+var MD5 = "md5";
+
+/** regex that matches PEM files, capturing the file type */
+var PEM_REGEX =
+ /^(-----BEGIN (.*) KEY-----\r?\n[:\s,-\/+=a-zA-Z0-9\r\n]*\r?\n-----END \2 KEY-----\r?\n)/m;
+
+/** "unsealer" key object to authenticate objects */
+var theUnsealer = [ "ursa unsealer" ];
+
+
+/*
+ * Helper functions
+ */
+
+/**
+ * Return true iff x is either a string or a Buffer.
+ */
+function isStringOrBuffer(x) {
+ return (typeof x === STRING) || Buffer.isBuffer(x);
+}
+
+/**
+ * Extract and identify the PEM file type represented in the given
+ * buffer. Returns the extracted type string or undefined if the
+ * buffer doesn't seem to be any sort of PEM format file.
+ */
+function identifyPemType(buf) {
+ var str = encodeBuffer(buf, UTF8);
+ var match = PEM_REGEX.exec(str);
+
+ if (!match) {
+ return undefined;
+ }
+
+ return match[2];
+}
+
+/**
+ * Return whether the given buffer or string appears (trivially) to be a
+ * valid public key file in PEM format.
+ */
+function isPublicKeyPem(buf) {
+ var kind = identifyPemType(buf);
+ return (kind == "PUBLIC");
+}
+
+/**
+ * Return whether the given buffer or string appears (trivially) to be a
+ * valid private key file in PEM format.
+ */
+function isPrivateKeyPem(buf) {
+ var kind = identifyPemType(buf);
+ return (kind == "RSA PRIVATE");
+}
+
+/**
+ * Return a buffer containing the encoding of the given bigint for use
+ * as part of an SSH-style public key file. The input value must be a
+ * buffer representing an unsigned bigint in big-endian order.
+ */
+function toSshBigint(value) {
+ // The output is signed, so we need to add an extra 00 byte at the
+ // head if the high-order bit is set.
+ var prefix00 = ((value[0] & 0x80) !== 0);
+ var length = value.length + (prefix00 ? 1 : 0);
+ var result = new Buffer(length + 4);
+ var offset = 0;
+
+ result.writeUInt32BE(length, offset);
+ offset += 4;
+
+ if (prefix00) {
+ result[offset] = 0;
+ offset++;
+ }
+
+ value.copy(result, offset);
+ return result;
+}
+
+/**
+ * Create and return a buffer containing an SSH-style public key file for
+ * the given RsaWrap object.
+ *
+ * For the record, an SSH-style public key file consists of three
+ * concatenated values, each one length-prefixed:
+ *
+ * literal string "ssh-rsa"
+ * exponent
+ * modulus
+ *
+ * The literal string header is length-prefixed. The two numbers are
+ * represented as signed big-int values in big-endian order, also
+ * length-prefixed.
+ */
+function createSshPublicKey(rsa) {
+ var e = toSshBigint(rsa.getExponent());
+ var m = toSshBigint(rsa.getModulus());
+
+ var header = toSshBigint(new Buffer("ssh-rsa", UTF8));
+ var result = new Buffer(header.length + m.length + e.length);
+ var offset = 0;
+
+ header.copy(result, offset);
+ offset += header.length;
+ e.copy(result, offset);
+ offset += e.length;
+ m.copy(result, offset);
+
+ return result;
+}
+
+/**
+ * Validate the given encoding name. Throws an exception if invalid.
+ */
+function validateEncoding(encoding) {
+ switch (encoding) {
+ case BASE64:
+ case BINARY:
+ case HEX:
+ case UTF16:
+ case UTF8: {
+ // These are all valid.
+ break;
+ }
+ default: {
+ throw new Error("Invalid encoding: " + encoding);
+ }
+ }
+}
+
+/**
+ * Convert a buffer into an appropriately-encoded string, or return it
+ * unmodified if the encoding is undefined.
+ */
+function encodeBuffer(buf, encoding) {
+ if (encoding === undefined) {
+ return buf;
+ }
+
+ validateEncoding(encoding);
+ return buf.toString(encoding);
+}
+
+/**
+ * Return a buffer or undefined argument as-is, or convert a given
+ * string into a buffer by using the indicated encoding. An undefined
+ * encoding is interpreted to mean UTF8.
+ */
+function decodeString(str, encoding) {
+ if ((str === undefined) || Buffer.isBuffer(str)) {
+ return str;
+ }
+
+ if (encoding === undefined) {
+ encoding = UTF8;
+ }
+
+ validateEncoding(encoding);
+ return new Buffer(str, encoding);
+}
+/**
+ * OpenSSH Public key to RSA
+ * @param {String|Object} key OpenSSH Public Key
+ * @param key encoding, default 'base64'
+ * @returns {PublicKey}
+ */
+function openSshPublicKey(key, encoding) {
+ if (!Buffer.isBuffer(key)) {
+ key = key.substr(0, 3) === 'ssh' ? key.split(' ')[1] : key;
+ key = new Buffer(key, encoding || 'base64');
+ }
+
+ function parsePublicKey(key) {
+ var parts = [],
+ partsLength = 3;
+
+ while(key.length) {
+ var dLen = key.readInt32BE(0);
+ var data = key.slice(4, dLen+4);
+ key = key.slice(4+dLen);
+ parts.push(data);
+ if (!(--partsLength)) break;
+ }
+
+ return {
+ modulus : parts[2],
+ exponent: parts[1],
+ type : parts[0]
+ };
+ }
+
+ var pubKey = parsePublicKey(key);
+ var rsa = new RsaWrap();
+
+ if (pubKey.type != 'ssh-rsa') {
+ throw new TypeError('Only "ssh-rsa" format supported');
+ }
+
+ rsa.openPublicSshKey(pubKey.modulus, pubKey.exponent);
+
+ return PublicKey(rsa);
+}
+
+/**
+ * Public Key object. This is the externally-visible object that one gets
+ * when constructing an instance from a public key. The constructor takes
+ * a native RsaWrap object.
+ */
+function PublicKey(rsa) {
+ var self;
+
+ function getExponent(encoding) {
+ return encodeBuffer(rsa.getExponent(), encoding);
+ }
+
+ function getModulus(encoding) {
+ return encodeBuffer(rsa.getModulus(), encoding);
+ }
+
+ function toPublicPem(encoding) {
+ return encodeBuffer(rsa.getPublicKeyPem(), encoding);
+ }
+
+ function toPublicSsh(encoding) {
+ return encodeBuffer(createSshPublicKey(rsa), encoding);
+ }
+
+ function toPublicSshFingerprint(encoding) {
+ return sshFingerprint(createSshPublicKey(rsa), undefined, encoding);
+ }
+
+ function encrypt(buf, bufEncoding, outEncoding, padding) {
+ buf = decodeString(buf, bufEncoding);
+ padding = (padding === undefined) ?
+ ursaNative.RSA_PKCS1_OAEP_PADDING : padding;
+ return encodeBuffer(rsa.publicEncrypt(buf, padding), outEncoding);
+ }
+
+ function publicDecrypt(buf, bufEncoding, outEncoding, padding) {
+ buf = decodeString(buf, bufEncoding);
+ padding = (padding === undefined) ?
+ ursaNative.RSA_PKCS1_PADDING : padding;
+ return encodeBuffer(rsa.publicDecrypt(buf, padding), outEncoding);
+ }
+
+ function verify(algorithm, hash, sig, encoding) {
+ algorithm = textToNid(algorithm);
+ hash = decodeString(hash, encoding);
+ sig = decodeString(sig, encoding);
+ return rsa.verify(algorithm, hash, sig);
+ }
+
+ function hashAndVerify(algorithm, buf, sig, encoding,
+ use_pss_padding, salt_len) {
+ if (use_pss_padding) {
+ sig = publicDecrypt(sig, encoding, undefined,
+ ursaNative.RSA_NO_PADDING);
+
+ var hash = crypto.createHash(algorithm);
+ hash.update(decodeString(buf, encoding));
+ buf = new Buffer(hash.digest(BINARY), BINARY);
+
+ return rsa.verifyPSSPadding(textToNid(algorithm), buf, sig,
+ (salt_len === undefined) ? ursaNative.RSA_PKCS1_SALT_LEN_HLEN : salt_len);
+ } else {
+ var verifier = createVerifier(algorithm);
+ verifier.update(buf, encoding);
+ return verifier.verify(self, sig, encoding);
+ }
+ }
+
+ function unseal(unsealer) {
+ return (unsealer === theUnsealer) ? self : undefined;
+ }
+
+ self = {
+ encrypt: encrypt,
+ getExponent: getExponent,
+ getModulus: getModulus,
+ hashAndVerify: hashAndVerify,
+ publicDecrypt: publicDecrypt,
+ toPublicPem: toPublicPem,
+ toPublicSsh: toPublicSsh,
+ toPublicSshFingerprint: toPublicSshFingerprint,
+ verify: verify,
+ unseal: unseal
+ };
+
+ return self;
+}
+
+/**
+ * Private Key object. This is the externally-visible object that one
+ * gets when constructing an instance from a private key (aka a
+ * keypair). The constructor takes a native RsaWrap object.
+ */
+function PrivateKey(rsa) {
+ var self;
+
+ function getPrivateExponent(encoding) {
+ return encodeBuffer(rsa.getPrivateExponent(), encoding);
+ }
+
+ function toPrivatePem(encoding) {
+ return encodeBuffer(rsa.getPrivateKeyPem(), encoding);
+ }
+
+ function toEncryptedPrivatePem(passPhrase, cipher, encoding) {
+ if(!passPhrase) return toPrivatePem(encoding);
+ return encodeBuffer(rsa.getPrivateKeyPem(passPhrase, cipher));
+ }
+
+ function decrypt(buf, bufEncoding, outEncoding, padding) {
+ buf = decodeString(buf, bufEncoding);
+ padding = (padding === undefined) ? ursaNative.RSA_PKCS1_OAEP_PADDING : padding;
+ return encodeBuffer(rsa.privateDecrypt(buf, padding), outEncoding);
+ }
+
+ function privateEncrypt(buf, bufEncoding, outEncoding, padding) {
+ buf = decodeString(buf, bufEncoding);
+ padding = (padding === undefined) ? ursaNative.RSA_PKCS1_PADDING : padding;
+ return encodeBuffer(rsa.privateEncrypt(buf, padding), outEncoding);
+ }
+
+ function sign(algorithm, hash, hashEncoding, outEncoding) {
+ algorithm = textToNid(algorithm);
+ hash = decodeString(hash, hashEncoding);
+ return encodeBuffer(rsa.sign(algorithm, hash), outEncoding);
+ }
+
+ function hashAndSign(algorithm, buf, bufEncoding, outEncoding,
+ use_pss_padding, salt_len) {
+ if (use_pss_padding) {
+ var hash = crypto.createHash(algorithm);
+ hash.update(decodeString(buf, bufEncoding));
+ buf = new Buffer(hash.digest(BINARY), BINARY);
+
+ buf = rsa.addPSSPadding(textToNid(algorithm), buf,
+ (salt_len === undefined) ? ursaNative.RSA_PKCS1_SALT_LEN_HLEN : salt_len);
+
+ return privateEncrypt(buf, undefined, outEncoding,
+ ursaNative.RSA_NO_PADDING);
+ } else {
+ var signer = createSigner(algorithm);
+ signer.update(buf, bufEncoding);
+ return signer.sign(self, outEncoding);
+ }
+ }
+
+ self = PublicKey(rsa);
+ self.decrypt = decrypt;
+ self.getPrivateExponent = getPrivateExponent;
+ self.hashAndSign = hashAndSign;
+ self.privateEncrypt = privateEncrypt;
+ self.sign = sign;
+ self.toPrivatePem = toPrivatePem;
+ self.toEncryptedPrivatePem = toEncryptedPrivatePem;
+ return self;
+}
+
+
+/*
+ * Exported bindings
+ */
+
+/**
+ * Create a new public key object, from the given PEM-encoded file.
+ */
+function createPublicKey(pem, encoding) {
+ var rsa = new RsaWrap();
+ pem = decodeString(pem, encoding);
+
+ try {
+ rsa.setPublicKeyPem(pem);
+ } catch (ex) {
+ if (!isPublicKeyPem(pem)) {
+ throw new Error("Not a public key.");
+ }
+ throw ex;
+ }
+
+ return PublicKey(rsa);
+}
+
+/**
+ * Create a new private key object, from the given PEM-encoded file,
+ * optionally decrypting the file with a password.
+ */
+function createPrivateKey(pem, password, encoding) {
+ var rsa = new RsaWrap();
+ pem = decodeString(pem, encoding);
+ password = decodeString(password, encoding);
+
+ try {
+ // Note: The native code is sensitive to the actual number of
+ // arguments. It's *not* okay to pass undefined as a password.
+ if (password) {
+ rsa.setPrivateKeyPem(pem, password);
+ } else {
+ rsa.setPrivateKeyPem(pem);
+ }
+ } catch (ex) {
+ if (!isPrivateKeyPem(pem)) {
+ throw new Error("Not a private key.");
+ }
+ throw ex;
+ }
+
+ return PrivateKey(rsa);
+}
+
+/**
+ * Create public key from components
+ */
+function createPublicKeyFromComponents(modulus, exponent) {
+ var rsa = new RsaWrap();
+ rsa.createPublicKeyFromComponents(modulus, exponent);
+ return PublicKey(rsa);
+}
+
+/**
+ * Create private key from components
+ */
+function createPrivateKeyFromComponents(modulus, exponent, p, q, dp, dq, inverseQ, d) {
+ var rsa = new RsaWrap();
+ rsa.createPrivateKeyFromComponents(modulus, exponent, p, q, dp, dq, inverseQ, d);
+
+ return PrivateKey(rsa);
+}
+
+/**
+ * Generate a new private key object (aka a keypair).
+ */
+function generatePrivateKey(modulusBits, exponent) {
+ if (modulusBits === undefined) {
+ modulusBits = 2048;
+ }
+
+ if (exponent === undefined) {
+ exponent = 65537;
+ }
+
+ var rsa = new RsaWrap();
+ rsa.generatePrivateKey(modulusBits, exponent);
+
+ return PrivateKey(rsa);
+}
+
+/**
+ * Create a key object from a PEM format file, either a private or
+ * public key depending on what kind of file is passed in. If given
+ * a private key file, it must not be encrypted.
+ */
+function createKey(pem, encoding) {
+ pem = decodeString(pem, encoding);
+
+ if (isPublicKeyPem(pem)) {
+ return createPublicKey(pem);
+ } else if (isPrivateKeyPem(pem)) {
+ return createPrivateKey(pem);
+ } else {
+ throw new Error("Not a key.");
+ }
+}
+
+/**
+ * Return the SSH-style public key fingerprint of the given SSH-format
+ * public key.
+ */
+function sshFingerprint(sshKey, sshEncoding, outEncoding) {
+ var hash = crypto.createHash(MD5);
+
+ hash.update(decodeString(sshKey, sshEncoding));
+ var result = new Buffer(hash.digest(BINARY), BINARY);
+ return encodeBuffer(result, outEncoding);
+}
+
+/**
+ * Return whether the given object is a key object (either public or
+ * private), as constructed by this module.
+ */
+function isKey(obj) {
+ var obj2;
+
+ try {
+ var unseal = obj.unseal;
+ if (typeof unseal !== "function") {
+ return false;
+ }
+ obj2 = unseal(theUnsealer);
+ } catch (ex) {
+ // Ignore; can't assume that other objects obey any particular
+ // unsealing protocol.
+ // TODO: Log?
+ return false;
+ }
+
+ return obj2 !== undefined;
+}
+
+/**
+ * Return whether the given object is a private key object, as
+ * constructed by this module.
+ */
+function isPrivateKey(obj) {
+ return isKey(obj) && (obj.decrypt !== undefined);
+}
+
+/**
+ * Return whether the given object is a public key object (per se), as
+ * constructed by this module.
+ */
+function isPublicKey(obj) {
+ return isKey(obj) && !isPrivateKey(obj);
+}
+
+/**
+ * Assert wrapper for isKey().
+ */
+function assertKey(obj) {
+ assert(isKey(obj));
+}
+
+/**
+ * Assert wrapper for isPrivateKey().
+ */
+function assertPrivateKey(obj) {
+ assert(isPrivateKey(obj));
+}
+
+/**
+ * Assert wrapper for isPublicKey().
+ */
+function assertPublicKey(obj) {
+ assert(isPublicKey(obj));
+}
+
+/**
+ * Coerce the given key value into an private key object, returning
+ * it. If given a private key object, this just returns it as-is. If
+ * given a string or Buffer, it tries to parse it as PEM. Anything
+ * else is an error.
+ */
+function coercePrivateKey(orig) {
+ if (isPrivateKey(orig)) {
+ return orig;
+ } else if (isStringOrBuffer(orig)) {
+ return createPrivateKey(orig);
+ }
+
+ throw new Error("Not a private key: " + orig);
+}
+
+/**
+ * Coerce the given key value into a public key object, returning
+ * it. If given a private key object, this just returns it as-is. If
+ * given a string or Buffer, it tries to parse it as PEM. Anything
+ * else is an error.
+ */
+function coercePublicKey(orig) {
+ if (isPublicKey(orig)) {
+ return orig;
+ } else if (isStringOrBuffer(orig)) {
+ return createPublicKey(orig);
+ }
+
+ throw new Error("Not a public key: " + orig);
+}
+
+/**
+ * Coerce the given key value into a key object (either public or
+ * private), returning it. If given a private key object, this just
+ * returns it as-is. If given a string or Buffer, it tries to parse it
+ * as PEM. Anything else is an error.
+ */
+function coerceKey(orig) {
+ if (isKey(orig)) {
+ return orig;
+ } else if (isStringOrBuffer(orig)) {
+ return createKey(orig);
+ }
+
+ throw new Error("Not a key: " + orig);
+}
+
+/**
+ * Check whether the two objects are both keys of some sort and
+ * have the same public part.
+ */
+function matchingPublicKeys(key1, key2) {
+ if (!(isKey(key1) && isKey(key2))) {
+ return false;
+ }
+
+ // This isn't the most efficient implementation, but it will suffice:
+ // We convert both to ssh form, which has very little leeway for
+ // variation, and compare bytes.
+
+ var ssh1 = key1.toPublicSsh(UTF8);
+ var ssh2 = key2.toPublicSsh(UTF8);
+
+ return ssh1 === ssh2;
+}
+
+/**
+ * Check whether the two objects are both keys of some sort, are
+ * both public or both private, and have the same contents.
+ */
+function equalKeys(key1, key2) {
+ // See above for rationale. In this case, there's no ssh form for
+ // private keys, so we just use PEM for that.
+
+ if (isPrivateKey(key1) && isPrivateKey(key2)) {
+ var pem1 = key1.toPrivatePem(UTF8);
+ var pem2 = key2.toPrivatePem(UTF8);
+ return pem1 === pem2;
+ }
+
+ if (isPublicKey(key1) && isPublicKey(key2)) {
+ return matchingPublicKeys(key1, key2);
+ }
+
+ return false;
+}
+
+/**
+ * Create a signer object.
+ */
+function createSigner(algorithm) {
+ var hash = crypto.createHash(algorithm);
+ var self = {};
+
+ function update(buf, bufEncoding) {
+ buf = decodeString(buf, bufEncoding);
+ hash.update(buf);
+ return self;
+ }
+
+ function sign(privateKey, outEncoding) {
+ var hashBuf = new Buffer(hash.digest(BINARY), BINARY);
+ return privateKey.sign(algorithm, hashBuf, undefined, outEncoding);
+ }
+
+ self.sign = sign;
+ self.update = update;
+ return self;
+}
+
+/**
+ * Create a verifier object.
+ */
+function createVerifier(algorithm) {
+ var hash = crypto.createHash(algorithm);
+ var self = {};
+
+ function update(buf, bufEncoding) {
+ buf = decodeString(buf, bufEncoding);
+ hash.update(buf);
+ return self;
+ }
+
+ function verify(publicKey, sig, sigEncoding) {
+ var hashBuf = new Buffer(hash.digest(BINARY), BINARY);
+ sig = decodeString(sig, sigEncoding);
+ return publicKey.verify(algorithm, hashBuf, sig);
+ }
+
+ self.update = update;
+ self.verify = verify;
+ return self;
+}
+
+
+/*
+ * Initialization
+ */
+
+module.exports = {
+ assertKey: assertKey,
+ assertPrivateKey: assertPrivateKey,
+ assertPublicKey: assertPublicKey,
+ coerceKey: coerceKey,
+ coercePrivateKey: coercePrivateKey,
+ coercePublicKey: coercePublicKey,
+ createKey: createKey,
+ createPrivateKey: createPrivateKey,
+ createPrivateKeyFromComponents: createPrivateKeyFromComponents,
+ openSshPublicKey: openSshPublicKey,
+ createPublicKey: createPublicKey,
+ createPublicKeyFromComponents: createPublicKeyFromComponents,
+ createSigner: createSigner,
+ createVerifier: createVerifier,
+ equalKeys: equalKeys,
+ generatePrivateKey: generatePrivateKey,
+ isKey: isKey,
+ isPrivateKey: isPrivateKey,
+ isPublicKey: isPublicKey,
+ matchingPublicKeys: matchingPublicKeys,
+ sshFingerprint: sshFingerprint,
+ RSA_NO_PADDING: ursaNative.RSA_NO_PADDING,
+ RSA_PKCS1_PADDING: ursaNative.RSA_PKCS1_PADDING,
+ RSA_PKCS1_OAEP_PADDING: ursaNative.RSA_PKCS1_OAEP_PADDING,
+ RSA_PKCS1_SALT_LEN_HLEN: ursaNative.RSA_PKCS1_SALT_LEN_HLEN,
+ RSA_PKCS1_SALT_LEN_MAX: ursaNative.RSA_PKCS1_SALT_LEN_MAX,
+ RSA_PKCS1_SALT_LEN_RECOVER: ursaNative.RSA_PKCS1_SALT_LEN_RECOVER
+};
diff --git a/express-server/node_modules/ursa-optional/package.json b/express-server/node_modules/ursa-optional/package.json
new file mode 100644
index 00000000..5dc12754
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/package.json
@@ -0,0 +1,110 @@
+{
+ "_args": [
+ [
+ "ursa-optional@^0.9.10",
+ "/nodeapps/https-test/greenlock-express.js/node_modules/rsa-compat"
+ ]
+ ],
+ "_from": "ursa-optional@>=0.9.10 <0.10.0",
+ "_hasShrinkwrap": false,
+ "_id": "ursa-optional@0.9.10",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/ursa-optional",
+ "_nodeVersion": "10.13.0",
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/ursa-optional_0.9.10_1541526082762_0.09868043920674285"
+ },
+ "_npmUser": {
+ "email": "mkg20001@gmail.com",
+ "name": "mkg20001"
+ },
+ "_npmVersion": "6.4.1",
+ "_phantomChildren": {},
+ "_requested": {
+ "name": "ursa-optional",
+ "raw": "ursa-optional@^0.9.10",
+ "rawSpec": "^0.9.10",
+ "scope": null,
+ "spec": ">=0.9.10 <0.10.0",
+ "type": "range"
+ },
+ "_requiredBy": [
+ "/rsa-compat"
+ ],
+ "_resolved": "https://registry.npmjs.org/ursa-optional/-/ursa-optional-0.9.10.tgz",
+ "_shasum": "f2eabfe0b6001dbf07a78740cd0a6e5ba6eb2554",
+ "_shrinkwrap": null,
+ "_spec": "ursa-optional@^0.9.10",
+ "_where": "/nodeapps/https-test/greenlock-express.js/node_modules/rsa-compat",
+ "author": {
+ "email": "danfuzz@milk.com",
+ "name": "Dan Bornstein",
+ "url": "http://www.milk.com/"
+ },
+ "bugs": {
+ "url": "https://github.com/mkg20001/ursa/issues"
+ },
+ "dependencies": {
+ "bindings": "^1.3.0",
+ "nan": "^2.11.1"
+ },
+ "description": "RSA public/private key OpenSSL bindings for node and io.js",
+ "devDependencies": {
+ "mocha": "^5.2.0"
+ },
+ "directories": {
+ "lib": "lib",
+ "test": "test"
+ },
+ "dist": {
+ "fileCount": 21,
+ "integrity": "sha512-RvEbhnxlggX4MXon7KQulTFiJQtLJZpSb9ZSa7ZTkOW0AzqiVTaLjI4vxaSzJBDH9dwZ3ltZadFiBaZslp6haA==",
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJb4dJDCRA9TVsSAnZWagAAjP4P/27Bci055Hpb+wCQWR4s\nHVYq0NnLrTcDuMGzpJxI48QvueBMFGH2zUWZWfHuzoiGAoDaTPMtMg7BLV+S\nU2GTKkjgfZYOYS/fCGt/zv2/7pxXDy0cFUFhZWY9e6Rrupwmcdc24uiJHcxA\nazLQpqb9nm/cwXWqs+9gwkidJ6G+VgouujaNkhsvugIZDYDfXmEW4cTw+aUH\nmtjOh8l/Csc+GOxJulW6rOM9qEDOopULVCVowtJb1Rfz/aZgdDE3iSIzcrzS\nTstfVsA30JJmxy87YZYyGyJpRbV5Sig9o3fA9HaEkuZTxzLZxlUW6Qkh4DD4\n8zq1CnEeJAL/Y70aowApumLDojOOhSB+GHjmR/cshyALHGEe6aRmQWG7HYdz\nIeMJT559AtuW8wmf7lOuPGJnrGWpQwqp/6QJIDmptgGLqISOHh8Pi0NBhevJ\nz9KUISSIPJ7GmdLBohkRfXeUDAh8swsuLhG2XmDESbzh7ZntlN1+vB4EmVee\njMI3d7JRdQNUnnEW6epu/bGE73lWUsLJVbl8N1mkMwLMG1V/eAe81ft5Bafh\nTAYdUnA2ZfuGM2OGnuKwtOsMLQLbU+PP10/MjmchCKDXzouuSbVDvmmRqeza\n/KmGnFT1d7bEhzGdCQkeHTpPo5+1tKF/A36RBP4cJT2+d7GjHIe3lhFJUG/+\nOai6\r\n=H75D\r\n-----END PGP SIGNATURE-----\r\n",
+ "shasum": "f2eabfe0b6001dbf07a78740cd0a6e5ba6eb2554",
+ "tarball": "https://registry.npmjs.org/ursa-optional/-/ursa-optional-0.9.10.tgz",
+ "unpackedSize": 158923
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "gitHead": "0999dcf62cced5102913f925cb4fcfabdd480dfb",
+ "homepage": "https://github.com/mkg20001/ursa#readme",
+ "keywords": [
+ "crypto",
+ "digest",
+ "hash",
+ "key",
+ "openssl",
+ "private",
+ "public",
+ "rsa",
+ "sign",
+ "signature",
+ "verification",
+ "verify"
+ ],
+ "license": "Apache-2.0",
+ "main": "lib/ursa.js",
+ "maintainers": [
+ {
+ "name": "mkg20001",
+ "email": "mkg20001@gmail.com"
+ }
+ ],
+ "name": "ursa-optional",
+ "optionalDependencies": {},
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/mkg20001/ursa.git"
+ },
+ "scripts": {
+ "install": "node rebuild.js",
+ "rebuild": "node-gyp rebuild",
+ "test": "mocha --recursive --reporter spec",
+ "test-watch": "npm test -- -w --reporter min"
+ },
+ "version": "0.9.10"
+}
diff --git a/express-server/node_modules/ursa-optional/rebuild.js b/express-server/node_modules/ursa-optional/rebuild.js
new file mode 100644
index 00000000..dd87825b
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/rebuild.js
@@ -0,0 +1,17 @@
+var cp = require('child_process');
+var verbose = Boolean(process.env.URSA_VERBOSE);
+if (verbose) {
+ var p = cp.spawn(process.execPath, [process.env.npm_execpath, 'run', 'rebuild'], {cwd: process.cwd(), stdio: 'inherit'});
+} else {
+ var p = cp.spawnSync(process.execPath, [process.env.npm_execpath, 'run', 'rebuild'], {cwd: process.cwd()});
+ if (p.status || p.signal || p.error) {
+ console.log('ursaNative bindings compilation fail. This is not an issue. Modules that depend on it will use fallbacks.');
+ var fs = require('fs');
+ if (p.error) {
+ fs.writeFileSync('./stderr.log', p.error.stack);
+ } else {
+ fs.writeFileSync('./stdout.log', p.stdout);
+ fs.writeFileSync('./stderr.log', p.stderr);
+ }
+ }
+}
diff --git a/express-server/node_modules/ursa-optional/src/ursaNative.cc b/express-server/node_modules/ursa-optional/src/ursaNative.cc
new file mode 100644
index 00000000..acd2670d
--- /dev/null
+++ b/express-server/node_modules/ursa-optional/src/ursaNative.cc
@@ -0,0 +1,1865 @@
+// Copyright 2012 The Obvious Corporation.
+
+#include "ursaNative.h"
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace v8;
+
+#ifdef _WIN32
+#include
+#define VAR_ARRAY(type, name, size) type *name = (type *)_alloca(size)
+#else
+#define VAR_ARRAY(type, name, size) type name[size]
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+#include
+#include
+
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+ /* If the fields n and e in r are NULL, the corresponding input
+ * parameters MUST be non-NULL for n and e. d may be
+ * left NULL (in case only the public key is used).
+ */
+ if ((r->n == NULL && n == NULL) || (r->e == NULL && e == NULL))
+ return 0;
+
+ if (n != NULL)
+ {
+ BN_free(r->n);
+ r->n = n;
+ }
+ if (e != NULL)
+ {
+ BN_free(r->e);
+ r->e = e;
+ }
+ if (d != NULL)
+ {
+ BN_free(r->d);
+ r->d = d;
+ }
+
+ return 1;
+}
+
+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
+{
+ /* If the fields p and q in r are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((r->p == NULL && p == NULL) || (r->q == NULL && q == NULL))
+ return 0;
+
+ if (p != NULL)
+ {
+ BN_free(r->p);
+ r->p = p;
+ }
+ if (q != NULL)
+ {
+ BN_free(r->q);
+ r->q = q;
+ }
+
+ return 1;
+}
+
+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
+{
+ /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((r->dmp1 == NULL && dmp1 == NULL) || (r->dmq1 == NULL && dmq1 == NULL) || (r->iqmp == NULL && iqmp == NULL))
+ return 0;
+
+ if (dmp1 != NULL)
+ {
+ BN_free(r->dmp1);
+ r->dmp1 = dmp1;
+ }
+ if (dmq1 != NULL)
+ {
+ BN_free(r->dmq1);
+ r->dmq1 = dmq1;
+ }
+ if (iqmp != NULL)
+ {
+ BN_free(r->iqmp);
+ r->iqmp = iqmp;
+ }
+
+ return 1;
+}
+
+void RSA_get0_key(const RSA *r,
+ const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+ if (n != NULL)
+ *n = r->n;
+ if (e != NULL)
+ *e = r->e;
+ if (d != NULL)
+ *d = r->d;
+}
+
+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+ if (p != NULL)
+ *p = r->p;
+ if (q != NULL)
+ *q = r->q;
+}
+
+void RSA_get0_crt_params(const RSA *r,
+ const BIGNUM **dmp1, const BIGNUM **dmq1,
+ const BIGNUM **iqmp)
+{
+ if (dmp1 != NULL)
+ *dmp1 = r->dmp1;
+ if (dmq1 != NULL)
+ *dmq1 = r->dmq1;
+ if (iqmp != NULL)
+ *iqmp = r->iqmp;
+}
+
+void DSA_get0_pqg(const DSA *d,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ if (p != NULL)
+ *p = d->p;
+ if (q != NULL)
+ *q = d->q;
+ if (g != NULL)
+ *g = d->g;
+}
+
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ /* If the fields p, q and g in d are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((d->p == NULL && p == NULL) || (d->q == NULL && q == NULL) || (d->g == NULL && g == NULL))
+ return 0;
+
+ if (p != NULL)
+ {
+ BN_free(d->p);
+ d->p = p;
+ }
+ if (q != NULL)
+ {
+ BN_free(d->q);
+ d->q = q;
+ }
+ if (g != NULL)
+ {
+ BN_free(d->g);
+ d->g = g;
+ }
+
+ return 1;
+}
+
+void DSA_get0_key(const DSA *d,
+ const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key != NULL)
+ *pub_key = d->pub_key;
+ if (priv_key != NULL)
+ *priv_key = d->priv_key;
+}
+
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ /* If the field pub_key in d is NULL, the corresponding input
+ * parameters MUST be non-NULL. The priv_key field may
+ * be left NULL.
+ */
+ if (d->pub_key == NULL && pub_key == NULL)
+ return 0;
+
+ if (pub_key != NULL)
+ {
+ BN_free(d->pub_key);
+ d->pub_key = pub_key;
+ }
+ if (priv_key != NULL)
+ {
+ BN_free(d->priv_key);
+ d->priv_key = priv_key;
+ }
+
+ return 1;
+}
+
+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+ if (pr != NULL)
+ *pr = sig->r;
+ if (ps != NULL)
+ *ps = sig->s;
+}
+
+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ if (r == NULL || s == NULL)
+ return 0;
+ BN_clear_free(sig->r);
+ BN_clear_free(sig->s);
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
+{
+ if (pr != NULL)
+ *pr = sig->r;
+ if (ps != NULL)
+ *ps = sig->s;
+}
+
+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
+{
+ if (r == NULL || s == NULL)
+ return 0;
+ BN_clear_free(sig->r);
+ BN_clear_free(sig->s);
+ sig->r = r;
+ sig->s = s;
+ return 1;
+}
+
+void DH_get0_pqg(const DH *dh,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ if (p != NULL)
+ *p = dh->p;
+ if (q != NULL)
+ *q = dh->q;
+ if (g != NULL)
+ *g = dh->g;
+}
+
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ /* If the fields p and g in d are NULL, the corresponding input
+ * parameters MUST be non-NULL. q may remain NULL.
+ */
+ if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL))
+ return 0;
+
+ if (p != NULL)
+ {
+ BN_free(dh->p);
+ dh->p = p;
+ }
+ if (q != NULL)
+ {
+ BN_free(dh->q);
+ dh->q = q;
+ }
+ if (g != NULL)
+ {
+ BN_free(dh->g);
+ dh->g = g;
+ }
+
+ if (q != NULL)
+ {
+ dh->length = BN_num_bits(q);
+ }
+
+ return 1;
+}
+
+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key != NULL)
+ *pub_key = dh->pub_key;
+ if (priv_key != NULL)
+ *priv_key = dh->priv_key;
+}
+
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ /* If the field pub_key in dh is NULL, the corresponding input
+ * parameters MUST be non-NULL. The priv_key field may
+ * be left NULL.
+ */
+ if (dh->pub_key == NULL && pub_key == NULL)
+ return 0;
+
+ if (pub_key != NULL)
+ {
+ BN_free(dh->pub_key);
+ dh->pub_key = pub_key;
+ }
+ if (priv_key != NULL)
+ {
+ BN_free(dh->priv_key);
+ dh->priv_key = priv_key;
+ }
+
+ return 1;
+}
+
+int DH_set_length(DH *dh, long length)
+{
+ dh->length = length;
+ return 1;
+}
+
+const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx)
+{
+ return ctx->iv;
+}
+
+unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx)
+{
+ return ctx->iv;
+}
+#endif
+
+Nan::Persistent constructor;
+
+/*
+ * Initialization and binding
+ */
+#define NanThrowError(err) Nan::ThrowError(err);
+#define NanNewBufferHandle(length) Nan::NewBuffer(length).ToLocalChecked()
+#define args info
+#define NanScope() Nan::HandleScope scope
+#define NanReturnUndefined() \
+ { \
+ info.GetReturnValue().Set(Nan::Undefined()); \
+ return; \
+ }
+#define NanNew Nan::New
+#define NanReturnValue(value) \
+ { \
+ info.GetReturnValue().Set(value); \
+ return; \
+ }
+#define NanFalse() Nan::False()
+#define NanTrue() Nan::True()
+
+#define RSA_PKCS1_SALT_LEN_HLEN -1
+#define RSA_PKCS1_SALT_LEN_MAX -2
+#define RSA_PKCS1_SALT_LEN_RECOVER -2
+
+/**
+ * Top-level initialization function.
+ */
+void init(Local