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
JavaScript
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 };