2
0

Reorganize core source and add Docker support to CLI.

This commit is contained in:
Maarten Billemont
2018-06-05 20:01:46 -04:00
parent 8e41cba7ac
commit c2aafd8602
215 changed files with 65 additions and 47 deletions

View File

@@ -0,0 +1,15 @@
build: mkdir-es5 es5/mpw-js/pbkdf2.js es5/mpw-js/scrypt.js es5/mpw-js/mpw.js es5/setImmediate-polyfill.js
mkdir-es5:
mkdir -p es5
mkdir -p es5/mpw-js
es5/%: $*
babel $* -o $@ --presets es2015 --source-maps
clean:
rm -rf es5 2>/dev/null
update:
git submodule update --init --recursive
git submodule foreach git pull origin master

View File

@@ -0,0 +1,8 @@
ES5
===
If your browser does not support ECMAScript 6, you will need to run babel to compile an ES5-compatible version of the ES6 mpw-js code.
1. Install npm. On OS X, you can use `brew install npm`.
2. Install babel. With npm installed, you can use `npm -g install babel-cli babel-preset-es2015`
3. Build the ES5-translation of the ES6 code. From this directory, just run `make`.

View File

@@ -0,0 +1,49 @@
// Test for required ES6 features
// Use an eval call to avoid a hard-fail on ES5 parsers.
var ES6 = false;
var esdir = "es5/";
try {
// Use ES6 code if the ES6 class, let, destructive assignment and rest arguments are supported.
eval("class $ES6 { constructor() { let b = true; this.b = b; } } var [ES6, esdir] = ((...args) => args)(new $ES6().b, '')");
} catch (e) {
}
// If crypto.subtle is not supported, try crypto.webkitSubtle instead.
if (window.crypto && !window.crypto.subtle && window.crypto.webkitSubtle)
window.crypto.subtle = window.crypto.webkitSubtle;
if ((!window.crypto || !window.crypto.subtle) && window.SubtleCrypto)
window.crypto = { subtle: window.SubtleCrypto }
// If Web Crypto API is not supported we include a JS crypto library
// https://code.google.com/p/crypto-js/
/* Disabled by default. Enable manually if your browser requires this.
if (!window.crypto || !window.crypto.subtle) {
document.write("<script src=https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js><\/script>");
document.write("<script src=https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/pbkdf2.js><\/script>");
document.write("<script src=https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/lib-typedarrays-min.js><\/script>");
}/**/
if (!Number.MAX_SAFE_INTEGER)
Number.MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
// If Typed Arrays are not supported we include the polyfill
// https://github.com/inexorabletash/polyfill
window.ArrayBuffer || document.write("<script src=js/typedarray-polyfill.js><\/script>");
// If TextEncoder is not supported we include the polyfill
// https://github.com/inexorabletash/text-encoding
window.TextEncoder || document.write("<script src=js/encoding-polyfill.js><\/script>");
// If Promise is not supported we include the polyfill
// https://github.com/taylorhakes/promise-polyfill
window.Promise || document.write("<script src=js/promise-polyfill.js><\/script>");
// If setImmediate is not implemented we include the polyfill
window.setImmediate || document.write("<script src=js/" + esdir + "setImmediate-polyfill.js><\/script>");
// Include the scrypt implementation
document.write("<script src=js/" + esdir + "mpw-js/pbkdf2.js><\/script>");
document.write("<script src=js/" + esdir + "mpw-js/scrypt.js?1><\/script>");
// Include the MPW class
document.write("<script src=js/" + esdir + "mpw-js/mpw.js?1><\/script>");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,114 @@
var mpw, error;
function updateMPW() {
mpw = null;
startWork();
mpw = new MPW( $('#userName')[0].value, $('#masterPassword')[0].value, $('#version')[0].value );
mpw.key.then(
function() {
doneWork();
},
function(reason) {
error = reason;
mpw = null;
doneWork();
}
);
}
function startWork() {
update(true);
}
function doneWork() {
update(false);
}
function update(working) {
var screen = mpw? 'site': 'identity';
// Screen Name
if (screen == 'identity') {
$('#identity').addClass('active');
if (!working)
$('#userName').focus();
}
else {
$('#identity').removeClass('active');
$('#userName')[0].value = $('#masterPassword')[0].value = '';
}
if (screen == 'site') {
$('#site').addClass('active');
if (!working)
$('#siteName').focus();
}
else {
$('#site').removeClass('active');
$('#siteName')[0].value = $('#sitePassword')[0].value = '';
}
// Working
if (working && screen == 'identity')
$('#identity').addClass('working').find('input, select').attr('disabled', 'disabled');
else
$('#identity').removeClass('working').find('input, select').removeAttr('disabled');
if (working && screen == 'site')
$('#site').addClass('working');
else
$('#site').removeClass('working');
// Error
$('#error').text(error);
}
function updateSite() {
if (!mpw) {
doneWork();
return
}
startWork();
mpw.generatePassword( $('#siteName')[0].value, $('#siteCounter')[0].valueAsNumber, $('#siteType')[0].value )
.then( function (sitePassword) {
$('#sitePassword').text(sitePassword);
doneWork();
}, function (reason) {
error = reason;
doneWork();
});
}
function selectText(element) {
var doc = document, range, selection;
if (doc.body.createTextRange) { //ms
range = doc.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) { //all others
selection = window.getSelection();
range = doc.createRange();
range.selectNodeContents(element);
selection.removeAllRanges();
selection.addRange(range);
}
}
$(function() {
$('#identity form').on('submit', function() {
updateMPW();
return false;
});
$('#site input, #site select').on('change input keyup', function() {
updateSite();
});
$('#logout').on('click', function() {
mpw = null;
doneWork();
});
$('#sitePassword').on('click', function() {
selectText(this);
});
doneWork();
});

