}
public function register($attestationResponse) {
+ error_log("WebAuthn register called with: " . substr($attestationResponse, 0, 200));
+
if (!isset($_SESSION['challenge']) || !isset($_SESSION['username'])) {
+ error_log("WebAuthn register: missing challenge or username in session");
return false;
}
unset($_SESSION['username']);
try {
- $publicKeyCredentialSource = PublicKeyCredentialSource::createFromString($attestationResponse);
+ error_log("WebAuthn register: decoding JSON response");
+ // Decode the JSON response from JavaScript
+ $attestationData = json_decode($attestationResponse, true);
+
+ if ($attestationData === null) {
+ error_log("WebAuthn register: JSON decode failed. Error: " . json_last_error_msg());
+ return false;
+ }
+
+ error_log("WebAuthn register: JSON decoded successfully");
+
+ // Convert base64 back to binary
+ $attestationObject = base64_decode($attestationData['response']['attestationObject']);
+ $clientDataJSON = base64_decode($attestationData['response']['clientDataJSON']);
+ $rawId = base64_decode($attestationData['rawId']);
+
+ // Create the credential source from the components
+ $publicKeyCredentialSource = PublicKeyCredentialSource::createFromString(
+ json_encode([
+ 'attestationObject' => base64_encode($attestationObject),
+ 'clientDataJSON' => base64_encode($clientDataJSON),
+ 'id' => $attestationData['id'],
+ 'rawId' => base64_encode($rawId),
+ 'type' => $attestationData['type']
+ ])
+ );
+
$publicKeyCredential = $publicKeyCredentialSource->getPublicKeyCredential();
if (!$publicKeyCredential->verify($challenge, $this->origin)) {
if (!empty($username)) {
// Vérifier si le nom d'utilisateur existe déjà
- $stmt = $pdo->prepare("SELECT user_id FROM users WHERE username = ?");
+ $stmt = $pdo->prepare("SELECT id FROM users WHERE username = ?");
$stmt->execute([$username]);
if ($stmt->fetch()) {
$error = "Ce nom d'utilisateur est déjà pris.";
// Enregistrer l'utilisateur et la YubiKey dans la base de données
$pdo->beginTransaction();
try {
- // Insérer l'utilisateur
- $stmt = $pdo->prepare("INSERT INTO users (username) VALUES (?)");
- $stmt->execute([$username]);
- $userId = $pdo->lastInsertId();
+ // Insérer l'utilisateur (avec yubikey vide car la colonne est requise)
+ $stmt = $pdo->prepare("INSERT INTO users (username, yubikey) VALUES (?, ?) RETURNING id");
+ $stmt->execute([$username, '']); // yubikey vide pour l'instant
+ $userId = $stmt->fetchColumn();
// Insérer la YubiKey
$stmt = $pdo->prepare("INSERT INTO yubikeys (user_id, key_data, public_key) VALUES (?, ?, ?)");
$stmt->execute([$userId, $registrationData['credentialId'], $registrationData['publicKey']]);
// Mettre à jour l'utilisateur avec l'ID de la YubiKey
- $stmt = $pdo->prepare("UPDATE users SET yubikey_id = ? WHERE user_id = ?");
+ $stmt = $pdo->prepare("UPDATE users SET yubikey_id = ? WHERE id = ?");
$stmt->execute([$pdo->lastInsertId(), $userId]);
$pdo->commit();
</form>
<script>
+ // Helper function to convert ArrayBuffer to Base64
+ function arrayBufferToBase64(buffer) {
+ let binary = '';
+ const bytes = new Uint8Array(buffer);
+ const len = bytes.byteLength;
+ for (let i = 0; i < len; i++) {
+ binary += String.fromCharCode(bytes[i]);
+ }
+ return btoa(binary);
+ }
+
document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('registrationForm');
const usernameInput = document.getElementById('username');
if (registrationOptions === null) {
// Step 1: Get registration options
try {
- const response = await fetch('register.php', {
+ const response = await fetch('/diary-web/public/register.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
body: `username=${encodeURIComponent(usernameInput.value)}`
});
- const data = await response.json();
+ const responseText = await response.text();
+ console.log('Server response (step 1 - username check):', responseText);
+ console.log('Response length:', responseText.length);
+ console.log('First 100 chars:', responseText.substring(0, 100));
+
+ try {
+ const data = JSON.parse(responseText);
- if (data.success) {
- registrationOptions = data.options;
- usernameInput.disabled = true;
- registerButton.disabled = true;
- yubikeySection.style.display = 'block';
- webauthnMessage.textContent = 'Prêt pour l\'authentification YubiKey...';
-
- // Step 2: Call WebAuthn API
- await startWebAuthnRegistration();
- } else {
- alert(data.error || 'Erreur lors de la préparation de l\'inscription');
+ if (data.success) {
+ registrationOptions = data.options;
+ usernameInput.disabled = true;
+ registerButton.disabled = true;
+ yubikeySection.style.display = 'block';
+ webauthnMessage.textContent = 'Prêt pour l\'authentification YubiKey...';
+
+ // Step 2: Call WebAuthn API
+ await startWebAuthnRegistration();
+ } else {
+ alert(data.error || 'Erreur lors de la préparation de l\'inscription');
+ }
+ } catch (parseError) {
+ console.error('JSON parse error:', parseError);
+ alert('Erreur: Réponse du serveur invalide. Voir console pour détails.');
}
} catch (error) {
console.error('Error:', error);
- alert('Erreur lors de la communication avec le serveur');
+ console.error('Error details:', error.message, error.stack);
+ try {
+ console.log('Response text:', await response.text());
+ } catch (e) {
+ console.log('Could not get response text');
+ }
+ alert('Erreur lors de la communication avec le serveur: ' + error.message);
}
}
});
if (credential) {
// Send the attestation response to the server
- const response = await fetch('register.php', {
+ // Convert credential to a format that can be sent to the server
+ const attestationResponse = {
+ id: credential.id,
+ rawId: arrayBufferToBase64(credential.rawId),
+ response: {
+ attestationObject: arrayBufferToBase64(credential.response.attestationObject),
+ clientDataJSON: arrayBufferToBase64(credential.response.clientDataJSON)
+ },
+ type: credential.type
+ };
+
+ const response = await fetch('/diary-web/public/register.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
- body: `attestationResponse=${encodeURIComponent(JSON.stringify(credential))}`
+ body: `attestationResponse=${encodeURIComponent(JSON.stringify(attestationResponse))}`
});
- const data = await response.json();
+ const responseText = await response.text();
+ console.log('Server response (step 2 - attestation):', responseText);
+ console.log('Response length:', responseText.length);
+ console.log('First 100 chars:', responseText.substring(0, 100));
+
+ try {
+ const data = JSON.parse(responseText);
- if (data.success) {
- webauthnMessage.textContent = 'Inscription réussie ! Redirection...';
- window.location.href = data.redirect;
- } else {
- webauthnMessage.textContent = data.error || 'Erreur lors de l\'inscription';
+ if (data.success) {
+ webauthnMessage.textContent = 'Inscription réussie ! Redirection...';
+ window.location.href = data.redirect;
+ } else {
+ webauthnMessage.textContent = data.error || 'Erreur lors de l\'inscription';
+ }
+ } catch (parseError) {
+ console.error('JSON parse error:', parseError);
+ webauthnMessage.textContent = 'Erreur: Réponse du serveur invalide. Voir console pour détails.';
registerButton.disabled = false;
}
} else {
}
} catch (error) {
console.error('WebAuthn error:', error);
+ console.error('WebAuthn error details:', error.message, error.stack);
webauthnMessage.textContent = 'Erreur YubiKey: ' + error.message;
registerButton.disabled = false;
}