91334a46b5
Co-authored-by: Cursor <cursoragent@cursor.com>
140 lines
4.4 KiB
PHP
140 lines
4.4 KiB
PHP
<?php
|
|
// This file is part of Moodle - http://moodle.org/
|
|
|
|
/**
|
|
* Persist MeetLet installation identity + cached runtime authorization.
|
|
*
|
|
* @package mod_meetletacbfree
|
|
* @copyright 2026 MeetLet
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
namespace mod_meetletacbfree\registration;
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
/**
|
|
* Single-row registration store in meetletacbfree_license.
|
|
*/
|
|
class store {
|
|
public const TABLE = 'meetletacbfree_license';
|
|
|
|
/**
|
|
* @return \stdClass|null
|
|
*/
|
|
public static function get_record() {
|
|
global $DB;
|
|
if (!$DB->get_manager()->table_exists(self::TABLE)) {
|
|
return null;
|
|
}
|
|
$rows = $DB->get_records(self::TABLE, null, 'id ASC', '*', 0, 1);
|
|
return $rows ? reset($rows) : null;
|
|
}
|
|
|
|
/**
|
|
* @return \stdClass
|
|
*/
|
|
public static function ensure_identity(): \stdClass {
|
|
global $DB;
|
|
$row = self::get_record();
|
|
if ($row && !empty($row->installation_id) && !empty($row->private_key_pem)) {
|
|
return $row;
|
|
}
|
|
$kp = crypto::generate_installation_keypair();
|
|
$now = time();
|
|
if ($row) {
|
|
$row->installation_id = $row->installation_id ?: crypto::random_installation_id();
|
|
$row->private_key_pem = $kp['private_pem'];
|
|
$row->public_key_pem = $kp['public_pem'];
|
|
$row->timemodified = $now;
|
|
$DB->update_record(self::TABLE, $row);
|
|
return $row;
|
|
}
|
|
$rec = (object)[
|
|
'installation_id' => crypto::random_installation_id(),
|
|
'private_key_pem' => $kp['private_pem'],
|
|
'public_key_pem' => $kp['public_pem'],
|
|
'auth_json' => null,
|
|
'license_uuid' => null,
|
|
'status' => 'inactive',
|
|
'last_error' => null,
|
|
'last_validated' => 0,
|
|
'timecreated' => $now,
|
|
'timemodified' => $now,
|
|
];
|
|
$rec->id = $DB->insert_record(self::TABLE, $rec);
|
|
return $rec;
|
|
}
|
|
|
|
/**
|
|
* @param array $fields
|
|
*/
|
|
public static function update(array $fields): \stdClass {
|
|
global $DB;
|
|
$row = self::ensure_identity();
|
|
foreach ($fields as $k => $v) {
|
|
$row->{$k} = $v;
|
|
}
|
|
$row->timemodified = time();
|
|
$DB->update_record(self::TABLE, $row);
|
|
return $row;
|
|
}
|
|
|
|
/**
|
|
* @return array{payload:array,signature:string}|null
|
|
*/
|
|
public static function get_authorization(): ?array {
|
|
$row = self::get_record();
|
|
if (!$row || empty($row->auth_json)) {
|
|
return null;
|
|
}
|
|
$decoded = json_decode($row->auth_json, true);
|
|
if (!is_array($decoded) || empty($decoded['payload']) || empty($decoded['signature'])) {
|
|
return null;
|
|
}
|
|
return $decoded;
|
|
}
|
|
|
|
/**
|
|
* @return array{code:string,message:string,details?:?array,request_id?:?string,at:int}|null
|
|
*/
|
|
public static function get_last_error(): ?array {
|
|
$row = self::get_record();
|
|
if (!$row || empty($row->last_error)) {
|
|
return null;
|
|
}
|
|
$raw = (string)$row->last_error;
|
|
$decoded = json_decode($raw, true);
|
|
if (is_array($decoded) && !empty($decoded['code'])) {
|
|
return [
|
|
'code' => (string)$decoded['code'],
|
|
'message' => (string)($decoded['message'] ?? $decoded['code']),
|
|
'details' => isset($decoded['details']) && is_array($decoded['details']) ? $decoded['details'] : null,
|
|
'request_id' => isset($decoded['request_id']) ? (string)$decoded['request_id'] : null,
|
|
'at' => (int)($decoded['at'] ?? ($row->timemodified ?? 0)),
|
|
];
|
|
}
|
|
return [
|
|
'code' => 'UNKNOWN',
|
|
'message' => $raw,
|
|
'details' => null,
|
|
'request_id' => null,
|
|
'at' => (int)($row->timemodified ?? 0),
|
|
];
|
|
}
|
|
|
|
public static function rotate_identity(): \stdClass {
|
|
$kp = crypto::generate_installation_keypair();
|
|
return self::update([
|
|
'installation_id' => crypto::random_installation_id(),
|
|
'private_key_pem' => $kp['private_pem'],
|
|
'public_key_pem' => $kp['public_pem'],
|
|
'auth_json' => null,
|
|
'license_uuid' => null,
|
|
'status' => 'inactive',
|
|
'last_error' => null,
|
|
'last_validated' => 0,
|
|
]);
|
|
}
|
|
}
|