Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.07% covered (success)
91.07%
51 / 56
85.71% covered (warning)
85.71%
6 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
Helper
91.07% covered (success)
91.07%
51 / 56
85.71% covered (warning)
85.71%
6 / 7
19.26
0.00% covered (danger)
0.00%
0 / 1
 isRequestForApiV2
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 isRequestForApiV4
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getRouteName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getRoutePrefix
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
3
 getRoute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getPackageInfo
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 signRequest
88.37% covered (warning)
88.37%
38 / 43
0.00% covered (danger)
0.00%
0 / 1
7.08
1<?php
2
3namespace App\Lib;
4
5use App\Exceptions\Api\V4\CrmException;
6use Illuminate\Contracts\Encryption\DecryptException;
7use Illuminate\Http\Request;
8use Illuminate\Support\Facades\Crypt;
9use Illuminate\Support\Facades\Route;
10
11/**
12 * Helper Class
13 */
14class Helper
15{
16    /**
17     * Package infos.
18     *
19     * @var array
20     */
21    private static $packageInfos;
22
23    /**
24     * Tells if the request is within apiV2 routes.
25     *
26     * @param \Illuminate\Http\Request $request
27     * @return boolean
28     */
29    public static function isRequestForApiV2(Request $request): bool
30    {
31        // * Small hack to ensure to know if route is From APIv2.
32        $routeName = static::getRouteName($request) ??
33            (strpos($request->path(), 'api/v2') === 0 ? 'apiV2.' : null) ?? 'none';
34        return strpos($routeName, 'apiV2.') === 0;
35    }
36
37    /**
38     * Tells if the request is within apiV4 routes.
39     *
40     * @param \Illuminate\Http\Request $request
41     * @return boolean
42     */
43    public static function isRequestForApiV4(Request $request): bool
44    {
45        // * Small hack to ensure to know if route is From APIv4.
46        $routeName = static::getRouteName($request) ??
47            (strpos($request->path(), 'api/v4') === 0 ? 'apiV4.' : null) ?? 'none';
48        return strpos($routeName, 'apiV4.') === 0;
49    }
50
51    /**
52     * Try to get current route name
53     *
54     * @param \Illuminate\Http\Request $request
55     * @return string|null
56     */
57    public static function getRouteName(Request $request): ?string
58    {
59        return Route::currentRouteName() ?? ($request->route() ? $request->route()->getName() : null);
60    }
61
62    /**
63     * Try to get current route prefix.
64     *
65     * @param \Illuminate\Http\Request $request
66     * @return string|null
67     */
68    public static function getRoutePrefix(Request $request): ?string
69    {
70        return (Route::getCurrentRoute() ? Route::getCurrentRoute()->getPrefix() : null) ??
71            ($request->route() ? $request->route()->getPrefix() : null);
72    }
73
74    /**
75     * Try to get route from request.
76     *
77     * @param \Illuminate\Http\Request $request
78     * @return \Illuminate\Routing\Route|null
79     */
80    public static function getRoute(Request $request): \Illuminate\Routing\Route|null
81    {
82        return Route::getRoutes()->getByName(static::getRouteName($request));
83    }
84
85    /**
86     * Get composer.json infos.
87     *
88     * @return array
89     */
90    public static function getPackageInfo(): array
91    {
92        if (!static::$packageInfos) {
93            static::$packageInfos = \json_decode(\file_get_contents(__DIR__ . '/../../composer.json'), true);
94        }
95        return static::$packageInfos;
96    }
97
98    /**
99     * Calculate the request signature.
100     *
101     * @param string $secret
102     * @param string $uri
103     * @param string $method
104     * @param array  $parameters
105     * @return string request signature
106     * @throws \App\Exceptions\Api\V4\CrmException If an error occurs.
107     */
108    public static function signRequest(string $secret, string $uri, string $method, array $parameters): string
109    {
110        try {
111            $uri    = collect(\parse_url($uri));
112            $method = \strtolower($method);
113
114            // * Remove signature from parameters to calculate the hashmac.
115            $signature = collect([
116                'uri' => sprintf(
117                    '%s://%s%s',
118                    $uri->get('scheme'),
119                    $uri->get('host'),
120                    $uri->get('path')
121                ),
122                'method' => $method
123            ]);
124
125            $flattenRequestArray = function (array $array) use (&$flattenRequestArray) {
126                $out = [];
127                foreach ($array as $key => $value) {
128                    if (is_array($value)) {
129                        $subArray = $flattenRequestArray($value);
130                        foreach ($subArray as $subKey => $subValue) {
131                            $out["$key.$subKey"] = $subValue;
132                        }
133                        continue;
134                    }
135                    $out[$key] = $value;
136                }
137                return $out;
138            };
139
140            $parameters = $flattenRequestArray($parameters);
141            $parameters = collect($parameters);
142
143            // * Remove signature from parameters.
144            $parameters->pull('signature');
145
146            // * Natural sort all parameters.
147            $parameters = $parameters->sortKeys(\SORT_NATURAL)
148                ->map(function ($value, $key) {
149                    return sprintf('%s=%s', \rawurlencode($key), \rawurlencode($value));
150                });
151
152            $signature->push($parameters->implode('&'));
153
154            $calculatedHash = base64_encode(hash_hmac(
155                'sha256',
156                $signature->implode('\n'),
157                Crypt::decryptString($secret),
158                true
159            ));
160
161            if (!$calculatedHash) {
162                throw new CrmException('Failed to calculate requests hash');
163            }
164
165            return $calculatedHash;
166        } catch (DecryptException $e) {
167            throw new CrmException('Failed to decrypt service credentials', 0, $e);
168        } catch (\Exception $e) {
169            throw new CrmException('An error occured when authenticating service', 0, $e);
170        } //end try
171    }
172}