View File

@@ -0,0 +1,186 @@
(function() {
var root;
if (typeof window === 'object' && window) {
root = window;
} else {
root = global;
}
if (typeof module !== 'undefined' && module.exports) {
module.exports = root.Promise ? root.Promise : Promise;
} else if (!root.Promise) {
root.Promise = Promise;
}
// Use polyfill for setImmediate for performance gains
var asap = root.setImmediate || function(fn) { setTimeout(fn, 1); };
// Polyfill for Function.prototype.bind
function bind(fn, thisArg) {
return function() {
fn.apply(thisArg, arguments);
}
}
var isArray = Array.isArray || function(value) { return Object.prototype.toString.call(value) === "[object Array]" };
function Promise(fn) {
if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
if (typeof fn !== 'function') throw new TypeError('not a function');
this._state = null;
this._value = null;
this._deferreds = []
doResolve(fn, bind(resolve, this), bind(reject, this))
}
function handle(deferred) {
var me = this;
if (this._state === null) {
this._deferreds.push(deferred);
return
}
asap(function() {
var cb = me._state ? deferred.onFulfilled : deferred.onRejected
if (cb === null) {
(me._state ? deferred.resolve : deferred.reject)(me._value);
return;
}
var ret;
try {
ret = cb(me._value);
}
catch (e) {
deferred.reject(e);
return;
}
deferred.resolve(ret);
})
}
function resolve(newValue) {
try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
if (newValue === this) throw new TypeError('A promise cannot be resolved with itself.');
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (typeof then === 'function') {
doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));
return;
}
}
this._state = true;
this._value = newValue;
finale.call(this);
} catch (e) { reject.call(this, e); }
}
function reject(newValue) {
this._state = false;
this._value = newValue;
finale.call(this);
}
function finale() {
for (var i = 0, len = this._deferreds.length; i < len; i++) {
handle.call(this, this._deferreds[i]);
}
this._deferreds = null;
}
function Handler(onFulfilled, onRejected, resolve, reject){
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
this.onRejected = typeof onRejected === 'function' ? onRejected : null;
this.resolve = resolve;
this.reject = reject;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/
function doResolve(fn, onFulfilled, onRejected) {
var done = false;
try {
fn(function (value) {
if (done) return;
done = true;
onFulfilled(value);
}, function (reason) {
if (done) return;
done = true;
onRejected(reason);
})
} catch (ex) {
if (done) return;
done = true;
onRejected(ex);
}
}
Promise.prototype['catch'] = function (onRejected) {
return this.then(null, onRejected);
};
Promise.prototype.then = function(onFulfilled, onRejected) {
var me = this;
return new Promise(function(resolve, reject) {
handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));
})
};
Promise.all = function () {
var args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);
return new Promise(function (resolve, reject) {
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
try {
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then;
if (typeof then === 'function') {
then.call(val, function (val) { res(i, val) }, reject);
return;
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
} catch (ex) {
reject(ex);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
};
Promise.resolve = function (value) {
if (value && typeof value === 'object' && value.constructor === Promise) {
return value;
}
return new Promise(function (resolve) {
resolve(value);
});
};
Promise.reject = function (value) {
return new Promise(function (resolve, reject) {
reject(value);
});
};
Promise.race = function (values) {
return new Promise(function (resolve, reject) {
for(var i = 0, len = values.length; i < len; i++) {
values[i].then(resolve, reject);
}
});
};
})();

View File

@@ -0,0 +1,211 @@
/*! by Tom Thorogood <me@tomthorogood.co.uk> */
/*! This work is licensed under the Creative Commons Attribution 4.0
International License. To view a copy of this license, visit
http://creativecommons.org/licenses/by/4.0/ or see LICENSE. */
// setImmediate is a 0-delay setTimeout of sorts introduced
// by MS and wrongly held back by other browsers
window.setImmediate || !function (global) {
// Get the global prototype to attach setImmediate to
let attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
// If we couldn't get the prototype or setTimeout wasn't attached
// to the prototype we just attach to global
attachTo && attachTo.setTimeout || (attachTo = global);
// If the MS prefixed implementation exists, use it
if (global.msSetImmediate) {
return attachTo.setImmediate = global.msSetImmediate, attachTo.clearImmediate = global.msClearImmediate;
}
// https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js
// This checks if the current environment is Node.js
if (global.process && Object.prototype.toString(global.process) === "[object process]") {
// If it is we might be able to use timers
let timers = global.require("timers");
// If it implements setImmediate we use it
if (timers && timers.setImmediate) {
return attachTo.setImmediate = timers.setImmediate, attachTo.clearImmediate = timers.clearImmediate;
}
// If it isn't we polyfill with nextTick which is
// sufficiently similar
if (global.process.nextTick) {
return attachTo.setImmediate = function (func, ...params) {
// Invoke func with the params as passed into setImmediate
global.process.nextTick(() => func(...params));
}, attachTo.clearImmediate = function (immediateID) {
// There is no id or way to stop nextTick
throw new Error("clearImmediate not implemented");
};
}
}
// http://dbaron.org/log/20100309-faster-timeouts
// https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js
// https://github.com/kriskowal/q/blob/0428c15d2ffc8e874b4be3a50e92884ef8701a6f/q.js#L125-141
// If we have messaging channels, or we have postMessage and this
// isn't a WebWorker, we can use messaging
if (global.MessageChannel || global.postMessage && !global.importScripts && (function () {
// This checks if global.postMessage is asynchronous,
// it has been known to be buggy and synchronous in
// some browsers
let postMessageIsAsynchronous = true;
let oldOnMessage = global.onmessage;
global.onmessage = function () { postMessageIsAsynchronous = false; };
global.postMessage("", "*");
global.onmessage = oldOnMessage;
return postMessageIsAsynchronous;
})()) {
// A unique id prefix to ensure that ONLY valid messages are accepted
let messageName = `setImmediate-polyfill-${Math.random()}`.replace("0.", "");
// The numeric identifier of the next dispatched scrypt call
let immediateID = 1;
// The timeout function and arguments, indexed by numeric identifier
let timeouts = { };
// If a MessageChannel exists we can use it to avoid sending
// messages to the browser which could cause interoperability
// issues
let channel = global.MessageChannel && new global.MessageChannel();
// We need to start port1 in order to receive messages sent
// from port2
channel && channel.port1.start();
// Add a handler to the message event of either the message
// channel, if it exists, or global if it does not
(channel && channel.port1 || global).addEventListener("message", function (event) {
// If event data is not a string, i.e. doesn't implement split,
// we didn't send it
if (!event.data || !event.data.split) {
return;
}
// Split the identifier into the name and numeric id
let [name, immediateID] = event.data.split("$");
// If we are not using a MessageChannel check that the source
// of the event was this window, also check the name is valid,
// if either of these are not true, we didn't send it
if (!channel && event.source !== global || name !== messageName) {
return;
}
// Prevent the event from propagating further
event.stopPropagation();
// Retrieve the function and the arguments we will invoke
// leaving func and params as null if the immediateID
// does not exist in timeouts (because clearImmediate has
// been called before we got here)
let [func, params] = timeouts[immediateID] || [ ];
// Invoke the func with the appropriate parameters
func && func(...params);
// Clear func and params for GC
func = params = null;
// Remove key:immediateID from timeouts to ensure it's only
// called once and to allow for GC
delete timeouts[immediateID];
}, false);
return attachTo.setImmediate = function (func, ...params) {
// Store the function and it's arguments in timeouts
timeouts[immediateID] = [func, params];
// Post the message either using port2 of the MessageChannel
// or on global if it's not available w/ the unique id
// If the message is sent on global we dispatch it w/ a
// targetOrigin of "*" (indicating no preference)
(channel && channel.port2 || global).postMessage([messageName, immediateID].join("$"), ...(channel ? [ ] : ["*"]));
// We return a unique numeric id to identify the call
// to setImmediate, this allows it to be cancelled
return immediateID++;
}, attachTo.clearImmediate = function (immediateID) {
// Delete the function and arguments associated
// w/ identifier of immediateID
delete timeouts[immediateID];
};
}
// Set setImmediate to prefixed or non-prefixed requestAnimationFrame
// requestAnimationFrame dispatches at a later point in the event cycle
attachTo.setImmediate = global.requestAnimationFrame || global.mozRequestAnimationFrame || global.webkitRequestAnimationFrame || global.msRequestAnimationFrame;
// If requestAnimationFrame existed we end, setting clearImmediate
// to cancelAnimationFrame
if (attachTo.setImmediate) {
return attachTo.clearImmediate = global.cancelAnimationFrame || global.mozCancelAnimationFrame || global.webkitCancelAnimationFrame || global.msCancelAnimationFrame || global.webkitCancelRequestAnimationFrame;
}
// https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js
// We can use a script tag and the readystatechange event on IE(?)
if (global.document && "onreadystatechange" in global.document.getElementsByTagName("script")[0]) {
// The numeric identifier of the next dispatched scrypt call
let immediateID = 1;
// A boolean value to allow clearImmediate to work,
// indexed by numeric identifier
let timeouts = { };
return attachTo.setImmediate = function (func, ...params) {
// Set true in timeouts for immediateID to indicate the func
// should be invoked
timeouts[immediateID] = true;
// Create a script tag that will be added to the DOM
let script = global.document.createElement("script");
// Add a handler for onreadystatechange
script.onreadystatechange = function () {
// If the timeout has not been cancelled, call the func
// w/ the arguments specified
timeouts[immediateID] && func(...params);
// Remove key:immediateID from timeouts to ensure it's only called once
delete timeouts[immediateID];
// Remove the handler to allow GC
script.onreadystatechange = null;
// Remove the script tag from the DOM to ensure GC
global.document.body.removeChild(script);
// Nullify the script variable to allow GC
script = null;
};
// Add the script tag to the DOM to which begins loading
// the tag which will invoke the readystatechange event
global.document.body.appendChild(script);
// Return a unique numeric id to identify the call
// to setImmediate, this allows it to be cancelled
return immediateID++;
}, attachTo.clearImmediate = function (immediateID) {
// Remove key:immediateID from timeouts to prevent func from being called
delete timeouts[immediateID];
};
}
// The worst fallback is setTimeout, although the delay is set to 0,
// in reality this should have a ~20ms delay as this is an important
// part of the spec
attachTo.setImmediate = (func, ...params) => global.setTimeout(func, 0, ...params);
attachTo.clearImmediate = global.clearTimeout;
// Here we check if the arguments passed to setTimeout actually will be
// passed to the callback, on older versions of IE(?) this check will fail
global.setTimeout(function (arg) {
// If the test fails, we wrap func in a closure that will invoke func w/
// the arguments
arg || (attachTo.setImmediate = (func, ...params) => global.setTimeout(() => func(...params), 0));
}, 0, true);
}(this || window);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long