|
@@ -2,19 +2,97 @@ import { Request as ExpressRequest, Response as ExpressResponse } from "express"
|
|
|
import { existsSync, promises } from "fs";
|
|
|
import { join } from "path";
|
|
|
import { ENVIRONMENT } from "src/utils/environment";
|
|
|
-import { Option } from "@shared/common/async_utils";
|
|
|
+import { Option, tryDo } from "@shared/common/async_utils";
|
|
|
import { rpcClient } from "src/utils/rpc";
|
|
|
+import got from "got";
|
|
|
+import { logger } from "src/utils/logging";
|
|
|
|
|
|
export interface VerifyInfo {
|
|
|
captchaSitekey: string;
|
|
|
+ userVerified: boolean;
|
|
|
}
|
|
|
|
|
|
+export interface VerifyRequest {
|
|
|
+ captchaResponse: string;
|
|
|
+}
|
|
|
+
|
|
|
+interface HCaptchaResponse {
|
|
|
+ success: boolean;
|
|
|
+ "error-codes"?: string[];
|
|
|
+}
|
|
|
+
|
|
|
+const VERIFY_URL = "https://hcaptcha.com/siteverify";
|
|
|
+
|
|
|
type GetResult = Promise<ExpressResponse<VerifyInfo>>;
|
|
|
-export const get = async (req: ExpressRequest, res: ExpressResponse): GetResult => res.json({
|
|
|
- captchaSitekey: ENVIRONMENT.hCaptchaSitekey,
|
|
|
-});
|
|
|
+export const get = async (req: ExpressRequest, res: ExpressResponse): GetResult => {
|
|
|
+ if (!req.session?.userId) {
|
|
|
+ return res.json({
|
|
|
+ captchaSitekey: ENVIRONMENT.hCaptchaSitekey,
|
|
|
+ userVerified: true,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return res.json({
|
|
|
+ captchaSitekey: ENVIRONMENT.hCaptchaSitekey,
|
|
|
+ userVerified: (await rpcClient.userVerified({ userId: req.session.userId })).verified,
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+type PostResult = Promise<ExpressResponse<Option<unknown, { error: string }>>>;
|
|
|
+export const post = async (req: ExpressRequest, res: ExpressResponse): PostResult => {
|
|
|
+ const hasToken = (body: unknown):
|
|
|
+ body is VerifyRequest => body instanceof Object
|
|
|
+ && (body as VerifyRequest).captchaResponse !== undefined;
|
|
|
+ if (!hasToken(req.body)) {
|
|
|
+ return res.json({
|
|
|
+ ok: false,
|
|
|
+ error: "No user token provided, please try again",
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!req.session?.userId) {
|
|
|
+ return res.json({
|
|
|
+ ok: false,
|
|
|
+ error: "Not logged in, please log in",
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ const response = await tryDo(got<HCaptchaResponse>(VERIFY_URL, {
|
|
|
+ method: "post",
|
|
|
+ responseType: "json",
|
|
|
+ form: {
|
|
|
+ secret: ENVIRONMENT.hCaptchaSecret,
|
|
|
+ response: req.body.captchaResponse,
|
|
|
+ },
|
|
|
+ }));
|
|
|
+
|
|
|
+ if (!response.ok) {
|
|
|
+ logger.error("Failed to hCaptcha user %s: %s", req.session.userId, response.error);
|
|
|
+ return res.json({
|
|
|
+ ok: false,
|
|
|
+ error: "Failed to verify hCaptcha response. Please try again.",
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ const captchaResponse = response.result.body;
|
|
|
|
|
|
-// type PostResult = Promise<ExpressResponse<Option<unknown, { error: string }>>>;
|
|
|
-// export const post = async (req: ExpressRequest, res: ExpressResponse): PostResult => {
|
|
|
+ if (!captchaResponse.success) {
|
|
|
+ const errors = captchaResponse["error-codes"] ?? [];
|
|
|
+ logger.error("Failed hCaptcha verify on user %s. Got errors: %s", req.session.userId, errors.join(";"));
|
|
|
+ return res.json({
|
|
|
+ ok: false,
|
|
|
+ error: "Failed to verify hCaptcha response. Please try again.",
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
-// };
|
|
|
+ const verifyResponse = await rpcClient.verifyUser({ userId: req.session.userId });
|
|
|
+ if (!verifyResponse.ok) {
|
|
|
+ logger.error("Failed to verify user %s (%s)", req.session.userId, req.session.username);
|
|
|
+ return res.json({
|
|
|
+ ok: false,
|
|
|
+ error: "Failed to verify your account. Please try again or contact server owners.",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return res.json({
|
|
|
+ ok: true,
|
|
|
+ });
|
|
|
+};
|