storenest-commerce
Version:
Complete e-commerce SDK for Storenest platform with React components, multi-language support, secure checkout, and enterprise-grade security
170 lines (169 loc) • 6.94 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDebugMode = exports.setDebugMode = exports.getSecretKey = exports.setSecretKey = exports.getProxyUrl = exports.setProxyUrl = exports.getApiKey = exports.setApiKey = exports.getApiBaseUrl = exports.setApiBaseUrl = void 0;
exports.formatPrice = formatPrice;
exports.getOrCreateUserId = getOrCreateUserId;
exports.generateNonce = generateNonce;
exports.generateApiToken = generateApiToken;
// Secure configuration storage using closure
const config = (() => {
let apiBaseUrl = '';
let apiKey = null;
let proxyUrl = null;
let secretKey = null;
let debugMode = false;
return {
setApiBaseUrl: (url) => { apiBaseUrl = url; },
getApiBaseUrl: () => apiBaseUrl,
setApiKey: (key) => { apiKey = key; },
getApiKey: () => apiKey,
setProxyUrl: (url) => { proxyUrl = url; },
getProxyUrl: () => proxyUrl,
setSecretKey: (key) => { secretKey = key; },
getSecretKey: () => secretKey,
setDebugMode: (debug) => { debugMode = debug; },
getDebugMode: () => debugMode,
};
})();
function formatPrice(price, locale = 'hr-HR', currency = 'EUR') {
return price.toLocaleString(locale, {
style: 'currency',
currency,
});
}
function getOrCreateUserId(storageKey = 'userId') {
if (typeof window === 'undefined')
return null;
let userId = window.localStorage.getItem(storageKey);
if (!userId) {
userId = 'guest-' + generateSecureRandomString(9);
window.localStorage.setItem(storageKey, userId);
}
return userId;
}
// Generate cryptographically secure random string
function generateSecureRandomString(length) {
// Try Node.js crypto first (for server-side)
if (typeof require !== 'undefined') {
try {
const crypto = require('crypto');
const randomBytes = crypto.randomBytes(length);
const result = Array.from(randomBytes, (byte) => byte.toString(36)).join('').substring(0, length);
return result;
}
catch (error) {
// Node.js crypto failed, continue to Web Crypto API
}
}
// Try Web Crypto API (for browsers)
try {
if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
const array = new Uint8Array(length);
window.crypto.getRandomValues(array);
const result = Array.from(array, byte => byte.toString(36)).join('').substring(0, length);
return result;
}
}
catch (error) {
// Web Crypto API failed, continue to fallback
}
// Final fallback - WARNING: Less secure
if (config.getDebugMode()) {
console.warn('⚠️ Storenest Commerce: Using fallback random generation. This is less secure than cryptographic random generation.');
}
let result = '';
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
// Generate a nonce for unpredictability using crypto-secure random
function generateNonce() {
const randomPart = generateSecureRandomString(16);
const timestamp = Date.now().toString(36);
const nonce = `${randomPart}${timestamp}`;
return nonce;
}
// Generate a secure token for API requests using Web Crypto API
async function generateApiToken(apiKey, requestBody) {
const timestamp = Date.now().toString();
const nonce = generateNonce();
// Create signature using SHA-256 hash of apiKey:timestamp:nonce:bodyHash
const bodyHash = requestBody ? await generateBodyHash(requestBody) : '';
const dataToSign = bodyHash ? `${apiKey}:${timestamp}:${nonce}:${bodyHash}` : `${apiKey}:${timestamp}:${nonce}`;
const signature = await generateSecureSignature(dataToSign);
return { timestamp, signature, nonce };
}
// Generate SHA-256 hash of request body
async function generateBodyHash(body) {
const encoder = new TextEncoder();
const data = encoder.encode(body);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
}
// Generate secure signature using Web Crypto API
async function generateSecureSignature(data) {
try {
// Try Node.js crypto first (for server-side)
if (typeof require !== 'undefined') {
try {
const crypto = require('crypto');
const hash = crypto.createHash('sha256');
hash.update(data);
const result = hash.digest('hex');
return result;
}
catch (error) {
// Node.js crypto failed, continue to Web Crypto API
}
}
// Use Web Crypto API if available (modern browsers)
if (typeof window !== 'undefined' && window.crypto && window.crypto.subtle) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const result = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return result;
}
// Fallback for older browsers or server-side (less secure but functional)
if (config.getDebugMode()) {
console.warn('⚠️ Storenest Commerce: Using fallback hash function. This is less secure than SHA-256.');
}
const result = fallbackHash(data);
return result;
}
catch (error) {
// If Web Crypto API fails, use fallback
if (config.getDebugMode()) {
console.warn('⚠️ Storenest Commerce: Using fallback hash function due to crypto API failure.');
}
const result = fallbackHash(data);
return result;
}
}
// Fallback hash function (less secure but functional)
function fallbackHash(str) {
let hash = 0;
if (str.length === 0)
return hash.toString();
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32-bit integer
}
return Math.abs(hash).toString(16);
}
// Export config functions
exports.setApiBaseUrl = config.setApiBaseUrl;
exports.getApiBaseUrl = config.getApiBaseUrl;
exports.setApiKey = config.setApiKey;
exports.getApiKey = config.getApiKey;
exports.setProxyUrl = config.setProxyUrl;
exports.getProxyUrl = config.getProxyUrl;
exports.setSecretKey = config.setSecretKey;
exports.getSecretKey = config.getSecretKey;
exports.setDebugMode = config.setDebugMode;
exports.getDebugMode = config.getDebugMode;