// Dev helper: provision a STATIC-OTP mitra login for local/QA testing. // // Uses the existing test-OTP-bypass allowlist (app_config.test_otp_bypass), // the same mechanism shipped for Apple-reviewer QA. It: // 1. ensures an ACTIVE mitra exists with the test phone (mitras default to // is_active=false, which the mitra verify route rejects with 403), // 2. adds a phone-scoped, mitra-scoped static OTP entry (bcrypt-hashed), // 3. flips the global bypass kill-switch on. // // After running, log into the mitra app with PHONE + OTP below — no Fazpass, // no console code-reading. Re-running is idempotent. // // Usage (from backend/): node scripts/setup-test-mitra-otp.mjs // Override defaults: TEST_MITRA_PHONE=+628... TEST_MITRA_OTP=123456 node scripts/setup-test-mitra-otp.mjs import 'dotenv/config' import { getDb } from '../src/db/client.js' import { getTestOtpBypass, addTestOtpBypassEntry, setTestOtpBypassEnabled, } from '../src/services/config.service.js' const PHONE = process.env.TEST_MITRA_PHONE || '+6281200000001' const OTP = process.env.TEST_MITRA_OTP || '123456' const LABEL = process.env.TEST_MITRA_LABEL || 'Dev static OTP (mitra)' const DISPLAY_NAME = process.env.TEST_MITRA_NAME || 'Test Bestie' // Far-future expiry — the allowlist requires a future expires_at per entry. const EXPIRES_AT = '2099-01-01T00:00:00.000Z' const sql = getDb() async function main () { // 1. Ensure an ACTIVE mitra with this phone (raw SQL — avoids importing // mitra.service, which pulls in the valkey plugin and would leave an open // handle keeping this script alive). const [existing] = await sql`SELECT id, is_active FROM mitras WHERE phone = ${PHONE}` if (!existing) { const [m] = await sql` INSERT INTO mitras (phone, display_name, is_active) VALUES (${PHONE}, ${DISPLAY_NAME}, true) RETURNING id ` console.log(` created active mitra ${m.id} (${PHONE})`) } else if (!existing.is_active) { await sql`UPDATE mitras SET is_active = true WHERE id = ${existing.id}` console.log(` mitra ${existing.id} existed — activated`) } else { console.log(` mitra ${existing.id} already exists and active`) } // 2. Add the static-OTP allowlist entry (skip if one already exists for this // phone+mitra — addTestOtpBypassEntry throws on duplicate). const current = await getTestOtpBypass() const exists = current.entries.some(e => e.phone === PHONE && e.user_type === 'mitra') if (exists) { console.log(' bypass entry already present for this phone+mitra — leaving as is') console.log(' (to rotate the OTP: delete the entry in CC → Settings, then re-run)') } else { await addTestOtpBypassEntry({ phone: PHONE, otp: OTP, user_type: 'mitra', label: LABEL, expires_at: EXPIRES_AT, }) console.log(` added bypass entry: ${PHONE} → otp ${OTP} (mitra)`) } // 3. Global kill-switch ON. await setTestOtpBypassEnabled(true) console.log(' bypass allowlist ENABLED') console.log('\n✅ Static mitra OTP ready:') console.log(` phone: ${PHONE}`) console.log(` otp: ${exists ? '(unchanged — set on a previous run)' : OTP}`) } main() .then(() => sql.end({ timeout: 5 })) .catch(async (err) => { console.error('FAILED:', err.message) await sql.end({ timeout: 5 }) process.exit(1) })