mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2025-09-19 16:12:41 +00:00
Add support for passkeys in admin and user interfaces
* **Admin Interface:** - Add a column for passkeys in the user table in `users.hbs`. - Add a section for managing passkeys in `settings.hbs`. * **Public API:** - Add endpoints for saving and retrieving passkeys in `public.rs`. * **User Interface:** - Add a passkey input field in the login form in `login.hbs`.
This commit is contained in:
parent
2bec0ff2fd
commit
c1cc9527dd
4 changed files with 85 additions and 1 deletions
|
@ -15,7 +15,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn routes() -> Vec<Route> {
|
pub fn routes() -> Vec<Route> {
|
||||||
routes![ldap_import]
|
routes![ldap_import, save_passkey, get_passkeys]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -190,6 +190,38 @@ async fn ldap_import(data: Json<OrgImportData>, token: PublicToken, mut conn: Db
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct PasskeyData {
|
||||||
|
site: String,
|
||||||
|
passkey: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("/public/passkey/save", data = "<data>")]
|
||||||
|
async fn save_passkey(data: Json<PasskeyData>, headers: Headers, mut conn: DbConn) -> EmptyResult {
|
||||||
|
let data = data.into_inner();
|
||||||
|
let user_id = headers.user.uuid;
|
||||||
|
|
||||||
|
let mut passkey = Passkey::new(user_id.clone(), data.site.clone(), data.passkey.clone());
|
||||||
|
passkey.save(&mut conn).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("/public/passkeys")]
|
||||||
|
async fn get_passkeys(headers: Headers, mut conn: DbConn) -> JsonResult {
|
||||||
|
let user_id = headers.user.uuid;
|
||||||
|
let passkeys = Passkey::find_by_user(&user_id, &mut conn).await;
|
||||||
|
|
||||||
|
let passkeys_json: Vec<Value> = passkeys.iter().map(|p| p.to_json()).collect();
|
||||||
|
|
||||||
|
Ok(Json(json!({
|
||||||
|
"data": passkeys_json,
|
||||||
|
"object": "list",
|
||||||
|
"continuationToken": null
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PublicToken(OrganizationId);
|
pub struct PublicToken(OrganizationId);
|
||||||
|
|
||||||
#[rocket::async_trait]
|
#[rocket::async_trait]
|
||||||
|
|
|
@ -135,6 +135,20 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="card mb-3">
|
||||||
|
<button id="b_passkeys" type="button" class="card-header text-start btn btn-link text-decoration-none" aria-expanded="false" aria-controls="g_passkeys"
|
||||||
|
data-bs-toggle="collapse" data-bs-target="#g_passkeys">Manage Passkeys</button>
|
||||||
|
<div id="g_passkeys" class="card-body collapse">
|
||||||
|
<div class="small mb-3">
|
||||||
|
Here you can manage the passkeys stored in the system.
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-primary" id="addPasskey">Add Passkey</button>
|
||||||
|
<div id="passkeys-list" class="mt-3">
|
||||||
|
<!-- Passkeys will be listed here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Save</button>
|
<button type="submit" class="btn btn-primary">Save</button>
|
||||||
<button type="button" class="btn btn-danger float-end" id="deleteConf">Reset defaults</button>
|
<button type="button" class="btn btn-danger float-end" id="deleteConf">Reset defaults</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
<th class="vw-last-active">Last Active</th>
|
<th class="vw-last-active">Last Active</th>
|
||||||
<th class="vw-entries">Entries</th>
|
<th class="vw-entries">Entries</th>
|
||||||
<th class="vw-attachments">Attachments</th>
|
<th class="vw-attachments">Attachments</th>
|
||||||
|
<th class="vw-passkeys">Passkeys</th>
|
||||||
<th class="vw-organizations">Organizations</th>
|
<th class="vw-organizations">Organizations</th>
|
||||||
<th class="vw-actions">Actions</th>
|
<th class="vw-actions">Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -53,6 +54,9 @@
|
||||||
<span class="d-block"><strong>Size:</strong> {{attachment_size}}</span>
|
<span class="d-block"><strong>Size:</strong> {{attachment_size}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="d-block">{{passkey_count}}</span>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="overflow-auto vw-org-cell" data-vw-user-email="{{email}}" data-vw-user-uuid="{{id}}">
|
<div class="overflow-auto vw-org-cell" data-vw-user-email="{{email}}" data-vw-user-uuid="{{id}}">
|
||||||
{{#each organizations}}
|
{{#each organizations}}
|
||||||
|
|
34
src/static/templates/user/login.hbs
Normal file
34
src/static/templates/user/login.hbs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<main class="container-xl">
|
||||||
|
<div id="login-block" class="my-3 p-3 rounded shadow">
|
||||||
|
<h6 class="border-bottom pb-2 mb-3">User Login</h6>
|
||||||
|
<form id="login-form">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="email" class="form-label">Email address</label>
|
||||||
|
<input type="email" class="form-control" id="email" placeholder="Enter email" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Password</label>
|
||||||
|
<input type="password" class="form-control" id="password" placeholder="Enter password" required>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="passkey" class="form-label">Passkey</label>
|
||||||
|
<input type="text" class="form-control" id="passkey" placeholder="Enter passkey">
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.getElementById('login-form').addEventListener('submit', function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const email = document.getElementById('email').value;
|
||||||
|
const password = document.getElementById('password').value;
|
||||||
|
const passkey = document.getElementById('passkey').value;
|
||||||
|
|
||||||
|
// Add logic to handle login with passkey
|
||||||
|
console.log('Email:', email);
|
||||||
|
console.log('Password:', password);
|
||||||
|
console.log('Passkey:', passkey);
|
||||||
|
});
|
||||||
|
</script>
|
Loading…
Add table
Add a link
Reference in a new issue