Skip to content

Commit ae804e0

Browse files
committed
Add local password file manager
1 parent ed7d41f commit ae804e0

13 files changed

+184
-50
lines changed

background/background.js

+1-27
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,11 @@
1-
/**
2-
3-
The MIT License (MIT)
4-
5-
Copyright (c) 2015 Steven Campbell.
6-
7-
Permission is hereby granted, free of charge, to any person obtaining a copy
8-
of this software and associated documentation files (the "Software"), to deal
9-
in the Software without restriction, including without limitation the rights
10-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11-
copies of the Software, and to permit persons to whom the Software is
12-
furnished to do so, subject to the following conditions:
13-
14-
The above copyright notice and this permission notice shall be included in
15-
all copies or substantial portions of the Software.
16-
17-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23-
THE SOFTWARE.
24-
25-
*/
26-
271
"use strict";
282

293
/*
304
This page runs as an Event page, not a Background page, so don't use global variables
315
(they will be lost)
326
*/
337

34-
import ProtectedMemory from '$services/protectedMemory.js'
8+
import { ProtectedMemory } from '$services/protectedMemory.js'
359
import { Settings } from '$services/settings.js'
3610

3711
function Background(protectedMemory, settings) {

services/localChromePasswordFileManager.js

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
"use strict";
2-
2+
const Base64 = require('base64-arraybuffer')
33
import { ChromePromiseApi } from '$lib/chrome-api-promise.js'
44

55
const chromePromise = ChromePromiseApi()
66

77
function LocalChromePasswordFileManager() {
88
var exports = {
99
key: 'local',
10-
routePath: '/drag-drop-file',
1110
listDatabases: listDatabases,
1211
getDatabaseChoiceData: getDatabaseChoiceData,
1312
getChosenDatabaseFile: getChosenDatabaseFile,
@@ -17,12 +16,29 @@ function LocalChromePasswordFileManager() {
1716
title: 'Chrome Storage',
1817
icon: 'icon-upload',
1918
chooseTitle: 'File System',
20-
chooseDescription: 'Upload files from your local or remote file-system. A one-time copy of the file(s) will be saved in Chrome local storage. If you update the database on your local system then you will have to re-upload it in order to see the changes.'
19+
chooseDescription: 'Upload files from your local or remote file-system. A one-time copy of the file(s) will be saved in Chrome local storage. If you update the database on your local system then you will have to re-upload it in order to see the changes.',
20+
login: enable,
21+
logout: disable,
22+
isLoggedIn: isEnabled
2123
};
2224

2325
var backwardCompatibleVersion = 1; //missing version or version less than this is ignored due missing info or bugs in old storage
2426
var currentVersion = 1; //current version
2527

28+
function enable() {
29+
return chromePromise.storage.local.set({'localPasswordFilesEnabled':true})
30+
}
31+
32+
function disable () {
33+
return chromePromise.storage.local.set({'localPasswordFilesEnabled':false})
34+
}
35+
36+
function isEnabled () {
37+
return chromePromise.storage.local.get('localPasswordFilesEnabled').then(result => {
38+
return result.localPasswordFilesEnabled || false
39+
})
40+
}
41+
2642
var savingLocks = []; //prevent reading while an async save is ongoing
2743
function listDatabases() {
2844
return Promise.all(savingLocks).then(function() {

services/passwordFileStore.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Provides a container for various storage mechanisms (aka FileManagers)that can be injected,
55
* so that the rest of the code can be independent of specifics.
66
**/
7-
module.exports = function PasswordFileStoreRegistry() {
7+
function PasswordFileStoreRegistry() {
88
var exports = {
99
listFileManagers: listFileManagers,
1010
getChosenDatabaseFile: getChosenDatabaseFile
@@ -37,3 +37,5 @@ module.exports = function PasswordFileStoreRegistry() {
3737

3838
return exports;
3939
}
40+
41+
export { PasswordFileStoreRegistry }

services/protectedMemory.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
let Base64 = require('base64-arraybuffer')
1010

11-
module.exports = function ProtectedMemory() {
11+
function ProtectedMemory() {
1212
var my = {
1313
getData: getData,
1414
setData: setData,
@@ -137,3 +137,5 @@ module.exports = function ProtectedMemory() {
137137

138138
return my;
139139
}
140+
141+
export { ProtectedMemory }

services/sampleDatabaseFileManager.js

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const chromePromise = ChromePromiseApi()
88
function SampleDatabaseFileManager() {
99
var exports = {
1010
key: 'sample',
11-
routePath: '/sample-database',
1211
listDatabases: listDatabases,
1312
getDatabaseChoiceData: getDatabaseChoiceData,
1413
getChosenDatabaseFile: getChosenDatabaseFile,

services/secureCacheDisk.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Max storage time is 40 minutes, which is the expected TTL of the secret. You
1212
* can see details of the expiry time in chrome://identity-internals/
1313
*/
14-
module.exports = function SecureCacheDisk(protectedMemory, secureCacheMemory, settings) {
14+
function SecureCacheDisk(protectedMemory, secureCacheMemory, settings) {
1515
var exports = {
1616
save: set,
1717
get: get,
@@ -135,3 +135,5 @@ module.exports = function SecureCacheDisk(protectedMemory, secureCacheMemory, se
135135

136136
return exports;
137137
}
138+
139+
export { SecureCacheDisk }

services/secureCacheMemory.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
/**
44
* Storage in background page memory.
55
*/
6-
module.exports = function SecureCacheMemory(protectedMemory) {
6+
function SecureCacheMemory(protectedMemory) {
77
var exports = {}
88

99
var awaiting = [];
@@ -84,3 +84,5 @@ module.exports = function SecureCacheMemory(protectedMemory) {
8484

8585
return exports;
8686
}
87+
88+
export { SecureCacheMemory }

services/sharedUrlFileManager.js

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ const chromePromise = ChromePromiseApi()
88
function SharedUrlFileManager() {
99
var exports = {
1010
key: 'shared-url',
11-
routePath: '/shared-url',
1211
listDatabases: listDatabases,
1312
getDatabaseChoiceData: getDatabaseChoiceData,
1413
getChosenDatabaseFile: getChosenDatabaseFile,

src/Options.vue

+8-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
v-if="show.manageDatabases.visible"
1414
:dropbox-file-manager="services.dropboxFileManager"
1515
:google-drive-manager="services.googleDrivePasswordFileManager"
16+
:local-file-manager="services.localChromePasswordFileManager"
1617
:onedrive-manager="services.oneDriveFileManager"
1718
:sample-manager="services.sampleDatabaseFileManager"
1819
:shared-url-manager="services.sharedUrlFileManager"
@@ -32,12 +33,12 @@
3233

3334
<script>
3435
// Singletons
35-
import ChromePromiseApi from '$lib/chrome-api-promise.js'
36+
import { ChromePromiseApi } from '$lib/chrome-api-promise.js'
3637
import { Settings } from '$services/settings.js'
37-
import ProtectedMemory from '$services/protectedMemory.js'
38-
import SecureCacheMemory from '$services/secureCacheMemory.js'
39-
import SecureCacheDisk from '$services/secureCacheDisk.js'
40-
import PasswordFileStore from '$services/passwordFileStore.js'
38+
import { ProtectedMemory } from '$services/protectedMemory.js'
39+
import { SecureCacheMemory } from '$services/secureCacheMemory.js'
40+
import { SecureCacheDisk } from '$services/secureCacheDisk.js'
41+
import { PasswordFileStoreRegistry } from '$services/passwordFileStore.js'
4142
import { KeyFileParser } from '$services/keyFileParser.js'
4243
// File Managers
4344
import { LocalChromePasswordFileManager } from '$services/localChromePasswordFileManager.js'
@@ -68,7 +69,7 @@ const sharedUrlFileManager = new SharedUrlFileManager()
6869
const oneDriveFileManager = new OneDriveFileManager(settings)
6970
const sampleDatabaseFileManager = new SampleDatabaseFileManager()
7071
71-
const passwordFileStoreRegistry = new PasswordFileStore(localChromePasswordFileManager, dropboxFileManager, googleDrivePasswordFileManager, sharedUrlFileManager, sampleDatabaseFileManager, oneDriveFileManager)
72+
const passwordFileStoreRegistry = new PasswordFileStoreRegistry(localChromePasswordFileManager, dropboxFileManager, googleDrivePasswordFileManager, sharedUrlFileManager, sampleDatabaseFileManager, oneDriveFileManager)
7273
7374
export default {
7475
name: 'app',
@@ -88,6 +89,7 @@ export default {
8889
settings,
8990
dropboxFileManager,
9091
googleDrivePasswordFileManager,
92+
localChromePasswordFileManager,
9193
oneDriveFileManager,
9294
sampleDatabaseFileManager,
9395
sharedUrlFileManager,

src/Popup.vue

+5-5
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@
2626
<script>
2727
// Singletons
2828
import { Settings } from '$services/settings.js'
29-
import ProtectedMemory from '$services/protectedMemory.js'
29+
import { ProtectedMemory } from '$services/protectedMemory.js'
3030
import { KeepassHeader } from '$services/keepassHeader.js'
3131
import { KeepassReference } from '$services/keepassReference.js'
3232
import { KeepassService } from '$services/keepassService.js'
3333
import { UnlockedState } from '$services/unlockedState.js'
34-
import SecureCacheMemory from '$services/secureCacheMemory.js'
35-
import SecureCacheDisk from '$services/secureCacheDisk.js'
36-
import PasswordFileStore from '$services/passwordFileStore.js'
34+
import { SecureCacheMemory } from '$services/secureCacheMemory.js'
35+
import { SecureCacheDisk } from '$services/secureCacheDisk.js'
36+
import { PasswordFileStoreRegistry } from '$services/passwordFileStore.js'
3737
import { Links } from '$services/links.js'
3838
// File Managers
3939
import { LocalChromePasswordFileManager } from '$services/localChromePasswordFileManager.js'
@@ -65,7 +65,7 @@ const sharedUrlFileManager = new SharedUrlFileManager()
6565
const oneDriveFileManager = new OneDriveFileManager(settings)
6666
const sampleDatabaseFileManager = new SampleDatabaseFileManager()
6767
68-
const passwordFileStoreRegistry = new PasswordFileStore(localChromePasswordFileManager, dropboxFileManager, googleDrivePasswordFileManager, sharedUrlFileManager, sampleDatabaseFileManager, oneDriveFileManager)
68+
const passwordFileStoreRegistry = new PasswordFileStoreRegistry(localChromePasswordFileManager, dropboxFileManager, googleDrivePasswordFileManager, sharedUrlFileManager, sampleDatabaseFileManager, oneDriveFileManager)
6969
const keepassService = new KeepassService(keepassHeader, settings, passwordFileStoreRegistry, keepassReference)
7070
7171
export default {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<!--
2+
SharedLinkProvider:
3+
Simple http provider that can also handle Dropbox Shared Links
4+
-->
5+
<template>
6+
<div class="box-bar roomy database-manager">
7+
<generic-provider-ui
8+
:busy="busy"
9+
:databases="databases"
10+
:loggedIn="loggedIn"
11+
:error="messages.error"
12+
:provider-manager="providerManager"
13+
:toggle-login="toggleLogin"
14+
:removeable="true"
15+
:remove-function="removePasswordFile"></generic-provider-ui>
16+
<div class="url-form shared-link-box" v-if="loggedIn">
17+
<input type="file" style="display:none" id="file-selector" name='file' @change="handleAdd" multiple />
18+
<a class="waves-effect waves-light btn" @click="selectFile">Add URL Source</a>
19+
</div>
20+
</div>
21+
</template>
22+
23+
<script>
24+
const Base64 = require('base64-arraybuffer')
25+
import GenericProviderUi from '@/components/GenericProviderUi'
26+
27+
export default {
28+
data () {
29+
return {
30+
busy: false,
31+
currentUrl: "",
32+
currentUrlTitle: "",
33+
databases: [],
34+
loggedIn: false,
35+
messages: {
36+
error: ""
37+
}
38+
}
39+
},
40+
components: {
41+
GenericProviderUi
42+
},
43+
props: {
44+
providerManager: Object,
45+
settings: Object
46+
},
47+
methods: {
48+
toggleLogin () {
49+
if (this.loggedIn){
50+
this.settings.disableDatabaseProvider(this.providerManager)
51+
this.providerManager.logout().then(() => {this.loggedIn = false})
52+
} else {
53+
this.providerManager.login().then(() => {this.loggedIn = true})
54+
}
55+
},
56+
selectFile (event) {
57+
document.getElementById('file-selector').click();
58+
},
59+
removePasswordFile (index) {
60+
if (index >= this.databases.length || index < 0)
61+
return // not a valid index...
62+
let fi = this.databases[index]
63+
this.providerManager.deleteDatabase(fi)
64+
.then(this.providerManager.listDatabases)
65+
.then(files => {
66+
this.databases = files
67+
})
68+
},
69+
handleAdd (event) {
70+
let files = event.target.files;
71+
this.messages.error = ""
72+
for (var i=0; i<files.length; i++){
73+
let reader = new FileReader()
74+
let fp = files[i]
75+
reader.readAsArrayBuffer(fp)
76+
reader.onload = (e) => {
77+
if (fp.name.indexOf('.kdbx') < 0 || fp.size < 70) {
78+
this.messages.error += fp.name + " is not a valid KeePass v2+ file. "
79+
return;
80+
}
81+
82+
var fi = {
83+
title: fp.name,
84+
lastModified: fp.lastModified,
85+
lastModifiedDate: fp.lastModifiedDate,
86+
size: fp.size,
87+
type: fp.type,
88+
data: Base64.encode(e.target.result)
89+
}
90+
91+
var existingIndex = null;
92+
this.databases.forEach(function(existingFile, index) {
93+
if (existingFile.title == fi.title) {
94+
existingIndex = index;
95+
}
96+
});
97+
98+
if (existingIndex == null) {
99+
//add
100+
this.databases.push(fi);
101+
} else {
102+
//replace
103+
this.databases[existingIndex] = fi;
104+
}
105+
106+
return this.providerManager.saveDatabase({
107+
title: fi.title,
108+
data: fi.data,
109+
lastModified: fi.lastModified
110+
})
111+
} // end onload
112+
}
113+
}
114+
},
115+
mounted () {
116+
this.providerManager.isLoggedIn().then(loggedIn => {
117+
console.log("WOOOOO", loggedIn)
118+
this.loggedIn = loggedIn
119+
})
120+
this.providerManager.listDatabases().then(databases => {
121+
if (databases !== false)
122+
this.databases = databases
123+
})
124+
}
125+
}
126+
</script>
127+
128+
<style lang="scss">
129+
@import "../styles/settings.scss";
130+
</style>

0 commit comments

Comments
 (0)