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
|
@ -27,5 +27,38 @@ class ProfileController extends Controller
|
||||||
|
|
||||||
return view($response,'admin/profile/profile.twig',['email' => $email, 'username' => $username, 'status' => $status, 'role' => $role]);
|
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",
|
"gettext/gettext": "^5.7",
|
||||||
"punic/punic": "^3.8",
|
"punic/punic": "^3.8",
|
||||||
"league/iso3166": "^4.3",
|
"league/iso3166": "^4.3",
|
||||||
"stripe/stripe-php": "^13.3"
|
"stripe/stripe-php": "^13.3",
|
||||||
|
"robthree/twofactorauth": "^2.1",
|
||||||
|
"lbuchs/webauthn": "^2.1"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|
|
@ -119,7 +119,7 @@
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>Secure your account with WebAuthn. Click the button below to register your device for passwordless sign-in.</p>
|
<p>Secure your account with WebAuthn. Click the button below to register your device for passwordless sign-in.</p>
|
||||||
<!-- Connect WebAuthn Button -->
|
<!-- 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 -->
|
<!-- WebAuthn Devices Table -->
|
||||||
<div class="table-responsive mt-4">
|
<div class="table-responsive mt-4">
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
|
@ -156,4 +156,51 @@
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</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 %}
|
{% endblock %}
|
|
@ -83,6 +83,9 @@ $app->group('', function ($route) {
|
||||||
$route->get('/support/media', SupportController::class .':mediakit')->setName('mediakit');
|
$route->get('/support/media', SupportController::class .':mediakit')->setName('mediakit');
|
||||||
|
|
||||||
$route->get('/profile', ProfileController::class .':profile')->setName('profile');
|
$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('/mode', HomeController::class .':mode')->setName('mode');
|
||||||
$route->get('/lang', HomeController::class .':lang')->setName('lang');
|
$route->get('/lang', HomeController::class .':lang')->setName('lang');
|
||||||
$route->get('/avatar', HomeController::class .':avatar')->setName('avatar');
|
$route->get('/avatar', HomeController::class .':avatar')->setName('avatar');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue