/* MIGRATION TO CLEAN PRODUCTION DATA * * the way the passphrases are stored in login_user_backups is inconsistent. * we need to try to detect which word list was used and transform it accordingly */ import fs from 'fs' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') const PHRASE_WORD_COUNT = 24 const WORDS = fs .readFileSync('src/config/mnemonic.uncompressed_buffer13116.txt') .toString() .split(',') const KeyPairEd25519Create = (passphrase: string[]): Buffer[] => { if (!passphrase.length || passphrase.length < PHRASE_WORD_COUNT) { throw new Error('passphrase empty or to short') } const state = Buffer.alloc(sodium.crypto_hash_sha512_STATEBYTES) sodium.crypto_hash_sha512_init(state) for (let i = 0; i < PHRASE_WORD_COUNT; i++) { const value = Buffer.alloc(8) const wordIndex = WORDS.indexOf(passphrase[i]) value.writeBigInt64LE(BigInt(wordIndex)) sodium.crypto_hash_sha512_update(state, value) } // trailing space is part of the login_server implementation const clearPassphrase = passphrase.slice(0, PHRASE_WORD_COUNT).join(' ') + ' ' sodium.crypto_hash_sha512_update(state, Buffer.from(clearPassphrase)) const outputHashBuffer = Buffer.alloc(sodium.crypto_hash_sha512_BYTES) sodium.crypto_hash_sha512_final(state, outputHashBuffer) const pubKey = Buffer.alloc(sodium.crypto_sign_PUBLICKEYBYTES) const privKey = Buffer.alloc(sodium.crypto_sign_SECRETKEYBYTES) sodium.crypto_sign_seed_keypair( pubKey, privKey, outputHashBuffer.slice(0, sodium.crypto_sign_SEEDBYTES), ) return [pubKey, privKey] } export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { // Delete data with no reference in login_users table // eslint-disable-next-line no-console // 663 affected rows const userBackups = await queryFn( `SELECT passphrase, LOWER(HEX(pubkey)) as pubkey, user_id FROM login_user_backups LEFT JOIN login_users ON login_user_backups.user_id = login_users.id WHERE user_id=1503`, // WHERE pubkey is not null`, // todo fix this condition and regenerate ) let i = 0 // eslint-disable-next-line no-console userBackups.forEach(async (userBackup) => { const passphrase = userBackup.passphrase.split(' ') const keyPair = KeyPairEd25519Create(passphrase) if (keyPair[0].toString('hex') !== userBackup.pubkey) { i++ // eslint-disable-next-line no-console console.log( 'Missmatch Pubkey', i, userBackup.user_id, `"${userBackup.passphrase}"`, `"${keyPair[0].toString('hex')}`, `"${userBackup.pubkey}"`, ) } else { // eslint-disable-next-line no-console // console.log('SUCCESS: ', `"${keyPair[0].toString('hex')}`, `"${userBackup.pubkey}"`) } }) } export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { return [] // cannot transform things back }