2
0

mpw-js: A javascript implementation of Master Password.

This commit is contained in:
Maarten Billemont 2014-10-23 20:10:25 -04:00
parent 41ae6a5de5
commit b3a886a6db
13 changed files with 13149 additions and 0 deletions

3
.gitmodules vendored
View File

@ -19,3 +19,6 @@
[submodule "External/jrswizzle"]
path = External/jrswizzle
url = git://github.com/jonmarimba/jrswizzle.git
[submodule "Site/2013-05/mpw-js/js/mpw-js"]
path = Site/2013-05/mpw-js/js/mpw-js
url = https://github.com/Lyndir/mpw-js.git

View File

@ -0,0 +1,110 @@
@import url(http://fonts.googleapis.com/css?family=Flamenco:300|Exo+2:400,100,900);
/**** BASE STYLE ****/
html {
background: radial-gradient(black 15%, transparent 16%) 0 0,
radial-gradient(black 15%, transparent 16%) 8px 8px,
radial-gradient(rgba(255,255,255,.05) 15%, transparent 20%) 0 1px,
radial-gradient(rgba(255,255,255,.05) 15%, transparent 20%) 8px 9px;
background-color: #161616;
background-size: 16px 16px;
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
body {
background: radial-gradient(transparent 16%, black);
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
clear: both;
font-family: 'Exo 2',
"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica,
Arial, "Lucida Grande", sans-serif;
font-weight: 300;
color: #DDD;
text-align: center;
}
h1, h2, h3, h4 {
margin: 0;
}
h1 {
font-size: 5em;
}
a {
font: inherit;
color: inherit;
}
input, select {
background: rgba(0, 0, 0, .3);
border: 1px solid #000;
border-radius: 4px;
width: 67%;
height: 2em;
margin: 1ex 0;
font: inherit;
color: inherit;
text-align: center;
}
input:focus, select:focus {
outline: none;
box-shadow: 0 0 50px #333;
}
input.half, select.half {
width: 33%;
}
input[type="submit"], input[type="image"] {
background: transparent;
border: none;
width: auto;
font-size: 2em;
}
input[type="submit"] {
display: inline;
}
#identity.working input[type="submit"] {
display: none;
}
input[type="image"] {
display: none;
}
#identity.working input[type="image"] {
display: inline;
}
#error {
color: red;
}
header, section {
overflow: hidden;
clear: both;
}
header {
font-size: 0.8em;
}
section {
font-size: 2.5em;
}
/**** LAYOUT ****/
section {
display: none;
}
section.active {
display: block;
}
.small {
font-size: 0.5em;
}

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32" fill="white">
<path opacity=".25" d="M16 0 A16 16 0 0 0 16 32 A16 16 0 0 0 16 0 M16 4 A12 12 0 0 1 16 28 A12 12 0 0 1 16 4"/>
<path d="M16 0 A16 16 0 0 1 32 16 L28 16 A12 12 0 0 0 16 4z">
<animateTransform attributeName="transform" type="rotate" from="0 16 16" to="360 16 16" dur="0.8s" repeatCount="indefinite" />
</path>
</svg>

After

Width:  |  Height:  |  Size: 423 B

View File

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Master Password &mdash; Secure your life, forget your passwords.</title>
<meta content="Master Password is an ingenious password solution that makes your passwords truly impossible to lose." />
<meta name="apple-itunes-app" content="app-id=510296984" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<header>
<p><a href="http://masterpasswordapp.com">Master Password</a> by <a href="http://www.lhunath.com" title="Maarten Billemont">lhunath</a> and <a href="https://tomthorogood.co.uk/" title="Tom Thorogood">tmthrgd</a></p>
<span id="error"></span>
</header>
<section id="identity" class="active"><form action="#">
<h1>Identity</h1>
<p>
<input id="userName" type="text" placeholder="Your Full Name" /><br>
<input id="masterPassword" type="password" placeholder="Your Master Password" /><br>
<input type="submit" value="⏎" /><br>
<input type="image" src="img/spinner.svg" />
</p>
</form></section>
<section id="site">
<h1>Site</h1>
<p>
<input id="siteName" type="text" placeholder="Site Name (eg. apple.com)" /><br>
<span class="small">
<input id="siteCounter" type="number" placeholder="Site Counter" min="1" max="100" value="1" class="half" />
<select id="siteType" class="half">
<option value="pin">PIN</option>
<option value="short">Short</option>
<option value="basic">Basic</option>
<option value="medium">Medium</option>
<option value="long" selected>Long</option>
<option value="maximum">Maximum</option>
<option value="name">Name</option>
<option value="phrase">Phrase</option>
</select>
</span><br>
<input id="sitePassword" placeholder="Your password is ..." disabled /><br>
<input id="logout" type="submit" value="⎋" />
<input type="image" src="img/spinner.svg" />
</p>
</section>
<!-- Scripts -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-2.1.1.js"><\/script>')</script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-2.1.1.min.js"><\/script>')</script>
<script src="js/dependencies.js?1"></script>
<script src="js/main.js?1"></script>
</body>
</html>

View File

@ -0,0 +1,47 @@
// 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/
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/components/lib-typedarrays-min.js><\/script>");
}
// 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>");
// 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 ES6 is not supported we must include traceur-runtime.js
ES6 || document.write("<script src=js/mpw-js/traceur-runtime.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
var SCRYPTASM_PATH = (window.location + '').replace(/[^/]*(#[^#]*)?$/, 'js/mpw-js/scrypt-asm.js');
document.write("<script src=js/mpw-js/" + esdir + "scrypt.js><\/script>");
// Include the MPW class
document.write("<script src=js/mpw-js/" + esdir + "mpw.js><\/script>");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
var mpw;
function updateMPW() {
update('identity', 'identity');
mpw = new MPW( $('#userName')[0].value, $('#masterPassword')[0].value );
updateActive();
}
function updateActive() {
if (!mpw)
update('identity');
else
mpw.key.then(
function() {
update('site');
},
function(reason) {
update('identity', null, reason);
}
);
}
function update(active, working, error) {
// Working
if (working == 'identity') {
$('#identity').addClass('working').find('input, select').attr('disabled', 'disabled');
}
else {
$('#userName')[0].value = $('#masterPassword')[0].value = '';
$('#identity').removeClass('working').find('input, select').removeAttr('disabled');
}
if (working == 'site')
$('#site').addClass('working');
else
$('#site').removeClass('working');
// Active
if (active == 'identity') {
$('#identity').addClass('active');
$('#site').removeClass('active');
if (!working)
$('#userName').focus();
}
else {
$('#identity').removeClass('active');
$('#site').addClass('active');
$('#siteName').focus();
if (!working)
$('#siteName').focus();
}
// Error
$('#error').text(error);
}
function updateSite() {
update('site', 'site');
if (!mpw)
updateActive();
else
mpw.generatePassword( $('#siteName')[0].value, $('#siteCounter')[0].valueAsNumber, $('#siteType')[0].value )
.then( function (sitePassword) {
$('#sitePassword').val(sitePassword);
update('site');
}, function (reason) {
update('site', null, reason);
});
}
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;
updateActive();
});
$('#sitePassword').on('click', function() {
selectText(this);
});
updateActive();
});

@ -0,0 +1 @@
Subproject commit 768cfad320668f480e2e44f7bf85c1f0de1b4059

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);
}
});
};
})();

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