PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / libraries / mvc / admin / models / license.php
vikappointments / libraries / mvc / admin / models Last commit date
acl.php 1 day ago license.php 1 day ago override.php 1 day ago overrides.php 1 day ago shortcode.php 1 day ago shortcodes.php 1 day ago
license.php
314 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 JLoader::import('adapter.mvc.models.form');
15
16 /**
17 * VikAppointments plugin License model.
18 *
19 * @since 1.1.11
20 * @see JModelForm
21 */
22 class VikAppointmentsModelLicense extends JModelForm
23 {
24 /**
25 * The base end-point URI.
26 *
27 * @var string
28 */
29 protected $baseUri = 'https://vikwp.com/api/';
30
31 /**
32 * Implements the request needed to validate the PRO license of the plugin.
33 *
34 * @param string $key The license key.
35 *
36 * @return mixed The response if valid, false otherwise.
37 */
38 public function validate($key)
39 {
40 // validate specified key
41 if (!preg_match("/^[a-zA-Z0-9]{16,16}$/", $key))
42 {
43 // invalid key, register error
44 $this->setError(new Exception(JText::translate('VAPINVALIDPROKEY'), 400));
45
46 return false;
47 }
48
49 // update license hash
50 VikAppointmentsLoader::import('update.license');
51 $hash = VikAppointmentsLicense::getHash();
52
53 // validation end-point
54 $url = $this->baseUri . '?task=licenses.validate';
55
56 // init HTTP transport
57 $http = new JHttp();
58
59 // build post data
60 $data = array(
61 'key' => $key,
62 'application' => 'vap',
63 'version' => VIKAPPOINTMENTS_SOFTWARE_VERSION,
64 'domain' => JUri::root(),
65 'ip' => $_SERVER['REMOTE_ADDR'],
66 'hash' => $hash,
67 );
68
69 // build headers
70 $headers = array(
71 /**
72 * Always bypass SSL validation while reaching our end-point.
73 *
74 * @since 1.2
75 */
76 'sslverify' => false,
77 );
78
79 /**
80 * Apply filters to manipulate the post data and the headers at runtime.
81 *
82 * @param array $data The post data array.
83 * @param array &$headers An associative array of HTTP directives.
84 * @param string $action The type of action to perform (validate).
85 *
86 * @since 1.2
87 */
88 $data = apply_filters_ref_array('vikappointments_license_before_post', array($data, &$headers, 'validate'));
89
90 // make connection with VikWP server
91 $response = $http->post($url, $data, $headers);
92
93 if ($response->code != 200)
94 {
95 // register error returned by VikWP
96 $this->setError(new Exception($response->body, $response->code));
97
98 return false;
99 }
100
101 // try decoding JSON
102 $body = json_decode($response->body);
103
104 if (!$body || $body->status != 1)
105 {
106 // invalid response received, register error
107 $this->setError(new Exception(JText::sprintf('VAPINVALIDRESPONSE', $response->body), 500));
108
109 return false;
110 }
111
112 // import necessary libraries
113 VikAppointmentsLoader::import('update.changelog');
114 VikAppointmentsLoader::import('update.license');
115
116 // register values
117 VikAppointmentsChangelog::store((isset($body->changelog) ? $body->changelog : ''));
118 VikAppointmentsLicense::setKey($body->key);
119 VikAppointmentsLicense::setExpirationDate($body->expdate);
120
121 // return response object
122 return $body;
123 }
124
125 /**
126 * Implements the request needed to download the PRO version of the plugin.
127 *
128 * @param string $key The license key.
129 *
130 * @return boolean True on success, false otherwise.
131 */
132 public function download($key)
133 {
134 // validate specified key
135 if (!preg_match("/^[a-zA-Z0-9]{16,16}$/", $key))
136 {
137 // invalid key, register error
138 $this->setError(new Exception(JText::translate('VAPINVALIDPROKEY'), 400));
139
140 return false;
141 }
142
143 // update license hash
144 VikAppointmentsLoader::import('update.license');
145 $hash = VikAppointmentsLicense::getHash();
146
147 JLoader::import('adapter.filesystem.folder');
148
149 // get temporary dir
150 $tmp = get_temp_dir();
151
152 // clean temporary path
153 $tmp = rtrim(JPath::clean($tmp), DIRECTORY_SEPARATOR);
154
155 // make sure the folder exists
156 if (!is_dir($tmp))
157 {
158 // missing temporary folder, register error
159 $this->setError(new Exception(sprintf('Temporary folder [%s] does not exist', $tmp), 404));
160
161 return false;
162 }
163
164 // make sure the temporary folder is writable
165 if (!wp_is_writable($tmp))
166 {
167 // tmp folder not writable, register error
168 $this->setError(new Exception(sprintf('Temporary folder [%s] is not writable', $tmp), 403));
169
170 return false;
171 }
172
173 // download end-point
174 $url = $this->baseUri . '?task=licenses.download';
175
176 // init HTTP transport
177 $http = new JHttp();
178
179 // build request headers
180 $headers = array(
181 // turn on stream to push body within a file
182 'stream' => true,
183 // define the filepath in which the data will be pushed
184 'filename' => $tmp . DIRECTORY_SEPARATOR . 'vikappointmentspro.zip',
185 // make sure the request is non blocking
186 'blocking' => true,
187 // force timeout to 60 seconds
188 'timeout' => 60,
189 /**
190 * Always bypass SSL validation while reaching our end-point.
191 *
192 * @since 1.2
193 */
194 'sslverify' => false,
195 );
196
197 // build post data
198 $data = array(
199 'key' => $key,
200 'application' => 'vap',
201 'version' => VIKAPPOINTMENTS_SOFTWARE_VERSION,
202 'domain' => JUri::root(),
203 'ip' => $_SERVER['REMOTE_ADDR'],
204 'hash' => $hash,
205 );
206
207 /**
208 * Apply filters to manipulate the post data and the headers at runtime.
209 *
210 * @param array $data The post data array.
211 * @param array &$headers An associative array of HTTP directives.
212 * @param string $action The type of action to perform (download).
213 *
214 * @since 1.2
215 */
216 $data = apply_filters_ref_array('vikappointments_license_before_post', array($data, &$headers, 'download'));
217
218 // make connection VikWP server
219 $response = $http->post($url, $data, $headers);
220
221 if ($response->code != 200)
222 {
223 // register error returned by VikWP
224 $this->setError(new Exception($response->body, $response->code));
225
226 return false;
227 }
228
229 // make sure the file has been saved
230 if (!JFile::exists($headers['filename']))
231 {
232 // something went wrong while saving the archive, register error
233 $this->setError(new Exception('ZIP package could not be saved on disk', 404));
234
235 return false;
236 }
237
238 // create destination folder for extracted elements
239 $dest = $tmp . DIRECTORY_SEPARATOR . 'vikappointments';
240
241 // make sure the destination folder doesn't exist
242 if (JFolder::exists($dest))
243 {
244 // remove it before proceeding with the extraction
245 JFolder::delete($dest);
246 }
247
248 // import archive class handler
249 JLoader::import('adapter.filesystem.archive');
250
251 // the package was downloaded successfully, let's extract it (onto TMP folder)
252 $extracted = JArchive::extract($headers['filename'], $tmp);
253
254 // we no longer need the archive
255 JFile::delete($headers['filename']);
256
257 if (!$extracted)
258 {
259 // an error occurred while extracting the files, register it
260 $this->setError(new Exception(sprintf('Cannot extract files to [%s]', $tmp), 500));
261
262 return false;
263 }
264
265 // make sure the folder is intact
266 if (!JFolder::exists($dest))
267 {
268 // impossible to access the extracted elements, register error
269 $this->setError(new Exception(sprintf('Cannot access extracted elements from [%s] folder', $dest), 404));
270
271 return false;
272 }
273
274 // copy the root files
275 $root_files = JFolder::files($dest, '.', false, true);
276
277 foreach ($root_files as $file)
278 {
279 if (!JFile::copy($file, VIKAPPOINTMENTS_BASE . DIRECTORY_SEPARATOR . basename($file)))
280 {
281 // delete folder before exiting
282 JFolder::delete($dest);
283
284 // we cannot afford to not be able to copy a root file, register error
285 $this->setError(new Exception(sprintf('Cannot copy root [%s] file', basename($file)), 500));
286
287 return false;
288 }
289 }
290
291 // copy the root folders
292 $root_folders = JFolder::folders($dest, '.', false, true);
293
294 foreach ($root_folders as $folder)
295 {
296 if (!JFolder::copy($folder, VIKAPPOINTMENTS_BASE . DIRECTORY_SEPARATOR . basename($folder), '', true))
297 {
298 // delete folder before exiting
299 JFolder::delete($dest);
300
301 // we cannot afford to not be able to copy a root folder, register error
302 $this->setError(new Exception(sprintf('Cannot copy root [%s] folder', basename($folder)), 500));
303
304 return false;
305 }
306 }
307
308 // process complete, clean up the temporary folder before exiting
309 JFolder::delete($dest);
310
311 return true;
312 }
313 }
314