+ Format handler

* Creator view updated
* Some small changes
This commit is contained in:
2019-10-31 11:02:09 +01:00
parent 945b4d809a
commit 3bb2d742c4
19 changed files with 509 additions and 129 deletions

View File

@@ -16,13 +16,13 @@ Attackers are using password dictionaries with more then one million passwords.
## QR-Code schema ## 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.** 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: 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: `|%§` 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: 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: 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: 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
View File

@@ -42,6 +42,15 @@
"@types/node": "*" "@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": { "@types/node": {
"version": "12.11.6", "version": "12.11.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.6.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.6.tgz",
@@ -57,6 +66,12 @@
"@types/bn.js": "*" "@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": { "asn1.js": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz",
@@ -67,6 +82,32 @@
"minimalistic-assert": "^1.0.0" "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": { "bn.js": {
"version": "4.11.8", "version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
@@ -131,6 +172,11 @@
"typedarray": "^0.0.6" "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": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "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==", "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==",
"dev": true "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": { "extract-zip": {
"version": "1.6.7", "version": "1.6.7",
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
@@ -242,6 +293,16 @@
"universalify": "^0.1.0" "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": { "get-stream": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "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", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" "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": { "isarray": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -321,6 +393,11 @@
"json-buffer": "3.0.0" "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": { "lowercase-keys": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -446,6 +523,11 @@
"util-deprecate": "~1.0.1" "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": { "responselike": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
@@ -470,11 +552,21 @@
"truncate-utf8-bytes": "^1.0.0" "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": { "slide": {
"version": "1.1.6", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
"integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" "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": { "string_decoder": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -541,6 +633,19 @@
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true "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": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",

View File

@@ -4,16 +4,17 @@
"description": "OffPass, a special password manager. All your passwords are not stored in an encrypted container but offline.", "description": "OffPass, a special password manager. All your passwords are not stored in an encrypted container but offline.",
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"instascan": "^1.0.0",
"openpgp": "^4.6.2" "openpgp": "^4.6.2"
}, },
"devDependencies": { "devDependencies": {
"@types/jquery": "^3.3.31",
"@types/openpgp": "^4.4.7", "@types/openpgp": "^4.4.7",
"electron": "^7.0.0" "electron": "^7.0.0"
}, },
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"start": "tsc && electron src/main.js", "start": "tsc && electron src/main.js"
"clean": "del /S src\\js\\*.js && del src\\*.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -21,8 +21,10 @@
} }
.options div:hover { .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); 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 { .options div i {

View File

@@ -7,39 +7,40 @@
} }
#create_setup .options { #create_setup .options {
display: grid; display: grid;
grid-template-columns: 1fr 1fr 1fr; grid-template-columns: .2fr 1fr;
grid-template-rows: .25fr .25fr .25fr; grid-template-rows: repeat(8, 1fr);
row-gap: 50px; row-gap: 20px;
column-gap: 50px; column-gap: 90px;
margin-left: 50px; margin-left: 50px;
width: calc(100% - 100px); 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 { #name {
grid-column: 1;
grid-row: 1; grid-row: 1;
} }
#username {
#url {
grid-column: 2 / 4;
grid-row: 1;
}
#email {
grid-column: 1;
grid-row: 2; grid-row: 2;
} }
#email {
#password {
grid-column: 1 / 4;
grid-row: 3; grid-row: 3;
display: inline-block;
border: 1px solid white;
} }
#password input { #password {
border: none; grid-row: 4;
width: 100%;
} }
#password i { #url {
grid-row: 5;
border-left: none; }
#algorithm {
grid-row: 6;
} }

View File

