diff --git a/scratchpad/last_marker.txt b/scratchpad/last_marker.txt new file mode 100644 index 00000000..0d6419cc --- /dev/null +++ b/scratchpad/last_marker.txt @@ -0,0 +1 @@ +L_R18_pass_1782681418 \ No newline at end of file diff --git a/scratchpad/msg_atrest.js b/scratchpad/msg_atrest.js new file mode 100644 index 00000000..b651e0d3 --- /dev/null +++ b/scratchpad/msg_atrest.js @@ -0,0 +1,28 @@ +// Pass L / D1: read latest messages in couples/{COUPLE}/conversations/main/messages. +// Print ONLY metadata + enc-status (never decrypted/plaintext content). Also assert a plaintext +// marker does NOT appear anywhere (at-rest leak check). +const admin = require('firebase-admin') +const path = require('path') +const fs = require('fs') +const SA = path.join(__dirname, '..', 'closer-app-22014-firebase-adminsdk-fbsvc-ed20bf6003.json') +const COUPLE = process.env.COUPLE_ID || 'Xal3Kw3gjSdn0niERYKJ' +const MARKER = (fs.existsSync(path.join(__dirname,'last_marker.txt')) ? fs.readFileSync(path.join(__dirname,'last_marker.txt'),'utf8').trim() : '') +admin.initializeApp({ credential: admin.credential.cert(require(SA)) }) +const db = admin.firestore() +const CIPHER = /^(enc:v1:|sealed:v1:)/ +const enc = v => typeof v==='string' ? (CIPHER.test(v)?`enc✓(${v.length})`:`RAW?(${v.length})`) : typeof v +;(async () => { + const col = db.collection('couples').doc(COUPLE).collection('conversations').doc('main').collection('messages') + const snap = await col.orderBy('createdAt','desc').limit(6).get() + console.log(`marker=${MARKER||'(none)'} latest ${snap.size} messages (newest first):`) + let leak = false + snap.forEach(d => { + const m = d.data() + const ts = m.createdAt && m.createdAt.toDate ? m.createdAt.toDate().toISOString() : m.createdAt + console.log(` ${ts} sender=${(m.senderId||'').slice(0,6)}… text=${enc(m.text)}`) + // leak check across the whole doc JSON + if (MARKER) { const blob = JSON.stringify(m); if (blob.includes(MARKER)) { leak = true; console.log(' ❌❌ PLAINTEXT MARKER LEAK in this doc') } } + }) + if (MARKER) console.log(leak ? '=== LEAK: marker found in plaintext ===' : '=== OK: marker NOT present in plaintext (encrypted or not yet sent) ===') + process.exit(0) +})().catch(e=>{console.error('FATAL',e.message);process.exit(1)}) diff --git a/scratchpad/premium_state.js b/scratchpad/premium_state.js new file mode 100644 index 00000000..392b1f51 --- /dev/null +++ b/scratchpad/premium_state.js @@ -0,0 +1,26 @@ +const admin = require('firebase-admin') +const path = require('path') +const SA = path.join(__dirname, '..', 'closer-app-22014-firebase-adminsdk-fbsvc-ed20bf6003.json') +const COUPLE = process.env.COUPLE_ID || 'Xal3Kw3gjSdn0niERYKJ' +admin.initializeApp({ credential: admin.credential.cert(require(SA)) }) +const db = admin.firestore() +function shallow(v){ if(typeof v==='string') return v.length>40?`str(${v.length})`:v; if(Array.isArray(v)) return `[${v.length}]`; if(v&&typeof v==='object') return '{'+Object.keys(v).join(',')+'}'; return v } +;(async () => { + const c = await db.collection('couples').doc(COUPLE).get() + const cd = c.data() || {} + console.log('=== couple top-level keys ===') + for (const k of Object.keys(cd)) console.log(` ${k} = ${shallow(cd[k])}`) + // find uid-like values + const uids = new Set() + for (const [k,v] of Object.entries(cd)) { + if (typeof v==='string' && /^[A-Za-z0-9]{20,}$/.test(v)) uids.add(v) + if (Array.isArray(v)) v.forEach(x=>{ if(typeof x==='string'&&/^[A-Za-z0-9]{20,}$/.test(x)) uids.add(x) }) + if (v&&typeof v==='object'&&!Array.isArray(v)) Object.keys(v).forEach(x=>{ if(/^[A-Za-z0-9]{20,}$/.test(x)) uids.add(x) }) + } + console.log('=== candidate member uids ===', [...uids].map(u=>u.slice(0,10)+'…')) + for (const uid of uids) { + const ent = await db.collection('users').doc(uid).collection('entitlements').doc('premium').get() + console.log(` ${uid.slice(0,10)}… entitlements/premium:`, ent.exists?JSON.stringify(ent.data()):'MISSING(free)') + } + process.exit(0) +})().catch(e=>{console.error('FATAL',e.message);process.exit(1)}) diff --git a/scratchpad/qh_mirror.js b/scratchpad/qh_mirror.js new file mode 100644 index 00000000..2737f1fe --- /dev/null +++ b/scratchpad/qh_mirror.js @@ -0,0 +1,12 @@ +const admin = require('firebase-admin'); const path=require('path') +admin.initializeApp({credential:admin.credential.cert(require(path.join(__dirname,'..','closer-app-22014-firebase-adminsdk-fbsvc-ed20bf6003.json')))}) +const db=admin.firestore() +const QA='Y05AKO2IlTPMa0JQW1BiNIM0uzK2', SAM='imDjjOTTQv' +;(async()=>{ + for(const uid of [QA]){ + const d=await db.collection('users').doc(uid).get(); const x=d.data()||{} + const keys=Object.keys(x).filter(k=>/quiet|timezone|tz|notif/i.test(k)) + console.log(uid.slice(0,8)+'… quiet/tz keys:', keys.length?JSON.stringify(Object.fromEntries(keys.map(k=>[k,x[k]]))):'(none present)') + } + process.exit(0) +})().catch(e=>{console.error(e.message);process.exit(1)})