Merge branch 'main' of github.com:adminerevo/adminerevo into main

This commit is contained in:
Lionel Laffineur 2023-08-14 15:29:25 +02:00
commit 5bf0c77b99
3 changed files with 253 additions and 7 deletions

View file

@ -0,0 +1,85 @@
<?php
/**
* Import SQL files from a directory
*
* @author joshcangit, https://github.com/joshcangit
* @author Roy-Orbitson, https://github.com/Roy-Orbison
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerImportFromDir {
protected $dir;
/**
* @param string $dir optional directory to read from, other than Adminer's current working dir.
*/
function __construct($dir = '') {
$dir = (string) $dir;
if ($dir != '') {
$dir = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
}
$this->dir = $dir;
}
protected function _readFiles($gz = false) {
$mapped = array();
$glob = "$this->dir*.[Ss][Qq][Ll]";
if ($gz) {
$suffix = '.gz'; # lowercase only because of core
$glob .= $suffix;
$suffix_cut = -3;
}
if ($files = glob($glob)) {
$from = strlen($this->dir);
foreach ($files as $file) {
if ($from) {
$file = substr($file, $from); # do not expose server paths in output
}
if ($gz) {
$mapped[substr($file, 0, $suffix_cut)] = $file;
}
else {
$mapped[$file] = $file;
}
}
}
return $mapped;
}
function importServerPath() {
static $posted = null;
$files = $this->_readFiles();
if (extension_loaded('zlib')) {
$files += $this->_readFiles(true); # core prioritises files without .gz
}
if (count($files) > 1) {
ksort($files);
}
if ($posted !== null || !isset($_POST['webfile'])) {
# use existing translation strings
echo "<fieldset><legend>" . lang('From server') . "</legend><div>";
echo lang('Webserver file %s', '<select name="webfilename">' . optionlist(array('' => lang('Select')) + $files, $posted, true) . '</select>');
echo ' <input type="submit" name="webfile" value="' . lang('Run file') . '">';
echo "</div></fieldset>\n";
$posted = null;
return false; # skip core UI
}
if (
empty($_POST['webfilename'])
|| !is_string($_POST['webfilename'])
|| !array_key_exists($_POST['webfilename'], $files)
) {
$posted = '';
return 'SELECTED_FILE_DOES_NOT_EXIST'; # can't return empty string because of core file_exists() check
}
$posted = $_POST['webfilename'];
return $this->dir . $posted;
}
}

138
plugins/login-external.php Normal file
View file

