|
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); |
|
|
|
|
|
|
30
|
|
|
} |
|
31
|
|
|
} |
|
32
|
|
|
|
|
33
|
|
|
public static function startScanJob(Token $token, string $domain, bool $isRecurrent = false, int $dangerLevel = 0, bool $isRegistered = false) |
|
|
|
|
|
|
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) |
|
|
|
|
|
|
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')); |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
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); |
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
259
|
|
|
$client = new Client(); |
|
260
|
|
|
|
|
261
|
|
|
$request = new Request('POST', $callback, [ |
|
|
|
|
|
|
262
|
|
|
'body' => $scanResult, |
|
263
|
|
|
]); |
|
264
|
|
|
|
|
265
|
|
|
$client->sendAsync($request); |
|
|
|
|
|
|
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) { |
|
|
|
|
|
|
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
|
|
|
|