Skip to content

Commit

Permalink
feat: new restore backup
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Works committed Dec 19, 2019
1 parent dccce1f commit cde7167
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 143 deletions.
150 changes: 7 additions & 143 deletions src/extension/background-script/WelcomeService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,77 +11,16 @@ import {
recover_ECDH_256k1_KeyPair_ByMnemonicWord,
MnemonicGenerationInformation,
} from '../../utils/mnemonic-code'
import {
createProfileWithPersona,
createPersonaByJsonWebKey,
createDefaultFriendsGroup,
updateOrCreateProfile,
} from '../../database'
import { IdentifierMap } from '../../database/IdentifierMap'
import {
queryPersonasWithPrivateKey,
PersonaDBAccess,
queryProfileDB,
createPersonaDB,
attachProfileDB,
PersonaRecord,
LinkedProfileDetails,
} from '../../database/Persona/Persona.db'
import {
CryptoKeyToJsonWebKey,
JsonWebKeyToCryptoKey,
getKeyParameter,
} from '../../utils/type-transform/CryptoKey-JsonWebKey'
import { createProfileWithPersona, createPersonaByJsonWebKey, createDefaultFriendsGroup } from '../../database'
import { attachProfileDB, LinkedProfileDetails } from '../../database/Persona/Persona.db'
import { CryptoKeyToJsonWebKey } from '../../utils/type-transform/CryptoKey-JsonWebKey'
import { deriveLocalKeyFromECDHKey } from '../../utils/mnemonic-code/localKeyGenerate'
import { BackupJSONFileLatest, UpgradeBackupJSONFile } from '../../utils/type-transform/BackupFormat/JSON/latest'
import { attachProfile } from './IdentityService'
import { BackupJSONFileVersion1 } from '../../utils/type-transform/BackupFormat/JSON/version-1'
import { ProfileIdentifier, PersonaIdentifier, Identifier, ECKeyIdentifier } from '../../database/type'
import { upgradeFromBackupJSONFileVersion1 } from '../../utils/type-transform/BackupFormat/JSON/version-2'
import { ProfileIdentifier, PersonaIdentifier } from '../../database/type'
import { generateBackupJSON } from './WelcomeServices/generateBackupJSON'

OnlyRunInContext('background', 'WelcomeService')

async function generateBackupJSON(): Promise<BackupJSONFileLatest> {
const manifest = browser.runtime.getManifest()
const whoami: BackupJSONFileVersion1['whoami'] = []

// ? transaction start
{
const t = (await PersonaDBAccess()).transaction(['personas', 'profiles'])
for (const persona of await queryPersonasWithPrivateKey(t as any)) {
for (const profileID of persona.linkedProfiles.keys()) {
const profile = await queryProfileDB(profileID, t as any)
whoami.push({
network: profileID.network,
userId: profileID.userId,
nickname: profile?.nickname,
// @ts-ignore
localKey:
// Keep this line to split ts-ignore
(profile?.localKey ?? persona.localKey) as CryptoKey | undefined,
publicKey: persona.publicKey,
privateKey: persona.privateKey,
})
}
}
}
// ? transaction ends

for (const each of whoami) {
// ? Can't do this in the transaction.
// ? Will cause transaction closes.
if (!each.localKey) continue
each.localKey = await CryptoKeyToJsonWebKey((each.localKey as unknown) as CryptoKey)
}

return upgradeFromBackupJSONFileVersion1({
grantedHostPermissions: (await browser.permissions.getAll()).origins || [],
maskbookVersion: manifest.version,
version: 1,
whoami: whoami.filter(x => x.localKey && x.publicKey && x.privateKey && x.network && x.userId),
// people not supported yet.
})
}
export { generateBackupJSON } from './WelcomeServices/generateBackupJSON'
export { restoreBackup } from './WelcomeServices/restoreBackup'

