Spaces:
Paused
Paused
Download Services/deviceInfoService.js from imkrish/campverse-backend: direct link, hf CLI and curl.
- Browser
- Download file 6.27 kB
-
https://huggingface.co/spaces/imkrish/campverse-backend/resolve/main/Services/deviceInfoService.js
- Command line
-
hf download hf://spaces/imkrish/campverse-backend/Services/deviceInfoService.js
-
curl -L -o deviceInfoService.js https://huggingface.co/spaces/imkrish/campverse-backend/resolve/main/Services/deviceInfoService.js
6.27 kB
| const UAParser = require('ua-parser-js'); | |
| /** | |
| * Device Info Service | |
| * Parses user agent and extracts device, browser, OS information | |
| * Also handles IP-based geolocation | |
| */ | |
| /** | |
| * Parse user agent string to extract device info | |
| * @param {string} userAgent - User agent string from request | |
| * @returns {Object} Parsed device information | |
| */ | |
| function parseUserAgent(userAgent) { | |
| if (!userAgent) { | |
| return { | |
| device: 'Unknown Device', | |
| browser: 'Unknown Browser', | |
| os: 'Unknown OS', | |
| userAgent: '' | |
| }; | |
| } | |
| const parser = new UAParser(userAgent); | |
| const result = parser.getResult(); | |
| // Format device name | |
| let device = 'Unknown Device'; | |
| if (result.device.vendor && result.device.model) { | |
| device = `${result.device.vendor} ${result.device.model}`; | |
| } else if (result.device.type) { | |
| device = result.device.type.charAt(0).toUpperCase() + result.device.type.slice(1); | |
| } else { | |
| // Infer from OS | |
| if (result.os.name?.toLowerCase().includes('android')) { | |
| device = 'Android Device'; | |
| } else if (result.os.name?.toLowerCase().includes('ios')) { | |
| device = 'iPhone/iPad'; | |
| } else if (result.os.name?.toLowerCase().includes('mac')) { | |
| device = 'Mac'; | |
| } else if (result.os.name?.toLowerCase().includes('windows')) { | |
| device = 'Windows PC'; | |
| } else if (result.os.name?.toLowerCase().includes('linux')) { | |
| device = 'Linux PC'; | |
| } else { | |
| device = 'Desktop'; | |
| } | |
| } | |
| // Format browser name with version | |
| let browser = 'Unknown Browser'; | |
| if (result.browser.name) { | |
| browser = result.browser.name; | |
| if (result.browser.version) { | |
| const majorVersion = result.browser.version.split('.')[0]; | |
| browser += ` ${majorVersion}`; | |
| } | |
| } | |
| // Format OS with version | |
| let os = 'Unknown OS'; | |
| if (result.os.name) { | |
| os = result.os.name; | |
| if (result.os.version) { | |
| os += ` ${result.os.version}`; | |
| } | |
| } | |
| return { | |
| device, | |
| browser, | |
| os, | |
| userAgent, | |
| raw: result | |
| }; | |
| } | |
| /** | |
| * Get client IP address from request | |
| * Handles proxies and load balancers | |
| * @param {Object} req - Express request object | |
| * @returns {string} Client IP address | |
| */ | |
| function getClientIP(req) { | |
| // Check various headers for proxied requests | |
| const forwardedFor = req.headers['x-forwarded-for']; | |
| if (forwardedFor) { | |
| // x-forwarded-for can contain multiple IPs, first one is client | |
| return forwardedFor.split(',')[0].trim(); | |
| } | |
| const realIP = req.headers['x-real-ip']; | |
| if (realIP) { | |
| return realIP.trim(); | |
| } | |
| const cfConnectingIP = req.headers['cf-connecting-ip']; // Cloudflare | |
| if (cfConnectingIP) { | |
| return cfConnectingIP.trim(); | |
| } | |
| // Fallback to socket remote address | |
| return req.socket?.remoteAddress || req.ip || 'Unknown'; | |
| } | |
| /** | |
| * Get geolocation from IP address using free IP-API service | |
| * Falls back gracefully if service is unavailable | |
| * @param {string} ipAddress - IP address to geolocate | |
| * @returns {Object} Location information | |
| */ | |
| async function getLocationFromIP(ipAddress) { | |
| const defaultLocation = { | |
| city: '', | |
| region: '', | |
| country: '', | |
| countryCode: '', | |
| formatted: 'Unknown Location', | |
| coordinates: { lat: null, lon: null } | |
| }; | |
| // Skip for localhost/private IPs | |
| if (!ipAddress || | |
| ipAddress === '::1' || | |
| ipAddress === '127.0.0.1' || | |
| ipAddress.startsWith('192.168.') || | |
| ipAddress.startsWith('10.') || | |
| ipAddress.startsWith('172.')) { | |
| return { ...defaultLocation, formatted: 'Local Network' }; | |
| } | |
| try { | |
| // Using ip-api.com (free, no API key needed, 45 req/min limit) | |
| const response = await fetch(`http://ip-api.com/json/${ipAddress}?fields=status,message,country,countryCode,region,regionName,city,lat,lon`, { | |
| signal: AbortSignal.timeout(3000) // 3 second timeout | |
| }); | |
| if (!response.ok) { | |
| return defaultLocation; | |
| } | |
| const data = await response.json(); | |
| if (data.status === 'fail') { | |
| return defaultLocation; | |
| } | |
| const location = { | |
| city: data.city || '', | |
| region: data.regionName || data.region || '', | |
| country: data.country || '', | |
| countryCode: data.countryCode || '', | |
| coordinates: { | |
| lat: data.lat || null, | |
| lon: data.lon || null | |
| } | |
| }; | |
| // Format location string | |
| const parts = [location.city, location.region, location.country].filter(Boolean); | |
| location.formatted = parts.length > 0 ? parts.join(', ') : 'Unknown Location'; | |
| return location; | |
| } catch (error) { | |
| console.error('Geolocation lookup failed:', error.message); | |
| return defaultLocation; | |
| } | |
| } | |
| /** | |
| * Get complete device info from request | |
| * Combines user agent parsing, IP extraction, and geolocation | |
| * @param {Object} req - Express request object | |
| * @returns {Object} Complete device information | |
| */ | |
| async function getDeviceInfo(req) { | |
| const userAgent = req.headers['user-agent'] || ''; | |
| const ipAddress = getClientIP(req); | |
| const deviceInfo = parseUserAgent(userAgent); | |
| const location = await getLocationFromIP(ipAddress); | |
| return { | |
| ...deviceInfo, | |
| ipAddress, | |
| location | |
| }; | |
| } | |
| /** | |
| * Synchronous version - skips geolocation | |
| * Use when you don't need location data immediately | |
| * @param {Object} req - Express request object | |
| * @returns {Object} Device information without location | |
| */ | |
| function getDeviceInfoSync(req) { | |
| const userAgent = req.headers['user-agent'] || ''; | |
| const ipAddress = getClientIP(req); | |
| const deviceInfo = parseUserAgent(userAgent); | |
| return { | |
| ...deviceInfo, | |
| ipAddress, | |
| location: { formatted: 'Loading...' } | |
| }; | |
| } | |
| /** | |
| * Format device info for display | |
| * @param {Object} deviceInfo - Device info object | |
| * @returns {string} Formatted string for display | |
| */ | |
| function formatDeviceInfo(deviceInfo) { | |
| const parts = []; | |
| if (deviceInfo.browser && deviceInfo.browser !== 'Unknown Browser') { | |
| parts.push(deviceInfo.browser); | |
| } | |
| if (deviceInfo.os && deviceInfo.os !== 'Unknown OS') { | |
| parts.push(`on ${deviceInfo.os}`); | |
| } | |
| return parts.length > 0 ? parts.join(' ') : 'Unknown Device'; | |
| } | |
| module.exports = { | |
| parseUserAgent, | |
| getClientIP, | |
| getLocationFromIP, | |
| getDeviceInfo, | |
| getDeviceInfoSync, | |
| formatDeviceInfo | |
| }; | |