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.

249 lines (219 loc) 6.97 kB
const RauthProvider = require('./core/RauthProvider'); const Utils = require('./core/utils'); /** * Server utilities for Express webhook handling */ class RauthServer { /** * Create Express middleware for body parsing with raw body preservation * @returns {Function} Express middleware */ static createBodyParserMiddleware() { return (req, res, next) => { let data = ''; req.setEncoding('utf8'); req.on('data', (chunk) => { data += chunk; }); req.on('end', () => { try { req.body = JSON.parse(data); req.rawBody = data; next(); } catch (error) { res.status(400).json({ success: false, error: 'Invalid JSON payload' }); } }); }; } /** * Create webhook validation middleware * @returns {Function} Express middleware */ static createWebhookValidationMiddleware() { return (req, res, next) => { const webhookSecret = req.headers['x-webhook-secret']; if (!webhookSecret) { return res.status(401).json({ success: false, error: 'Missing webhook secret header' }); } // Get initialized config const stats = RauthProvider.getStats(); if (!stats.initialized) { return res.status(500).json({ success: false, error: 'RauthProvider not initialized' }); } next(); }; } /** * Create comprehensive webhook handler with validation * @returns {Function} Express middleware */ static createWebhookHandler() { return [ this.createBodyParserMiddleware(), this.createWebhookValidationMiddleware(), RauthProvider.webhookHandler() ]; } /** * Create health check endpoint * @returns {Function} Express middleware */ static createHealthCheckHandler() { return async (req, res) => { try { const stats = RauthProvider.getStats(); const apiHealth = await RauthProvider.checkApiHealth(); res.status(200).json({ success: true, message: 'RauthProvider is healthy', stats: stats, apiHealth: apiHealth }); } catch (error) { res.status(500).json({ success: false, error: 'RauthProvider health check failed', details: error.message }); } }; } /** * Create session initialization endpoint * @returns {Function} Express middleware */ static createSessionInitHandler() { return async (req, res) => { try { const { phone } = req.body; if (!phone) { return res.status(400).json({ success: false, error: 'Phone number is required' }); } // Pass the entire headers object to initSession const initResult = await RauthProvider.initSession(phone, req.headers); // Forward the API response directly to the client // New response format: // { // session_token: "api-generated-token", // wa_link: "https://wa.me/918888888888?text=fhad-dfsfd-eqwt-l4dt-lueb", // qr_image_link: "https://cdn.rauth.io/qr/15523456.png" // } res.status(200).json({ success: true, message: 'Session initialized successfully', ...initResult }); } catch (error) { res.status(400).json({ success: false, error: error.message }); } }; } /** * Create session verification endpoint * @returns {Function} Express middleware */ static createSessionVerificationHandler() { return async (req, res) => { try { const { sessionToken, userPhone } = req.body; if (!sessionToken || !userPhone) { return res.status(400).json({ success: false, error: 'sessionToken and userPhone are required' }); } const isVerified = await RauthProvider.verifySession(sessionToken, userPhone); if (!isVerified) { return res.status(401).json({ success: false, error: 'Phone number not verified or session expired' }); } res.status(200).json({ success: true, message: 'Session verified successfully', sessionToken: sessionToken, userPhone: userPhone }); } catch (error) { res.status(400).json({ success: false, error: error.message }); } }; } /** * Create session revocation check middleware * @returns {Function} Express middleware */ static createRevocationCheckMiddleware() { return async (req, res, next) => { try { const sessionToken = req.headers['x-session-token'] || req.body.sessionToken; if (!sessionToken) { return res.status(400).json({ success: false, error: 'Session token is required' }); } const isRevoked = await RauthProvider.isSessionRevoked(sessionToken); if (isRevoked) { return res.status(401).json({ success: false, error: 'Session has been revoked. Please log in again.' }); } req.sessionToken = sessionToken; next(); } catch (error) { res.status(500).json({ success: false, error: 'Internal server error' }); } }; } /** * Setup complete Express routes for RauthProvider * @param {Object} app - Express app instance * @param {Object} options - Route options * @param {string} [options.webhookPath='/rauth/webhook'] - Webhook endpoint path * @param {string} [options.healthPath='/rauth/health'] - Health check endpoint path * @param {string} [options.initPath='/rauth/init'] - Session init endpoint path * @param {string} [options.verifyPath='/rauth/verify'] - Session verify endpoint path */ static setupRoutes(app, options = {}) { const { webhookPath = '/rauth/webhook', healthPath = '/rauth/health', initPath = '/rauth/init', verifyPath = '/rauth/verify' } = options; // Webhook endpoint app.post(webhookPath, this.createWebhookHandler()); // Health check endpoint app.get(healthPath, this.createHealthCheckHandler()); // Session initialization endpoint app.post(initPath, this.createSessionInitHandler()); // Session verification endpoint app.post(verifyPath, this.createSessionVerificationHandler()); } } module.exports = RauthServer;