1
0
Fork 0
vaultwarden-test/src/static/templates/admin/page.hbs

298 Zeilen
13 KiB
Handlebars

2019-01-19 22:12:52 +01:00
<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>
2019-01-19 22:12:52 +01:00
<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="row justify-content-between">
<div class="col">
<strong>{{Name}}</strong>
2019-01-25 18:50:57 +01:00
{{#if TwoFactorEnabled}}
<span class="badge badge-success ml-2">2FA</span>
{{/if}}
{{#unless _Enabled}}
<span class="badge badge-warning ml-2">Disabled</span>
{{/unless}}
<span class="d-block">{{Email}}</span>
</div>
<div class="col">
<strong> Organizations:</strong>
<span class="d-block">
{{#each Organizations}}
<span class="badge badge-primary" data-orgtype="{{Type}}">{{Name}}</span>
{{/each}}
</span>
</div>
<div style="flex: 0 0 240px;">
<a class="mr-3" href="#" onclick='deauthUser({{jsesc Id}})'>Deauthorize sessions</a>
<a class="mr-3" href="#" onclick='deleteUser({{jsesc Id}}, {{jsesc Email}})'>Delete User</a>
</div>
</div>
</div>
</div>
2019-01-19 22:12:52 +01:00
{{/each}}
</div>
2019-01-19 22:12:52 +01:00
<small class="d-block text-right mt-3">
<a id="reload-btn" href="">Reload users</a>
</small>
</div>
2019-01-19 22:12:52 +01:00
<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>
2019-01-19 22:12:52 +01:00
</div>
2019-02-05 22:17:02 +01:00
<div id="config-block" class="align-items-center p-3 mb-3 bg-secondary rounded shadow">
<div>
2019-02-05 22:17:02 +01:00
<h6 class="text-white mb-3">Configuration</h6>
<div class="small text-white mb-3">
NOTE: The settings here override the environment variables. Once saved, it's recommended to stop setting them
to avoid confusion. This does not apply to the read-only section, which can only be set through the environment.
</div>
2019-02-05 22:17:02 +01:00
<form class="form accordion" id="config-form">
{{#each config}}
2019-02-05 22:17:02 +01:00
{{#if groupdoc}}
<div class="card bg-light mb-3">
2019-02-06 17:32:13 +01:00
<div class="card-header"><button type="button" class="btn btn-link collapsed" data-toggle="collapse"
2019-02-05 22:17:02 +01:00
data-target="#g_{{group}}">{{groupdoc}}</button></div>
<div id="g_{{group}}" class="card-body collapse" data-parent="#config-form">
{{#each elements}}
{{#if editable}}
<div class="form-group row" title="[{{name}}] {{doc.description}}">
2019-02-08 20:49:04 +01:00
{{#case type "text" "number" "password"}}
2019-02-05 22:17:02 +01:00
<label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label>
2019-02-08 20:49:04 +01:00
<div class="col-sm-8 input-group">
<input class="form-control conf-{{type}}" id="input_{{name}}" type="{{type}}"
name="{{name}}" value="{{value}}" {{#if default}} placeholder="Default: {{default}}"
{{/if}}>
{{#case type "password"}}
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button"
onclick="toggleVis('#input_{{name}}');">Show/hide</button>
</div>
{{/case}}
2019-02-05 22:17:02 +01:00
</div>
{{/case}}
{{#case type "checkbox"}}
<div class="col-sm-3">{{doc.name}}</div>
<div class="col-sm-8">
<div class="form-check">
<input class="form-check-input conf-{{type}}" type="checkbox" id="input_{{name}}"
name="{{name}}" {{#if value}} checked {{/if}}>
2019-02-05 22:17:02 +01:00
<label class="form-check-label" for="input_{{name}}"> Default: {{default}} </label>
</div>
</div>
{{/case}}
</div>
2019-02-05 22:17:02 +01:00
{{/if}}
{{/each}}
</div>
</div>
{{/if}}
{{/each}}
<div class="card bg-light mb-3">
<div class="card-header"><button type="button" class="btn btn-link collapsed" data-toggle="collapse"
data-target="#g_readonly">Read-Only Config</button></div>
<div id="g_readonly" class="card-body collapse" data-parent="#config-form">
<div class="small mb-3">
NOTE: These options can't be modified in the editor because they would require the server
to be restarted. To modify them, you need to set the correct environment variables when
launching the server. You can check the variable names in the tooltips of each option.
</div>
{{#each config}}
{{#each elements}}
{{#unless editable}}
<div class="form-group row" title="[{{name}}] {{doc.description}}">
{{#case type "text" "number" "password"}}
<label for="input_{{name}}" class="col-sm-3 col-form-label">{{doc.name}}</label>
<div class="col-sm-8 input-group">
<input readonly class="form-control" id="input_{{name}}" type="{{type}}"
value="{{value}}" {{#if default}} placeholder="Default: {{default}}" {{/if}}>
{{#case type "password"}}
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button"
onclick="toggleVis('#input_{{name}}');">Show/hide</button>
</div>
{{/case}}
</div>
{{/case}}
{{#case type "checkbox"}}
<div class="col-sm-3">{{doc.name}}</div>
<div class="col-sm-8">
<div class="form-check">
<input disabled class="form-check-input" type="checkbox" id="input_{{name}}"
{{#if value}} checked {{/if}}>
<label class="form-check-label" for="input_{{name}}"> Default: {{default}} </label>
</div>
</div>
{{/case}}
</div>
{{/unless}}
{{/each}}
{{/each}}
</div>
</div>
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" class="btn btn-danger float-right" onclick="deleteConf();">Reset defaults</button>
</form>
</div>
</div>
2019-01-19 22:12:52 +01:00
</main>
<style>
#config-block ::placeholder {
/* Most modern browsers support this now. */
color: orangered;
}
</style>
2019-01-19 22:12:52 +01:00
<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();
}
2019-02-08 20:49:04 +01:00
function toggleVis(input_id) {
var type = $(input_id).attr("type");
if (type === "text") {
$(input_id).attr("type", "password");
} else {
$(input_id).attr("type", "text");
}
return false;
}
2019-01-19 22:12:52 +01:00
function _post(url, successMsg, errMsg, data) {
$.post({
url: url,
data: data,
//async: false,
contentType: "application/json",
}).done(function () {
2019-01-21 23:41:27 +01:00
alert(successMsg);
}).fail(function (e) {
const r = e.responseJSON;
const msg = r ? r.ErrorModel.Message : "Unknown error";
alert(errMsg + ": " + msg);
}).always(reload);
2019-01-19 22:12:52 +01:00
}
function deleteUser(id, mail) {
var input_mail = prompt("To delete user '" + mail + "', please type the name below")
2019-01-22 17:26:17 +01:00
if (input_mail != null) {
2019-01-19 22:12:52 +01:00
if (input_mail == mail) {
_post("/admin/users/" + id + "/delete",
"User deleted correctly",
"Error deleting user");
} else {
alert("Wrong email, please try again")
}
}
2019-01-21 23:41:27 +01:00
return false;
2019-01-19 22:12:52 +01:00
}
function deauthUser(id) {
_post("/admin/users/" + id + "/deauth",
"Sessions deauthorized correctly",
"Error deauthorizing sessions");
return false;
}
2019-01-19 22:12:52 +01:00
function inviteUser() {
inv = $("#email-invite");
data = JSON.stringify({ "email": inv.val() });
2019-01-19 22:12:52 +01:00
inv.val("");
_post("/admin/invite/", "User invited correctly",
"Error inviting user", data);
2019-01-21 23:41:27 +01:00
return false;
2019-01-19 22:12:52 +01:00
}
function getFormData() {
let data = {};
$(".conf-checkbox").each(function (i, e) {
data[e.name] = $(e).is(":checked");
});
$(".conf-number").each(function (i, e) {
data[e.name] = +e.value;
});
2019-02-08 20:49:04 +01:00
$(".conf-text, .conf-password").each(function (i, e) {
data[e.name] = e.value || null;
});
return data;
}
function saveConfig() {
data = JSON.stringify(getFormData());
_post("/admin/config/", "Config saved correctly",
"Error saving config", data);
return false;
}
function deleteConf() {
2019-02-06 17:32:13 +01:00
var input = prompt("This will remove all user configurations, and restore the defaults and the " +
"values set by the environment. This operation could be dangerous. Type 'DELETE' to proceed:");
if (input === "DELETE") {
_post("/admin/config/delete",
"Config deleted correctly",
"Error deleting config");
} else {
alert("Wrong input, please try again")
}
return false;
}
function masterCheck(check_id, inputs_query) {
function toggleEnabled(check_id, inputs_query, enabled) {
$(inputs_query).prop("disabled", !enabled)
if (!enabled)
$(inputs_query).val("");
$(check_id).prop("disabled", false);
};
function onChanged(check_id, inputs_query) {
return function _fn() { toggleEnabled(check_id, inputs_query, this.checked); };
};
toggleEnabled(check_id, inputs_query, $(check_id).is(":checked"));
$(check_id).change(onChanged(check_id, inputs_query));
}
let OrgTypes = {
"0": { "name": "Owner", "color": "orange" },
"1": { "name": "Admin", "color": "blueviolet" },
"2": { "name": "User", "color": "blue" },
"3": { "name": "Manager", "color": "green" },
};
2019-01-19 22:12:52 +01:00
$(window).on('load', function () {
$("#invite-form").submit(inviteUser);
$("#config-form").submit(saveConfig);
2019-01-19 22:12:52 +01:00
$("img.identicon").each(function (i, e) {
e.src = identicon(e.dataset.src);
});
$('[data-orgtype]').each(function (i, e) {
let orgtype = OrgTypes[e.dataset.orgtype];
e.style.backgroundColor = orgtype.color;
e.title = orgtype.name;
});
// These are formatted because otherwise the
// VSCode formatter breaks But they still work
// {{#each config}} {{#if grouptoggle}}
masterCheck("#input_{{grouptoggle}}", "#g_{{group}} input");
// {{/if}} {{/each}}
2019-01-19 22:12:52 +01:00
});
</script>