diff --git a/CHANGELOG b/CHANGELOG index 3a71e59c2..ee50eb16e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ CHANGELOG Roundcube Webmail =========================== +- Enigma: Add script to import keys from filesystem to the db storage (for multihost) + +RELEASE 1.4.1 +------------- - Elastic: Change HTML editor widget to improve form flow (#6992) - Elastic: Fix position of mobile floating action button (#7038) - Managesieve: Fix locked UI after opening filter frame (#7007) diff --git a/plugins/enigma/bin/import_keys.sh b/plugins/enigma/bin/import_keys.sh new file mode 100755 index 000000000..e56cedc34 --- /dev/null +++ b/plugins/enigma/bin/import_keys.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env php + | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(__DIR__ . '/../../../') . '/'); + +require INSTALL_PATH . 'program/include/clisetup.php'; + +$rcmail = rcube::get_instance(); + +// get arguments +$args = rcube_utils::get_opt(array( + 'u' => 'user', + 'h' => 'host', + 'd' => 'dir', + 'x' => 'dry-run', +)); + +if ($_SERVER['argv'][1] == 'help') { + print_usage(); + exit; +} + +if (empty($args['dir'])) { + rcube::raise_error("--dir argument is required", true); +} + +$host = get_host($args); +$dirs = array(); + +// Read the homedir and iterate over all subfolders (as users) +if (empty($args['user'])) { + if ($dh = opendir($args['dir'])) { + while (($dir = readdir($dh)) !== false) { + if ($dir != '.' && $dir != '..') { + $dirs[$args['dir'] . '/' . $dir] = $dir; + } + } + closedir($dh); + } +} +// a single user +else { + $dirs = array($args['dir'] => $args['user']); +} + +foreach ($dirs as $dir => $user) { + echo "Importing keys from $dir\n"; + + if ($user_id = get_user_id($user, $host)) { + reset_state($user_id, !empty($args['dry-run'])); + import_dir($user_id, $dir, !empty($args['dry-run'])); + } +} + + +function print_usage() +{ + print "Usage: import.sh [options]\n"; + print "Options:\n"; + print " --user=username User, if not set --dir subfolders will be iterated\n"; + print " --host=host The IMAP hostname or IP the given user is related to\n"; + print " --dir=path Location of the gpg homedir\n"; + print " --dry-run Do nothing, just list found user/files\n"; +} + +function get_host($args) +{ + global $rcmail; + + if (empty($args['host'])) { + $hosts = $rcmail->config->get('default_host', ''); + if (is_string($hosts)) { + $args['host'] = $hosts; + } + else if (is_array($hosts) && count($hosts) == 1) { + $args['host'] = reset($hosts); + } + else { + rcube::raise_error("Specify a host name", true); + } + + // host can be a URL like tls://192.168.12.44 + $host_url = parse_url($args['host']); + if ($host_url['host']) { + $args['host'] = $host_url['host']; + } + } + + return $args['host']; +} + +function get_user_id($username, $host) +{ + global $rcmail; + + $db = $rcmail->get_dbh(); + + // find user in local database + $user = rcube_user::query($username, $host); + + if (empty($user)) { + rcube::raise_error("User does not exist: $username"); + } + + return $user->ID; +} + +function reset_state($user_id, $dry_run = false) +{ + global $rcmail; + + if ($dry_run) { + return; + } + + $db = $rcmail->get_dbh(); + + $db->query("DELETE FROM " . $db->table_name('filestore', true) + . " WHERE `user_id` = ? AND `context` = ?", + $user_id, 'enigma'); +} + +function import_dir($user_id, $dir, $dry_run = false) +{ + global $rcmail; + + $db = $rcmail->get_dbh(); + $table = $db->table_name('filestore', true); + $db_files = array('pubring.gpg', 'secring.gpg', 'pubring.kbx'); + $maxsize = min($db->get_variable('max_allowed_packet', 1048500), 4*1024*1024) - 2000; + + foreach (glob("$dir/private-keys-v1.d/*.key") as $file) { + $db_files[] = substr($file, strlen($dir) + 1); + } + + foreach ($db_files as $file) { + if ($mtime = @filemtime("$dir/$file")) { + $data = file_get_contents("$dir/$file"); + $data = base64_encode($data); + $datasize = strlen($data); + + if ($datasize > $maxsize) { + rcube::raise_error(array( + 'code' => 605, 'line' => __LINE__, 'file' => __FILE__, + 'message' => "Enigma: Failed to save $file. Size exceeds max_allowed_packet." + ), true, false); + + continue; + } + + echo "* $file\n"; + + if ($dry_run) { + continue; + } + + $result = $db->query( + "INSERT INTO $table (`user_id`, `context`, `filename`, `mtime`, `data`)" + . " VALUES(?, 'enigma', ?, ?, ?)", + $user_id, $file, $mtime, $data); + + if ($db->is_error($result)) { + rcube::raise_error(array( + 'code' => 605, 'line' => __LINE__, 'file' => __FILE__, + 'message' => "Enigma: Failed to save $file into database." + ), true, false); + } + } + } +}