refactor(dev-only): import tools (#2121)
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { AegisToAuthenticatorConverter } from './AegisToAuthenticatorConverter'
|
||||
import data from './testData'
|
||||
|
||||
describe('AegisConverter', () => {
|
||||
let application: WebApplicationInterface
|
||||
|
||||
beforeEach(() => {
|
||||
application = {
|
||||
generateUUID: jest.fn().mockReturnValue('test'),
|
||||
} as unknown as WebApplicationInterface
|
||||
})
|
||||
|
||||
it('should parse entries', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
|
||||
const result = converter.parseEntries(data)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result?.length).toBe(2)
|
||||
expect(result?.[0]).toStrictEqual({
|
||||
service: 'TestMail',
|
||||
account: 'test@test.com',
|
||||
secret: 'TESTMAILTESTMAILTESTMAILTESTMAIL',
|
||||
notes: 'Some note',
|
||||
})
|
||||
expect(result?.[1]).toStrictEqual({
|
||||
service: 'Some Service',
|
||||
account: 'test@test.com',
|
||||
secret: 'SOMESERVICESOMESERVICESOMESERVIC',
|
||||
notes: 'Some other service',
|
||||
})
|
||||
})
|
||||
|
||||
it('should create note from entries with editor info', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
|
||||
const parsedEntries = converter.parseEntries(data)
|
||||
|
||||
const result = converter.createNoteFromEntries(
|
||||
parsedEntries!,
|
||||
{
|
||||
lastModified: 123456789,
|
||||
name: 'test.json',
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result.content_type).toBe('Note')
|
||||
expect(result.created_at).toBeInstanceOf(Date)
|
||||
expect(result.updated_at).toBeInstanceOf(Date)
|
||||
expect(result.uuid).not.toBeNull()
|
||||
expect(result.content.title).toBe('test')
|
||||
expect(result.content.text).toBe(
|
||||
'[{"service":"TestMail","account":"test@test.com","secret":"TESTMAILTESTMAILTESTMAILTESTMAIL","notes":"Some note"},{"service":"Some Service","account":"test@test.com","secret":"SOMESERVICESOMESERVICESOMESERVIC","notes":"Some other service"}]',
|
||||
)
|
||||
expect(result.content.noteType).toBe(NoteType.Authentication)
|
||||
expect(result.content.editorIdentifier).toBe(FeatureIdentifier.TokenVaultEditor)
|
||||
})
|
||||
|
||||
it('should create note from entries without editor info', () => {
|
||||
const converter = new AegisToAuthenticatorConverter(application)
|
||||
|
||||
const parsedEntries = converter.parseEntries(data)
|
||||
|
||||
const result = converter.createNoteFromEntries(
|
||||
parsedEntries!,
|
||||
{
|
||||
lastModified: 123456789,
|
||||
name: 'test.json',
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
expect(result).not.toBeNull()
|
||||
expect(result.content_type).toBe('Note')
|
||||
expect(result.created_at).toBeInstanceOf(Date)
|
||||
expect(result.updated_at).toBeInstanceOf(Date)
|
||||
expect(result.uuid).not.toBeNull()
|
||||
expect(result.content.title).toBe('test')
|
||||
expect(result.content.text).toBe(
|
||||
'[{"service":"TestMail","account":"test@test.com","secret":"TESTMAILTESTMAILTESTMAILTESTMAIL","notes":"Some note"},{"service":"Some Service","account":"test@test.com","secret":"SOMESERVICESOMESERVICESOMESERVIC","notes":"Some other service"}]',
|
||||
)
|
||||
expect(result.content.noteType).toBeFalsy()
|
||||
expect(result.content.editorIdentifier).toBeFalsy()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,92 @@
|
||||
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { readFileAsText } from '../Utils'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { WebApplicationInterface } from '@standardnotes/services'
|
||||
import { Importer } from '../Importer'
|
||||
|
||||
type AegisData = {
|
||||
db: {
|
||||
entries: {
|
||||
issuer: string
|
||||
name: string
|
||||
info: {
|
||||
secret: string
|
||||
}
|
||||
note: string
|
||||
}[]
|
||||
}
|
||||
}
|
||||
|
||||
type AuthenticatorEntry = {
|
||||
service: string
|
||||
account: string
|
||||
secret: string
|
||||
notes: string
|
||||
}
|
||||
|
||||
export class AegisToAuthenticatorConverter extends Importer {
|
||||
constructor(protected override application: WebApplicationInterface) {
|
||||
super(application)
|
||||
}
|
||||
|
||||
createNoteFromEntries(
|
||||
entries: AuthenticatorEntry[],
|
||||
file: {
|
||||
lastModified: number
|
||||
name: string
|
||||
},
|
||||
addEditorInfo: boolean,
|
||||
): DecryptedTransferPayload<NoteContent> {
|
||||
return {
|
||||
created_at: new Date(file.lastModified),
|
||||
created_at_timestamp: file.lastModified,
|
||||
updated_at: new Date(file.lastModified),
|
||||
updated_at_timestamp: file.lastModified,
|
||||
uuid: this.application.generateUUID(),
|
||||
content_type: ContentType.Note,
|
||||
content: {
|
||||
title: file.name.split('.')[0],
|
||||
text: JSON.stringify(entries),
|
||||
references: [],
|
||||
...(addEditorInfo && {
|
||||
noteType: NoteType.Authentication,
|
||||
editorIdentifier: FeatureIdentifier.TokenVaultEditor,
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
async convertAegisBackupFileToNote(
|
||||
file: File,
|
||||
addEditorInfo: boolean,
|
||||
): Promise<DecryptedTransferPayload<NoteContent>> {
|
||||
const content = await readFileAsText(file)
|
||||
|
||||
const entries = this.parseEntries(content)
|
||||
|
||||
if (!entries) {
|
||||
throw new Error('Could not parse entries')
|
||||
}
|
||||
|
||||
return this.createNoteFromEntries(entries, file, addEditorInfo)
|
||||
}
|
||||
|
||||
parseEntries(data: string): AuthenticatorEntry[] | null {
|
||||
try {
|
||||
const json = JSON.parse(data) as AegisData
|
||||
const entries = json.db.entries.map((entry) => {
|
||||
return {
|
||||
service: entry.issuer,
|
||||
account: entry.name,
|
||||
secret: entry.info.secret,
|
||||
notes: entry.note,
|
||||
} as AuthenticatorEntry
|
||||
})
|
||||
return entries
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
42
packages/ui-services/src/Import/AegisConverter/testData.ts
Normal file
42
packages/ui-services/src/Import/AegisConverter/testData.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
const data = {
|
||||
version: 1,
|
||||
header: {
|
||||
slots: null,
|
||||
params: null,
|
||||
},
|
||||
db: {
|
||||
version: 2,
|
||||
entries: [
|
||||
{
|
||||
type: 'totp',
|
||||
uuid: 'c74a11c4-4f23-417b-818a-e11f6a4d51d7',
|
||||
name: 'test@test.com',
|
||||
issuer: 'TestMail',
|
||||
note: 'Some note',
|
||||
icon: null,
|
||||
info: {
|
||||
secret: 'TESTMAILTESTMAILTESTMAILTESTMAIL',
|
||||
algo: 'SHA1',
|
||||
digits: 6,
|
||||
period: 30,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'totp',
|
||||
uuid: '803ed58f-b2c4-386c-9aad-645a47309124',
|
||||
name: 'test@test.com',
|
||||
issuer: 'Some Service',
|
||||
note: 'Some other service',
|
||||
icon: null,
|
||||
info: {
|
||||
secret: 'SOMESERVICESOMESERVICESOMESERVIC',
|
||||
algo: 'SHA1',
|
||||
digits: 6,
|
||||
period: 30,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
export default JSON.stringify(data, null, 2)
|
||||
Reference in New Issue
Block a user