<?php
|
namespace JVBase\integrations;
|
use JVBase\managers\CustomTable;
|
|
if (!defined('ABSPATH')) {
|
exit;
|
}
|
|
class Auth
|
{
|
private static ?Auth $instance = null;
|
private string $encryption_key;
|
private CustomTable $table;
|
|
private function __construct()
|
{
|
$this->getEncryptionKey();
|
$this->defineTable();
|
}
|
|
protected function defineTable():void
|
{
|
$table = CustomTable::for('integrations');
|
$table->setColumns([
|
'id' => 'bigint(20) unsigned NOT NULL AUTO_INCREMENT',
|
'user_id' => $table->getUserIDType().' DEFAULT NULL',
|
'integration' => "ENUM('bluesky','cloudflare','facebook','google-maps','gmb','helcim','instagram','postmark','square','umami') NOT NULL",
|
'credentials' => 'varchar(1000) DEFAULT NULL',
|
'created_at' => 'datetime DEFAULT CURRENT_TIMESTAMP',
|
'updated_at' => 'datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
|
'last_tested' => 'datetime DEFAULT NULL',
|
'is_healthy' => 'tinyint(1) DEFAULT 1',
|
'webhook_healthy' => 'tinyint(1) DEFAULT 1',
|
'request_healthy' => 'tinyint(1) DEFAULT 1',
|
'oauth_healthy' => 'tinyint(1) DEFAULT 1',
|
]);
|
|
$table->setKeys([
|
['key' => 'PRIMARY', 'value' => '(`id`)'],
|
['key' => 'UNIQUE', 'value' => '`user_integration` (`user_id`, `integration`)'],
|
'`user` (`user_id`)',
|
]);
|
|
$base = BASE;
|
$table->setConstraints([
|
"CONSTRAINT `{$base}integrations_user` FOREIGN KEY (`user_id`)
|
REFERENCES `{$table->getUserTable()}` (`ID`) ON DELETE CASCADE"
|
]);
|
$table->defineTable();
|
$this->table = $table;
|
}
|
|
public static function getInstance(): Auth
|
{
|
if (self::$instance === null) {
|
self::$instance = new self();
|
}
|
return self::$instance;
|
}
|
|
/**
|
* Store encrypted credentials
|
*/
|
public function storeCredentials(string $service, array $credentials, ?int $userID = null): bool
|
{
|
$find = $this->findBy($service, $userID);
|
error_log('Storing Credentials: '.print_r($credentials, true));
|
|
$update = [
|
'credentials' => $this->encrypt(json_encode($credentials))
|
];
|
|
error_log('Find: '.print_r($find, true));
|
error_log('Update: '.print_r($update, true));
|
$updated = $this->table->findOrCreate($find, $update);
|
error_log('Last error: '.print_r($this->table->getLastError(), true));
|
error_log('Updated: '.print_r($updated, true));
|
|
return (bool)$updated;
|
}
|
|
/**
|
* Retrieve and decrypt credentials
|
*/
|
public function getCredentials(string $service, ?int $userID = null): array
|
{
|
$find = $this->findBy($service, $userID);
|
$credentials = $this->table->pluck('credentials', $find);
|
if (empty($credentials)) {
|
return [];
|
}
|
$decrypted_data = $this->decrypt($credentials[0]);
|
return empty($decrypted_data) ? [] : json_decode($decrypted_data, true);
|
}
|
|
/**
|
* Delete credentials
|
*/
|
public function deleteCredentials(string $service, ?int $userID = null): bool
|
{
|
$find = $this->findBy($service, $userID);
|
return $this->table->delete($find);
|
}
|
|
protected function findBy(string $service, ?int $userID = null):array
|
{
|
return [
|
'user_id' => $userID,
|
'integration'=> $service
|
];
|
}
|
|
/**
|
* Check if credentials exist
|
*/
|
public function hasCredentials(string $service, ?int $userID = null): bool
|
{
|
return !empty($this->getCredentials($service, $userID));
|
}
|
|
/**
|
* Get or create encryption key
|
*/
|
private function getEncryptionKey():void
|
{
|
$this->encryption_key = JVB_KEY;
|
}
|
|
/**
|
* Encrypt data
|
*/
|
private function encrypt(string $data): string
|
{
|
$iv = random_bytes(16);
|
$encrypted = openssl_encrypt($data, 'AES-256-CBC', $this->encryption_key, 0, $iv);
|
return base64_encode($iv . $encrypted);
|
}
|
|
/**
|
* Decrypt data
|
*/
|
private function decrypt(string $data): ?string
|
{
|
$data = base64_decode($data);
|
$iv = substr($data, 0, 16);
|
$encrypted = substr($data, 16);
|
|
return openssl_decrypt($encrypted, 'AES-256-CBC', $this->encryption_key, 0, $iv);
|
}
|
|
/**
|
* Get all users with credentials for a service
|
*/
|
public function getUsersWithCredentials(string $service): array
|
{
|
return $this->table->pluck('user_id', ['integration' => $service]);
|
}
|
|
public function updateTested(string $service, ?int $userID = null):void
|
{
|
$find = $this->findBy($service, $userID);
|
$this->table->update([
|
'last_tested' => time(),
|
], $find);
|
}
|
|
public function markUnhealthy(string $service, string $type = '', ?int $userID = null):void
|
{
|
$update = [];
|
switch ($type) {
|
case 'oauth':
|
$update['oauth_healthy'] = 0;
|
break;
|
case 'request':
|
$update['request_healthy'] = 0;
|
break;
|
case 'webhook':
|
$update['webhook_healthy'] = 0;
|
break;
|
default:
|
$update['is_healthy'] = 0;
|
break;
|
}
|
$find = $this->findBy($service, $userID);
|
$this->table->update($update, $find);
|
}
|
}
|