sunuid-sdk 1.0.51 → 1.0.53
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/dist/sunuid-sdk.esm.js +5 -5
- package/dist/sunuid-sdk.esm.js.map +1 -1
- package/dist/sunuid-sdk.js +5 -5
- package/dist/sunuid-sdk.js.map +1 -1
- package/dist/sunuid-sdk.min.js +1 -1
- package/dist/sunuid-sdk.min.js.map +1 -1
- package/docs/INTEGRATION_GUIDE.md +334 -0
- package/docs/SECURITY_GUIDE.md +369 -0
- package/examples/.htaccess.example +190 -0
- package/examples/README.md +192 -0
- package/examples/auto-code.js +234 -0
- package/examples/auto-integration.html +337 -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/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-init.php +154 -0
- package/examples/secure-integration-example.js +186 -0
- package/examples/secure-integration.html +410 -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/package.json +24 -10
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="fr">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>SunuID - Exemple Sans Boucle</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: Arial, sans-serif;
|
|
10
|
+
max-width: 800px;
|
|
11
|
+
margin: 0 auto;
|
|
12
|
+
padding: 20px;
|
|
13
|
+
background: #f5f5f5;
|
|
14
|
+
}
|
|
15
|
+
.container {
|
|
16
|
+
background: white;
|
|
17
|
+
padding: 30px;
|
|
18
|
+
border-radius: 10px;
|
|
19
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
20
|
+
}
|
|
21
|
+
.status {
|
|
22
|
+
padding: 15px;
|
|
23
|
+
border-radius: 5px;
|
|
24
|
+
margin: 10px 0;
|
|
25
|
+
}
|
|
26
|
+
.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
|
27
|
+
.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
|
28
|
+
.info { background: #d1ecf1; color: #0c5460; border: 1px solid #bee5eb; }
|
|
29
|
+
.warning { background: #fff3cd; color: #856404; border: 1px solid #ffeaa7; }
|
|
30
|
+
.qr-container {
|
|
31
|
+
text-align: center;
|
|
32
|
+
margin: 20px 0;
|
|
33
|
+
padding: 20px;
|
|
34
|
+
border: 2px dashed #ccc;
|
|
35
|
+
border-radius: 10px;
|
|
36
|
+
}
|
|
37
|
+
button {
|
|
38
|
+
background: #007bff;
|
|
39
|
+
color: white;
|
|
40
|
+
border: none;
|
|
41
|
+
padding: 10px 20px;
|
|
42
|
+
border-radius: 5px;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
margin: 5px;
|
|
45
|
+
}
|
|
46
|
+
button:hover { background: #0056b3; }
|
|
47
|
+
button:disabled { background: #6c757d; cursor: not-allowed; }
|
|
48
|
+
.hidden { display: none; }
|
|
49
|
+
.log {
|
|
50
|
+
background: #f8f9fa;
|
|
51
|
+
padding: 10px;
|
|
52
|
+
border-radius: 5px;
|
|
53
|
+
font-family: monospace;
|
|
54
|
+
font-size: 12px;
|
|
55
|
+
max-height: 200px;
|
|
56
|
+
overflow-y: auto;
|
|
57
|
+
margin: 10px 0;
|
|
58
|
+
}
|
|
59
|
+
</style>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<div class="container">
|
|
63
|
+
<h1>🔧 SunuID - Exemple Sans Boucle</h1>
|
|
64
|
+
|
|
65
|
+
<div id="status" class="status info">
|
|
66
|
+
Prêt à initialiser le SDK...
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div id="controls">
|
|
70
|
+
<button id="initBtn" onclick="initSDK()">🚀 Initialiser SDK</button>
|
|
71
|
+
<button id="qrBtn" onclick="generateQR()" disabled>📱 Générer QR</button>
|
|
72
|
+
<button id="destroyBtn" onclick="destroySDK()" disabled>🗑️ Détruire SDK</button>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
<div id="qr-section" class="hidden">
|
|
76
|
+
<h2>📱 QR Code</h2>
|
|
77
|
+
<div id="qr-area" class="qr-container">
|
|
78
|
+
<!-- Le QR code sera affiché ici -->
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div id="logs">
|
|
83
|
+
<h3>📋 Logs</h3>
|
|
84
|
+
<div id="logContainer" class="log">
|
|
85
|
+
<!-- Les logs seront affichés ici -->
|
|
86
|
+
</div>
|
|
87
|
+
<button onclick="clearLogs()">🧹 Nettoyer logs</button>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<!-- Socket.IO -->
|
|
92
|
+
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
|
|
93
|
+
|
|
94
|
+
<!-- SunuID SDK -->
|
|
95
|
+
<script src="../../dist/sunuid-sdk.min.js"></script>
|
|
96
|
+
|
|
97
|
+
<script>
|
|
98
|
+
// Variables globales
|
|
99
|
+
let sunuid = null;
|
|
100
|
+
let initCount = 0;
|
|
101
|
+
|
|
102
|
+
// Configuration du SDK
|
|
103
|
+
const config = {
|
|
104
|
+
apiUrl: 'https://api.sunuid.fayma.sn',
|
|
105
|
+
clientId: '1754166754_221A57B46843D755',
|
|
106
|
+
secretId: '56d40fe70507228b27f2640ae65894177c2fedbf246e2b30978fde1fc43953c5',
|
|
107
|
+
type: 2, // AUTH
|
|
108
|
+
theme: 'light',
|
|
109
|
+
language: 'fr',
|
|
110
|
+
|
|
111
|
+
// IMPORTANT: autoInit désactivé
|
|
112
|
+
autoInit: false,
|
|
113
|
+
|
|
114
|
+
// Callbacks
|
|
115
|
+
onSuccess: function(data) {
|
|
116
|
+
log('🎉 Succès: ' + JSON.stringify(data));
|
|
117
|
+
updateStatus('Succès: ' + JSON.stringify(data), 'success');
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
onError: function(error) {
|
|
121
|
+
log('❌ Erreur: ' + error.message);
|
|
122
|
+
updateStatus('Erreur: ' + error.message, 'error');
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
onStatusUpdate: function(status) {
|
|
126
|
+
log('📊 Statut: ' + status);
|
|
127
|
+
updateStatus('Statut: ' + status, 'info');
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Fonction de log personnalisée
|
|
132
|
+
function log(message) {
|
|
133
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
134
|
+
const logContainer = document.getElementById('logContainer');
|
|
135
|
+
logContainer.innerHTML += `[${timestamp}] ${message}\n`;
|
|
136
|
+
logContainer.scrollTop = logContainer.scrollHeight;
|
|
137
|
+
console.log(message);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Fonction de mise à jour du statut
|
|
141
|
+
function updateStatus(message, type) {
|
|
142
|
+
const statusEl = document.getElementById('status');
|
|
143
|
+
statusEl.textContent = message;
|
|
144
|
+
statusEl.className = `status ${type}`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Fonction d'initialisation du SDK
|
|
148
|
+
async function initSDK() {
|
|
149
|
+
try {
|
|
150
|
+
initCount++;
|
|
151
|
+
log(`🔄 Tentative d'initialisation #${initCount}`);
|
|
152
|
+
|
|
153
|
+
// Vérifier si déjà initialisé
|
|
154
|
+
if (sunuid && sunuid.isInitialized) {
|
|
155
|
+
log('⚠️ SDK déjà initialisé, ignoré');
|
|
156
|
+
updateStatus('SDK déjà initialisé', 'warning');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Créer une nouvelle instance
|
|
161
|
+
log('🔧 Création nouvelle instance SDK...');
|
|
162
|
+
sunuid = new SunuID(config);
|
|
163
|
+
|
|
164
|
+
// Initialisation manuelle
|
|
165
|
+
log('🚀 Initialisation manuelle...');
|
|
166
|
+
await sunuid.init();
|
|
167
|
+
|
|
168
|
+
log('✅ SDK initialisé avec succès !');
|
|
169
|
+
updateStatus('SDK initialisé avec succès', 'success');
|
|
170
|
+
|
|
171
|
+
// Activer les boutons
|
|
172
|
+
document.getElementById('qrBtn').disabled = false;
|
|
173
|
+
document.getElementById('destroyBtn').disabled = false;
|
|
174
|
+
document.getElementById('initBtn').disabled = true;
|
|
175
|
+
|
|
176
|
+
} catch (error) {
|
|
177
|
+
log('❌ Erreur lors de l\'initialisation: ' + error.message);
|
|
178
|
+
updateStatus('Erreur d\'initialisation: ' + error.message, 'error');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Fonction de génération de QR
|
|
183
|
+
async function generateQR() {
|
|
184
|
+
try {
|
|
185
|
+
if (!sunuid || !sunuid.isInitialized) {
|
|
186
|
+
log('⚠️ SDK non initialisé');
|
|
187
|
+
updateStatus('SDK non initialisé', 'warning');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
log('📱 Génération du QR code...');
|
|
192
|
+
document.getElementById('qr-section').classList.remove('hidden');
|
|
193
|
+
|
|
194
|
+
const result = await sunuid.generateQR('qr-area');
|
|
195
|
+
log('✅ QR code généré: ' + JSON.stringify(result));
|
|
196
|
+
updateStatus('QR code généré avec succès', 'success');
|
|
197
|
+
|
|
198
|
+
} catch (error) {
|
|
199
|
+
log('❌ Erreur génération QR: ' + error.message);
|
|
200
|
+
updateStatus('Erreur génération QR: ' + error.message, 'error');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Fonction de destruction du SDK
|
|
205
|
+
function destroySDK() {
|
|
206
|
+
try {
|
|
207
|
+
if (sunuid) {
|
|
208
|
+
log('🗑️ Destruction du SDK...');
|
|
209
|
+
sunuid.destroy();
|
|
210
|
+
sunuid = null;
|
|
211
|
+
|
|
212
|
+
log('✅ SDK détruit');
|
|
213
|
+
updateStatus('SDK détruit', 'info');
|
|
214
|
+
|
|
215
|
+
// Réinitialiser l'interface
|
|
216
|
+
document.getElementById('qrBtn').disabled = true;
|
|
217
|
+
document.getElementById('destroyBtn').disabled = true;
|
|
218
|
+
document.getElementById('initBtn').disabled = false;
|
|
219
|
+
document.getElementById('qr-section').classList.add('hidden');
|
|
220
|
+
document.getElementById('qr-area').innerHTML = '';
|
|
221
|
+
|
|
222
|
+
} else {
|
|
223
|
+
log('⚠️ Aucun SDK à détruire');
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
log('❌ Erreur destruction: ' + error.message);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Fonction de nettoyage des logs
|
|
231
|
+
function clearLogs() {
|
|
232
|
+
document.getElementById('logContainer').innerHTML = '';
|
|
233
|
+
log('🧹 Logs nettoyés');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Initialisation au chargement de la page
|
|
237
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
238
|
+
log('📄 Page chargée - Prêt à initialiser le SDK');
|
|
239
|
+
updateStatus('Prêt à initialiser le SDK', 'info');
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Exposer globalement pour debug
|
|
243
|
+
window.sunuid = sunuid;
|
|
244
|
+
window.initSDK = initSDK;
|
|
245
|
+
window.generateQR = generateQR;
|
|
246
|
+
window.destroySDK = destroySDK;
|
|
247
|
+
window.clearLogs = clearLogs;
|
|
248
|
+
</script>
|
|
249
|
+
</body>
|
|
250
|
+
</html>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration SunuID SDK - Personnalisation du Nom du Partenaire
|
|
3
|
+
*
|
|
4
|
+
* Ce fichier montre comment configurer le SDK pour afficher le nom
|
|
5
|
+
* de votre entreprise au lieu de "SunuID" dans les labels et textes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Configuration pour la production avec nom personnalisé
|
|
9
|
+
window.SunuIDConfig = {
|
|
10
|
+
// URL de l'API de production
|
|
11
|
+
apiUrl: 'https://api.sunuid.fayma.sn',
|
|
12
|
+
|
|
13
|
+
// Endpoints spécifiques
|
|
14
|
+
endpoints: {
|
|
15
|
+
qrGenerate: '/qr-generate',
|
|
16
|
+
qrStatus: '/qr-status',
|
|
17
|
+
qrConfirm: '/qr-confirm',
|
|
18
|
+
debug: '/debug',
|
|
19
|
+
test: '/test-sdk'
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Exemple 1: Banque
|
|
24
|
+
const banqueConfig = {
|
|
25
|
+
clientId: 'banque_client_id',
|
|
26
|
+
secretId: 'banque_secret_id',
|
|
27
|
+
type: 2, // Authentification
|
|
28
|
+
partnerName: 'Ma Banque', // Nom personnalisé
|
|
29
|
+
theme: 'light',
|
|
30
|
+
language: 'fr',
|
|
31
|
+
|
|
32
|
+
// Configuration pour la production
|
|
33
|
+
apiUrl: 'https://api.sunuid.fayma.sn',
|
|
34
|
+
secureInitUrl: 'https://sunuid.fayma.sn/secure-init',
|
|
35
|
+
|
|
36
|
+
// Callbacks
|
|
37
|
+
onSuccess: (data) => {
|
|
38
|
+
console.log('Authentification réussie avec Ma Banque:', data);
|
|
39
|
+
},
|
|
40
|
+
onError: (error) => {
|
|
41
|
+
console.error('Erreur Ma Banque:', error);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Exemple 2: E-commerce
|
|
46
|
+
const ecommerceConfig = {
|
|
47
|
+
clientId: 'ecommerce_client_id',
|
|
48
|
+
secretId: 'ecommerce_secret_id',
|
|
49
|
+
type: 2, // Authentification
|
|
50
|
+
partnerName: 'MonShop', // Nom personnalisé
|
|
51
|
+
theme: 'dark',
|
|
52
|
+
language: 'fr',
|
|
53
|
+
|
|
54
|
+
// Configuration pour la production
|
|
55
|
+
apiUrl: 'https://api.sunuid.fayma.sn',
|
|
56
|
+
secureInitUrl: 'https://sunuid.fayma.sn/secure-init',
|
|
57
|
+
|
|
58
|
+
// Callbacks
|
|
59
|
+
onSuccess: (data) => {
|
|
60
|
+
console.log('Authentification réussie avec MonShop:', data);
|
|
61
|
+
},
|
|
62
|
+
onError: (error) => {
|
|
63
|
+
console.error('Erreur MonShop:', error);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// Exemple 3: Administration
|
|
68
|
+
const adminConfig = {
|
|
69
|
+
clientId: 'admin_client_id',
|
|
70
|
+
secretId: 'admin_secret_id',
|
|
71
|
+
type: 1, // KYC
|
|
72
|
+
partnerName: 'Gouvernement', // Nom personnalisé
|
|
73
|
+
theme: 'light',
|
|
74
|
+
language: 'fr',
|
|
75
|
+
|
|
76
|
+
// Configuration pour la production
|
|
77
|
+
apiUrl: 'https://api.sunuid.fayma.sn',
|
|
78
|
+
secureInitUrl: 'https://sunuid.fayma.sn/secure-init',
|
|
79
|
+
|
|
80
|
+
// Callbacks
|
|
81
|
+
onSuccess: (data) => {
|
|
82
|
+
console.log('KYC réussi avec Gouvernement:', data);
|
|
83
|
+
},
|
|
84
|
+
onError: (error) => {
|
|
85
|
+
console.error('Erreur Gouvernement:', error);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Initialisation avec configuration personnalisée
|
|
90
|
+
function initSunuIDWithPartnerName(config) {
|
|
91
|
+
const sunuid = new SunuID(config);
|
|
92
|
+
|
|
93
|
+
sunuid.init().then(() => {
|
|
94
|
+
console.log(`SDK initialisé pour ${config.partnerName}`);
|
|
95
|
+
|
|
96
|
+
// Exemple d'utilisation
|
|
97
|
+
sunuid.generateQR('qr-container', {
|
|
98
|
+
theme: config.theme,
|
|
99
|
+
onSuccess: config.onSuccess,
|
|
100
|
+
onError: config.onError
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
}).catch(error => {
|
|
104
|
+
console.error(`Erreur d'initialisation pour ${config.partnerName}:`, error);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return sunuid;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Utilisation
|
|
111
|
+
// initSunuIDWithPartnerName(banqueConfig);
|
|
112
|
+
// initSunuIDWithPartnerName(ecommerceConfig);
|
|
113
|
+
// initSunuIDWithPartnerName(adminConfig);
|
|
114
|
+
|
|
115
|
+
// Export pour utilisation dans d'autres fichiers
|
|
116
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
117
|
+
module.exports = {
|
|
118
|
+
banqueConfig,
|
|
119
|
+
ecommerceConfig,
|
|
120
|
+
adminConfig,
|
|
121
|
+
initSunuIDWithPartnerName
|
|
122
|
+
};
|
|
123
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration SunuID SDK pour la Production
|
|
3
|
+
*
|
|
4
|
+
* Ce fichier montre comment configurer le SDK pour la production
|
|
5
|
+
* en remplaçant les URLs locales par les URLs de production.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Configuration pour la production
|
|
9
|
+
window.SunuIDConfig = {
|
|
10
|
+
// URL de l'API de production
|
|
11
|
+
apiUrl: 'https://api.sunuid.fayma.sn',
|
|
12
|
+
|
|
13
|
+
// Endpoints spécifiques
|
|
14
|
+
endpoints: {
|
|
15
|
+
qrGenerate: '/qr-generate',
|
|
16
|
+
qrStatus: '/qr-status',
|
|
17
|
+
qrConfirm: '/qr-confirm',
|
|
18
|
+
debug: '/debug',
|
|
19
|
+
test: '/test-sdk'
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
// Configuration par défaut
|
|
23
|
+
defaultConfig: {
|
|
24
|
+
theme: 'light',
|
|
25
|
+
language: 'fr',
|
|
26
|
+
autoRefresh: true,
|
|
27
|
+
refreshInterval: 30000, // 30 secondes
|
|
28
|
+
qrSize: 300,
|
|
29
|
+
qrMargin: 10
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Exemple d'utilisation en production
|
|
34
|
+
const sunuid = new SunuID({
|
|
35
|
+
clientId: 'votre_client_id',
|
|
36
|
+
secretId: 'votre_secret_id',
|
|
37
|
+
type: 2, // Authentification
|
|
38
|
+
partnerName: 'Votre Entreprise',
|
|
39
|
+
theme: 'light',
|
|
40
|
+
language: 'fr',
|
|
41
|
+
|
|
42
|
+
// Configuration pour la production
|
|
43
|
+
apiUrl: 'https://api.sunuid.fayma.sn',
|
|
44
|
+
secureInitUrl: 'https://sunuid.fayma.sn/secure-init',
|
|
45
|
+
|
|
46
|
+
// Callbacks
|
|
47
|
+
onSuccess: (data) => {
|
|
48
|
+
console.log('Authentification réussie:', data);
|
|
49
|
+
},
|
|
50
|
+
onError: (error) => {
|
|
51
|
+
console.error('Erreur:', error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Initialisation
|
|
56
|
+
sunuid.init().then(() => {
|
|
57
|
+
console.log('SDK initialisé pour la production');
|
|
58
|
+
}).catch(error => {
|
|
59
|
+
console.error('Erreur d\'initialisation:', error);
|
|
60
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* SunuID SDK - Endpoint d'initialisation sécurisée
|
|
4
|
+
*
|
|
5
|
+
* Ce fichier permet au SDK JavaScript de récupérer des tokens temporaires
|
|
6
|
+
* contenant les credentials sans les exposer directement dans le code client.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT :
|
|
9
|
+
* - Remplacez les credentials par vos vrais credentials
|
|
10
|
+
* - Stockez ce fichier en dehors du répertoire public si possible
|
|
11
|
+
* - Utilisez des variables d'environnement en production
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
// Headers CORS pour permettre les requêtes depuis le SDK JavaScript
|
|
15
|
+
header('Content-Type: application/json');
|
|
16
|
+
header('Access-Control-Allow-Origin: *');
|
|
17
|
+
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
|
|
18
|
+
header('Access-Control-Allow-Headers: Content-Type, Authorization');
|
|
19
|
+
|
|
20
|
+
// Gérer les requêtes OPTIONS (preflight)
|
|
21
|
+
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
22
|
+
http_response_code(200);
|
|
23
|
+
exit();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Configuration SunuID (à remplacer par vos vrais credentials)
|
|
27
|
+
$SUNUID_CONFIG = [
|
|
28
|
+
'client_id' => $_ENV['SUNUID_CLIENT_ID'] ?? 'your_client_id_here',
|
|
29
|
+
'secret_id' => $_ENV['SUNUID_SECRET_ID'] ?? 'your_secret_id_here',
|
|
30
|
+
'api_url' => $_ENV['SUNUID_API_URL'] ?? 'https://api.sunuid.fayma.sn',
|
|
31
|
+
'token_expiry' => $_ENV['SUNUID_TOKEN_EXPIRY'] ?? 300, // 5 minutes
|
|
32
|
+
'max_requests' => $_ENV['SUNUID_MAX_REQUESTS'] ?? 10
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Valider les paramètres d'initialisation
|
|
37
|
+
*/
|
|
38
|
+
function validateInitParams($data) {
|
|
39
|
+
$required = ['timestamp', 'nonce'];
|
|
40
|
+
|
|
41
|
+
foreach ($required as $field) {
|
|
42
|
+
if (!isset($data[$field])) {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Vérifier que le timestamp n'est pas trop ancien (5 minutes)
|
|
48
|
+
if (time() - $data['timestamp'] > 300) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Générer un token sécurisé contenant les credentials
|
|
57
|
+
*/
|
|
58
|
+
function generateSecureToken($config) {
|
|
59
|
+
$payload = [
|
|
60
|
+
'client_id' => $config['client_id'],
|
|
61
|
+
'secret_id' => $config['secret_id'],
|
|
62
|
+
'api_url' => $config['api_url'],
|
|
63
|
+
'exp' => time() + $config['token_expiry'],
|
|
64
|
+
'iat' => time(),
|
|
65
|
+
'nonce' => bin2hex(random_bytes(16))
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
// Encoder en base64 pour simplicité
|
|
69
|
+
// En production, utilisez JWT ou un chiffrement plus robuste
|
|
70
|
+
return base64_encode(json_encode($payload));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Valider un token reçu
|
|
75
|
+
*/
|
|
76
|
+
function validateToken($token) {
|
|
77
|
+
try {
|
|
78
|
+
$decoded = json_decode(base64_decode($token), true);
|
|
79
|
+
|
|
80
|
+
if (!$decoded) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Vérifier l'expiration
|
|
85
|
+
if (isset($decoded['exp']) && $decoded['exp'] < time()) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return $decoded;
|
|
90
|
+
} catch (Exception $e) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Traitement des requêtes
|
|
96
|
+
$method = $_SERVER['REQUEST_METHOD'];
|
|
97
|
+
$input = json_decode(file_get_contents('php://input'), true) ?? [];
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
switch ($method) {
|
|
101
|
+
case 'POST':
|
|
102
|
+
// Générer un token pour l'initialisation sécurisée
|
|
103
|
+
if (!validateInitParams($input)) {
|
|
104
|
+
throw new Exception('Paramètres invalides');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
$token = generateSecureToken($SUNUID_CONFIG);
|
|
108
|
+
|
|
109
|
+
echo json_encode([
|
|
110
|
+
'success' => true,
|
|
111
|
+
'token' => $token,
|
|
112
|
+
'expires_in' => $SUNUID_CONFIG['token_expiry'],
|
|
113
|
+
'timestamp' => time()
|
|
114
|
+
]);
|
|
115
|
+
break;
|
|
116
|
+
|
|
117
|
+
case 'GET':
|
|
118
|
+
// Valider un token (pour usage côté serveur)
|
|
119
|
+
$token = $_GET['token'] ?? null;
|
|
120
|
+
|
|
121
|
+
if (!$token) {
|
|
122
|
+
throw new Exception('Token manquant');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
$decoded = validateToken($token);
|
|
126
|
+
|
|
127
|
+
if (!$decoded) {
|
|
128
|
+
throw new Exception('Token invalide ou expiré');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
echo json_encode([
|
|
132
|
+
'success' => true,
|
|
133
|
+
'credentials' => [
|
|
134
|
+
'client_id' => $decoded['client_id'],
|
|
135
|
+
'secret_id' => $decoded['secret_id'],
|
|
136
|
+
'api_url' => $decoded['api_url']
|
|
137
|
+
],
|
|
138
|
+
'expires_at' => $decoded['exp']
|
|
139
|
+
]);
|
|
140
|
+
break;
|
|
141
|
+
|
|
142
|
+
default:
|
|
143
|
+
throw new Exception('Méthode non supportée');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
} catch (Exception $e) {
|
|
147
|
+
http_response_code(400);
|
|
148
|
+
echo json_encode([
|
|
149
|
+
'success' => false,
|
|
150
|
+
'error' => $e->getMessage(),
|
|
151
|
+
'timestamp' => time()
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
154
|
+
?>
|