verify.ts 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import { Request as ExpressRequest, Response as ExpressResponse } from "express";
  2. import { existsSync, promises } from "fs";
  3. import { join } from "path";
  4. import { ENVIRONMENT } from "src/utils/environment";
  5. import { Option, tryDo } from "@shared/common/async_utils";
  6. import { rpcClient } from "src/utils/rpc";
  7. import got from "got";
  8. import { logger } from "src/utils/logging";
  9. export interface VerifyInfo {
  10. captchaSitekey: string;
  11. userVerified: boolean;
  12. }
  13. export interface VerifyRequest {
  14. captchaResponse: string;
  15. }
  16. interface HCaptchaResponse {
  17. success: boolean;
  18. "error-codes"?: string[];
  19. }
  20. const VERIFY_URL = "https://hcaptcha.com/siteverify";
  21. type GetResult = Promise<ExpressResponse<VerifyInfo>>;
  22. export const get = async (req: ExpressRequest, res: ExpressResponse): GetResult => {
  23. if (!req.session?.userId) {
  24. return res.json({
  25. captchaSitekey: ENVIRONMENT.hCaptchaSitekey,
  26. userVerified: true,
  27. });
  28. }
  29. return res.json({
  30. captchaSitekey: ENVIRONMENT.hCaptchaSitekey,
  31. userVerified: (await rpcClient.userVerified({ userId: req.session.userId })).verified,
  32. });
  33. };
  34. type PostResult = Promise<ExpressResponse<Option<unknown, { error: string }>>>;
  35. export const post = async (req: ExpressRequest, res: ExpressResponse): PostResult => {
  36. const hasToken = (body: unknown):
  37. body is VerifyRequest => body instanceof Object
  38. && (body as VerifyRequest).captchaResponse !== undefined;
  39. if (!hasToken(req.body)) {
  40. return res.json({
  41. ok: false,
  42. error: "No user token provided, please try again",
  43. });
  44. }
  45. if (!req.session?.userId) {
  46. return res.json({
  47. ok: false,
  48. error: "Not logged in, please log in",
  49. });
  50. }
  51. const response = await tryDo(got<HCaptchaResponse>(VERIFY_URL, {
  52. method: "post",
  53. responseType: "json",
  54. form: {
  55. secret: ENVIRONMENT.hCaptchaSecret,
  56. response: req.body.captchaResponse,
  57. },
  58. }));
  59. if (!response.ok) {
  60. logger.error("Failed to hCaptcha user %s: %s", req.session.userId, response.error);
  61. return res.json({
  62. ok: false,
  63. error: "Failed to verify hCaptcha response. Please try again.",
  64. });
  65. }
  66. const captchaResponse = response.result.body;
  67. if (!captchaResponse.success) {
  68. const errors = captchaResponse["error-codes"] ?? [];
  69. logger.error("Failed hCaptcha verify on user %s. Got errors: %s", req.session.userId, errors.join(";"));
  70. return res.json({
  71. ok: false,
  72. error: "Failed to verify hCaptcha response. Please try again.",
  73. });
  74. }
  75. const verifyResponse = await rpcClient.verifyUser({ userId: req.session.userId });
  76. if (!verifyResponse.ok) {
  77. logger.error("Failed to verify user %s (%s)", req.session.userId, req.session.username);
  78. return res.json({
  79. ok: false,
  80. error: "Failed to verify your account. Please try again or contact server owners.",
  81. });
  82. }
  83. return res.json({
  84. ok: true,
  85. });
  86. };