HumanVerification.php 6.54 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)
    {
23
24
25
        // The specific user
        $user = null;
        $newUser = true;
Dominik Hebeler's avatar
Dominik Hebeler committed
26
27
28
29
30
31
32
33
34
35
36
37
38
39
        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);
            }
40

41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
            
            $users = DB::select('select * from humanverification where id = ?', [$id]);
            
            # Lock out everyone in a Bot network
            # Find out how many requests this IP has made
            $sum = 0;
            foreach($users as $userTmp){
                if($uid == $userTmp->uid){
                    $user = ['uid' => $userTmp->uid,
                            'id' => $userTmp->id,
                            'unusedResultPages' => intval($userTmp->unusedResultPages),
                            'whitelist' => filter_var($userTmp->whitelist, FILTER_VALIDATE_BOOLEAN),
                            'whitelistCounter' => $userTmp->whitelistCounter,
                            'locked' => filter_var($userTmp->locked, FILTER_VALIDATE_BOOLEAN),
                            "lockedKey" => $userTmp->lockedKey,
                            'updated_at' => Carbon::now(),
                            ];
                    $newUser = false;
                }
                if($userTmp->whitelist === 0)
                    $sum += $userTmp->unusedResultPages;
            }
Dominik Hebeler's avatar
Dominik Hebeler committed
63
64
65
            # If this user doesn't have an entry we will create one

            if ($user === null) {
66
                $user =
Dominik Hebeler's avatar
Dominik Hebeler committed
67
68
69
70
71
72
73
74
75
                    [
                        'uid' => $uid,
                        'id' => $id,
                        'unusedResultPages' => 0,
                        'whitelist' => false,
                        'whitelistCounter' => 0,
                        'locked' => false,
                        "lockedKey" => "",
                        'updated_at' => Carbon::now(),
76
                    ];
Dominik Hebeler's avatar
Dominik Hebeler committed
77
            }
78

Dominik Hebeler's avatar
Dominik Hebeler committed
79
80
81
82
83
84
85
86
87
88
89
            # 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
90

Dominik Hebeler's avatar
Dominik Hebeler committed
91
            }
92

Dominik Hebeler's avatar
Dominik Hebeler committed
93
            // Defines if this is the only user using that IP Adress
94
95
96
97
98
99
100
            $alone = true;
            foreach($users as $userTmp){
                if($userTmp->uid != $uid && !$userTmp->whitelist)
                    $alone = false;
            }
            if ((!$alone && $sum >= 50 && !$user["whitelist"]) || $refererLock) {
                $user["locked"] = true;
Dominik Hebeler's avatar
Dominik Hebeler committed
101
            }
102

Dominik Hebeler's avatar
Dominik Hebeler committed
103
            # If the user is locked we will force a Captcha validation
104
            if ($user["locked"]) {
Dominik Hebeler's avatar
Dominik Hebeler committed
105
                $captcha = Captcha::create("default", true);
106
                $user["lockedKey"] = $captcha["key"];
Dominik Hebeler's avatar
Dominik Hebeler committed
107
108
109
110
111
112
113
114
115
                return
                new Response(
                    view('humanverification.captcha')
                        ->with('title', "Bestätigung erforderlich")
                        ->with('id', $uid)
                        ->with('url', url()->full())
                        ->with('image', $captcha["img"])
                );
            }
116

117
            $user["unusedResultPages"]++;
Dominik Hebeler's avatar
Dominik Hebeler committed
118

119
            if ($alone || $user["whitelist"]) {
Dominik Hebeler's avatar
Dominik Hebeler committed
120
121
122
123
124
125
126
127
                # 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

128
129
                if ($user["unusedResultPages"] === 50 || $user["unusedResultPages"] === 75 || $user["unusedResultPages"] === 85 || $user["unusedResultPages"] >= 90) {
                    $user["locked"] = true;
Dominik Hebeler's avatar
Dominik Hebeler committed
130
131
132
133
134
                }

            }
        } catch (\Illuminate\Database\QueryException $e) {
            // Failure in contacting metager3.de
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
        } finally {
            // Update the user in the database
            if($newUser){
                DB::table('humanverification')->insert(
                    [
                        'uid' => $user["uid"],
                        'id' => $user["id"],
                        'unusedResultPages' => $user['unusedResultPages'],
                        'whitelist' => $user["whitelist"],
                        'whitelistCounter' => $user["whitelistCounter"],
                        'locked' => $user["locked"],
                        "lockedKey" => $user["lockedKey"],
                        'updated_at' => $user["updated_at"],
                    ]
                );
            }else{
                DB::table('humanverification')->where('uid', $uid)->update(
                    [
                        'uid' => $user["uid"],
                        'id' => $user["id"],
                        'unusedResultPages' => $user['unusedResultPages'],
                        'whitelist' => $user["whitelist"],
                        'whitelistCounter' => $user["whitelistCounter"],
                        'locked' => $user["locked"],
                        "lockedKey" => $user["lockedKey"],
                        'updated_at' => $user["updated_at"],
                    ]
                    );
            }
Dominik Hebeler's avatar
Dominik Hebeler committed
164
        }
165
        $request->request->add(['verification_id' => $user["uid"], 'verification_count' => $user["unusedResultPages"]]);
Dominik Hebeler's avatar
Dominik Hebeler committed
166
167
168
        return $next($request);
    }
}