support 2FA auth

This commit is contained in:
kawamataryo 2024-10-18 09:14:45 +09:00
parent f7e2c58c72
commit 9544a7f67c
4 changed files with 67 additions and 8 deletions

View File

@ -1,24 +1,35 @@
import type { PlasmoMessaging } from "@plasmohq/messaging";
import { BskyClient } from "../../lib/bskyClient";
import { AUTH_FACTOR_TOKEN_REQUIRED_ERROR_MESSAGE } from "~lib/constants";
import { ComAtprotoServerCreateSession } from "@atproto/api";
const handler: PlasmoMessaging.MessageHandler = async (req, res) => {
const { identifier, password } = req.body;
const { identifier, password, authFactorToken } = req.body;
try {
const agent = await BskyClient.createAgent({
identifier,
password,
...(authFactorToken && { authFactorToken: authFactorToken }),
});
res.send({
session: agent.session,
});
} catch (e) {
res.send({
error: {
message: e.message,
},
});
if (e instanceof ComAtprotoServerCreateSession.AuthFactorTokenRequiredError) {
res.send({
error: {
message: AUTH_FACTOR_TOKEN_REQUIRED_ERROR_MESSAGE,
},
});
} else {
res.send({
error: {
message: e.message,
},
});
}
}
};

View File

@ -6,6 +6,7 @@ const clientCache = new Map<string, BskyClient>();
export type BskyLoginParams = {
identifier: string;
password: string;
authFactorToken?: string;
};
export class BskyClient {
@ -49,11 +50,13 @@ export class BskyClient {
public static async createAgent({
identifier,
password,
authFactorToken,
}: BskyLoginParams): Promise<BskyClient> {
const client = new BskyClient();
const { data } = await client.agent.login({
identifier,
password,
...(authFactorToken && { authFactorToken }),
});
client.me = {
did: data.did,

View File

@ -73,3 +73,5 @@ export const MATCH_TYPE_LABEL_AND_COLOR = {
color: "secondary",
},
};
export const AUTH_FACTOR_TOKEN_REQUIRED_ERROR_MESSAGE = "AuthFactorTokenRequiredError";

View File

@ -11,6 +11,7 @@ import {
MESSAGE_TYPE,
STORAGE_KEYS,
TARGET_URLS_REGEX,
AUTH_FACTOR_TOKEN_REQUIRED_ERROR_MESSAGE,
} from "~lib/constants";
function IndexPopup() {
@ -18,6 +19,9 @@ function IndexPopup() {
const [password, setPassword] = useState("");
const [identifier, setIdentifier] = useState("");
const [reloadCount, setReloadCount] = useState(0);
const [authFactorToken, setAuthFactorToken] = useState("");
const [isShowAuthFactorTokenInput, setIsShowAuthFactorTokenInput] =
useState(false);
const [message, setMessage] = useState<null | {
type: (typeof MESSAGE_TYPE)[keyof typeof MESSAGE_TYPE];
message: string;
@ -68,7 +72,7 @@ function IndexPopup() {
if (!Object.values(TARGET_URLS_REGEX).some((r) => r.test(currentUrl))) {
setErrorMessage(
"Error: Invalid page. please open the Twitter following or blocking page.",
"Error: Invalid page. please open the 𝕏 following or blocking or list page.",
);
return;
}
@ -101,10 +105,15 @@ function IndexPopup() {
body: {
identifier: formattedIdentifier,
password,
...(authFactorToken && { authFactorToken: authFactorToken.trim() }),
},
});
if (res.hasError) {
setErrorMessage(res.message);
if (res.message === AUTH_FACTOR_TOKEN_REQUIRED_ERROR_MESSAGE) {
setIsShowAuthFactorTokenInput(true);
} else {
setErrorMessage(res.message);
}
} else {
window.close();
}
@ -210,6 +219,40 @@ function IndexPopup() {
className="input input-bordered input-sm w-full max-w-xs join-item focus:outline-none"
/>
</label>
{isShowAuthFactorTokenInput && (
<>
<label className="join mt-2 w-full" htmlFor="authFactorToken">
<span className="join-item btn btn-sm btn-active cursor-default">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.5 6v.75m0 3v.75m0 3v.75m0 3V18m-9-5.25h5.25M7.5 15h3M3.375 5.25c-.621 0-1.125.504-1.125 1.125v3.026a2.999 2.999 0 0 1 0 5.198v3.026c0 .621.504 1.125 1.125 1.125h17.25c.621 0 1.125-.504 1.125-1.125v-3.026a2.999 2.999 0 0 1 0-5.198V6.375c0-.621-.504-1.125-1.125-1.125H3.375Z"
/>
</svg>
</span>
<input
type="text"
name="authFactorToken"
placeholder="2FA token"
value={authFactorToken}
onChange={(e) => setAuthFactorToken(e.target.value)}
className="input input-bordered input-sm w-full max-w-xs join-item focus:outline-none"
/>
</label>
<p className="mt-2 text-warning">
A 2FA token has been sent to your email. Please enter the token
above.
</p>
</>
)}
<button
type="submit"
className={