sort and limit password history parsing

This commit is contained in:
Kyle Spearrin 2019-03-25 09:10:33 -04:00
parent 8ed27eeeec
commit 58c34b896c
2 changed files with 99 additions and 75 deletions

View File

@ -12,62 +12,62 @@ if (Utils.isNode) {
const TestData: string = '***aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee***\n' + const TestData: string = '***aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee***\n' +
JSON.stringify({ JSON.stringify({
uuid: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', uuid: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
updatedAt: 1486071244, updatedAt: 1486071244,
securityLevel: 'SL5', securityLevel: 'SL5',
contentsHash: 'aaaaaaaa', contentsHash: 'aaaaaaaa',
title: 'Imported Entry', title: 'Imported Entry',
location: 'https://www.google.com', location: 'https://www.google.com',
secureContents: { secureContents: {
fields: [ fields: [
{ {
value: 'user@test.net', value: 'user@test.net',
id: 'email-input', id: 'email-input',
name: 'email', name: 'email',
type: 'T', type: 'T',
designation: 'username', designation: 'username',
}, },
{ {
value: 'myservicepassword', value: 'myservicepassword',
id: 'password-input', id: 'password-input',
name: 'password', name: 'password',
type: 'P', type: 'P',
designation: 'password', designation: 'password',
}, },
], ],
sections: [ sections: [
{ {
fields: [ fields: [
{ {
k: 'concealed', k: 'concealed',
n: 'AAAAAAAAAAAABBBBBBBBBBBCCCCCCCCC', n: 'AAAAAAAAAAAABBBBBBBBBBBCCCCCCCCC',
v: 'console-password-123', v: 'console-password-123',
t: 'console password', t: 'console password',
}, },
], ],
title: 'Admin Console', title: 'Admin Console',
name: 'admin_console', name: 'admin_console',
}, },
], ],
passwordHistory: [ passwordHistory: [
{ {
value: 'old-password', value: 'old-password',
time: 1447791421, time: 1447791421,
}, },
], ],
},
URLs: [
{
label: 'website',
url: 'https://www.google.com',
}, },
], URLs: [
txTimestamp: 1508941334, {
createdAt: 1390426636, label: 'website',
typeName: 'webforms.WebForm', url: 'https://www.google.com',
}); },
],
txTimestamp: 1508941334,
createdAt: 1390426636,
typeName: 'webforms.WebForm',
});
const WindowsTestData = JSON.stringify({ const WindowsOpVaultTestData = JSON.stringify({
category: '001', category: '001',
created: 1544823719, created: 1544823719,
hmac: 'NtyBmTTPOb88HV3JUKPx1xl/vcMhac9kvCfe/NtszY0=', hmac: 'NtyBmTTPOb88HV3JUKPx1xl/vcMhac9kvCfe/NtszY0=',
@ -89,13 +89,29 @@ const WindowsTestData = JSON.stringify({
details: { details: {
passwordHistory: [ passwordHistory: [
{ {
value: 'oldpass2', value: 'oldpass1',
time: 1553394449, time: 1553394449,
}, },
{ {
value: 'oldpass1', value: 'oldpass2',
time: 1553394457, time: 1553394457,
}, },
{
value: 'oldpass3',
time: 1553394458,
},
{
value: 'oldpass4',
time: 1553394459,
},
{
value: 'oldpass5',
time: 1553394460,
},
{
value: 'oldpass6',
time: 1553394461,
},
], ],
fields: [ fields: [
{ {
@ -481,18 +497,26 @@ describe('1Password 1Pif Importer', () => {
expect(ph.lastUsedDate.toISOString()).toEqual('2015-11-17T20:17:01.000Z'); expect(ph.lastUsedDate.toISOString()).toEqual('2015-11-17T20:17:01.000Z');
}); });
it('should create password history from windows 1pif format', async () => { it('should create password history from windows opvault 1pif format', async () => {
const importer = new Importer(); const importer = new Importer();
const result = importer.parse(WindowsTestData); const result = importer.parse(WindowsOpVaultTestData);
const cipher = result.ciphers.shift(); const cipher = result.ciphers.shift();
expect(cipher.passwordHistory.length).toEqual(2); expect(cipher.passwordHistory.length).toEqual(5);
let ph = cipher.passwordHistory.shift(); let ph = cipher.passwordHistory.shift();
expect(ph.password).toEqual('oldpass2'); expect(ph.password).toEqual('oldpass6');
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:29.000Z'); expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:41.000Z');
ph = cipher.passwordHistory.shift(); ph = cipher.passwordHistory.shift();
expect(ph.password).toEqual('oldpass1'); expect(ph.password).toEqual('oldpass5');
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:40.000Z');
ph = cipher.passwordHistory.shift();
expect(ph.password).toEqual('oldpass4');
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:39.000Z');
ph = cipher.passwordHistory.shift();
expect(ph.password).toEqual('oldpass3');
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:38.000Z');
ph = cipher.passwordHistory.shift();
expect(ph.password).toEqual('oldpass2');
expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:37.000Z'); expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:37.000Z');
}); });
}); });

View File

@ -79,21 +79,11 @@ export class OnePassword1PifImporter extends BaseImporter implements Importer {
}); });
} }
if (item.details.passwordHistory != null) { if (item.details.passwordHistory != null) {
this.processPasswordHistory(item.details.passwordHistory, cipher); this.parsePasswordHistory(item.details.passwordHistory, cipher);
} }
} }
} }
private processPasswordHistory(items: any[], cipher: CipherView) {
cipher.passwordHistory = cipher.passwordHistory || [];
items.forEach((entry: any) => {
const phv = new PasswordHistoryView();
phv.password = entry.value;
phv.lastUsedDate = new Date(entry.time * 1000);
cipher.passwordHistory.push(phv);
});
}
private processStandardItem(item: any, cipher: CipherView) { private processStandardItem(item: any, cipher: CipherView) {
cipher.favorite = item.openContents && item.openContents.faveIndex ? true : false; cipher.favorite = item.openContents && item.openContents.faveIndex ? true : false;
cipher.name = this.getValueOrDefault(item.title); cipher.name = this.getValueOrDefault(item.title);
@ -143,11 +133,21 @@ export class OnePassword1PifImporter extends BaseImporter implements Importer {
}); });
} }
if (item.secureContents.passwordHistory != null) { if (item.secureContents.passwordHistory != null) {
this.processPasswordHistory(item.secureContents.passwordHistory, cipher); this.parsePasswordHistory(item.secureContents.passwordHistory, cipher);
} }
} }
} }
private parsePasswordHistory(items: any[], cipher: CipherView) {
const maxSize = items.length > 5 ? 5 : items.length;
cipher.passwordHistory = items.sort((a, b) => b.time - a.time).slice(0, maxSize).map((entry: any) => {
const ph = new PasswordHistoryView();
ph.password = entry.value;
ph.lastUsedDate = new Date(entry.time * 1000);
return ph;
});
}
private parseFields(fields: any[], cipher: CipherView, designationKey: string, valueKey: string, nameKey: string) { private parseFields(fields: any[], cipher: CipherView, designationKey: string, valueKey: string, nameKey: string) {
fields.forEach((field: any) => { fields.forEach((field: any) => {
if (field[valueKey] == null || field[valueKey].toString().trim() === '') { if (field[valueKey] == null || field[valueKey].toString().trim() === '') {