/**
*
Expand Down Expand Up @@ -214,79 +153,4 @@ export async function openOptionsPage(route: string) {
return browser.tabs.create({ url: browser.runtime.getURL('/index.html#' + route) })
}

/**
* Restore the backup
*/
export async function restoreBackup(json: object, whoAmI?: ProfileIdentifier): Promise<void> {
// function mapID(x: { network: string; userId: string }): ProfileIdentifier {
// return new ProfileIdentifier(x.network, x.userId)
// }
const data = UpgradeBackupJSONFile(json, whoAmI)
if (!data) throw new TypeError(geti18nString('service_invalid_backup_file'))

const keyCache = new Map<JsonWebKey, CryptoKey>()
const aes = getKeyParameter('aes')

// Transform all JsonWebKey to CryptoKey
await Promise.all([
...[...data.personas, ...data.profiles]
.filter(x => x.localKey)
.map(x => JsonWebKeyToCryptoKey(x.localKey!, ...aes).then(k => keyCache.set(x.localKey!, k))),
])
{
const t: any = (await PersonaDBAccess()).transaction(['personas', 'profiles'], 'readwrite')
for (const x of data.personas) {
const id = Identifier.fromString(x.identifier, ECKeyIdentifier).unwrap(
`Not a valid identifier at persona.identifier`,
)
if (x.privateKey && !x.privateKey.d) throw new Error('Invalid private key')
await createPersonaDB(
{
createdAt: new Date(x.createdAt),
updatedAt: new Date(x.updatedAt),
identifier: id,
linkedProfiles: new IdentifierMap(new Map(), ProfileIdentifier),
publicKey: x.publicKey,
localKey: keyCache.get(x.localKey!),
mnemonic: x.mnemonic,
nickname: x.nickname,
privateKey: x.privateKey,
},
t,
)
}

for (const x of data.profiles) {
const id = Identifier.fromString(x.identifier, ProfileIdentifier).unwrap(
`Not a valid identifier at profile.identifier`,
)
await updateOrCreateProfile(
{
identifier: id,
createdAt: new Date(x.createdAt),
updatedAt: new Date(x.updatedAt),
nickname: x.nickname,
localKey: keyCache.get(x.localKey!),
},
t,
)
if (x.linkedPersona) {
const cid = Identifier.fromString(x.linkedPersona, ECKeyIdentifier).unwrap(
'Not a valid identifier at linkedPersona',
)
await attachProfileDB(id, cid, { connectionConfirmState: 'confirmed' }, t)
}
}
// ! transaction t ends here.
}

for (const x of data.posts) {
// TODO:
}

for (const x of data.userGroups) {
// TODO:
}
}

export { createPersonaByMnemonic } from '../../database'
59 changes: 59 additions & 0 deletions src/extension/background-script/WelcomeServices/restoreBackup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { ProfileIdentifier, Identifier, ECKeyIdentifier } from '../../../database/type'
import { UpgradeBackupJSONFile } from '../../../utils/type-transform/BackupFormat/JSON/latest'
import { geti18nString } from '../../../utils/i18n'
import { getKeyParameter, JsonWebKeyToCryptoKey } from '../../../utils/type-transform/CryptoKey-JsonWebKey'
import { PersonaDBAccess, createPersonaDB, attachProfileDB } from '../../../database/Persona/Persona.db'
import { updateOrCreateProfile } from '../../../database'
import { PersonaRecordFromJSONFormat } from '../../../utils/type-transform/BackupFormat/JSON/DBRecord-JSON/PersonaRecord'
import { ProfileRecordFromJSONFormat } from '../../../utils/type-transform/BackupFormat/JSON/DBRecord-JSON/ProfileRecord'
import { PostRecordFromJSONFormat } from '../../../utils/type-transform/BackupFormat/JSON/DBRecord-JSON/PostRecord'
import { createPostDB } from '../../../database/post'
import { GroupRecordFromJSONFormat } from '../../../utils/type-transform/BackupFormat/JSON/DBRecord-JSON/GroupRecord'
import { createUserGroupDatabase, updateUserGroupDatabase } from '../../../database/group'

/**
* Restore the backup
*/
export async function restoreBackup(json: object, whoAmI?: ProfileIdentifier): Promise<void> {
const data = UpgradeBackupJSONFile(json, whoAmI)
if (!data) throw new TypeError(geti18nString('service_invalid_backup_file'))

const keyCache = new Map<JsonWebKey, CryptoKey>()
const aes = getKeyParameter('aes')

// Transform all JsonWebKey to CryptoKey
await Promise.all([
...[...data.personas, ...data.profiles]
.filter(x => x.localKey)
.map(x => JsonWebKeyToCryptoKey(x.localKey!, ...aes).then(k => keyCache.set(x.localKey!, k))),
])
{
const t: any = (await PersonaDBAccess()).transaction(['personas', 'profiles'], 'readwrite')
for (const x of data.personas) {
await createPersonaDB(PersonaRecordFromJSONFormat(x, keyCache), t)
}

for (const x of data.profiles) {
const { linkedPersona, ...record } = ProfileRecordFromJSONFormat(x, keyCache)
await updateOrCreateProfile(record, t)
if (linkedPersona) {
await attachProfileDB(record.identifier, linkedPersona, { connectionConfirmState: 'confirmed' }, t)
}
}
// ! transaction t ends here.
}

for (const x of data.posts) {
if (x.postCryptoKey) {
const c = await JsonWebKeyToCryptoKey(x.postCryptoKey, ...aes)
keyCache.set(x.postCryptoKey, c)
}
await createPostDB(PostRecordFromJSONFormat(x, keyCache))
}

for (const x of data.userGroups) {
const rec = GroupRecordFromJSONFormat(x)
await createUserGroupDatabase(rec.identifier, rec.groupName)
await updateUserGroupDatabase(rec, 'append')
}
}

0 comments on commit cde7167

Please sign in to comment.