mirror of
https://github.com/getnamingo/registry.git
synced 2025-06-28 23:23:22 +02:00
Further preparation for 2FA and WebAuthn
This commit is contained in:
parent
95e47cd9a6
commit
e7ddc2e997
4 changed files with 87 additions and 2 deletions
|
@ -28,4 +28,37 @@ class ProfileController extends Controller
|
|||
return view($response,'admin/profile/profile.twig',['email' => $email, 'username' => $username, 'status' => $status, 'role' => $role]);
|
||||
}
|
||||
|
||||
public function getRegistrationChallenge(Request $request, Response $response)
|
||||
{
|
||||
$user = $request->getAttribute('user'); // Assuming you have the user info
|
||||
$username = $user->getUsername(); // Replace with your method to get the username
|
||||
$userEmail = $user->getEmail(); // Replace with your method to get the user's email
|
||||
|
||||
$challenge = $this->webAuthn->prepareChallengeForRegistration($username, $userEmail);
|
||||
$_SESSION['webauthn_challenge'] = $challenge; // Store the challenge in the session
|
||||
|
||||
$response->getBody()->write(json_encode($challenge));
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
}
|
||||
|
||||
public function verifyRegistration(Request $request, Response $response)
|
||||
{
|
||||
$data = json_decode($request->getBody()->getContents(), true);
|
||||
|
||||
try {
|
||||
$credential = $this->webAuthn->processCreate($data, $_SESSION['webauthn_challenge']);
|
||||
unset($_SESSION['webauthn_challenge']);
|
||||
|
||||
// Store the credential data in the database
|
||||
// $user->addWebAuthnCredential($credential);
|
||||
|
||||
$response->getBody()->write(json_encode(['success' => true]));
|
||||
return $response->withHeader('Content-Type', 'application/json');
|
||||
} catch (\Exception $e) {
|
||||
// Handle error, return an appropriate response
|
||||
$response->getBody()->write(json_encode(['error' => $e->getMessage()]));
|
||||
return $response->withHeader('Content-Type', 'application/json')->withStatus(400);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -35,7 +35,9 @@
|
|||
"gettext/gettext": "^5.7",
|
||||
"punic/punic": "^3.8",
|
||||
"league/iso3166": "^4.3",
|
||||
"stripe/stripe-php": "^13.3"
|
||||
"stripe/stripe-php": "^13.3",
|
||||
"robthree/twofactorauth": "^2.1",
|
||||
"lbuchs/webauthn": "^2.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
<div class="card-body">
|
||||
<p>Secure your account with WebAuthn. Click the button below to register your device for passwordless sign-in.</p>
|
||||
<!-- Connect WebAuthn Button -->
|
||||
<button type="button" class="btn btn-success">Connect WebAuthn Device</button>
|
||||
<button type="button" class="btn btn-success" id="connectWebAuthnButton">Connect WebAuthn Device</button>
|
||||
<!-- WebAuthn Devices Table -->
|
||||
<div class="table-responsive mt-4">
|
||||
<table class="table table-striped">
|
||||
|
@ -156,4 +156,51 @@
|
|||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const connectButton = document.getElementById('connectWebAuthnButton');
|
||||
|
||||
connectButton.addEventListener('click', function() {
|
||||
// Step 1: Get the registration challenge from the server
|
||||
fetch('/webauthn/register/challenge')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Step 2: Call WebAuthn API to create credentials
|
||||
return navigator.credentials.create({
|
||||
publicKey: data
|
||||
});
|
||||
})
|
||||
.then(credentials => {
|
||||
// Step 3: Send the credentials back to the server for verification
|
||||
const publicKeyCredential = {
|
||||
id: credentials.id,
|
||||
rawId: btoa(String.fromCharCode.apply(null, new Uint8Array(credentials.rawId))),
|
||||
type: credentials.type,
|
||||
response: {
|
||||
attestationObject: btoa(String.fromCharCode.apply(null, new Uint8Array(credentials.response.attestationObject))),
|
||||
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(credentials.response.clientDataJSON)))
|
||||
}
|
||||
};
|
||||
|
||||
return fetch('/webauthn/register/verify', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(publicKeyCredential)
|
||||
});
|
||||
})
|
||||
.then(response => {
|
||||
if(response.ok) {
|
||||
// Handle successful registration, e.g., update the UI
|
||||
} else {
|
||||
// Handle registration error
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during WebAuthn registration:', error);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -83,6 +83,9 @@ $app->group('', function ($route) {
|
|||
$route->get('/support/media', SupportController::class .':mediakit')->setName('mediakit');
|
||||
|
||||
$route->get('/profile', ProfileController::class .':profile')->setName('profile');
|
||||
$route->get('/webauthn/register/challenge', ProfileController::class . ':getRegistrationChallenge')->setName('webauthn.register.challenge');
|
||||
$route->post('/webauthn/register/verify', ProfileController::class . ':verifyRegistration')->setName('webauthn.register.verify');
|
||||
|
||||
$route->get('/mode', HomeController::class .':mode')->setName('mode');
|
||||
$route->get('/lang', HomeController::class .':lang')->setName('lang');
|
||||
$route->get('/avatar', HomeController::class .':avatar')->setName('avatar');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue