From e5b8a01367ca97b45b7b0f06c52b5b535979b3ee Mon Sep 17 00:00:00 2001 From: Terranom674 Date: Thu, 20 Aug 2026 10:31:59 +0200 Subject: [PATCH] Remove legacy local reconcile runtime --- runtime/reconcile.php | 336 ------------------------------------------ 1 file changed, 336 deletions(-) delete mode 100644 runtime/reconcile.php diff --git a/runtime/reconcile.php b/runtime/reconcile.php deleted file mode 100644 index 8d7062e..0000000 --- a/runtime/reconcile.php +++ /dev/null @@ -1,336 +0,0 @@ -#!/usr/bin/env php -$plain,'piwigo_user'=>'','piwigo_password'=>'','api_key_id'=>'','api_key_secret'=>''); - } - return array( - 'db_password'=>(string)($decoded['db_password'] ?? ''), - 'piwigo_user'=>(string)($decoded['piwigo_user'] ?? ''), - 'piwigo_password'=>(string)($decoded['piwigo_password'] ?? ''), - 'api_key_id'=>(string)($decoded['api_key_id'] ?? ''), - 'api_key_secret'=>(string)($decoded['api_key_secret'] ?? ''), - ); -} - -function encrypt_reconcile(array $credentials, $hexKey) -{ - $plain = json_encode(array( - 'v'=>2, - 'db_password'=>(string)$credentials['db_password'], - 'piwigo_user'=>(string)$credentials['piwigo_user'], - 'piwigo_password'=>(string)$credentials['piwigo_password'], - 'api_key_id'=>(string)$credentials['api_key_id'], - 'api_key_secret'=>(string)$credentials['api_key_secret'], - ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - if (!is_string($plain)) fail_reconcile('Connector-Zugangsdaten konnten nicht serialisiert werden.'); - $iv = random_bytes(12); - $tag = ''; - $cipher = openssl_encrypt($plain, 'aes-256-gcm', hex2bin($hexKey), OPENSSL_RAW_DATA, $iv, $tag); - if ($cipher === false) fail_reconcile('Connector-Zugangsdaten konnten nicht verschluesselt werden.'); - return base64_encode(json_encode(array( - 'v'=>1, - 'iv'=>base64_encode($iv), - 'tag'=>base64_encode($tag), - 'data'=>base64_encode($cipher), - ))); -} - -function write_runtime_status($piwigoRoot, $id, $stateDir, $message) -{ - $payload = json_encode(array( - 'state'=>'error', - 'message'=>'Runtime-Vorbereitung fehlgeschlagen', - 'timestamp'=>time(), - 'auth_mode'=>'failed', - 'api'=>array('state'=>'not_run','message'=>''), - 'fallback'=>array('state'=>'not_run','message'=>''), - 'error_detail'=>(string)$message, - ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - if (!is_string($payload)) return; - $targets = array(rtrim($piwigoRoot, '/').'/_data/bratonien-tools/nc-connector-status/connection-'.$id.'.json'); - if ($stateDir !== '') $targets[] = rtrim($stateDir, '/').'/connector-status.json'; - foreach ($targets as $target) - { - $dir = dirname($target); - if (!is_dir($dir)) @mkdir($dir, 0755, true); - @file_put_contents($target, $payload."\n", LOCK_EX); - @chmod($target, 0644); - } -} - -function sql_reconcile(mysqli $db, $value) -{ - return $db->real_escape_string((string)$value); -} - -function nextcloud_view_available(array $config, $password, $view) -{ - if (!preg_match('/^[A-Za-z_][A-Za-z0-9_]*$/', (string)$view)) return false; - $spec = array(0=>array('file','/dev/null','r'),1=>array('pipe','w'),2=>array('pipe','w')); - $command = array( - 'psql','-XAt','-v','ON_ERROR_STOP=1', - '-h',(string)$config['host'],'-p',(string)$config['port'],'-U',(string)$config['user'],'-d',(string)$config['database'], - '-c','SELECT 1 FROM '.$view.' LIMIT 1' - ); - $env = $_ENV; - $env['PGPASSWORD'] = (string)$password; - $process = @proc_open($command, $spec, $pipes, null, $env); - if (!is_resource($process)) return false; - stream_get_contents($pipes[1]); - stream_get_contents($pipes[2]); - fclose($pipes[1]); fclose($pipes[2]); - return proc_close($process) === 0; -} - -function configured_access_user(array $config) -{ - foreach (array('access_user','nextcloud_access_user','showcase_user') as $key) - { - $value = trim((string)($config[$key] ?? '')); - if ($value !== '') return $value; - } - return ''; -} - -$pluginRoot = dirname(__DIR__); -$piwigoRoot = dirname($pluginRoot, 2); -$dbConfig = $piwigoRoot.'/local/config/database.inc.php'; -$configDir = '/etc/bratonien-tools/nc-connector'; -$stateRoot = '/var/lib/bratonien-tools/nc-connector'; - -try -{ - if (!is_readable($dbConfig)) fail_reconcile('Piwigo-Datenbankkonfiguration ist nicht lesbar: '.$dbConfig); - $conf = array(); - $prefixeTable = 'piwigo_'; - require $dbConfig; - foreach (array('db_host','db_user','db_password','db_base') as $key) - { - if (!isset($conf[$key])) fail_reconcile('Piwigo-Datenbankkonfiguration ist unvollstaendig: '.$key); - } - - $db = new mysqli($conf['db_host'], $conf['db_user'], $conf['db_password'], $conf['db_base']); - if ($db->connect_errno) fail_reconcile('Piwigo-Datenbank ist nicht erreichbar: '.$db->connect_error); - $db->set_charset('utf8mb4'); - - $keyResult = $db->query("SELECT value FROM `{$prefixeTable}config` WHERE param='bratonien_nc_connector_secret' LIMIT 1"); - if (!$keyResult || !$keyResult->num_rows) fail_reconcile('Connector-Schluessel wurde nicht gefunden.'); - $hexKey = trim((string)$keyResult->fetch_assoc()['value']); - - $table = $prefixeTable.'bratonien_tools_nc_connections'; - $rows = $db->query("SELECT id,name,adapter,enabled,takeover_state,config_json,secret_blob FROM `{$table}` ORDER BY id"); - if (!$rows) fail_reconcile('Connector-Verbindungen konnten nicht gelesen werden: '.$db->error); - - if (!is_dir($configDir) && !mkdir($configDir, 0700, true)) fail_reconcile('Runtime-Konfigurationsverzeichnis konnte nicht angelegt werden.'); - chmod($configDir, 0700); - - while ($row = $rows->fetch_assoc()) - { - $id = (int)$row['id']; - $config = json_decode((string)$row['config_json'], true); - if (!is_array($config)) $config = array(); - $stateDir = rtrim((string)($config['state_dir'] ?? ''), '/'); - if ($stateDir === '') $stateDir = $stateRoot.'/connection-'.$id; - - try - { - if ((string)$row['adapter'] !== 'local') continue; - $isActive = (int)$row['enabled'] === 1 && (string)$row['takeover_state'] === 'active'; - $accessUser = configured_access_user($config); - $wizardConnection = (string)($config['origin'] ?? '') === 'native' - && trim((string)($config['nextcloud_url'] ?? '')) !== '' - && $accessUser !== ''; - $verification = isset($config['verification']) && is_array($config['verification']) ? $config['verification'] : null; - $verificationFailed = is_array($verification) && empty($verification['ok']); - if (!$isActive && (!$wizardConnection || $verificationFailed)) continue; - - foreach (array('host','port','database','user','source_view','activity_view','gallery_root') as $key) - { - if (trim((string)($config[$key] ?? '')) === '') fail_reconcile('Konfiguration unvollstaendig: '.$key.' fehlt.'); - } - $storages = isset($config['storages']) && is_array($config['storages']) ? $config['storages'] : array(); - if (!$storages) fail_reconcile('Keine Storage-Zuordnungen gespeichert.'); - - $credentials = decrypt_reconcile((string)$row['secret_blob'], $hexKey); - if ($credentials['db_password'] === '') fail_reconcile('Datenbankpasswort fehlt.'); - - $sourceMode = trim((string)($config['source_mode'] ?? '')); - if ($sourceMode === 'user-filesystem') - { - @unlink($configDir.'/connection-'.$id.'.conf'); - fail_reconcile('Diese Verbindung verwendet den verworfenen experimentellen Benutzerpfad-Modus. Bitte die Verbindung mit dem aktuellen Assistenten neu anlegen.'); - } - - if ($sourceMode === '' || $sourceMode === 'legacy-view') - { - $canMigrate = $accessUser !== '' - && nextcloud_view_available($config, $credentials['db_password'], 'piwigo_connector_shares') - && nextcloud_view_available($config, $credentials['db_password'], 'piwigo_connector_activity'); - if ($canMigrate) - { - $sourceMode = 'user-shares'; - $config['source_mode'] = $sourceMode; - $config['source_view'] = 'piwigo_connector_shares'; - $config['activity_view'] = 'piwigo_connector_activity'; - $config['access_user'] = $accessUser; - $config['nextcloud_access_user'] = $accessUser; - unset($config['showcase_user']); - echo "NC Connector: Verbindung #{$id} auf generische benutzergefilterte Quellen migriert.\n"; - } - else - { - $sourceMode = 'legacy-view'; - $config['source_mode'] = $sourceMode; - } - } - - if (!in_array($sourceMode, array('legacy-view','user-shares','selected-fileids'), true)) fail_reconcile('Unbekannter Quellenmodus: '.$sourceMode); - if ($sourceMode !== 'legacy-view' && $accessUser === '') fail_reconcile('Für die verbindungsbezogene Quelle fehlt der Nextcloud-Benutzer.'); - - $roots = isset($config['roots']) && is_array($config['roots']) ? $config['roots'] : array(); - if ($sourceMode === 'selected-fileids' && !$roots) fail_reconcile('Für die Verbindung sind keine ausgewählten Nextcloud-Datei-IDs gespeichert.'); - - if (!$isActive && !array_key_exists('api_enabled', $config)) - { - $hasFallback = $credentials['piwigo_user'] !== '' && $credentials['piwigo_password'] !== ''; - if (!$hasFallback) fail_reconcile('Die Verbindung besitzt weder einen eigenen API-Zugang noch einen eigenen Fallback.'); - $credentials['api_key_id'] = ''; - $credentials['api_key_secret'] = ''; - $config['piwigo_auth'] = 'connection-scoped'; - $config['api_enabled'] = false; - $row['secret_blob'] = encrypt_reconcile($credentials, $hexKey); - } - - $connectionScoped = (string)($config['piwigo_auth'] ?? '') === 'connection-scoped' || array_key_exists('api_enabled', $config); - if ($connectionScoped) - { - $apiAvailable = !empty($config['api_enabled']) && $credentials['api_key_id'] !== '' && $credentials['api_key_secret'] !== ''; - $fallbackAvailable = $credentials['piwigo_user'] !== '' && $credentials['piwigo_password'] !== ''; - if (!$apiAvailable && !$fallbackAvailable) fail_reconcile('Kein verbindungseigener Piwigo-Zugang gespeichert.'); - } - - if (!is_dir($stateDir) && !mkdir($stateDir, 0750, true)) fail_reconcile('State-Verzeichnis konnte nicht angelegt werden.'); - chmod($stateDir, 0750); - - $base = $configDir.'/connection-'.$id; - $dbPasswordPath = $base.'.db-password'; - $piwigoPasswordPath = $base.'.piwigo-password'; - $storagePath = $base.'.storages.tsv'; - $rootsPath = $base.'.roots.tsv'; - $configPath = $base.'.conf'; - $statusFile = $stateDir.'/connector-status.json'; - - file_put_contents($dbPasswordPath, $credentials['db_password']."\n", LOCK_EX); - chmod($dbPasswordPath, 0600); - - $fallbackAvailable = $credentials['piwigo_user'] !== '' && $credentials['piwigo_password'] !== ''; - if ($fallbackAvailable) - { - file_put_contents($piwigoPasswordPath, $credentials['piwigo_password']."\n", LOCK_EX); - chmod($piwigoPasswordPath, 0600); - } - else @unlink($piwigoPasswordPath); - - $storageLines = array('# storage_idsource_prefixlocal_mountinclude_prefix'); - foreach ($storages as $storage) - { - $storageLines[] = (string)($storage['storage_id'] ?? '')."\t" - .trim((string)($storage['source_prefix'] ?? ''), '/')."\t" - .(string)($storage['local_mount'] ?? '')."\t" - .trim((string)($storage['include_prefix'] ?? ''), '/'); - } - file_put_contents($storagePath, implode("\n", $storageLines)."\n", LOCK_EX); - chmod($storagePath, 0600); - - if ($sourceMode === 'selected-fileids') - { - $rootLines = array('# fileiddisplay_name'); - foreach ($roots as $root) - { - $fileid = (int)($root['fileid'] ?? 0); - $display = trim((string)($root['display_name'] ?? '')); - if ($fileid < 1 || $display === '' || preg_match('/[\t\r\n]/', $display)) fail_reconcile('Eine gespeicherte Nextcloud-Quelle ist ungueltig.'); - $rootLines[] = $fileid."\t".$display; - } - file_put_contents($rootsPath, implode("\n", $rootLines)."\n", LOCK_EX); - chmod($rootsPath, 0600); - } - else @unlink($rootsPath); - - $lines = array( - 'PIWIGO_ROOT='.$piwigoRoot, - 'GALLERY_ROOT='.(string)$config['gallery_root'], - 'STATE_DIR='.$stateDir, - 'STATUS_FILE='.$statusFile, - 'NC_DB_HOST='.(string)$config['host'], - 'NC_DB_PORT='.(string)$config['port'], - 'NC_DB_NAME='.(string)$config['database'], - 'NC_DB_USER='.(string)$config['user'], - 'NC_DB_VIEW='.(string)$config['source_view'], - 'NC_ACTIVITY_VIEW='.(string)$config['activity_view'], - 'NC_DB_PASSWORD_FILE='.$dbPasswordPath, - 'STORAGE_CONFIG='.$storagePath, - 'SOURCE_MODE='.$sourceMode, - 'QUIET_SECONDS='.(int)($config['quiet_seconds'] ?? 120), - 'MAX_WAIT_SECONDS='.(int)($config['max_wait_seconds'] ?? 900), - 'FULL_SYNC_SECONDS='.(int)($config['full_sync_seconds'] ?? 86400), - 'PIWIGO_SYNC_ENABLED=1', - ); - if ($sourceMode !== 'legacy-view') $lines[] = 'ACCESS_USER='.escapeshellarg($accessUser); - if ($sourceMode === 'selected-fileids') $lines[] = 'ROOTS_CONFIG='.$rootsPath; - if ($fallbackAvailable) - { - $lines[] = 'PIWIGO_SYNC_USER='.$credentials['piwigo_user']; - $lines[] = 'PIWIGO_SYNC_PASSWORD_FILE='.$piwigoPasswordPath; - } - file_put_contents($configPath, implode("\n", $lines)."\n", LOCK_EX); - chmod($configPath, 0600); - - $config['state_dir'] = $stateDir; - $config['status_file'] = $statusFile; - $config['runtime'] = array('mode'=>'shared-runner','config'=>$configPath,'reconciled_at'=>date('Y-m-d H:i:s')); - $json = json_encode($config, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); - if (!is_string($json)) fail_reconcile('Connector-Konfiguration konnte nicht serialisiert werden.'); - $now = date('Y-m-d H:i:s'); - $sql = "UPDATE `{$table}` SET enabled=1,takeover_state='active',config_json='".sql_reconcile($db,$json)."',secret_blob='".sql_reconcile($db,$row['secret_blob'])."',updated='".sql_reconcile($db,$now)."' WHERE id=".$id; - if (!$db->query($sql)) fail_reconcile('Runtime-Status konnte nicht gespeichert werden: '.$db->error); - if (!$isActive) echo "NC Connector: Verbindung #{$id} ({$row['name']}) automatisch in die gemeinsame Runtime uebernommen.\n"; - } - catch (Throwable $e) - { - write_runtime_status($piwigoRoot, $id, $stateDir, $e->getMessage()); - fwrite(STDERR, "NC Connector #{$id}: ".$e->getMessage()."\n"); - } - } - - exit(0); -} -catch (Throwable $e) -{ - fwrite(STDERR, "NC Connector Reconcile: ".$e->getMessage()."\n"); - exit(1); -}