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

namespace App\Http\Controllers;

5 6 7
use Captcha;
use Carbon;
use Illuminate\Hashing\BcryptHasher as Hasher;
Dominik Hebeler's avatar
Dominik Hebeler committed
8
use Illuminate\Http\Request;
9
use Illuminate\Support\Facades\Cache;
10
use Illuminate\Support\Facades\Redis;
Dominik Hebeler's avatar
Dominik Hebeler committed
11 12 13 14
use Input;

class HumanVerification extends Controller
{
15
    const PREFIX = "humanverification";
16 17
    const EXPIRELONG = 60 * 60 * 24 * 14;
    const EXPIRESHORT = 60 * 60 * 72;
18

19
    public static function captcha(Request $request, Hasher $hasher, $id, $uid, $url = null)
20 21 22 23
    {
        if ($url != null) {
            $url = base64_decode(str_replace("<<SLASH>>", "/", $url));
        } else {
Dominik Hebeler's avatar
Dominik Hebeler committed
24 25 26 27 28 29 30 31 32 33 34
            $url = $request->input('url', url("/"));
        }

        $protocol = "http://";

        if ($request->secure()) {
            $protocol = "https://";
        }

        if (stripos($url, $protocol . $request->getHttpHost()) !== 0) {
            $url = url("/");
35
        }
Dominik Hebeler's avatar
Dominik Hebeler committed
36

37 38 39 40 41 42 43 44 45
        $userlist = Cache::get(HumanVerification::PREFIX . "." . $id, []);
        $user = null;

        if (sizeof($userlist) === 0 || empty($userlist[$uid])) {
            return redirect('/');
        } else {
            $user = $userlist[$uid];
        }

46
        if ($request->getMethod() == 'POST') {
47
            \App\PrometheusExporter::CaptchaAnswered();
48
            $lockedKey = $user["lockedKey"];
49 50
            $key = $request->input('captcha');
            $key = strtolower($key);
51

52
            if (!$hasher->check($key, $lockedKey)) {
53
                $captcha = Captcha::create("default", true);
54 55
                $user["lockedKey"] = $captcha["key"];
                HumanVerification::saveUser($user);
56
                \App\PrometheusExporter::CaptchaShown();
57
                return view('humanverification.captcha')->with('title', 'Bestätigung notwendig')
58
                    ->with('uid', $user["uid"])
59 60 61
                    ->with('id', $id)
                    ->with('url', $url)
                    ->with('image', $captcha["img"])
Dominik Hebeler's avatar
Dominik Hebeler committed
62
                    ->with('errorMessage', 'Fehler: Falsche Eingabe!');
63
            } else {
64
                \App\PrometheusExporter::CaptchaCorrect();
65
                # If we can unlock the Account of this user we will redirect him to the result page
66
                if ($user !== null && $user["locked"]) {
Dominik Hebeler's avatar
Dominik Hebeler committed
67
                    # The Captcha was correct. We can remove the key from the user
68 69 70 71 72
                    # Additionally we will whitelist him so he is not counted towards botnetwork
                    $user["locked"] = false;
                    $user["lockedKey"] = "";
                    $user["whitelist"] = true;
                    HumanVerification::saveUser($user);
Dominik Hebeler's avatar
Dominik Hebeler committed
73
                    return redirect($url);
74
                } else {
Dominik Hebeler's avatar
Dominik Hebeler committed
75 76 77 78
                    return redirect('/');
                }
            }
        }
Dominik Hebeler's avatar
Dominik Hebeler committed
79

80
        $captcha = Captcha::create("default", true);
81 82
        $user["lockedKey"] = $captcha["key"];
        HumanVerification::saveUser($user);
83
        \App\PrometheusExporter::CaptchaShown();
84
        return view('humanverification.captcha')->with('title', 'Bestätigung notwendig')
85
            ->with('uid', $user["uid"])
86 87 88
            ->with('id', $id)
            ->with('url', $url)
            ->with('image', $captcha["img"]);
Dominik Hebeler's avatar
Dominik Hebeler committed
89

Dominik Hebeler's avatar
Dominik Hebeler committed
90 91
    }

92 93 94
    public static function remove(Request $request)
    {
        if (!$request->has('mm')) {
Dominik Hebeler's avatar
Dominik Hebeler committed
95 96
            abort(404, "Keine Katze gefunden.");
        }
97

98
        if (HumanVerification::checkId($request, $request->input('mm'))) {
99
            HumanVerification::removeUser($request, $request->input('mm'));
Dominik Hebeler's avatar
Dominik Hebeler committed
100 101 102 103 104
        }
        return response(hex2bin('89504e470d0a1a0a0000000d494844520000000100000001010300000025db56ca00000003504c5445000000a77a3dda0000000174524e530040e6d8660000000a4944415408d76360000000020001e221bc330000000049454e44ae426082'), 200)
            ->header('Content-Type', 'image/png');
    }

105 106 107
    public static function removeGet(Request $request, $mm, $password, $url)
    {
        $url = base64_decode(str_replace("<<SLASH>>", "/", $url));
Dominik Hebeler's avatar
Dominik Hebeler committed
108 109
        # 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"));
Dominik Hebeler's avatar
Dominik Hebeler committed
110

111
        if (HumanVerification::checkId($request, $mm) && $requiredPass === $password) {
112
            HumanVerification::removeUser($request, $mm);
Dominik Hebeler's avatar
Dominik Hebeler committed
113 114 115 116
        }
        return redirect($url);
    }

117 118 119
    private static function saveUser($user)
    {
        $userList = Cache::get(HumanVerification::PREFIX . "." . $user["id"], []);
Dominik Hebeler's avatar
Dominik Hebeler committed
120

121 122 123 124 125
        if ($user["whitelist"]) {
            $user["expiration"] = now()->addWeeks(2);
        } else {
            $user["expiration"] = now()->addHours(72);
        }
Dominik Hebeler's avatar
Dominik Hebeler committed
126
        $userList[$user["uid"]] = $user;
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
        Cache::put(HumanVerification::PREFIX . "." . $user["id"], $userList, now()->addWeeks(2));
    }

