<?php
|
namespace JVBase\integrations;
|
|
use JVBase\managers\CustomTable;
|
|
if (!defined('ABSPATH')) {
|
exit;
|
}
|
|
class CredentialsManager
|
{
|
private static ?CredentialsManager $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().' NOT NULL',
|
'integration' => "ENUM('bluesky','cloudflare','facebook','google-maps','gmb','helcim','instagram','postmark','square','umami') NOT NULL",
|
'credentials' => 'varchar(255) DEFAULT NULL',
|
'created_at' => 'datetime DEFAULT CURRENT_TIMESTAMP',
|
'updated_at' => 'datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'
|
]);
|
|
$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(): CredentialsManager
|
{
|
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);
|
$update = [
|
'credentials' => $this->encrypt(json_encode($credentials))
|
];
|
return (bool)$this->table->findOrCreate($find, $update);
|
}
|
|
/**
|
* 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' => is_null($userID) ? 0 : $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]);
|
}
|
}
|