59 lines
1.6 KiB
JavaScript
59 lines
1.6 KiB
JavaScript
// backfill email_lookup from user_profile.email (decrypt if needed)
|
||
import dotenv from 'dotenv';
|
||
dotenv.config(); // only used if you run outside compose
|
||
|
||
import crypto from 'crypto';
|
||
import mysqlPool from '../config/mysqlPool.js';
|
||
import { initEncryption, decrypt } from '../shared/crypto/encryption.js';
|
||
|
||
const sql = mysqlPool.raw || mysqlPool;
|
||
|
||
const EMAIL_INDEX_KEY =
|
||
process.env.EMAIL_INDEX_SECRET || process.env.JWT_SECRET || 'dev-fallback';
|
||
|
||
function emailLookup(s) {
|
||
return crypto
|
||
.createHmac('sha256', EMAIL_INDEX_KEY)
|
||
.update(String(s).trim().toLowerCase())
|
||
.digest('hex');
|
||
}
|
||
|
||
async function run() {
|
||
await initEncryption(); // needed if some emails are gcm:… encrypted
|
||
|
||
const [rows] = await sql.query('SELECT id, email FROM user_profile');
|
||
|
||
let updated = 0, skipped = 0, failed = 0;
|
||
|
||
for (const r of rows) {
|
||
try {
|
||
let plain = r.email || '';
|
||
if (plain && plain.startsWith('gcm:')) {
|
||
// decrypt returns plaintext email
|
||
plain = await decrypt(plain);
|
||
}
|
||
|
||
if (!plain) { skipped++; continue; }
|
||
|
||
const lookup = emailLookup(plain);
|
||
|
||
await sql.query(
|
||
'UPDATE user_profile SET email_lookup = ? WHERE id = ? LIMIT 1',
|
||
[lookup, r.id]
|
||
);
|
||
updated++;
|
||
} catch (e) {
|
||
failed++;
|
||
console.error('[backfill]', r.id, e?.message || e);
|
||
}
|
||
}
|
||
|
||
console.log(`✅ backfill complete updated=${updated} skipped=${skipped} failed=${failed}`);
|
||
}
|
||
|
||
// Allow top‑level await in ESM; otherwise wrap:
|
||
run().then(() => process.exit(0)).catch(err => {
|
||
console.error(err);
|
||
process.exit(1);
|
||
});
|