Commit 8d4db597 authored by Karl Hasselbring's avatar Karl Hasselbring
Browse files

Merge with Development

parents 088fe0bd 93be40fc
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Validator;
use Input;
use DB;
use Carbon;
class HumanVerification extends Controller
{
public static function captcha(Request $request, $id, $url){
if($request->getMethod() == 'POST'){
$rules = ['captcha' => 'required|captcha'];
$validator = Validator::make($request->all(), $rules);
if($validator->fails()){
return view('captcha')->with('title', 'Bestätigung notwendig')->with('id', $id)->with('url', base64_decode($url))->with('errorMessage', 'Bitte Captcha eingeben:');
}else{
# If we can unlock the Account of this user we will redirect him to the result page
$id = $request->input('id');
$url = $request->input('url');
$user = DB::table('humanverification')->where('id', $id)->first();
if($user !== null && $user->locked === 1){
DB::table('humanverification')->where('id', $id)->update(['locked' => false]);
return redirect($url);
}else{
return redirect('/');
}
}
}
return view('captcha')->with('title', 'Bestätigung notwendig')->with('id', $id)->with('url', base64_decode($url));
}
public static function remove(Request $request){
if(!$request->has('mm')){
abort(404, "Keine Katze gefunden.");
}
$id = md5($request->ip());
if(HumanVerification::checkId($request, $request->input('mm'))){
# Remove the entry from the database
DB::table('humanverification')->where('id', $id)->where('updated_at', '<', Carbon::NOW()->subSeconds(2) )->delete();
}
return response(hex2bin('89504e470d0a1a0a0000000d494844520000000100000001010300000025db56ca00000003504c5445000000a77a3dda0000000174524e530040e6d8660000000a4944415408d76360000000020001e221bc330000000049454e44ae426082'), 200)
->header('Content-Type', 'image/png');
}
public static function removeGet(Request $request, $mm, $password, $url){
$url = base64_decode($url);
# If the user is correct and the password is we will delete any entry in the database
$requiredPass = md5($mm . Carbon::NOW()->day . $url . env("PROXY_PASSWORD"));
if(HumanVerification::checkId($request, $mm) && $requiredPass === $password){
# Remove the entry from the database
DB::table('humanverification')->where('id', $mm)->where('updated_at', '<', Carbon::NOW()->subSeconds(2) )->delete();
}
return redirect($url);
}
private static function checkId($request, $id){
if(md5($request->ip()) === $id){
return true;
}else{
return false;
}
}
}
......@@ -16,6 +16,7 @@ class Kernel extends HttpKernel
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Fideloper\Proxy\TrustProxies::class,
// \App\Http\Middleware\VerifyCsrfToken::class,
];
/**
......@@ -26,10 +27,6 @@ class Kernel extends HttpKernel
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
#\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
......@@ -37,6 +34,15 @@ class Kernel extends HttpKernel
'throttle:60,1',
'bindings',
],
'session' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
/**
......@@ -54,5 +60,6 @@ class Kernel extends HttpKernel
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'referer.check' => \App\Http\Middleware\RefererCheck::class,
'humanverification' => \App\Http\Middleware\HumanVerification::class,
];
}
<?php
namespace App\Http\Middleware;
use Closure;
use DB;
use Carbon;
class HumanVerification
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$id = md5($request->ip());
/**
* If the user sends a Password or a key
* We will not verificate the user.
* If someone that uses a bot finds this out we
* might have to change it at some point.
*/
if($request->filled('password') || $request->filled('key') || $request->filled('appversion') || !env('BOT_PROTECTION', false)){
return $next($request);
}
$user = DB::table('humanverification')->where('id', $id)->first();
$createdAt = now();
$unusedResultPages = 1;
$locked = false;
# If this user doesn't have an entry we will create one
if($user === null){
DB::table('humanverification')->insert(
['id' => $id, 'unusedResultPages' => 1, 'locked' => false, 'updated_at' => now()]
);
# Insert the URL the user tries to reach
DB::table('usedurls')->insert(['user_id' => $id, 'url' => url()->full()]);
$user = DB::table('humanverification')->where('id', $id)->first();
}else if($user->locked !== 1){
$unusedResultPages = intval($user->unusedResultPages);
$unusedResultPages++;
# We have different security gates:
# 50, 75, 85, >=90 => Captcha validated Result Pages
# If the user shows activity on our result page the counter will be deleted
# Maybe I'll add a ban if the user reaches 100
if($unusedResultPages === 50 || $unusedResultPages === 75 || $unusedResultPages === 85 || $unusedResultPages >= 90){
$locked = true;
}
DB::table('humanverification')->where('id', $id)->update(['unusedResultPages' => $unusedResultPages, 'locked' => $locked, 'updated_at' => $createdAt]);
# Insert the URL the user tries to reach
DB::table('usedurls')->insert(['user_id' => $id, 'url' => url()->full()]);
}
$request->request->add(['verification_id' => $id, 'verification_count' => $unusedResultPages]);
# If the user is locked we will force a Captcha validation
if($user->locked === 1){
return redirect('meta/verification/' . $id . '/' . urlencode(base64_encode(url()->full())));
}
return $next($request);
}
}
......@@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Redis;
use Jenssegers\Agent\Agent;
use LaravelLocalization;
use Log;
use Carbon;
use Predis\Connection\ConnectionException;
class MetaGer
......@@ -53,12 +54,13 @@ class MetaGer
protected $urlsBlacklisted = [];
protected $url;
protected $languageDetect;
protected $verificationId;
protected $verificationCount;
public function __construct()
{
# Timer starten
$this->starttime = microtime(true);
# Versuchen Blacklists einzulesen
if (file_exists(config_path() . "/blacklistDomains.txt") && file_exists(config_path() . "/blacklistUrl.txt")) {
$tmp = file_get_contents(config_path() . "/blacklistDomains.txt");
......@@ -252,6 +254,9 @@ class MetaGer
#Adgoal Implementation
$this->results = $this->parseAdgoal($this->results);
# Human Verification
$this->results = $this->humanVerification($this->results);
$counter = 0;
$firstRank = 0;
......@@ -447,6 +452,22 @@ class MetaGer
return $results;
}
public function humanVerification($results){
# Let's check if we need to implement a redirect for human verification
if($this->verificationCount > 10){
foreach($results as $result){
$link = $result->link;
$day = Carbon::now()->day;
$pw = md5($this->verificationId . $day . $link . env("PROXY_PASSWORD"));
$url = route('humanverification', ['mm' => $this->verificationId, 'pw' => $pw, "url" => urlencode(base64_encode($link))]);
$result->link = $url;
}
return $results;
}else{
return $results;
}
}
public function authorize($key)
{
$postdata = http_build_query(array(
......@@ -1022,6 +1043,8 @@ class MetaGer
$this->quicktips = true;
}
$this->verificationId = $request->input('verification_id', null);
$this->verificationCount = intval($request->input('verification_count', '0'));
$this->apiKey = $request->input('key', '');
$this->validated = false;
......
......@@ -39,6 +39,8 @@ class RouteServiceProvider extends ServiceProvider
$this->mapWebRoutes();
$this->mapSessionRoutes();
//
}
......@@ -76,4 +78,21 @@ class RouteServiceProvider extends ServiceProvider
require base_path('routes/api.php');
});
}
/**
* Define the "session" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapSessionRoutes()
{
Route::group([
'middleware' => 'session',
'namespace' => $this->namespace,
], function ($router) {
require base_path('routes/session.php');
});
}
}
File mode changed from 100644 to 100755
......@@ -182,6 +182,7 @@ return [
Jenssegers\Agent\AgentServiceProvider::class,
Fideloper\Proxy\TrustedProxyServiceProvider::class,
Collective\Html\HtmlServiceProvider::class,
Mews\Captcha\CaptchaServiceProvider::class,
],
/*
......@@ -233,6 +234,8 @@ return [
'Agent' => Jenssegers\Agent\Facades\Agent::class,
'Form' => Collective\Html\FormFacade::class,
'HTML' => Collective\Html\HtmlFacade::class,
'Captcha' => Mews\Captcha\Facades\Captcha::class,
'Carbon' => Carbon\Carbon::class,
],
];
<?php
return [
'characters' => '2346789abcdefghjmnpqrtuxyzABCDEFGHJMNPQRTUXYZ',
'default' => [
'length' => 5,
'width' => 220,
'height' => 66,
'quality' => 90,
],
'flat' => [
'length' => 6,
'width' => 160,
'height' => 46,
'quality' => 90,
'lines' => 6,
'bgImage' => false,
'bgColor' => '#ecf2f4',
'fontColors'=> ['#2c3e50', '#c0392b', '#16a085', '#c0392b', '#8e44ad', '#303f9f', '#f57c00', '#795548'],
'contrast' => -5,
],
'mini' => [
'length' => 3,
'width' => 60,
'height' => 32,
],
'inverse' => [
'length' => 5,
'width' => 120,
'height' => 36,
'quality' => 90,
'sensitive' => true,
'angle' => 12,
'sharpen' => 10,
'blur' => 2,
'invert' => true,
'contrast' => -5,
]
];
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateHumanverificationTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('humanverification', function (Blueprint $table) {
$table->string('id')->unique();
$table->integer('unusedResultPages');
$table->boolean('locked');
$table->timestamp('updated_at');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('humanverification');
}
}
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class Usedurls extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('usedurls', function (Blueprint $table) {
$table->increments('id')->unique();
$table->string('user_id');
$table->text('url');
$table->timestamp('created_at');
$table->foreign('user_id')->references('id')->on('humanverification')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('usedurls');
}
}
......@@ -15,6 +15,7 @@
* php-xml
* php-zip
* php-redis
* php-gd
* sqlite3
* redis-server
* Die Perl-Pakete
......@@ -40,4 +41,4 @@ zögere bitte nicht ein [Ticket zu schreiben](https://gitlab.metager3.de/open-so
Der MetaGer-eigene Code, sofern nicht anders anders angegeben, steht unter der [AGPL-Lizenz Version 3](https://www.gnu.org/licenses/agpl-3.0).
Eine Liste der Projekte, auf denen MetaGer basiert, und deren Lizenzen sind in der Datei [LICENSE]( zu finden.
Eine Liste der Projekte, auf denen MetaGer basiert, und deren Lizenzen sind in der Datei [LICENSE](https://gitlab.metager3.de/open-source/MetaGer/blob/development/LICENSE) zu finden.
$(function () {
setFocusCreatorActionListeners();
loadInitialCustomFocuses();
loadInitialSelectedFocus();
focusChanged();
$(function() {
setLabelText();
setKeyListeners();
setDropdownListeners();
});
/**
* Sets all action listeners for this page
*/
function setFocusCreatorActionListeners () {
$('.focusCheckbox').click(checkboxCheckListener);
$('#addFocusBtn').click(() => showFocusCreateDialog(''));
$('#editFocusBtn').click(editCurrentFocus);
$('.save-focus-btn').click(saveFocus);
$('.delete-focus-btn').click(deleteFocus);
$('#focus-select').change(focusChanged);
// Save Focus on clicking enter while in the focus name input
$('#focus-name').keyup(function (event) {
if (event.keyCode == 13) {
saveFocus();
}
});
$('#create-focus-modal').on('shown.bs.modal', function () {
$('#focus-name').focus();
});
}
/**
* Loads all the custom focuses stored in local storage
*/
function loadInitialCustomFocuses () {
for (var key in localStorage) {
if (key.startsWith('focus_')) {
var focus = loadFocusById(key);
addFocus(focus.name);
}
}
}
function loadInitialSelectedFocus () {
setFocus(getFocusInUrl());
}
/**
* Shows the focus create dialog
* If an id is given it will try to load a focus for the given id
*/
function showFocusCreateDialog (id) {
if (id === undefined) {
id = '';
}
document.getElementById('original-id').value = id;
$('#create-focus-modal').modal('show');
var storedFocus = loadFocusById(id);
var focus = {};
// Try to load a focus for the given id
$('#focus-name').val('');
uncheckAll();
if (storedFocus !== null) {
try {
focus = JSON.parse(localStorage.getItem(id));
$('#focus-name').val(focus.name);
for (var key in focus) {
if (key.startsWith('engine_')) {
$('.focusCheckbox[name=' + key + ']').prop('checked', true);
}
function setKeyListeners() {
$(document).keydown(function(event) {
if ($("input#show-create-focus").is(":checked")) {
if (event.keyCode == 27) {
$("input#show-create-focus").prop("checked", false);
} else if (event.keyCode == 13) {
$("#customSearchForm").submit();
}
} catch (ex) {
console.error(ex);
}
}
toggleDeleteButton();
}
/**
* Shows the focus create dialog for a given id
*/
function showFocusEditDialog (id) {
showFocusCreateDialog(id);
}
function getCurrentFocus () {
return $('#foki > div.active').attr('id');
}
/**
* Shows an edit dialog for the current selected focus
*/
function editCurrentFocus () {
var currentFocus = getCurrentFocus();
if (currentFocus !== undefined) {
showFocusEditDialog(currentFocus);
}
}
/**
* Shows/Hides the delete button if (no) checkboxes are selected
*/
function toggleDeleteButton () {
if (atLeastOneChecked()) {
$('.delete-focus-btn').show();
} else {
$('.delete-focus-btn').hide();
}
}
/**
* Save the current Focus
* Listens for save button
*/
function saveFocus () {
/* Vorprüfungen */
// Falls keine Suchmaschine ausgewählt wurde
if (!atLeastOneChecked()) {
switch (document.documentElement.lang) {
case 'en':
alert('Please select at least 1 search engine.');
break;
case 'es':
alert('Por favor, seleccione al menos un motor de búsqueda.');
break;
default:
alert('Bitte mindestens 1 Suchmaschine auswählen.');
break;
}
return;
}
// Falls der Name zu kurz ist oder ungültige Zeichen enthält
var name = document.getElementById('focus-name').value;
if (!isValidName(name)) {
switch (document.documentElement.lang) {
case 'en':
alert('No characters other than a-z, A-Z, 0-9, ä, ö, ü, ß, -, _ allowed, at least 1 character');
break;
case 'es':
alert('Por favor, introduzca un nombre válido');
break;
default:
alert('Bitte gültigen Namen eingeben:\n* Keine Sonderzeichen\n* Mindestens 1 Buchstabe\n');
break;
}
return;
}
// Liest die original-id des aktuellen fokus-dialogs (gesetzt wenn man einen Fokus bearbeitet)
var oldId = document.getElementById('original-id').value;
var id = getIdFromName(name);
var overwrite = true;
// Wenn bereits ein Fokus mit dem Namen existiert, man diesen aber nicht editiert sondern gerade einen Neuen erstellt
if (alreadyInUse(name) && oldId !== id) {
// Fragt den Nutzer ob er den Fokus überschreiben möchte
if (!confirm('Name bereits genutzt\nüberschreiben?')) {
// Falls nicht wird das Speichern abgebrochen
return;
}
// Ansonsten wird der andere Fokus gelöscht
deleteFocusById(id);
}
/* Fokus speichern */
var focus = {};
// Ausgewählte Suchmaschinen lesen und zu Fokus hinzufügen
$('input[type=checkbox]:checked').each(function (el) {
focus[$(this).attr('name')] = $(this).val();
});