From 58c34b896c214cc599ecb106adce6aee8a400802 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Mon, 25 Mar 2019 09:10:33 -0400 Subject: [PATCH] sort and limit password history parsing --- .../importers/onepassword1PifImporter.spec.ts | 150 ++++++++++-------- src/importers/onepassword1PifImporter.ts | 24 +-- 2 files changed, 99 insertions(+), 75 deletions(-) diff --git a/spec/common/importers/onepassword1PifImporter.spec.ts b/spec/common/importers/onepassword1PifImporter.spec.ts index 971e82e6a2..352c3cb651 100644 --- a/spec/common/importers/onepassword1PifImporter.spec.ts +++ b/spec/common/importers/onepassword1PifImporter.spec.ts @@ -12,62 +12,62 @@ if (Utils.isNode) { const TestData: string = '***aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee***\n' + JSON.stringify({ - uuid: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', - updatedAt: 1486071244, - securityLevel: 'SL5', - contentsHash: 'aaaaaaaa', - title: 'Imported Entry', - location: 'https://www.google.com', - secureContents: { - fields: [ - { - value: 'user@test.net', - id: 'email-input', - name: 'email', - type: 'T', - designation: 'username', - }, - { - value: 'myservicepassword', - id: 'password-input', - name: 'password', - type: 'P', - designation: 'password', - }, - ], - sections: [ - { - fields: [ - { - k: 'concealed', - n: 'AAAAAAAAAAAABBBBBBBBBBBCCCCCCCCC', - v: 'console-password-123', - t: 'console password', - }, - ], - title: 'Admin Console', - name: 'admin_console', - }, - ], - passwordHistory: [ - { - value: 'old-password', - time: 1447791421, - }, - ], - }, - URLs: [ - { - label: 'website', - url: 'https://www.google.com', + uuid: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', + updatedAt: 1486071244, + securityLevel: 'SL5', + contentsHash: 'aaaaaaaa', + title: 'Imported Entry', + location: 'https://www.google.com', + secureContents: { + fields: [ + { + value: 'user@test.net', + id: 'email-input', + name: 'email', + type: 'T', + designation: 'username', + }, + { + value: 'myservicepassword', + id: 'password-input', + name: 'password', + type: 'P', + designation: 'password', + }, + ], + sections: [ + { + fields: [ + { + k: 'concealed', + n: 'AAAAAAAAAAAABBBBBBBBBBBCCCCCCCCC', + v: 'console-password-123', + t: 'console password', + }, + ], + title: 'Admin Console', + name: 'admin_console', + }, + ], + passwordHistory: [ + { + value: 'old-password', + time: 1447791421, + }, + ], }, - ], - txTimestamp: 1508941334, - createdAt: 1390426636, - typeName: 'webforms.WebForm', -}); + URLs: [ + { + label: 'website', + url: 'https://www.google.com', + }, + ], + txTimestamp: 1508941334, + createdAt: 1390426636, + typeName: 'webforms.WebForm', + }); -const WindowsTestData = JSON.stringify({ +const WindowsOpVaultTestData = JSON.stringify({ category: '001', created: 1544823719, hmac: 'NtyBmTTPOb88HV3JUKPx1xl/vcMhac9kvCfe/NtszY0=', @@ -89,13 +89,29 @@ const WindowsTestData = JSON.stringify({ details: { passwordHistory: [ { - value: 'oldpass2', + value: 'oldpass1', time: 1553394449, }, { - value: 'oldpass1', + value: 'oldpass2', time: 1553394457, }, + { + value: 'oldpass3', + time: 1553394458, + }, + { + value: 'oldpass4', + time: 1553394459, + }, + { + value: 'oldpass5', + time: 1553394460, + }, + { + value: 'oldpass6', + time: 1553394461, + }, ], fields: [ { @@ -481,18 +497,26 @@ describe('1Password 1Pif Importer', () => { 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 result = importer.parse(WindowsTestData); + const result = importer.parse(WindowsOpVaultTestData); const cipher = result.ciphers.shift(); - expect(cipher.passwordHistory.length).toEqual(2); + expect(cipher.passwordHistory.length).toEqual(5); let ph = cipher.passwordHistory.shift(); - expect(ph.password).toEqual('oldpass2'); - expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:29.000Z'); - + expect(ph.password).toEqual('oldpass6'); + expect(ph.lastUsedDate.toISOString()).toEqual('2019-03-24T02:27:41.000Z'); 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'); }); }); diff --git a/src/importers/onepassword1PifImporter.ts b/src/importers/onepassword1PifImporter.ts index ced4c9104d..eb2d4d532e 100644 --- a/src/importers/onepassword1PifImporter.ts +++ b/src/importers/onepassword1PifImporter.ts @@ -79,21 +79,11 @@ export class OnePassword1PifImporter extends BaseImporter implements Importer { }); } 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) { cipher.favorite = item.openContents && item.openContents.faveIndex ? true : false; cipher.name = this.getValueOrDefault(item.title); @@ -143,11 +133,21 @@ export class OnePassword1PifImporter extends BaseImporter implements Importer { }); } 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) { fields.forEach((field: any) => { if (field[valueKey] == null || field[valueKey].toString().trim() === '') {