Completed
Push — master ( 9dab44...8bd79e )
by Robbie
02:00
created

src/Model/Comment/SecurityToken.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SilverStripe\Comments\Model\Comment;
4
5
use SilverStripe\Control\Controller;
6
use SilverStripe\Security\Member;
7
use SilverStripe\Security\RandomGenerator;
8
9
/**
10
 * Provides the ability to generate cryptographically secure tokens for comment moderation
11
 */
12
class SecurityToken
13
{
14
    /**
15
     * @var string
16
     */
17
    private $secret = null;
18
19
    /**
20
     * @param Comment $comment Comment to generate this token for
21
     */
22
    public function __construct($comment)
23
    {
24
        if (!$comment->SecretToken) {
25
            $comment->SecretToken = $this->generate();
26
            $comment->write();
27
        }
28
        $this->secret = $comment->SecretToken;
29
    }
30
31
    /**
32
     * Generate the token for the given salt and current secret
33
     *
34
     * @param string $salt
35
     *
36
     * @return string
37
     */
38
    protected function getToken($salt)
39
    {
40
        return hash_pbkdf2('sha256', $this->secret, $salt, 1000, 30);
41
    }
42
43
    /**
44
     * Get the member-specific salt.
45
     *
46
     * The reason for making the salt specific to a user is that it cannot be "passed in" via a
47
     * querystring, requiring the same user to be present at both the link generation and the
48
     * controller action.
49
     *
50
     * @param string $salt   Single use salt
51
     * @param Member $member Member object
52
     *
53
     * @return string Generated salt specific to this member
54
     */
55
    protected function memberSalt($salt, $member)
56
    {
57
        // Fallback to salting with ID in case the member has not one set
58
        return $salt . ($member->Salt ?: $member->ID);
59
    }
60
61
    /**
62
     * @param string $url    Comment action URL
63
     * @param Member $member Member to restrict access to this action to
64
     *
65
     * @return string
66
     */
67
    public function addToUrl($url, $member)
68
    {
69
        $salt = $this->generate(15); // New random salt; Will be passed into url
70
        // Generate salt specific to this member
71
        $memberSalt = $this->memberSalt($salt, $member);
72
        $token = $this->getToken($memberSalt);
73
        return Controller::join_links(
74
            $url,
75
            sprintf(
76
                '?t=%s&s=%s',
77
                urlencode($token),
78
                urlencode($salt)
79
            )
80
        );
81
    }
82
83
    /**
84
     * @param SS_HTTPRequest $request
85
     *
86
     * @return boolean
87
     */
88
    public function checkRequest($request)
89
    {
90
        $member = Member::currentUser();
0 ignored issues
show
Deprecated Code introduced by
The method SilverStripe\Security\Member::currentUser() has been deprecated with message: 5.0.0 use Security::getCurrentUser()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
91
        if (!$member) {
92
            return false;
93
        }
94
95
        $salt = $request->getVar('s');
96
        $memberSalt = $this->memberSalt($salt, $member);
97
        $token = $this->getToken($memberSalt);
98
99
        // Ensure tokens match
100
        return $token === $request->getVar('t');
101
    }
102
103
104
    /**
105
     * Generates new random key
106
     *
107
     * @param integer $length
0 ignored issues
show
Should the type for parameter $length not be integer|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
108
     *
109
     * @return string
110
     */
111
    protected function generate($length = null)
112
    {
113
        $generator = new RandomGenerator();
114
        $result = $generator->randomToken('sha256');
115
        if ($length !== null) {
116
            return substr($result, 0, $length);
117
        }
118
        return $result;
119
    }
120
}
121