    private static function deleteUser($user)
    {
        $userList = Cache::get(HumanVerification::PREFIX . "." . $user["id"], []);
        $newUserList = [];
        $changed = false;

        foreach ($userList as $uid => $userTmp) {
            if ($userTmp["uid"] !== $user["uid"]) {
                $newUserList[$userTmp["uid"]] = $userTmp;
            } else {
                $changed = true;
            }
        }
Dominik Hebeler's avatar
Dominik Hebeler committed
143

144
        if ($changed) {
Dominik Hebeler's avatar
Dominik Hebeler committed
145 146 147 148 149
            if (sizeof($newUserList) > 0) {
                Cache::put(HumanVerification::PREFIX . "." . $user["id"], $newUserList, now()->addWeeks(2));
            } else {
                Cache::forget(HumanVerification::PREFIX . "." . $user["id"], $newUserList);
            }
150 151 152
        }
    }

153 154
    private static function removeUser($request, $uid)
    {
Dominik Hebeler's avatar
Dominik Hebeler committed
155 156
        $ip = $request->ip();
        $id = "";
Dominik Hebeler's avatar
Bugfix  
Dominik Hebeler committed
157
        if (HumanVerification::couldBeSpammer($ip)) {
Dominik Hebeler's avatar
Dominik Hebeler committed
158
            $id = hash("sha1", "999.999.999.999");
Dominik Hebeler's avatar
Dominik Hebeler committed
159
        } else {
Dominik Hebeler's avatar
Dominik Hebeler committed
160
            $id = hash("sha1", $ip);
Dominik Hebeler's avatar
Dominik Hebeler committed
161
        }
162

163 164 165 166 167 168 169
        $userlist = Cache::get(HumanVerification::PREFIX . "." . $id, []);
        $user = null;

        if (sizeof($userlist) === 0 || empty($userlist[$uid])) {
            return;
        } else {
            $user = $userlist[$uid];
170 171 172
        }

        $sum = 0;
173
        foreach ($userlist as $uidTmp => $userTmp) {
Dominik Hebeler's avatar
Dominik Hebeler committed
174
            if (!empty($userTmp) && gettype($userTmp["whitelist"]) === "boolean" && !$userTmp["whitelist"]) {
175 176
                $sum += intval($userTmp["unusedResultPages"]);
            }
177 178
        }
        # Check if we have to whitelist the user or if we can simply delete the data
179
        if ($user["unusedResultPages"] < $sum && !$user["whitelist"]) {
180
            # Whitelist
181
            $user["whitelist"] = true;
182 183
        }

184
        if ($user["whitelist"]) {
185 186
            $user["unusedResultPages"] = 0;
            HumanVerification::saveUser($user);
187
        } else {
188
            HumanVerification::deleteUser($user);
189 190 191
        }
    }

192 193
    private static function checkId($request, $id)
    {
Dominik Hebeler's avatar
Dominik Hebeler committed
194 195
        $uid = "";
        $ip = $request->ip();
Dominik Hebeler's avatar
Bugfix  
Dominik Hebeler committed
196
        if (HumanVerification::couldBeSpammer($ip)) {
Dominik Hebeler's avatar
Dominik Hebeler committed
197
            $uid = hash("sha1", "999.999.999.999" . $ip . $_SERVER["AGENT"] . "uid");
Dominik Hebeler's avatar
Dominik Hebeler committed
198
        } else {
Dominik Hebeler's avatar
Dominik Hebeler committed
199
            $uid = hash("sha1", $ip . $_SERVER["AGENT"] . "uid");
Dominik Hebeler's avatar
Dominik Hebeler committed
200 201 202
        }

        if ($uid === $id) {
Dominik Hebeler's avatar
Dominik Hebeler committed
203
            return true;
204
        } else {
Dominik Hebeler's avatar
Dominik Hebeler committed
205 206 207
            return false;
        }
    }
Dominik Hebeler's avatar
Dominik Hebeler committed
208

Dominik Hebeler's avatar
Bugfix  
Dominik Hebeler committed
209
    public static function couldBeSpammer($ip)
Dominik Hebeler's avatar
Dominik Hebeler committed
210
    {
Dominik Hebeler's avatar
Bugfix  
Dominik Hebeler committed
211 212
        # Check for recent Spams
        $eingabe = \Request::input('eingabe');
213 214 215 216 217
        $spams = Redis::lrange("spam", 0, -1);
        foreach ($spams as $spam) {
            if (\preg_match($spam, $eingabe)) {
                return true;
            }
Dominik Hebeler's avatar
Bugfix  
Dominik Hebeler committed
218 219
        }

220
        return false;
Dominik Hebeler's avatar
Dominik Hebeler committed
221
    }
222

Dominik Hebeler's avatar
Dominik Hebeler committed
223 224
    public function botOverview(Request $request)
    {
225 226 227 228
        $id = "";
        $uid = "";
        $ip = $request->ip();
        if (\App\Http\Controllers\HumanVerification::couldBeSpammer($ip)) {
Dominik Hebeler's avatar
Dominik Hebeler committed
229 230
            $id = hash("sha1", "999.999.999.999");
            $uid = hash("sha1", "999.999.999.999" . $ip . $_SERVER["AGENT"] . "uid");
231
        } else {
Dominik Hebeler's avatar
Dominik Hebeler committed
232 233
            $id = hash("sha1", $ip);
            $uid = hash("sha1", $ip . $_SERVER["AGENT"] . "uid");
234 235 236 237 238 239 240 241
        }

        $userList = Cache::get(HumanVerification::PREFIX . "." . $id);
        $user = $userList[$uid];

        return view('humanverification.botOverview')
            ->with('title', "Bot Overview")
            ->with('ip', $ip)
242
            ->with('userList', $userList)
243 244 245
            ->with('user', $user);
    }

Dominik Hebeler's avatar
Dominik Hebeler committed
246 247
    public function botOverviewChange(Request $request)
    {
248 249 250 251
        $id = "";
        $uid = "";
        $ip = $request->ip();
        if (\App\Http\Controllers\HumanVerification::couldBeSpammer($ip)) {
Dominik Hebeler's avatar
Dominik Hebeler committed
252 253
            $id = hash("sha1", "999.999.999.999");
            $uid = hash("sha1", "999.999.999.999" . $ip . $_SERVER["AGENT"] . "uid");
254
        } else {
Dominik Hebeler's avatar
Dominik Hebeler committed
255 256
            $id = hash("sha1", $ip);
            $uid = hash("sha1", $ip . $_SERVER["AGENT"] . "uid");
257 258 259 260 261
        }

        $userList = Cache::get(HumanVerification::PREFIX . "." . $id);
        $user = $userList[$uid];

Dominik Hebeler's avatar
Dominik Hebeler committed
262
        if ($request->filled("locked")) {
263
            $user["locked"] = boolval($request->input('locked'));
Dominik Hebeler's avatar
Dominik Hebeler committed
264
        } elseif ($request->filled("whitelist")) {
265
            $user["whitelist"] = boolval($request->input('whitelist'));
Dominik Hebeler's avatar
Dominik Hebeler committed
266
        } elseif ($request->filled("unusedResultPages")) {
267 268 269 270 271 272
            $user["unusedResultPages"] = intval($request->input('unusedResultPages'));
        }

        HumanVerification::saveUser($user);
        return redirect('admin/bot');
    }
Dominik Hebeler's avatar
Dominik Hebeler committed
273
}