Completed
Push — master ( 3bbd71...e8f989 )
by Philip
02:35
created

UserSetup::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 6
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
/*
4
 * This file is part of the CRUDlexUser package.
5
 *
6
 * (c) Philip Lehmann-Böhm <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace CRUDlex;
13
14
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
15
use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder;
16
use CRUDlex\AbstractData;
17
use CRUDlex\Entity;
18
19
/**
20
 * This class setups CRUDlex with some events so the passwords get salted and
21
 * hashed properly.
22
 */
23
class UserSetup {
24
25
	/**
26
	 * The encoder to use.
27
	 */
28
	protected $encoder;
29
30
    /**
31
     * Gets a closure for possibly generating a password hash in the entity.
32
     *
33
     * @param AbstractData $data
34
     * the AbstractData instance managing the users
35
     *
36
     * @param string $passwordField
37
     * the Entity fieldname of the password hash
38
     *
39
     * @param string $saltField
40
     * the Entity fieldname of the password hash salt
41
     */
42
    protected function getPWHashFunction(AbstractData $data, $passwordField, $saltField) {
43
        $that = $this;
44
        return function(Entity $entity) use ($data, $passwordField, $saltField, $that) {
45
            $password = $entity->get($passwordField);
46
47
            if (!$password) {
48
                return true;
49
            }
50
51
            $salt = $entity->get($saltField);
52
            $newSalt = $that->possibleGenSalt($salt, $entity, $saltField);
53
54
            $passwordHash = $this->encoder->encodePassword($password, $salt);
55
56
            $doGenerateHash = $that->doGenerateHash($data, $entity, $passwordField, $password, $newSalt);
57
58
            if ($doGenerateHash) {
59
                $entity->set($passwordField, $passwordHash);
60
            }
61
            return true;
62
        };
63
    }
64
    
65
    /**
66
     * Constructor.
67
     *
68
     * @param PasswordEncoderInterface $encoder
69
     * the encoder to use, defaults to BCryptPasswordEncoder if null is given
70
     */
71
    public function __construct(PasswordEncoderInterface $encoder = null) {
0 ignored issues
show
Unused Code introduced by
The parameter $encoder is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
72
    	$this->encoder = $passwordEncoder;
0 ignored issues
show
Bug introduced by
The variable $passwordEncoder does not exist. Did you mean $encoder?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
73
    	if ($this->encoder === null) {
74
    		$this->encoder = new BCryptPasswordEncoder(13);
75
    	}
76
    }
77
78
    /**
79
     * Generates a new salt if the given salt is null.
80
     *
81
     * @param string $salt
82
     * the salt to override if null
83
     * @param Entity
84
     * the entity getting the new salt
85
     * @param string $saltField
86
     * the field holding the salt in the entity
87
     *
88
     * @return boolean
89
     * true if a new salt was generated
90
     */
91
    public function possibleGenSalt(&$salt, Entity $entity, $saltField) {
92
        if (!$salt) {
93
            $salt = $this->getSalt(40);
94
            $entity->set($saltField, $salt);
95
            return true;
96
        }
97
        return false;
98
    }
99
100
    /**
101
     * Determines whether the entity needs a new hash generated.
102
     *
103
     * @param AbstractData $data
104
     * the CRUDlex data instance of the user entity
105
     * @param Entity $entity
106
     * the entity
107
     * @param string $passwordField
108
     * the field holding the password hash in the entity
109
     * @param string $password
110
     * the current password hash
111
     * @param boolean $newSalt
112
     * whether a new password hash salt was generated
113
     *
114
     * @return boolean
115
     * true if the entity needs a new hash
116
     */
117
    public function doGenerateHash(AbstractData $data, Entity $entity, $passwordField, $password, $newSalt) {
118
        $doGenerateHash = true;
119
        $id = $entity->get('id');
120
        if ($id !== null) {
121
            $oldEntity = $data->get($entity->get('id'));
122
            $doGenerateHash = $oldEntity->get($passwordField) !== $password || $newSalt;
123
        }
124
        return $doGenerateHash;
125
    }
126
127
    /**
128
     * Generates a random salt of the given length.
129
     *
130
     * @param int $len
131
     * the desired length
132
     *
133
     * @return string
134
     * a random salt of the given length
135
     */
136
    public function getSalt($len) {
137
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()-=_+';
138
        $l = strlen($chars) - 1;
139
        $str = '';
140
        for ($i = 0; $i < $len; ++$i) {
141
            $str .= $chars[mt_rand(0, $l)];
142
        }
143
        return $str;
144
    }
145
146
    /**
147
     * Setups CRUDlex with some events so the passwords get salted and
148
     * hashed properly.
149
     *
150
     * @param AbstractData $data
151
     * the AbstractData instance managing the users
152
     *
153
     * @param string $passwordField
154
     * the Entity fieldname of the password hash
155
     *
156
     * @param string $saltField
157
     * the Entity fieldname of the password hash salt
158
     */
159
    public function addEvents(AbstractData $data, $passwordField = 'password', $saltField = 'salt') {
160
161
        $that = $this;
162
        $saltGenFunction = function(Entity $entity) use ($saltField, $that) {
163
            $salt = $that->getSalt(40);
164
            $entity->set($saltField, $salt);
165
            return true;
166
        };
167
168
        $data->pushEvent('before', 'create', $saltGenFunction);
169
170
        $pwHashFunction = $this->getPWHashFunction($data, $passwordField, $saltField);
171
172
        $data->pushEvent('before', 'create', $pwHashFunction);
173
        $data->pushEvent('before', 'update', $pwHashFunction);
174
175
    }
176
177
}
178