diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index bbe1079..9fec453 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -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. \ No newline at end of file +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. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bca77e9..19b1fae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 759b0ea..e99131f 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/css/choose.css b/src/css/choose.css index 9105ddb..ba4b51e 100644 --- a/src/css/choose.css +++ b/src/css/choose.css @@ -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 { diff --git a/src/css/create.css b/src/css/create.css index 12a0128..3167099 100644 --- a/src/css/create.css +++ b/src/css/create.css @@ -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; } \ No newline at end of file diff --git a/src/css/global.css b/src/css/global.css index a325026..19b5be1 100644 --- a/src/css/global.css +++ b/src/css/global.css @@ -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; diff --git a/src/css/scanner.css b/src/css/scanner.css index 6dcdbe1..92576f6 100644 --- a/src/css/scanner.css +++ b/src/css/scanner.css @@ -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 { diff --git a/src/css/welcome.css b/src/css/welcome.css new file mode 100644 index 0000000..f986d63 --- /dev/null +++ b/src/css/welcome.css @@ -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; +} \ No newline at end of file diff --git a/src/html/create.html b/src/html/create.html index 26e2811..e0b879a 100644 --- a/src/html/create.html +++ b/src/html/create.html @@ -1,12 +1,24 @@
-

New QR-Code

+ + + + + + - + - - +
+ +
+
+
+ + -
- - -
- \ No newline at end of file diff --git a/src/html/index.html b/src/html/index.html index a7ef490..3f8f72e 100644 --- a/src/html/index.html +++ b/src/html/index.html @@ -5,6 +5,8 @@ OffPass + + @@ -24,8 +26,6 @@

Welcome to OffPass

Please enter your master password


- - Or create a new QR-Code
@@ -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) => { @@ -85,55 +100,7 @@ error.css('bottom', '-500px;') }, 5000); - } - - 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({ diff --git a/src/html/welcome.html b/src/html/welcome.html new file mode 100644 index 0000000..2c7b668 --- /dev/null +++ b/src/html/welcome.html @@ -0,0 +1,8 @@ +
+
+ +

Welcome

+

to OffPass, the next level of password storage.

+ Let's start +
+
\ No newline at end of file diff --git a/src/js/create.ts b/src/js/create.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/js/format.js b/src/js/format.js new file mode 100644 index 0000000..b2fea49 --- /dev/null +++ b/src/js/format.js @@ -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; diff --git a/src/js/format.ts b/src/js/format.ts new file mode 100644 index 0000000..ceeab79 --- /dev/null +++ b/src/js/format.ts @@ -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; +} + +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; + } +} \ No newline at end of file diff --git a/src/js/loader.js b/src/js/loader.js index 3553e83..626ffbc 100644 --- a/src/js/loader.js +++ b/src/js/loader.js @@ -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; diff --git a/src/js/loader.ts b/src/js/loader.ts index 18c051c..5669b97 100644 --- a/src/js/loader.ts +++ b/src/js/loader.ts @@ -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) { @@ -46,6 +40,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: document.getElementById(module_name) }; @@ -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); }); } } \ No newline at end of file diff --git a/src/js/scanner.js b/src/js/scanner.js index e69de29..213b347 100644 --- a/src/js/scanner.js +++ b/src/js/scanner.js @@ -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"); + }) + }); + }) +} \ No newline at end of file diff --git a/src/js/welcome.js b/src/js/welcome.js new file mode 100644 index 0000000..6ac9896 --- /dev/null +++ b/src/js/welcome.js @@ -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'); +}); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 7a73a41..cbf48e3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,2 +1,6 @@ { + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "module": "commonjs" + } } \ No newline at end of file