mirror of
https://github.com/lifegpc/eh-downloader.git
synced 2026-06-06 05:38:44 +08:00
101 lines
3.6 KiB
TypeScript
101 lines
3.6 KiB
TypeScript
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 { encodeBase64 as encode } from "std/encoding/base64.ts";
|
|
import { UserAgent } from "std/http/user_agent.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");
|
|
if (document.location.protocol === "https:") {
|
|
b.append("secure", "1");
|
|
}
|
|
b.append("client", "fresh");
|
|
b.append("client_version", "0.0.1");
|
|
b.append("client_platform", "web");
|
|
const ua = new UserAgent(navigator.userAgent);
|
|
let name = ua.browser.name;
|
|
if (name && ua.browser.version) {
|
|
name += " " + ua.browser.version;
|
|
}
|
|
if (name) {
|
|
b.append("device", name);
|
|
}
|
|
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>
|
|
);
|
|
}
|
|
}
|