vw_small

Hardened fork of Vaultwarden (https://github.com/dani-garcia/vaultwarden) with fewer features.
git clone https://git.philomathiclife.com/repos/vw_small
Log | Files | Refs | README

commit 92bbb98d48c657450097c86481b594485cc81e1d
parent 834c84774638b994b13fb967b09511fbec6ed986
Author: Daniel GarcĂ­a <dani-garcia@users.noreply.github.com>
Date:   Sat, 19 Jan 2019 22:12:52 +0100

Created base template

Diffstat:
Msrc/api/admin.rs | 55+++++++++++++++++++++++++++++++++++++------------------
Msrc/main.rs | 1+
Asrc/static/templates/admin/admin_base.hbs | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/static/templates/admin/admin_login.hbs | 69++++++++++++++++++---------------------------------------------------
Msrc/static/templates/admin/admin_page.hbs | 189+++++++++++++++++++++++++++++++------------------------------------------------
5 files changed, 179 insertions(+), 184 deletions(-)

diff --git a/src/api/admin.rs b/src/api/admin.rs @@ -21,27 +21,53 @@ pub fn routes() -> Vec<Route> { routes![admin_login, post_admin_login, admin_page, invite_user, delete_user] } -#[derive(FromForm)] -struct LoginForm { - token: String, -} - const COOKIE_NAME: &'static str = "BWRS_ADMIN"; const ADMIN_PATH: &'static str = "/admin"; +#[derive(Serialize)] +struct AdminTemplateData { + users: Vec<Value>, + page_content: String, + error: Option<String>, +} + +impl AdminTemplateData { + fn login(error: Option<String>) -> Self { + Self { + users: Vec::new(), + page_content: String::from("admin/admin_login"), + error, + } + } + + fn admin(users: Vec<Value>) -> Self { + Self { + users, + page_content: String::from("admin/admin_page"), + error: None, + } + } + + fn render(self) -> Result<String, Error> { + CONFIG.templates.render("admin/admin_base", &self).map_err(Into::into) + } +} + #[get("/", rank = 2)] fn admin_login(flash: Option<FlashMessage>) -> Result<Html<String>, Error> { // If there is an error, show it - let msg = flash - .map(|msg| format!("{}: {}", msg.name(), msg.msg())) - .unwrap_or_default(); - let error = json!({ "error": msg }); + let msg = flash.map(|msg| format!("{}: {}", msg.name(), msg.msg())); // Return the page - let text = CONFIG.templates.render("admin/admin_login", &error)?; + let text = AdminTemplateData::login(msg).render()?; Ok(Html(text)) } +#[derive(FromForm)] +struct LoginForm { + token: String, +} + #[post("/", data = "<data>")] fn post_admin_login(data: Form<LoginForm>, mut cookies: Cookies, ip: ClientIp) -> Result<Redirect, Flash<Redirect>> { let data = data.into_inner(); @@ -74,19 +100,12 @@ fn _validate_token(token: &str) -> bool { } } -#[derive(Serialize)] -struct AdminTemplateData { - users: Vec<Value>, -} - #[get("/", rank = 1)] fn admin_page(_token: AdminToken, conn: DbConn) -> Result<Html<String>, Error> { let users = User::get_all(&conn); let users_json: Vec<Value> = users.iter().map(|u| u.to_json(&conn)).collect(); - let data = AdminTemplateData { users: users_json }; - - let text = CONFIG.templates.render("admin/admin_page", &data)?; + let text = AdminTemplateData::admin(users_json).render()?; Ok(Html(text)) } diff --git a/src/main.rs b/src/main.rs @@ -352,6 +352,7 @@ fn load_templates(path: String) -> Handlebars { reg!("email/pw_hint_some"); reg!("email/send_org_invite"); + reg!("admin/admin_base"); reg!("admin/admin_login"); reg!("admin/admin_page"); diff --git a/src/static/templates/admin/admin_base.hbs b/src/static/templates/admin/admin_base.hbs @@ -0,0 +1,48 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta http-equiv="content-type" content="text/html; charset=UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <title>Bitwarden_rs Admin Panel</title> + + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css" + integrity="sha256-azvvU9xKluwHFJ0Cpgtf0CYzK7zgtOznnzxV4924X1w=" crossorigin="anonymous" /> + <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" + crossorigin="anonymous"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.10.0/js/md5.js" integrity="sha256-tCQ/BldMlN2vWe5gAiNoNb5svoOgVUhlUgv7UjONKKQ=" + crossorigin="anonymous"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/identicon.js/2.3.3/identicon.min.js" integrity="sha256-nYoL3nK/HA1e1pJvLwNPnpKuKG9q89VFX862r5aohmA=" + crossorigin="anonymous"></script> + + <style> + body { + padding-top: 70px; + } + + img { + width: 48px; + height: 48px; + } + </style> +</head> + +<body class="bg-light"> + <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top shadow"> + <a class="navbar-brand" href="#">Bitwarden_rs</a> + <div class="navbar-collapse"> + <ul class="navbar-nav"> + <li class="nav-item active"> + <a class="nav-link" href="/admin">Admin Panel</a> + </li> + <li class="nav-item"> + <a class="nav-link" href="/">Vault</a> + </li> + </ul> + </div> + </nav> + + {{> (page_content) }} +</body> + +</html> +\ No newline at end of file diff --git a/src/static/templates/admin/admin_login.hbs b/src/static/templates/admin/admin_login.hbs @@ -1,54 +1,21 @@ -<!DOCTYPE html> -<html lang="en"> - -<head> - <meta http-equiv="content-type" content="text/html; charset=UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <title>Bitwarden_rs Admin Panel</title> - - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha256-azvvU9xKluwHFJ0Cpgtf0CYzK7zgtOznnzxV4924X1w=" crossorigin="anonymous" /> - <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> - - <style> - body { padding-top: 70px; } - </style> -</head> - -<body class="bg-light"> - <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top shadow"> - <a class="navbar-brand" href="#">Bitwarden_rs</a> - <div class="navbar-collapse"> - <ul class="navbar-nav"> - <li class="nav-item active"> - <a class="nav-link" href="/admin">Admin Panel</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="/">Vault</a> - </li> - </ul> - </div> - </nav> - <main class="container"> - {{#if error}} - <div class="align-items-center p-3 mb-3 text-white-50 bg-warning rounded shadow"> - <div> - <h6 class="mb-0 text-white">{{error}}</h6> - </div> +<main class="container"> + {{#if error}} + <div class="align-items-center p-3 mb-3 text-white-50 bg-warning rounded shadow"> + <div> + <h6 class="mb-0 text-white">{{error}}</h6> </div> - {{/if}} + </div> + {{/if}} - <div class="align-items-center p-3 mb-3 text-white-50 bg-danger rounded shadow"> - <div> - <h6 class="mb-0 text-white">Authentication key needed to continue</h6> - <small>Please provide it below:</small> + <div class="align-items-center p-3 mb-3 text-white-50 bg-danger rounded shadow"> + <div> + <h6 class="mb-0 text-white">Authentication key needed to continue</h6> + <small>Please provide it below:</small> - <form class="form-inline" method="post"> - <input type="password" class="form-control w-50 mr-2" name="token" placeholder="Enter admin token"> - <button type="submit" class="btn btn-primary">Save</button> - </form> - </div> + <form class="form-inline" method="post"> + <input type="password" class="form-control w-50 mr-2" name="token" placeholder="Enter admin token"> + <button type="submit" class="btn btn-primary">Save</button> + </form> </div> - </main> -</body> - -</html> -\ No newline at end of file + </div> +</main> +\ No newline at end of file diff --git a/src/static/templates/admin/admin_page.hbs b/src/static/templates/admin/admin_page.hbs @@ -1,124 +1,83 @@ -<!DOCTYPE html> -<html lang="en"> +<main class="container"> + <div id="users-block" class="my-3 p-3 bg-white rounded shadow"> + <h6 class="border-bottom pb-2 mb-0">Registered Users</h6> -<head> - <meta http-equiv="content-type" content="text/html; charset=UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <title>Bitwarden_rs Admin Panel</title> - - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/css/bootstrap.min.css" - integrity="sha256-azvvU9xKluwHFJ0Cpgtf0CYzK7zgtOznnzxV4924X1w=" crossorigin="anonymous" /> - <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" - crossorigin="anonymous"></script> - <script src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.10.0/js/md5.js" integrity="sha256-tCQ/BldMlN2vWe5gAiNoNb5svoOgVUhlUgv7UjONKKQ=" - crossorigin="anonymous"></script> - <script src="https://cdnjs.cloudflare.com/ajax/libs/identicon.js/2.3.3/identicon.min.js" integrity="sha256-nYoL3nK/HA1e1pJvLwNPnpKuKG9q89VFX862r5aohmA=" - crossorigin="anonymous"></script> - - <style> - body { padding-top: 70px; } - img { width: 48px; height: 48px; } - </style> - - <script> - function reload() { window.location.reload(); } - function identicon(email) { - const data = new Identicon(md5(email), { size: 48, format: 'svg' }); - return "data:image/svg+xml;base64," + data.toString(); - } - function _post(url, successMsg, errMsg, data) { - $.post({ url: url, data: data }) - .done(function () { - alert(successMsg); - reload(); - }).fail(function (e) { - const r = e.responseJSON; - const msg = r ? r.ErrorModel.Message : "Unknown error"; - alert(errMsg + ": " + msg); - }); - } - function deleteUser(id, mail) { - var input_mail = prompt("To delete user '" + mail + "', please type the name below") - if (input_mail) { - if (input_mail == mail) { - _post("/admin/users/" + id + "/delete", - "User deleted correctly", - "Error deleting user"); - } else { - alert("Wrong email, please try again") - } - } - } - function inviteUser() { - inv = $("#email-invite"); - data = JSON.stringify({ "Email": inv.val() }); - inv.val(""); - _post("/admin/invite/", "User invited correctly", - "Error inviting user", data); - } - - $(window).on('load', function () { - //$("#reload-btn").click(reload); - $("#invite-form").submit(inviteUser); - $("img.identicon").each(function (i, e) { - e.src = identicon(e.dataset.src); - }); - }); - </script> -</head> - -<body class="bg-light"> - <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top shadow"> - <a class="navbar-brand" href="#">Bitwarden_rs</a> - <div class="navbar-collapse"> - <ul class="navbar-nav"> - <li class="nav-item active"> - <a class="nav-link" href="/admin">Admin Panel</a> - </li> - <li class="nav-item"> - <a class="nav-link" href="/">Vault</a> - </li> - </ul> - </div> - </nav> - <main class="container"> - <div id="users-block" class="my-3 p-3 bg-white rounded shadow"> - <h6 class="border-bottom pb-2 mb-0">Registered Users</h6> - - <div id="users-list"> - {{#each users}} - <div class="media pt-3"> - {{!-- row.find(".tmp-icon").attr("src", identicon(user.Email)) --}} - <img class="mr-2 rounded identicon" data-src="{{Email}}"> - <div class="media-body pb-3 mb-0 small border-bottom"> - <div class="d-flex justify-content-between"> - <strong>{{Name}}</strong> - <a class="tmp-del mr-3" href="" onclick='deleteUser("{{Id}}", "{{Email}}");'>Delete User</a> - </div> - <span class="d-block">{{Email}}</span> + <div id="users-list"> + {{#each users}} + <div class="media pt-3"> + <img class="mr-2 rounded identicon" data-src="{{Email}}"> + <div class="media-body pb-3 mb-0 small border-bottom"> + <div class="d-flex justify-content-between"> + <strong>{{Name}}</strong> + <a class="tmp-del mr-3" href="" onclick='deleteUser("{{Id}}", "{{Email}}");'>Delete User</a> </div> + <span class="d-block">{{Email}}</span> </div> - {{/each}} - </div> + {{/each}} - <small class="d-block text-right mt-3"> - <a id="reload-btn" href="">Reload users</a> - </small> </div> - <div id="invite-form-block" class="align-items-center p-3 mb-3 text-white-50 bg-secondary rounded shadow"> - <div> - <h6 class="mb-0 text-white">Invite User</h6> - <small>Email:</small> + <small class="d-block text-right mt-3"> + <a id="reload-btn" href="">Reload users</a> + </small> + </div> - <form class="form-inline" id="invite-form"> - <input type="email" class="form-control w-50 mr-2" id="email-invite" placeholder="Enter email"> - <button type="submit" class="btn btn-primary">Invite</button> - </form> - </div> + <div id="invite-form-block" class="align-items-center p-3 mb-3 text-white-50 bg-secondary rounded shadow"> + <div> + <h6 class="mb-0 text-white">Invite User</h6> + <small>Email:</small> + + <form class="form-inline" id="invite-form"> + <input type="email" class="form-control w-50 mr-2" id="email-invite" placeholder="Enter email"> + <button type="submit" class="btn btn-primary">Invite</button> + </form> </div> - </main> -</body> + </div> +</main> -</html> -\ No newline at end of file +<script> + function reload() { window.location.reload(); } + function identicon(email) { + const data = new Identicon(md5(email), { size: 48, format: 'svg' }); + return "data:image/svg+xml;base64," + data.toString(); + } + function _post(url, successMsg, errMsg, data) { + $.post({ url: url, data: data }) + .done(function () { + alert(successMsg); + reload(); + }).fail(function (e) { + const r = e.responseJSON; + const msg = r ? r.ErrorModel.Message : "Unknown error"; + alert(errMsg + ": " + msg); + }); + } + function deleteUser(id, mail) { + var input_mail = prompt("To delete user '" + mail + "', please type the name below") + if (input_mail) { + if (input_mail == mail) { + _post("/admin/users/" + id + "/delete", + "User deleted correctly", + "Error deleting user"); + } else { + alert("Wrong email, please try again") + } + } + } + function inviteUser() { + inv = $("#email-invite"); + data = JSON.stringify({ "Email": inv.val() }); + inv.val(""); + _post("/admin/invite/", "User invited correctly", + "Error inviting user", data); + } + + $(window).on('load', function () { + //$("#reload-btn").click(reload); + $("#invite-form").submit(inviteUser); + $("img.identicon").each(function (i, e) { + e.src = identicon(e.dataset.src); + }); + }); +</script> +\ No newline at end of file