mirror of https://github.com/keeweb/keeweb
browser extension connector: implemented get-databasehash
parent
933df5fae4
commit
dc4742bf5c
|
@ -19,6 +19,10 @@ class FileCollection extends Collection {
|
|||
getByName(name) {
|
||||
return this.find((file) => file.name.toLowerCase() === name.toLowerCase());
|
||||
}
|
||||
|
||||
firstActiveKdbxFile() {
|
||||
return this.find((file) => file.active && !file.backend);
|
||||
}
|
||||
}
|
||||
|
||||
export { FileCollection };
|
||||
|
|
|
@ -97,11 +97,17 @@ const ProtocolHandlers = {
|
|||
|
||||
'get-databasehash'(request) {
|
||||
decryptRequest(request);
|
||||
return encryptResponse(request, {
|
||||
action: 'hash',
|
||||
version: RuntimeInfo.version,
|
||||
hash: 'TODO'
|
||||
});
|
||||
|
||||
const firstFile = AppModel.instance.files.firstActiveKdbxFile();
|
||||
if (firstFile?.defaultGroupHash) {
|
||||
return encryptResponse(request, {
|
||||
action: 'hash',
|
||||
version: RuntimeInfo.version,
|
||||
hash: firstFile.defaultGroupHash
|
||||
});
|
||||
} else {
|
||||
return { action: 'get-databasehash', error: 'No open files', errorCode: '1' };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -469,7 +469,7 @@ class AppModel {
|
|||
}
|
||||
}
|
||||
|
||||
createNewFile(name) {
|
||||
createNewFile(name, callback) {
|
||||
if (!name) {
|
||||
for (let i = 0; ; i++) {
|
||||
name = Locale.openNewFile + (i || '');
|
||||
|
@ -479,9 +479,10 @@ class AppModel {
|
|||
}
|
||||
}
|
||||
const newFile = new FileModel({ id: IdGenerator.uuid() });
|
||||
newFile.create(name);
|
||||
this.addFile(newFile);
|
||||
return newFile;
|
||||
newFile.create(name, () => {
|
||||
this.addFile(newFile);
|
||||
callback?.(newFile);
|
||||
});
|
||||
}
|
||||
|
||||
openFile(params, callback) {
|
||||
|
|
|
@ -31,6 +31,9 @@ class FileModel extends Model {
|
|||
kdbxweb.Kdbx.load(fileData, credentials)
|
||||
.then((db) => {
|
||||
this.db = db;
|
||||
})
|
||||
.then(() => this.setDefaultGroupHash())
|
||||
.then(() => {
|
||||
this.readModel();
|
||||
this.setOpenFile({ passwordLength: password ? password.textLength : 0 });
|
||||
if (keyFileData) {
|
||||
|
@ -43,7 +46,7 @@ class FileModel extends Model {
|
|||
': ' +
|
||||
logger.ts(ts) +
|
||||
', ' +
|
||||
this.kdfArgsToString(db.header) +
|
||||
this.kdfArgsToString(this.db.header) +
|
||||
', ' +
|
||||
Math.round(fileData.byteLength / 1024) +
|
||||
' kB'
|
||||
|
@ -90,13 +93,16 @@ class FileModel extends Model {
|
|||
}
|
||||
}
|
||||
|
||||
create(name) {
|
||||
create(name, callback) {
|
||||
const password = kdbxweb.ProtectedValue.fromString('');
|
||||
const credentials = new kdbxweb.Credentials(password);
|
||||
this.db = kdbxweb.Kdbx.create(credentials, name);
|
||||
this.name = name;
|
||||
this.readModel();
|
||||
this.set({ active: true, created: true, name });
|
||||
return this.setDefaultGroupHash().then(() => {
|
||||
this.set({ active: true, created: true, name });
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
importWithXml(fileXml, callback) {
|
||||
|
@ -107,6 +113,9 @@ class FileModel extends Model {
|
|||
kdbxweb.Kdbx.loadXml(fileXml, credentials)
|
||||
.then((db) => {
|
||||
this.db = db;
|
||||
})
|
||||
.then(() => this.setDefaultGroupHash())
|
||||
.then(() => {
|
||||
this.readModel();
|
||||
this.set({ active: true, created: true });
|
||||
logger.info('Imported file ' + this.name + ': ' + logger.ts(ts));
|
||||
|
@ -128,13 +137,17 @@ class FileModel extends Model {
|
|||
const demoFile = kdbxweb.ByteUtils.arrayToBuffer(
|
||||
kdbxweb.ByteUtils.base64ToBytes(demoFileData)
|
||||
);
|
||||
kdbxweb.Kdbx.load(demoFile, credentials).then((db) => {
|
||||
this.db = db;
|
||||
this.name = 'Demo';
|
||||
this.readModel();
|
||||
this.setOpenFile({ passwordLength: 4, demo: true });
|
||||
callback();
|
||||
});
|
||||
kdbxweb.Kdbx.load(demoFile, credentials)
|
||||
.then((db) => {
|
||||
this.db = db;
|
||||
})
|
||||
.then(() => this.setDefaultGroupHash())
|
||||
.then(() => {
|
||||
this.name = 'Demo';
|
||||
this.readModel();
|
||||
this.setOpenFile({ passwordLength: 4, demo: true });
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
setOpenFile(props) {
|
||||
|
@ -230,6 +243,17 @@ class FileModel extends Model {
|
|||
}
|
||||
}
|
||||
|
||||
setDefaultGroupHash() {
|
||||
const uuidStr = kdbxweb.ByteUtils.bytesToHex(this.db.getDefaultGroup().uuid.bytes);
|
||||
const uuidBytes = kdbxweb.ByteUtils.stringToBytes(uuidStr);
|
||||
|
||||
return kdbxweb.CryptoEngine.sha256(uuidBytes)
|
||||
.then((hashBytes) => kdbxweb.ByteUtils.bytesToHex(hashBytes))
|
||||
.then((defaultGroupHash) => {
|
||||
this.set({ defaultGroupHash }, { silent: true });
|
||||
});
|
||||
}
|
||||
|
||||
subId(id) {
|
||||
return this.id + ':' + id;
|
||||
}
|
||||
|
@ -770,7 +794,8 @@ FileModel.defineModelProperties({
|
|||
supportsTags: true,
|
||||
supportsColors: true,
|
||||
supportsIcons: true,
|
||||
supportsExpiration: true
|
||||
supportsExpiration: true,
|
||||
defaultGroupHash: ''
|
||||
});
|
||||
|
||||
export { FileModel };
|
||||
|
|
|
@ -145,31 +145,41 @@ class ImportCsvView extends View {
|
|||
|
||||
runImport() {
|
||||
let group = this.targetGroup;
|
||||
let file = group ? group.file : undefined;
|
||||
if (!group) {
|
||||
|
||||
let filePromise;
|
||||
if (group) {
|
||||
filePromise = Promise.resolve(group.file);
|
||||
} else {
|
||||
const fileName = this.fileName.replace(/\.csv$/i, '');
|
||||
file = this.appModel.createNewFile(fileName);
|
||||
group = file.groups[0];
|
||||
filePromise = new Promise((resolve) => this.appModel.createNewFile(fileName, resolve));
|
||||
}
|
||||
for (const row of this.model.rows) {
|
||||
const newEntry = EntryModel.newEntry(group, file);
|
||||
for (let ix = 0; ix < row.length; ix++) {
|
||||
let value = row[ix];
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
const mapping = this.fieldMapping[ix];
|
||||
if (mapping.type === 'ignore' || !mapping.field) {
|
||||
continue;
|
||||
}
|
||||
if (mapping.field === 'Password') {
|
||||
value = kdbxweb.ProtectedValue.fromString(value);
|
||||
}
|
||||
newEntry.setField(mapping.field, value);
|
||||
|
||||
filePromise.then((file) => {
|
||||
if (!group) {
|
||||
group = file.groups[0];
|
||||
}
|
||||
}
|
||||
file.reload();
|
||||
this.emit('done');
|
||||
|
||||
for (const row of this.model.rows) {
|
||||
const newEntry = EntryModel.newEntry(group, file);
|
||||
for (let ix = 0; ix < row.length; ix++) {
|
||||
let value = row[ix];
|
||||
if (!value) {
|
||||
continue;
|
||||
}
|
||||
const mapping = this.fieldMapping[ix];
|
||||
if (mapping.type === 'ignore' || !mapping.field) {
|
||||
continue;
|
||||
}
|
||||
if (mapping.field === 'Password') {
|
||||
value = kdbxweb.ProtectedValue.fromString(value);
|
||||
}
|
||||
newEntry.setField(mapping.field, value);
|
||||
}
|
||||
}
|
||||
|
||||
file.reload();
|
||||
this.emit('done');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue