211 lines
6.3 KiB
JavaScript
211 lines
6.3 KiB
JavaScript
var ewpass = {};
|
|
|
|
(function(ns) {
|
|
const SEED_PREFIX = 'E. W. Password Generator Seed/';
|
|
const DERIVE_PREFIX = 'Domain Password/';
|
|
const Storage = window.localStorage;
|
|
|
|
const BASIC_MAP = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
|
const EXTENDED_MAP = BASIC_MAP + '`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?';
|
|
|
|
var settings = {
|
|
'checksum': undefined,
|
|
'DEFAULT': [ 16, 1, true ],
|
|
'domains': {}
|
|
};
|
|
var currentDomain = undefined;
|
|
var seedValid = false;
|
|
|
|
var checkSeedChecksum = () => {
|
|
const valid = $('#checksum').text() === settings.checksum;
|
|
|
|
$('#chkok').html(valid ? '✓' : '✗');
|
|
$('#chkset').prop('disabled', valid ? 'disabled' : '');
|
|
|
|
seedValid = valid;
|
|
};
|
|
|
|
var setDomains = () => {
|
|
$domainlist = $("#domainlist")
|
|
|
|
$domainlist.html('');
|
|
|
|
Object.keys(settings.domains).sort().forEach(domain =>
|
|
$domainlist.append($('<option>').attr('value', domain).text(domain))
|
|
);
|
|
};
|
|
|
|
var calcRounds = l => {
|
|
var m = 0xffffffff;
|
|
var n = 0;
|
|
|
|
while (m > 0) {
|
|
m = Math.floor(m / l);
|
|
n++;
|
|
}
|
|
|
|
return n;
|
|
};
|
|
|
|
ns.resetSeed = () => {
|
|
$('#seed').val('');
|
|
$('#seed').prop('disabled', '');
|
|
$('#checksum').text('-');
|
|
$('#chkok').text('');
|
|
$('#chkset').prop('disabled', 'disabled');
|
|
|
|
seedValid = false;
|
|
|
|
$('#seed').focus();
|
|
};
|
|
|
|
ns.calculateSeed = () => {
|
|
sha256(SEED_PREFIX + $('#seed').val()).then(hash => {
|
|
$('#seed').val(hash);
|
|
$('#seed').prop('disabled', 'disabled');
|
|
$('#checksum').text(hash.substring(0, 2));
|
|
checkSeedChecksum();
|
|
});
|
|
};
|
|
|
|
ns.storeSeedChecksum = () => {
|
|
settings.checksum = $('#checksum').text();
|
|
Storage.setItem('checksum', settings.checksum);
|
|
checkSeedChecksum();
|
|
};
|
|
|
|
ns.checkDomainInputMatchesToOption = () => {
|
|
var domain = $('#domain').val();
|
|
if (domain in settings.domains) {
|
|
ns.loadSettingsForDomain(domain);
|
|
} else {
|
|
ns.loadSettingsForDomain('');
|
|
}
|
|
};
|
|
|
|
ns.loadSettingsForDomain = (domain) => {
|
|
if (domain === undefined) {
|
|
ns.loadSettingsForDomain($('#domain').val());
|
|
return;
|
|
}
|
|
|
|
var _settings;
|
|
|
|
if (domain === '') {
|
|
$('#length').prop('disabled', 'disabled');
|
|
$('#iteration').prop('disabled', 'disabled');
|
|
$('#nextiter').prop('disabled', 'disabled');
|
|
$('#extended').prop('disabled', 'disabled');
|
|
$('#storedomain').prop('disabled', 'disabled');
|
|
$('#docopy').prop('disabled', 'disabled');
|
|
|
|
_settings = settings.DEFAULT;
|
|
} else if (domain in settings.domains) {
|
|
_settings = settings.domains[domain];
|
|
} else if (!confirm('Add new domain "' + domain + '" ?')) {
|
|
$('#domain').val('');
|
|
ns.loadSettingsForDomain('');
|
|
return;
|
|
} else {
|
|
settings.domains[domain] = settings.DEFAULT.slice();
|
|
setDomains();
|
|
|
|
_settings = settings.domains[domain];
|
|
Storage.setItem('domains', JSON.stringify(settings.domains));
|
|
}
|
|
|
|
$('#length').val(_settings[0]);
|
|
$('#iteration').val(_settings[1]);
|
|
$('#extended').prop('checked', _settings[2] ? 'checked' : '');
|
|
|
|
if (_settings !== settings.DEFAULT) {
|
|
$('#length').prop('disabled', '');
|
|
$('#iteration').prop('disabled', '');
|
|
$('#nextiter').prop('disabled', '');
|
|
$('#extended').prop('disabled', '');
|
|
$('#storedomain').prop('disabled', '');
|
|
$('#docopy').prop('disabled', '');
|
|
|
|
currentDomain = domain;
|
|
}
|
|
};
|
|
|
|
ns.storeSettingsForDomain = () => {
|
|
_settings = [
|
|
parseInt($('#length').val()),
|
|
parseInt($('#iteration').val()),
|
|
$('#extended').prop('checked')
|
|
];
|
|
|
|
settings.domains[currentDomain] = _settings;
|
|
Storage.setItem('domains', JSON.stringify(settings.domains));
|
|
};
|
|
|
|
ns.nextIteration = () => {
|
|
$('#iteration').val(parseInt($('#iteration').val()) + 1);
|
|
ns.storeSettingsForDomain();
|
|
};
|
|
|
|
ns.deriveAndCopyToClipboard = () => {
|
|
if (!seedValid) {
|
|
alert('Enter master password first!');
|
|
ns.resetSeed();
|
|
return;
|
|
}
|
|
|
|
$docopy = $('#docopy');
|
|
$docopy.prop('disabled', 'disabled');
|
|
|
|
sha256(DERIVE_PREFIX + $('#seed').val() + '/' + settings.domains[currentDomain][1] + '/' + currentDomain).then(hash => {
|
|
const map = settings.domains[currentDomain][2] ? EXTENDED_MAP : BASIC_MAP;
|
|
|
|
const rounds = calcRounds(map.length);
|
|
var pw = '';
|
|
|
|
for (var i = 0; i < 8; i++) {
|
|
var x = parseInt(hash.substring(i * 8, (i+1) * 8), 16);
|
|
for (var j = 0; j < rounds; j++) {
|
|
pw += map.substring(x % map.length, x % map.length + 1);
|
|
x = Math.floor(x / map.length);
|
|
}
|
|
}
|
|
|
|
pw = pw.substring(0, settings.domains[currentDomain][0]);
|
|
|
|
navigator.clipboard.writeText(pw).then(() => {
|
|
$docopy.val('[ COPIED ]');
|
|
setInterval(() => {
|
|
$docopy.val('Copy password');
|
|
$docopy.prop('disabled', '');
|
|
}, 1500);
|
|
});
|
|
});
|
|
};
|
|
|
|
ns.setup = () => {
|
|
if (Storage.getItem('checksum') != null) {
|
|
settings.checksum = Storage.getItem('checksum');
|
|
}
|
|
if (Storage.getItem('domains') != null) {
|
|
settings.domains = JSON.parse(Storage.getItem('domains'));
|
|
console.debug('Loaded domains:', settings.domains);
|
|
setDomains();
|
|
}
|
|
|
|
var setupReturnEvent = (o, handler) => {
|
|
o.keypress((event, value) => {
|
|
if (event.which === 13) {
|
|
handler(o.val());
|
|
}
|
|
});
|
|
};
|
|
|
|
setupReturnEvent($('#seed'), ns.calculateSeed);
|
|
setupReturnEvent($('#domain'), ns.loadSettingsForDomain);
|
|
|
|
ns.resetSeed();
|
|
ns.loadSettingsForDomain();
|
|
};
|
|
|
|
})(ewpass);
|