Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"postinstall": "patch-package && gulp fix-lockfile",
"prepare": "husky install",
"test": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js",
"test:debug": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js --runInBand",
"test:update": "node --experimental-vm-modules ./node_modules/jest/bin/jest.js -u",
"spellcheck": "cspell lint --no-must-find-files"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/backup-format/src/normalize/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import { generateBackupVersion2, isBackupVersion2, normalizeBackupVersion2 } fro
import type { NormalizedBackup } from './type'

export * from './type'
function __normalizeBackup(data: unknown): NormalizedBackup.Data {
async function __normalizeBackup(data: unknown): Promise<NormalizedBackup.Data> {
if (isBackupVersion2(data)) return normalizeBackupVersion2(data)
if (isBackupVersion1(data)) return normalizeBackupVersion1(data)
if (isBackupVersion0(data)) return normalizeBackupVersion0(data)
throw new TypeError(BackupErrors.UnknownFormat)
}

export function normalizeBackup(data: unknown): NormalizedBackup.Data {
const normalized = __normalizeBackup(data)
export async function normalizeBackup(data: unknown): Promise<NormalizedBackup.Data> {
const normalized = await __normalizeBackup(data)

// fix invalid URL
normalized.settings.grantedHostPermissions = normalized.settings.grantedHostPermissions.filter((url) =>
Expand Down
4 changes: 2 additions & 2 deletions packages/backup-format/src/version-0/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function isBackupVersion0(obj: unknown): obj is BackupJSONFileVersion0 {
return false
}
}
export function normalizeBackupVersion0(file: BackupJSONFileVersion0): NormalizedBackup.Data {
export async function normalizeBackupVersion0(file: BackupJSONFileVersion0): Promise<NormalizedBackup.Data> {
const backup = createEmptyNormalizedBackup()
backup.meta.version = 0
backup.meta.maskVersion = Some('<=1.3.2')
Expand All @@ -36,7 +36,7 @@ export function normalizeBackupVersion0(file: BackupJSONFileVersion0): Normalize
if (!isEC_Public_JsonWebKey(publicKey)) return backup

const persona: NormalizedBackup.PersonaBackup = {
identifier: ECKeyIdentifierFromJsonWebKey(publicKey),
identifier: await ECKeyIdentifierFromJsonWebKey(publicKey),
publicKey,
linkedProfiles: new Map(),
localKey: isAESJsonWebKey(local) ? Some(local) : None,
Expand Down
4 changes: 2 additions & 2 deletions packages/backup-format/src/version-1/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function isBackupVersion1(obj: unknown): obj is BackupJSONFileVersion1 {
return false
}
}
export function normalizeBackupVersion1(file: BackupJSONFileVersion1): NormalizedBackup.Data {
export async function normalizeBackupVersion1(file: BackupJSONFileVersion1): Promise<NormalizedBackup.Data> {
const backup = createEmptyNormalizedBackup()

backup.meta.version = 1
Expand All @@ -49,7 +49,7 @@ export function normalizeBackupVersion1(file: BackupJSONFileVersion1): Normalize
}

if (isEC_Public_JsonWebKey(publicKey)) {
const personaID = ECKeyIdentifierFromJsonWebKey(publicKey)
const personaID = await ECKeyIdentifierFromJsonWebKey(publicKey)
const persona: NormalizedBackup.PersonaBackup = backup.personas.get(personaID) || {
identifier: personaID,
nickname: None,
Expand Down
4 changes: 2 additions & 2 deletions packages/backup-format/src/version-2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function isBackupVersion2(item: unknown): item is BackupJSONFileVersion2
return false
}

export function normalizeBackupVersion2(item: BackupJSONFileVersion2): NormalizedBackup.Data {
export async function normalizeBackupVersion2(item: BackupJSONFileVersion2): Promise<NormalizedBackup.Data> {
const backup = createEmptyNormalizedBackup()

backup.meta.version = 2
Expand All @@ -38,7 +38,7 @@ export function normalizeBackupVersion2(item: BackupJSONFileVersion2): Normalize
for (const persona of personas) {
const { publicKey } = persona
if (!isEC_Public_JsonWebKey(publicKey)) continue
const identifier = ECKeyIdentifierFromJsonWebKey(publicKey)
const identifier = await ECKeyIdentifierFromJsonWebKey(publicKey)
const normalizedPersona: NormalizedBackup.PersonaBackup = {
identifier,
linkedProfiles: new Map(),
Expand Down
13 changes: 8 additions & 5 deletions packages/encryption/src/payload_internal/version-37.encoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ const enum Index {
data = 6,
}
export async function encode37(payload: PayloadWellFormed.Payload) {
const payload_arr: any[] = [0]
type KeyMaterials = Partial<Record<EC_KeyCurveEnum, Uint8Array>>
type AcceptableArray = Array<number | string | Uint8Array | null | Array<KeyMaterials | number | Uint8Array>>

const payload_arr: AcceptableArray = [0]

if (payload.author.some) {
const { network, userId } = payload.author.val
Expand All @@ -27,7 +30,7 @@ export async function encode37(payload: PayloadWellFormed.Payload) {
const raw = await exportCryptoKeyToRaw(key)
if (raw.ok) {
if (algr === EC_KeyCurveEnum.secp256k1)
payload_arr[Index.authorPublicKey] = compressSecp256k1KeyRaw(raw.val)
payload_arr[Index.authorPublicKey] = await compressSecp256k1KeyRaw(raw.val)
else payload_arr[Index.authorPublicKey] = raw.val
} else {
payload_arr[Index.authorPublicKey] = null
Expand All @@ -36,13 +39,13 @@ export async function encode37(payload: PayloadWellFormed.Payload) {
}
if (payload.encryption.type === 'E2E') {
const { ephemeralPublicKey, iv, ownersAESKeyEncrypted } = payload.encryption
const keyMaterials: any = {}
const subArr: any[] = [1, ownersAESKeyEncrypted, iv, keyMaterials]
const keyMaterials: Partial<Record<EC_KeyCurveEnum, Uint8Array>> = {}
const subArr: Array<KeyMaterials | number | Uint8Array> = [1, ownersAESKeyEncrypted, iv, keyMaterials]
for (const [alg, key] of ephemeralPublicKey.entries()) {
const k = await exportCryptoKeyToRaw(key)
if (k.err) warn(key, k.err)
else {
if (alg === EC_KeyCurveEnum.secp256k1) keyMaterials[alg] = compressSecp256k1KeyRaw(k.val)
if (alg === EC_KeyCurveEnum.secp256k1) keyMaterials[alg] = await compressSecp256k1KeyRaw(k.val)
else keyMaterials[alg] = k.val
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function importAsymmetryKey(algr: unknown, key: unknown, name: string) {
if (typeof algr === 'number') {
if (algr in EC_KeyCurveEnum) {
if (algr === EC_KeyCurveEnum.secp256k1) {
pubKey = decompressSecp256k1KeyRaw(pubKey)
pubKey = await decompressSecp256k1KeyRaw(pubKey)
}
const key = await importEC(pubKey, algr)
if (key.err) return key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function encodeSignature(sig: Option<Signature>) {
async function compressSecp256k1Key(key: CryptoKey) {
const jwk = await exportCryptoKeyToJWK(key)
if (jwk.err) return jwk.mapErr((e) => new CheckedError(CryptoException.InvalidCryptoKey, e))
const arr = Result.wrap(() => compressSecp256k1Point(jwk.val.x!, jwk.val.y!)).mapErr(
const arr = (await Result.wrapAsync(() => compressSecp256k1Point(jwk.val.x!, jwk.val.y!))).mapErr(
(e) => new CheckedError(CryptoException.InvalidCryptoKey, e),
)
if (arr.err) return arr
Expand Down
8 changes: 4 additions & 4 deletions packages/encryption/src/payload_internal/version-38.parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ async function decodePublicSharedAESKey(
}

async function decodeECDHPublicKey(compressedPublic: string): Promise<OptionalResult<EC_Key, CryptoException>> {
const key = decodeUint8ArrayCrypto(compressedPublic).andThen((val) =>
Result.wrap(() => decompressSecp256k1Point(val)).mapErr(
(e) => new CheckedError(CryptoException.InvalidCryptoKey, e),
),
const key = await andThenAsync(decodeUint8ArrayCrypto(compressedPublic), async (val) =>
(
await Result.wrapAsync(() => decompressSecp256k1Point(val))
).mapErr((e) => new CheckedError(CryptoException.InvalidCryptoKey, e)),
)

if (key.err) return key
Expand Down
1 change: 1 addition & 0 deletions packages/encryption/tests/setup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { test } from '@jest/globals'
import { atob, btoa } from 'buffer'
import { polyfill } from '@dimensiondev/secp256k1-webcrypto/node'
import '../../shared-base/node_modules/tiny-secp256k1'

test('Setup env', () => {})

Expand Down
4 changes: 2 additions & 2 deletions packages/mask/background/database/persona/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ export async function createPersonaByJsonWebKey(options: {
mnemonic?: PersonaRecord['mnemonic']
uninitialized?: boolean
}): Promise<PersonaIdentifier> {
const identifier = ECKeyIdentifierFromJsonWebKey(options.publicKey)
const identifier = await ECKeyIdentifierFromJsonWebKey(options.publicKey)
const record: PersonaRecord = {
createdAt: new Date(),
updatedAt: new Date(),
Expand Down Expand Up @@ -184,7 +184,7 @@ export async function createProfileWithPersona(
mnemonic?: PersonaRecord['mnemonic']
},
): Promise<void> {
const ec_id = ECKeyIdentifierFromJsonWebKey(keys.publicKey)
const ec_id = await ECKeyIdentifierFromJsonWebKey(keys.publicKey)
const rec: PersonaRecord = {
createdAt: new Date(),
updatedAt: new Date(),
Expand Down
2 changes: 1 addition & 1 deletion packages/mask/background/services/backup/restore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export async function restoreUnconfirmedBackup({ id, action }: RestoreUnconfirme
export async function addUnconfirmedBackup(raw: string): Promise<Result<{ info: BackupPreview; id: string }, unknown>> {
return Result.wrapAsync(async () => {
const backupObj: unknown = JSON.parse(raw)
const backup = normalizeBackup(backupObj)
const backup = await normalizeBackup(backupObj)
const preview = getBackupPreviewInfo(backup)
const id = uuid()
unconfirmedBackup.set(id, backup)
Expand Down
2 changes: 1 addition & 1 deletion packages/mask/background/services/crypto/decryption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ async function storeAuthorPublicKey(
if (persona?.privateKey) return

const key = (await crypto.subtle.exportKey('jwk', pub.key)) as EC_JsonWebKey
const otherPersona = await queryPersonaDB(ECKeyIdentifierFromJsonWebKey(key))
const otherPersona = await queryPersonaDB(await ECKeyIdentifierFromJsonWebKey(key))
if (otherPersona?.privateKey) return

return createProfileWithPersona(
Expand Down
6 changes: 3 additions & 3 deletions packages/mask/background/services/identity/persona/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export async function setupPersona(id: PersonaIdentifier) {
export async function loginExistPersonaByPrivateKey(privateKeyString: string): Promise<PersonaIdentifier | null> {
const privateKey = decode(decodeArrayBuffer(privateKeyString))
if (!isEC_Private_JsonWebKey(privateKey)) throw new TypeError('Invalid private key')
const identifier = ECKeyIdentifierFromJsonWebKey(privateKey)
const identifier = await ECKeyIdentifierFromJsonWebKey(privateKey)

const persona = await queryPersonaDB(identifier, undefined, true)
if (persona) {
Expand All @@ -86,7 +86,7 @@ export async function loginExistPersonaByPrivateKey(privateKeyString: string): P
export async function mobile_queryPersonaByPrivateKey(privateKeyString: string): Promise<MobilePersona | null> {
if (process.env.architecture !== 'app') throw new Error('This function is only available in app')
const privateKey = decode(decodeArrayBuffer(privateKeyString)) as EC_JsonWebKey
const identifier = ECKeyIdentifierFromJsonWebKey(privateKey)
const identifier = await ECKeyIdentifierFromJsonWebKey(privateKey)

const persona = await queryPersonaDB(identifier, undefined, true)
if (persona) {
Expand All @@ -112,7 +112,7 @@ export async function queryPersonaByMnemonic(mnemonic: string, password: ''): Pr
}

const { key } = await recover_ECDH_256k1_KeyPair_ByMnemonicWord(mnemonic, password)
const identifier = ECKeyIdentifierFromJsonWebKey(key.privateKey)
const identifier = await ECKeyIdentifierFromJsonWebKey(key.privateKey)
const persona = await queryPersonaDB(identifier, undefined, true)
if (persona) {
await loginPersona(persona.identifier)
Expand Down
8 changes: 4 additions & 4 deletions packages/mask/background/services/identity/persona/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export async function generate_ECDH_256k1_KeyPair_ByMnemonicWord(
const seed = await bip39.mnemonicToSeed(mnemonicWord, password)
const masterKey = wallet.HDKey.parseMasterSeed(seed)
const derivedKey = masterKey.derive(path)
const key = await split_ec_k256_keypair_into_pub_priv(HDKeyToJwk(derivedKey))
const key = await split_ec_k256_keypair_into_pub_priv(await HDKeyToJwk(derivedKey))
return {
key,
password,
Expand All @@ -76,7 +76,7 @@ export async function recover_ECDH_256k1_KeyPair_ByMnemonicWord(
const seed = await bip39.mnemonicToSeed(mnemonicWord, password)
const masterKey = wallet.HDKey.parseMasterSeed(seed)
const derivedKey = masterKey.derive(path)
const key = await split_ec_k256_keypair_into_pub_priv(HDKeyToJwk(derivedKey))
const key = await split_ec_k256_keypair_into_pub_priv(await HDKeyToJwk(derivedKey))
return {
key,
password,
Expand All @@ -89,8 +89,8 @@ export async function recover_ECDH_256k1_KeyPair_ByMnemonicWord(

export const validateMnemonic = bip39.validateMnemonic

function HDKeyToJwk(hdk: wallet.HDKey): JsonWebKey {
const jwk = decompressSecp256k1Key(encodeArrayBuffer(hdk.publicKey))
async function HDKeyToJwk(hdk: wallet.HDKey): Promise<JsonWebKey> {
const jwk = await decompressSecp256k1Key(encodeArrayBuffer(hdk.publicKey))
jwk.d = hdk.privateKey ? toBase64URL(hdk.privateKey) : undefined
return jwk
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ delegateWalletRestore(async function (backup) {
const name = wallet.name

if (wallet.privateKey.some)
await recoverWalletFromPrivateKey(name, JWKToKey(wallet.privateKey.val, 'private'))
await recoverWalletFromPrivateKey(name, await JWKToKey(wallet.privateKey.val, 'private'))
else if (wallet.mnemonic.some) {
// fix a backup bug of pre-v2.2.2 versions
const accounts = await getDerivableAccounts(wallet.mnemonic.val.words, 1, 5)
Expand Down Expand Up @@ -223,17 +223,17 @@ function keyToJWK(key: string, type: 'public' | 'private'): JsonWebKey {
}
}

function JWKToKey(jwk: EC_JsonWebKey, type: 'public' | 'private'): string {
async function JWKToKey(jwk: EC_JsonWebKey, type: 'public' | 'private'): Promise<string> {
const ec = new EC('secp256k1')
if (type === 'public' && jwk.x && jwk.y) {
const xb = fromBase64URL(jwk.x)
const yb = fromBase64URL(jwk.y)
const point = new Uint8Array(concatArrayBuffer(new Uint8Array([0x04]), xb, yb))
if (isSecp256k1Point(point)) return `0x${ec.keyFromPublic(point).getPublic(false, 'hex')}`
if (await isSecp256k1Point(point)) return `0x${ec.keyFromPublic(point).getPublic(false, 'hex')}`
}
if (type === 'private' && jwk.d) {
const db = fromBase64URL(jwk.d)
if (isSecp256k1PrivateKey(db)) return `0x${ec.keyFromPrivate(db).getPrivate('hex')}`
if (await isSecp256k1PrivateKey(db)) return `0x${ec.keyFromPrivate(db).getPrivate('hex')}`
}
throw new Error('invalid private key')
}
Expand Down
Loading