CoolFace
Apppublic

sanket3280/code-execution

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
challengeTokens.js180 linesDownload Raw Back to utils
1const jwt = require('jsonwebtoken');2const { config } = require('../config/env.config');3 4/**5 * Challenge Token Management Utility6 * Handles generation and verification of challenge-specific JWT tokens7 * with 24-hour expiry and automatic rotation support8 */9 10/**11 * Generate a participant token for challenge access12 * @param {String} userId - User's MongoDB ObjectId13 * @param {String} challengeId - Challenge's MongoDB ObjectId14 * @param {Object} options - Additional options15 * @returns {String} JWT token16 */17function generateParticipantToken(userId, challengeId, options = {}) {18  const payload = {19    type: 'participant',20    userId: userId.toString(),21    challengeId: challengeId.toString(),22    role: options.isCreator ? 'creator' : 'participant',23    permissions: {24      canSolveProblems: true,25      canViewProblems: true,26      canSpectate: options.hasSpectatorAccess || false27    },28    iat: Math.floor(Date.now() / 1000)29  };30 31  // Token expires in 24 hours32  const token = jwt.sign(payload, config.jwt.secret, {33    expiresIn: '24h'34  });35 36  return token;37}38 39/**40 * Generate a spectator token for viewing participant code41 * @param {String} userId - User's MongoDB ObjectId42 * @param {String} challengeId - Challenge's MongoDB ObjectId43 * @param {Object} permissions - Spectator permissions44 * @returns {String} JWT token45 */46function generateSpectatorToken(userId, challengeId, permissions = {}) {47  const payload = {48    type: 'spectator',49    userId: userId.toString(),50    challengeId: challengeId.toString(),51    role: permissions.isCreator ? 'creator' : 'spectator',52    permissions: {53      canViewAllParticipants: permissions.canViewAllParticipants !== false,54      canViewCodeHistory: permissions.canViewCodeHistory || false,55      canFlagSuspicious: permissions.canFlagSuspicious || false,56      canViewSolutions: false, // Spectators cannot view solutions57      canViewJudgeOutput: false, // Spectators cannot view judge output58      canViewErrors: false // Spectators cannot view error details59    },60    iat: Math.floor(Date.now() / 1000)61  };62 63  // Token expires in 24 hours64  const token = jwt.sign(payload, config.jwt.secret, {65    expiresIn: '24h'66  });67 68  return token;69}70 71/**72 * Verify and decode a challenge token73 * @param {String} token - JWT token to verify74 * @returns {Object} Decoded token payload75 * @throws {Error} If token is invalid or expired76 */77function verifyToken(token) {78  try {79    const decoded = jwt.verify(token, config.jwt.secret);80    return decoded;81  } catch (error) {82    if (error.name === 'TokenExpiredError') {83      const err = new Error('Token has expired');84      err.code = 'TOKEN_EXPIRED';85      throw err;86    }87    if (error.name === 'JsonWebTokenError') {88      const err = new Error('Invalid token');89      err.code = 'TOKEN_INVALID';90      throw err;91    }92    throw error;93  }94}95 96/**97 * Check if token is near expiry (< 24 hours remaining)98 * @param {String} token - JWT token to check99 * @returns {Boolean} True if token expires in less than 24 hours100 */101function isTokenNearExpiry(token) {102  try {103    const decoded = jwt.decode(token);104    if (!decoded || !decoded.exp) return true;105    106    const now = Math.floor(Date.now() / 1000);107    const timeUntilExpiry = decoded.exp - now;108    109    // Return true if less than 24 hours (86400 seconds) remaining110    return timeUntilExpiry < 86400;111  } catch (error) {112    return true;113  }114}115 116/**117 * Decode token without verification (for inspection)118 * @param {String} token - JWT token to decode119 * @returns {Object|null} Decoded token payload or null120 */121function decodeToken(token) {122  try {123    return jwt.decode(token);124  } catch (error) {125    return null;126  }127}128 129/**130 * Add token to revocation list in Redis131 * @param {String} token - JWT token to revoke132 * @param {Number} ttl - Time to live in seconds (default 24 hours)133 */134async function revokeToken(token) {135  try {136    const { client: redisClient } = require('./redis');137    if (!redisClient || !redisClient.isOpen) {138      console.warn('Redis not available for token revocation');139      return false;140    }141    142    // Store revoked token with 24 hour TTL143    await redisClient.setEx(`revoked:${token}`, 86400, 'true');144    return true;145  } catch (error) {146    console.error('Error revoking token:', error);147    return false;148  }149}150 151/**152 * Check if token is in revocation list153 * @param {String} token - JWT token to check154 * @returns {Boolean} True if token is revoked155 */156async function isTokenRevoked(token) {157  try {158    const { client: redisClient } = require('./redis');159    if (!redisClient || !redisClient.isOpen) {160      return false; // If Redis is down, don't block valid tokens161    }162    163    const isRevoked = await redisClient.get(`revoked:${token}`);164    return !!isRevoked;165  } catch (error) {166    console.error('Error checking token revocation:', error);167    return false;168  }169}170 171module.exports = {172  generateParticipantToken,173  generateSpectatorToken,174  verifyToken,175  isTokenNearExpiry,176  decodeToken,177  revokeToken,178  isTokenRevoked179};180