Completed
Push — master ( 5e8dd9...520f05 )
by Arnold
02:32
created

Confirmation   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 115
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 10
lcom 1
cbo 2
dl 0
loc 115
ccs 28
cts 28
cp 1
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
fetchUserById() 0 1 ?
getConfirmationSecret() 0 1 ?
A createHashids() 0 12 2
A getConfirmationChecksum() 0 5 1
A getConfirmationToken() 0 11 2
B fetchUserForConfirmation() 0 28 5
1
<?php
2
3
namespace Jasny\Auth;
4
5
use Hashids\Hashids;
6
7
/**
8
 * Generate and verify confirmation tokens.
9
 * 
10
 * Uses the hashids library.
11
 * @link http://hashids.org/php/
12
 * 
13
 * <code>
14
 * class Auth extends Jasny\Auth
15
 * {
16
 *   use Jasny\Auth\Confirmation;
17
 * 
18
 *   public function getConfirmationSecret()
19
 *   {
20
 *     return "f)lk3sd^92qlj$%f8321*(&lk";
21
 *   }
22
 * 
23
 *   ...
24
 * }
25
 * </code>
26
 */
27
trait Confirmation
28
{
29
    /**
30
     * Fetch a user by ID
31
     * 
32
     * @param int|string $id
33
     * @return User|null
34
     */
35
    abstract public function fetchUserById($id);
36
    
37
    /**
38
     * Get secret for the confirmation hash
39
     * 
40
     * @return string
41
     */
42
    abstract protected function getConfirmationSecret();
43
44
    
45
    /**
46
     * Create a heashids interface
47
     * 
48
     * @param string $secret
0 ignored issues
show
Bug introduced by
There is no parameter named $secret. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
49
     * @return Hashids
50
     */
51 12
    protected function createHashids($subject)
52
    {
53 12
        if (!class_exists(Hashids::class)) {
54
            // @codeCoverageIgnoreStart
55
            throw new \Exception("Unable to generate a confirmation hash: Hashids library is not installed");
56
            // @codeCoverageIgnoreEnd
57
        }
58
        
59 12
        $salt = hash('sha256', $this->getConfirmationSecret() . $subject);
60
        
61 12
        return new Hashids($salt);
62
    }
63
    
64
    /**
65
     * Generate a confirm checksum based on a user id and secret.
66
     * 
67
     * For more entropy overwrite this method:
68
     * <code>
69
     *   protected function getConfirmationChecksum($id, $entropy = 32)
70
     *   {
71
     *     return parent::getConfirmationChecksum($id, $entropy);
72
     *   }
73
     * </code>
74
     * 
75
     * @param string $id
76
     * @param int    $len  The number of integers (between 12 and 64)
77
     * @return int
78
     */
79 9
    protected function getConfirmationChecksum($id, $len = 12)
80
    {
81 9
        $hash = hash('sha256', $id . $this->getConfirmationSecret());
82 9
        return substr($hash, 0, $len);
83
    }
84
    
85
    /**
86
     * Generate a confirmation token
87
     * 
88
     * @param User    $user
89
     * @param string  $subject      What needs to be confirmed?
90
     * @param boolean $usePassword  Use password hash in checksum
91
     * @return string
92
     */
93 3
    public function getConfirmationToken(User $user, $subject, $usePassword = false)
94
    {
95 3
        $hashids = $this->createHashids($subject);
96
        
97 3
        $id = $user->getId();
98 3
        $pwd = $usePassword ? $user->getHashedPassword() : '';
99
        
100 3
        $confirm = $this->getConfirmationChecksum($id . $pwd);
101
        
102 3
        return $hashids->encodeHex($confirm . $id);
103
    }
104
    
105
    /**
106
     * Get user by confirmation hash
107
     * 
108
     * @param string $token    Confirmation token
109
     * @param string $subject  What needs to be confirmed?
110
     * @param boolean $usePassword  Use password hash in checksum
111
     * @return User|null
112
     */
113 9
    public function fetchUserForConfirmation($token, $subject, $usePassword = false)
114
    {
115 9
        $hashids = $this->createHashids($subject);
116
        
117 9
        $idAndConfirm = $hashids->decodeHex($token);
118
        
119 9
        if (empty($idAndConfirm)) {
120 3
            return null;
121
        }
122
        
123 6
        $len = strlen($this->getConfirmationChecksum(''));
124 6
        $id = substr($idAndConfirm, $len);
125 6
        $confirm = substr($idAndConfirm, 0, $len);
126
        
127 6
        $user = $this->fetchUserById($id);
128
129 6
        if (!isset($user)) {
130 1
            return null;
131
        }
132
        
133 5
        $pwd = $usePassword ? $user->getHashedPassword() : '';
134
        
135 5
        if ($confirm !== $this->getConfirmationChecksum($id . $pwd)) {
136 2
            return null;
137
        }
138
        
139 3
        return $user;
140
    }
141
}
142