UNPKG

rauth-provider

Version:

A lightweight, plug-and-play Node.js library for phone number authentication using the Rauth.io reverse verification flow via WhatsApp or SMS.

157 lines (143 loc) 4.27 kB
import crypto from 'crypto'; /** * Utility functions for RauthProvider */ class Utils { /** * Prepare session initialization payload for API * @param {string} phone - Phone number * @param {string} ip - IP address * @param {string} userAgent - User agent string * @param {string} deviceId - Device ID * @param {string} deviceModel - Device model * @returns {Object} Session initialization payload */ static prepareSessionInitPayload(phone, ip, userAgent, deviceId, deviceModel) { return { phone, ip, userAgent, deviceId, deviceModel, timestamp: Date.now(), }; } /** * Extract device information from request headers * @param {Object} req - Express request object * @returns {Object} Device information */ static extractDeviceInfo(req) { const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress; const userAgent = req.headers['user-agent'] || ''; const deviceId = req.headers['x-device-id'] || ''; const deviceModel = req.headers['x-device-model'] || ''; return { ip, userAgent, deviceId, deviceModel, }; } /** * Validate phone number format * @param {string} phone - Phone number * @returns {boolean} True if valid */ static isValidPhoneNumber(phone) { // Basic phone number validation (can be enhanced as needed) const phoneRegex = /^\+?[1-9]\d{1,14}$/; return phoneRegex.test(phone); } /** * Validate required fields in payload * @param {Object} payload - Payload object * @param {Array} requiredFields - Array of required field names * @returns {Object} Validation result with success flag and missing fields */ static validatePayload(payload, requiredFields) { const missing = []; for (const field of requiredFields) { if (payload[field] === undefined || payload[field] === null || payload[field] === '') { missing.push(field); } } return { success: missing.length === 0, missing, }; } /** * Create a standardized error response * @param {string} message - Error message * @param {string} code - Error code * @param {number} statusCode - HTTP status code * @returns {Object} Error response object */ static createErrorResponse(message, code = 'RAUTH_ERROR', statusCode = 400) { return { success: false, error: { message, code, statusCode, }, }; } /** * Create a standardized success response * @param {Object} data - Success data * @param {string} message - Success message * @returns {Object} Success response object */ static createSuccessResponse(data, message = 'Success') { return { success: true, message, data, }; } /** * Safe JSON parsing with error handling * @param {string} jsonString - JSON string to parse * @returns {Object|null} Parsed object or null if parsing fails */ static safeJsonParse(jsonString) { try { return JSON.parse(jsonString); } catch (error) { return null; } } /** * Generate webhook signature for verification * @param {string} payload - Payload to sign * @param {string} secret - Webhook secret * @returns {string} HMAC signature */ static generateWebhookSignature(payload, secret) { return crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); } /** * Verify webhook signature * @param {string} payload - Payload to verify * @param {string} signature - Provided signature * @param {string} secret - Webhook secret * @returns {boolean} True if signature is valid */ static verifyWebhookSignature(payload, signature, secret) { const expectedSignature = this.generateWebhookSignature(payload, secret); try { return crypto.timingSafeEqual( Buffer.from(expectedSignature, 'hex'), Buffer.from(signature, 'hex') ); } catch (error) { return false; } } } export { Utils };