mirror of
https://github.com/chevereto/chevereto.git
synced 2025-10-26 00:36:15 +02:00
Automatic push 4.0.11
This commit is contained in:
BIN
.github/banner/chevereto-ultimate-remix.png
vendored
Normal file
BIN
.github/banner/chevereto-ultimate-remix.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
BIN
.github/banner/chevereto-ultimate.png
vendored
BIN
.github/banner/chevereto-ultimate.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 164 KiB |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
.DS_Store
|
||||
/.env
|
||||
/.idea
|
||||
/app/.upgrading
|
||||
/app/CHEVERETO_LICENSE_KEY
|
||||
/app/vendor
|
||||
/app/build
|
||||
/app/.phpunit.cache
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
Chevereto 4.0.10 (2024-02-07)
|
||||
|
||||
- ✅ Added version CLI command
|
||||
- ✅ Improved error display on CLI install
|
||||
- 🐞 Fixed bug in AWS open_basedir restriction
|
||||
- 🐞 Fixed bug in banners settings page
|
||||
- 🐞 Fixed bug in comments implementation
|
||||
- 🐞 Fixed bug in file size handling
|
||||
- 🐞 Fixed bug in notifications missing links
|
||||
- 🐞 Fixed bug in NSFW display
|
||||
- 🐞 Fixed bug in Spanish translation
|
||||
- 🐞 Fixed bug in update database query
|
||||
- 🐞 Fixed bug in upload file title
|
||||
- 🐞 Fixed bug in user interface for iOS
|
||||
- 💅 Disabled listing viewer by default
|
||||
- 💅 Improved arrow style navigation
|
||||
- 💅 Improved notifications display (default avatar)
|
||||
8
.package/4.0.11.txt
Normal file
8
.package/4.0.11.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
Chevereto 4.0.11 (2024-02-21)
|
||||
|
||||
- ✅ Added one-click upgrade system
|
||||
- ✅ Added license key configuration
|
||||
- ✅ Added /dashboard/?license
|
||||
- ✅ Added /dashboard/?installed
|
||||
- ✅ Added /dashboard/?upgrade
|
||||
- 💅 Improved software version at dashboard
|
||||
@@ -1,12 +1,14 @@
|
||||
# Chevereto: Ultimate image sharing software 🦄
|
||||
# Chevereto: Ultimate image sharing software
|
||||
|
||||
> 🔔 [Subscribe](https://chv.to/newsletter) to don't miss any update regarding Chevereto.
|
||||
|
||||
<p align="center">
|
||||
<img alt="Chevereto" src="chevereto.svg" width="50%">
|
||||
<a href="https://chevereto.com"><img alt="Chevereto" src="chevereto.svg" width="80%"></a>
|
||||
</p>
|
||||
|
||||

|
||||
[](https://chevereto.com)
|
||||
|
||||
[](https://chv.to/community)
|
||||
|
||||
[](https://chv.to/community)
|
||||
[](LICENSE)
|
||||
|
||||
10
app/composer.lock
generated
10
app/composer.lock
generated
@@ -5378,16 +5378,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.10.57",
|
||||
"version": "1.10.59",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "1627b1d03446904aaa77593f370c5201d2ecc34e"
|
||||
"reference": "e607609388d3a6d418a50a49f7940e8086798281"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/1627b1d03446904aaa77593f370c5201d2ecc34e",
|
||||
"reference": "1627b1d03446904aaa77593f370c5201d2ecc34e",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/e607609388d3a6d418a50a49f7940e8086798281",
|
||||
"reference": "e607609388d3a6d418a50a49f7940e8086798281",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5436,7 +5436,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-01-24T11:51:34+00:00"
|
||||
"time": "2024-02-20T13:59:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
||||
@@ -87,4 +87,5 @@ return [
|
||||
'CHEVERETO_SERVICING' => 'server',
|
||||
'CHEVERETO_SESSION_SAVE_HANDLER' => 'files',
|
||||
'CHEVERETO_SESSION_SAVE_PATH' => '/tmp',
|
||||
'CHEVERETO_EDITION' => 'pro',
|
||||
];
|
||||
|
||||
@@ -43,6 +43,7 @@ if ($opts === []) {
|
||||
}
|
||||
define('ACCESS', $access);
|
||||
require_once __DIR__ . '/../load/php-boot.php';
|
||||
require_once __DIR__ . '/../load/loader.php';
|
||||
require_once loaderHandler(
|
||||
$_COOKIE,
|
||||
$_ENV,
|
||||
|
||||
@@ -13,7 +13,17 @@ use function Chevereto\Legacy\loaderHandler;
|
||||
|
||||
define('ACCESS', 'web');
|
||||
|
||||
require_once __DIR__ . '/../load/php-boot.php';
|
||||
$appDir = __DIR__ . '/../..';
|
||||
$loadDir = __DIR__ . '/../load';
|
||||
require_once $loadDir . '/php-boot.php';
|
||||
$uri = $_SERVER['REQUEST_URI'] ?? '';
|
||||
$parseUri = parse_url($uri);
|
||||
if (in_array($parseUri['path'], ['/upgrading', '/upgrading/'])
|
||||
&& file_exists($appDir . '/.upgrading/upgrading.lock')) {
|
||||
require $appDir . '/upgrading.php';
|
||||
exit;
|
||||
}
|
||||
require_once $loadDir . '/loader.php';
|
||||
require_once loaderHandler(
|
||||
$_COOKIE,
|
||||
$_ENV,
|
||||
|
||||
@@ -594,6 +594,7 @@ $settings_updates = [
|
||||
'4.0.10' => [
|
||||
'listing_viewer' => 0,
|
||||
],
|
||||
'4.0.11' => null,
|
||||
];
|
||||
$cheveretoFreeMap = [
|
||||
'1.0.0' => '3.8.3',
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
const APP_VERSION = '4.0.10';
|
||||
const APP_VERSION = '4.0.11';
|
||||
const APP_VERSION_AKA = 'macanudo';
|
||||
|
||||
@@ -33,7 +33,6 @@ use function Chevereto\Legacy\G\is_url;
|
||||
use function Chevereto\Legacy\G\json_error;
|
||||
use function Chevereto\Legacy\G\json_output;
|
||||
use function Chevereto\Legacy\G\random_string;
|
||||
use function Chevereto\Legacy\G\timing_safe_compare;
|
||||
use function Chevereto\Legacy\getSetting;
|
||||
use function Chevereto\Vars\env;
|
||||
use function Chevereto\Vars\files;
|
||||
@@ -66,7 +65,7 @@ return function (Handler $handler) {
|
||||
if ((getSetting('api_v1_key') ?? '') == '') {
|
||||
throw new Exception("API V1 public key can't be null. Go to your dashboard and set the Guest API key.", 0);
|
||||
}
|
||||
if (!timing_safe_compare(getSetting('api_v1_key'), $key)) {
|
||||
if (!hash_equals(getSetting('api_v1_key'), $key)) {
|
||||
throw new Exception("Invalid guest API key.", 100);
|
||||
}
|
||||
} else {
|
||||
@@ -124,7 +123,7 @@ return function (Handler $handler) {
|
||||
throw new Exception('Upload using base64 source must be done using POST method.', 130);
|
||||
}
|
||||
$source = trim(preg_replace('/\s+/', '', $source));
|
||||
if (!timing_safe_compare(base64_encode(base64_decode($source)), $source)) {
|
||||
if (!hash_equals(base64_encode(base64_decode($source)), $source)) {
|
||||
throw new Exception('Invalid base64 string.', 120);
|
||||
}
|
||||
$api_temp_file = tempnam(sys_get_temp_dir(), 'chvtemp');
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use function Chevere\String\randomString;
|
||||
use Chevereto\Config\Config;
|
||||
use function Chevereto\Legacy\badgePaid;
|
||||
use Chevereto\Legacy\Classes\Akismet;
|
||||
@@ -45,11 +46,11 @@ use function Chevereto\Legacy\G\is_valid_url;
|
||||
use function Chevereto\Legacy\G\redirect;
|
||||
use function Chevereto\Legacy\G\sanitize_relative_path;
|
||||
use function Chevereto\Legacy\G\starts_with;
|
||||
use function Chevereto\Legacy\G\timing_safe_compare;
|
||||
use function Chevereto\Legacy\G\unlinkIfExists;
|
||||
use function Chevereto\Legacy\get_available_languages;
|
||||
use function Chevereto\Legacy\get_chv_default_setting;
|
||||
use function Chevereto\Legacy\get_share_links;
|
||||
use function Chevereto\Legacy\getLicenseKey;
|
||||
use function Chevereto\Legacy\getSetting;
|
||||
use function Chevereto\Legacy\getSettings;
|
||||
use function Chevereto\Legacy\getSystemNotices;
|
||||
@@ -73,6 +74,34 @@ return function (Handler $handler) {
|
||||
|
||||
return;
|
||||
}
|
||||
if (env()['CHEVERETO_CONTEXT'] !== 'saas'
|
||||
&& ($handler->request()[0] ?? null) === 'upgrade'
|
||||
) {
|
||||
if (!$handler::checkAuthToken(request()['auth_token'] ?? '')) {
|
||||
$handler->issueError(403);
|
||||
|
||||
return;
|
||||
}
|
||||
$upgradingDir = PATH_APP . '.upgrading/';
|
||||
if (!is_dir($upgradingDir)) {
|
||||
mkdir($upgradingDir);
|
||||
}
|
||||
$upgradingLock = $upgradingDir . 'upgrading.lock';
|
||||
unlinkIfExists($upgradingLock);
|
||||
$token = randomString(128);
|
||||
touch($upgradingLock);
|
||||
file_put_contents($upgradingLock, $token);
|
||||
$params = [
|
||||
'action' => 'download',
|
||||
'token' => $token,
|
||||
'return' => 'dashboard/?installed',
|
||||
];
|
||||
$query = http_build_query($params);
|
||||
redirect(
|
||||
get_base_url('upgrading/?' . $query),
|
||||
302,
|
||||
);
|
||||
}
|
||||
$doing = $handler->request()[0] ?? 'stats';
|
||||
$logged_user = Login::getUser();
|
||||
if ($logged_user === []) {
|
||||
@@ -91,7 +120,7 @@ return function (Handler $handler) {
|
||||
}
|
||||
$route_prefix = 'dashboard';
|
||||
$routes = [
|
||||
'stats' => _s('Stats'),
|
||||
'stats' => _s('Home'),
|
||||
'images' => _s('Images'),
|
||||
'albums' => _n('Album', 'Albums', 20),
|
||||
'users' => _n('User', 'Users', 20),
|
||||
@@ -118,7 +147,7 @@ return function (Handler $handler) {
|
||||
}
|
||||
}
|
||||
$icons = [
|
||||
'stats' => 'fas fa-chart-bar',
|
||||
'stats' => 'fas fa-home',
|
||||
'images' => 'fas fa-image',
|
||||
'albums' => 'fas fa-images',
|
||||
'users' => 'fas fa-users',
|
||||
@@ -212,6 +241,7 @@ return function (Handler $handler) {
|
||||
if ($doing == '') {
|
||||
$doing = $default_route;
|
||||
}
|
||||
$route_menu = [];
|
||||
foreach ($routes as $route => $label) {
|
||||
$aux = str_replace('_', '-', $route);
|
||||
$handler::setCond($route_prefix . '_' . $aux, $doing == $aux);
|
||||
@@ -285,24 +315,34 @@ return function (Handler $handler) {
|
||||
'files' => get_app_version(),
|
||||
'db' => getSetting('chevereto_version_installed') ?? ''
|
||||
];
|
||||
$links = [];
|
||||
$linksButtons = '';
|
||||
$links = [
|
||||
[
|
||||
'label' => _s('Documentation'),
|
||||
'icon' => 'fas fa-book',
|
||||
'href' => $handler::var('docsBaseUrl')
|
||||
],
|
||||
[
|
||||
'label' => _s('%s docs', _s('Admin')),
|
||||
'icon' => 'fas fa-user-tie',
|
||||
'href' => 'https://v4-admin.chevereto.com'
|
||||
],
|
||||
[
|
||||
'label' => _s('%s docs', _n('User', 'Users', 1)),
|
||||
'icon' => 'fas fa-user',
|
||||
'href' => 'https://v4-user.chevereto.com'
|
||||
],
|
||||
];
|
||||
$licenseKey = getLicenseKey();
|
||||
$handler::setVar('licenseKey', $licenseKey);
|
||||
if (env()['CHEVERETO_CONTEXT'] !== 'saas') {
|
||||
$upgradeClass = 'hidden';
|
||||
$upgradeLink = get_base_url('dashboard/upgrade/?auth_token=' . $handler::getAuthToken());
|
||||
if ($licenseKey !== '' && env()['CHEVERETO_EDITION'] === 'free') {
|
||||
$upgradeClass = '';
|
||||
}
|
||||
$upgradeTitle = '<i class=\"fa-solid fa-boxes-packing\"></i> ' . _s('Upgrade now');
|
||||
$links = array_merge($links, [
|
||||
[
|
||||
'label' => _s('Upgrade now'),
|
||||
'icon' => 'fas fa-download',
|
||||
'class' => 'green ' . $upgradeClass,
|
||||
'attr' => 'data-action="upgrade" data-options=\'{"title":"' . $upgradeTitle . '"}\' href="' . $upgradeLink . '" data-confirm="' . _s("The latest release will be downloaded and extracted in the filesystem.") . '"',
|
||||
],
|
||||
]);
|
||||
$links = array_merge($links, [
|
||||
[
|
||||
'label' => _s("License key"),
|
||||
'icon' => 'fas fa-key',
|
||||
'class' => 'accent outline',
|
||||
'attr' => 'data-action="license" data-modal="edit" data-target="modal-license-key"'
|
||||
],
|
||||
]);
|
||||
}
|
||||
if (env()['CHEVERETO_CONTEXT'] === 'saas') {
|
||||
$links = array_merge($links, [
|
||||
[
|
||||
@@ -311,33 +351,12 @@ return function (Handler $handler) {
|
||||
'href' => 'https://chevereto.cloud/support'
|
||||
],
|
||||
]);
|
||||
} else {
|
||||
$links = array_merge($links, [
|
||||
[
|
||||
'label' => _s("Releases"),
|
||||
'icon' => 'fas fa-rocket',
|
||||
'href' => 'https://releases.chevereto.com'
|
||||
],
|
||||
[
|
||||
'label' => _s('Support'),
|
||||
'icon' => 'fas fa-medkit',
|
||||
'href' => 'https://chevereto.com/support'
|
||||
],
|
||||
[
|
||||
'label' => _s('Community'),
|
||||
'icon' => 'fas fa-users',
|
||||
'href' => 'https://chevereto.com/community'
|
||||
],
|
||||
[
|
||||
'label' => _s("License"),
|
||||
'icon' => 'fas fa-key',
|
||||
'href' => 'https://chevereto.com/panel/license'
|
||||
]
|
||||
]);
|
||||
}
|
||||
foreach ($links as $link) {
|
||||
$linksButtons .= strtr('<a href="%href%" target="_blank" class="btn btn-small default margin-right-5 margin-top-5"><span class="btn-icon fa-btn-icon %icon%"></span> %label%</a>', [
|
||||
'%href%' => $link['href'],
|
||||
$attr = $link['attr'] ?? 'href="%href%" target="_blank"';
|
||||
$class = $link['class'] ?? 'default';
|
||||
$linksButtons .= strtr('<a ' . $attr . ' class="btn btn-small ' . $class . ' margin-right-5"><span class="btn-icon fa-btn-icon %icon%"></span><span class="btn-text">%label%</span></a>', [
|
||||
'%href%' => $link['href'] ?? '',
|
||||
'%icon%' => $link['icon'],
|
||||
'%label%' => $link['label'],
|
||||
]);
|
||||
@@ -351,7 +370,7 @@ return function (Handler $handler) {
|
||||
if (version_compare($chv_version['files'], $chv_version['db'], '>')) {
|
||||
$install_update_button = $chv_version['db'] . ' DB <span class="fas fa-database"></span> <a href="' . get_base_url('update') . '">' . _s('install update') . '</a>';
|
||||
}
|
||||
$version_check .= '<a data-action="check-for-updates" class="btn btn-small accent margin-right-5 margin-top-5"><span class="fas fa-arrow-alt-circle-up"></span> ' . _s("Check updates") . '</a>';
|
||||
$version_check .= '<a data-action="check-for-updates" class="btn btn-small accent margin-right-5 margin-top-5"><span class="fas fa-circle-up"></span> ' . _s("Check upgrades") . '</a>';
|
||||
if (datetime_diff($cron_last_ran, null, 'm') > 5) {
|
||||
$cronRemark .= ' — <span class="color-fail"><span class="fas fa-exclamation-triangle"></span> ' . _s('not running') . '</span>';
|
||||
}
|
||||
@@ -365,11 +384,11 @@ return function (Handler $handler) {
|
||||
$chv_version_minor = $chv_versioning[0] . '.' . $chv_versioning[1];
|
||||
$system_values = [
|
||||
'chv_version' => [
|
||||
'label' => '<div class="text-align-center"><a href="https://chevereto.com" target="_blank"><img src="' . absolute_to_url(PATH_PUBLIC_CONTENT_LEGACY_SYSTEM . 'chevereto-blue.svg') . '" alt="" width="50%"></a></div>',
|
||||
'label' => '<div class="text-align-center"><a href="https://chevereto.com" target="_blank"><img src="' . absolute_to_url(PATH_PUBLIC_CONTENT_LEGACY_SYSTEM . 'chevereto-blue.svg') . '" alt="" width="80%"></a></div>',
|
||||
'content' => '<div class="phone-text-align-center">'
|
||||
. '<h3 class="margin-bottom-10"><a target="_blank" href="https://releases.chevereto.com/' . $chv_version_major . '/' . $chv_version_minor . '/' . $chv_version['files'] . '">'
|
||||
. '<h3 class="margin-bottom-10 version-display"><a target="_blank" href="https://releases.chevereto.com/' . $chv_version_major . '/' . $chv_version_minor . '/' . $chv_version['files'] . '">'
|
||||
. $chv_version['files']
|
||||
. '<span class="btn-icon fas fas fa-code-branch"></span></a> <span class="software-version-name" title="' . APP_VERSION_AKA . '">' . APP_VERSION_AKA . '</span> </h3>'
|
||||
. '<span class="btn-icon fas fas fa-code-branch margin-left-5"></span></a><span class="software-version-name margin-left-10" title="' . APP_VERSION_AKA . '">' . APP_VERSION_AKA . '</span> </h3>'
|
||||
. $install_update_button
|
||||
. '<div class="margin-bottom-20">' . $version_check . $linksButtons . '</div>
|
||||
</div>'
|
||||
@@ -390,11 +409,48 @@ return function (Handler $handler) {
|
||||
'content' => '<i class="fas fa-network-wired"></i> ' . get_client_ip() . ' <a data-modal="simple" data-target="modal-connecting-ip"><i class="fas fa-question-circle margin-right-5"></i>' . _s('Not your IP?') . '</a>'
|
||||
],
|
||||
];
|
||||
|
||||
$cheveretoLinks = [
|
||||
[
|
||||
'label' => _s('Docs'),
|
||||
'icon' => 'fas fa-book',
|
||||
'href' => $handler::var('docsBaseUrl')
|
||||
],
|
||||
[
|
||||
'label' => _s("Releases"),
|
||||
'icon' => 'fas fa-rocket',
|
||||
'href' => 'https://releases.chevereto.com'
|
||||
],
|
||||
[
|
||||
'label' => _s('Support'),
|
||||
'icon' => 'fas fa-medkit',
|
||||
'href' => 'https://chevereto.com/support'
|
||||
],
|
||||
[
|
||||
'label' => _s('Community'),
|
||||
'icon' => 'fas fa-users',
|
||||
'href' => 'https://chevereto.com/community'
|
||||
],
|
||||
];
|
||||
$cheveretoLinksButtons = '';
|
||||
foreach ($cheveretoLinks as $link) {
|
||||
$attr = $link['attr'] ?? 'href="%href%" target="_blank"';
|
||||
$cheveretoLinksButtons .= strtr('<a ' . $attr . ' class="btn default btn-small margin-right-5"><span class="btn-icon fa-btn-icon %icon%"></span><span class="btn-text">%label%</span></a>', [
|
||||
'%href%' => $link['href'] ?? '',
|
||||
'%icon%' => $link['icon'],
|
||||
'%label%' => $link['label'],
|
||||
]);
|
||||
}
|
||||
|
||||
if (env()['CHEVERETO_CONTEXT'] !== 'saas') {
|
||||
$mysqlVersion = $db->getAttr(PDO::ATTR_SERVER_VERSION);
|
||||
$db->closeCursor();
|
||||
$mysqlServerInfo = $db->getAttr(PDO::ATTR_SERVER_INFO);
|
||||
$system_values_more = [
|
||||
'links' => [
|
||||
'label' => _s('Links'),
|
||||
'content' => $cheveretoLinksButtons,
|
||||
],
|
||||
'cli' => [
|
||||
'label' => 'CLI',
|
||||
'content' => '<i class="fas fa-terminal"></i> <span data-click="select-all">' . PATH_PUBLIC . 'app/bin/legacy</span>',
|
||||
@@ -1412,7 +1468,7 @@ return function (Handler $handler) {
|
||||
if (isset($page['id']) && $page['id'] == $v['page_id']) {
|
||||
continue; // Skip on same thing
|
||||
}
|
||||
if (timing_safe_compare($v[$kk], $POST[$kk])) {
|
||||
if (hash_equals($v[$kk], $POST[$kk])) {
|
||||
$input_errors[$kk] = sprintf($vv, $v['page_id']);
|
||||
}
|
||||
}
|
||||
@@ -1427,7 +1483,7 @@ return function (Handler $handler) {
|
||||
|
||||
try {
|
||||
Page::writePage(['file_path' => $POST['page_file_path'], 'code' => $page_write_code]);
|
||||
if ($handler->request()[2] == 'edit' && isset($page['file_path']) && !timing_safe_compare($page['file_path'], $POST['page_file_path'])) {
|
||||
if ($handler->request()[2] == 'edit' && isset($page['file_path']) && !hash_equals($page['file_path'], $POST['page_file_path'])) {
|
||||
unlinkIfExists(Page::getPath($page['file_path']));
|
||||
}
|
||||
if (isset($page['id'])) {
|
||||
@@ -1445,7 +1501,7 @@ return function (Handler $handler) {
|
||||
foreach ($page_fields as $v) {
|
||||
$postPage = $POST['page_' . $v];
|
||||
if ($handler->request()[2] == 'edit') {
|
||||
if (timing_safe_compare($page[$v] ?? '', $postPage ?? '')) {
|
||||
if (hash_equals($page[$v] ?? '', $postPage ?? '')) {
|
||||
continue;
|
||||
} // Skip not updated values
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ use function Chevereto\Legacy\isDebug;
|
||||
use function Chevereto\Legacy\isShowEmbedContent;
|
||||
use function Chevereto\Legacy\send_mail;
|
||||
use function Chevereto\Legacy\time_elapsed_string;
|
||||
use function Chevereto\Vars\env;
|
||||
use function Chevereto\Vars\files;
|
||||
use function Chevereto\Vars\post;
|
||||
use function Chevereto\Vars\request;
|
||||
@@ -1536,6 +1537,24 @@ return function (Handler $handler) {
|
||||
User::update($user_id, ['status' => $doing == 'user_ban' ? 'banned' : 'valid']);
|
||||
$json_array['status_code'] = 200;
|
||||
|
||||
break;
|
||||
case 'set-license-key':
|
||||
if (env()['CHEVERETO_CONTEXT'] === 'saas') {
|
||||
throw new Exception('Not found', 404);
|
||||
}
|
||||
if (!Login::isAdmin()) {
|
||||
throw new Exception(_s('Request denied'), 403);
|
||||
}
|
||||
$licenseKey = $POST['key'] ?? '';
|
||||
$licenseFile = PATH_APP . 'CHEVERETO_LICENSE_KEY';
|
||||
touch($licenseFile);
|
||||
if (file_put_contents($licenseFile, $licenseKey)) {
|
||||
$json_array['status_code'] = 200;
|
||||
$json_array['success'] = ['message' => _s('License key updated'), 'code' => 200];
|
||||
} else {
|
||||
throw new Exception('Error updating license key', 500);
|
||||
}
|
||||
|
||||
break;
|
||||
case 'deny':
|
||||
throw new Exception(_s('Request denied'), 403);
|
||||
|
||||
@@ -31,7 +31,6 @@ use function Chevereto\Legacy\G\is_url_web;
|
||||
use function Chevereto\Legacy\G\nullify_string;
|
||||
use function Chevereto\Legacy\G\redirect;
|
||||
use function Chevereto\Legacy\G\safe_html;
|
||||
use function Chevereto\Legacy\G\timing_safe_compare;
|
||||
use function Chevereto\Legacy\generate_hashed_token;
|
||||
use function Chevereto\Legacy\get_available_languages;
|
||||
use function Chevereto\Legacy\getIpButtonsArray;
|
||||
@@ -251,11 +250,11 @@ return function (Handler $handler) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (timing_safe_compare($row['user_username'], $POST['username']) and $user['username'] !== $row['user_username']) {
|
||||
if (hash_equals($row['user_username'], $POST['username']) and $user['username'] !== $row['user_username']) {
|
||||
$input_errors['username'] = 'Username already being used';
|
||||
}
|
||||
if (
|
||||
!empty($POST['email']) && timing_safe_compare($row['user_email'], $POST['email']) &&
|
||||
!empty($POST['email']) && hash_equals($row['user_email'], $POST['email']) &&
|
||||
$user['email'] !== $row['user_email']
|
||||
) {
|
||||
$input_errors['email'] = _s('Email already being used');
|
||||
@@ -266,7 +265,7 @@ return function (Handler $handler) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$is_error && $is_email_required && !empty($POST['email']) && !timing_safe_compare($user['email'] ?? '', $POST['email'])) {
|
||||
if (!$is_error && $is_email_required && !empty($POST['email']) && !hash_equals($user['email'] ?? '', $POST['email'])) {
|
||||
Confirmation::delete(['type' => 'account-change-email', 'user_id' => $user['id']]);
|
||||
$hashed_token = generate_hashed_token((int) $user['id']);
|
||||
Confirmation::insert([
|
||||
|
||||
@@ -23,7 +23,6 @@ use function Chevereto\Legacy\G\get_public_url;
|
||||
use Chevereto\Legacy\G\Handler;
|
||||
use function Chevereto\Legacy\G\redirect;
|
||||
use function Chevereto\Legacy\G\safe_html;
|
||||
use function Chevereto\Legacy\G\timing_safe_compare;
|
||||
use function Chevereto\Legacy\generate_hashed_token;
|
||||
use function Chevereto\Legacy\get_email_body_str;
|
||||
use function Chevereto\Legacy\getSetting;
|
||||
@@ -136,10 +135,10 @@ return function (Handler $handler) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (timing_safe_compare($row['user_username'], $POST['username'])) {
|
||||
if (hash_equals($row['user_username'], $POST['username'])) {
|
||||
$input_errors['username'] = 'Username already being used';
|
||||
}
|
||||
if (timing_safe_compare($row['user_email'], $POST['email'])) {
|
||||
if (hash_equals($row['user_email'], $POST['email'])) {
|
||||
$input_errors['email'] = _s('Email already being used');
|
||||
}
|
||||
if (!$show_resend_activation) {
|
||||
|
||||
@@ -424,7 +424,7 @@ class Handler
|
||||
return false;
|
||||
}
|
||||
|
||||
return timing_safe_compare(session()['G_auth_token'], $token);
|
||||
return hash_equals(session()['G_auth_token'], $token);
|
||||
}
|
||||
|
||||
public static function setVar(string $var, mixed $value): void
|
||||
|
||||
@@ -1032,6 +1032,7 @@ function loaderHandler(
|
||||
'CHEVERETO_ENABLE_UPLOAD_WATERMARK' => '0',
|
||||
'CHEVERETO_ENABLE_USERS' => '0',
|
||||
'CHEVERETO_MAX_USERS' => '1',
|
||||
'CHEVERETO_EDITION' => 'free',
|
||||
));
|
||||
new EnvVar($envVar);
|
||||
new ServerVar(array_merge($envDefault, $env, $_server));
|
||||
@@ -1314,3 +1315,14 @@ function adjustBrightness(string $hexCode, float $adjustPercent)
|
||||
|
||||
return '#' . implode($hexCode);
|
||||
}
|
||||
|
||||
function getLicenseKey(): string
|
||||
{
|
||||
$licenseKey = env()['CHEVERETO_LICENSE_KEY'] ?? '';
|
||||
$licenseFile = PATH_APP . 'CHEVERETO_LICENSE_KEY';
|
||||
if ($licenseKey === '' && file_exists($licenseFile)) {
|
||||
$licenseKey = file_get_contents($licenseFile);
|
||||
}
|
||||
|
||||
return $licenseKey;
|
||||
}
|
||||
|
||||
451
app/upgrading.php
Normal file
451
app/upgrading.php
Normal file
@@ -0,0 +1,451 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Chevereto.
|
||||
*
|
||||
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Download (auto license):
|
||||
php app/upgrading.php
|
||||
|
||||
Download (with license):
|
||||
CHEVERETO_LICENSE_KEY=your_license_key php app/upgrading.php
|
||||
|
||||
* .upgrading/upgrading.lock
|
||||
This setting affects non CLI (HTTP calls only).
|
||||
It exists when the upgrade has been authorized at dashboard.
|
||||
It contains the token for upgrade process, must be checked against request.
|
||||
|
||||
* .upgrading/downloading.lock
|
||||
It exists when the upgrade is downloading the new version.
|
||||
|
||||
* .upgrading/extracting.lock
|
||||
It exists when the upgrade is extracting the new version.
|
||||
|
||||
*/
|
||||
namespace Chevereto;
|
||||
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
use stdClass;
|
||||
use Throwable;
|
||||
use ZipArchive;
|
||||
|
||||
require_once __DIR__ . '/legacy/load/php-boot.php';
|
||||
|
||||
const ZIP_BALL = 'https://chevereto.com/api/download/%tag%';
|
||||
const LOGGER = __DIR__ . '/.upgrading/process.log';
|
||||
if (!file_exists(LOGGER)) {
|
||||
touch(LOGGER);
|
||||
}
|
||||
ob_start('ob_gzhandler');
|
||||
ob_implicit_flush(true);
|
||||
$rootDir = __DIR__ . '/..';
|
||||
$workingDir = __DIR__ . '/.upgrading';
|
||||
if (is_file($workingDir)) {
|
||||
unlink($workingDir);
|
||||
}
|
||||
$runtimeTable = [
|
||||
'log_errors' => ini_set('log_errors', true),
|
||||
'display_errors' => ini_set('display_errors', true),
|
||||
'error_log' => ini_set('error_log', $workingDir . '/error.log'),
|
||||
'ignore_user_abort' => ignore_user_abort(true),
|
||||
'time_limit' => @set_time_limit(0),
|
||||
'ini_set' => ini_set('default_charset', 'utf-8'),
|
||||
'setlocale' => setlocale(LC_ALL, 'en_US.UTF8'),
|
||||
'output_buffering' => ini_set('output_buffering', 'off'),
|
||||
'zlib.output_compression' => ini_set('zlib.output_compression', false),
|
||||
];
|
||||
$logProcess = $workingDir . '/process.log';
|
||||
$lockUpgrading = $workingDir . '/upgrading.lock';
|
||||
$lockDownloading = $workingDir . '/downloading.lock';
|
||||
$lockExtracting = $workingDir . '/extracting.lock';
|
||||
$upgradingKey = $rootDir . '/app/CHEVERETO_LICENSE_KEY';
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
|
||||
echo <<<HTML
|
||||
<html><head><style>body {padding: 0.5em;}</style><script>
|
||||
function goToUrl(url) {
|
||||
window.location.href = url;
|
||||
}
|
||||
</script></head><body><pre>
|
||||
HTML;
|
||||
}
|
||||
if (!is_dir($workingDir)) {
|
||||
mkdir($workingDir, 0755, true);
|
||||
}
|
||||
if (!is_writable($workingDir)) {
|
||||
abort('[!] Working dir is not writable', 500);
|
||||
}
|
||||
$envFile = __DIR__ . '/env.php';
|
||||
$env = [];
|
||||
if (file_exists($envFile)) {
|
||||
$env = require $envFile;
|
||||
}
|
||||
$env = array_merge($_ENV, $_SERVER, $env);
|
||||
if (!class_exists('ZipArchive')) {
|
||||
abort('[!] ZipArchive is not available');
|
||||
}
|
||||
$licenseKey = $env['CHEVERETO_LICENSE_KEY'] ?? '';
|
||||
if ($licenseKey === '' && file_exists($upgradingKey)) {
|
||||
$licenseKey = file_get_contents($upgradingKey);
|
||||
}
|
||||
$return = $_GET['return'] ?? '';
|
||||
$parseUri = parse_url($_SERVER['REQUEST_URI'] ?? '');
|
||||
$query = $parseUri['query'] ?? '';
|
||||
$pathUrl = $parseUri['path'] ?? '';
|
||||
$rootUrl = rtrim(dirname($pathUrl), '/') . '/';
|
||||
$actions = ['download', 'extract'];
|
||||
$filePath = $workingDir . '/' . 'chevereto.zip';
|
||||
if (PHP_SAPI === 'cli') {
|
||||
echo <<<LOGO
|
||||
__ __
|
||||
____/ / ___ _ _____ _______ / /____
|
||||
/ __/ _ \/ -_) |/ / -_) __/ -_) __/ _ \
|
||||
\__/_//_/\__/|___/\__/_/ \__/\__/\___/
|
||||
|
||||
|
||||
LOGO;
|
||||
$singleStep = true;
|
||||
$clear = getopt('c::') ?? null;
|
||||
if ($clear) {
|
||||
unlinkIfExists($lockUpgrading);
|
||||
unlinkIfExists($lockDownloading);
|
||||
unlinkIfExists($lockExtracting);
|
||||
logger('Locks cleared');
|
||||
die(0);
|
||||
}
|
||||
} else {
|
||||
$singleStep = false;
|
||||
$action = $_GET['action'] ?? '';
|
||||
$token = $_GET['token'] ?? '';
|
||||
if (!file_exists($lockUpgrading)) {
|
||||
abort('[!] Upgrade is not expected', 403);
|
||||
}
|
||||
$upgradeToken = file_get_contents($lockUpgrading);
|
||||
if (!hash_equals($upgradeToken, $token)) {
|
||||
abort('[!] Invalid token', 403);
|
||||
}
|
||||
if (($env['CHEVERETO_CONTEXT'] ?? null) === 'saas') {
|
||||
abort('[!] Upgrade is not needed on SaaS context', 403);
|
||||
}
|
||||
if (!in_array($action, $actions, true)) {
|
||||
abort('[!] Provide action=download or action=extract', 400);
|
||||
}
|
||||
}
|
||||
$upgradeToken ??= time();
|
||||
if ($singleStep || $action === 'download') {
|
||||
if (file_exists($lockDownloading)) {
|
||||
abort('[!] Downloading is already in progress', 400);
|
||||
}
|
||||
logger('Lock downloading process');
|
||||
file_put_contents($lockDownloading, $upgradeToken);
|
||||
$params['tag'] = '4';
|
||||
$params['license'] = $licenseKey;
|
||||
if ($params['license'] === '') {
|
||||
logger('Using free version [no CHEVERETO_LICENSE_KEY provided]');
|
||||
} else {
|
||||
logger('Using licensed version [CHEVERETO_LICENSE_KEY provided]');
|
||||
}
|
||||
logger(sprintf('About to download Chevereto %s', $params['tag']));
|
||||
|
||||
try {
|
||||
$response = downloadAction($workingDir, $params);
|
||||
} catch (Throwable $e) {
|
||||
logger('Unlock downloading process');
|
||||
unlink($lockDownloading);
|
||||
abort($e->getMessage(), 400);
|
||||
}
|
||||
logger($response->message);
|
||||
logger('Unlock downloading process');
|
||||
unlink($lockDownloading);
|
||||
$query = str_replace('action=download', 'action=extract', $query);
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
$continueUri = $pathUrl . '?' . $query;
|
||||
logger('Continue extraction in 3s at... ' . $continueUri);
|
||||
sleep(3);
|
||||
}
|
||||
}
|
||||
if ($singleStep || $action === 'extract') {
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
echo file_get_contents(LOGGER);
|
||||
}
|
||||
if (file_exists($lockExtracting)) {
|
||||
abort('[!] Extracting is already in progress', 400);
|
||||
}
|
||||
if (!file_exists($filePath)) {
|
||||
abort('[!] Package not downloaded', 400);
|
||||
}
|
||||
logger('Lock extracting process');
|
||||
file_put_contents($lockExtracting, $upgradeToken);
|
||||
|
||||
try {
|
||||
$response = extractAction($rootDir, $filePath);
|
||||
} catch (Throwable $e) {
|
||||
logger('Unlock extracting process');
|
||||
unlink($lockExtracting);
|
||||
abort($e->getMessage(), $e->getCode());
|
||||
}
|
||||
logger($response->message);
|
||||
unlink($filePath);
|
||||
logger('Unlock extracting process');
|
||||
unlink($lockExtracting);
|
||||
logger('Chevereto filesystem upgraded');
|
||||
unlinkIfExists($lockUpgrading);
|
||||
$safeResult = false;
|
||||
$command = $rootDir . '/app/bin/legacy -C update';
|
||||
if (passthruEnabled()) {
|
||||
logger('Command passthru');
|
||||
$safeResult = passthru($command);
|
||||
}
|
||||
if ($safeResult === false) {
|
||||
logger('Continue with database update');
|
||||
}
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
$continueUri = $rootUrl . $return;
|
||||
logger('Redirecting in 3s...');
|
||||
sleep(3);
|
||||
}
|
||||
unlink(LOGGER);
|
||||
}
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
echo '</pre></body>';
|
||||
if (isset($continueUri)) {
|
||||
echo <<<HTML
|
||||
<script>goToUrl("{$continueUri}")</script>
|
||||
HTML;
|
||||
}
|
||||
echo '</html>';
|
||||
}
|
||||
|
||||
function logger(string $message): void
|
||||
{
|
||||
$hour = gmdate('H:i:s');
|
||||
$message = $hour . ' * ' . $message . PHP_EOL;
|
||||
fwrite(fopen('php://output', 'r+'), $message);
|
||||
fwrite(fopen(LOGGER, 'a+'), $message);
|
||||
ob_flush();
|
||||
}
|
||||
|
||||
function curl(string $url, array $curlOpts = []): object
|
||||
{
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
|
||||
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||
curl_setopt($ch, CURLOPT_FAILONERROR, 0);
|
||||
curl_setopt($ch, CURLOPT_VERBOSE, 0);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Chevereto Upgrade');
|
||||
$fp = false;
|
||||
foreach ($curlOpts as $k => $v) {
|
||||
if (CURLOPT_FILE == $k) {
|
||||
$fp = $v;
|
||||
}
|
||||
curl_setopt($ch, $k, $v);
|
||||
}
|
||||
$file_get_contents = curl_exec($ch);
|
||||
$transfer = curl_getinfo($ch);
|
||||
if (curl_errno($ch)) {
|
||||
$curl_error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
throw new Exception('Curl error ' . $curl_error, 500);
|
||||
}
|
||||
curl_close($ch);
|
||||
$return = new stdClass();
|
||||
if (is_resource($fp)) {
|
||||
rewind($fp);
|
||||
$return->raw = stream_get_contents($fp);
|
||||
} else {
|
||||
$return->raw = $file_get_contents;
|
||||
}
|
||||
if (false !== strpos($transfer['content_type'], 'application/json')) {
|
||||
$return->json = json_decode($return->raw);
|
||||
if (is_resource($fp)) {
|
||||
$meta_data = stream_get_meta_data($fp);
|
||||
unlink($meta_data['uri']);
|
||||
}
|
||||
}
|
||||
$code = $transfer['http_code'];
|
||||
if (200 != $code && !isset($return->json)) {
|
||||
$return->json = new stdClass();
|
||||
$return->json->error = new stdClass();
|
||||
$return->json->error->message = 'Error performing HTTP request';
|
||||
$return->json->error->code = $code;
|
||||
}
|
||||
$return->transfer = $transfer;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
function getFormatBytes($bytes, int $round = 1): string
|
||||
{
|
||||
if (!is_numeric($bytes)) {
|
||||
return (string) $bytes;
|
||||
}
|
||||
if ($bytes < 1000) {
|
||||
return "$bytes B";
|
||||
}
|
||||
$units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
foreach ($units as $k => $v) {
|
||||
$multiplier = pow(1000, $k + 1);
|
||||
$threshold = $multiplier * 1000;
|
||||
if ($bytes < $threshold) {
|
||||
$size = round($bytes / $multiplier, $round);
|
||||
|
||||
return "$size $v";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getBytesToMb($bytes, int $round = 2): float
|
||||
{
|
||||
$mb = $bytes / pow(10, 6);
|
||||
if ($round) {
|
||||
$mb = round($mb, $round);
|
||||
}
|
||||
|
||||
return $mb;
|
||||
}
|
||||
|
||||
function downloadFile(string $url, array $params, string $filePath, bool $post = true): object
|
||||
{
|
||||
$fp = fopen($filePath, 'wb+');
|
||||
if (!$fp) {
|
||||
throw new Exception("Can't open temp file " . $filePath . ' (wb+)');
|
||||
}
|
||||
$ops = [
|
||||
CURLOPT_FILE => $fp,
|
||||
];
|
||||
if ($params !== []) {
|
||||
$ops[CURLOPT_POSTFIELDS] = http_build_query($params);
|
||||
}
|
||||
if ($post) {
|
||||
$ops[CURLOPT_POST] = true;
|
||||
}
|
||||
$curl = curl($url, $ops);
|
||||
fclose($fp);
|
||||
|
||||
return $curl;
|
||||
}
|
||||
|
||||
function downloadAction(string $workingDir, array $params): Response
|
||||
{
|
||||
$fileBasename = 'chevereto.zip';
|
||||
$filePath = $workingDir . '/' . $fileBasename;
|
||||
unlinkIfExists($filePath);
|
||||
$isPost = false;
|
||||
$zipBall = ZIP_BALL;
|
||||
$tag = $params['tag'] ?? 'latest';
|
||||
$zipBall = str_replace('%tag%', $tag, $zipBall);
|
||||
$isPost = true;
|
||||
$curl = downloadFile($zipBall, $params, $filePath, $isPost);
|
||||
if (isset($curl->json->error)) {
|
||||
throw new RuntimeException($curl->json->error->message, $curl->json->status_code);
|
||||
}
|
||||
if ($curl->transfer['http_code'] !== 200) {
|
||||
$error = '[HTTP ' . $curl->transfer['http_code'] . '] ' . $zipBall;
|
||||
|
||||
throw new RuntimeException($error, $curl->transfer['http_code']);
|
||||
}
|
||||
$fileSize = filesize($filePath);
|
||||
|
||||
return new Response(
|
||||
strtr('Downloaded %f (%w @%s)', [
|
||||
'%f' => $fileBasename,
|
||||
'%w' => getFormatBytes($fileSize),
|
||||
'%s' => getBytesToMb($curl->transfer['speed_download']) . 'MB/s.',
|
||||
]),
|
||||
[
|
||||
'fileBasename' => $fileBasename,
|
||||
'filePath' => $filePath,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function extractAction(string $pathTo, string $filePath): Response
|
||||
{
|
||||
if (!file_exists($pathTo) && !mkdir($pathTo)) {
|
||||
throw new Exception(sprintf("Working path %s doesn't exists and can't be created", $pathTo), 500);
|
||||
}
|
||||
if (!is_readable($pathTo)) {
|
||||
throw new Exception(sprintf('Working path %s is not readable', $pathTo), 500);
|
||||
}
|
||||
if (!is_readable($filePath)) {
|
||||
throw new Exception(sprintf("Can't read %s", basename($filePath)), 500);
|
||||
}
|
||||
$zip = new ZipArchive();
|
||||
$timeStart = microtime(true);
|
||||
$zipOpen = $zip->open($filePath);
|
||||
if ($zipOpen !== true) {
|
||||
throw new Exception(strtr("Can't extract %f - %m (ZipArchive #%z)", [
|
||||
'%f' => $filePath,
|
||||
'%m' => 'ZipArchive ' . $zipOpen . ' error',
|
||||
'%z' => $zipOpen,
|
||||
]), 500);
|
||||
}
|
||||
$numFiles = $zip->numFiles - 1;
|
||||
$extraction = $zip->extractTo($pathTo);
|
||||
if (!$extraction) {
|
||||
throw new Exception("Unable to extract to");
|
||||
}
|
||||
$zip->close();
|
||||
$timeTaken = round(microtime(true) - $timeStart, 2); //
|
||||
clearstatcache(true, $pathTo);
|
||||
|
||||
return new Response(
|
||||
strtr('Extraction completed for %n files in %ss', ['%n' => $numFiles, '%s' => $timeTaken]),
|
||||
[
|
||||
'numFiles' => $numFiles,
|
||||
'timeTaken' => $timeTaken,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
function abort(string $message)
|
||||
{
|
||||
logger($message);
|
||||
die(255);
|
||||
}
|
||||
|
||||
function passthruEnabled(): bool
|
||||
{
|
||||
if (!function_exists('passthru')) {
|
||||
return false;
|
||||
}
|
||||
$disabled = explode(',', ini_get('disable_functions'));
|
||||
|
||||
return !in_array('passthru', $disabled);
|
||||
}
|
||||
|
||||
function unlinkIfExists(string $file): void
|
||||
{
|
||||
if (!file_exists($file)) {
|
||||
return;
|
||||
}
|
||||
unlink($file);
|
||||
}
|
||||
|
||||
class Response
|
||||
{
|
||||
public string $message;
|
||||
|
||||
public array $data;
|
||||
|
||||
public function __construct(string $message, array $data = [])
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->data = $data;
|
||||
}
|
||||
}
|
||||
@@ -2161,20 +2161,27 @@ $(function () {
|
||||
) == -1
|
||||
) {
|
||||
PF.fn.modal.simple({
|
||||
title: '<i class="fas fa-arrow-alt-circle-up"></i> ' + PF.fn._s("Update available v%s", data.current_version),
|
||||
title: '<i class="fas fa-arrow-alt-circle-up"></i> ' + PF.fn._s("Chevereto v%s available", data.current_version),
|
||||
message: "<p>" +
|
||||
PF.fn._s("There is an update available for this system.") +
|
||||
"</p>" +
|
||||
PF.fn._s("There is a new Chevereto version available with the following release notes.") +
|
||||
' ' +
|
||||
PF.fn._s("Check %s for a complete changelog since you last upgrade.", '<a href="https://releases.chevereto.com/4.X/4.0/' + CHV.obj.system_info.version + '" target="_blank">' + CHV.obj.system_info.version + '<span class="btn-icon fas fas fa-code-branch"></span></a>') +
|
||||
'</p>' +
|
||||
'<textarea class="r4 resize-vertical">' +
|
||||
data.release_notes +
|
||||
data.release_notes.trim() +
|
||||
"</textarea>" +
|
||||
'<p>' +
|
||||
PF.fn._s("Check the %s for alternative update methods.", '<a href="https://chv.to/v4update" target="_blank">' + PF.fn._s('documentation') + '</a>') +
|
||||
'</p>' +
|
||||
'<div class="btn-container margin-bottom-0">' +
|
||||
'<a href="https://chv.to/v4update" target="_blank" class="btn btn-input accent">' +
|
||||
'<span class="btn-icon fas fa-external-link-alt user-select-none"></span>' +
|
||||
'<a href="' + PF.obj.config.base_url + 'dashboard/upgrade/?auth_token=' + PF.obj.config.auth_token
|
||||
+ '" class="btn btn-input accent">' +
|
||||
'<span class="btn-icon fas fa-download user-select-none"></span>' +
|
||||
'<span class="btn-text user-select-none">' +
|
||||
PF.fn._s("Update instructions") +
|
||||
PF.fn._s("Upgrade now") +
|
||||
'</span>' +
|
||||
'</a></div>',
|
||||
'</a> ' +
|
||||
'</div>',
|
||||
html: true,
|
||||
});
|
||||
} else {
|
||||
@@ -2189,7 +2196,30 @@ $(function () {
|
||||
});
|
||||
|
||||
if (typeof PF.fn.get_url_var("checkUpdates") !== typeof undefined) {
|
||||
$("[data-action=check-for-updates]").click();
|
||||
$("[data-action=check-for-updates]").trigger("click");
|
||||
}
|
||||
if (typeof PF.fn.get_url_var("upgrade") !== typeof undefined) {
|
||||
$("[data-action=upgrade]").trigger("click");
|
||||
}
|
||||
if (typeof PF.fn.get_url_var("license") !== typeof undefined) {
|
||||
$("[data-action='license']").trigger("click");
|
||||
}
|
||||
if (typeof PF.fn.get_url_var("installed") !== typeof undefined) {
|
||||
PF.fn.modal.simple({
|
||||
title: '<i class="fas fa-code-branch"></i> ' + PF.fn._s("Chevereto v%s installed", CHV.obj.system_info.version),
|
||||
message: "<p>" +
|
||||
PF.fn._s('Usage of Chevereto Software must be in compliance with the software license terms known as "The Chevereto License".') +
|
||||
'</p>' +
|
||||
'<div class="btn-container margin-bottom-0">' +
|
||||
'<a href="https://chevereto.com/license" target="_blank" class="btn btn-input accent">' +
|
||||
'<span class="btn-icon fas fa-file-contract user-select-none"></span>' +
|
||||
'<span class="btn-text user-select-none">' +
|
||||
PF.fn._s("License agreement") +
|
||||
'</span>' +
|
||||
'</a> ' +
|
||||
'</div>',
|
||||
html: true,
|
||||
});
|
||||
}
|
||||
$(document).on("click", "[data-action=system-update]", function (e) {
|
||||
if (!$("input#system-update").prop("checked")) {
|
||||
@@ -2832,7 +2862,31 @@ $(function () {
|
||||
$icon.addClass(iconClass);
|
||||
});
|
||||
|
||||
|
||||
$(document).on("click", "[href^='https://chevereto.com/']", function(e) {
|
||||
let hasBadge = $(this).find(".badge--paid").exists();
|
||||
if(!hasBadge) {
|
||||
return;
|
||||
}
|
||||
let href = $(this).attr("href");
|
||||
let buyFrom = PF.fn._s('Get a license from %s to unlock all features and support.', '<a href="'+href+'" target="_blank">chevereto.com</a>');
|
||||
let instructions = PF.fn._s('You can enter your license key in the dashboard panel.');
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
PF.fn.modal.simple({
|
||||
html: true,
|
||||
title: '<i class="fa-solid fa-boxes-packing"></i> Upgrade Chevereto',
|
||||
message: "<p>" + buyFrom +
|
||||
" " + instructions + "</p>" +
|
||||
'<div class="btn-container margin-bottom-0">' +
|
||||
'<a href="' + PF.obj.config.base_url + 'dashboard/?license" class="btn btn-input accent">' +
|
||||
'<span class="btn-icon fas fa-key user-select-none"></span>' +
|
||||
'<span class="btn-text user-select-none">' +
|
||||
PF.fn._s("Enter license") +
|
||||
'</span>' +
|
||||
'</a> ' +
|
||||
'</div>',
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
if (typeof CHV == "undefined") {
|
||||
@@ -3198,7 +3252,6 @@ CHV.fn.listingViewer = {
|
||||
var object = this.getObject(true);
|
||||
var template = this.getEl("template").html();
|
||||
var matches = template.match(/%(\S+)%/g);
|
||||
console.log(object)
|
||||
if (matches) {
|
||||
$.each(matches, function (i, v) {
|
||||
var handle = v.slice(1, -1).split(".");
|
||||
@@ -4715,7 +4768,6 @@ CHV.fn.resource_privacy_toggle = function (privacy) {
|
||||
}
|
||||
};
|
||||
|
||||
// Album stuff
|
||||
CHV.fn.submit_create_album = function () {
|
||||
var $modal = $(PF.obj.modal.selectors.root);
|
||||
if ($("[name=form-album-name]", $modal).val() == "") {
|
||||
@@ -6424,3 +6476,43 @@ CHV.fn.Palettes = {
|
||||
}, 400);
|
||||
}
|
||||
}
|
||||
|
||||
CHV.fn.license = {
|
||||
set: {
|
||||
submit: function () {
|
||||
var $modal = $(PF.obj.modal.selectors.root),
|
||||
submit = true;
|
||||
$.each($(":input", $modal), function (i, v) {
|
||||
if ($(this).val() == "" && $(this).attr("required")) {
|
||||
$(this).highlight();
|
||||
submit = false;
|
||||
}
|
||||
});
|
||||
if (!submit) {
|
||||
PF.fn.growl.call(PF.fn._s("Please fill all the required fields."));
|
||||
return false;
|
||||
}
|
||||
PF.obj.modal.form_data = {
|
||||
action: "set-license-key",
|
||||
key: $("[name=chevereto-license-key]", $modal).val(),
|
||||
};
|
||||
return true;
|
||||
},
|
||||
complete: {
|
||||
success: function (XHR) {
|
||||
let response = XHR.responseJSON;
|
||||
let $trigger = $("[data-action=upgrade]");
|
||||
if(CHV.obj.system_info.edition === 'free') {
|
||||
$trigger.removeClass("hidden");
|
||||
$trigger.trigger("click");
|
||||
return;
|
||||
}
|
||||
PF.fn.growl.call(PF.fn._s(response.success.message));
|
||||
},
|
||||
error: function (XHR) {
|
||||
var response = XHR.responseJSON;
|
||||
PF.fn.growl.call(PF.fn._s(response.error.message));
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -454,7 +454,6 @@ $(function () {
|
||||
deferred: window[$target.data("ajax-deferred")]
|
||||
};
|
||||
|
||||
// Window functions failed? Maybe those are named fn...
|
||||
if (typeof submit_function !== "function" && $target.data("submit-fn")) {
|
||||
var submit_fn_split = $target.data("submit-fn").split(".");
|
||||
submit_function = window;
|
||||
|
||||
@@ -15,6 +15,7 @@ use function Chevereto\Legacy\get_captcha_invisible_html;
|
||||
use function Chevereto\Legacy\get_translation_table;
|
||||
use function Chevereto\Legacy\getSetting;
|
||||
use function Chevereto\Legacy\getSettings;
|
||||
use function Chevereto\Vars\env;
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
if (!defined('ACCESS') || !ACCESS) {
|
||||
@@ -116,7 +117,10 @@ if (Handler::cond('captcha_needed') && getSetting('captcha_api') == '3') {
|
||||
CHV.obj.logged_user = <?php echo json_encode($logged_user_array); ?>;
|
||||
<?php
|
||||
if (Login::isAdmin()) { ?>
|
||||
CHV.obj.system_info = <?php echo json_encode(['version' => get_app_version()]); ?>;
|
||||
CHV.obj.system_info = <?php echo json_encode([
|
||||
'version' => get_app_version(),
|
||||
'edition' => env()['CHEVERETO_EDITION'],
|
||||
]); ?>;
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2573,3 +2573,7 @@ body.full--wh {
|
||||
.btn-cta:hover .btn-icon {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.version-display {
|
||||
font-size: 1.4em;
|
||||
}
|
||||
|
||||
2
content/legacy/themes/Peafowl/style.min.css
vendored
2
content/legacy/themes/Peafowl/style.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -2,6 +2,7 @@
|
||||
|
||||
use Chevereto\Legacy\Classes\Stat;
|
||||
use function Chevereto\Legacy\G\bytes_to_mb;
|
||||
use function Chevereto\Legacy\G\get_base_url;
|
||||
use function Chevereto\Legacy\G\get_client_ip;
|
||||
use Chevereto\Legacy\G\Handler;
|
||||
use function Chevereto\Legacy\get_static_url;
|
||||
@@ -12,6 +13,24 @@ if (!defined('ACCESS') || !ACCESS) {
|
||||
die('This file cannot be directly accessed.');
|
||||
}
|
||||
?>
|
||||
<div data-modal="modal-license-key" class="hidden" data-submit-fn="CHV.fn.license.set.submit" data-ajax-deferred="CHV.fn.license.set.complete" data-ajax-url="<?php echo get_base_url('json'); ?>">
|
||||
<span class="modal-box-title"><i class="fas fa-key"></i> <?php _se('License key'); ?></span>
|
||||
<p><?php _se(
|
||||
"Provide Chevereto license key by assigning the environment variable %env% or by creating the %file% containing the license key.",
|
||||
[
|
||||
'%env%' => '<code class="code font-weight-bold">CHEVERETO_LICENSE_KEY</code>',
|
||||
'%file%' => '<code class="code font-weight-bold">' . PATH_APP . 'CHEVERETO_LICENSE_KEY</code>',
|
||||
]
|
||||
); ?></p>
|
||||
<p><?php _se('You can also set the license in the textarea below.'); ?></p>
|
||||
<div class="modal-form margin-top-20">
|
||||
<div class="input-label overflow-auto">
|
||||
<label for="chevereto-license-key"><?php _se('Chevereto license key'); ?></label>
|
||||
<textarea placeholder="<?php _se('PASTE LICENSE KEY HERE'); ?>" id="chevereto-license-key" class="r3 resize-vertical" name="chevereto-license-key" data-focus="select-all"><?php echo Handler::var('licenseKey'); ?></textarea>
|
||||
<div class="input-below font-size-small"><?php _se('Get a license from %s to unlock all features and support.', '<a href="https://chevereto.com/pricing" target="_blank">chevereto.com</a>'); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div data-modal="modal-connecting-ip" class="hidden">
|
||||
<span class="modal-box-title"><i class="fas fa-question-circle"></i> <?php _se('Not your IP?'); ?></span>
|
||||
<div class="connecting-ip"><?php echo get_client_ip(); ?></div>
|
||||
|
||||
Reference in New Issue
Block a user