Add Login page

This commit is contained in:
2023-07-15 15:02:03 +08:00
parent 0519334686
commit a573d60191
3 changed files with 89 additions and 2 deletions

85
components/Login.tsx Normal file
View File

@@ -0,0 +1,85 @@
import { Component, ContextType } from "preact";
import { GlobalCtx } from "./GlobalContext.tsx";
import BMd3TextField from "./BMd3TextField.tsx";
import t from "../server/i18n.ts";
import { useState } from "preact/hooks";
import { MdTonalButton } from "../server/dmodule.ts";
import { set_state } from "../server/state.ts";
import pbkdf2Hmac from "pbkdf2-hmac/?target=es2022";
import { encode } from "std/encoding/base64.ts";
type Props = {
show: boolean;
};
export default class Login extends Component<Props> {
static contextType = GlobalCtx;
declare context: ContextType<typeof GlobalCtx>;
render() {
if (!this.props.show) return null;
if (!MdTonalButton.value) return null;
const [username, set_username] = useState<string>();
const [password, set_password] = useState<string>();
const [disabled, set_disabled] = useState(false);
const login = async (username: string, password: string) => {
set_disabled(true);
const b = new URLSearchParams();
b.append("username", username);
const p = new Uint8Array(
await pbkdf2Hmac(
password,
"eh-downloader-salt",
210000,
64,
"SHA-512",
),
);
const t = (new Date()).getTime();
const p2 = encode(
new Uint8Array(
await pbkdf2Hmac(p, t.toString(), 1000, 64, "SHA-512"),
),
);
b.append("password", p2);
b.append("t", t.toString());
b.append("set_cookie", "1");
const re2 = await fetch("/api/token", { method: "PUT", body: b });
const token = await re2.json();
if (!token.ok) {
throw Error(token.error);
}
};
const Button = MdTonalButton.value;
return (
<div>
<BMd3TextField
label={t("user.username")}
type="text"
value={username}
set_value={set_username}
/>
<BMd3TextField
label={t("user.password")}
type="password"
value={password}
set_value={set_password}
/>
<Button
disabled={disabled || !username || !password}
onClick={() => {
if (!username || !password) return;
login(username, password).then(() => {
set_disabled(false);
set_state("#/");
}).catch((e) => {
console.error(e);
set_disabled(false);
});
}}
>
{t("user.login")}
</Button>
</div>
);
}
}

View File

@@ -18,6 +18,7 @@ import { initCfg } from "../server/cfg.ts";
import { load_dmodule } from "../server/dmodule.ts";
import CreateRootUser from "../components/CreateRootUser.tsx";
import { check_auth_status } from "../server/auth.ts";
import Login from "../components/Login.tsx";
export type ContainerProps = {
i18n: I18NMap;
@@ -108,6 +109,7 @@ export default class Container extends Component<ContainerProps> {
/>
<NewTask show={state === "#/task_manager/new"} />
<CreateRootUser show={state === "#/create_root_user"} />
<Login show={state === "#/login"} />
</div>
);
}

View File

@@ -8,7 +8,7 @@ export async function check_auth_status() {
const re = await fetch("/api/user");
const u: JSONResult<BUser> = await re.json();
if (u.ok) return true;
if (u.status !== 404 && u.status !== 1) {
if (u.status !== 404 && u.status !== 1 && u.status !== 401) {
throw Error(u.error);
}
const re2 = await fetch("/api/status");
@@ -20,5 +20,5 @@ export async function check_auth_status() {
if (!parse_bool(localStorage.getItem("skip_create_root_user"), false)) {
set_state("#/create_root_user");
}
}
} else set_state("#/login");
}