+ Format handler
* Creator view updated * Some small changes
This commit is contained in:
@@ -16,13 +16,13 @@ Attackers are using password dictionaries with more then one million passwords.
|
||||
## QR-Code schema
|
||||
An OffPass QR-Code must follow this data schema or else OffPass wouldn't be able to read it. **The following examples are data after decryption.**
|
||||
```
|
||||
name|password|email|website_url|(custom1)data1|(custom2)data2
|
||||
name|username|password|email|website_url|(custom1)data1|(custom2)data2
|
||||
```
|
||||
Als Beispiel:
|
||||
```
|
||||
Main Steam Account|super_secret_example123|info@example.de|https://store.steampowered.com/login/|(2fa_backup)R1337
|
||||
Main Steam Account|mondei1|super_secret_example123|info@example.de|https://store.steampowered.com/login/|(2fa_backup)R1337
|
||||
|
||||
ProtonMail|mail_pw123|klier.nicolas@protonmail.com||
|
||||
ProtonMail||mail_pw123|klier.nicolas@protonmail.com||
|
||||
```
|
||||
These characters are reserved and cannot be used for any fields: `|%§`
|
||||
|
||||
@@ -35,9 +35,9 @@ The compression key is stored like that: `§key`, the decryption key is stored l
|
||||
|
||||
For example:
|
||||
```
|
||||
%session_key%§xa|passwords_not2134|email_too@example.com|§q|(§a)§gh|(uncompressed)value
|
||||
%session_key%§xa|mondei1|passwords_not2134|email_too@example.com|§q|(§a)§gh|(uncompressed)value
|
||||
|
||||
-> Google|passwords_not2134|email_either@example.com|https://accounts.google.com|(2fa_backup)245131,...|(uncompressed)value
|
||||
-> Google|mondei1|passwords_not2134|email_either@example.com|https://accounts.google.com|(2fa_backup)245131,...|(uncompressed)value
|
||||
```
|
||||
|
||||
This can has two advantages:
|
||||
@@ -51,7 +51,7 @@ But one disadvantage:
|
||||
OffPass will first look if the scanned QR-Code is actually an OffPass QR-Code. This is done by checking the first three charcters:
|
||||
|
||||
```
|
||||
op:jA0ECQMC+t514sews8e70jsBw4SWsYYgPGzi5Ps0OGr8/tVGngopmHDQpSpMkNtkWZU573zNsFyk VVN3elnAY0D+EIIzTpKxq0F3fQ==
|
||||
op1:jA0ECQMC+t514sews8e70jsBw4SWsYYgPGzi5Ps0OGr8/tVGngopmHDQpSpMkNtkWZU573zNsFykVVN3elnAY0D+EIIzTpKxq0F3fQ==
|
||||
```
|
||||
|
||||
This `op:` tells the program that this is actully a OffPass QR-Code. If this is not present, OffPass will abort further steps and notify the user that this is not an OffPass QR-Code.
|
||||
This `op1:` tells the program that this is actully a OffPass QR-Code and which version. If this is not present, OffPass will abort further steps and notify the user that this is not an OffPass QR-Code.
|
||||
105
package-lock.json
generated
105
package-lock.json
generated
@@ -42,6 +42,15 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/jquery": {
|
||||
"version": "3.3.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.3.31.tgz",
|
||||
"integrity": "sha512-Lz4BAJihoFw5nRzKvg4nawXPzutkv7wmfQ5121avptaSIXlDNJCUuxZxX/G+9EVidZGuO0UBlk+YjKbwRKJigg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/sizzle": "*"
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "12.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.6.tgz",
|
||||
@@ -57,6 +66,12 @@
|
||||
"@types/bn.js": "*"
|
||||
}
|
||||
},
|
||||
"@types/sizzle": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz",
|
||||
"integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==",
|
||||
"dev": true
|
||||
},
|
||||
"asn1.js": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz",
|
||||
@@ -67,6 +82,32 @@
|
||||
"minimalistic-assert": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"babel-polyfill": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
|
||||
"integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
|
||||
"requires": {
|
||||
"babel-runtime": "^6.26.0",
|
||||
"core-js": "^2.5.0",
|
||||
"regenerator-runtime": "^0.10.5"
|
||||
}
|
||||
},
|
||||
"babel-runtime": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
|
||||
"requires": {
|
||||
"core-js": "^2.4.0",
|
||||
"regenerator-runtime": "^0.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"bn.js": {
|
||||
"version": "4.11.8",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
|
||||
@@ -131,6 +172,11 @@
|
||||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "2.6.10",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.10.tgz",
|
||||
"integrity": "sha512-I39t74+4t+zau64EN1fE5v2W31Adtc/REhzWN+gWRRXg6WH5qAsZm62DHpQ1+Yhe4047T55jvzz7MUqF/dBBlA=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
@@ -193,6 +239,11 @@
|
||||
"integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"extract-zip": {
|
||||
"version": "1.6.7",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
|
||||
@@ -242,6 +293,16 @@
|
||||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fsm-as-promised": {
|
||||
"version": "0.13.2",
|
||||
"resolved": "https://registry.npmjs.org/fsm-as-promised/-/fsm-as-promised-0.13.2.tgz",
|
||||
"integrity": "sha1-X04RCGgotwoZItx7T4HAgX1ugjg=",
|
||||
"requires": {
|
||||
"es6-promise": "^4.0.2",
|
||||
"lodash": "^4.16.2",
|
||||
"stampit": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
|
||||
@@ -291,6 +352,17 @@
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"instascan": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/instascan/-/instascan-1.0.0.tgz",
|
||||
"integrity": "sha1-3llJ9z9pj43/aN8Ke89pQqeZ7kQ=",
|
||||
"requires": {
|
||||
"babel-polyfill": "^6.9.1",
|
||||
"fsm-as-promised": "^0.13.0",
|
||||
"visibilityjs": "^1.2.3",
|
||||
"webrtc-adapter": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
@@ -321,6 +393,11 @@
|
||||
"json-buffer": "3.0.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
|
||||
},
|
||||
"lowercase-keys": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
|
||||
@@ -446,6 +523,11 @@
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.10.5",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
|
||||
},
|
||||
"responselike": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
|
||||
@@ -470,11 +552,21 @@
|
||||
"truncate-utf8-bytes": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"sdp": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/sdp/-/sdp-1.5.4.tgz",
|
||||
"integrity": "sha1-jgOPbdsUvXZa4fS1IW4SCUUR4NA="
|
||||
},
|
||||
"slide": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
|
||||
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
|
||||
},
|
||||
"stampit": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/stampit/-/stampit-3.2.1.tgz",
|
||||
"integrity": "sha1-lTpBpJRYoLKG/7HjydbOcDblids="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
@@ -541,6 +633,19 @@
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
},
|
||||
"visibilityjs": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/visibilityjs/-/visibilityjs-1.2.8.tgz",
|
||||
"integrity": "sha512-Y+aL3OUX88b+/VSmkmC2ApuLbf0grzbNLpCfIDSw3BzTU6PqcPsdgIOaw8b+eZoy+DdQqnVN3y/Evow9vQq9Ig=="
|
||||
},
|
||||
"webrtc-adapter": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-1.4.0.tgz",
|
||||
"integrity": "sha1-WCiaY9BUxls2+w7zieovbQx/XZg=",
|
||||
"requires": {
|
||||
"sdp": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
"description": "OffPass, a special password manager. All your passwords are not stored in an encrypted container but offline.",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"instascan": "^1.0.0",
|
||||
"openpgp": "^4.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jquery": "^3.3.31",
|
||||
"@types/openpgp": "^4.4.7",
|
||||
"electron": "^7.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "tsc && electron src/main.js",
|
||||
"clean": "del /S src\\js\\*.js && del src\\*.js"
|
||||
"start": "tsc && electron src/main.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
}
|
||||
|
||||
.options div:hover {
|
||||
transform: scale(1.02);
|
||||
box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.5);
|
||||
background-color: rgba(255, 255, 255, .2);
|
||||
border: 1px rgba(255, 255, 255, 0.8) solid;
|
||||
border: 1px rgba(255, 255, 255, 0.9) solid;
|
||||
}
|
||||
|
||||
.options div i {
|
||||
|
||||
@@ -7,39 +7,40 @@
|
||||
}
|
||||
#create_setup .options {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-rows: .25fr .25fr .25fr;
|
||||
row-gap: 50px;
|
||||
column-gap: 50px;
|
||||
grid-template-columns: .2fr 1fr;
|
||||
grid-template-rows: repeat(8, 1fr);
|
||||
row-gap: 20px;
|
||||
column-gap: 90px;
|
||||
margin-left: 50px;
|
||||
width: calc(100% - 100px);
|
||||
}
|
||||
|
||||
#name, #username, #url, #email, #password, #algorithm, #advanced {
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
label {
|
||||
grid-column: 1;
|
||||
line-height: 2;
|
||||
text-align: right !important;
|
||||
}
|
||||
|
||||
#name {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
#url {
|
||||
grid-column: 2 / 4;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
#email {
|
||||
grid-column: 1;
|
||||
#username {
|
||||
grid-row: 2;
|
||||
}
|
||||
|
||||
#password {
|
||||
grid-column: 1 / 4;
|
||||
#email {
|
||||
grid-row: 3;
|
||||
display: inline-block;
|
||||
border: 1px solid white;
|
||||
}
|
||||
#password input {
|
||||
border: none;
|
||||
#password {
|
||||
grid-row: 4;
|
||||
width: 100%;
|
||||
}
|
||||
#password i {
|
||||
|
||||
border-left: none;
|
||||
#url {
|
||||
grid-row: 5;
|
||||
}
|
||||
#algorithm {
|
||||
grid-row: 6;
|
||||
}
|
||||
@@ -9,12 +9,13 @@ body {
|
||||
/*background-color: #2A2C2B;*/
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h1, h3 {
|
||||
font-family: 'Oxygen', sans-serif;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
p, span {
|
||||
p, span, label {
|
||||
font-family: 'Source Sans Pro', sans-serif;
|
||||
color: #fff;
|
||||
}
|
||||
@@ -55,6 +56,28 @@ input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.inputico {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border: 1px solid white !important;
|
||||
}
|
||||
.inputico: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;
|
||||
}
|
||||
.inputico input {
|
||||
border: none !important;
|
||||
width: 97%;
|
||||
}
|
||||
.inputico i {
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
right:0;
|
||||
top:5px;
|
||||
}
|
||||
|
||||
#taskbar {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
|
||||
@@ -28,14 +28,14 @@
|
||||
z-index: -5;
|
||||
opacity: 0;
|
||||
padding-left: 20px;
|
||||
backdrop-filter: blur(20px);
|
||||
background: linear-gradient(0deg, rgba(0,0,0,.75) 80%, rgba(94,94,94,.75) 100%);
|
||||
backdrop-filter: blur(50px);
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
box-shadow: 0px -10px 34px -10px rgba(0,0,0,0.75);
|
||||
}
|
||||
|
||||
#password {
|
||||
font-family: 'Consolas';
|
||||
font-weight: 200;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
.show {
|
||||
|
||||
29
src/css/welcome.css
Normal file
29
src/css/welcome.css
Normal file
@@ -0,0 +1,29 @@
|
||||
#welcome {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
#welcome div {
|
||||
text-align: center;
|
||||
width: 100vw;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 15%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#welcome img {
|
||||
height: 166px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
#welcome a {
|
||||
font-size: 16pt;
|
||||
}
|
||||
#welcome i {
|
||||
padding-left: 20px;
|
||||
}
|
||||
@@ -1,12 +1,24 @@
|
||||
<div id="create_setup" class="main" style="left: 150%;">
|
||||
<link rel="stylesheet" href="../css/create.css">
|
||||
<h1>New QR-Code</h1>
|
||||
<div class="options">
|
||||
<label>Password Titel</label>
|
||||
<label>Username</label>
|
||||
<label>E-Mail</label>
|
||||
<label>Password</label>
|
||||
<label>Login URL</label>
|
||||
<label>Algorithm</label>
|
||||
<input placeholder="Name" id="name">
|
||||
<input placeholder="Login URL (example: https://example.com/login, https://login.example.com)" id="url">
|
||||
<input placeholder="Username" id="username">
|
||||
<input placeholder="E-Mail" id="email">
|
||||
<input type="checkbox" id="compression">
|
||||
<select title="Hash Algorithm">
|
||||
<div id="password" class="inputico">
|
||||
<input placeholder="Password">
|
||||
<div>
|
||||
<i class="fas fa-random"></i>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<input placeholder="Login URL (example: https://example.com/login, https://login.example.com)" id="url">
|
||||
<select title="Hash Algorithm" id="algorithm">
|
||||
<option selected>Argon2i</option>
|
||||
<!--<option>Argon2d</option>-->
|
||||
<!--<option>Argon2id</option>-->
|
||||
@@ -14,10 +26,5 @@
|
||||
<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>
|
||||
@@ -5,6 +5,8 @@
|
||||
<title>OffPass</title>
|
||||
|
||||
<script type="text/javascript" src="../assets/instascan.min.js"></script>
|
||||
<script type="text/javascript" src="../js/scanner.js"></script>
|
||||
<script type="text/javascript" src="../ts/format.js"></script>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Oxygen:700&display=swap" rel="stylesheet">
|
||||
@@ -24,8 +26,6 @@
|
||||
<h1>Welcome to OffPass</h1>
|
||||
<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="error">
|
||||
@@ -38,11 +38,26 @@
|
||||
window.$ = window.jQuery = require('../assets/jquery-3.4.1.min.js');
|
||||
|
||||
const { Loader } = require('../js/loader.js');
|
||||
const { Format } = require('../js/format.js');
|
||||
const { remote } = require('electron');
|
||||
const pgp = require('openpgp');
|
||||
let master_password = "";
|
||||
|
||||
const loader = new Loader(document.getElementById('content'));
|
||||
const format = new Format("%AzTka312K1%Google|mondei1|passwords_not2134|email_either@example.com|https://accounts.google.com|(2fa_backup)245131,...|(uncompressed)value");
|
||||
format.parse();
|
||||
|
||||
console.log(format.build({
|
||||
decryptionKey: "az35LKuJ$w",
|
||||
title: "Steam",
|
||||
password: "lol_my-password1412%$",
|
||||
custom: [
|
||||
{
|
||||
key: "2fa_secret",
|
||||
value: "R24829"
|
||||
}
|
||||
]
|
||||
}));
|
||||
|
||||
// Slide
|
||||
$('#master').keypress(async (e) => {
|
||||
@@ -87,54 +102,6 @@
|
||||
|
||||
}
|
||||
|
||||
async function startWatching() {
|
||||
return new Promise((resolve, reject) => {
|
||||
Instascan.Camera.getCameras().then(function (cameras) {
|
||||
if (cameras.length > 0) {
|
||||
scanner.start(cameras[0]);
|
||||
navigator.mediaDevices.getUserMedia({video: true}).then((stream) => {
|
||||
preview.srcObject = stream;
|
||||
resolve(true);
|
||||
})
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
}).catch(function (e) {
|
||||
showError("No camera found.");
|
||||
$('#wait').animate({
|
||||
left: '150%'
|
||||
}, 200);
|
||||
$('#master_prompt').animate({
|
||||
left: '0'
|
||||
}, 100);
|
||||
});
|
||||
|
||||
navigator.mediaDevices.getUserMedia({video: true});
|
||||
const preview = document.getElementById('preview');
|
||||
|
||||
let scanner = new Instascan.Scanner({ video: preview, mirror: false });
|
||||
|
||||
scanner.addListener('scan', async (content) => {
|
||||
content = "-----BEGIN PGP MESSAGE-----\n\n" + content + "\n-----END PGP MESSAGE-----";
|
||||
console.log(content)
|
||||
pgp.decrypt({
|
||||
message: await pgp.message.readArmored(content),
|
||||
passwords: [ master_password ],
|
||||
format: 'string'
|
||||
}).then((plaintext) => {
|
||||
const scanned = $('#scanned');
|
||||
scanned.css('top', '85%');
|
||||
scanned.css('z-index', '2');
|
||||
scanned.addClass("fadeInUp");
|
||||
$('#password').text(plaintext.data)
|
||||
console.log(plaintext.data);
|
||||
}).catch((err) => {
|
||||
if (err) showError("Wrong master password");
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
function slide_left(from, to, duration = 300) {
|
||||
$('#' + from).animate({
|
||||
left: '-150%'
|
||||
|
||||
8
src/html/welcome.html
Normal file
8
src/html/welcome.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<div id="welcome" class="animated fadeInUp">
|
||||
<div>
|
||||
<img src="../assets/icon.png">
|
||||
<h1>Welcome</h1>
|
||||
<p>to OffPass, the next level of password storage.</p>
|
||||
<a href="#">Let's start<i class="fas fa-arrow-right"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
0
src/js/create.ts
Normal file
0
src/js/create.ts
Normal file
81
src/js/format.js
Normal file
81
src/js/format.js
Normal file
@@ -0,0 +1,81 @@
|
||||
"use strict";
|
||||
/**
|
||||
* This script is responsible to handle the data stored on QR-Codes.
|
||||
* For detailed information, please take a look at DEVELOPMENT.md in
|
||||
* the projects root directory.
|
||||
*/
|
||||
exports.__esModule = true;
|
||||
var Format = /** @class */ (function () {
|
||||
/**
|
||||
* Format handler
|
||||
* @param text The unparsed text provided on a QR-Code
|
||||
*/
|
||||
function Format(text) {
|
||||
// Example: %session_key%§xa|mondei1|passwords_not2134|email_too@example.com|§q|(§a)§gh|(uncompressed)value
|
||||
// Google|mondei1|passwords_not2134|email_either@example.com|https://accounts.google.com|(2fa_backup)245131,...|(uncompressed)value
|
||||
this.text = null;
|
||||
this.format = {
|
||||
title: "",
|
||||
username: "",
|
||||
password: "",
|
||||
email: "",
|
||||
loginURL: null
|
||||
};
|
||||
this.text = text;
|
||||
}
|
||||
Format.prototype.isCompatible = function () {
|
||||
return true;
|
||||
};
|
||||
Format.prototype.decrypt = function () {
|
||||
if (this.isCompatible()) {
|
||||
}
|
||||
};
|
||||
Format.prototype.parse = function () {
|
||||
var parts = this.text.split('|');
|
||||
// Parse static values
|
||||
this.format.title = parts[0];
|
||||
// Check if a decryption key exists at the start
|
||||
if (this.format.title.startsWith('%')) {
|
||||
this.format.decryptionKey = "";
|
||||
// Extract
|
||||
for (var i = 1; i < this.format.title.length; i++) {
|
||||
var char = this.format.title.charAt(i);
|
||||
if (char != '%') {
|
||||
this.format.decryptionKey += char;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Remove decryption key from first value
|
||||
this.format.title = this.format.title.substr(this.format.decryptionKey.length + 2, this.format.title.length); // + 2 because of the two '%'
|
||||
}
|
||||
this.format.username = parts[1];
|
||||
this.format.password = parts[2];
|
||||
this.format.email = parts[3];
|
||||
this.format.loginURL = new URL(parts[4]);
|
||||
console.log(this.format);
|
||||
};
|
||||
Format.prototype.build = function (data) {
|
||||
if (data == undefined)
|
||||
data = this.format;
|
||||
var raw = "";
|
||||
if (data.decryptionKey != undefined) {
|
||||
raw += "%" + data.decryptionKey + "%";
|
||||
}
|
||||
raw += data.title + "|";
|
||||
raw += data.username + "|";
|
||||
raw += data.password + "|";
|
||||
raw += data.email + "|";
|
||||
raw += data.loginURL + "|";
|
||||
if (data.custom != undefined) {
|
||||
data.custom.forEach(function (element) {
|
||||
raw += "(" + element.key + ")" + element.value + "|";
|
||||
});
|
||||
}
|
||||
raw = raw.substr(0, raw.length - 1); // Remove the last |
|
||||
return raw;
|
||||
};
|
||||
return Format;
|
||||
}());
|
||||
exports.Format = Format;
|
||||
105
src/js/format.ts
Normal file
105
src/js/format.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* This script is responsible to handle the data stored on QR-Codes.
|
||||
* For detailed information, please take a look at DEVELOPMENT.md in
|
||||
* the projects root directory.
|
||||
*/
|
||||
|
||||
export interface ICustom {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface IFormat {
|
||||
decryptionKey?: string;
|
||||
title: string;
|
||||
username?: string;
|
||||
password: string;
|
||||
email?: string;
|
||||
loginURL?: URL;
|
||||
custom?: Array<ICustom>;
|
||||
}
|
||||
|
||||
export class Format {
|
||||
// Example: %session_key%§xa|mondei1|passwords_not2134|email_too@example.com|§q|(§a)§gh|(uncompressed)value
|
||||
// Google|mondei1|passwords_not2134|email_either@example.com|https://accounts.google.com|(2fa_backup)245131,...|(uncompressed)value
|
||||
text: string = null;
|
||||
format: IFormat = {
|
||||
title: "",
|
||||
username: "",
|
||||
password: "",
|
||||
email: "",
|
||||
loginURL: null
|
||||
};
|
||||
|
||||
/**
|
||||
* Format handler
|
||||
* @param text The unparsed text provided on a QR-Code
|
||||
*/
|
||||
constructor(text?: string) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
isCompatible(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
decrypt() {
|
||||
if(this.isCompatible()) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
parse() {
|
||||
const parts = this.text.split('|');
|
||||
|
||||
// Parse static values
|
||||
this.format.title = parts[0];
|
||||
|
||||
// Check if a decryption key exists at the start
|
||||
if(this.format.title.startsWith('%')) {
|
||||
this.format.decryptionKey = "";
|
||||
// Extract
|
||||
for(let i = 1; i < this.format.title.length; i++) {
|
||||
const char = this.format.title.charAt(i);
|
||||
|
||||
if (char != '%') {
|
||||
this.format.decryptionKey += char;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Remove decryption key from first value
|
||||
this.format.title = this.format.title.substr(this.format.decryptionKey.length + 2, this.format.title.length) // + 2 because of the two '%'
|
||||
}
|
||||
|
||||
this.format.username = parts[1];
|
||||
this.format.password = parts[2];
|
||||
this.format.email = parts[3];
|
||||
this.format.loginURL = new URL(parts[4]);
|
||||
|
||||
console.log(this.format);
|
||||
}
|
||||
|
||||
build(data?: IFormat): string {
|
||||
if (data == undefined) data = this.format;
|
||||
|
||||
let raw = "";
|
||||
if(data.decryptionKey != undefined) {
|
||||
raw += "%" + data.decryptionKey + "%";
|
||||
}
|
||||
raw += data.title + "|";
|
||||
raw += data.username + "|";
|
||||
raw += data.password + "|";
|
||||
raw += data.email + "|";
|
||||
raw += data.loginURL + "|";
|
||||
|
||||
if (data.custom != undefined) {
|
||||
data.custom.forEach(element => {
|
||||
raw += `(${element.key})${element.value}|`;
|
||||
});
|
||||
}
|
||||
raw = raw.substr(0, raw.length - 1); // Remove the last |
|
||||
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
@@ -61,11 +61,6 @@ var Loader = /** @class */ (function () {
|
||||
css.setAttribute("href", "../css/" + module_name + ".css");
|
||||
_this.head.appendChild(css);
|
||||
var html_path = path_1.resolve("src/html/", module_name + ".html");
|
||||
// Load js file
|
||||
var js = document.createElement("script");
|
||||
js.setAttribute("type", "text/javascript");
|
||||
js.setAttribute("src", "../js/" + module_name + ".js");
|
||||
_this.head.appendChild(js);
|
||||
// Load html file
|
||||
fs_1.readFile(html_path, 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
@@ -74,6 +69,11 @@ var Loader = /** @class */ (function () {
|
||||
}
|
||||
else {
|
||||
_this.content.innerHTML += data;
|
||||
// Load js file
|
||||
var js = document.createElement("script");
|
||||
js.setAttribute("type", "text/javascript");
|
||||
js.setAttribute("src", "../js/" + module_name + ".js");
|
||||
_this.head.appendChild(js);
|
||||
// Push to loaded modules
|
||||
var mod = { name: module_name, js: js, css: css, html: document.getElementById(module_name) };
|
||||
_this.modules.push(mod);
|
||||
@@ -85,22 +85,15 @@ var Loader = /** @class */ (function () {
|
||||
});
|
||||
};
|
||||
Loader.prototype.unload = function (module_name) {
|
||||
return __awaiter(this, void 0, void 0, function () {
|
||||
return __generator(this, function (_a) {
|
||||
this.modules.forEach(function (element) {
|
||||
if (element.name == module_name) {
|
||||
console.log(element);
|
||||
/*
|
||||
element.js.parentElement.removeChild(element.js);
|
||||
element.css.parentElement.removeChild(element.css);
|
||||
element.html.parentElement.removeChild(element.html);*/
|
||||
element.html.remove();
|
||||
element.css.remove();
|
||||
element.js.remove();
|
||||
}
|
||||
});
|
||||
return [2 /*return*/];
|
||||
});
|
||||
this.modules.forEach(function (element) {
|
||||
if (element.name == module_name) {
|
||||
console.log(element);
|
||||
element.html.remove();
|
||||
element.css.remove();
|
||||
element.js.remove();
|
||||
return;
|
||||
}
|
||||
console.error("Tried to remove module which is not loaded:", module_name);
|
||||
});
|
||||
};
|
||||
return Loader;
|
||||
|
||||
@@ -32,12 +32,6 @@ export class Loader {
|
||||
|
||||
const html_path: string = res("src/html/", module_name + ".html");
|
||||
|
||||
// Load js file
|
||||
const js = document.createElement("script");
|
||||
js.setAttribute("type", "text/javascript");
|
||||
js.setAttribute("src", "../js/" + module_name + ".js");
|
||||
this.head.appendChild(js);
|
||||
|
||||
// Load html file
|
||||
readFile(html_path, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
@@ -47,6 +41,12 @@ export class Loader {
|
||||
else {
|
||||
this.content.innerHTML += data;
|
||||
|
||||
// Load js file
|
||||
const js = document.createElement("script");
|
||||
js.setAttribute("type", "text/javascript");
|
||||
js.setAttribute("src", "../js/" + module_name + ".js");
|
||||
this.head.appendChild(js);
|
||||
|
||||
// Push to loaded modules
|
||||
const mod: IModules = { name: module_name, js: js, css: css, html: <HTMLDivElement>document.getElementById(module_name) };
|
||||
this.modules.push(mod);
|
||||
@@ -57,18 +57,17 @@ export class Loader {
|
||||
});
|
||||
}
|
||||
|
||||
async unload(module_name) {
|
||||
unload(module_name) {
|
||||
this.modules.forEach(element => {
|
||||
if (element.name == module_name) {
|
||||
console.log(element);
|
||||
/*
|
||||
element.js.parentElement.removeChild(element.js);
|
||||
element.css.parentElement.removeChild(element.css);
|
||||
element.html.parentElement.removeChild(element.html);*/
|
||||
|
||||
element.html.remove();
|
||||
element.css.remove();
|
||||
element.js.remove();
|
||||
return;
|
||||
}
|
||||
console.error("Tried to remove module which is not loaded:", module_name);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
async function startWatching() {
|
||||
return new Promise((resolve, reject) => {
|
||||
Instascan.Camera.getCameras().then(function (cameras) {
|
||||
if (cameras.length > 0) {
|
||||
scanner.start(cameras[0]);
|
||||
navigator.mediaDevices.getUserMedia({video: true}).then((stream) => {
|
||||
preview.srcObject = stream;
|
||||
resolve(true);
|
||||
})
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
}).catch(function (e) {
|
||||
showError("No camera found.");
|
||||
$('#wait').animate({
|
||||
left: '150%'
|
||||
}, 200);
|
||||
$('#master_prompt').animate({
|
||||
left: '0'
|
||||
}, 100);
|
||||
});
|
||||
|
||||
navigator.mediaDevices.getUserMedia({video: true});
|
||||
const preview = document.getElementById('preview');
|
||||
|
||||
let scanner = new Instascan.Scanner({ video: preview, mirror: false });
|
||||
|
||||
scanner.addListener('scan', async (content) => {
|
||||
content = "-----BEGIN PGP MESSAGE-----\n\n" + content + "\n-----END PGP MESSAGE-----";
|
||||
console.log(content)
|
||||
pgp.decrypt({
|
||||
message: await pgp.message.readArmored(content),
|
||||
passwords: [ master_password ],
|
||||
format: 'string'
|
||||
}).then((plaintext) => {
|
||||
const scanned = $('#scanned');
|
||||
scanned.css('top', '85%');
|
||||
scanned.css('z-index', '2');
|
||||
scanned.addClass("fadeInUp");
|
||||
$('#password').text(plaintext.data)
|
||||
console.log(plaintext.data);
|
||||
}).catch((err) => {
|
||||
if (err) showError("Wrong master password");
|
||||
})
|
||||
});
|
||||
})
|
||||
}
|
||||
8
src/js/welcome.js
Normal file
8
src/js/welcome.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const welcome_container = document.getElementById('welcome');
|
||||
|
||||
$('#welcome a').click((e) => {
|
||||
$('#master_prompt').css('left', '150%');
|
||||
$('#master_prompt').css('display', 'block');
|
||||
slide_left('welcome', 'master_prompt');
|
||||
$('#master_prompt').css('left', '0');
|
||||
});
|
||||
@@ -1,2 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user