All files / src/routes roadmap-auth.js

100% Statements 44/44
96.29% Branches 26/27
100% Functions 4/4
100% Lines 40/40

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103              1x 1x 1x     1x   1x           46x 8x 8x   38x       22x 22x 88x   22x         1x 41x 41x   34x     34x 29x 27x 19x         32x 13x         13x 4x 5x   5x   4x 4x 3x 3x             32x 10x               22x   2x     2x           1x 5x     4x     1x  
/**
 * Roadmap page authentication routes.
 *
 * GET  /roadmap/me      → check if ShyTalk account exists for authenticated user
 * POST /roadmap/signout → sign out acknowledgment
 */
 
const router = require('express').Router();
const { db } = require('../utils/firebase');
const log = require('../utils/log');
 
// Fields safe to expose on the roadmap profile
const SAFE_FIELDS = ['uniqueId', 'displayName', 'avatarUrl', 'profilePhotoUrl'];
 
const DOWNLOAD_LINKS = {
  android: 'https://play.google.com/store/apps/details?id=com.shyden.shytalk',
  ios: 'https://apps.apple.com/app/shytalk/id6741488545',
};
 
function requireAuth(req, res) {
  if (!req.auth || (!req.auth.uniqueId && !req.auth.uid)) {
    res.status(401).json({ error: 'Authentication required' });
    return true;
  }
  return false;
}
 
function pickSafeFields(data) {
  const safe = {};
  for (const key of SAFE_FIELDS) {
    Eif (key in data) safe[key] = data[key];
  }
  return safe;
}
 
// ─── GET /roadmap/me ────────────────────────────────────────────
 
router.get('/roadmap/me', async (req, res) => {
  try {
    if (requireAuth(req, res)) return;
 
    let userData = null;
 
    // Try direct lookup by uniqueId
    if (req.auth.uniqueId) {
      const userDoc = await db.doc(`users/${req.auth.uniqueId}`).get();
      if (userDoc.exists) {
        userData = { uniqueId: Number(req.auth.uniqueId), ...userDoc.data() };
      }
    }
 
    // Fallback: lookup via identityMap using Firebase UID
    if (!userData && req.auth.uid) {
      const idSnap = await db
        .collection('identityMap')
        .where('firebaseUid', '==', req.auth.uid)
        .get();
 
      if (!idSnap.empty) {
        for (const idDoc of idSnap.docs) {
          const idData = idDoc.data();
          // Skip unlinked entries
          if (idData.unlinked) continue;
 
          const userDoc = await db.doc(`users/${idData.uniqueId}`).get();
          if (userDoc.exists) {
            userData = { uniqueId: idData.uniqueId, ...userDoc.data() };
            break;
          }
        }
      }
    }
 
    // No ShyTalk account found
    if (!userData) {
      return res.status(404).json({
        error:
          'No ShyTalk account found. Download the app to create an account, then come back to login.',
        downloadLinks: DOWNLOAD_LINKS,
      });
    }
 
    // Return safe profile fields only
    res.json(pickSafeFields(userData));
  } catch (err) {
    log.error('roadmap-auth', 'Failed to check account', {
      error: err.message,
    });
    res.status(500).json({ error: 'Internal server error' });
  }
});
 
// ─── POST /roadmap/signout ──────────────────────────────────────
 
router.post('/roadmap/signout', (req, res) => {
  if (requireAuth(req, res)) return;
  // Sign out is handled client-side (Firebase Auth).
  // This endpoint acknowledges the sign out.
  res.json({ success: true });
});
 
module.exports = router;