From 1c0b1101b037d4c91a63b95aa24717385a57a2e4 Mon Sep 17 00:00:00 2001
From: HF
Date: Mon, 8 Mar 2021 23:47:44 +0100
Subject: [PATCH] fix table width more captcha changes
---
deployment/example-ecosystem-captchas.yml | 1 +
src/captchaserver.js | 9 ++-
src/components/Captcha.jsx | 7 ++-
src/core/config.js | 2 +
src/routes/api/captcha.js | 53 +++++++++--------
src/routes/api/index.js | 10 ++--
src/ssr-components/Html.jsx | 2 -
src/styles/default.css | 2 +
src/ui/placePixel.js | 2 +-
src/utils/captcha.js | 69 +++++++++++------------
10 files changed, 90 insertions(+), 67 deletions(-)
diff --git a/deployment/example-ecosystem-captchas.yml b/deployment/example-ecosystem-captchas.yml
index f98120f5..f89f7b91 100644
--- a/deployment/example-ecosystem-captchas.yml
+++ b/deployment/example-ecosystem-captchas.yml
@@ -6,3 +6,4 @@ apps:
PORT: 8080
HOST: "localhost"
REDIS_URL: 'redis://localhost:6379'
+ CAPTCHA_TIMEOUT: 120
diff --git a/src/captchaserver.js b/src/captchaserver.js
index 1ea20a15..e13916e8 100644
--- a/src/captchaserver.js
+++ b/src/captchaserver.js
@@ -8,6 +8,9 @@ import process from 'process';
import http from 'http';
import ppfunCaptcha from 'ppfun-captcha';
+import { getIPFromRequest } from './utils/ip';
+import { setCaptchaSolution } from './utils/captcha';
+
const PORT = process.env.PORT || 8080;
const HOST = process.env.HOST || 'localhost';
@@ -22,8 +25,12 @@ const server = http.createServer((req, res) => {
nodeDeviation: 0.5,
connectionPathDeviation: 0.3,
});
- const ip = req.headers['x-real-ip'] || req.connection.remoteAddress;
+
+ const ip = getIPFromRequest(req);
+
+ setCaptchaSolution(captcha.text, ip);
console.log(`Serving ${captcha.text} to ${ip}`);
+
res.writeHead(200, {
'Content-Type': 'image/svg+xml',
'Cache-Control': 'no-cache',
diff --git a/src/components/Captcha.jsx b/src/components/Captcha.jsx
index 73c2a5c8..f442b8be 100644
--- a/src/components/Captcha.jsx
+++ b/src/components/Captcha.jsx
@@ -1,4 +1,8 @@
/*
+ * Form to ask for captcha.
+ * If callback is provided, it sets the captcha text to it.
+ * If callback is not provided, it provides a button to send the
+ * captcha itself
* @flow
*/
@@ -6,6 +10,7 @@ import React, { useState } from 'react';
import { t } from 'ttag';
import { IoReloadCircleSharp } from 'react-icons/io5';
+import { requestSolveCaptcha } from '../actions/fetch';
function getUrl() {
return `${window.ssv.captchaurl}/captcha.svg?${new Date().getTime()}`;
@@ -25,7 +30,7 @@ const Captcha = ({ callback, cancel }) => {
setError(true)}
/>
diff --git a/src/core/config.js b/src/core/config.js
index 521ab2db..f79d6d26 100644
--- a/src/core/config.js
+++ b/src/core/config.js
@@ -90,5 +90,7 @@ export const auth = {
// time on which to display captcha in minutes
export const CAPTCHA_TIME = parseInt(process.env.CAPTCHA_TIME, 10) || 30;
+// time during which the user can solve a captcha in seconds
+export const CAPTCHA_TIMEOUT = parseInt(process.env.CAPTCHA_TIMEOUT, 10) || 120;
export const SESSION_SECRET = process.env.SESSION_SECRET || 'dummy';
diff --git a/src/routes/api/captcha.js b/src/routes/api/captcha.js
index 45ab8b36..dfecc54b 100644
--- a/src/routes/api/captcha.js
+++ b/src/routes/api/captcha.js
@@ -8,42 +8,51 @@
import type { Request, Response } from 'express';
import logger from '../../core/logger';
-import { verifyCaptcha } from '../../utils/captcha';
+import { checkCaptchaSolution } from '../../utils/captcha';
import { getIPFromRequest } from '../../utils/ip';
export default async (req: Request, res: Response) => {
const ip = getIPFromRequest(req);
+ const { t } = req.ttag;
try {
- const { token } = req.body;
- if (!token) {
+ const { text } = req.body;
+ if (!text) {
res.status(400)
- .json({ errors: [{ msg: 'No token given' }] });
+ .json({ errors: [t`No captcha text given`] });
return;
}
- if (!await verifyCaptcha(token, ip)) {
- logger.info(`CAPTCHA ${ip} failed his captcha`);
- res.status(422)
- .json({
- errors: [{
- msg:
- 'You failed your captcha',
- }],
- });
- return;
- }
+ const ret = await checkCaptchaSolution(text, ip);
- res.status(200)
- .json({ success: true });
+ switch (ret) {
+ case 0:
+ res.status(200)
+ .json({ success: true });
+ break;
+ case 1:
+ res.status(422)
+ .json({
+ errors: [t`You took too long, try again.`],
+ });
+ break;
+ case 2:
+ res.status(422)
+ .json({
+ errors: [t`You failed your captcha`],
+ });
+ break;
+ default:
+ res.status(422)
+ .json({
+ errors: [t`Unknown Captcha Error`],
+ });
+ }
} catch (error) {
- logger.error('checkHuman', error);
+ logger.error('CAPTCHA', error);
res.status(500)
.json({
- errors: [{
- msg:
- 'Server error occured',
- }],
+ errors: [t`Server error occured`],
});
}
};
diff --git a/src/routes/api/index.js b/src/routes/api/index.js
index a378bc06..fefaa8d2 100644
--- a/src/routes/api/index.js
+++ b/src/routes/api/index.js
@@ -44,6 +44,11 @@ router.use((err, req, res, next) => {
}
});
+/*
+ * make localisations available
+ */
+router.use(expressTTag);
+
// captcah doesn't need a user
router.post('/captcha', captcha);
@@ -89,11 +94,6 @@ router.post('/block', block);
router.post('/blockdm', blockdm);
-/*
- * make localisations available
- */
-router.use(expressTTag);
-
router.get('/chathistory', chatHistory);
router.get('/me', me);
diff --git a/src/ssr-components/Html.jsx b/src/ssr-components/Html.jsx
index 02e3b7e7..4f7b142b 100644
--- a/src/ssr-components/Html.jsx
+++ b/src/ssr-components/Html.jsx
@@ -24,8 +24,6 @@ const Html = ({
styles,
// code as string
code,
- // if recaptcha should get loaded
- useCaptcha,
}) => (
diff --git a/src/styles/default.css b/src/styles/default.css
index 97318f5f..192cb2ba 100644
--- a/src/styles/default.css
+++ b/src/styles/default.css
@@ -112,6 +112,8 @@ td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
+ max-width: 18em;
+ overflow-x: hidden;
}
tr:nth-child(even) {
diff --git a/src/ui/placePixel.js b/src/ui/placePixel.js
index 200d711e..61d5943d 100644
--- a/src/ui/placePixel.js
+++ b/src/ui/placePixel.js
@@ -241,7 +241,7 @@ export function receivePixelReturn(
case 10:
store.dispatch(sweetAlert(
'Captcha',
- `Please prove that you are human..`,
+ t`Please prove that you are human`,
'captcha',
t`OK`,
));
diff --git a/src/utils/captcha.js b/src/utils/captcha.js
index bc74fe36..3e62c14c 100644
--- a/src/utils/captcha.js
+++ b/src/utils/captcha.js
@@ -5,58 +5,60 @@
import logger from '../core/logger';
import redis from '../data/redis';
-
+import { getIPv6Subnet } from './ip';
import {
CAPTCHA_URL,
CAPTCHA_TIME,
+ CAPTCHA_TIMEOUT,
} from '../core/config';
const TTL_CACHE = CAPTCHA_TIME * 60; // seconds
/*
- * https://docs.hcaptcha.com/
+ * set captcha solution
*
- * @param token
+ * @param text Solution of captcha
* @param ip
- * @return boolean, true if successful, false on error or fail
+ * @param ttl time to be valid in seconds
*/
-async function verifyHCaptcha(
- token: string,
+export function setCaptchaSolution(
+ text: string,
ip: string,
-): Promise {
- const success = true;
- if (success) {
- logger.info(`CAPTCHA ${ip} successfully solved captcha`);
- return true;
- }
- logger.info(`CAPTCHA Token for ${ip} not ok`);
- return false;
+) {
+ const key = `capt:${getIPv6Subnet(ip)}`;
+ return redis.setAsync(key, text, 'EX', CAPTCHA_TIMEOUT);
}
/*
- * verify captcha token from client
+ * check captcha solution
*
- * @param token token of solved captcha from client
+ * @param text Solution of captcha
* @param ip
- * @returns Boolean if successful
+ * @return 0 if solution right
+ * 1 if timed out
+ * 2 if wrong
*/
-export async function verifyCaptcha(
- token: string,
+export async function checkCaptchaSolution(
+ text: string,
ip: string,
-): Promise {
- try {
- const key = `human:${ip}`;
-
- if (!await verifyHCaptcha(token, ip)) {
- return false;
+) {
+ const ipn = getIPv6Subnet(ip);
+ const key = `capt:${ipn}`;
+ const solution = await redis.getAsync(key);
+ if (solution) {
+ if (solution.toString('utf8') === text) {
+ const solvkey = `human:${ipn}`;
+ await redis.setAsync(solvkey, '', 'EX', TTL_CACHE);
+ logger.info(`CAPTCHA ${ip} successfully solved captcha`);
+ return 0;
}
-
- await redis.setAsync(key, '', 'EX', TTL_CACHE);
- return true;
- } catch (error) {
- logger.error(error);
+ logger.info(
+ `CAPTCHA ${ip} got captcha wrong (${text} instead of ${solution})`,
+ );
+ return 2;
}
- return false;
+ logger.info(`CAPTCHA ${ip} timed out`);
+ return 1;
}
/*
@@ -70,7 +72,7 @@ export async function needCaptcha(ip: string) {
return false;
}
- const key = `human:${ip}`;
+ const key = `human:${getIPv6Subnet(ip)}`;
const ttl: number = await redis.ttlAsync(key);
if (ttl > 0) {
return false;
@@ -78,6 +80,3 @@ export async function needCaptcha(ip: string) {
logger.info(`CAPTCHA ${ip} got captcha`);
return true;
}
-
-
-export default verifyCaptcha;