Issues (43)

src/Http/Controllers/WebhookController.php (1 issue)

Labels
Severity
1
<?php
2
/**
3
 * This file implements Webhook Controller.
4
 *
5
 * @author    Bilal Gultekin <[email protected]>
6
 * @author    Justin Hartman <[email protected]>
7
 * @copyright 2019 22 Digital
8
 * @license   MIT
9
 * @since     v0.1
10
 */
11
12
namespace TwentyTwoDigital\CashierFastspring\Http\Controllers;
13
14
use Exception;
15
use Illuminate\Http\Request;
16
use Illuminate\Routing\Controller;
17
use Illuminate\Support\Facades\Event;
18
use Illuminate\Support\Str;
19
use Log;
20
use Symfony\Component\HttpFoundation\Response;
21
use TwentyTwoDigital\CashierFastspring\Events;
22
use TwentyTwoDigital\CashierFastspring\Fastspring\Fastspring;
23
24
/**
25
 * Controls the data flow into a webhook object and updates the view
26
 * whenever data changes.
27
 *
28
 * {@inheritdoc}
29
 */
30
class WebhookController extends Controller
31
{
32
    /**
33
     * Handle a Fastspring webhook call.
34
     *
35
     * @param \Illuminate\Http\Request $request The webhook requet
36
     *
37
     * @throws Exception
38
     *
39
     * @return \Symfony\Component\HttpFoundation\Response
40
     */
41 5
    public function handleWebhook(Request $request)
42
    {
43 5
        $payload = json_decode($request->getContent(), true);
44
45
        // keep id of successfully managed events
46 5
        $successfulEvents = [];
47
48 5
        $hmacSecret = getenv('FASTSPRING_HMAC_SECRET') === false
49 5
            ? config('services.fastspring.hmac_secret')
50 5
            : getenv('FASTSPRING_HMAC_SECRET');
51
52
        // we try to be sure about
53
        // message integrity and authentication of message
54 5
        if ($hmacSecret) {
55 2
            $signature = $request->header('X-FS-Signature');
56
57
            // generate signature to check
58 2
            $generatedSignature = base64_encode(hash_hmac('sha256', $request->getContent(), $hmacSecret, true));
0 ignored issues
show
It seems like $request->getContent() can also be of type resource; however, parameter $data of hash_hmac() 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

58
            $generatedSignature = base64_encode(hash_hmac('sha256', /** @scrutinizer ignore-type */ $request->getContent(), $hmacSecret, true));
Loading history...
59
60
            // check if equals
61 2
            if ($signature != $generatedSignature) {
62
                // if not that means
63
                // someone trying to fool you
64
                // or you misconfigured your settings
65 1
                throw new Exception('Message security violation, MAC is wrong!');
66
            }
67
        }
68
69
        // iterate and trigger events
70 4
        foreach ($payload['events'] as $event) {
71
            // prepare category event class names like OrderAny
72 4
            $explodedType = explode('.', $event['type']);
73 4
            $category = array_shift($explodedType);
74 4
            $categoryEvent = '\TwentyTwoDigital\CashierFastspring\Events\\' . Str::studly($category) . 'Any';
75
76
            // prepare category event class names like activity
77 4
            $activity = str_replace('.', ' ', $event['type']);
78 4
            $activityEvent = '\TwentyTwoDigital\CashierFastspring\Events\\' . Str::studly($activity);
79
80
            // there may be some exceptions on events
81
            // so if anything goes bad its ID won't be added on the successfullEvents
82
            // and these events won't be marked as processed on fastspring side
83
            // so that will make events more manageable
84
            try {
85
                // check if the related event classes are exist
86
                // there may be not handled events
87 4
                if (!class_exists($categoryEvent) || !class_exists($activityEvent)) {
88 1
                    throw new Exception('There is no event for ' . $event['type']);
89
                }
90
91
                // trigger events
92 4
                Event::dispatch(
93 4
                    new Events\Any(
94 4
                        $event['id'],
95 4
                        $event['type'],
96 4
                        $event['live'],
97 4
                        $event['processed'],
98 4
                        $event['created'],
99 4
                        $event['data']
100
                    )
101
                );
102
103 4
                Event::dispatch(
104 4
                    new $categoryEvent(
105 4
                        $event['id'],
106 4
                        $event['type'],
107 4
                        $event['live'],
108 4
                        $event['processed'],
109 4
                        $event['created'],
110 4
                        $event['data']
111
                    )
112
                );
113
114 4
                Event::dispatch(
115 4
                    new $activityEvent(
116 4
                        $event['id'],
117 4
                        $event['type'],
118 4
                        $event['live'],
119 4
                        $event['processed'],
120 4
                        $event['created'],
121 4
                        $event['data']
122
                    )
123
                );
124
125
                // add event id to successful events
126 4
                $successfulEvents[] = $event['id'];
127 1
            } catch (Exception $e) {
128
                // log the exception
129
                // and continue to iterate
130
131 4
                Log::error($e);
132
            }
133
        }
134
135
        // return successful ids of events to mark them processed
136 4
        return new Response(implode("\n", $successfulEvents), 202);
137
    }
138
}
139