* Refactor

+ Menu to create or read a password
+ New loader
This commit is contained in:
2019-10-27 00:06:51 +02:00
parent c258d995cf
commit 08af91f48c
14 changed files with 354 additions and 76 deletions

View File

@@ -27,7 +27,7 @@ ProtonMail|mail_pw123|klier.nicolas@protonmail.com||
These characters are reserved and cannot be used for any fields: `|%§`
### Compression
It is possible to compress QR-Codes. Instead of writing all data to the QR-Code you can write random strings (key) to it. OffPass itself holds a database of those random string and the corresponding encrypted value.
It is possible to compress QR-Codes. Instead of writing all data to the QR-Code you can write random strings (= key) to it. OffPass itself holds a database of those random strings and the corresponding encrypted value.
The program generates a `session key` (length of 10 characters) which is unique for each QR-Code. This session key is stored on the QR-Code and is used to encrypt the raw values in database. So not even If someone stells your database he wouldn't be able to read your compressed strings.
@@ -41,7 +41,7 @@ For example:
```
This can has two advantages:
* An attacker can't read compressed values (he would need the database)
* An attacker can't read compressed values If he is able to decrypt one QR-Code (he would need the database)
* You can get more data on one QR-Code
But one disadvantage:

40
src/css/choose.css Normal file
View File

@@ -0,0 +1,40 @@
.options {
display: grid;
grid-template-columns: .5fr 300px 300px .5fr;
grid-template-rows: .7fr;
column-gap: 50px;
position: absolute;
margin: 0 auto;
width: 100%;
height: 80%;
}
.options div {
transition: .2s ease-in-out;
background-color: rgba(255, 255, 255, 0);
grid-row: 2;
width: 300px;
height: 300px;
padding-top: 90px;
border: 1px rgba(255, 255, 255, 0.3) solid;
cursor: pointer;
}
.options div:hover {
background-color: rgba(255, 255, 255, .2);
border: 1px rgba(255, 255, 255, 0.8) solid;
}
.options div i {
font-size: 64pt;
}
#create {
grid-row: 1;
grid-column: 2;
float: right;
}
#scan {
grid-row: 1;
grid-column: 3;
}

45
src/css/create.css Normal file
View File

@@ -0,0 +1,45 @@
#create_setup {
position: absolute !important;
height: 100%;
}
#create_setup * {
text-align: center;
}
#create_setup .options {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: .25fr .25fr .25fr;
row-gap: 50px;
column-gap: 50px;
margin-left: 50px;
width: calc(100% - 100px);
}
#name {
grid-column: 1;
grid-row: 1;
}
#url {
grid-column: 2 / 4;
grid-row: 1;
}
#email {
grid-column: 1;
grid-row: 2;
}
#password {
grid-column: 1 / 4;
grid-row: 3;
display: inline-block;
border: 1px solid white;
}
#password input {
border: none;
}
#password i {
border-left: none;
}

View File

@@ -9,7 +9,7 @@ body {
/*background-color: #2A2C2B;*/
overflow: hidden;
}
h1 {
h1, h3 {
font-family: 'Oxygen', sans-serif;
color: #fff;
}
@@ -24,6 +24,35 @@ a {
text-decoration: none;
font-weight: bold;
font-family: 'Source Sans Pro', sans-serif;
user-select: none;
}
i {
color: white;
}
input {
background-color: transparent;
border: 1px rgb(200, 200, 200, .5) solid;
background-color: rgba(29, 29, 29, 0.2);
color: rgb(200, 200, 200, .6);
padding: 10px;
transition: .1s ease-in-out;
}
input:disabled {
border: 1px rgba(200, 200, 200, 0.7) solid;
background-color: rgba(78, 78, 78, 0.4) ;
}
input::placeholder {
color: rgb(207, 207, 207, .8);
}
input:focus {
border: 1px rgb(200, 200, 200, 1) solid;
background-color: rgba(29, 29, 29, 0.3);
color: rgb(200, 200, 200, 1);
outline: none;
}
#taskbar {
@@ -52,6 +81,42 @@ a {
position: absolute;
}
/* Error */
#error {
position: absolute;
display: flex;
bottom: -350px;
width: auto;
height: 55px;
padding-left: 10px;
padding-right: 20px;
backdrop-filter: blur(30px);
background-color: rgba(100, 0, 0, 0.6);
border-radius: 15px;
}
#error i {
font-size: 20pt;
padding: 14px;
color: rgb(255, 139, 139);
}
#error p {
padding-bottom: 20px;
}
.fill {
width: 100%;
}
/* Containers that are in the main view */
.main {
height: 100%;
width: 100%;
margin-top: 50px;
}
.main * {
text-align: center;
}
.options {
width: calc(100% - 100px);
}

View File

@@ -38,28 +38,6 @@
font-weight: 200;
}
/* Error */
#error {
position: absolute;
display: flex;
bottom: -350px;
width: auto;
height: 55px;
padding-left: 10px;
padding-right: 20px;
backdrop-filter: blur(30px);
background-color: rgba(100, 0, 0, 0.6);
border-radius: 15px;
}
#error i {
font-size: 20pt;
padding: 14px;
color: rgb(255, 139, 139);
}
#error p {
padding-bottom: 20px;
}
.show {
animation: showpass 1s;
opacity: 1 !important;

View File

@@ -2,27 +2,8 @@
text-align: center;
vertical-align: middle;
padding-top: calc(10% + 50px);
width: 100%;
height: 100%;
}
#master_prompt input {
margin-top: 50px;
background-color: transparent;
border: none;
border-bottom: 1px solid white;
color: white;
padding: 10px;
transition: .2s ease-in-out;
}
#master_prompt input::placeholder {
color: rgb(207, 207, 207);
}
#master_prompt input:focus {
border-bottom-width: 3px;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
#master_prompt a {
line-height: 5;
line-height: 15;
font-size: 13pt;
}

38
src/html/choose.html Normal file
View File

@@ -0,0 +1,38 @@
<div id="choose" class="main" style="left: 150%;">
<link href="../css/choose.css" rel="stylesheet">
<script>
window.$ = window.jQuery = require('../assets/jquery-3.4.1.min.js');
function scanClick() {
console.log("here");
await loader.load('scanner');
$('#scan').animate({
left: '-150'
});
$('#wait').animate({
left: '0'
}, 300);
const done = await startWatching();
$('#preview').animate({
left: '0'
}, 600);
}
</script>
<h1>Please choose your action</h1>
<div class="options">
<div id="create" onclick="scanClick()">
<i class="fas fa-plus" onclick="scanClick()"></i>
<h3>Create</h3>
<p>Create a new password and print it out.</p>
</div>
<div id="scan">
<i class="fas fa-qrcode"></i>
<h3>Scan</h3>
<p>Scan your existing password</p>
</div>
</div>
</div>

View File

@@ -1,3 +1,23 @@
<div id="create_setup">
<div id="create_setup" class="main" style="left: 150%;">
<link rel="stylesheet" href="../css/create.css">
<h1>New QR-Code</h1>
<div class="options">
<input placeholder="Name" id="name">
<input placeholder="Login URL (example: https://example.com/login, https://login.example.com)" id="url">
<input placeholder="E-Mail" id="email">
<input type="checkbox" id="compression">
<select title="Hash Algorithm">
<option selected>Argon2i</option>
<!--<option>Argon2d</option>-->
<!--<option>Argon2id</option>-->
<!--<option>Scrypt</option>-->
<option>Bcrypt</option>
<option>SHA-512</option>
</select>
<div id="password">
<input placeholder="Password">
<i class="fas fa-random"></i>
</div>
</div>
<script src="../js/create.js"></script>
</div>

View File

@@ -12,7 +12,6 @@
<link href="../assets/animate.css" rel="stylesheet">
<link href="../css/global.css" rel="stylesheet">
<link href="../css/start.css" rel="stylesheet">
<link href="../css/scanner.css" rel="stylesheet">
</head>
<body>
<div id="taskbar">
@@ -21,52 +20,48 @@
<i id="close" class="fas fa-times" onclick="remote.BrowserWindow.getFocusedWindow().close()"></i>
</div>
<div id="content">
<div id="master_prompt">
<div id="master_prompt" class="main">
<h1>Welcome to OffPass</h1>
<p>Please enter your master password for decryption</p>
<p>Please enter your master password</p>
<input id="master" placeholder="Master password..." type="password" autofocus><br>
<a href="#">Or create a new QR-Code</a>
</div>
<div id="wait">
<h1>Wait for camera...</h1>
</div>
<div id="scanned" class="animated">
<h1>Password: <span id="password"></span></h1>
</div>
<div id="error">
<i class="fas fa-exclamation-circle"></i><p>Decryption faild. Maybe wrong password?</p>
<i class="fas fa-exclamation-circle"></i>
<p></p>
</div>
<video id="preview"></video>
</div>
<script>
window.$ = window.jQuery = require('../assets/jquery-3.4.1.min.js');
const { Loader } = require('../js/loader.js');
const { remote } = require('electron');
const pgp = require('openpgp');
let master_password = "";
const loader = new Loader(document.getElementById('content'));
// Slide
$('#master').keypress(async (e) => {
if (e.which == 13) {
master_password = $('#master').val();
$('#master_prompt').animate({
left: '-150%'
}, 600, () => {
$(this).css('left', '150%');
});
$('#wait').animate({
}, 300, async () => {
await loader.load('choose');
$('#choose').animate({
left: '0'
}, 300);
const done = await startWatching();
$('#preview').animate({
left: '0'
}, 600);
});
}
});
$('#master_prompt a').click((e) => {
$('#master_prompt a').click(async (e) => {
await loader.load('create');
$('#master_prompt').animate({
left: '-150%'
});

11
src/html/scanner.html Normal file
View File

@@ -0,0 +1,11 @@
<!-- Styles -->
<link href="../css/scanner.css" rel="stylesheet">
<div id="wait">
<h1>Wait for camera...</h1>
</div>
<video id="preview"></video>
<div id="scanned" class="animated">
<h1>Password: <span id="password"></span></h1>
</div>

22
src/js/choose.js Normal file
View File

@@ -0,0 +1,22 @@
console.log("here")
window.$ = window.jQuery = require('../assets/jquery-3.4.1.min.js');
$('#scan').click(async (e) => {
console.log("here")
await loader.load('scanner');
$('#scan').animate({
left: '-150'
});
$('#wait').animate({
left: '0'
}, 300);
const done = await startWatching();
$('#preview').animate({
left: '0'
}, 600);
})

0
src/js/create.js Normal file
View File

View File

@@ -1,10 +1,68 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var fs_1 = require("fs");
var path_1 = require("path");
/**
* This script loads or unloads different modules present in src/js
* This script loads or unloads different modules present in src/html
*/
class Loader {
index = null;
constructor(index) {
var Loader = /** @class */ (function () {
function Loader(content) {
this.content = null;
this.content = content;
}
Loader.prototype.load = function (module_name) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
return [2 /*return*/, new Promise(function (resolve, reject) {
fs_1.readFile(path_1.resolve("src/html/", module_name + ".html"), 'utf8', function (err, data) {
if (err)
console.error("Error while loading module:", module_name, "(", path_1.resolve("src/html/", module_name + ".html"), ")");
else {
_this.content.innerHTML += data;
}
resolve(true);
});
})];
});
});
};
return Loader;
}());
exports.Loader = Loader;

25
src/js/loader.ts Normal file
View File

@@ -0,0 +1,25 @@
import { readFile } from "fs";
import { resolve as res } from "path";
/**
* This script loads or unloads different modules present in src/html
*/
export class Loader {
content: HTMLDivElement = null;
constructor(content: HTMLDivElement) {
this.content = content;
}
async load(module_name: string) {
return new Promise<Boolean>((resolve, reject) => {
readFile(res("src/html/", module_name + ".html"), 'utf8', (err, data) => {
if (err) console.error("Error while loading module:", module_name, "(", res("src/html/", module_name + ".html"), ")");
else {
this.content.innerHTML += data;
}
resolve(true);
})
});
}
}