diff --git a/Dockerfile b/Dockerfile index fd40ac1..610dbda 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,15 @@ -FROM composer:1.7 +FROM composer:2.2 -ENV TINI_VERSION 0.18.0-r0 - -RUN apk add --no-cache tini=$TINI_VERSION - -ADD . /src/app/ +RUN apk add --no-cache tini tzdata WORKDIR /src/app -RUN composer install +COPY . . -RUN cp includes/config.environment.inc.php includes/config.inc.php +RUN set -xe; \ + composer install; \ + cp includes/config.environment.inc.php includes/config.inc.php +ENV PORT 80 EXPOSE 80 -ENTRYPOINT [ "tini", "--", "php", "-S", "0.0.0.0:80" ] +ENTRYPOINT [ "sh", "-c", "tini -- php -S 0.0.0.0:$PORT" ] diff --git a/README.markdown b/README.markdown index ddf39d3..0938c08 100644 --- a/README.markdown +++ b/README.markdown @@ -41,7 +41,7 @@ git clone https://github.com/nrk/predis.git vendor Docker Image ============ -A public [phpRedisAdmin Docker image](https://hub.docker.com/r/erikdubbelboer/phpredisadmin/) is available on Docker Hub [automatically built](https://docs.docker.com/docker-hub/builds/) from latest source. +A public [phpRedisAdmin Docker image](https://hub.docker.com/r/erikdubbelboer/phpredisadmin/) is available on Docker Hub built from the latest tag. The file ```includes/config.environment.inc.php``` is used as the configuration file to allow environment variables to be used as configuration values. Example: ``` @@ -55,7 +55,10 @@ Environment variables summary * ``REDIS_1_HOST`` - define host of the Redis server * ``REDIS_1_NAME`` - define name of the Redis server * ``REDIS_1_PORT`` - define port of the Redis server +* ``REDIS_1_SCHEME`` - define scheme of the Redis server (tcp or tls) * ``REDIS_1_AUTH`` - define password of the Redis server +* ``REDIS_1_AUTH_FILE`` - define file containing the password of the Redis server +* ``REDIS_1_DATABASES`` - You can modify you config to prevent phpRedisAdmin from using CONFIG command * ``ADMIN_USER`` - define username for user-facing Basic Auth * ``ADMIN_PASS`` - define password for user-facing Basic Auth diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..1627ff2 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.13.x | :white_check_mark: | +| 1.12.x | :white_check_mark: | +| < 1.12 | :x: | + +## Reporting a Vulnerability + +Vulnerabilities can be emailed to erik@dubbelboer.com diff --git a/composer.json b/composer.json index 0cfdc77..3b3ab81 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "erik-dubbelboer/php-redis-admin", "description": "Simple web interface to manage Redis databases.", - "version": "1.13.0", + "version": "1.24.0", "license": "CC-BY-3.0", "homepage": "https://github.com/ErikDubbelboer/phpRedisAdmin", "authors": [ @@ -13,8 +13,11 @@ } ], "require": { - "predis/predis": "1.1.x-dev" + "ext-mbstring": "*", + "ext-json": "*", + "predis/predis": "v2.3.0", + "paragonie/random_compat": ">=2" }, "minimum-stability": "stable", - "target-dir": "ErikDubbelboer/phpRedisAdmin" + "target-dir": "ErikDubbelboer/phpRedisAdmin" } diff --git a/composer.lock b/composer.lock index ac3a614..f724f31 100644 --- a/composer.lock +++ b/composer.lock @@ -4,31 +4,82 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0c346d5e2f2e0897260911e1b2966180", + "content-hash": "401ff61cebe5223d003a47192d7c3d6a", "packages": [ + { + "name": "paragonie/random_compat", + "version": "v9.99.100", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", + "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", + "shasum": "" + }, + "require": { + "php": ">= 7" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^1" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com/" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "polyfill", + "pseudorandom", + "random" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/random_compat/issues", + "source": "https://github.com/paragonie/random_compat" + }, + "time": "2020-10-15T08:29:30+00:00" + }, { "name": "predis/predis", - "version": "v1.1.x-dev", + "version": "v2.3.0", "source": { "type": "git", - "url": "https://github.com/nrk/predis.git", - "reference": "111d100ee389d624036b46b35ed0c9ac59c71313" + "url": "https://github.com/predis/predis.git", + "reference": "bac46bfdb78cd6e9c7926c697012aae740cb9ec9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nrk/predis/zipball/111d100ee389d624036b46b35ed0c9ac59c71313", - "reference": "111d100ee389d624036b46b35ed0c9ac59c71313", + "url": "https://api.github.com/repos/predis/predis/zipball/bac46bfdb78cd6e9c7926c697012aae740cb9ec9", + "reference": "bac46bfdb78cd6e9c7926c697012aae740cb9ec9", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": "^7.2 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "friendsofphp/php-cs-fixer": "^3.3", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^8.0 || ^9.4" }, "suggest": { - "ext-curl": "Allows access to Webdis when paired with phpiredis", - "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + "ext-relay": "Faster connection with in-memory caching (>=0.6.2)" }, "type": "library", "autoload": { @@ -42,29 +93,41 @@ ], "authors": [ { - "name": "Daniele Alessandri", - "email": "suppakilla@gmail.com", - "homepage": "http://clorophilla.net/" + "name": "Till Krüss", + "homepage": "https://till.im/", + "role": "Maintainer" } ], - "description": "Flexible and feature-complete Redis client for PHP and HHVM", - "homepage": "http://github.com/nrk/predis", + "description": "A flexible and feature-complete Redis client for PHP.", + "homepage": "http://github.com/predis/predis", "keywords": [ "nosql", "predis", "redis" ], - "time": "2017-07-12T14:39:17+00:00" + "support": { + "issues": "https://github.com/predis/predis/issues", + "source": "https://github.com/predis/predis/tree/v2.3.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/tillkruss", + "type": "github" + } + ], + "time": "2024-11-21T20:00:02+00:00" } ], "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "predis/predis": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, - "platform": [], - "platform-dev": [] + "platform": { + "ext-mbstring": "*", + "ext-json": "*" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/css/common.css b/css/common.css index b2a8431..9dc6276 100644 --- a/css/common.css +++ b/css/common.css @@ -52,6 +52,6 @@ background: url(http://github.com/images/add.png) left center no-repeat; .data { -white-space: pre; +white-space: pre-wrap; } diff --git a/css/frame.css b/css/frame.css index e54ca9e..7cf935d 100644 --- a/css/frame.css +++ b/css/frame.css @@ -14,7 +14,6 @@ margin-left: -8em; } form .button { -margin-left: -7em; } @@ -53,3 +52,13 @@ float: left; margin: 1em; } + +.exception { +border: 1px solid #ff0000; +background-color: rgba(255, 0, 0, 0.2); +color: #880000; +padding: 10px; +border-radius: 5px; +margin: 20px; +} + diff --git a/css/index.css b/css/index.css index 7b898e5..4a56aa9 100644 --- a/css/index.css +++ b/css/index.css @@ -3,10 +3,14 @@ position: absolute; top: 0; bottom: 0; left: 0; +display: flex; +flex-direction: column; width: 290px; height: 100%; +} + +#header { padding-left: 10px; -border-right: 1px solid #000; } #sidebar a, #sidebar a:visited { @@ -23,7 +27,9 @@ text-decoration: underline; #keys { +flex-grow: 1; width: 290px; +margin-top: 10px; padding-left: 10px; overflow: auto; } @@ -36,6 +42,7 @@ padding: 0; #keys li { font-weight: normal; +white-space: nowrap; } #keys li.folder { @@ -115,6 +122,7 @@ background-color: #aaa; cursor: col-resize; padding: 0; margin: 0; +border-left: 1px solid #000; } #resize-layover { @@ -133,11 +141,12 @@ top: 0; left: 305px; right: 0; bottom: 0; -padding-left: 2em; } #frame iframe { -width: 100%; +width: calc(100% - 3em); height: 100%; +margin-left: 1.5em; +margin-right: 1.5em; } diff --git a/delete.php b/delete.php index cde8539..c329919 100644 --- a/delete.php +++ b/delete.php @@ -1,13 +1,13 @@ del($key); } @@ -73,4 +73,3 @@ die('?view&s=' . $server['id'] . '&d=' . $server['db'] . '&key=' . urlencode($keys[0])); } -?> diff --git a/docker-compose.yml b/docker-compose.yml index dab64b9..5ef83df 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,16 @@ -phpredisadmin: - build: . - environment: - - ADMIN_USER=admin - - ADMIN_PASS=admin - - REDIS_1_HOST=redis - - REDIS_1_PORT=6379 - links: - - redis - ports: - - "80:80" +services: + phpredisadmin: + build: . + environment: + - ADMIN_USER=admin + - ADMIN_PASS=admin + - REDIS_1_HOST=redis + - REDIS_1_PORT=6379 + links: + - redis + ports: + - "80:80" -redis: - image: redis - command: --loglevel verbose + redis: + image: redis + command: --loglevel verbose diff --git a/edit.php b/edit.php index 0940503..998012c 100644 --- a/edit.php +++ b/edit.php @@ -2,8 +2,7 @@ require_once 'includes/common.inc.php'; - - +global $redis, $config, $csrfToken, $server; // Are we editing or creating a new key? $edit = false; @@ -35,72 +34,83 @@ die('ERROR: could not encode value'); } - // String - if ($_POST['type'] == 'string') { - $redis->set($key, $value); - } - - // Hash - else if (($_POST['type'] == 'hash') && isset($_POST['hkey'])) { - if (strlen($_POST['hkey']) > $config['maxkeylen']) { - die('ERROR: Your hash key is to long (max length is '.$config['maxkeylen'].')'); + try { + // String + if ($_POST['type'] == 'string') { + $redis->set($key, $value); } - if ($edit && !$redis->hExists($key, input_convert($_POST['hkey']))) { - $redis->hDel($key, input_convert($_GET['hkey'])); + // Hash + else if (($_POST['type'] == 'hash') && isset($_POST['hkey'])) { + if (strlen($_POST['hkey']) > $config['maxkeylen']) { + die('ERROR: Your hash key is to long (max length is '.$config['maxkeylen'].')'); + } + + if ($edit && !$redis->hExists($key, input_convert($_POST['hkey']))) { + $redis->hDel($key, input_convert($_GET['hkey'])); + } + + $redis->hSet($key, input_convert($_POST['hkey']), $value); } - $redis->hSet($key, input_convert($_POST['hkey']), $value); - } + // List + else if (($_POST['type'] == 'list') && isset($_POST['index'])) { + $size = $redis->lLen($key); + + if (($_POST['index'] == '') || + ($_POST['index'] == $size)) { + // Push it at the end + $redis->rPush($key, $value); + } else if ($_POST['index'] == -1) { + // Push it at the start + $redis->lPush($key, $value); + } else if (($_POST['index'] >= 0) && + ($_POST['index'] < $size)) { + // Overwrite an index + $redis->lSet($key, input_convert($_POST['index']), $value); + } else { + die('ERROR: Out of bounds index'); + } + } - // List - else if (($_POST['type'] == 'list') && isset($_POST['index'])) { - $size = $redis->lLen($key); - - if (($_POST['index'] == '') || - ($_POST['index'] == $size)) { - // Push it at the end - $redis->rPush($key, $value); - } else if ($_POST['index'] == -1) { - // Push it at the start - $redis->lPush($key, $value); - } else if (($_POST['index'] >= 0) && - ($_POST['index'] < $size)) { - // Overwrite an index - $redis->lSet($key, input_convert($_POST['index']), $value); - } else { - die('ERROR: Out of bounds index'); + // Set + else if ($_POST['type'] == 'set') { + if ($_POST['value'] != $_POST['oldvalue']) { + // The only way to edit a Set value is to add it and remove the old value. + $redis->sRem($key, encodeOrDecode('save', $key, input_convert($_POST['oldvalue']))); + $redis->sAdd($key, $value); + } } - } - // Set - else if ($_POST['type'] == 'set') { - if ($_POST['value'] != $_POST['oldvalue']) { - // The only way to edit a Set value is to add it and remove the old value. - $redis->sRem($key, encodeOrDecode('save', $key, input_convert($_POST['oldvalue']))); - $redis->sAdd($key, $value); + // ZSet + else if (($_POST['type'] == 'zset') && isset($_POST['score']) && is_numeric($_POST['score'])) { + // The only way to edit a ZSet value is to add it and remove the old value. + $redis->zRem($key, encodeOrDecode('save', $key, input_convert($_POST['oldvalue']))); + $redis->zAdd($key, input_convert($_POST['score']), $value); } - } - // ZSet - else if (($_POST['type'] == 'zset') && isset($_POST['score'])) { - // The only way to edit a ZSet value is to add it and remove the old value. - $redis->zRem($key, encodeOrDecode('save', $key, input_convert($_POST['oldvalue']))); - $redis->zAdd($key, input_convert($_POST['score']), $value); - } + // Refresh the top so the key tree is updated. + require 'includes/header.inc.php'; - // Refresh the top so the key tree is updated. - require 'includes/header.inc.php'; + ?> + + - - +