These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) |
||
4 | * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) |
||
5 | * |
||
6 | * Licensed under The MIT License |
||
7 | * For full copyright and license information, please see the LICENSE.txt |
||
8 | * Redistributions of files must retain the above copyright notice. |
||
9 | * |
||
10 | * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) |
||
11 | * @link http://cakephp.org CakePHP(tm) Project |
||
12 | * @since 3.0.0 |
||
13 | * @license http://www.opensource.org/licenses/mit-license.php MIT License |
||
14 | */ |
||
15 | namespace App\Console; |
||
16 | |||
17 | use Cake\Auth\DefaultPasswordHasher; |
||
18 | use Cake\Utility\Security; |
||
19 | use Composer\Script\Event; |
||
20 | use Exception; |
||
21 | |||
22 | /** |
||
23 | * Provides installation hooks for when this application is installed via |
||
24 | * composer. Customize this class to suit your needs. |
||
25 | */ |
||
26 | class Installer |
||
27 | { |
||
28 | |||
29 | /** |
||
30 | * Does some routine installation tasks so people don't have to. |
||
31 | * |
||
32 | * @param \Composer\Script\Event $event The composer event object. |
||
33 | * |
||
34 | * @return void |
||
35 | */ |
||
36 | public static function postInstall(Event $event) |
||
37 | { |
||
38 | $io = $event->getIO(); |
||
39 | |||
40 | $rootDir = dirname(dirname(__DIR__)); |
||
41 | static::createAppConfig($rootDir, $io); |
||
42 | static::createWritableDirectories($rootDir, $io); |
||
43 | static::createRecaptchaConfig($rootDir, $io); |
||
44 | static::createDatabaseConfig($rootDir, $io); |
||
45 | static::createEmailConfig($rootDir, $io); |
||
46 | static::setDatabaseName($rootDir, $io); |
||
47 | |||
48 | // ask if the permissions should be changed |
||
49 | if ($io->isInteractive()) { |
||
50 | $validator = function ($arg) { |
||
51 | if (in_array($arg, ['Y', 'y', 'N', 'n'])) { |
||
52 | return $arg; |
||
53 | } |
||
54 | throw new Exception('This is not a valid answer. Please choose Y or n.'); |
||
55 | }; |
||
56 | $setFolderPermissions = $io->askAndValidate( |
||
57 | '<info>Set Folder Permissions ? (Default to Y)</info> [<comment>Y,n</comment>]? ', |
||
58 | $validator, |
||
59 | 10, |
||
60 | 'Y' |
||
61 | ); |
||
62 | |||
63 | if (in_array($setFolderPermissions, ['Y', 'y'])) { |
||
64 | static::setFolderPermissions($rootDir, $io); |
||
65 | } |
||
66 | } else { |
||
67 | static::setFolderPermissions($rootDir, $io); |
||
68 | } |
||
69 | |||
70 | $newKey = static::setSecuritySaltAndKey($rootDir, $io); |
||
71 | static::setAccountPassword($rootDir, $io, $newKey); |
||
72 | |||
73 | if (class_exists('\Cake\Codeception\Console\Installer')) { |
||
74 | \Cake\Codeception\Console\Installer::customizeCodeceptionBinary($event); |
||
75 | } |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * Create the config/app.php file if it does not exist. |
||
80 | * |
||
81 | * @param string $dir The application's root directory. |
||
82 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
83 | * |
||
84 | * @return void |
||
85 | */ |
||
86 | View Code Duplication | public static function createAppConfig($dir, $io) |
|
0 ignored issues
–
show
|
|||
87 | { |
||
88 | $appConfig = $dir . '/config/app.php'; |
||
89 | $defaultConfig = $dir . '/config/app.default.php'; |
||
90 | if (!file_exists($appConfig)) { |
||
91 | copy($defaultConfig, $appConfig); |
||
92 | $io->write('Created `config/app.php` file'); |
||
93 | } |
||
94 | } |
||
95 | |||
96 | /** |
||
97 | * Create the config/database.php file if it does not exist. |
||
98 | * |
||
99 | * @param string $dir The application's root directory. |
||
100 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
101 | * |
||
102 | * @return void |
||
103 | */ |
||
104 | View Code Duplication | public static function createDatabaseConfig($dir, $io) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
105 | { |
||
106 | $databaseConfig = $dir . '/config/database.php'; |
||
107 | $defaultConfig = $dir . '/config/database.default.php'; |
||
108 | if (!file_exists($databaseConfig)) { |
||
109 | copy($defaultConfig, $databaseConfig); |
||
110 | $io->write('Created `config/database.php` file'); |
||
111 | } |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * Create the config/email.php file if it does not exist. |
||
116 | * |
||
117 | * @param string $dir The application's root directory. |
||
118 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
119 | * |
||
120 | * @return void |
||
121 | */ |
||
122 | View Code Duplication | public static function createEmailConfig($dir, $io) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
123 | { |
||
124 | $databaseConfig = $dir . '/config/email.php'; |
||
125 | $defaultConfig = $dir . '/config/email.default.php'; |
||
126 | if (!file_exists($databaseConfig)) { |
||
127 | copy($defaultConfig, $databaseConfig); |
||
128 | $io->write('Created `config/email.php` file'); |
||
129 | } |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * Create the `logs` and `tmp` directories. |
||
134 | * |
||
135 | * @param string $dir The application's root directory. |
||
136 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
137 | * @return void |
||
138 | */ |
||
139 | public static function createWritableDirectories($dir, $io) |
||
140 | { |
||
141 | $paths = [ |
||
142 | 'logs', |
||
143 | 'tmp', |
||
144 | 'tmp/cache', |
||
145 | 'tmp/cache/models', |
||
146 | 'tmp/cache/persistent', |
||
147 | 'tmp/cache/views', |
||
148 | 'tmp/sessions', |
||
149 | 'tmp/tests' |
||
150 | ]; |
||
151 | |||
152 | foreach ($paths as $path) { |
||
153 | $path = $dir . '/' . $path; |
||
154 | if (!file_exists($path)) { |
||
155 | mkdir($path); |
||
156 | $io->write('Created `' . $path . '` directory'); |
||
157 | } |
||
158 | } |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Create the config/recaptcha.php file if it does not exist. |
||
163 | * |
||
164 | * @param string $dir The application's root directory. |
||
165 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
166 | * |
||
167 | * @return void |
||
168 | */ |
||
169 | View Code Duplication | public static function createRecaptchaConfig($dir, $io) |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
170 | { |
||
171 | $appConfig = $dir . '/config/recaptcha.php'; |
||
172 | $defaultConfig = $dir . '/config/recaptcha.default.php'; |
||
173 | if (!file_exists($appConfig)) { |
||
174 | copy($defaultConfig, $appConfig); |
||
175 | $io->write('Created `config/recaptcha.php` file'); |
||
176 | } |
||
177 | } |
||
178 | |||
179 | /** |
||
180 | * Set globally writable permissions on the "tmp" and "logs" directory. |
||
181 | * |
||
182 | * This is not the most secure default, but it gets people up and running quickly. |
||
183 | * |
||
184 | * @param string $dir The application's root directory. |
||
185 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
186 | * @return void |
||
187 | */ |
||
188 | public static function setFolderPermissions($dir, $io) |
||
189 | { |
||
190 | // Change the permissions on a path and output the results. |
||
191 | $changePerms = function ($path, $perms, $io) { |
||
192 | // Get permission bits from stat(2) result. |
||
193 | $currentPerms = fileperms($path) & 0777; |
||
194 | if (($currentPerms & $perms) == $perms) { |
||
195 | return; |
||
196 | } |
||
197 | |||
198 | $res = chmod($path, $currentPerms | $perms); |
||
199 | if ($res) { |
||
200 | $io->write('Permissions set on ' . $path); |
||
201 | } else { |
||
202 | $io->write('Failed to set permissions on ' . $path); |
||
203 | } |
||
204 | }; |
||
205 | |||
206 | $walker = function ($dir, $perms, $io) use (&$walker, $changePerms) { |
||
207 | $files = array_diff(scandir($dir), ['.', '..']); |
||
208 | foreach ($files as $file) { |
||
209 | $path = $dir . '/' . $file; |
||
210 | |||
211 | if (!is_dir($path)) { |
||
212 | continue; |
||
213 | } |
||
214 | |||
215 | $changePerms($path, $perms, $io); |
||
216 | $walker($path, $perms, $io); |
||
217 | } |
||
218 | }; |
||
219 | |||
220 | $worldWritable = bindec('0000000111'); |
||
221 | $walker($dir . '/tmp', $worldWritable, $io); |
||
222 | $changePerms($dir . '/tmp', $worldWritable, $io); |
||
223 | $changePerms($dir . '/logs', $worldWritable, $io); |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * Set the datasources.default.database value in the application's config file. |
||
228 | * |
||
229 | * @param string $dir The application's root directory. |
||
230 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
231 | * |
||
232 | * @return void |
||
233 | */ |
||
234 | public static function setDatabaseName($dir, $io) |
||
235 | { |
||
236 | $config = $dir . '/config/database.php'; |
||
237 | $content = file_get_contents($config); |
||
238 | |||
239 | $databaseName = $io->ask('What is the database host ? ', 'localhost'); |
||
240 | $content = str_replace('__DATABASE_HOST__', $databaseName, $content, $count); |
||
241 | |||
242 | $databaseName = $io->ask('What is the database name ? ', 'xeta_test'); |
||
243 | $content = str_replace('__DATABASE_NAME__', $databaseName, $content, $count); |
||
244 | |||
245 | $databaseName = $io->ask('What is the database username ? ', 'xeta'); |
||
246 | $content = str_replace('__DATABASE_USERNAME__', $databaseName, $content, $count); |
||
247 | |||
248 | $databaseName = $io->ask('What is the database password ? ', 'xeta'); |
||
249 | $content = str_replace('__DATABASE_PASSWORD__', $databaseName, $content, $count); |
||
250 | |||
251 | if ($count == 0) { |
||
252 | $io->write('No Datasources.default.database placeholder to replace.'); |
||
253 | |||
254 | return; |
||
255 | } |
||
256 | |||
257 | $result = file_put_contents($config, $content); |
||
258 | if ($result) { |
||
259 | $io->write('Updated Datasources.default.database value in config/app.php'); |
||
260 | |||
261 | return; |
||
262 | } |
||
263 | $io->write('Unable to update Datasources.default.database value.'); |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * Set the security.salt value in the application's config file. |
||
268 | * |
||
269 | * @param string $dir The application's root directory. |
||
270 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
271 | * @return void |
||
272 | */ |
||
273 | public static function setSecuritySaltAndKey($dir, $io) |
||
274 | { |
||
275 | $config = $dir . '/config/app.php'; |
||
276 | $content = file_get_contents($config); |
||
277 | |||
278 | $newKey = hash('sha256', Security::randomBytes(64)); |
||
279 | $securityKey = hash('sha256', Security::randomBytes(64)); |
||
280 | |||
281 | $content = str_replace('__SALT__', $newKey, $content, $count); |
||
282 | $content = str_replace('__KEY__', $securityKey, $content, $count); |
||
283 | |||
284 | if ($count == 0) { |
||
285 | $io->write('No Security.salt placeholder to replace.'); |
||
286 | |||
287 | return; |
||
288 | } |
||
289 | |||
290 | $result = file_put_contents($config, $content); |
||
291 | if ($result) { |
||
292 | $io->write('Updated Security.salt value in config/app.php'); |
||
293 | |||
294 | return $newKey; |
||
295 | } |
||
296 | $io->write('Unable to update Security.salt value.'); |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * Set up the admin and member password for the database. |
||
301 | * |
||
302 | * @param string $dir The application's root directory. |
||
303 | * @param \Composer\IO\IOInterface $io IO interface to write to console. |
||
304 | * @param string $newKey The new security.salt. |
||
305 | * |
||
306 | * @return void |
||
307 | */ |
||
308 | public static function setAccountPassword($dir, $io, $newKey = null) |
||
309 | { |
||
310 | if ($newKey == null) { |
||
311 | $io->write('The new Security.salt value is empty in config/Seeds/UsersSeed.php, can\'t set up the password.'); |
||
312 | |||
313 | return; |
||
314 | } |
||
315 | |||
316 | $database = $dir . '/config/Seeds/UsersSeed.php'; |
||
317 | $content = file_get_contents($database); |
||
318 | |||
319 | $adminPass = 'administrator'; |
||
320 | $memberPass = 'testaccount'; |
||
321 | |||
322 | $hasher = new DefaultPasswordHasher(); |
||
323 | |||
324 | $replacement = [ |
||
325 | $hasher->hash($adminPass), |
||
326 | $hasher->hash($memberPass), |
||
327 | ]; |
||
328 | |||
329 | $search = [ |
||
330 | '__ADMINPASSWORD__', |
||
331 | '__MEMBERPASSWORD__' |
||
332 | ]; |
||
333 | |||
334 | $content = str_replace($search, $replacement, $content, $count); |
||
335 | |||
336 | if ($count != 2) { |
||
337 | $io->write('Error, there was no password to replace.'); |
||
338 | |||
339 | return; |
||
340 | } |
||
341 | |||
342 | $result = file_put_contents($database, $content); |
||
343 | |||
344 | if ($result) { |
||
345 | $io->write('Set up Admin & Member passwords successfully !'); |
||
346 | |||
347 | return; |
||
348 | } |
||
349 | |||
350 | $io->write('Unable to set up Admin & Member passwords.'); |
||
351 | } |
||
352 | } |
||
353 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.