@ -0,0 +1,138 @@
<?php
/**
* Enables use of saved credentials for accessing a database, without divulging
* them. Provides a mechanism to authenticate each request against any login
* system external to Adminer, or to bypass authentication (for local
* development on a private machine).
*
* @author Roy Orbitson, https://github.com/Roy-Orbison
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerLoginExternal {
protected $externals;
/**
* Provide access details of your database, the current user's authentication status, and other config.
*
* @param array|object $externals An enumeration containing the fields normally completed on the login form:
* server
* database (optional, but recommended. user can always access any db the credentials allow)
* username
* password
* driver (defaults to 'server' for MySQL, but must be specified otherwise,
* e.g. 'pgsql', 'sqlite')
*
* Plus fields to control the behaviour of this plugin:
* authenticated (required boolean, ideally checked on *every* request, true if the
* user is known, currently authenticated, and has db privileges
* equivalent to the specified username)
* app_name (dynamically change the name of the tool from Adminer/AdminerEvo)
* manual_login (optional boolean to control auto-submission of Adminer's own login
* form, and prevents logging out whilst authenticated)
* expired_html (optional HTML message to show when user's external authentication
* expires whilst logged in to Adminer)
* failure_html (optional HTML message to show user they are not authenticated, e.g. a
* paragraph containing a link to the login page)
*/
function __construct($externals) {
$externals = (object) $externals;
if (empty($externals->driver)) {
$externals->driver = 'server';
}
if (isset($_POST['auth'])) {
$_POST['auth']['driver'] = $externals->driver;
$_POST['auth']['server'] = $_POST['auth']['username'] = $_POST['auth']['password'] = '';
}
$this->externals = $externals;
}
function name() {
return empty($this->externals->app_name) ? null : $this->externals->app_name;
}
function credentials() {
if (empty($this->externals->authenticated)) {
# always check external stat rather than relying on adminer's session login
auth_error(
empty($this->externals->expired_html) ?
'External authentication expired.' :
$this->externals->expired_html
);
return false;
}
return [
$this->externals->server,
$this->externals->username,
$this->externals->password,
];
}
function database() {
return empty($this->externals->database) ? null : $this->externals->database;
}
function loginForm() {
if (empty($this->externals->authenticated)) {
if (empty($this->externals->failure_html)) {
echo '<p>You must first log in to the system that grants access to this tool.</p>';
}
else {
echo $this->externals->failure_html;
}
return false;
}
if (empty($this->externals->manual_login)) {
echo script(
<<<EOJS
document.addEventListener(
'DOMContentLoaded',
function() {
document.forms[0].submit();
},
true
);
EOJS
);
}
}
function loginFormField($name, $heading) {
# only for user's benefit, submitted values are overridden by config
$value = '';
switch ($name) {
case 'db':
$value = h(isset($_GET['username']) ? (isset($_GET['db']) ? $_GET['db'] : '') : $this->database());
return <<<EOHTML
$heading<input type="text" name="auth[$name]" value="$value">
EOHTML;
case 'driver':
if (function_exists('get_driver')) {
$value = h($this->externals->driver);
$driver = h(get_driver($this->externals->driver)) ?: 'Unknown';
return <<<EOHTML
$heading<input type="hidden" name="auth[$name]" value="$value">$driver
EOHTML;
}
$value = ' value="' . h($this->externals->driver) . '"';
# don't break
case 'server':
case 'username':
case 'password':
return <<<EOHTML
<input type="hidden" name="auth[$name]"$value>
EOHTML;
}
}
function login($login, $password) {
return !empty($this->externals->authenticated);
}
}

View file

@ -54,16 +54,39 @@ function tablesFilterInput() {
}
sessionStorage && document.addEventListener('DOMContentLoaded', function () {
var db = qs('#dbs').querySelector('select');
db = db.options[db.selectedIndex].text;
if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){
qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter');
tablesFilter();
if (qs('#dbs') != null) {
var db = qs('#dbs').querySelector('select');
db = db.options[db.selectedIndex].text;
if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){
qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter');
tablesFilter();
}
sessionStorage.setItem('adminer_tables_filter_db', db);
}
sessionStorage.setItem('adminer_tables_filter_db', db);
document.addEventListener('keyup', function(event) {
if (event.ctrlKey && event.shiftKey && event.key == 'F') {
qs('#filter-field').focus();
return;
}
});
qs('#filter-field').addEventListener('keydown', function(event) {
if (event.key == 'Enter' || event.keyCode == 13 || event.which == 13) {
event.preventDefault();
return false;
}
});
});
</script>
<p class="jsonly"><input id="filter-field" autocomplete="off"><?php echo script("qs('#filter-field').oninput = tablesFilterInput;"); ?>
<fieldset style="margin-left: .8em;">
<legend><?php echo lang('Filter tables'); ?></legend>
<div>
<input type="search" id="filter-field" autocomplete="off" placeholder="Ctrl + Shift + F"><?php echo script("qs('#filter-field').oninput = tablesFilterInput;"); ?>
<input type="button" id="filter-field-reset" value="<?php echo lang('Clear'); ?>">
<?php echo script("qs('#filter-field-reset').onclick = function() { qs('#filter-field').value = ''; qs('#filter-field').dispatchEvent(new Event('input')); }"); ?>
</div>
</fieldset>
<?php
}
}