@@ -9,12 +9,13 @@ body {
/*background-color: #2A2C2B;*/ /*background-color: #2A2C2B;*/
overflow: hidden; overflow: hidden;
} }
h1, h3 { h1, h3 {
font-family: 'Oxygen', sans-serif; font-family: 'Oxygen', sans-serif;
color: #fff; color: #fff;
} }
p, span { p, span, label {
font-family: 'Source Sans Pro', sans-serif; font-family: 'Source Sans Pro', sans-serif;
color: #fff; color: #fff;
} }
@@ -55,6 +56,28 @@ input:focus {
outline: none; 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 { #taskbar {
display: flex; display: flex;
position: absolute; position: absolute;

View File

@@ -28,14 +28,14 @@
z-index: -5; z-index: -5;
opacity: 0; opacity: 0;
padding-left: 20px; padding-left: 20px;
backdrop-filter: blur(20px); backdrop-filter: blur(50px);
background: linear-gradient(0deg, rgba(0,0,0,.75) 80%, rgba(94,94,94,.75) 100%); background-color: rgba(0,0,0,0.4);
box-shadow: 0px -10px 34px -10px rgba(0,0,0,0.75); box-shadow: 0px -10px 34px -10px rgba(0,0,0,0.75);
} }
#password { #password {
font-family: 'Consolas'; font-family: 'Consolas';
font-weight: 200; font-weight: 100;
} }
.show { .show {

29
src/css/welcome.css Normal file
View 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;
}

View File

@@ -1,12 +1,24 @@
<div id="create_setup" class="main" style="left: 150%;"> <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"> <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="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 placeholder="E-Mail" id="email">
<input type="checkbox" id="compression"> <div id="password" class="inputico">
<select title="Hash Algorithm"> <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 selected>Argon2i</option>
<!--<option>Argon2d</option>--> <!--<option>Argon2d</option>-->
<!--<option>Argon2id</option>--> <!--<option>Argon2id</option>-->
@@ -14,10 +26,5 @@
<option>Bcrypt</option> <option>Bcrypt</option>
<option>SHA-512</option> <option>SHA-512</option>
</select> </select>
<div id="password">
<input placeholder="Password">
<i class="fas fa-random"></i>
</div> </div>
</div> </div>
<script src="../js/create.js"></script>
</div>

View File

@@ -5,6 +5,8 @@
<title>OffPass</title> <title>OffPass</title>
<script type="text/javascript" src="../assets/instascan.min.js"></script> <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=Source+Sans+Pro&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Oxygen:700&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> <h1>Welcome to OffPass</h1>
<p>Please enter your master password</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>
</div> </div>
<div id="error"> <div id="error">
@@ -38,11 +38,26 @@
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 { Loader } = require('../js/loader.js');
const { Format } = require('../js/format.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')); 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 // Slide
$('#master').keypress(async (e) => { $('#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) { function slide_left(from, to, duration = 300) {
$('#' + from).animate({ $('#' + from).animate({
left: '-150%' left: '-150%'

8
src/html/welcome.html Normal file
View 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
View File

81
src/js/format.js Normal file
View 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
View 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;
}
}

View File

@@ -61,11 +61,6 @@ var Loader = /** @class */ (function () {
css.setAttribute("href", "../css/" + module_name + ".css"); css.setAttribute("href", "../css/" + module_name + ".css");
_this.head.appendChild(css); _this.head.appendChild(css);
var html_path = path_1.resolve("src/html/", module_name + ".html"); 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 // Load html file
fs_1.readFile(html_path, 'utf8', function (err, data) { fs_1.readFile(html_path, 'utf8', function (err, data) {
if (err) { if (err) {
@@ -74,6 +69,11 @@ var Loader = /** @class */ (function () {
} }
else { else {
_this.content.innerHTML += data; _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 // Push to loaded modules
var mod = { name: module_name, js: js, css: css, html: document.getElementById(module_name) }; var mod = { name: module_name, js: js, css: css, html: document.getElementById(module_name) };
_this.modules.push(mod); _this.modules.push(mod);
@@ -85,22 +85,15 @@ var Loader = /** @class */ (function () {
}); });
}; };
Loader.prototype.unload = function (module_name) { Loader.prototype.unload = function (module_name) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
this.modules.forEach(function (element) { this.modules.forEach(function (element) {
if (element.name == module_name) { if (element.name == module_name) {
console.log(element); 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.html.remove();
element.css.remove(); element.css.remove();
element.js.remove(); element.js.remove();
return;
} }
}); console.error("Tried to remove module which is not loaded:", module_name);
return [2 /*return*/];
});
}); });
}; };
return Loader; return Loader;

View File

@@ -32,12 +32,6 @@ export class Loader {
const html_path: string = res("src/html/", module_name + ".html"); 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 // Load html file
readFile(html_path, 'utf8', (err, data) => { readFile(html_path, 'utf8', (err, data) => {
if (err) { if (err) {
@@ -47,6 +41,12 @@ export class Loader {
else { else {
this.content.innerHTML += data; 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 // Push to loaded modules
const mod: IModules = { name: module_name, js: js, css: css, html: <HTMLDivElement>document.getElementById(module_name) }; const mod: IModules = { name: module_name, js: js, css: css, html: <HTMLDivElement>document.getElementById(module_name) };
this.modules.push(mod); this.modules.push(mod);
@@ -57,18 +57,17 @@ export class Loader {
}); });
} }
async unload(module_name) { unload(module_name) {
this.modules.forEach(element => { this.modules.forEach(element => {
if (element.name == module_name) { if (element.name == module_name) {
console.log(element); 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.html.remove();
element.css.remove(); element.css.remove();
element.js.remove(); element.js.remove();
return;
} }
console.error("Tried to remove module which is not loaded:", module_name);
}); });
} }
} }

View File

@@ -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
View 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');
});

View File

@@ -1,2 +1,6 @@
{ {
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"module": "commonjs"
}
} }