* 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: `|%§` These characters are reserved and cannot be used for any fields: `|%§`
### Compression ### 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. 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: 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 * You can get more data on one QR-Code
But one disadvantage: 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;*/ /*background-color: #2A2C2B;*/
overflow: hidden; overflow: hidden;
} }
h1 { h1, h3 {
font-family: 'Oxygen', sans-serif; font-family: 'Oxygen', sans-serif;
color: #fff; color: #fff;
} }
@@ -24,6 +24,35 @@ a {
text-decoration: none; text-decoration: none;
font-weight: bold; font-weight: bold;
font-family: 'Source Sans Pro', sans-serif; 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 { #taskbar {
@@ -52,6 +81,42 @@ a {
position: absolute; 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 { .fill {
width: 100%; 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; 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 { .show {
animation: showpass 1s; animation: showpass 1s;
opacity: 1 !important; opacity: 1 !important;

View File

@@ -2,27 +2,8 @@
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
padding-top: calc(10% + 50px); 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 { #master_prompt a {
line-height: 5; line-height: 15;
font-size: 13pt; 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> <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> </div>

View File

@@ -12,7 +12,6 @@
<link href="../assets/animate.css" rel="stylesheet"> <link href="../assets/animate.css" rel="stylesheet">
<link href="../css/global.css" rel="stylesheet"> <link href="../css/global.css" rel="stylesheet">
<link href="../css/start.css" rel="stylesheet"> <link href="../css/start.css" rel="stylesheet">
<link href="../css/scanner.css" rel="stylesheet">
</head> </head>
<body> <body>
<div id="taskbar"> <div id="taskbar">
@@ -21,52 +20,48 @@
<i id="close" class="fas fa-times" onclick="remote.BrowserWindow.getFocusedWindow().close()"></i> <i id="close" class="fas fa-times" onclick="remote.BrowserWindow.getFocusedWindow().close()"></i>
</div> </div>
<div id="content"> <div id="content">
<div id="master_prompt"> <div id="master_prompt" class="main">
<h1>Welcome to OffPass</h1> <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> <input id="master" placeholder="Master password..." type="password" autofocus><br>
<a href="#">Or create a new QR-Code</a> <a href="#">Or create a new QR-Code</a>
</div> </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"> <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> </div>
<video id="preview"></video>
</div> </div>
<script> <script>
window.$ = window.jQuery = require('../assets/jquery-3.4.1.min.js'); window.$ = window.jQuery = require('../assets/jquery-3.4.1.min.js');
const { Loader } = require('../js/loader.js');
const { remote } = require('electron'); const { remote } = require('electron');
const pgp = require('openpgp'); const pgp = require('openpgp');
let master_password = ""; let master_password = "";
const loader = new Loader(document.getElementById('content'));
// Slide // Slide
$('#master').keypress(async (e) => { $('#master').keypress(async (e) => {
if (e.which == 13) { if (e.which == 13) {
master_password = $('#master').val(); master_password = $('#master').val();
$('#master_prompt').animate({ $('#master_prompt').animate({
left: '-150%' left: '-150%'
}, 600, () => { }, 300, async () => {
$(this).css('left', '150%'); await loader.load('choose');
$('#choose').animate({
left: '0'
}, 300);
}); });
$('#wait').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({ $('#master_prompt').animate({
left: '-150%' 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";
* This script loads or unloads different modules present in src/js var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
*/ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
class Loader { return new (P || (P = Promise))(function (resolve, reject) {
index = null; function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
constructor(index) { 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/html
*/
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);
})
});
}
}