]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Core/Password.php
Factorize
[galette.git] / galette / lib / Galette / Core / Password.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Password for galette. The original code was found
7 * in includes/functions.inc.php
8 *
9 * PHP version 5
10 *
11 * Copyright © 2003-2020 The Galette Team
12 *
13 * This file is part of Galette (http://galette.tuxfamily.org).
14 *
15 * Galette is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * Galette is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
27 *
28 * @category Core
29 * @package Galette
30 *
31 * @author Frédéric Jacquot <unknown@unknow.com>
32 * @author Georges Khaznadar (password encryption, images) <unknown@unknow.com>
33 * @author Johan Cwiklinski <johan@x-tnd.be>
34 * @copyright 2003-2014 The Galette Team
35 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
36 * @link http://galette.tuxfamily.org
37 * @since Available since 0.7dev - 2009-02-28
38 */
39
40 namespace Galette\Core;
41
42 use Throwable;
43 use Analog\Analog;
44 use Galette\Entity\Adherent;
45
46 /**
47 * Temporary password management
48 *
49 * @category Core
50 * @name Password
51 * @package Galette
52 * @author Frédéric Jacquot <unknown@unknow.com>
53 * @author Georges Khaznadar (password encryption, images) <unknown@unknow.com>
54 * @author Johan Cwiklinski <johan@x-tnd.be>
55 * @copyright 2009-2020 The Galette Team
56 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
57 * @link http://galette.tuxfamily.org
58 * @since Available since 0.7dev - 2011-06-16
59 */
60
61 class Password extends AbstractPassword
62 {
63 public const TABLE = 'tmppasswds';
64 public const PK = Adherent::PK;
65
66 /** @var integer Overrides default password size */
67 public const DEFAULT_SIZE = 50;
68 /** @var string Overrides default character set */
69 protected $chars = 'abcdefghjkmnpqrstuvwxyz0123456789&@{[]}%#+*:ABCDEFGHIJKLMNOPQRSTUVWXYZ';
70
71 private $zdb;
72
73 /**
74 * Default constructor
75 *
76 * @param Db $zdb Database instance:
77 * @param boolean $clean Whether we should clean expired passwords in database
78 */
79 public function __construct(Db $zdb, bool $clean = true)
80 {
81 $this->zdb = $zdb;
82 if ($clean === true) {
83 $this->cleanExpired();
84 }
85 }
86
87 /**
88 * Remove all old password entries
89 *
90 * @param int $id_adh Member identifier
91 *
92 * @return boolean
93 */
94 private function removeOldEntries(int $id_adh): bool
95 {
96 try {
97 $delete = $this->zdb->delete(self::TABLE);
98 $delete->where(self::PK . ' = ' . $id_adh);
99
100 $del = $this->zdb->execute($delete);
101 if ($del) {
102 Analog::log(
103 'Temporary passwords for `' . $id_adh . '` has been removed.',
104 Analog::DEBUG
105 );
106 }
107 return true;
108 } catch (Throwable $e) {
109 Analog::log(
110 'An error has occurred removing old tmppasswords ' .
111 $e->getMessage(),
112 Analog::ERROR
113 );
114 return false;
115 }
116 }
117
118 /**
119 * Generates a new password for specified member
120 *
121 * @param int $id_adh Member identifier
122 *
123 * @return boolean
124 */
125 public function generateNewPassword($id_adh): bool
126 {
127 //first of all, we'll remove all existant entries for specified id
128 $this->removeOldEntries($id_adh);
129
130 //second, generate a new password and store it in the database
131 $password = $this->makeRandomPassword();
132 $hash = password_hash($password, PASSWORD_BCRYPT);
133
134 try {
135 $values = array(
136 self::PK => $id_adh,
137 'tmp_passwd' => $hash,
138 'date_crea_tmp_passwd' => date('Y-m-d H:i:s')
139 );
140
141 $insert = $this->zdb->insert(self::TABLE);
142 $insert->values($values);
143
144 $add = $this->zdb->execute($insert);
145 if ($add) {
146 Analog::log(
147 'New passwords temporary set for `' . $id_adh . '`.',
148 Analog::DEBUG
149 );
150 $this->setPassword($password);
151 $this->setHash($hash);
152 return true;
153 } else {
154 return false;
155 }
156 } catch (Throwable $e) {
157 Analog::log(
158 "An error occurred trying to add temporary password entry. " .
159 $e->getMessage(),
160 Analog::ERROR
161 );
162 return false;
163 }
164 }
165
166 /**
167 * Remove expired passwords queries (older than 24 hours)
168 *
169 * @return boolean
170 */
171 protected function cleanExpired(): bool
172 {
173 $date = new \DateTime();
174 $date->sub(new \DateInterval('PT24H'));
175
176 try {
177 $delete = $this->zdb->delete(self::TABLE);
178 $delete->where->lessThan(
179 'date_crea_tmp_passwd',
180 $date->format('Y-m-d H:i:s')
181 );
182 $del = $this->zdb->execute($delete);
183 if ($del) {
184 Analog::log(
185 'Old Temporary passwords have been deleted.',
186 Analog::DEBUG
187 );
188 }
189 return true;
190 } catch (Throwable $e) {
191 Analog::log(
192 'An error occurred deleting expired temporary passwords. ' .
193 $e->getMessage(),
194 Analog::WARNING
195 );
196 return false;
197 }
198 }
199
200 /**
201 * Check if requested hash is valid
202 *
203 * @param string $hash the hash
204 *
205 * @return false|int false if hash is not valid, member id otherwise
206 */
207 public function isHashValid(string $hash)
208 {
209 try {
210 $select = $this->zdb->select(self::TABLE);
211 $select->columns(
212 array(self::PK)
213 )->where(array('tmp_passwd' => $hash));
214
215 $results = $this->zdb->execute($select);
216
217 if ($results->count() > 0) {
218 $result = $results->current();
219 $pk = self::PK;
220 return $result->$pk;
221 } else {
222 return false;
223 }
224 } catch (Throwable $e) {
225 Analog::log(
226 'An error occurred getting requested hash. ' . $e->getMessage(),
227 Analog::WARNING
228 );
229 return false;
230 }
231 }
232
233 /**
234 * Remove a hash that has been used (ie. once password has been updated)
235 *
236 * @param string $hash hash
237 *
238 * @return boolean
239 */
240 public function removeHash(string $hash): bool
241 {
242 try {
243 $delete = $this->zdb->delete(self::TABLE);
244 $delete->where(
245 array('tmp_passwd' => $hash)
246 );
247
248 $del = $this->zdb->execute($delete);
249 if ($del) {
250 Analog::log(
251 'Used hash has been successfully remove',
252 Analog::DEBUG
253 );
254 return true;
255 }
256 } catch (Throwable $e) {
257 Analog::log(
258 'An error occurred attempting to delete used hash' .
259 $e->getMessage(),
260 Analog::WARNING
261 );
262 return false;
263 }
264 }
265 }