Skip to content

Commit

Permalink
Argon2 and OTP fixes (#352)
Browse files Browse the repository at this point in the history
  • Loading branch information
subdavis authored Aug 9, 2024
1 parent 5917f5e commit efc2da0
Show file tree
Hide file tree
Showing 15 changed files with 77 additions and 123 deletions.
6 changes: 3 additions & 3 deletions background/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { Settings } from '$services/settings.js'
import { Notifications } from "$services/notifications";

function Background(protectedMemory, settings, notifications) {
console.log('Background worker registered');
console.log('Background worker registered.');
chrome.runtime.onInstalled.addListener(settings.upgrade);
chrome.runtime.onStartup.addListener(forgetStuff);

Expand Down Expand Up @@ -96,7 +96,7 @@ function Background(protectedMemory, settings, notifications) {
files: ["/dist/contentScripts/index.global.js"],
}, function(result) {
//script injected
console.log("injected")
console.log("Autofill script injected.")
chrome.tabs.sendMessage(message.tabId, {
m: "fillPassword",
u: message.u,
Expand Down Expand Up @@ -179,7 +179,7 @@ function Background(protectedMemory, settings, notifications) {
function clearClipboard() {
// No longer have access to document in this context.
// https://github.com/GoogleChrome/chrome-extensions-samples/tree/main/functional-samples/cookbook.offscreen-clipboard-write
console.log('Clearing clipboard');
console.info('Clearing clipboard');
// var clearClipboard = function(e) {
// e.clipboardData.setData('text/plain', "");
// e.preventDefault();
Expand Down
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,21 @@
"dev:background": "run-s build:background -- --mode development",
"dev:js": "run-s build:js -- --mode development",
"build": "cross-env NODE_ENV=production run-s clear build:web build:prepare build:background build:js",
"build:ff": "cross-env NODE_ENV=production TARGET=firefox run-s clear build:web build:prepare build:background build:js",
"build:ff": "cross-env NODE_ENV=production TARGET=firefox run-s clear build:web build:prepare build:background build:js",
"build:prepare": "esno scripts/prepare.ts",
"build:background": "vite build --config vite.config.background.mts",
"build:js": "vite build --config vite.config.content.mts",
"build:web": "vite build",
"pack:zip": "rimraf extension.zip && zip -r extension.zip extension/*"
},
"dependencies": {
"argon2-browser": "^1.18.0",
"axios": "^1.7.2",
"base64-arraybuffer": "^1.0.2",
"case": "^1.5.4",
"font-awesome": "^4.7.0",
"json-formatter-js": "^2.2.0",
"kdbxweb": "^1.2.4",
"kdbxweb": "^2.1.1",
"materialize-css": "^1.0.0",
"pako": "^1.0.6",
"vue": "2",
Expand All @@ -52,6 +53,7 @@
"npm-run-all": "^4.1.5",
"rimraf": "^6.0.1",
"sass": "^1.77.8",
"vite": "^5.3.5"
"vite": "^5.3.5",
"vite-plugin-wasm": "^3.3.0"
}
}
4 changes: 2 additions & 2 deletions scripts/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ function chromeManifestV3(): Manifest.WebExtensionManifest {
content_security_policy: {
extension_pages: isDev
// this is required on dev for Vite script to load
? `script-src \'self\' http://localhost:${port}; object-src \'self\'`
: 'script-src \'self\'; object-src \'self\''
? `script-src \'self\' \'wasm-unsafe-eval\' http://localhost:${port}; object-src \'self\'`
: 'script-src \'self\' \'wasm-unsafe-eval\'; object-src \'self\''
},
action,
"commands": {
Expand Down
6 changes: 2 additions & 4 deletions services/keepassHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function KeepassHeader() {
var VERSION_KDBX = 3;
if (h.sigKeePass != DBSIG_KEEPASS || (h.sigKeePassType != DBSIG_KDBX && h.sigKeePassType != DBSIG_KDBX_ALPHA && h.sigKeePassType != DBSIG_KDB && h.sigKeePassType != DBSIG_KDB_NEW)) {
//fail
console.log("Signature fail. sig 1:" + h.sigKeePass.toString(16) + ", sig2:" + h.sigKeePassType.toString(16));
console.error("Signature fail. sig 1:" + h.sigKeePass.toString(16) + ", sig2:" + h.sigKeePassType.toString(16));
throw new Error('This is not a valid KeePass file - file signature is not correct.')
}

Expand All @@ -39,8 +39,6 @@ function KeepassHeader() {
readKdbHeader(buf, 8, h);
}

//console.log(h);
//console.log("version: " + h.version.toString(16) + ", keyRounds: " + h.keyRounds);
return h;
}

Expand Down Expand Up @@ -96,7 +94,7 @@ function KeepassHeader() {
var len = descriptor.getUint16(1, littleEndian);

var dv = new DataView(buf, position + 3, len);
//console.log("fieldid " + fieldId + " found at " + position);

position += 3;
switch (fieldId) {
case 0: //end of header
Expand Down
2 changes: 1 addition & 1 deletion services/keepassReference.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import kdbxweb from 'kdbxweb';
import * as kdbxweb from 'kdbxweb';

function KeepassReference() {
"use strict";
Expand Down
47 changes: 27 additions & 20 deletions services/keepassService.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,30 @@ import * as Base64 from 'base64-arraybuffer'
import * as Case from 'case'
// import pako from 'pako'
import * as kdbxweb from 'kdbxweb'
import argon2 from 'argon2-browser/dist/argon2-bundled.min.js';

kdbxweb.CryptoEngine.setArgon2Impl((
password, salt,
memory, iterations, length, parallelism, type, version
) => {
console.log('Using argon2 implementation', password, salt, memory, iterations, length, parallelism, type, version);
return argon2.hash({
pass: new Uint8Array(password),
salt: new Uint8Array(salt),
time: iterations,
mem: memory,
hashLen: length,
parallelism,
type,
version,
}).then((v) => v.hash)
});

import { argon2 } from '@/lib/argon2.js'
import { parseUrl, getValidTokens } from '@/lib/utils.js'

function KeepassService(keepassHeader, settings, passwordFileStoreRegistry, keepassReference) {
var my = {};

var littleEndian = (function () {
var buffer = new ArrayBuffer(2);
new DataView(buffer).setInt16(0, 256, true);
return new Int16Array(buffer)[0] === 256;
})();

/**
* return Promise(arrayBufer)
*/
Expand All @@ -40,7 +51,7 @@ function KeepassService(keepassHeader, settings, passwordFileStoreRegistry, keep
} else if (masterPassword === "" && keyFileInfo !== undefined) {
// Keyfile but empty password provided. Assume password is unused.
// This extension does not support the combo empty string + keyfile.
protectedMasterPassword = null;
protectedMasterPassword = null
} else {
protectedMasterPassword = kdbxweb.ProtectedValue.fromString(masterPassword)
}
Expand All @@ -58,10 +69,8 @@ function KeepassService(keepassHeader, settings, passwordFileStoreRegistry, keep
if (!h) throw new Error('Failed to read file header');

if (h.kdbx) { // KDBX - use kdbxweb library
kdbxweb.CryptoEngine.argon2 = argon2;
var kdbxCreds = jsonCredentialsToKdbx(masterKey);
return kdbxweb.Kdbx.load(buf, kdbxCreds).then(db => {
var psk = new Uint8Array(db.header.protectedStreamKey, 0, db.header.protectedStreamKey.length);
var entries = parseKdbxDb(db.groups);
majorVersion = db.header.versionMajor;
return processReferences(entries, majorVersion);
Expand Down Expand Up @@ -190,15 +199,14 @@ function KeepassService(keepassHeader, settings, passwordFileStoreRegistry, keep
entry.keys.push('tags');
}
if (db_entry.fields) {
var field_keys = Object.keys(db_entry.fields);
for (let k = 0; k < field_keys.length; k++) {
var field = field_keys[k];
if (typeof db_entry.fields[field] === 'object') {
for (const [key, field] of db_entry.fields) {
const camelKey = Case.camel(key);
if (typeof field === 'object') {
// type = object ? protected value
entry.protectedData[Case.camel(field)] = protectedValueToJSON(db_entry.fields[field]);
entry.protectedData[camelKey] = protectedValueToJSON(field);
} else {
entry.keys.push(Case.camel(field));
entry[Case.camel(field)] = db_entry.fields[field];
entry.keys.push(camelKey);
entry[camelKey] = field;
}
}
}
Expand Down Expand Up @@ -232,10 +240,9 @@ function KeepassService(keepassHeader, settings, passwordFileStoreRegistry, keep
*/

function protectedValueToJSON(pv) {
console.log(pv)
return {
salt: Array.from(pv._salt),
value: Array.from(pv._value)
salt: Array.from(pv.salt),
value: Array.from(pv.value)
}
}

Expand Down
1 change: 0 additions & 1 deletion services/secureCacheMemory.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ function SecureCacheMemory(protectedMemory) {
//wake up the background page and get a pipe to send/receive messages:
exports.get = function (key) {
ready.then(function (port) {
console.log(port)
port.postMessage({
action: 'get',
key: key
Expand Down
12 changes: 6 additions & 6 deletions src/components/EntryDetails.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script>
import * as OTP from '@/lib/otp.js'
import { Otp as OTP } from '@/lib/otp.js'
import { parseUrl } from '@/lib/utils.js'
import GoBack from '@/components/GoBack.vue'
Expand Down Expand Up @@ -43,23 +43,23 @@ export default {
let otpobj = OTP.parseUrl(url)
this.otp = true
let do_otp = () => {
otpobj.next((code, timeleft) => {
otpobj.next((_, code, timeleft) => {
this.otp_value = code;
this.otp_timeleft = (timeleft / 1000) | 0;
this.otp_width = Math.floor(timeleft / 300) + "%"
})
}
this.otp_loop = setInterval(do_otp, 2000)
this.otp_loop = setInterval(do_otp, 1000)
do_otp()
},
autofill(e) {
e.stopPropagation()
console.log("autofill")
console.debug("autofill")
this.unlockedState.autofill(this.entry);
},
copy(e) {
e.stopPropagation()
console.log("copy")
console.debug("copy")
this.unlockedState.copyPassword(this.entry);
}
},
Expand Down Expand Up @@ -128,7 +128,7 @@ export default {
<br>
<span class="attribute-value">{{otp_value}}</span>
<div class="progress">
<div class="determinate" v-bind:style="{ width: otp_width }"></div>
<div :key="otp_value" class="determinate" style="transition: width 1s linear;" v-bind:style="{ width: otp_width }"></div>
</div>
</div>

Expand Down
2 changes: 0 additions & 2 deletions src/components/EntryList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export default {
},
watch: {
searchTerm(val) {
console.log(val)
this.unlockedState.cacheSet('searchFilter', val) // Causes cache refresh
if (val.length) {
this.filteredEntries = this.allEntries.filter(entry => {
Expand Down Expand Up @@ -113,7 +112,6 @@ export default {
}
},
mounted() {
console.log("EntryList mounted", this.priorityEntries, this.searchTerm)
// Autofocus searchbox
this.$nextTick(function () {
this.$refs.searchbox.focus();
Expand Down
5 changes: 2 additions & 3 deletions src/components/EntryListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export default {
},
computed: {
header: function () {
console.log(this.entry)
if (this.entry.title.length > 0)
return this.entry.title
return this.entry.url
Expand All @@ -29,12 +28,12 @@ export default {
},
autofill(e) {
e.stopPropagation()
console.log("autofill")
console.debug("autofill")
this.unlockedState.autofill(this.entry);
},
copy(e) {
e.stopPropagation()
console.log("copy")
console.debug("copy")
this.unlockedState.copyPassword(this.entry);
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/components/Unlock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ export default {
this.unlockedState.clearCache() // new
},
showResults(entries) {
console.log('showResults', entries)
let getMatchesForThreshold = (threshold, entries, requireEmptyURL = false) => {
return entries.filter(e => (e.matchRank >= threshold) && (requireEmptyURL ? !e.URL : true));
}
Expand Down Expand Up @@ -195,7 +194,6 @@ export default {
this.unlock()
},
unlock(passwordKey) {
console.log('unlock')
this.busy = true
this.generalMessages.error = ""
let passwordKeyPromise;
Expand Down Expand Up @@ -240,6 +238,7 @@ export default {
console.error(err)
this.generalMessages['error'] = err.message || "invalid keyfile or KDBX file"
this.busy = false
throw err
})
}
},
Expand All @@ -251,7 +250,6 @@ export default {
if (!this.isUnlocked()) {
let try_autounlock = () => {
console.log('try')
this.busy = true
this.settings.getKeyFiles().then(keyFiles => {
this.keyFiles = keyFiles
Expand Down Expand Up @@ -291,10 +289,7 @@ export default {
this.busy = true
try {
console.log('mounted2')
// console.log('mounted2', entries)
let entries = await this.secureCache.get('secureCache.entries');
console.log('mounted2', entries)
if (entries !== undefined && entries.length > 0) {
this.showResults(entries)
} else {
Expand Down
37 changes: 0 additions & 37 deletions src/lib/argon2.js

This file was deleted.

15 changes: 0 additions & 15 deletions src/lib/argon2.wasm.js

This file was deleted.

3 changes: 2 additions & 1 deletion vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { dirname, relative } from 'node:path'
import type { UserConfig } from 'vite'
import { defineConfig } from 'vite'
import Vue from '@vitejs/plugin-vue2'
import wasm from 'vite-plugin-wasm'

import { isDev, isLocal, port, r } from './scripts/utils'
import packageJson from './package.json'
Expand All @@ -21,7 +22,7 @@ export const sharedConfig: UserConfig = {
},
plugins: [
Vue(),

wasm(),
// rewrite assets to use relative path
{
name: 'assets-rewrite',
Expand Down
Loading

0 comments on commit efc2da0

Please sign in to comment.