fix table width

more captcha changes
This commit is contained in:
HF 2021-03-08 23:47:44 +01:00
parent 7dd44811a6
commit 1c0b1101b0
10 changed files with 90 additions and 67 deletions

View File

@ -6,3 +6,4 @@ apps:
PORT: 8080
HOST: "localhost"
REDIS_URL: 'redis://localhost:6379'
CAPTCHA_TIMEOUT: 120

View File

@ -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',

View File

@ -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 }) => {
</span>
</p>
<img
style={{width: '75%'}}
style={{ width: '75%' }}
src={captchaUrl}
onError={() => setError(true)}
/>

View File

@ -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';

View File

@ -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`],
});
}
};

View File

@ -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);

View File

@ -24,8 +24,6 @@ const Html = ({
styles,
// code as string
code,
// if recaptcha should get loaded
useCaptcha,
}) => (
<html className="no-js" lang="en">
<head>

View File

@ -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) {

View File

@ -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`,
));

View File

@ -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<boolean> {
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<boolean> {
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;