verify.ts 3.0 KB

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