UNPKG

@critters/next

Version:

Secure bug reporting library for Next.js applications

223 lines (222 loc) 7.17 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateSignature = generateSignature; exports.isBrowser = isBrowser; exports.isServer = isServer; exports.getBrowserInfo = getBrowserInfo; exports.formatError = formatError; exports.safeStringify = safeStringify; exports.sanitizeData = sanitizeData; exports.getTimestamp = getTimestamp; exports.debugLog = debugLog; const crypto_1 = require("crypto"); const hmac_sha256_1 = __importDefault(require("crypto-js/hmac-sha256")); const enc_hex_1 = __importDefault(require("crypto-js/enc-hex")); /** * Generate HMAC signature for request validation */ function generateSignature(payload, secretKey) { // If no secret key is provided, return an empty string if (!secretKey) { return ""; } // Use Node.js crypto in server environment if (typeof window === "undefined" && typeof crypto_1.createHmac === "function") { return (0, crypto_1.createHmac)("sha256", secretKey).update(payload).digest("hex"); } // Use crypto-js in browser environment return (0, hmac_sha256_1.default)(payload, secretKey).toString(enc_hex_1.default); } /** * Check if code is running in browser environment */ function isBrowser() { return typeof window !== "undefined"; } /** * Check if code is running in server environment */ function isServer() { return !isBrowser(); } /** * Get browser information */ function getBrowserInfo() { if (!isBrowser()) { return {}; } const { userAgent } = window.navigator; // Extract browser name and version const getBrowserDetails = () => { var _a, _b, _c, _d, _e; const ua = userAgent.toLowerCase(); let browser = "unknown"; let version = "unknown"; // Extract browser and version if (ua.indexOf("edge") > -1) { browser = "edge"; version = ((_a = ua.match(/edge\/(\d+(\.\d+)?)/)) === null || _a === void 0 ? void 0 : _a[1]) || "unknown"; } else if (ua.indexOf("chrome") > -1) { browser = "chrome"; version = ((_b = ua.match(/chrome\/(\d+(\.\d+)?)/)) === null || _b === void 0 ? void 0 : _b[1]) || "unknown"; } else if (ua.indexOf("firefox") > -1) { browser = "firefox"; version = ((_c = ua.match(/firefox\/(\d+(\.\d+)?)/)) === null || _c === void 0 ? void 0 : _c[1]) || "unknown"; } else if (ua.indexOf("safari") > -1) { browser = "safari"; version = ((_d = ua.match(/version\/(\d+(\.\d+)?)/)) === null || _d === void 0 ? void 0 : _d[1]) || "unknown"; } else if (ua.indexOf("msie") > -1 || ua.indexOf("trident") > -1) { browser = "ie"; version = ((_e = ua.match(/(?:msie |rv:)(\d+(\.\d+)?)/)) === null || _e === void 0 ? void 0 : _e[1]) || "unknown"; } return { name: browser, version }; }; // Extract OS information const getOSDetails = () => { const ua = userAgent.toLowerCase(); let os = "unknown"; if (ua.indexOf("win") > -1) { os = "windows"; } else if (ua.indexOf("mac") > -1) { os = "macos"; } else if (ua.indexOf("linux") > -1) { os = "linux"; } else if (ua.indexOf("android") > -1) { os = "android"; } else if (ua.indexOf("ios") > -1 || /iphone|ipad|ipod/.test(ua)) { os = "ios"; } return os; }; // Detect device type const getDeviceType = () => { const ua = userAgent.toLowerCase(); if (/ipad|tablet|playbook|silk/.test(ua)) { return "tablet"; } else if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/.test(ua)) { return "mobile"; } return "desktop"; }; // Get viewport dimensions const getViewport = () => { return { width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight, }; }; const browserDetails = getBrowserDetails(); const os = getOSDetails(); const device = getDeviceType(); const viewport = getViewport(); return { name: browserDetails.name, version: browserDetails.version, os, device, viewport, userAgent, }; } /** * Format error object into a standardized structure */ function formatError(error) { if (error instanceof Error) { return { name: error.name, message: error.message, stack: error.stack, }; } // Handle non-Error objects return { name: "Unknown Error", message: typeof error === "string" ? error : String(error), }; } /** * Safe stringify function that handles circular references */ function safeStringify(obj) { const seen = new WeakSet(); return JSON.stringify(obj, (key, value) => { if (typeof value === "object" && value !== null) { if (seen.has(value)) { return "[Circular Reference]"; } seen.add(value); } // Handle Error objects if (value instanceof Error) { return { name: value.name, message: value.message, stack: value.stack, }; } return value; }); } /** * Sanitize sensitive data from objects */ function sanitizeData(data, sensitiveKeys = ["password", "token", "secret", "key", "auth"]) { const result = {}; for (const [key, value] of Object.entries(data)) { // Check if the key contains any sensitive words const isSensitive = sensitiveKeys.some((sensitiveKey) => key.toLowerCase().includes(sensitiveKey.toLowerCase())); if (isSensitive) { result[key] = "[REDACTED]"; } else if (typeof value === "object" && value !== null) { // Recursively sanitize nested objects result[key] = Array.isArray(value) ? value.map((item) => typeof item === "object" && item !== null ? sanitizeData(item, sensitiveKeys) : item) : sanitizeData(value, sensitiveKeys); } else { result[key] = value; } } return result; } /** * Get current timestamp in ISO format */ function getTimestamp() { return new Date().toISOString(); } /** * Log message with prefix in debug mode */ function debugLog(message, data) { try { const config = require("./config").BugTrackerConfig.getInstance(); if (config.isDebugMode()) { console.log(`[Bug Tracker] ${message}`, data); } } catch (e) { // Silently fail if config is not initialized } }