ScanController::getLastScanDate()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 2
dl 0
loc 15
rs 9.9666
c 0
b 0
f 0
1
<?php
2
3
namespace App\Http\Controllers;
4
5
use App\Domain;
6
use App\Http\Requests\ScannerStartRequest;
7
use App\Jobs\ScanJob;
8
use App\Scan;
9
use App\ScanResult;
10
use App\Siweocs\Models\ScanRawResultResponse;
11
use App\Siweocs\Models\ScanStatusResponse;
12
use App\Token;
13
use GuzzleHttp\Client;
14
use Illuminate\Http\Request;
15
use Illuminate\Support\Carbon;
16
use Log;
17
18
class ScanController extends Controller
19
{
20
    public function start(ScannerStartRequest $request)
21
    {
22
        $token = Token::getTokenByString(($request->header('siwecosToken')));
23
24
        Log::info('Token: '.$token->token);
25
        if ($token instanceof Token && $token->reduceCredits()) {
26
            $isNotTestRunner = $request->json('isNotATest') ?? true;
27
            $dangerlevel = $request->json('dangerLevel') ?? 10;
28
29
            return self::startScanJob($token, $request->json('domain'), false, $dangerlevel, $isNotTestRunner);
0 ignored issues
show
Bug introduced by
It seems like $dangerlevel can also be of type Symfony\Component\HttpFoundation\ParameterBag; however, parameter $dangerLevel of App\Http\Controllers\Sca...troller::startScanJob() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

29
            return self::startScanJob($token, $request->json('domain'), false, /** @scrutinizer ignore-type */ $dangerlevel, $isNotTestRunner);
Loading history...
Bug introduced by
It seems like $isNotTestRunner can also be of type Symfony\Component\HttpFoundation\ParameterBag; however, parameter $isRegistered of App\Http\Controllers\Sca...troller::startScanJob() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

29
            return self::startScanJob($token, $request->json('domain'), false, $dangerlevel, /** @scrutinizer ignore-type */ $isNotTestRunner);
Loading history...
Bug introduced by
It seems like $request->json('domain') can also be of type Symfony\Component\HttpFoundation\ParameterBag; however, parameter $domain of App\Http\Controllers\Sca...troller::startScanJob() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

29
            return self::startScanJob($token, /** @scrutinizer ignore-type */ $request->json('domain'), false, $dangerlevel, $isNotTestRunner);
Loading history...
30
        }
31
    }
32
33
    public static function startScanJob(Token $token, string $domain, bool $isRecurrent = false, int $dangerLevel = 0, bool $isRegistered = false)
0 ignored issues
show
Unused Code introduced by
The parameter $isRegistered is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

33
    public static function startScanJob(Token $token, string $domain, bool $isRecurrent = false, int $dangerLevel = 0, /** @scrutinizer ignore-unused */ bool $isRegistered = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
34
    {
35
36
        // create a new scan order
37
        /** @var Domain $currentDomain */
38
        $currentDomain = Domain::getDomainOrFail($domain, $token->id);
39
        /** @var Scan $scan */
40
        $scan = $token->scans()->create([
41
            'token_id'      => $token->id,
42
            'url'           => $currentDomain->domain,
43
            'callbackurls'  => [],
44
            'dangerLevel'   => $dangerLevel,
45
            'recurrentscan' => $isRecurrent,
46
        ]);
47
48
        $scan->recurrentscan = $isRecurrent ? 1 : 0;
49
        $scan->save();
50
51
        $envVars = array_key_exists('APP_NAME', $_ENV) ? $_ENV : getenv();
52
53
        // dispatch each scanner to the queue
54
        foreach ($envVars as $key => $value) {
55
            Log::info($key.' '.$value);
56
            if (!preg_match("/^SCANNER_(\w+)_URL$/", $key, $scanner_name)) {
57
                continue;
58
            }
59
            if (!preg_match("/^https?:\/\//", $value)) {
60
                continue;
61
            }
62
            ScanJob::dispatch($scanner_name[1], $value, $scan);
63
        }
64
65
        return response()->json(new ScanStatusResponse($scan));
66
    }
67
68
    public function GetResultById(int $id)
69
    {
70
        $scan = Scan::find($id);
71
72
        return response()->json(new ScanRawResultResponse($scan));
73
    }
74
75
    public function GetStatusById(int $id)
76
    {
77
        $scan = Scan::find($id);
78
79
        return response()->json(new ScanStatusResponse($scan));
80
    }
81
82
    public function status(Request $request)
83
    {
84
        //		$token  = Token::getTokenByString( ( $request->header( 'siwecosToken' ) ) );
85
        //		$domain = Domain::getDomainOrFail( $request->get( 'url'), $token->id  );
86
        $domain = Domain::whereDomain($request->get('url'))->first();
87
        $scan = Scan::whereUrl($domain->domain)->latest()->first();
88
        if ($scan instanceof Scan) {
89
            return response()->json(new ScanStatusResponse($scan));
90
        }
91
92
        return response('No results found', 422);
93
    }
94
95
    public function result(Request $request)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

95
    public function result(/** @scrutinizer ignore-unused */ Request $request)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
96
    {
97
        // to be implemented
98
    }
99
100
    /**
101
     * @param Request $request
102
     *
103
     * @return Scan
104
     */
105
    public function startFreeScan(Request $request)
106
    {
107
        $domainFilter = parse_url($request->json('domain'));
0 ignored issues
show
Bug introduced by
It seems like $request->json('domain') can also be of type Symfony\Component\HttpFoundation\ParameterBag; however, parameter $url of parse_url() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

107
        $domainFilter = parse_url(/** @scrutinizer ignore-type */ $request->json('domain'));
Loading history...
108
        $domain = $domainFilter['scheme'].'://'.$domainFilter['host'];
109
110
        //PING THE GIVEN DOMAIN
111
        if (!self::isDomainAlive($domain)) {
112
            Log::info('Domain not found '.$domain);
113
114
            return response('Domain not alive', 422);
0 ignored issues
show
Bug Best Practice introduced by
The expression return response('Domain not alive', 422) returns the type Illuminate\Contracts\Rou...HttpFoundation\Response which is incompatible with the documented return type App\Scan.
Loading history...
115
        }
116
117
        Log::info('Start Freescan for:'.$domain);
118
        /** @var Domain $freeScanDomain */
119
        $freeScanDomain = Domain::whereDomain($domain)->first();
120
121
        if ($freeScanDomain instanceof Domain) {
0 ignored issues
show
introduced by
$freeScanDomain is always a sub-type of App\Domain. If $freeScanDomain can have other possible types, add them to app/Http/Controllers/ScanController.php:118.
Loading history...
122
            //Domain already taken or another freescan has taken
123
            /* @var Scan $lastScan */
124
            //			$lastScan = $freeScanDomain->scans()->get()->last();
125
            //			if ( $lastScan instanceof Scan ) {
126
            //				// return minified Version
127
            //				return response()->json( new ScanStatusResponse( $lastScan ) );
128
            //			}
129
130
            return $this->startNewFreeScan($freeScanDomain);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->startNewFreeScan($freeScanDomain) returns the type Illuminate\Http\JsonResponse which is incompatible with the documented return type App\Scan.
Loading history...
131
        }
132
        $freeScanDomain = new Domain(['domain' => $domain]);
133
        $freeScanDomain->save();
134
135
        return $this->startNewFreeScan($freeScanDomain);
136
    }
137
138
    /**
139
     * Check if Domain is Alive or redirects (200 / 301).
140
     *
141
     * @param string $domain
142
     *
143
     * @return bool
144
     */
145
    public static function isDomainAlive(string $domain)
146
    {
147
        $client = new Client();
148
149
        try {
150
            $response = $client->get($domain);
151
            if ($response->getStatusCode() === 200 || $response->getStatusCode() === 301) {
152
                return true;
153
            }
154
        } catch (\Exception $ex) {
155
            Log::info($domain.' '.$ex->getMessage());
156
157
            return false;
158
        }
159
160
        return false;
161
    }
162
163
    protected function startNewFreeScan(Domain $freeScanDomain)
164
    {
165
        // start Scan and Broadcast Result afterwards
166
        /** @var Scan $scan */
167
        $scan = $freeScanDomain->scans()->create([
168
            'url'          => $freeScanDomain,
169
            'callbackurls' => [],
170
            'dangerLevel'  => 0,
171
            'freescan'     => true,
172
        ]);
173
        $scan->freescan = 1;
174
        $scan->save();
175
176
        // dispatch each scanner to the queue
177
        foreach ($_ENV as $key => $value) {
178
            if (!preg_match("/^SCANNER_(\w+)_URL$/", $key, $scanner_name)) {
179
                continue;
180
            }
181
            if (!preg_match("/^https?:\/\//", $value)) {
182
                continue;
183
            }
184
            ScanJob::dispatch($scanner_name[1], $value, $scan);
185
        }
186
187
        return response()->json(new ScanStatusResponse($scan));
188
    }
189
190
    public function getLastScanDate(string $format, string $domain)
191
    {
192
        /** @var Scan $currentLastScan */
193
        $domainReal = 'https://'.$domain;
194
        $currentLastScan = Scan::whereUrl($domainReal)->where('status', '3')->whereFreescan(0)->get()->last();
195
        if ($currentLastScan instanceof Scan) {
0 ignored issues
show
introduced by
$currentLastScan is always a sub-type of App\Scan. If $currentLastScan can have other possible types, add them to app/Http/Controllers/ScanController.php:192.
Loading history...
196
            return $currentLastScan->updated_at->format($format);
197
        }
198
        $domainReal = 'http://'.$domain;
199
        $currentLastScan = Scan::whereUrl($domainReal)->where('status', '3')->whereFreescan(0)->get()->last();
200
        if ($currentLastScan instanceof Scan) {
201
            return $currentLastScan->updated_at->format($format);
202
        }
203
204
        return response('No finished scan found', 422);
205
    }
206
207
    public function resultRaw(Request $request)
208
    {
209
        $token = Token::getTokenByString(($request->header('siwecosToken')));
210
        $domain = Domain::getDomainOrFail($request->get('domain'), $token->id);
211
        if ($domain instanceof Domain) {
0 ignored issues
show
introduced by
$domain is always a sub-type of App\Domain.
Loading history...
212
            $latestScan = Scan::whereUrl($domain->domain)->whereStatus(3)->latest()->first();
213
214
            if ($latestScan instanceof Scan) {
215
                return response()->json(new ScanRawResultResponse($latestScan));
216
            }
217
218
            return response('No finished scan found.', 404);
219
        }
220
221
        return response('No domain found', 404);
222
    }
223
224
    public function resultRawFree(Request $request)
225
    {
226
        $domain = Domain::whereDomain($request->get('domain'))->first();
227
        if ($domain instanceof Domain) {
228
            $latestScan = Scan::whereUrl($domain->domain)->whereFreescan(0)->whereStatus(3)->latest()->first();
229
230
            if ($latestScan instanceof Scan) {
231
                return response()->json(new ScanRawResultResponse($latestScan));
232
            }
233
234
            return response('No finished scan found.', 404);
235
        }
236
237
        return response('No domain found', 404);
238
    }
239
240
    // TODO: Check and Test
241
    public function callback(Request $request, int $scanId)
242
    {
243
244
        /** @var ScanResult $scanResult */
245
        $scanResult = ScanResult::findOrFail($scanId);
246
        Log::info($scanId.' / '.$scanResult->scan_id.' Callback: '.json_encode($request->json()->all()));
247
        if (!$request->json('hasError')) {
248
            Log::info($request->json('score').' für '.$scanResult->id);
0 ignored issues
show
Bug introduced by
Are you sure $request->json('score') of type Symfony\Component\HttpFo...tion\ParameterBag|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

248
            Log::info(/** @scrutinizer ignore-type */ $request->json('score').' für '.$scanResult->id);
Loading history...
249
            $scanResult->update([
250
                'result'      => $request->json('tests'),
251
                'total_score' => $request->json('score'),
252
            ]);
253
            $scanResult->total_score = $request->json('score');
254
            $scanResult->has_error = 0;
255
            $scanResult->complete_request = $request->json()->all();
256
            $scanResult->save();
257
            //   Sends the ScanResult to the given callback urls.
258
            foreach ($scanResult->scan->callbackurls as $callback) {
0 ignored issues
show
Bug introduced by
The expression $scanResult->scan->callbackurls of type string is not traversable.
Loading history...
259
                $client = new Client();
260
261
                $request = new Request('POST', $callback, [
0 ignored issues
show
Bug introduced by
'POST' of type string is incompatible with the type array expected by parameter $query of Illuminate\Http\Request::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

261
                $request = new Request(/** @scrutinizer ignore-type */ 'POST', $callback, [
Loading history...
262
                    'body' => $scanResult,
263
                ]);
264
265
                $client->sendAsync($request);
0 ignored issues
show
Bug introduced by
$request of type Illuminate\Http\Request is incompatible with the type Psr\Http\Message\RequestInterface expected by parameter $request of GuzzleHttp\Client::sendAsync(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

265
                $client->sendAsync(/** @scrutinizer ignore-type */ $request);
Loading history...
266
            }
267
        } else {
268
            $scanResult->update([
269
                'result'        => $request->json('tests'),
270
                'total_score'   => $request->json('score'),
271
                'error_message' => $request->json('errorMessage'),
272
            ]);
273
            $scanResult->has_error = 1;
274
            $scanResult->complete_request = $request->json()->all();
275
            $scanResult->save();
276
            $scanResult->save();
277
        }
278
279
        $this->updateScanStatus(Scan::find($scanResult->scan_id));
280
    }
281
282
    protected function updateScanStatus(Scan $scan)
283
    {
284
        Log::info('Get Progress from id: '.$scan->id.' for '.$scan->url);
285
        if ($scan->getProgress() >= 99) {
286
            $scan->update([
287
                'status' => 3,
288
289
            ]);
290
            Log::info('Ready to update '.$scan->id.' to status 3');
291
            // SCAN IS FINISHED! INFORM USER
292
            if ($scan->recurrentscan === 1 && $scan->results->count() === 5) {
0 ignored issues
show
introduced by
The condition $scan->recurrentscan === 1 is always false.
Loading history...
293
                //CHECK LAST NOTIFICATION
294
                // SHOULD FIX #28 IN BLA
295
                $domainString = $scan->url;
296
                Log::info('TRY TO GET DOMAIN OBJECT FOR '.$domainString);
297
                /** @var Domain $domain */
298
                $domain = Domain::whereDomain($domainString)->first();
299
                Log::info('SCAN FINISHED FOR'.$domainString.'//'.$domain->domain_token);
300
                $totalScore = 0;
301
                /** @var ScanResult $result */
302
                foreach ($scan->results() as $result) {
303
                    $totalScore += $result->total_score;
304
                }
305
306
                $totalScore /= 5;
307
                Log::info('TOTAL SCORE FOR DOMAIN '.$domain->domain.' // '.$totalScore);
308
                if ($domain instanceof Domain && ($domain->last_notification === null || $domain->last_notification < Carbon::now()->addWeeks(-1)) && $totalScore <= 50) {
309
                    Log::info('LAST NOTIFICATION FOR '.$domainString.' EARLIER THEN 1 WEEK');
310
                    $domain->last_notification = Carbon::now();
311
                    $domain->save();
312
                    $client = new Client();
313
                    $client->get(env('BLA_URL', 'https://api.siwecos.de/bla/current/public').'/api/v1/generateLowScoreReport/'.$scan->id);
314
                    Log::info('CONNECT REPORT GEN ON '.env('BLA_URL'));
315
                }
316
            }
317
            $scan->save();
318
            Log::info('Done updating   '.$scan->id.' to status 3');
319
            // Call broadcasting api from business layer
320
            $client = new Client();
321
            $client->get(env('BLA_URL', 'https://api.siwecos.de/bla/current/public').'/api/v1/freescan/'.$scan->id);
322
            Log::info('CONNECT FREESCAN ON '.env('BLA_URL'));
323
        }
324
    }
325
}
326