sunuid-sdk 1.0.51 → 1.0.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +429 -193
- package/docs/INTEGRATION_GUIDE.md +334 -0
- package/docs/SECURITY_GUIDE.md +368 -0
- package/examples/.htaccess.example +187 -0
- package/examples/README.md +192 -0
- package/examples/auto-code.js +234 -0
- package/examples/auto-integration.html +337 -0
- package/examples/basic-usage.php +42 -0
- package/examples/callback-example.html +232 -0
- package/examples/config-example.js +41 -0
- package/examples/demo.html +323 -0
- package/examples/env.example +83 -0
- package/examples/local-qr.php +49 -0
- package/examples/minimal-code.js +147 -0
- package/examples/minimal-integration.html +157 -0
- package/examples/no-loop-example.html +250 -0
- package/examples/partner-name-config.js +123 -0
- package/examples/production-config.js +60 -0
- package/examples/secure-integration-example.js +186 -0
- package/examples/secure-integration.html +410 -0
- package/examples/secure-usage.php +309 -0
- package/examples/simple-kyc.html +95 -0
- package/examples/simple-login.html +96 -0
- package/examples/test-partner-name.html +251 -0
- package/examples/test-production.html +200 -0
- package/examples/universal-kyc.html +199 -0
- package/examples/universal-login.html +148 -0
- package/examples/web-integration.php +138 -0
- package/package.json +24 -10
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# SunuID SDK - Guide d'Intégration
|
|
2
|
+
|
|
3
|
+
## 📦 Vue d'ensemble
|
|
4
|
+
|
|
5
|
+
Le SunuID SDK permet aux partenaires d'intégrer facilement les QR codes d'authentification et KYC dans leurs applications web. Ce package JavaScript offre une interface simple et moderne pour afficher les QR codes SunuID.
|
|
6
|
+
|
|
7
|
+
## 🚀 Installation
|
|
8
|
+
|
|
9
|
+
### 1. Inclure les fichiers
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<!-- CSS -->
|
|
13
|
+
<link rel="stylesheet" href="https://sunuid.sn/css/sunuid-sdk.css">
|
|
14
|
+
|
|
15
|
+
<!-- JavaScript -->
|
|
16
|
+
<script src="https://sunuid.sn/js/sunuid-sdk.js"></script>
|
|
17
|
+
|
|
18
|
+
<!-- FontAwesome (pour les icônes) -->
|
|
19
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Initialisation
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
// Configuration du SDK
|
|
26
|
+
const sunuidConfig = {
|
|
27
|
+
apiUrl: 'https://sunuid.sn/api',
|
|
28
|
+
partnerId: 'VOTRE_PARTNER_ID',
|
|
29
|
+
clientId: 'VOTRE_CLIENT_ID',
|
|
30
|
+
secretId: 'VOTRE_SECRET_ID',
|
|
31
|
+
theme: 'light', // 'light' ou 'dark'
|
|
32
|
+
language: 'fr',
|
|
33
|
+
autoRefresh: true,
|
|
34
|
+
refreshInterval: 30000, // 30 secondes
|
|
35
|
+
onSuccess: function(data) {
|
|
36
|
+
console.log('Authentification réussie:', data);
|
|
37
|
+
// Rediriger vers le dashboard
|
|
38
|
+
window.location.href = '/dashboard';
|
|
39
|
+
},
|
|
40
|
+
onError: function(error) {
|
|
41
|
+
console.error('Erreur:', error);
|
|
42
|
+
// Afficher un message d'erreur
|
|
43
|
+
showErrorMessage('Erreur de connexion');
|
|
44
|
+
},
|
|
45
|
+
onExpired: function() {
|
|
46
|
+
console.log('QR code expiré');
|
|
47
|
+
// Actualiser automatiquement ou afficher un message
|
|
48
|
+
showExpiredMessage();
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Initialiser le SDK
|
|
53
|
+
const sunuid = initSunuID(sunuidConfig);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 🔐 Authentification
|
|
57
|
+
|
|
58
|
+
### Générer un QR code d'authentification
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<!-- Conteneur pour le QR code -->
|
|
62
|
+
<div id="auth-qr-container"></div>
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
// Générer le QR code d'authentification
|
|
67
|
+
sunuid.generateAuthQR('auth-qr-container', {
|
|
68
|
+
theme: 'light',
|
|
69
|
+
redirectUrl: 'https://votre-site.com/dashboard',
|
|
70
|
+
customData: {
|
|
71
|
+
userAgent: navigator.userAgent,
|
|
72
|
+
timestamp: Date.now()
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 📋 KYC (Know Your Customer)
|
|
78
|
+
|
|
79
|
+
### Générer un QR code KYC
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<!-- Conteneur pour le QR code KYC -->
|
|
83
|
+
<div id="kyc-qr-container"></div>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
// Générer le QR code KYC
|
|
88
|
+
sunuid.generateKYCQR('kyc-qr-container', {
|
|
89
|
+
theme: 'dark',
|
|
90
|
+
kycType: 'full', // 'basic' ou 'full'
|
|
91
|
+
requiredFields: ['identity', 'address', 'phone'],
|
|
92
|
+
redirectUrl: 'https://votre-site.com/kyc-complete'
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## 🎨 Personnalisation
|
|
97
|
+
|
|
98
|
+
### Thèmes disponibles
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
// Thème clair (par défaut)
|
|
102
|
+
sunuid.generateAuthQR('container', { theme: 'light' });
|
|
103
|
+
|
|
104
|
+
// Thème sombre
|
|
105
|
+
sunuid.generateAuthQR('container', { theme: 'dark' });
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Options de configuration
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const options = {
|
|
112
|
+
theme: 'light', // 'light' ou 'dark'
|
|
113
|
+
language: 'fr', // 'fr', 'en', 'ar'
|
|
114
|
+
autoRefresh: true, // Actualisation automatique
|
|
115
|
+
refreshInterval: 30000, // Intervalle en millisecondes
|
|
116
|
+
redirectUrl: 'https://...', // URL de redirection après succès
|
|
117
|
+
customData: {}, // Données personnalisées
|
|
118
|
+
onSuccess: function(data) {
|
|
119
|
+
// Callback en cas de succès
|
|
120
|
+
},
|
|
121
|
+
onError: function(error) {
|
|
122
|
+
// Callback en cas d'erreur
|
|
123
|
+
},
|
|
124
|
+
onExpired: function() {
|
|
125
|
+
// Callback quand le QR expire
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 📱 Exemples Complets
|
|
131
|
+
|
|
132
|
+
### Page de Connexion
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<!DOCTYPE html>
|
|
136
|
+
<html lang="fr">
|
|
137
|
+
<head>
|
|
138
|
+
<meta charset="UTF-8">
|
|
139
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
140
|
+
<title>Connexion - Mon Application</title>
|
|
141
|
+
<link rel="stylesheet" href="https://sunuid.sn/css/sunuid-sdk.css">
|
|
142
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
143
|
+
</head>
|
|
144
|
+
<body>
|
|
145
|
+
<div class="login-container">
|
|
146
|
+
<h1>Connexion Sécurisée</h1>
|
|
147
|
+
<p>Scannez le QR code avec l'application SunuID</p>
|
|
148
|
+
|
|
149
|
+
<!-- Conteneur pour le QR code -->
|
|
150
|
+
<div id="auth-qr-container"></div>
|
|
151
|
+
|
|
152
|
+
<div class="login-footer">
|
|
153
|
+
<p>Pas encore d'application SunuID ?</p>
|
|
154
|
+
<a href="https://sunuid.sn/download" target="_blank">Télécharger</a>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<script src="https://sunuid.sn/js/sunuid-sdk.js"></script>
|
|
159
|
+
<script>
|
|
160
|
+
// Configuration
|
|
161
|
+
const sunuid = initSunuID({
|
|
162
|
+
apiUrl: 'https://sunuid.sn/api',
|
|
163
|
+
partnerId: 'VOTRE_PARTNER_ID',
|
|
164
|
+
clientId: 'VOTRE_CLIENT_ID',
|
|
165
|
+
secretId: 'VOTRE_SECRET_ID',
|
|
166
|
+
theme: 'light',
|
|
167
|
+
onSuccess: function(data) {
|
|
168
|
+
// Rediriger vers le dashboard
|
|
169
|
+
window.location.href = '/dashboard?token=' + data.token;
|
|
170
|
+
},
|
|
171
|
+
onError: function(error) {
|
|
172
|
+
alert('Erreur de connexion: ' + error.message);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Générer le QR code
|
|
177
|
+
sunuid.generateAuthQR('auth-qr-container');
|
|
178
|
+
</script>
|
|
179
|
+
</body>
|
|
180
|
+
</html>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Processus KYC
|
|
184
|
+
|
|
185
|
+
```html
|
|
186
|
+
<!DOCTYPE html>
|
|
187
|
+
<html lang="fr">
|
|
188
|
+
<head>
|
|
189
|
+
<meta charset="UTF-8">
|
|
190
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
191
|
+
<title>Vérification KYC</title>
|
|
192
|
+
<link rel="stylesheet" href="https://sunuid.sn/css/sunuid-sdk.css">
|
|
193
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
194
|
+
</head>
|
|
195
|
+
<body>
|
|
196
|
+
<div class="kyc-container">
|
|
197
|
+
<h1>Vérification d'Identité</h1>
|
|
198
|
+
<p>Complétez votre profil avec SunuID</p>
|
|
199
|
+
|
|
200
|
+
<!-- Conteneur pour le QR code KYC -->
|
|
201
|
+
<div id="kyc-qr-container"></div>
|
|
202
|
+
|
|
203
|
+
<div class="kyc-info">
|
|
204
|
+
<h3>Informations requises :</h3>
|
|
205
|
+
<ul>
|
|
206
|
+
<li>Pièce d'identité (CNI, Passeport)</li>
|
|
207
|
+
<li>Justificatif de domicile</li>
|
|
208
|
+
<li>Photo de profil</li>
|
|
209
|
+
</ul>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<script src="https://sunuid.sn/js/sunuid-sdk.js"></script>
|
|
214
|
+
<script>
|
|
215
|
+
const sunuid = initSunuID({
|
|
216
|
+
apiUrl: 'https://sunuid.sn/api',
|
|
217
|
+
partnerId: 'VOTRE_PARTNER_ID',
|
|
218
|
+
clientId: 'VOTRE_CLIENT_ID',
|
|
219
|
+
secretId: 'VOTRE_SECRET_ID',
|
|
220
|
+
theme: 'dark',
|
|
221
|
+
onSuccess: function(data) {
|
|
222
|
+
// KYC complété
|
|
223
|
+
window.location.href = '/kyc-complete?status=success';
|
|
224
|
+
},
|
|
225
|
+
onError: function(error) {
|
|
226
|
+
alert('Erreur KYC: ' + error.message);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Générer le QR code KYC
|
|
231
|
+
sunuid.generateKYCQR('kyc-qr-container', {
|
|
232
|
+
kycType: 'full',
|
|
233
|
+
requiredFields: ['identity', 'address', 'phone', 'photo']
|
|
234
|
+
});
|
|
235
|
+
</script>
|
|
236
|
+
</body>
|
|
237
|
+
</html>
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## 🔧 API Référence
|
|
241
|
+
|
|
242
|
+
### Méthodes principales
|
|
243
|
+
|
|
244
|
+
#### `generateAuthQR(containerId, options)`
|
|
245
|
+
Génère un QR code d'authentification.
|
|
246
|
+
|
|
247
|
+
**Paramètres :**
|
|
248
|
+
- `containerId` (string) : ID du conteneur HTML
|
|
249
|
+
- `options` (object) : Options de configuration
|
|
250
|
+
|
|
251
|
+
#### `generateKYCQR(containerId, options)`
|
|
252
|
+
Génère un QR code KYC.
|
|
253
|
+
|
|
254
|
+
**Paramètres :**
|
|
255
|
+
- `containerId` (string) : ID du conteneur HTML
|
|
256
|
+
- `options` (object) : Options de configuration
|
|
257
|
+
|
|
258
|
+
#### `checkQRStatus(qrId)`
|
|
259
|
+
Vérifie le statut d'un QR code.
|
|
260
|
+
|
|
261
|
+
**Paramètres :**
|
|
262
|
+
- `qrId` (string) : ID du QR code
|
|
263
|
+
|
|
264
|
+
#### `refreshQR(containerId, type, options)`
|
|
265
|
+
Actualise un QR code.
|
|
266
|
+
|
|
267
|
+
**Paramètres :**
|
|
268
|
+
- `containerId` (string) : ID du conteneur HTML
|
|
269
|
+
- `type` (string) : 'auth' ou 'kyc'
|
|
270
|
+
- `options` (object) : Options de configuration
|
|
271
|
+
|
|
272
|
+
#### `destroy()`
|
|
273
|
+
Nettoie les ressources du SDK.
|
|
274
|
+
|
|
275
|
+
### Événements
|
|
276
|
+
|
|
277
|
+
#### `onSuccess(data)`
|
|
278
|
+
Appelé quand l'authentification/KYC est réussie.
|
|
279
|
+
|
|
280
|
+
#### `onError(error)`
|
|
281
|
+
Appelé en cas d'erreur.
|
|
282
|
+
|
|
283
|
+
#### `onExpired()`
|
|
284
|
+
Appelé quand le QR code expire.
|
|
285
|
+
|
|
286
|
+
## 🛡️ Sécurité
|
|
287
|
+
|
|
288
|
+
### Authentification
|
|
289
|
+
Le SDK utilise les clés API du partenaire pour s'authentifier :
|
|
290
|
+
- `X-SunuID-Client-ID`
|
|
291
|
+
- `X-SunuID-Secret-ID`
|
|
292
|
+
- `X-SunuID-Partner-ID`
|
|
293
|
+
|
|
294
|
+
### Validation
|
|
295
|
+
- Vérification des paramètres requis
|
|
296
|
+
- Validation des URLs de redirection
|
|
297
|
+
- Protection contre les attaques CSRF
|
|
298
|
+
|
|
299
|
+
## 📊 Monitoring
|
|
300
|
+
|
|
301
|
+
### Logs
|
|
302
|
+
Le SDK génère des logs pour le debugging :
|
|
303
|
+
```javascript
|
|
304
|
+
console.log('SunuID SDK initialisé avec succès');
|
|
305
|
+
console.error('SunuID SDK Error:', error);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Métriques
|
|
309
|
+
Les partenaires peuvent suivre :
|
|
310
|
+
- Nombre de QR codes générés
|
|
311
|
+
- Taux de succès d'authentification
|
|
312
|
+
- Temps de réponse de l'API
|
|
313
|
+
|
|
314
|
+
## 🆘 Support
|
|
315
|
+
|
|
316
|
+
### Documentation
|
|
317
|
+
- [Guide d'intégration](https://docs.sunuid.sn)
|
|
318
|
+
- [API Reference](https://api.sunuid.sn/docs)
|
|
319
|
+
- [Exemples](https://github.com/sunuid/sdk-examples)
|
|
320
|
+
|
|
321
|
+
### Support technique
|
|
322
|
+
- Email : support@sunuid.sn
|
|
323
|
+
- Chat : https://chat.sunuid.sn
|
|
324
|
+
- Documentation : https://docs.sunuid.sn
|
|
325
|
+
|
|
326
|
+
## 📄 Licence
|
|
327
|
+
|
|
328
|
+
Ce SDK est distribué sous licence MIT. Voir le fichier LICENSE pour plus de détails.
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
**Version :** 1.0.0
|
|
333
|
+
**Dernière mise à jour :** Août 2025
|
|
334
|
+
**Compatibilité :** ES6+, IE11+
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# 🔒 Guide de Sécurisation - SunuID SDK
|
|
2
|
+
|
|
3
|
+
Ce guide explique les différentes méthodes pour sécuriser les credentials lors de l'utilisation du SDK SunuID.
|
|
4
|
+
|
|
5
|
+
## 🚨 Problème de Sécurité
|
|
6
|
+
|
|
7
|
+
**NE JAMAIS** exposer les credentials (`clientId` et `secretId`) directement dans le code JavaScript côté client, car ils seraient visibles par tous les utilisateurs.
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// ❌ DANGEREUX - Ne jamais faire cela
|
|
11
|
+
const config = {
|
|
12
|
+
clientId: '1754166754_221A57B46843D755', // Visible par tous !
|
|
13
|
+
secretId: '56d40fe70507228b27f2640ae65894177c2fedbf246e2b30978fde1fc43953c5', // Visible par tous !
|
|
14
|
+
type: 2
|
|
15
|
+
};
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## ✅ Solutions de Sécurisation
|
|
19
|
+
|
|
20
|
+
### 1. Initialisation Sécurisée (Recommandée)
|
|
21
|
+
|
|
22
|
+
Le SDK dispose d'un système d'initialisation sécurisée qui récupère les credentials via un token temporaire.
|
|
23
|
+
|
|
24
|
+
#### Configuration côté serveur
|
|
25
|
+
|
|
26
|
+
1. **Créer le fichier `secure-init.php`** (déjà fourni dans le SDK) :
|
|
27
|
+
|
|
28
|
+
```php
|
|
29
|
+
<?php
|
|
30
|
+
// Configuration sécurisée (à stocker dans un fichier .env en production)
|
|
31
|
+
$SUNUID_CONFIG = [
|
|
32
|
+
'client_id' => 'VOTRE_CLIENT_ID',
|
|
33
|
+
'secret_id' => 'VOTRE_SECRET_ID',
|
|
34
|
+
'api_url' => 'https://api.sunuid.fayma.sn',
|
|
35
|
+
'token_expiry' => 3600, // 1 heure
|
|
36
|
+
'max_requests_per_token' => 100
|
|
37
|
+
];
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
2. **Configurer les credentials** dans `secure-init.php` :
|
|
41
|
+
- Remplacez `VOTRE_CLIENT_ID` et `VOTRE_SECRET_ID` par vos vrais credentials
|
|
42
|
+
- Stockez ce fichier en dehors du répertoire public si possible
|
|
43
|
+
- Utilisez des variables d'environnement en production
|
|
44
|
+
|
|
45
|
+
#### Configuration côté client
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
// ✅ SÉCURISÉ - Aucun credential exposé
|
|
49
|
+
const secureConfig = {
|
|
50
|
+
type: 2, // 1=KYC, 2=AUTH, 3=SIGNATURE
|
|
51
|
+
partnerName: 'MonApplication',
|
|
52
|
+
theme: 'light',
|
|
53
|
+
|
|
54
|
+
// Activer l'initialisation sécurisée
|
|
55
|
+
secureInit: true,
|
|
56
|
+
secureInitUrl: '/secure-init.php', // URL vers votre endpoint sécurisé
|
|
57
|
+
|
|
58
|
+
// Options de sécurité
|
|
59
|
+
enableSecurityLogs: true,
|
|
60
|
+
validateInputs: true,
|
|
61
|
+
maxRetries: 3,
|
|
62
|
+
requestTimeout: 10000
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Utilisation
|
|
66
|
+
const sunuid = new SunuID(secureConfig);
|
|
67
|
+
await sunuid.init(); // Les credentials sont récupérés automatiquement
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
#### Avantages de l'initialisation sécurisée
|
|
71
|
+
|
|
72
|
+
- ✅ **Aucun credential exposé** dans le code client
|
|
73
|
+
- ✅ **Tokens temporaires** avec expiration
|
|
74
|
+
- ✅ **Limitation des requêtes** par token
|
|
75
|
+
- ✅ **Logs de sécurité** automatiques
|
|
76
|
+
- ✅ **Validation des paramètres** côté serveur
|
|
77
|
+
|
|
78
|
+
### 2. Variables d'Environnement (Production)
|
|
79
|
+
|
|
80
|
+
Pour une sécurité maximale en production, utilisez des variables d'environnement :
|
|
81
|
+
|
|
82
|
+
#### Configuration serveur (.env)
|
|
83
|
+
|
|
84
|
+
```env
|
|
85
|
+
SUNUID_CLIENT_ID=1754166754_221A57B46843D755
|
|
86
|
+
SUNUID_SECRET_ID=56d40fe70507228b27f2640ae65894177c2fedbf246e2b30978fde1fc43953c5
|
|
87
|
+
SUNUID_API_URL=https://api.sunuid.fayma.sn
|
|
88
|
+
SUNUID_TOKEN_EXPIRY=3600
|
|
89
|
+
SUNUID_MAX_REQUESTS=100
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### Modification de secure-init.php
|
|
93
|
+
|
|
94
|
+
```php
|
|
95
|
+
<?php
|
|
96
|
+
// Charger les variables d'environnement
|
|
97
|
+
require_once 'vendor/autoload.php'; // Si vous utilisez Composer
|
|
98
|
+
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
|
|
99
|
+
$dotenv->load();
|
|
100
|
+
|
|
101
|
+
$SUNUID_CONFIG = [
|
|
102
|
+
'client_id' => $_ENV['SUNUID_CLIENT_ID'],
|
|
103
|
+
'secret_id' => $_ENV['SUNUID_SECRET_ID'],
|
|
104
|
+
'api_url' => $_ENV['SUNUID_API_URL'],
|
|
105
|
+
'token_expiry' => (int)$_ENV['SUNUID_TOKEN_EXPIRY'],
|
|
106
|
+
'max_requests_per_token' => (int)$_ENV['SUNUID_MAX_REQUESTS']
|
|
107
|
+
];
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3. Proxy API (Alternative)
|
|
111
|
+
|
|
112
|
+
Si vous ne pouvez pas utiliser l'initialisation sécurisée, créez un proxy API :
|
|
113
|
+
|
|
114
|
+
#### Proxy API (proxy-sunuid.php)
|
|
115
|
+
|
|
116
|
+
```php
|
|
117
|
+
<?php
|
|
118
|
+
header('Content-Type: application/json');
|
|
119
|
+
header('Access-Control-Allow-Origin: *');
|
|
120
|
+
header('Access-Control-Allow-Methods: POST');
|
|
121
|
+
header('Access-Control-Allow-Headers: Content-Type');
|
|
122
|
+
|
|
123
|
+
// Configuration sécurisée
|
|
124
|
+
$config = [
|
|
125
|
+
'client_id' => $_ENV['SUNUID_CLIENT_ID'],
|
|
126
|
+
'secret_id' => $_ENV['SUNUID_SECRET_ID'],
|
|
127
|
+
'api_url' => 'https://api.sunuid.fayma.sn'
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
// Récupérer les données de la requête
|
|
131
|
+
$input = json_decode(file_get_contents('php://input'), true);
|
|
132
|
+
$endpoint = $_GET['endpoint'] ?? '';
|
|
133
|
+
|
|
134
|
+
// Valider l'endpoint
|
|
135
|
+
$allowedEndpoints = ['qr-generate', 'qr-status', 'debug'];
|
|
136
|
+
if (!in_array($endpoint, $allowedEndpoints)) {
|
|
137
|
+
http_response_code(400);
|
|
138
|
+
echo json_encode(['error' => 'Endpoint non autorisé']);
|
|
139
|
+
exit;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Faire la requête vers l'API SunuID
|
|
143
|
+
$ch = curl_init();
|
|
144
|
+
curl_setopt($ch, CURLOPT_URL, $config['api_url'] . '/' . $endpoint);
|
|
145
|
+
curl_setopt($ch, CURLOPT_POST, true);
|
|
146
|
+
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($input));
|
|
147
|
+
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
148
|
+
'Content-Type: application/json'
|
|
149
|
+
]);
|
|
150
|
+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
151
|
+
|
|
152
|
+
$response = curl_exec($ch);
|
|
153
|
+
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
154
|
+
curl_close($ch);
|
|
155
|
+
|
|
156
|
+
http_response_code($httpCode);
|
|
157
|
+
echo $response;
|
|
158
|
+
?>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### Configuration côté client
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
// Configuration avec proxy
|
|
165
|
+
const proxyConfig = {
|
|
166
|
+
type: 2,
|
|
167
|
+
partnerName: 'MonApplication',
|
|
168
|
+
|
|
169
|
+
// Utiliser le proxy au lieu de l'API directe
|
|
170
|
+
apiUrl: '/proxy-sunuid.php',
|
|
171
|
+
|
|
172
|
+
// Les credentials sont gérés côté serveur
|
|
173
|
+
secureInit: false // Désactiver car on utilise le proxy
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const sunuid = new SunuID(proxyConfig);
|
|
177
|
+
await sunuid.init();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 4. Chiffrement côté client (Moins sécurisé)
|
|
181
|
+
|
|
182
|
+
⚠️ **ATTENTION** : Cette méthode est moins sécurisée car le chiffrement peut être inversé.
|
|
183
|
+
|
|
184
|
+
```javascript
|
|
185
|
+
// Chiffrement simple (à éviter en production)
|
|
186
|
+
function encryptCredentials(clientId, secretId, key) {
|
|
187
|
+
const data = clientId + '|' + secretId;
|
|
188
|
+
return btoa(data + '|' + key);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function decryptCredentials(encrypted, key) {
|
|
192
|
+
try {
|
|
193
|
+
const decoded = atob(encrypted);
|
|
194
|
+
const parts = decoded.split('|');
|
|
195
|
+
if (parts[2] === key) {
|
|
196
|
+
return {
|
|
197
|
+
clientId: parts[0],
|
|
198
|
+
secretId: parts[1]
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
} catch (e) {
|
|
202
|
+
console.error('Erreur déchiffrement:', e);
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Utilisation (moins sécurisé)
|
|
208
|
+
const encrypted = encryptCredentials('clientId', 'secretId', 'maCleSecrete');
|
|
209
|
+
const credentials = decryptCredentials(encrypted, 'maCleSecrete');
|
|
210
|
+
|
|
211
|
+
const config = {
|
|
212
|
+
clientId: credentials.clientId,
|
|
213
|
+
secretId: credentials.secretId,
|
|
214
|
+
type: 2
|
|
215
|
+
};
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## 🔧 Configuration Recommandée
|
|
219
|
+
|
|
220
|
+
### Pour le Développement
|
|
221
|
+
|
|
222
|
+
```javascript
|
|
223
|
+
// Utiliser l'initialisation sécurisée avec secure-init.php
|
|
224
|
+
const devConfig = {
|
|
225
|
+
type: 2,
|
|
226
|
+
partnerName: 'DevApp',
|
|
227
|
+
secureInit: true,
|
|
228
|
+
secureInitUrl: '/secure-init.php',
|
|
229
|
+
enableSecurityLogs: true
|
|
230
|
+
};
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Pour la Production
|
|
234
|
+
|
|
235
|
+
```javascript
|
|
236
|
+
// Utiliser des variables d'environnement + initialisation sécurisée
|
|
237
|
+
const prodConfig = {
|
|
238
|
+
type: 2,
|
|
239
|
+
partnerName: 'ProdApp',
|
|
240
|
+
secureInit: true,
|
|
241
|
+
secureInitUrl: '/api/secure-init', // Endpoint sécurisé
|
|
242
|
+
enableSecurityLogs: true,
|
|
243
|
+
validateInputs: true,
|
|
244
|
+
maxRetries: 3,
|
|
245
|
+
requestTimeout: 10000
|
|
246
|
+
};
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## 🛡️ Bonnes Pratiques de Sécurité
|
|
250
|
+
|
|
251
|
+
### 1. Protection des Fichiers
|
|
252
|
+
|
|
253
|
+
```apache
|
|
254
|
+
# .htaccess - Protéger les fichiers sensibles
|
|
255
|
+
<Files "secure-init.php">
|
|
256
|
+
Order Allow,Deny
|
|
257
|
+
Deny from all
|
|
258
|
+
</Files>
|
|
259
|
+
|
|
260
|
+
<Files ".env">
|
|
261
|
+
Order Allow,Deny
|
|
262
|
+
Deny from all
|
|
263
|
+
</Files>
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### 2. Validation côté serveur
|
|
267
|
+
|
|
268
|
+
```php
|
|
269
|
+
// Valider les paramètres d'entrée
|
|
270
|
+
function validateRequest($data) {
|
|
271
|
+
$errors = [];
|
|
272
|
+
|
|
273
|
+
if (!isset($data['type']) || !in_array($data['type'], [1, 2, 3])) {
|
|
274
|
+
$errors[] = 'Type invalide';
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (!isset($data['partnerName']) || strlen($data['partnerName']) < 2) {
|
|
278
|
+
$errors[] = 'Nom partenaire invalide';
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return $errors;
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 3. Logs de Sécurité
|
|
286
|
+
|
|
287
|
+
```php
|
|
288
|
+
// Logger les tentatives d'accès
|
|
289
|
+
function logSecurityEvent($event, $data) {
|
|
290
|
+
$log = [
|
|
291
|
+
'timestamp' => date('c'),
|
|
292
|
+
'event' => $event,
|
|
293
|
+
'ip' => $_SERVER['REMOTE_ADDR'],
|
|
294
|
+
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
|
|
295
|
+
'data' => $data
|
|
296
|
+
];
|
|
297
|
+
|
|
298
|
+
error_log('SunuID Security: ' . json_encode($log));
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### 4. Rate Limiting
|
|
303
|
+
|
|
304
|
+
```php
|
|
305
|
+
// Limiter le nombre de requêtes par IP
|
|
306
|
+
function checkRateLimit($ip) {
|
|
307
|
+
$cacheFile = sys_get_temp_dir() . '/sunuid_rate_limit_' . md5($ip);
|
|
308
|
+
$limit = 10; // 10 requêtes
|
|
309
|
+
$window = 3600; // par heure
|
|
310
|
+
|
|
311
|
+
if (file_exists($cacheFile)) {
|
|
312
|
+
$data = json_decode(file_get_contents($cacheFile), true);
|
|
313
|
+
if ($data['count'] >= $limit && (time() - $data['start']) < $window) {
|
|
314
|
+
return false; // Limite dépassée
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Mettre à jour le compteur
|
|
319
|
+
file_put_contents($cacheFile, json_encode([
|
|
320
|
+
'count' => ($data['count'] ?? 0) + 1,
|
|
321
|
+
'start' => $data['start'] ?? time()
|
|
322
|
+
]));
|
|
323
|
+
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## 📋 Checklist de Sécurité
|
|
329
|
+
|
|
330
|
+
- [ ] ✅ Utiliser l'initialisation sécurisée (`secureInit: true`)
|
|
331
|
+
- [ ] ✅ Stocker les credentials dans des variables d'environnement
|
|
332
|
+
- [ ] ✅ Protéger les fichiers sensibles avec `.htaccess`
|
|
333
|
+
- [ ] ✅ Valider tous les paramètres d'entrée
|
|
334
|
+
- [ ] ✅ Implémenter des logs de sécurité
|
|
335
|
+
- [ ] ✅ Limiter le taux de requêtes
|
|
336
|
+
- [ ] ✅ Utiliser HTTPS en production
|
|
337
|
+
- [ ] ✅ Vérifier régulièrement les logs de sécurité
|
|
338
|
+
- [ ] ✅ Mettre à jour les credentials régulièrement
|
|
339
|
+
- [ ] ✅ Tester la sécurité avec des outils d'audit
|
|
340
|
+
|
|
341
|
+
## 🚨 Signaux d'Alerte
|
|
342
|
+
|
|
343
|
+
Si vous voyez ces patterns dans votre code, c'est un signe de problème de sécurité :
|
|
344
|
+
|
|
345
|
+
```javascript
|
|
346
|
+
// ❌ DANGEREUX
|
|
347
|
+
const clientId = '1754166754_221A57B46843D755';
|
|
348
|
+
const secretId = '56d40fe70507228b27f2640ae65894177c2fedbf246e2b30978fde1fc43953c5';
|
|
349
|
+
|
|
350
|
+
// ❌ DANGEREUX
|
|
351
|
+
const config = {
|
|
352
|
+
clientId: window.SUNUID_CLIENT_ID, // Variable globale
|
|
353
|
+
secretId: localStorage.getItem('sunuid_secret') // Stockage local
|
|
354
|
+
};
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## 📞 Support
|
|
358
|
+
|
|
359
|
+
Si vous avez des questions sur la sécurisation, consultez :
|
|
360
|
+
|
|
361
|
+
1. **Documentation officielle** : `/docs/`
|
|
362
|
+
2. **Exemples sécurisés** : `/examples/secure-integration.html`
|
|
363
|
+
3. **Code source** : `/src/sunuid-sdk.js`
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
**⚠️ Rappel important** : La sécurité de vos credentials est de votre responsabilité. Suivez toujours les bonnes pratiques et testez votre implémentation avant la mise en production.
|
|
368
|
+
|