Commit 19fae3d9 authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

Merge branch '1208-include-audiocaptcha' into 'development'

Resolve "Include Audiocaptcha"

Closes #1208

See merge request !1992
parents 474637c8 28bc7370
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class TruncateLogs extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'logs:truncate';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Truncates Logs that should only be kept for a day';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$log_files = [
\storage_path("logs/metager/bv_fail.csv"),
\storage_path("logs/metager/captcha_show.csv"),
\storage_path("logs/metager/captcha_solve.csv"),
];
foreach ($log_files as $log_file) {
if (\file_exists($log_file) && \is_writable($log_file)) {
$fp = fopen($log_file, "r+");
try {
ftruncate($fp, 0);
} finally {
fclose($fp);
}
}
}
return 0;
}
}
......@@ -20,6 +20,7 @@ class Kernel extends ConsoleKernel
$schedule->command('requests:gather')->everyFifteenMinutes();
$schedule->command('requests:useragents')->everyFiveMinutes();
$schedule->command('logs:gather')->everyMinute();
$schedule->command('logs:truncate')->daily()->onOneServer();
$schedule->command('spam:load')->everyMinute();
$schedule->command('load:affiliate-blacklist')->everyMinute();
$schedule->command('affilliates:store')->everyMinute()
......
......@@ -4,15 +4,17 @@ namespace App\Http\Controllers;
use App\Models\Verification\CookieVerification;
use App\Models\Verification\HumanVerification as ModelsHumanVerification;
use Captcha;
use App\Models\Verification\Captcha;
use Carbon;
use Cookie;
use Crypt;
use Illuminate\Hashing\BcryptHasher as Hasher;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Input;
use Laravel\SerializableClosure\Signers\Hmac;
use LaravelLocalization;
class HumanVerification extends Controller
{
......@@ -39,13 +41,27 @@ class HumanVerification extends Controller
return redirect($redirect_url);
}
$captcha = Captcha::create("default", true);
$captcha = new Captcha(
app('Illuminate\Filesystem\Filesystem'),
app('Illuminate\Contracts\Config\Repository'),
app('Intervention\Image\ImageManager'),
app('Illuminate\Session\Store'),
app('Illuminate\Hashing\BcryptHasher'),
app('Illuminate\Support\Str')
);
$captcha_key = $captcha->create('default', true);
// Extract the correct solution to this captcha for generating the Audio Captcha
$text = implode(" ", $captcha->getText());
$tts_url = TTSController::CreateTTSUrl($text, LaravelLocalization::getCurrentLocale());
\App\PrometheusExporter::CaptchaShown();
return view('humanverification.captcha')->with('title', 'Bestätigung notwendig')
->with('url', $redirect_url)
->with('correct', $captcha["key"])
->with('image', $captcha["img"])
->with('correct', $captcha_key["key"])
->with('image', $captcha_key["img"])
->with('tts_url', $tts_url)
->with('css', [mix('css/verify/index.css')]);
}
......@@ -97,6 +113,20 @@ class HumanVerification extends Controller
$params = array();
}
$query = isset($params["eingabe"]) ? $params["eingabe"] : "";
$time = 0;
if ($request->filled("begin")) {
$time = $request->input("begin");
$time = \filter_var($time, \FILTER_VALIDATE_FLOAT);
if ($time === false) {
$time = 0;
} else {
$time = microtime(true) - $time;
}
}
self::logCaptchaSolve($query, $time, $request->has("dnaa"));
$params['token'] = $token; // Overwrite if exists
// Note that this will url_encode all values
......@@ -115,6 +145,23 @@ class HumanVerification extends Controller
}
}
private static function logCaptchaSolve(string $query, float $time, bool $dnaa = false)
{
$log = [
now()->format("Y-m-d H:i:s"),
$query,
"time=" . $time,
"dnaa=" . var_export($dnaa, true)
];
$file_path = \storage_path("logs/metager/captcha_solve.csv");
$fh = fopen($file_path, "a");
try {
\fputcsv($fh, $log);
} finally {
fclose($fh);
}
}
public static function logCaptcha(Request $request)
{
$fail2banEnabled = config("metager.metager.fail2ban.enabled");
......
<?php
namespace App\Http\Controllers;
use Crypt;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Http\Request;
class TTSController extends Controller
{
public function tts(Request $request)
{
$text_params = $request->input("text", "");
try {
$text_params = Crypt::decrypt($text_params);
} catch (DecryptException $exception) {
abort(404);
}
$text = $text_params["text"];
$locale = $text_params["locale"];
$voices = [
"de" => "bits1-hsmm",
"en_GB" => "dfki-prudence-hsmm",
];
$mary_tts_params = [
"INPUT_TEXT" => $text,
"INPUT_TYPE" => "TEXT",
"OUTPUT_TYPE" => "AUDIO",
"AUDIO" => "WAVE_FILE",
"LOCALE" => $locale,
"VOICE" => $voices[$locale]
];
$mary_tts_url = config("metager.metager.tts.base_url");
if (empty($mary_tts_url)) {
abort(404);
}
$get_params = \http_build_query($mary_tts_params, "", "&", PHP_QUERY_RFC1738);
$mary_tts_url .= "/process?" . $get_params;
$content = \file_get_contents($mary_tts_url);
return response($content, 200, [
"Content-Type" => "audio/x-wav",
"Pragma" => "no-cache",
"Cache-Control" => "no-cache, no-store, must-revalidate",
"Content-Length" => strlen($content),
]);
}
/**
* Generates a URL for transforming given text into
* speech in given locale
*
* @param $text The Text to convert to speech
* @param $locale The Locale of the speech (only "de" and "en" supported currently; fallback is en)
*/
public static function CreateTTSUrl(string $text, string $locale = "en_GB")
{
$supported_locales = [
"de" => "de",
"en" => "en_GB"
];
$text_param = [
"text" => $text,
"locale" => in_array($locale, array_keys($supported_locales)) ? $supported_locales[$locale] : "en_GB",
];
$text_param = Crypt::encrypt($text_param);
$url = route("tts", ["text" => $text_param]);
return $url;
}
}
......@@ -94,7 +94,6 @@ class HumanVerification
return $next($request);
}
// TODO remove function
private function logCaptcha(\Illuminate\Http\Request $request)
{
$log = [
......@@ -102,13 +101,12 @@ class HumanVerification
$request->input("eingabe"),
"js=" . \app()->make(SearchSettings::class)->javascript_enabled,
];
$file_path = \storage_path("logs/metager/captcha.csv");
$file_path = \storage_path("logs/metager/captcha_show.csv");
$fh = fopen($file_path, "a");
try {
\fputcsv($fh, $log);
} finally {
fclose($fh);
}
// Temporary Log to test new functionality. Will be removed again soon
}
}
<?php
namespace App\Models\Verification;
use Mews\Captcha\Captcha as MewsCaptcha;
class Captcha extends MewsCaptcha
{
public function getText()
{
return $this->text;
}
}
......@@ -2,7 +2,7 @@
return [
'characters' => '2346789abcdefghjmnpqrtuxyzABCDEFGHJMNPQRTUXYZ',
'characters' => '2346789abcdefgjnpqrtuxyzABCDEFGJNPQRTUXYZ',
'default' => [
'bgImage' => true,
......
......@@ -17,6 +17,9 @@ return [
"assoziator" => env("ASSO_KEY"),
"berlin" => env("berlin"),
],
"tts" => [
"base_url" => env("TTS_BASE_URL", ""),
],
"fetcher" => [
"proxy" => [
"host" => env("PROXY_HOST", ""),
......
<?php
return [
'1' => 'Sicherheitsabfrage',
'2' => 'Bitte geben Sie die 5 Zeichen aus dem Bild in die Eingabebox und bestätigen Sie mit "OK" um zur Ergebnisseite zu gelangen.',
'2' => 'Bitte geben Sie die 5 Zeichen aus dem Bild oder dem Audioplayer in die Eingabebox ein und bestätigen Sie mit "OK" um zur Ergebnisseite zu gelangen.',
'3' => 'Captcha eingeben',
'4' => 'Auf diesem Gerät nicht erneut fragen (optional; setzt einen Cookie)',
'5' => 'Neues Captcha generieren'
];
<?php
return [
'1' => 'Sorry to bother you',
'2' => 'Please enter the five characters from the picture in the input box and confirm with "OK" to get to the result page.',
'2' => 'Please enter the five characters from the picture or the audioplayer into the input field and confirm with "OK" to get to the result page.',
'3' => 'Enter captcha',
'4' => 'Do not ask again on this device (optional; sets a cookie)',
'5' => 'Generate a new captcha'
];
<?php
return [
'1' => 'Perdon por la molestia',
'2' => 'Ingrese los cinco caracteres de la imagen en el cuadro de entrada y confirme con "OK" para llegar a la página de resultados.',
'2' => 'Introduzca los cinco caracteres de la imagen o del reproductor de audio en el campo de entrada y confirme con "OK" para llegar a la página de resultados.',
'3' => 'Entrar en captcha',
'4' => 'No volver a preguntar en este dispositivo (opcional, establece una cookie)',
'5' => 'Generar un nuevo Captcha'
];
#captcha-container {
display: flex;
justify-content: center;
margin-bottom: 2rem;
flex-direction: column;
margin-bottom: .5rem;
>img {
max-width: 100%;
max-width: min
}
>div#audio-captcha>audio {
width: 100%;
}
}
#error {
......@@ -19,4 +24,23 @@
&>input[type=checkbox] {
cursor: pointer;
}
}
#submit-group {
display: flex;
align-items: center;
gap: 1rem;
margin-top: 1rem;
max-width: 100%;
flex-wrap: wrap;
>button {
min-width: 8rem;
flex-grow: 1;
}
>a {
display: block;
white-space: nowrap;
}
}
\ No newline at end of file
......@@ -7,9 +7,16 @@
<p>@lang('captcha.2')</p>
<form method="post" action="{{ route('captcha_solve') }}">
<input type="hidden" name="url" value="{!! $url !!}">
<input type="hidden" name="begin" value="{{ \microtime(true) }}">
<input type="hidden" name="c" value="{{ $correct }}">
<div id="captcha-container">
<img src="{{ $image }}" />
<div id="audio-captcha">
<audio controls="controls" preload="none">
<source src="{{$tts_url}}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
</div>
</div>
@if(Request::has('e'))
<p id="error">{{ __('Fehler: Falsche Eingabe!') }}</p>
......@@ -19,6 +26,9 @@
<input type="checkbox" name="dnaa" id="dnaa" @if(Request::has("dnaa"))checked @endif>
<label for="dnaa">@lang('captcha.4')</label>
</div>
<p><button type="submit" class="btn btn-success" name="check">OK</button></p>
<div id="submit-group">
<button type="submit" class="btn btn-success" name="check">OK</button>
<a href="{{ url()->full() }}">@lang('captcha.5')</a>
</div>
</form>
@endsection
\ No newline at end of file
......@@ -3,6 +3,7 @@
use App\Http\Controllers\AdminInterface;
use App\Http\Controllers\Prometheus;
use App\Http\Controllers\SearchEngineList;
use App\Http\Controllers\TTSController;
use Jenssegers\Agent\Agent;
use Illuminate\Http\Request;
use Illuminate\Routing\Router;
......@@ -44,6 +45,8 @@ Route::get('asso', function () {
->with('darkcss', [mix('css/asso/dark.css')]);
});
Route::get('tts', [TTSController::class, 'tts'])->name("tts");
Route::get('asso/meta.ger3', 'Assoziator@asso')->middleware('browserverification:assoresults', 'humanverification')->name("assoresults");
Route::get('impressum', function () {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment