* Refactor
+ Menu to create or read a password + New loader
This commit is contained in:
@@ -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
40
src/css/choose.css
Normal 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
45
src/css/create.css
Normal 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
38
src/html/choose.html
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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
11
src/html/scanner.html
Normal 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
22
src/js/choose.js
Normal 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
0
src/js/create.js
Normal file
@@ -1,10 +1,68 @@
|
||||
/**
|
||||
* This script loads or unloads different modules present in src/js
|
||||
*/
|
||||
class Loader {
|
||||
index = null;
|
||||
|
||||
constructor(index) {
|
||||
|
||||
"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/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
25
src/js/loader.ts
Normal 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);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user