ipHasher.js
1 import crypto from "crypto"; 2 import config from "@/config.js"; 3 import { logger } from "@/middleware/logging.js"; 4 5 const IpHasherUtils = { 6 hashUserId: (userId) => { 7 if (!userId) { 8 return ""; 9 } 10 return crypto.createHash("sha256").update(userId + config.security.auth.hashSalt).digest("hex").substring(0, 16); 11 }, 12 13 hashIpAddress: (ip, userId) => { 14 if (!ip || typeof ip !== "string") { 15 return null; 16 } 17 18 const normalizedIp = ip.trim().toLowerCase(); 19 const hashedUserId = IpHasherUtils.hashUserId(userId); 20 const salt = `${config.security.auth.hashSalt}-${hashedUserId}`; 21 const hash = crypto.createHash("sha256") 22 .update(normalizedIp + salt) 23 .digest("hex"); 24 25 return hash; 26 }, 27 28 checkIpHashAbuse: async (ipHash, maxSessions = null) => { 29 if (!ipHash || typeof ipHash !== "string") { 30 return { count: 0, exceedsLimit: false }; 31 } 32 33 const limit = maxSessions ?? config.security.maxSessionsPerIp; 34 35 try { 36 const { User } = await import("@/models/User.js"); 37 const count = await User.countDocuments({ lastIpHash: ipHash }).maxTimeMS(config.timeouts.medium); 38 return { count, exceedsLimit: count > limit }; 39 } catch (error) { 40 logger.error("Error checking IP hash abuse", { error: error.message, ipHash: ipHash.substring(0, 8) + "..." }); 41 return { count: 0, exceedsLimit: false, error: true }; 42 } 43 }, 44 }; 45 46 export { IpHasherUtils }; 47 export const hashUserId = IpHasherUtils.hashUserId; 48 export const hashIpAddress = IpHasherUtils.hashIpAddress; 49 export const checkIpHashAbuse = IpHasherUtils.checkIpHashAbuse;