🔧 improved secret handling

- BulmaSecret automatically returns to "hidden" after 2.5 seconds in "pending"
- ConfigView clears the credential values if not viewed
This commit is contained in:
Jörn-Michael Miehe 2025-12-30 02:31:53 +00:00
parent 8e8e894638
commit 811fec743e
2 changed files with 48 additions and 25 deletions

View file

@ -139,12 +139,15 @@
<dt>Zugangsdaten</dt>
<dd class="is-family-monospace">
<BulmaSecret @load="load_dav_credentials">
<BulmaSecret
@show="load_credentials(creds.dav, 'admin/dav_credentials')"
@hide="clear_credentials(creds.dav)"
>
<span class="tag is-danger">user</span>
{{ dav_credentials[0] }}
{{ creds.dav[0] }}
<br />
<span class="tag is-danger">pass</span>
{{ dav_credentials[1] }}
{{ creds.dav[1] }}
</BulmaSecret>
</dd>
@ -167,12 +170,15 @@
<dt>UI-Admin</dt>
<dd class="is-family-monospace">
<BulmaSecret @load="load_ui_credentials">
<BulmaSecret
@show="load_credentials(creds.ui, 'admin/ui_credentials')"
@hide="clear_credentials(creds.ui)"
>
<span class="tag is-danger">user</span>
{{ ui_credentials[0] }}
{{ creds.ui[0] }}
<br />
<span class="tag is-danger">pass</span>
{{ ui_credentials[1] }}
{{ creds.ui[1] }}
</BulmaSecret>
</dd>
</dl>
@ -237,8 +243,10 @@ const admin_config_model = ref<AdminConfigModel>({
});
const doors = ref<DoorSaved[]>([]);
const dav_credentials = ref<Credentials>(["", ""]);
const ui_credentials = ref<Credentials>(["", ""]);
const creds = ref<Record<string, Credentials>>({
dav: ["", ""],
ui: ["", ""],
});
function fmt_puzzle_date(name: keyof AdminConfigModel["puzzle"]): string {
const iso_date = admin_config_model.value.puzzle[name];
@ -257,22 +265,24 @@ async function on_open(): Promise<void> {
void store_update; // discard value
admin_config_model.value = new_admin_config_model;
doors.value = new_doors;
creds.value = { dav: ["", ""], ui: ["", ""] };
}
async function load_dav_credentials(): Promise<void> {
async function load_credentials(
creds: Credentials,
endpoint: string,
): Promise<void> {
try {
dav_credentials.value = await API.request<Credentials>(
"admin/dav_credentials",
);
const new_creds = await API.request<Credentials>(endpoint);
creds[0] = new_creds[0];
creds[1] = new_creds[1];
} catch {}
}
async function load_ui_credentials(): Promise<void> {
try {
ui_credentials.value = await API.request<Credentials>(
"admin/ui_credentials",
);
} catch {}
function clear_credentials(creds: Credentials): void {
creds[0] = "";
creds[1] = "";
}
</script>

View file

@ -4,8 +4,8 @@
<span v-else>***</span>
<BulmaButton
:class="`is-small is-${record.color} ml-2`"
:icon="['fas', `${record.icon}`]"
:busy="state === 'clicked'"
:icon="['fas', record.icon]"
:busy="state === 'pending'"
@click="on_click"
/>
</template>
@ -16,24 +16,37 @@ import { computed, ref } from "vue";
import BulmaButton from "./Button.vue";
const emit = defineEmits<{
(event: "load"): void;
(event: "show"): void;
(event: "hide"): void;
}>();
type State = "hidden" | "clicked" | "visible";
type State = "hidden" | "pending" | "visible";
const state = ref<State>("hidden");
const state_map: Record<State, { color: string; icon: string; next: State }> = {
hidden: { color: "primary", icon: "eye-slash", next: "clicked" },
clicked: { color: "warning", icon: "eye-slash", next: "visible" },
hidden: { color: "primary", icon: "eye-slash", next: "pending" },
pending: { color: "warning", icon: "eye-slash", next: "visible" },
visible: { color: "danger", icon: "eye", next: "hidden" },
} as const;
const record = computed(() => state_map[state.value] ?? state_map.hidden);
let pending_timeout: number | undefined;
function on_click(): void {
state.value = record.value.next;
if (state.value === "hidden") {
emit("hide");
}
if (state.value === "pending") {
pending_timeout = window.setTimeout(() => (state.value = "hidden"), 2500);
} else {
window.clearTimeout(pending_timeout);
}
if (state.value === "visible") {
emit("load");
emit("show");
}
}
</script>