mirror of https://github.com/keeweb/keeweb
simple password generator
parent
7e1b075c5e
commit
ee4f770952
|
@ -4,7 +4,10 @@ var Backbone = require('backbone');
|
|||
|
||||
var AppSettingsModel = Backbone.Model.extend({
|
||||
defaults: {
|
||||
theme: 'd'
|
||||
theme: 'd',
|
||||
genOpts: {
|
||||
length: 16, upper: true, lower: true, digits: true, special: false, brackets: false, high: false, ambiguous: false
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
'use strict';
|
||||
|
||||
var kdbxweb = require('kdbxweb');
|
||||
|
||||
var PasswordGenerator = {
|
||||
charRanges: {
|
||||
upper: 'ABCDEFGHJKLMNPQRSTUVWXYZ',
|
||||
lower: 'abcdefghijkmnpqrstuvwxyz',
|
||||
digits: '23456789',
|
||||
special: '!@#$%^&*_+-=,./?;:`"~\'\\',
|
||||
brackets: '()[]<>',
|
||||
high: '¡¢£¤¥¦§©ª«¬®¯°±²³´µ¶¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ',
|
||||
ambiguous: 'O0oIl1'
|
||||
},
|
||||
generate: function(opts) {
|
||||
if (!opts || typeof opts.length !== 'number' || opts.length < 0) {
|
||||
return '';
|
||||
}
|
||||
var pass = '';
|
||||
var ranges = Object.keys(this.charRanges)
|
||||
.filter(function(r) { return opts[r]; })
|
||||
.map(function(r) { return this.charRanges[r]; }, this);
|
||||
if (!ranges.length) {
|
||||
return '';
|
||||
}
|
||||
var randomBytes = kdbxweb.Random.getBytes(opts.length * 2);
|
||||
var pos = 0;
|
||||
while (pass.length < opts.length) {
|
||||
var rangeNum = randomBytes[pos++] % ranges.length;
|
||||
var range = ranges[rangeNum];
|
||||
pass += range[randomBytes[pos++] % range.length];
|
||||
}
|
||||
return pass;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PasswordGenerator;
|
|
@ -18,6 +18,8 @@ var FooterView = Backbone.View.extend({
|
|||
},
|
||||
|
||||
initialize: function () {
|
||||
this.views = {};
|
||||
|
||||
KeyHandler.onKey(Keys.DOM_VK_L, this.lockWorkspace, this, KeyHandler.SHORTCUT_ACTION);
|
||||
KeyHandler.onKey(Keys.DOM_VK_G, this.genPass, this, KeyHandler.SHORTCUT_ACTION);
|
||||
KeyHandler.onKey(Keys.DOM_VK_O, this.openFile, this, KeyHandler.SHORTCUT_ACTION);
|
||||
|
@ -36,14 +38,24 @@ var FooterView = Backbone.View.extend({
|
|||
Backbone.trigger('lock-workspace');
|
||||
},
|
||||
|
||||
genPass: function() {
|
||||
genPass: function(e) {
|
||||
e.stopPropagation();
|
||||
if (this.views.gen) {
|
||||
this.views.gen.remove();
|
||||
return;
|
||||
}
|
||||
var el = this.$el.find('.footer__btn-generate'),
|
||||
rect = el[0].getBoundingClientRect(),
|
||||
bodyRect = document.body.getBoundingClientRect(),
|
||||
right = bodyRect.right - rect.right,
|
||||
bottom = bodyRect.bottom - rect.top;
|
||||
var generator = new GeneratorView({ model: { pos: { right: right, bottom: bottom } } });
|
||||
var generator = new GeneratorView({ model: {
|
||||
pos: { right: right, bottom: bottom },
|
||||
genOpts: this.model.settings.get('genOpts')
|
||||
}});
|
||||
generator.render();
|
||||
generator.once('remove', (function() { delete this.views.gen; }).bind(this));
|
||||
this.views.gen = generator;
|
||||
},
|
||||
|
||||
showFile: function(e) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
var Backbone = require('backbone');
|
||||
var Backbone = require('backbone'),
|
||||
PasswordGenerator = require('../util/password-generator');
|
||||
|
||||
var GeneratorView = Backbone.View.extend({
|
||||
el: 'body',
|
||||
|
@ -8,20 +9,46 @@ var GeneratorView = Backbone.View.extend({
|
|||
template: require('templates/generator.html'),
|
||||
|
||||
events: {
|
||||
'mousedown': 'mousedown'
|
||||
'click': 'click',
|
||||
'mousemove .gen__length-range': 'lengthChange',
|
||||
'change .gen__length-range': 'lengthChange',
|
||||
'change .gen__check input[type=checkbox]': 'checkChange'
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
$('body').one('mousedown', this.remove.bind(this));
|
||||
$('body').one('click', this.remove.bind(this));
|
||||
this.gen = _.clone(this.model.genOpts);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.renderTemplate();
|
||||
this.renderTemplate(this.gen);
|
||||
this.$el.css(this.model.pos);
|
||||
this.generate();
|
||||
},
|
||||
|
||||
mousedown: function(e) {
|
||||
click: function(e) {
|
||||
e.stopPropagation();
|
||||
},
|
||||
|
||||
lengthChange: function(e) {
|
||||
var val = +e.target.value;
|
||||
if (val !== this.gen.length) {
|
||||
this.gen.length = val;
|
||||
this.$el.find('.gen__length-range-val').html(val);
|
||||
this.generate();
|
||||
}
|
||||
},
|
||||
|
||||
checkChange: function(e) {
|
||||
var id = $(e.target).data('id');
|
||||
if (id) {
|
||||
this.gen[id] = e.target.checked;
|
||||
}
|
||||
this.generate();
|
||||
},
|
||||
|
||||
generate: function() {
|
||||
this.$el.find('.gen__result').text(PasswordGenerator.generate(this.gen));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,21 @@
|
|||
.gen {
|
||||
position: absolute;
|
||||
@include dropdown;
|
||||
padding: $base-padding;
|
||||
&__input-small {
|
||||
padding: $base-spacing;
|
||||
width: 10em;
|
||||
&__length-range {
|
||||
}
|
||||
&__check {
|
||||
width: 40%;
|
||||
display: inline-block;
|
||||
&:nth-child(even) {
|
||||
margin-left: 15%;
|
||||
}
|
||||
}
|
||||
&__result {
|
||||
@include user-select(text);
|
||||
font-family: $monospace-font-family;
|
||||
margin-top: $base-padding-v;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,3 +138,139 @@ option {
|
|||
color: text-border();
|
||||
}
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
display: none;
|
||||
|
||||
& + label:hover:before {
|
||||
@include th {
|
||||
color: action-color();
|
||||
}
|
||||
}
|
||||
& + label:before {
|
||||
@include fa-icon;
|
||||
content: $fa-var-square-o;
|
||||
display: inline-block;
|
||||
width: 1.3em;
|
||||
@include th {
|
||||
color: text-color();
|
||||
}
|
||||
}
|
||||
&:checked + label:before {
|
||||
content: $fa-var-check-square-o;
|
||||
}
|
||||
}
|
||||
|
||||
$thumb-size: 8px;
|
||||
$track-width: 100%;
|
||||
$track-height: 1px;
|
||||
|
||||
@mixin track {
|
||||
@include size(100% 1px);
|
||||
@include th { background: background-color(); }
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@mixin thumb {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-radius: 1px;
|
||||
cursor: pointer;
|
||||
@include th { background: border-color(); }
|
||||
}
|
||||
|
||||
&input[type=range] {
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
margin: 12px 0;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
&::-webkit-slider-runnable-track {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
cursor: pointer;
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
border-radius: 1px;
|
||||
border: none;
|
||||
}
|
||||
&::-webkit-slider-thumb {
|
||||
border: none;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
border-radius: 14px;
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
cursor: pointer;
|
||||
-webkit-appearance: none;
|
||||
margin-top: -6.5px;
|
||||
}
|
||||
// &:focus::-webkit-slider-runnable-track {
|
||||
// @include th { background: active-color(); }
|
||||
// }
|
||||
&::-moz-range-track {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
cursor: pointer;
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
border-radius: 1px;
|
||||
border: none;
|
||||
}
|
||||
&::-moz-range-thumb {
|
||||
border: none;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
border-radius: 14px;
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
cursor: pointer;
|
||||
}
|
||||
&::-ms-track {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
&::-ms-fill-lower {
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
border: none;
|
||||
}
|
||||
&::-ms-fill-upper {
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
border: none;
|
||||
}
|
||||
&::-ms-thumb {
|
||||
border: none;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
border-radius: 14px;
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
cursor: pointer;
|
||||
}
|
||||
&:focus::-ms-fill-lower {
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
}
|
||||
&:focus::-ms-fill-upper {
|
||||
@include th {
|
||||
background: text-color();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
$base-font-family: system, -apple-system, ".SFNSDisplay-Regular", "Helvetica Neue", "Helvetica", "Roboto", "Arial", sans-serif;
|
||||
$font-family-text-thin: system, -apple-system, ".SFNSText-Light", "Helvetica Neue", "Helvetica", "Roboto", "Arial", sans-serif;
|
||||
$heading-font-family: $base-font-family;
|
||||
$monospace-font-family: monaco,Consolas,"Lucida Console",monospace;
|
||||
|
||||
// Font Sizes
|
||||
$base-font-size: 12px;
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
<div class="gen">
|
||||
<input type="text" class="gen__input-small" id="gen__text-len" value="16" maxlength="2" size="2" />
|
||||
<label for="gen__text-len">symbols</label>
|
||||
<div>Length: <span class="gen__length-range-val"><%= length %></span></div>
|
||||
<input type="range" class="gen__length-range" value="16" min="2" max="32" />
|
||||
<div>
|
||||
<input type="checkbox" id="gen__check-upper" checked><label for="gen__check-upper">ABC</label>
|
||||
<input type="checkbox" id="gen__check-lower" checked><label for="gen__check-lower">abc</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="gen__check-digits" checked><label for="gen__check-digits">123</label>
|
||||
<input type="checkbox" id="gen__check-special"><label for="gen__check-special">!@#</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="gen__check-brackets"><label for="gen__check-brackets">({<</label>
|
||||
<input type="checkbox" id="gen__check-high"><label for="gen__check-high">äæ±</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="gen__check-ambiguous"><label for="gen__check-ambiguous">0Oo</label>
|
||||
<div class="gen__check"><input type="checkbox" id="gen__check-upper"
|
||||
data-id="upper" <%= upper ? 'checked' : '' %>><label for="gen__check-upper">ABC</label></div>
|
||||
<div class="gen__check"><input type="checkbox" id="gen__check-lower"
|
||||
data-id="lower" <%= lower ? 'checked' : '' %>><label for="gen__check-lower">abc</label></div>
|
||||
<div class="gen__check"><input type="checkbox" id="gen__check-digits"
|
||||
data-id="digits" <%= digits ? 'checked' : '' %>><label for="gen__check-digits">123</label></div>
|
||||
<div class="gen__check"><input type="checkbox" id="gen__check-special"
|
||||
data-id="special" <%= special ? 'checked' : '' %>><label for="gen__check-special">!@#</label></div>
|
||||
<div class="gen__check"><input type="checkbox" id="gen__check-brackets"
|
||||
data-id="brackets" <%= brackets ? 'checked' : '' %>><label for="gen__check-brackets">({<</label></div>
|
||||
<div class="gen__check"><input type="checkbox" id="gen__check-high"
|
||||
data-id="high" <%= high ? 'checked' : '' %>><label for="gen__check-high">äæ±</label></div>
|
||||
<div class="gen__check"><input type="checkbox" id="gen__check-ambiguous"
|
||||
data-id="ambiguous" <%= ambiguous ? 'checked' : '' %>><label for="gen__check-ambiguous">0Oo</label></div>
|
||||
</div>
|
||||
<div class="gen__result">password</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue