Improve captcha (#7138)
This commit is contained in:
parent
41d7515f85
commit
0e45f10d99
|
@ -152,7 +152,6 @@
|
||||||
"gulp-tslint": "8.1.4",
|
"gulp-tslint": "8.1.4",
|
||||||
"gulp-typescript": "6.0.0-alpha.1",
|
"gulp-typescript": "6.0.0-alpha.1",
|
||||||
"hard-source-webpack-plugin": "0.13.1",
|
"hard-source-webpack-plugin": "0.13.1",
|
||||||
"hcaptcha": "0.0.2",
|
|
||||||
"html-minifier": "4.0.0",
|
"html-minifier": "4.0.0",
|
||||||
"http-proxy-agent": "4.0.1",
|
"http-proxy-agent": "4.0.1",
|
||||||
"http-signature": "1.3.5",
|
"http-signature": "1.3.5",
|
||||||
|
@ -208,7 +207,6 @@
|
||||||
"random-seed": "0.3.0",
|
"random-seed": "0.3.0",
|
||||||
"ratelimiter": "3.4.1",
|
"ratelimiter": "3.4.1",
|
||||||
"re2": "1.15.9",
|
"re2": "1.15.9",
|
||||||
"recaptcha-promise": "1.0.0",
|
|
||||||
"reconnecting-websocket": "4.4.0",
|
"reconnecting-websocket": "4.4.0",
|
||||||
"redis": "3.0.2",
|
"redis": "3.0.2",
|
||||||
"redis-lock": "0.1.4",
|
"redis-lock": "0.1.4",
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
declare module 'recaptcha-promise' {
|
|
||||||
interface IVerifyOptions {
|
|
||||||
secret_key?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IVerify {
|
|
||||||
(response: string, remoteAddress?: string): Promise<boolean>;
|
|
||||||
init(options: IVerifyOptions): IVerify;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace recaptchaPromise {} // Hack
|
|
||||||
|
|
||||||
const verify: IVerify;
|
|
||||||
|
|
||||||
export = verify;
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { URLSearchParams } from 'url';
|
||||||
|
import { getAgentByUrl } from './fetch';
|
||||||
|
import config from '../config';
|
||||||
|
|
||||||
|
export async function verifyRecaptcha(secret: string, response: string) {
|
||||||
|
const result = await getCaptchaResponse('https://www.recaptcha.net/recaptcha/api/siteverify', secret, response).catch(e => {
|
||||||
|
throw `recaptcha-request-failed: ${e}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.success !== true) {
|
||||||
|
const errorCodes = result['error-codes'] ? result['error-codes']?.join(', ') : '';
|
||||||
|
throw `recaptcha-failed: ${errorCodes}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function verifyHcaptcha(secret: string, response: string) {
|
||||||
|
const result = await getCaptchaResponse('https://hcaptcha.com/siteverify', secret, response).catch(e => {
|
||||||
|
throw `hcaptcha-request-failed: ${e}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.success !== true) {
|
||||||
|
const errorCodes = result['error-codes'] ? result['error-codes']?.join(', ') : '';
|
||||||
|
throw `hcaptcha-failed: ${errorCodes}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaptchaResponse = {
|
||||||
|
success: boolean;
|
||||||
|
'error-codes'?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getCaptchaResponse(url: string, secret: string, response: string): Promise<CaptchaResponse> {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
secret,
|
||||||
|
response
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await fetch(url, {
|
||||||
|
method: 'POST',
|
||||||
|
body: params,
|
||||||
|
headers: {
|
||||||
|
'User-Agent': config.userAgent
|
||||||
|
},
|
||||||
|
timeout: 10 * 1000,
|
||||||
|
agent: getAgentByUrl
|
||||||
|
}).catch(e => {
|
||||||
|
throw `${e.message || e}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw `${res.status}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await res.json() as CaptchaResponse;
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
import * as Koa from 'koa';
|
import * as Koa from 'koa';
|
||||||
import { fetchMeta } from '../../../misc/fetch-meta';
|
import { fetchMeta } from '../../../misc/fetch-meta';
|
||||||
import { verify } from 'hcaptcha';
|
import { verifyHcaptcha, verifyRecaptcha } from '../../../misc/captcha';
|
||||||
import * as recaptcha from 'recaptcha-promise';
|
|
||||||
import { Users, RegistrationTickets } from '../../../models';
|
import { Users, RegistrationTickets } from '../../../models';
|
||||||
import { signup } from '../common/signup';
|
import { signup } from '../common/signup';
|
||||||
|
|
||||||
|
@ -14,26 +13,15 @@ export default async (ctx: Koa.Context) => {
|
||||||
// ただしテスト時はこの機構は障害となるため無効にする
|
// ただしテスト時はこの機構は障害となるため無効にする
|
||||||
if (process.env.NODE_ENV !== 'test') {
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
if (instance.enableHcaptcha && instance.hcaptchaSecretKey) {
|
if (instance.enableHcaptcha && instance.hcaptchaSecretKey) {
|
||||||
const success = await verify(instance.hcaptchaSecretKey, body['hcaptcha-response']).then(
|
await verifyHcaptcha(instance.hcaptchaSecretKey, body['hcaptcha-response']).catch(e => {
|
||||||
({ success }) => success,
|
ctx.throw(400, e);
|
||||||
() => false,
|
});
|
||||||
);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
ctx.throw(400, 'hcaptcha-failed');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instance.enableRecaptcha && instance.recaptchaSecretKey) {
|
if (instance.enableRecaptcha && instance.recaptchaSecretKey) {
|
||||||
recaptcha.init({
|
await verifyRecaptcha(instance.recaptchaSecretKey, body['g-recaptcha-response']).catch(e => {
|
||||||
secret_key: instance.recaptchaSecretKey
|
ctx.throw(400, e);
|
||||||
});
|
});
|
||||||
|
|
||||||
const success = await recaptcha(body['g-recaptcha-response']);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
ctx.throw(400, 'recaptcha-failed');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
yarn.lock
24
yarn.lock
|
@ -1773,13 +1773,6 @@ aws4@^1.8.0:
|
||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
|
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
|
||||||
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
|
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
|
||||||
|
|
||||||
axios@^0.20.0:
|
|
||||||
version "0.20.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd"
|
|
||||||
integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==
|
|
||||||
dependencies:
|
|
||||||
follow-redirects "^1.10.0"
|
|
||||||
|
|
||||||
bach@^1.0.0:
|
bach@^1.0.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880"
|
resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880"
|
||||||
|
@ -4275,11 +4268,6 @@ flush-write-stream@^1.0.2:
|
||||||
inherits "^2.0.3"
|
inherits "^2.0.3"
|
||||||
readable-stream "^2.3.6"
|
readable-stream "^2.3.6"
|
||||||
|
|
||||||
follow-redirects@^1.10.0:
|
|
||||||
version "1.13.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db"
|
|
||||||
integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==
|
|
||||||
|
|
||||||
for-in@^1.0.1, for-in@^1.0.2:
|
for-in@^1.0.1, for-in@^1.0.2:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||||
|
@ -4825,11 +4813,6 @@ hash-sum@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
|
resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a"
|
||||||
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
|
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
|
||||||
|
|
||||||
hcaptcha@0.0.2:
|
|
||||||
version "0.0.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/hcaptcha/-/hcaptcha-0.0.2.tgz#18f4c055a2315db9f732ac77f9d0e30026bb2eb7"
|
|
||||||
integrity sha512-wWOncj/sY+q8s7tV12tjn3cFNoQhSu3l/7nTJi4QkFKALQi9XnduoXrV/KFzLg5lnB+5560zSAoi9YdYPDw6Eg==
|
|
||||||
|
|
||||||
he@1.2.0, he@^1.2.0:
|
he@1.2.0, he@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
|
||||||
|
@ -8701,13 +8684,6 @@ readdirp@~3.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch "^2.0.7"
|
picomatch "^2.0.7"
|
||||||
|
|
||||||
recaptcha-promise@1.0.0:
|
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/recaptcha-promise/-/recaptcha-promise-1.0.0.tgz#df16f208197fbfd571950cfb32ec3160e3909e0f"
|
|
||||||
integrity sha512-aiJNjKa13YqjF0QmiBUSFpUHjgjJAkRGBndbhHUrwyaxpGdzTxnsLlVEKZvh0gj75AJ/H8H6Bn9qCs8fVc3X1g==
|
|
||||||
dependencies:
|
|
||||||
axios "^0.20.0"
|
|
||||||
|
|
||||||
rechoir@^0.6.2:
|
rechoir@^0.6.2:
|
||||||
version "0.6.2"
|
version "0.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
|
||||||
|
|
Loading…
Reference in New Issue