HumanVerification.php 5.3 KB
Newer Older
Dominik Hebeler's avatar
Dominik Hebeler committed
1
2
3
4
<?php

namespace App\Http\Middleware;

5
6
use Captcha;
use Carbon;
Dominik Hebeler's avatar
Dominik Hebeler committed
7
8
use Closure;
use DB;
9
use Illuminate\Http\Response;
Dominik Hebeler's avatar
Dominik Hebeler committed
10
use URL;
Dominik Hebeler's avatar
Dominik Hebeler committed
11
12
13
14
15
16
17
18
19
20
21
22

class HumanVerification
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
Dominik Hebeler's avatar
Dominik Hebeler committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        try {
            $id = hash("sha512", $request->ip());
            $uid = hash("sha512", $request->ip() . $_SERVER["AGENT"]);
            unset($_SERVER["AGENT"]);

            /**
             * 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);
            }
37

Dominik Hebeler's avatar
Dominik Hebeler committed
38
            // The specific user
39
40
            $user = DB::table('humanverification')->where('uid', $uid)->first();

Dominik Hebeler's avatar
Dominik Hebeler committed
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
            $createdAt = Carbon::now();
            $unusedResultPages = 1;
            $locked = false;
            # If this user doesn't have an entry we will create one

            if ($user === null) {
                DB::table('humanverification')->insert(
                    [
                        'uid' => $uid,
                        'id' => $id,
                        'unusedResultPages' => 0,
                        'whitelist' => false,
                        'whitelistCounter' => 0,
                        'locked' => false,
                        "lockedKey" => "",
                        'updated_at' => Carbon::now(),
                    ]
                );
                # Insert the URL the user tries to reach
                $url = url()->full();
                DB::table('usedurls')->insert(['uid' => $uid, 'id' => $id, 'eingabe' => $request->input('eingabe', '')]);
                $user = DB::table('humanverification')->where('uid', $uid)->first();
            }
64

Dominik Hebeler's avatar
Dominik Hebeler committed
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
            # Lock out everyone in a Bot network
            # Find out how many requests this IP has made
            $sum = DB::table('humanverification')->where('id', $id)->where('whitelist', false)->sum('unusedResultPages');

            # A lot of automated requests are from websites that redirect users to our result page.
            # We will detect those requests and put a captcha
            $referer = URL::previous();
            # Just the URL-Parameter
            $refererLock = false;
            if (stripos($referer, "?") !== false) {
                $referer = substr($referer, stripos($referer, "?") + 1);
                $referer = urldecode($referer);
                if (preg_match("/http[s]{0,1}:\/\/metager\.de\/meta\/meta.ger3\?.*?eingabe=([\w\d]+\.){1,2}[\w\d]+/si", $referer) === 1) {
                    $refererLock = true;
                }
Dominik Hebeler's avatar
Dominik Hebeler committed
80

Dominik Hebeler's avatar
Dominik Hebeler committed
81
            }
82

Dominik Hebeler's avatar
Dominik Hebeler committed
83
84
85
86
87
88
            // Defines if this is the only user using that IP Adress
            $alone = DB::table('humanverification')->where('id', $id)->count() === 1;
            if ((!$alone && $sum >= 50 && $user->whitelist !== 1) || $refererLock) {
                DB::table('humanverification')->where('uid', $uid)->update(['locked' => true]);
                $user->locked = 1;
            }
89

Dominik Hebeler's avatar
Dominik Hebeler committed
90
91
92
93
94
95
96
97
98
99
100
101
102
            # If the user is locked we will force a Captcha validation
            if ($user->locked === 1) {
                $captcha = Captcha::create("default", true);
                DB::table('humanverification')->where('uid', $uid)->update(['lockedKey' => $captcha["key"]]);
                return
                new Response(
                    view('humanverification.captcha')
                        ->with('title', "Bestätigung erforderlich")
                        ->with('id', $uid)
                        ->with('url', url()->full())
                        ->with('image', $captcha["img"])
                );
            }
103

Dominik Hebeler's avatar
Dominik Hebeler committed
104
105
            $unusedResultPages = intval($user->unusedResultPages);
            $unusedResultPages++;
106
            $locked = false;
Dominik Hebeler's avatar
Dominik Hebeler committed
107

Dominik Hebeler's avatar
Dominik Hebeler committed
108
109
110
111
112
113
114
115
116
117
118
119
120
121
            if ($alone || $user->whitelist === 1) {
                # This IP doesn't need verification yet
                # The user currently isn't locked

                # 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;
                }

            }
122
123
124
125
            DB::table('humanverification')->where('uid', $uid)->update(['unusedResultPages' => $unusedResultPages, 'locked' => $locked]);
            # Insert the URL the user tries to reach
            DB::table('usedurls')->insert(['uid' => $uid, 'id' => $id, 'eingabe' => $request->input('eingabe', '')]);

Dominik Hebeler's avatar
Dominik Hebeler committed
126
127
        } catch (\Illuminate\Database\QueryException $e) {
            // Failure in contacting metager3.de
Dominik Hebeler's avatar
Dominik Hebeler committed
128
        }
129
130
        if(isset($uid) && isset($unusedResultPages))
            $request->request->add(['verification_id' => $uid, 'verification_count' => $unusedResultPages]);
Dominik Hebeler's avatar
Dominik Hebeler committed
131
132
133
        return $next($request);
    }
}