Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace tool_brickfield;
18
 
19
/**
20
 * Class registration contains the functions to manage registration validation.
21
 *
22
 * @package     tool_brickfield
23
 * @author      2021 Onwards Mike Churchward <mike@brickfieldlabs.ie>
24
 * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL
25
 */
26
class registration {
27
 
28
    /** @var int Registration information has not been entered. */
29
    const NOT_ENTERED = 0;
30
 
31
    /** @var int Registration information has been entered but not externally validated. */
32
    const PENDING = 1;
33
 
34
    /** @var int Registration information was entered but was not validated within the defined grace periods. */
35
    const INVALID = 2;
36
 
37
    /** @var int Registration information has been externally validated. */
38
    const VALIDATED = 3;
39
 
40
    /** @var int Registration information has expired and needs to be revalidated. */
41
    const EXPIRED = 4;
42
 
43
    /** @var int Registration validation attempted, but failed. */
44
    const ERROR = 5;
45
 
46
    /** @var string Name of variable storing the registration status. */
47
    const STATUS = 'bfregstatus';
48
 
49
    /** @var string Name of variable storing the last time the registration information was checked. */
50
    const VALIDATION_CHECK_TIME = 'bfregvalidationchecktime';
51
 
52
    /** @var string Name of variable storing the time the registration information was validated. */
53
    const VALIDATION_TIME = 'bfregvalidationtime';
54
 
55
    /** @var string Name of variable storing the time the summary data was last sent. */
56
    const SUMMARY_TIME = 'bfsummarytime';
57
 
58
    /** @var string Name of variable storing the registration API key. */
59
    const API_KEY = 'key';
60
 
61
    /** @var string Name of variable storing the registration API key. */
62
    const SECRET_KEY = 'hash';
63
 
64
    /** @var string Name of the variable storing the site id. */
65
    const SITEID = 'id';
66
 
67
    /** @var int The current validation status. */
68
    protected $validation;
69
 
70
    /** @var int The last time the validation was checked. */
71
    protected $checktime;
72
 
73
    /** @var int The last time the validation time was confirmed. */
74
    protected $validationtime;
75
 
76
    /** @var int The last time the summary data was sent. */
77
    protected $summarytime;
78
 
79
    /** @var string The API key required for registration. */
80
    protected $apikey;
81
 
82
    /** @var string The secret key required for registration. */
83
    protected $secretkey;
84
 
85
    /** @var string The registered site id. */
86
    protected $siteid;
87
 
88
    /** @var string The URL to register at. */
89
    private static $regurl = 'https://account.mybrickfield.ie/register';
90
 
91
    /** @var string The URL to view terms at. */
92
    private static $termsurl = 'https://account.mybrickfield.ie/terms';
93
 
94
    /**
95
     * Object registration constructor.
96
     * @throws \dml_exception
97
     */
98
    public function __construct() {
99
        $this->validation = $this->get_status();
100
        $this->checktime = $this->get_check_time();
101
        $this->validationtime = $this->get_validation_time();
102
        $this->summarytime = $this->get_summary_time();
103
        $this->apikey = $this->get_api_key();
104
        $this->secretkey = $this->get_secret_key();
105
        $this->siteid = $this->get_siteid();
106
    }
107
 
108
    /**
109
     * System can be used when it has been validated, or when its still awaiting validation.
110
     * @return bool
111
     */
112
    public function toolkit_is_active(): bool {
113
        return $this->status_is_validated() || $this->validation_pending();
114
    }
115
 
116
    /**
117
     * The "not validated" state also needs the grace period to still be in effect.
118
     * @return bool
119
     */
120
    public function validation_pending(): bool {
121
        return ($this->status_is_pending() || $this->status_is_error()) && $this->grace_period_valid();
122
    }
123
 
124
    /**
125
     * Return true if there was a validation error.
126
     * @return bool
127
     */
128
    public function validation_error(): bool {
129
        return $this->status_is_error();
130
    }
131
 
132
    /**
133
     * Perform all necessary steps when new keys are added. Also check that they actually look like keys.
134
     * @param string $apikey
135
     * @param string $secretkey
136
     * @return bool
137
     */
138
    public function set_keys_for_registration(string $apikey, string $secretkey): bool {
139
        if ($this->keys_are_valid($apikey, $secretkey)) {
140
            $this->set_api_key($apikey);
141
            $this->set_secret_key($secretkey);
142
            $this->set_not_validated();
143
            if ($this->summarytime <= 0) {
144
                $this->set_summary_time();
145
            }
146
            return true;
147
        } else {
148
            $this->set_api_key('');
149
            $this->set_secret_key('');
150
            $this->set_not_entered();
151
            return false;
152
        }
153
    }
154
 
155
    /**
156
     * If the registration is not already valid, validate it. This may connect to the registration site.
157
     * @return bool
158
     * @throws \dml_exception
159
     */
160
    public function validate(): bool {
161
        // If this is currently valid, return true, unless its time to check again.
162
        if ($this->status_is_validated()) {
163
            // If the summary data has not been sent in over a week, invalidate the registration.
164
            if ($this->summarydata_grace_period_expired()) {
165
                $this->set_invalid();
166
                return false;
167
            }
168
            // Confirm registration after the grace period has expired.
169
            if ($this->grace_period_valid()) {
170
                return true;
171
            } else {
172
                // Recheck the registration.
173
                return $this->revalidate();
174
            }
175
        }
176
 
177
        // Check for valid keys, and possibly move status to validation stage.
178
        if (!$this->keys_are_valid()) {
179
            // The current stored keys are not valid format, set the status to "not entered".
180
            $this->set_not_entered();
181
            return false;
182
        } else if ($this->status_is_not_entered()) {
183
            // If no keys have previously been seen, move to validation stage.
184
            $this->set_not_validated();
185
        }
186
 
187
        // If no validation has been confirmed, check the registration site.
188
        if ($this->validation_pending()) {
189
            $brickfieldconnect = $this->get_registration_connection();
190
            $this->set_check_time();
191
            if ($brickfieldconnect->is_registered() || $brickfieldconnect->update_registration($this->apikey, $this->secretkey)) {
192
                // Keys are present and have been validated.
193
                $this->set_valid();
194
                return true;
195
            } else {
196
                // Keys are present but were not validated.
197
                $this->set_error();
198
            }
199
        }
200
 
201
        // If any of the grace periods have passed without a validation, invalidate the registration.
202
        if (!$this->grace_period_valid() || $this->summarydata_grace_period_expired()) {
203
            $this->set_invalid();
204
            return false;
205
        } else {
206
            return true;
207
        }
208
    }
209
 
210
    /**
211
     * Even if the regisration is currently valid, validate it again.
212
     * @return bool
213
     * @throws \dml_exception
214
     */
215
    public function revalidate(): bool {
216
        if ($this->status_is_validated()) {
217
            $this->set_not_validated();
218
        }
219
        return $this->validate();
220
    }
221
 
222
    /**
223
     * Get api key.
224
     * @return string
225
     * @throws \dml_exception
226
     */
227
    public function get_api_key(): string {
228
        $key = get_config(manager::PLUGINNAME, self::API_KEY);
229
        if ($key === false) {
230
            // Not set in config yet, so default it to "".
231
            $key = '';
232
            $this->set_api_key($key);
233
        }
234
        return $key;
235
    }
236
 
237
    /**
238
     * Get secret key.
239
     * @return string
240
     * @throws \dml_exception
241
     */
242
    public function get_secret_key(): string {
243
        $key = get_config(manager::PLUGINNAME, self::SECRET_KEY);
244
        if ($key === false) {
245
            // Not set in config yet, so default it to "".
246
            $key = '';
247
            $this->set_secret_key($key);
248
        }
249
        return $key;
250
    }
251
 
252
    /**
253
     * Get the registration URL.
254
     * @return string
255
     */
256
    public function get_regurl(): string {
257
        return self::$regurl;
258
    }
259
 
260
    /**
261
     * Get the terms and conditions URL.
262
     * @return string
263
     */
264
    public function get_termsurl(): string {
265
        return self::$termsurl;
266
    }
267
 
268
    /**
269
     * Perform all actions needed to note that the summary data was sent.
270
     */
271
    public function mark_summary_data_sent() {
272
        $this->set_summary_time();
273
    }
274
 
275
    /**
276
     * Set the registered site id.
277
     * @param int $id
278
     * @return bool
279
     */
280
    public function set_siteid(int $id): bool {
281
        $this->siteid = $id;
282
        return set_config(self::SITEID, $id, manager::PLUGINNAME);
283
    }
284
 
285
    /**
286
     * Return the registered site id.
287
     * @return int
288
     * @throws \dml_exception
289
     */
290
    public function get_siteid(): int {
291
        $siteid = get_config(manager::PLUGINNAME, self::SITEID);
292
        if ($siteid === false) {
293
            // Not set in config yet, so default it to 0.
294
            $siteid = 0;
295
            $this->set_siteid($siteid);
296
        }
297
        return (int)$siteid;
298
    }
299
 
300
    /**
301
     * Set the status as keys "not entered".
302
     * @return bool
303
     */
304
    protected function set_not_entered(): bool {
305
        return $this->set_status(self::NOT_ENTERED);
306
    }
307
 
308
    /**
309
     * "Not validated" means we have keys, but have not confirmed them yet. Set the validation time to start the grace period.
310
     * @return bool
311
     */
312
    protected function set_not_validated(): bool {
313
        $this->set_validation_time();
314
        return $this->set_status(self::PENDING);
315
    }
316
 
317
    /**
318
     * Set the registration as invalid.
319
     * @return bool
320
     */
321
    protected function set_invalid(): bool {
322
        $this->set_api_key('');
323
        $this->set_secret_key('');
324
        $this->set_siteid(0);
325
        return $this->set_status(self::INVALID);
326
    }
327
 
328
    /**
329
     * Set the registration as valid.
330
     * @return bool
331
     */
332
    protected function set_valid(): bool {
333
        $this->set_validation_time();
334
        $this->set_summary_time();
335
        return $this->set_status(self::VALIDATED);
336
    }
337
 
338
    /**
339
     * Set the status to "expired".
340
     * @return bool
341
     */
342
    protected function set_expired(): bool {
343
        return $this->set_status(self::EXPIRED);
344
    }
345
 
346
    /**
347
     * Set the status to "error".
348
     * @return bool
349
     */
350
    protected function set_error(): bool {
351
        return $this->set_status(self::ERROR);
352
    }
353
 
354
    /**
355
     * Set the configured api key value.
356
     * @param string $keyvalue
357
     * @return bool
358
     */
359
    protected function set_api_key(string $keyvalue): bool {
360
        $this->apikey = $keyvalue;
361
        return set_config(self::API_KEY, $keyvalue, manager::PLUGINNAME);
362
    }
363
 
364
    /**
365
     * Set the configured secret key value.
366
     * @param string $keyvalue
367
     * @return bool
368
     */
369
    protected function set_secret_key(string $keyvalue): bool {
370
        $this->secretkey = $keyvalue;
371
        return set_config(self::SECRET_KEY, $keyvalue, manager::PLUGINNAME);
372
    }
373
 
374
    /**
375
     * Return true if the logic says that the registration is valid.
376
     * @return bool
377
     */
378
    protected function status_is_validated(): bool {
379
        return $this->validation == self::VALIDATED;
380
    }
381
 
382
    /**
383
     * Return true if the current status is "not entered".
384
     * @return bool
385
     */
386
    protected function status_is_not_entered(): bool {
387
        return $this->validation == self::NOT_ENTERED;
388
    }
389
 
390
    /**
391
     * Return true if the current status is "pending".
392
     * @return bool
393
     */
394
    protected function status_is_pending(): bool {
395
        return $this->validation == self::PENDING;
396
    }
397
 
398
    /**
399
     * Return true if the current status is "expired".
400
     * @return bool
401
     */
402
    protected function status_is_expired(): bool {
403
        return $this->validation == self::EXPIRED;
404
    }
405
 
406
    /**
407
     * Return true if the current status is "invalid".
408
     * @return bool
409
     */
410
    protected function status_is_invalid(): bool {
411
        return $this->validation == self::INVALID;
412
    }
413
 
414
    /**
415
     * Return true if the current status is "error".
416
     * @return bool
417
     */
418
    protected function status_is_error() {
419
        return $this->validation == self::ERROR;
420
    }
421
 
422
    /**
423
     * Set the current registration status.
424
     * @param int $status
425
     * @return bool
426
     */
427
    protected function set_status(int $status): bool {
428
        $this->validation = $status;
429
        return set_config(self::STATUS, $status, manager::PLUGINNAME);
430
    }
431
 
432
    /**
433
     * Return the current registration status.
434
     * @return int
435
     * @throws \dml_exception
436
     */
437
    protected function get_status(): int {
438
        $status = get_config(manager::PLUGINNAME, self::STATUS);
439
        if ($status === false) {
440
            // Not set in config yet, so default it to "NOT_ENTERED".
441
            $status = self::NOT_ENTERED;
442
            $this->set_status($status);
443
        }
444
        return (int)$status;
445
    }
446
 
447
    /**
448
     * Set the time of the last registration check.
449
     * @param int $time
450
     * @return bool
451
     */
452
    protected function set_check_time(int $time = 0): bool {
453
        $time = ($time == 0) ? time() : $time;
454
        $this->checktime = $time;
455
        return set_config(self::VALIDATION_CHECK_TIME, $time, manager::PLUGINNAME);
456
    }
457
 
458
    /**
459
     * Get the time of the last registration check.
460
     * @return int
461
     * @throws \dml_exception
462
     */
463
    protected function get_check_time(): int {
464
        $time = get_config(manager::PLUGINNAME, self::VALIDATION_CHECK_TIME);
465
        if ($time === false) {
466
            // Not set in config yet, so default it to 0.
467
            $time = 0;
468
            $this->set_check_time($time);
469
        }
470
        return (int)$time;
471
    }
472
 
473
    /**
474
     * Set the registration validation time.
475
     * @param int $time
476
     * @return bool
477
     */
478
    protected function set_validation_time(int $time = 0): bool {
479
        $time = ($time == 0) ? time() : $time;
480
        $this->validationtime = $time;
481
        return set_config(self::VALIDATION_TIME, $time, manager::PLUGINNAME);
482
    }
483
 
484
    /**
485
     * Return the time of the registration validation.
486
     * @return int
487
     * @throws \dml_exception
488
     */
489
    protected function get_validation_time(): int {
490
        $time = get_config(manager::PLUGINNAME, self::VALIDATION_TIME);
491
        if ($time === false) {
492
            // Not set in config yet, so default it to 0.
493
            $time = 0;
494
            $this->set_validation_time($time);
495
        }
496
        return (int)$time;
497
    }
498
 
499
    /**
500
     * Set the time of the summary update.
501
     * @param int $time
502
     * @return bool
503
     */
504
    protected function set_summary_time(int $time = 0): bool {
505
        $time = ($time == 0) ? time() : $time;
506
        $this->summarytime = $time;
507
        return set_config(self::SUMMARY_TIME, $time, manager::PLUGINNAME);
508
    }
509
 
510
    /**
511
     * Return the time of the last summary update.
512
     * @return int
513
     * @throws \dml_exception
514
     */
515
    protected function get_summary_time(): int {
516
        $time = get_config(manager::PLUGINNAME, self::SUMMARY_TIME);
517
        if ($time === false) {
518
            // Not set in config yet, so default it to 0.
519
            $time = 0;
520
            $this->set_summary_time($time);
521
        }
522
        return (int)$time;
523
    }
524
 
525
    /**
526
     * Return true if all keys have valid format.
527
     * @param string|null $apikey
528
     * @param string|null $secretkey
529
     * @return bool
530
     */
531
    protected function keys_are_valid(?string $apikey = null, ?string $secretkey = null): bool {
532
        $apikey = $apikey ?? $this->apikey;
533
        $secretkey = $secretkey ?? $this->secretkey;
534
        return $this->apikey_is_valid($apikey) && $this->secretkey_is_valid($secretkey);
535
    }
536
 
537
    /**
538
     * Validates that the entered API key is in the expected format.
539
     * @param string $apikey
540
     * @return bool
541
     */
542
    protected function apikey_is_valid(string $apikey): bool {
543
        return $this->valid_key_format($apikey);
544
    }
545
 
546
    /**
547
     * Validates that the entered Secret key is in the expected format.
548
     * @param string $secretkey
549
     * @return bool
550
     */
551
    protected function secretkey_is_valid(string $secretkey): bool {
552
        return $this->valid_key_format($secretkey);
553
    }
554
 
555
    /**
556
     * Validates that the passed in key looks like an MD5 hash.
557
     * @param string $key
558
     * @return bool
559
     */
560
    protected function valid_key_format(string $key): bool {
561
        return !empty($key) && (preg_match('/^[a-f0-9]{32}$/', $key) === 1);
562
    }
563
 
564
    /**
565
     * Get the registration grace period.
566
     * @return int
567
     */
568
    protected function get_grace_period(): int {
569
        return WEEKSECS;
570
    }
571
 
572
    /**
573
     * Check if the unvalidated time is still within the grace period.
574
     * @return bool
575
     */
576
    protected function grace_period_valid(): bool {
577
        return (time() - $this->validationtime) < $this->get_grace_period();
578
    }
579
 
580
    /**
581
     * Check if the last time the summary data was sent is within the grace period.
582
     * @return bool
583
     */
584
    protected function summarydata_grace_period_expired(): bool {
585
        return (time() - $this->summarytime) > $this->get_grace_period();
586
    }
587
 
588
    /**
589
     * Return an instance of the connection class.
590
     * @return brickfieldconnect
591
     */
592
    protected function get_registration_connection(): brickfieldconnect {
593
        return new brickfieldconnect();
594
    }
595
}