4
4
5
5
use Closure ;
6
6
use Illuminate \Http \Request ;
7
- use Illuminate \Contracts \Config \Repository ;
8
7
use SoapBox \SignedRequests \Requests \Verifier ;
8
+ use Illuminate \Contracts \Cache \Repository as Cache ;
9
+ use Illuminate \Contracts \Config \Repository as Configurations ;
10
+ use SoapBox \SignedRequests \Exceptions \ExpiredRequestException ;
9
11
use SoapBox \SignedRequests \Exceptions \InvalidSignatureException ;
10
12
11
13
class VerifySignature
@@ -17,17 +19,28 @@ class VerifySignature
17
19
*/
18
20
protected $ configurations ;
19
21
22
+ /**
23
+ * An instance of the cache repository.
24
+ *
25
+ * @var \Illuminate\Contracts\Cache\Repository
26
+ */
27
+ protected $ cache ;
28
+
20
29
/**
21
30
* Expect an instance of the configurations repository so we can lookup
22
31
* where to find our signature, algorithm, and key from.
23
32
*
24
33
* @param \Illuminate\Contracts\Config\Repository $configurations
25
34
* An instance of the Illuminate configurations repository to lookup
26
35
* configurations with.
36
+ * @param \Illuminate\Contracts\Cache\Repository $cache
37
+ * An instance of the Illuminate cache repository for preventing
38
+ * replay attacks.
27
39
*/
28
- public function __construct (Repository $ configurations )
40
+ public function __construct (Configurations $ configurations, Cache $ cache )
29
41
{
30
42
$ this ->configurations = $ configurations ;
43
+ $ this ->cache = $ cache ;
31
44
}
32
45
33
46
/**
@@ -36,6 +49,10 @@ public function __construct(Repository $configurations)
36
49
*
37
50
* @throws \SoapBox\SignedRequests\Exceptions\InvalidSignatureException
38
51
* Thrown when the signature of the request is not valid.
52
+ * @throws \SoapBox\SignedRequests\Exceptions\ExpiredRequestException
53
+ * Thrown if request replays are disabled and either the request
54
+ * timestamp is outside the window of tolerance, or the request has
55
+ * previously been served.
39
56
*
40
57
* @param \Illuminate\Http\Request $request
41
58
* An instance of the request.
@@ -48,6 +65,22 @@ public function handle(Request $request, Closure $next)
48
65
{
49
66
$ signed = new Verifier ($ request );
50
67
68
+ $ key = sprintf (
69
+ '%s.%s ' ,
70
+ $ this ->configurations ->get ('signed-requests.cache-prefix ' ),
71
+ $ signed ->getId ()
72
+ );
73
+
74
+ $ tolerance = $ this ->configurations ->get ('signed-requests.request-replay.tolerance ' );
75
+
76
+ if (false == $ this ->configurations ->get ('signed-requests.request-replay.allow ' )) {
77
+ $ isExpired = $ signed ->isExpired ($ tolerance );
78
+
79
+ if ($ isExpired || $ this ->cache ->has ($ key )) {
80
+ throw new ExpiredRequestException ();
81
+ }
82
+ }
83
+
51
84
$ signed
52
85
->setSignatureHeader ($ this ->configurations ->get ('signed-requests.headers.signature ' ))
53
86
->setAlgorithmHeader ($ this ->configurations ->get ('signed-requests.headers.algorithm ' ));
@@ -56,6 +89,8 @@ public function handle(Request $request, Closure $next)
56
89
throw new InvalidSignatureException ();
57
90
}
58
91
92
+ $ this ->cache ->put ($ key , $ key , $ tolerance / 60 );
93
+
59
94
return $ next ($ request );
60
95
}
61
96
}
0 commit comments