Documentation Index Fetch the complete documentation index at: https://docs.oneclickdz.com/llms.txt
Use this file to discover all available pages before exploring further.
Sécurité des clés API
Stockage
Ne commitez jamais les clés API dans le contrôle de version ou ne les exposez pas dans du code côté client.
// ❌ Bad: Hardcoded in source code
const API_KEY = "sk_live_abc123" ;
// ✅ Good: Use environment variables
const API_KEY = process . env . FLEXY_API_KEY ;
Variables d’environnement
# .env file
FLEXY_API_KEY = sk_live_your_key_here
FLEXY_SANDBOX_KEY = sk_test_your_sandbox_key
API_BASE_URL = https://api.oneclickdz.com
// Load environment variables
require ( "dotenv" ). config ();
const apiKey = process . env . FLEXY_API_KEY ;
Rotation des clés
// Support multiple keys for zero-downtime rotation
const API_KEYS = {
primary: process . env . FLEXY_API_KEY_PRIMARY ,
secondary: process . env . FLEXY_API_KEY_SECONDARY ,
};
async function callApiWithRotation ( endpoint , data ) {
try {
return await callApi ( endpoint , data , API_KEYS . primary );
} catch ( error ) {
if ( error . status === 401 ) {
// Try secondary key
return await callApi ( endpoint , data , API_KEYS . secondary );
}
throw error ;
}
}
Application du HTTPS
// Always use HTTPS
const API_BASE_URL = "https://api.oneclickdz.com" ;
// Reject self-signed certificates in production
const axios = require ( "axios" );
const https = require ( "https" );
const client = axios . create ({
baseURL: API_BASE_URL ,
httpsAgent: new https . Agent ({
rejectUnauthorized: process . env . NODE_ENV === "production" ,
}),
});
Validation des requêtes
// Validate all inputs before sending to API
const Joi = require ( "joi" );
const mobileTopupSchema = Joi . object ({
plan_code: Joi . string (). required (),
MSSIDN: Joi . string ()
. pattern ( / ^ 0 [ 567 ][ 0-9 ] {8} $ / )
. required (),
amount: Joi . number ()
. min ( 50 )
. max ( 5000 )
. when ( "plan_code" , {
is: Joi . string (). pattern ( / ^ DYN/ ),
then: Joi . required (),
otherwise: Joi . forbidden (),
}),
reference: Joi . string (). max ( 100 ). required (),
});
function validateTopupRequest ( data ) {
const { error , value } = mobileTopupSchema . validate ( data );
if ( error ) {
throw new Error ( `Validation error: ${ error . message } ` );
}
return value ;
}
Gestion des données sensibles
Ne journalisez pas les données sensibles
// ❌ Bad: Logs API key
console . log ( "Request:" , {
headers: { "X-Access-Token" : apiKey },
body: data ,
});
// ✅ Good: Redact sensitive info
function sanitizeLog ( data ) {
const sanitized = { ... data };
if ( sanitized . headers ?.[ "X-Access-Token" ]) {
sanitized . headers [ "X-Access-Token" ] = "***REDACTED***" ;
}
return sanitized ;
}
console . log ( "Request:" , sanitizeLog ( request ));
Protégez les numéros de téléphone
// Mask phone numbers in logs/UI
function maskPhone ( phone ) {
if ( phone . length !== 10 ) return phone ;
return phone . slice ( 0 , 4 ) + "****" + phone . slice ( - 2 );
}
console . log ( "Top-up sent to:" , maskPhone ( "0551234567" )); // 0551****67
Sécurisez les codes de cartes
// Never log full card codes
function maskCardCode ( code ) {
if ( code . length <= 4 ) return "****" ;
return "****" + code . slice ( - 4 );
}
// Store securely
await db . orders . create ({
data: {
userId: user . id ,
cardCode: encrypt ( cardCode ), // Encrypt sensitive data
cardCodeMasked: maskCardCode ( cardCode ),
},
});
Limitation du débit
// Implement client-side rate limiting
const rateLimit = require ( "express-rate-limit" );
const apiLimiter = rateLimit ({
windowMs: 60 * 1000 , // 1 minute
max: 60 , // Max 60 requests per minute
message: "Too many requests, please try again later" ,
});
app . use ( "/api/topup" , apiLimiter , topupHandler );
Liste blanche d’IP
Contactez le support pour mettre votre serveur sur liste blanche d’IP pour une sécurité supplémentaire.
// Make requests from whitelisted IPs only
const WHITELISTED_IPS = [ "192.168.1.100" , "10.0.0.50" ];
function isWhitelisted ( ip ) {
return WHITELISTED_IPS . includes ( ip );
}
app . use (( req , res , next ) => {
const clientIp = req . ip ;
if ( ! isWhitelisted ( clientIp )) {
return res . status ( 403 ). json ({ error: "Forbidden" });
}
next ();
});
Journalisation des audits
// Log all API interactions for audit
async function auditLog ( event , data ) {
await db . auditLogs . create ({
data: {
timestamp: new Date (),
event ,
userId: data . userId ,
action: data . action ,
ipAddress: data . ip ,
userAgent: data . userAgent ,
requestId: data . requestId ,
success: data . success ,
// Don't log sensitive data
metadata: sanitize ( data . metadata ),
},
});
}
// Usage
await auditLog ( "topup_sent" , {
userId: user . id ,
action: "SEND_MOBILE_TOPUP" ,
ip: req . ip ,
userAgent: req . get ( "user-agent" ),
requestId: response . requestId ,
success: true ,
});
Messages d’erreur
// Don't expose internal details in error messages
function getSafeErrorMessage ( error ) {
// Internal errors
if ( error . status >= 500 ) {
return {
message: "An error occurred. Please try again later." ,
code: "INTERNAL_ERROR" ,
requestId: error . requestId , // Include for support
};
}
// Client errors - be specific but safe
return {
message: error . message ,
code: error . code ,
};
}
Configuration sécurisée
// Séparer les configurations sandbox/production
const config = {
sandbox: {
apiKey: process . env . FLEXY_SANDBOX_KEY ,
baseUrl: "https://api.oneclickdz.com" ,
testMode: true ,
logLevel: "debug" ,
},
production: {
apiKey: process . env . FLEXY_API_KEY ,
baseUrl: "https://api.oneclickdz.com" ,
testMode: false ,
logLevel: "error" ,
},
};
const env = process . env . NODE_ENV || "sandbox" ;
const currentConfig = config [ env ];
Sécurité des dépendances
# Auditer régulièrement les dépendances
npm audit
# Mettre à jour les packages vulnérables
npm audit fix
# Utiliser des outils comme Snyk
npm install -g snyk
snyk test
Chiffrement des données au repos
// Chiffrer les données sensibles avant de les stocker
const crypto = require ( "crypto" );
const ENCRYPTION_KEY = process . env . ENCRYPTION_KEY ; // Clé 32 octets
const IV_LENGTH = 16 ;
function encrypt ( text ) {
const iv = crypto . randomBytes ( IV_LENGTH );
const cipher = crypto . createCipheriv (
"aes-256-cbc" ,
Buffer . from ( ENCRYPTION_KEY ),
iv
);
let encrypted = cipher . update ( text );
encrypted = Buffer . concat ([ encrypted , cipher . final ()]);
return iv . toString ( "hex" ) + ":" + encrypted . toString ( "hex" );
}
function decrypt ( text ) {
const parts = text . split ( ":" );
const iv = Buffer . from ( parts . shift (), "hex" );
const encrypted = Buffer . from ( parts . join ( ":" ), "hex" );
const decipher = crypto . createDecipheriv (
"aes-256-cbc" ,
Buffer . from ( ENCRYPTION_KEY ),
iv
);
let decrypted = decipher . update ( encrypted );
decrypted = Buffer . concat ([ decrypted , decipher . final ()]);
return decrypted . toString ();
}
// Utilisation
const cardCode = "1234-5678-9012" ;
const encrypted = encrypt ( cardCode );
await db . orders . create ({ data: { cardCode: encrypted } });
Liste de contrôle de sécurité
Clés API
✓ Stockées dans des variables d’environnement ✓ Non committées dans le contrôle de version ✓ Renouvelées périodiquement
HTTPS
✓ Toutes les requêtes utilisent HTTPS ✓ Validation des certificats activée
Validation des entrées
✓ Toutes les entrées validées avant les appels API ✓ Validation par schéma en place
Journalisation
✓ Les données sensibles ne sont pas journalisées ✓ Journaux d’audit activés ✓ IDs de requête tracés
Limitation du débit
✓ Limitation côté client ✓ Logique de réessai avec backoff
Protection des données
✓ Données sensibles chiffrées au repos ✓ Numéros de téléphone masqués dans les journaux ✓ Codes de cartes sécurisés
Résumé des bonnes pratiques
Ne jamais exposer les clés Utiliser des variables d’environnement
Toujours utiliser HTTPS Sécuriser toutes les communications
Tout valider Vérifier les entrées avant d’envoyer
Chiffrer les données sensibles Protéger les données au repos
Liens connexes
Authentification Configuration des clés API
Gestion des erreurs Gérer les erreurs en toute sécurité