mirror of
https://github.com/Terranom674/Piwigo_Bratonien_Tools.git
synced 2026-09-19 18:44:30 +00:00
Allow API-only native NC connector activation
This commit is contained in:
@@ -25,82 +25,57 @@ $stateRoot = '/var/lib/bratonien-tools/nc-connector';
|
|||||||
$servicePath = '/etc/systemd/system/bratonien-nc-connector.service';
|
$servicePath = '/etc/systemd/system/bratonien-nc-connector.service';
|
||||||
$timerPath = '/etc/systemd/system/bratonien-nc-connector.timer';
|
$timerPath = '/etc/systemd/system/bratonien-nc-connector.timer';
|
||||||
|
|
||||||
function fail_install($message)
|
function fail_install($message) { throw new RuntimeException($message); }
|
||||||
{
|
|
||||||
throw new RuntimeException($message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function run_install(array $command, $allowFailure = false)
|
function run_install(array $command, $allowFailure = false)
|
||||||
{
|
{
|
||||||
$spec = array(
|
$spec = array(0=>array('file','/dev/null','r'),1=>array('pipe','w'),2=>array('pipe','w'));
|
||||||
0 => array('file', '/dev/null', 'r'),
|
|
||||||
1 => array('pipe', 'w'),
|
|
||||||
2 => array('pipe', 'w'),
|
|
||||||
);
|
|
||||||
$process = proc_open($command, $spec, $pipes);
|
$process = proc_open($command, $spec, $pipes);
|
||||||
if (!is_resource($process))
|
if (!is_resource($process)) fail_install('Prozess konnte nicht gestartet werden: '.implode(' ', $command));
|
||||||
{
|
|
||||||
fail_install('Prozess konnte nicht gestartet werden: '.implode(' ', $command));
|
|
||||||
}
|
|
||||||
$stdout = stream_get_contents($pipes[1]);
|
$stdout = stream_get_contents($pipes[1]);
|
||||||
$stderr = stream_get_contents($pipes[2]);
|
$stderr = stream_get_contents($pipes[2]);
|
||||||
fclose($pipes[1]);
|
fclose($pipes[1]); fclose($pipes[2]);
|
||||||
fclose($pipes[2]);
|
|
||||||
$exit = proc_close($process);
|
$exit = proc_close($process);
|
||||||
if ($exit !== 0 && !$allowFailure)
|
if ($exit !== 0 && !$allowFailure)
|
||||||
{
|
{
|
||||||
$detail = trim($stderr) !== '' ? trim($stderr) : trim($stdout);
|
$detail = trim($stderr) !== '' ? trim($stderr) : trim($stdout);
|
||||||
fail_install('Befehl fehlgeschlagen ('.$exit.'): '.implode(' ', $command).($detail !== '' ? "\n".$detail : ''));
|
fail_install('Befehl fehlgeschlagen ('.$exit.'): '.implode(' ', $command).($detail !== '' ? "\n".$detail : ''));
|
||||||
}
|
}
|
||||||
return array('exit'=>$exit, 'stdout'=>(string)$stdout, 'stderr'=>(string)$stderr);
|
return array('exit'=>$exit,'stdout'=>(string)$stdout,'stderr'=>(string)$stderr);
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrypt_install_credentials($blob, $hexKey)
|
function decrypt_install_credentials($blob, $hexKey)
|
||||||
{
|
{
|
||||||
if (!preg_match('/^[a-f0-9]{64}$/', $hexKey))
|
if (!preg_match('/^[a-f0-9]{64}$/', $hexKey)) fail_install('Connector-Schluessel ist ungueltig.');
|
||||||
{
|
|
||||||
fail_install('Connector-Schluessel ist ungueltig.');
|
|
||||||
}
|
|
||||||
$outer = base64_decode(trim((string)$blob), true);
|
$outer = base64_decode(trim((string)$blob), true);
|
||||||
$payload = is_string($outer) ? json_decode($outer, true) : null;
|
$payload = is_string($outer) ? json_decode($outer, true) : null;
|
||||||
if (!is_array($payload) || (int)($payload['v'] ?? 0) !== 1)
|
if (!is_array($payload) || (int)($payload['v'] ?? 0) !== 1) fail_install('Connector-Zugangsdaten haben ein unbekanntes Format.');
|
||||||
{
|
|
||||||
fail_install('Connector-Zugangsdaten haben ein unbekanntes Format.');
|
|
||||||
}
|
|
||||||
$iv = base64_decode((string)($payload['iv'] ?? ''), true);
|
$iv = base64_decode((string)($payload['iv'] ?? ''), true);
|
||||||
$tag = base64_decode((string)($payload['tag'] ?? ''), true);
|
$tag = base64_decode((string)($payload['tag'] ?? ''), true);
|
||||||
$cipher = base64_decode((string)($payload['data'] ?? ''), true);
|
$cipher = base64_decode((string)($payload['data'] ?? ''), true);
|
||||||
$plain = openssl_decrypt($cipher, 'aes-256-gcm', hex2bin($hexKey), OPENSSL_RAW_DATA, $iv, $tag);
|
$plain = openssl_decrypt($cipher, 'aes-256-gcm', hex2bin($hexKey), OPENSSL_RAW_DATA, $iv, $tag);
|
||||||
if ($plain === false || $plain === '')
|
if ($plain === false || $plain === '') fail_install('Connector-Zugangsdaten konnten nicht entschluesselt werden.');
|
||||||
{
|
|
||||||
fail_install('Connector-Zugangsdaten konnten nicht entschluesselt werden.');
|
|
||||||
}
|
|
||||||
$decoded = json_decode($plain, true);
|
$decoded = json_decode($plain, true);
|
||||||
if (!is_array($decoded) || empty($decoded['db_password']) || empty($decoded['piwigo_user']) || empty($decoded['piwigo_password']))
|
if (!is_array($decoded))
|
||||||
{
|
{
|
||||||
fail_install('Fuer eine native Aktivierung muessen Datenbank- und Piwigo-Zugangsdaten vollstaendig gespeichert sein.');
|
// Backward compatibility: old connections stored only the DB password.
|
||||||
|
return array('db_password'=>$plain,'piwigo_user'=>'','piwigo_password'=>'');
|
||||||
}
|
}
|
||||||
return $decoded;
|
if (empty($decoded['db_password'])) fail_install('Datenbankpasswort fehlt in den Connector-Zugangsdaten.');
|
||||||
|
return array(
|
||||||
|
'db_password'=>(string)$decoded['db_password'],
|
||||||
|
'piwigo_user'=>(string)($decoded['piwigo_user'] ?? ''),
|
||||||
|
'piwigo_password'=>(string)($decoded['piwigo_password'] ?? ''),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sql_install(mysqli $db, $value)
|
function sql_install(mysqli $db, $value) { return $db->real_escape_string((string)$value); }
|
||||||
{
|
|
||||||
return $db->real_escape_string((string)$value);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!is_readable($dbConfig))
|
if (!is_readable($dbConfig)) fail_install('Piwigo-Datenbankkonfiguration nicht lesbar: '.$dbConfig);
|
||||||
{
|
$conf = array(); $prefixeTable = 'piwigo_'; require $dbConfig;
|
||||||
fail_install('Piwigo-Datenbankkonfiguration nicht lesbar: '.$dbConfig);
|
foreach (array('db_host','db_user','db_password','db_base') as $key) if (!isset($conf[$key])) fail_install('Piwigo-Datenbankkonfiguration enthaelt '.$key.' nicht.');
|
||||||
}
|
|
||||||
$conf = array();
|
|
||||||
$prefixeTable = 'piwigo_';
|
|
||||||
require $dbConfig;
|
|
||||||
foreach (array('db_host','db_user','db_password','db_base') as $key)
|
|
||||||
{
|
|
||||||
if (!isset($conf[$key])) fail_install('Piwigo-Datenbankkonfiguration enthaelt '.$key.' nicht.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$db = new mysqli($conf['db_host'], $conf['db_user'], $conf['db_password'], $conf['db_base']);
|
$db = new mysqli($conf['db_host'], $conf['db_user'], $conf['db_password'], $conf['db_base']);
|
||||||
if ($db->connect_errno) fail_install('Piwigo-Datenbank nicht erreichbar: '.$db->connect_error);
|
if ($db->connect_errno) fail_install('Piwigo-Datenbank nicht erreichbar: '.$db->connect_error);
|
||||||
@@ -111,29 +86,27 @@ try
|
|||||||
if (!$result || !$result->num_rows) fail_install('Connector-Verbindung #'.$id.' wurde nicht gefunden.');
|
if (!$result || !$result->num_rows) fail_install('Connector-Verbindung #'.$id.' wurde nicht gefunden.');
|
||||||
$row = $result->fetch_assoc();
|
$row = $result->fetch_assoc();
|
||||||
if ((string)$row['adapter'] !== 'local') fail_install('Native Aktivierung ist derzeit nur fuer lokale Verbindungen verfuegbar.');
|
if ((string)$row['adapter'] !== 'local') fail_install('Native Aktivierung ist derzeit nur fuer lokale Verbindungen verfuegbar.');
|
||||||
if ((string)$row['takeover_state'] !== 'verified' || (int)$row['enabled'] !== 0)
|
if ((string)$row['takeover_state'] !== 'verified' || (int)$row['enabled'] !== 0) fail_install('Die Verbindung muss zuerst erfolgreich verifiziert und deaktiviert sein.');
|
||||||
{
|
|
||||||
fail_install('Die Verbindung muss zuerst erfolgreich verifiziert und deaktiviert sein.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = json_decode((string)$row['config_json'], true);
|
$config = json_decode((string)$row['config_json'], true);
|
||||||
if (!is_array($config) || empty($config['verification']['ok'])) fail_install('Erfolgreiche Verifikation fehlt.');
|
if (!is_array($config) || empty($config['verification']['ok'])) fail_install('Erfolgreiche Verifikation fehlt.');
|
||||||
foreach (array('host','port','database','user','source_view','activity_view','gallery_root') as $key)
|
foreach (array('host','port','database','user','source_view','activity_view','gallery_root') as $key) if (trim((string)($config[$key] ?? '')) === '') fail_install('Connector-Konfiguration ist unvollstaendig: '.$key.' fehlt.');
|
||||||
{
|
|
||||||
if (trim((string)($config[$key] ?? '')) === '') fail_install('Connector-Konfiguration ist unvollstaendig: '.$key.' fehlt.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$keyResult = $db->query("SELECT value FROM `".$prefixeTable."config` WHERE param='bratonien_nc_connector_secret' LIMIT 1");
|
$keyResult = $db->query("SELECT value FROM `".$prefixeTable."config` WHERE param='bratonien_nc_connector_secret' LIMIT 1");
|
||||||
if (!$keyResult || !$keyResult->num_rows) fail_install('Connector-Schluessel wurde in Piwigo nicht gefunden.');
|
if (!$keyResult || !$keyResult->num_rows) fail_install('Connector-Schluessel wurde in Piwigo nicht gefunden.');
|
||||||
$keyRow = $keyResult->fetch_assoc();
|
$credentials = decrypt_install_credentials((string)$row['secret_blob'], (string)$keyResult->fetch_assoc()['value']);
|
||||||
$credentials = decrypt_install_credentials((string)$row['secret_blob'], (string)$keyRow['value']);
|
|
||||||
|
$apiAvailable = false;
|
||||||
|
$apiResult = $db->query("SELECT value FROM `".$prefixeTable."config` WHERE param='bratonien_nc_piwigo_api' LIMIT 1");
|
||||||
|
if ($apiResult && $apiResult->num_rows) $apiAvailable = trim((string)$apiResult->fetch_assoc()['value']) !== '';
|
||||||
|
$fallbackAvailable = $credentials['piwigo_user'] !== '' && $credentials['piwigo_password'] !== '';
|
||||||
|
if (!$apiAvailable && !$fallbackAvailable) fail_install('Weder Piwigo-API noch Fallback-Zugang sind gespeichert.');
|
||||||
|
|
||||||
$stateDir = $stateRoot.'/connection-'.$id;
|
$stateDir = $stateRoot.'/connection-'.$id;
|
||||||
$statusFile = $stateDir.'/connector-status.json';
|
$statusFile = $stateDir.'/connector-status.json';
|
||||||
if (!is_dir($configDir) && !mkdir($configDir, 0700, true)) fail_install('Konfigurationsverzeichnis konnte nicht angelegt werden.');
|
if (!is_dir($configDir) && !mkdir($configDir, 0700, true)) fail_install('Konfigurationsverzeichnis konnte nicht angelegt werden.');
|
||||||
if (!is_dir($stateDir) && !mkdir($stateDir, 0750, true)) fail_install('State-Verzeichnis konnte nicht angelegt werden.');
|
if (!is_dir($stateDir) && !mkdir($stateDir, 0750, true)) fail_install('State-Verzeichnis konnte nicht angelegt werden.');
|
||||||
chmod($configDir, 0700);
|
chmod($configDir, 0700); chmod($stateDir, 0750);
|
||||||
chmod($stateDir, 0750);
|
|
||||||
|
|
||||||
$base = $configDir.'/connection-'.$id;
|
$base = $configDir.'/connection-'.$id;
|
||||||
$dbPasswordPath = $base.'.db-password';
|
$dbPasswordPath = $base.'.db-password';
|
||||||
@@ -141,19 +114,23 @@ try
|
|||||||
$storagePath = $base.'.storages.tsv';
|
$storagePath = $base.'.storages.tsv';
|
||||||
$configPath = $base.'.conf';
|
$configPath = $base.'.conf';
|
||||||
|
|
||||||
file_put_contents($dbPasswordPath, (string)$credentials['db_password']."\n", LOCK_EX);
|
file_put_contents($dbPasswordPath, (string)$credentials['db_password']."\n", LOCK_EX); chmod($dbPasswordPath, 0600);
|
||||||
file_put_contents($piwigoPasswordPath, (string)$credentials['piwigo_password']."\n", LOCK_EX);
|
if ($fallbackAvailable)
|
||||||
chmod($dbPasswordPath, 0600);
|
{
|
||||||
chmod($piwigoPasswordPath, 0600);
|
file_put_contents($piwigoPasswordPath, (string)$credentials['piwigo_password']."\n", LOCK_EX); chmod($piwigoPasswordPath, 0600);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@unlink($piwigoPasswordPath);
|
||||||
|
}
|
||||||
|
|
||||||
$storageLines = array('# storage_id<TAB>source_prefix<TAB>local_mount');
|
$storageLines = array('# storage_id<TAB>source_prefix<TAB>local_mount');
|
||||||
foreach ((array)($config['storages'] ?? array()) as $storage)
|
foreach ((array)($config['storages'] ?? array()) as $storage)
|
||||||
{
|
{
|
||||||
$storageLines[] = (string)($storage['storage_id'] ?? '')."\t".(string)($storage['source_prefix'] ?? '')."\t".(string)($storage['local_mount'] ?? '');
|
$storageLines[] = (string)($storage['storage_id'] ?? '')."\t".trim((string)($storage['source_prefix'] ?? ''), '/')."\t".(string)($storage['local_mount'] ?? '');
|
||||||
}
|
}
|
||||||
if (count($storageLines) === 1) fail_install('Keine Storage-Zuordnungen gespeichert.');
|
if (count($storageLines) === 1) fail_install('Keine Storage-Zuordnungen gespeichert.');
|
||||||
file_put_contents($storagePath, implode("\n", $storageLines)."\n", LOCK_EX);
|
file_put_contents($storagePath, implode("\n", $storageLines)."\n", LOCK_EX); chmod($storagePath, 0600);
|
||||||
chmod($storagePath, 0600);
|
|
||||||
|
|
||||||
$lines = array(
|
$lines = array(
|
||||||
'PIWIGO_ROOT='.$piwigoRoot,
|
'PIWIGO_ROOT='.$piwigoRoot,
|
||||||
@@ -172,44 +149,32 @@ try
|
|||||||
'MAX_WAIT_SECONDS='.(int)($config['max_wait_seconds'] ?? 900),
|
'MAX_WAIT_SECONDS='.(int)($config['max_wait_seconds'] ?? 900),
|
||||||
'FULL_SYNC_SECONDS='.(int)($config['full_sync_seconds'] ?? 86400),
|
'FULL_SYNC_SECONDS='.(int)($config['full_sync_seconds'] ?? 86400),
|
||||||
'PIWIGO_SYNC_ENABLED=1',
|
'PIWIGO_SYNC_ENABLED=1',
|
||||||
'PIWIGO_SYNC_USER='.(string)$credentials['piwigo_user'],
|
|
||||||
'PIWIGO_SYNC_PASSWORD_FILE='.$piwigoPasswordPath,
|
|
||||||
);
|
);
|
||||||
file_put_contents($configPath, implode("\n", $lines)."\n", LOCK_EX);
|
if ($fallbackAvailable)
|
||||||
chmod($configPath, 0600);
|
{
|
||||||
|
$lines[] = 'PIWIGO_SYNC_USER='.(string)$credentials['piwigo_user'];
|
||||||
|
$lines[] = 'PIWIGO_SYNC_PASSWORD_FILE='.$piwigoPasswordPath;
|
||||||
|
}
|
||||||
|
file_put_contents($configPath, implode("\n", $lines)."\n", LOCK_EX); chmod($configPath, 0600);
|
||||||
|
|
||||||
echo "Teste Verbindung mit Plugin-Runtime...\n";
|
echo "Teste Verbindung mit Plugin-Runtime...\n";
|
||||||
$test = run_install(array('env', 'PIWIGO_CONFIG='.$configPath, 'bash', $pluginRoot.'/runtime/sync.sh'), true);
|
$test = run_install(array('env', 'PIWIGO_CONFIG='.$configPath, 'bash', $pluginRoot.'/runtime/sync.sh'), true);
|
||||||
if ($test['exit'] !== 0)
|
if ($test['exit'] !== 0)
|
||||||
{
|
{
|
||||||
@unlink($configPath);
|
@unlink($configPath); @unlink($storagePath); @unlink($dbPasswordPath); @unlink($piwigoPasswordPath);
|
||||||
@unlink($storagePath);
|
|
||||||
@unlink($dbPasswordPath);
|
|
||||||
@unlink($piwigoPasswordPath);
|
|
||||||
$detail = trim($test['stderr']) !== '' ? trim($test['stderr']) : trim($test['stdout']);
|
$detail = trim($test['stderr']) !== '' ? trim($test['stderr']) : trim($test['stdout']);
|
||||||
fail_install('Runtime-Test fehlgeschlagen'.($detail !== '' ? ': '.$detail : '.'));
|
fail_install('Runtime-Test fehlgeschlagen'.($detail !== '' ? ': '.$detail : '.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$service = "[Unit]\nDescription=Bratonien NC Connector Sync\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/env bash ".$pluginRoot."/runtime/run-all.sh\n\n";
|
$service = "[Unit]\nDescription=Bratonien NC Connector Sync\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=oneshot\nExecStart=/usr/bin/env bash ".$pluginRoot."/runtime/run-all.sh\n\n";
|
||||||
$timer = "[Unit]\nDescription=Bratonien NC Connector regelmaessig pruefen\n\n[Timer]\nOnBootSec=3min\nOnUnitActiveSec=1min\nRandomizedDelaySec=15s\nPersistent=true\n\n[Install]\nWantedBy=timers.target\n";
|
$timer = "[Unit]\nDescription=Bratonien NC Connector regelmaessig pruefen\n\n[Timer]\nOnBootSec=3min\nOnUnitActiveSec=1min\nRandomizedDelaySec=15s\nPersistent=true\n\n[Install]\nWantedBy=timers.target\n";
|
||||||
file_put_contents($servicePath, $service, LOCK_EX);
|
file_put_contents($servicePath, $service, LOCK_EX); file_put_contents($timerPath, $timer, LOCK_EX); chmod($servicePath,0644); chmod($timerPath,0644);
|
||||||
file_put_contents($timerPath, $timer, LOCK_EX);
|
|
||||||
chmod($servicePath, 0644);
|
|
||||||
chmod($timerPath, 0644);
|
|
||||||
|
|
||||||
$config['state_dir'] = $stateDir;
|
$config['state_dir']=$stateDir;$config['status_file']=$statusFile;$config['runtime']=array('mode'=>'plugin-runtime','config'=>$configPath);
|
||||||
$config['status_file'] = $statusFile;
|
$json=json_encode($config,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);$now=date('Y-m-d H:i:s');
|
||||||
$config['runtime'] = array('mode'=>'plugin-runtime', 'config'=>$configPath);
|
if (!$db->query("UPDATE `".$table."` SET enabled=1, takeover_state='active', config_json='".sql_install($db,$json)."', updated='".sql_install($db,$now)."' WHERE id=".$id)) fail_install('Connector-Status konnte nicht gespeichert werden: '.$db->error);
|
||||||
$json = json_encode($config, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
||||||
$now = date('Y-m-d H:i:s');
|
|
||||||
if (!$db->query("UPDATE `".$table."` SET enabled=1, takeover_state='active', config_json='".sql_install($db, $json)."', updated='".sql_install($db, $now)."' WHERE id=".$id))
|
|
||||||
{
|
|
||||||
fail_install('Connector-Status konnte nicht gespeichert werden: '.$db->error);
|
|
||||||
}
|
|
||||||
|
|
||||||
run_install(array('systemctl', 'daemon-reload'));
|
|
||||||
run_install(array('systemctl', 'enable', '--now', 'bratonien-nc-connector.timer'));
|
|
||||||
|
|
||||||
|
run_install(array('systemctl','daemon-reload')); run_install(array('systemctl','enable','--now','bratonien-nc-connector.timer'));
|
||||||
echo "Aktivierung erfolgreich.\n";
|
echo "Aktivierung erfolgreich.\n";
|
||||||
echo "Verbindung #".$id." verwendet jetzt den nativen Bratonien-Tools-State unter ".$stateDir.".\n";
|
echo "Verbindung #".$id." verwendet jetzt den nativen Bratonien-Tools-State unter ".$stateDir.".\n";
|
||||||
echo "Der gemeinsame Connector-Timer verarbeitet alle installierten connection-*.conf Dateien.\n";
|
echo "Der gemeinsame Connector-Timer verarbeitet alle installierten connection-*.conf Dateien.\n";
|
||||||
|
|||||||
Reference in New Issue
Block a user