Skip to content

Commit

Permalink
Merge pull request #3241 from NamelessMC/release/2.0.3
Browse files Browse the repository at this point in the history
Release/2.0.3
  • Loading branch information
samerton authored Jan 28, 2023
2 parents 26bbbae + 5718df0 commit 5a79b61
Show file tree
Hide file tree
Showing 104 changed files with 1,964 additions and 1,089 deletions.
3 changes: 3 additions & 0 deletions .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ body:
description: From StaffCP -> Overview
options:
- Development version
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- < 2.0.0
validations:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
strategy:
matrix:
operating-system: ["ubuntu-latest"]
php-versions: ["7.4", "8.0", "8.1"]
php-versions: ["7.4", "8.0", "8.1", "8.2"]
steps:
- uses: actions/checkout@v2

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@
/uploads/avatars/**
/node_modules/
composer.lock
/.node_cache/
/release/
48 changes: 48 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,54 @@
## [Unreleased](https://github.com/NamelessMC/Nameless/compare/v2.0.0...v2)
> [Milestone](https://github.com/NamelessMC/Nameless/milestone/18)
## [2.0.3](https://github.com/NamelessMC/Nameless/compare/v2.0.2...v2.0.3) - 2023-01-28
### Added
- Allow cancelling OAuth register flow [#3089](https://github.com/NamelessMC/Nameless/pull/3089)
- Add ability to change password of users via StaffCP [#3097](https://github.com/NamelessMC/Nameless/pull/3097)
- Apply rate limiting to forgot password [#3130](https://github.com/NamelessMC/Nameless/pull/3130)
- Add rate limiting to user profile posts [#3145](https://github.com/NamelessMC/Nameless/pull/3145)
- Add instructions on how to disable portal page to template [#3161](https://github.com/NamelessMC/Nameless/pull/3161)
- Add warning for using 3rd party panel templates [#3189](https://github.com/NamelessMC/Nameless/pull/3189)
- Add back discord invite instructions [#3195](https://github.com/NamelessMC/Nameless/pull/3195)
- Allow selecting timezone during install [#3199](https://github.com/NamelessMC/Nameless/pull/3199)

### Changed
- Simplify missing vendor instructions [#3079](https://github.com/NamelessMC/Nameless/pull/3079)
- Automatically detect installation path during installation [#3081](https://github.com/NamelessMC/Nameless/pull/3081)
- Various performance improvements [#3119](https://github.com/NamelessMC/Nameless/pull/3119)
- Remove user field from re-auth page [#3071](https://github.com/NamelessMC/Nameless/pull/3071)
- Delete reported user on deletion [#3065](https://github.com/NamelessMC/Nameless/pull/3065)
- Update forum + topic latest post when a user is marked as spam [#3124](https://github.com/NamelessMC/Nameless/pull/3124)
- Delete replies to a spammer's topic [#3135](https://github.com/NamelessMC/Nameless/pull/3135)
- Allow all tinymce valid_children when admin [#3144](https://github.com/NamelessMC/Nameless/pull/3144)
- Move from yarn to npm [#3173](https://github.com/NamelessMC/Nameless/pull/3173)
- Simplify forum post quoting system [#3184](https://github.com/NamelessMC/Nameless/pull/3184)
- Ignore future dates in dashboard overview graph data [#3197](https://github.com/NamelessMC/Nameless/pull/3197)
- Add X-API-Key fallback header if Authorization is missing [#3217](https://github.com/NamelessMC/Nameless/pull/3217)
- Use X-Forwarded-Proto to determine port [#3229](https://github.com/NamelessMC/Nameless/pull/3229)
- Properly encode content for javascript [#3227](https://github.com/NamelessMC/Nameless/pull/3227)
- Allow browser scripts to bypass force_2fa redirects [#3076](https://github.com/NamelessMC/Nameless/pull/3076)

### Fixed
- Keep inaccessible labels in a topic when editing them as an unauthorised user [#3033](https://github.com/NamelessMC/Nameless/pull/3033)
- Fix OAuth url [#3031](https://github.com/NamelessMC/Nameless/pull/3031)
- Show correct server id when it is updated [#3075](https://github.com/NamelessMC/Nameless/pull/3075)
- Fix widget error when user is deleted [#3078](https://github.com/NamelessMC/Nameless/pull/3078)
- Fix tinymce image upload errors [#3095](https://github.com/NamelessMC/Nameless/pull/3095)
- Return redirect when punishing users [#3101](https://github.com/NamelessMC/Nameless/pull/3101)
- Fix oauth bypasses validation & banned checks [#3103](https://github.com/NamelessMC/Nameless/pull/3103)
- Fix update available alerts on frontend
- Fix TinyMCE spoiler plugin url [#3088](https://github.com/NamelessMC/Nameless/pull/3088)
- Fix fallback to default template not working [#3153](https://github.com/NamelessMC/Nameless/pull/3153)
- Fix sorting with thousands separators in value [#3162](https://github.com/NamelessMC/Nameless/pull/3162)
- Fix checkbox aligning vertically [#3170](https://github.com/NamelessMC/Nameless/pull/3170)
- Fix captcha validation [#3175](https://github.com/NamelessMC/Nameless/pull/3175)
- Misc fixes [#3128](https://github.com/NamelessMC/Nameless/pull/3128)
- Remove binding column name [#3187](https://github.com/NamelessMC/Nameless/pull/3187)
- Fix post editing [#3176](https://github.com/NamelessMC/Nameless/pull/3176)
- Fix LatestPostsWidget bugs [#3204](https://github.com/NamelessMC/Nameless/pull/3204)
- Fix Util::setSetting cache not being updated [#3221](https://github.com/NamelessMC/Nameless/pull/3221)

## [2.0.2](https://github.com/NamelessMC/Nameless/compare/v2.0.1...v2.0.2) - 2022-08-13

### Added
Expand Down
19 changes: 18 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Here are some things you should know when contributing:
composer install --dev
```
- This could take up to about a minute depending on your internet connection.
- We use Yarn to manage frontend dependencies.
- Depending on the way you installed Yarn, you will need to run either `yarnpkg` or `yarn install` to download the required dependencies.
- You can use the CLI (command line) install script to reset your development environment in less than 5 seconds!
- Run the following command when in the root directory:
```console
Expand All @@ -35,7 +37,7 @@ Here are some things you should know when contributing:
```console
vendor/bin/phinx migrate -c core/migrations/phinx.php
```

## Versioning
As of NamelessMC 2.0.0 (to be released at time of writing), we use a unique versioning system.
Similar to [semver](https://semver.org), we follow the `major.minor.patch` versioning pattern, however there are a few things to note:
Expand All @@ -62,3 +64,18 @@ Deprecations rule of thumb:
- We might deprecate methods, classes or constants within a minor release.
- These will get tagged with `@deprecated` and will be announced.
- When something is marked as deprecated, it will not be removed until at least the next major release.

## Backporting

* Security fixes and bug fixes should always be backported, if possible.
* Enhancements should usually be backported. New features should rarely be backported. Changes involving language files should be avoided, Weblate only updates the development branch.
* Changes should be as small as possible to reduce conflicts.
* Squash when merging. This makes backporting easier. If you think your changes deserve multiple commits, consider splitting them into multiple pull requests.
* Mark the pull request with the appropriate milestone. [@Derkades](https://github.com/Derkades) keeps an eye on merged PRs and cherry-pick changes to the appropriate release branch.

## Releasing a new version

1. Ensure you have a clean copy of the source code without leftover files from testing. For example, clone the Nameless repository into a new directory
2. Run ./release.sh. Release zip files are produced and placed in `./release`.
3. TODO: Add instructions for producing a zip only containing files changed since the last release
4. TODO: Add instructions for publishing a release
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright © 2014-2022 NamelessMC Contributors
Copyright © 2014-2023 NamelessMC Contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion core/classes/Core/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static function all(): array {
}

if (!self::exists()) {
throw new RuntimeException('Config file does not exist');
throw new RuntimeException('Config file does not exist. If this happened during installation, please restart the installation in a new private/incognito browser window.');
}

return self::$_config_cache = require(ROOT_PATH . '/core/config.php');
Expand Down
12 changes: 8 additions & 4 deletions core/classes/Core/Email.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,23 @@ private static function sendMailer(array $email) {
$mail->IsSMTP();
$mail->SMTPDebug = SMTP::DEBUG_OFF;
$mail->Debugoutput = 'html';
$mail->CharSet = 'UTF-8';
$mail->Encoding = 'base64';
$mail->CharSet = PHPMailer::CHARSET_UTF8;
$mail->Encoding = PHPMailer::ENCODING_BASE64;
$mail->Timeout = 15;

// login to their smtp account
$mail->Host = Config::get('email.host', '');
// set to override the resolution of the server hostname
$mail->Hostname = Config::get('email.hostname', '');
// required to be set if they have a separate web server and mail server using the same hostname
$mail->Helo = Config::get('email.helo', '');
$mail->Port = Config::get('email.port', 587);
$mail->SMTPSecure = Config::get('email.secure', 'tls');
$mail->SMTPSecure = Config::get('email.secure', PHPMailer::ENCRYPTION_STARTTLS);
$mail->SMTPAuth = Config::get('email.smtp_auth', true);
$mail->Username = Config::get('email.username', '');
$mail->Password = Config::get('email.password', '');

// set from email ("outgoing email" seting)
// set from email ("outgoing email" setting)
$mail->setFrom(Config::get('email.email', ''), Config::get('email.name', ''));

// add a "to" address
Expand Down
4 changes: 3 additions & 1 deletion core/classes/Core/Input.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public static function createTinyEditor(Language $language, string $name, ?strin

$js .= "
tinymce.init({
verify_html: " . ($admin ? 'false' : 'true') . ",
selector: '#$name',
browser_spellcheck: true,
contextmenu: false,
Expand All @@ -127,7 +128,7 @@ public static function createTinyEditor(Language $language, string $name, ?strin
'hr', 'image', 'link', 'lists', 'spoiler', 'code', 'table',
],
external_plugins: {
'spoiler': '" . URL::build('/core/assets/plugins/tinymce_spoiler/plugin.min.js') . "',
'spoiler': '" . (defined('CONFIG_PATH') ? CONFIG_PATH : '') . "/core/assets/plugins/tinymce_spoiler/plugin.min.js',
},
toolbar: 'undo redo | bold italic underline strikethrough formatselect fontsizeselect forecolor backcolor ltr rtl emoticons | alignleft aligncenter alignright alignjustify | codesample " . ($admin ? "code" : "") . " hr image link numlist bullist | spoiler-add spoiler-remove',
spoiler_caption: '{$language->get('general', 'spoiler')}',
Expand Down Expand Up @@ -181,6 +182,7 @@ public static function createTinyEditor(Language $language, string $name, ?strin
xhr.send(formData);
},
" . ($admin ? 'valid_children: "+body[style],+body[link],+*[*]",' : '') . "
extended_valid_elements: " . ($admin ?
'"script[src|async|defer|type|charset],+@[data-options]"'
: 'undefined') . "
Expand Down
27 changes: 13 additions & 14 deletions core/classes/Core/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -283,14 +283,13 @@ public static function replaceAnchorsWithText(string $data): string {
return URL::replaceAnchorsWithText($data);
}

private static function getSettingsCache(?string $module): ?array {
private static function hasSettingsCache(?string $module): bool {
$cache_name = $module !== null ? $module : 'core';
return self::$_cached_settings !== null && isset(self::$_cached_settings[$cache_name]);
}

if (self::$_cached_settings === null ||
!isset(self::$_cached_settings[$cache_name])) {
return null;
}

private static function &getSettingsCache(?string $module): array {
$cache_name = $module !== null ? $module : 'core';
return self::$_cached_settings[$cache_name];
}

Expand All @@ -309,9 +308,7 @@ private static function setSettingsCache(?string $module, array $cache): void {
* @return ?string Setting from DB or $fallback.
*/
public static function getSetting(string $setting, ?string $fallback = null, string $module = 'core'): ?string {
$cache = self::getSettingsCache($module);

if ($cache === null) {
if (!self::hasSettingsCache($module)) {
// Load all settings for this module and store it as a dictionary
if ($module === 'core') {
$result = DB::getInstance()->query('SELECT `name`, `value` FROM `nl2_settings` WHERE `module` IS NULL')->results();
Expand All @@ -326,6 +323,7 @@ public static function getSetting(string $setting, ?string $fallback = null, str
self::setSettingsCache($module, $cache);
}

$cache = &self::getSettingsCache($module);
return $cache[$setting] ?? $fallback;
}

Expand Down Expand Up @@ -367,15 +365,16 @@ public static function setSetting(string $setting, ?string $new_value, string $m
}
}

$cache = self::getSettingsCache($module);
if ($cache === null) {
if (!self::hasSettingsCache($module)) {
return;
}

if ($new_value === null && isset($cache[$setting])) {
unset($cache[$setting]);
} else if ($new_value !== null) {
$cache = &self::getSettingsCache($module);

if ($new_value !== null) {
$cache[$setting] = $new_value;
} else if (isset($cache[$setting])) {
unset($cache[$setting]);
}
}

Expand Down
15 changes: 9 additions & 6 deletions core/classes/Core/Validate.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,15 @@ public static function check(array $source, array $items = []): Validate {
if (is_array($rule_value)) {
$table = $rule_value[0];
[$ignore_col, $ignore_val] = explode(':', $rule_value[1]);
$check = $validator->_db->query('SELECT * FROM nl2_' . $table . ' WHERE ? = ? AND ? <> ?', [
$item,
$value,
$ignore_col,
$ignore_val,
]);
$sql =
<<<SQL
SELECT *
FROM nl2_$table
WHERE $item = ?
AND $ignore_col <> ?
SQL;

$check = $validator->_db->query($sql, [$value, $ignore_val]);
} else {
$table = $rule_value;
$check = $validator->_db->get($table, [$item, $value]);
Expand Down
4 changes: 3 additions & 1 deletion core/classes/Database/DB.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,16 @@ public function query(string $sql, array $params = [], bool $isSelect = null) {

if ($this->_statement->execute()) {
// Only fetch the results if this is a SELECT query.
if ($isSelect || str_starts_with(strtoupper($sql), 'SELECT')) {
if ($isSelect || str_starts_with(strtoupper(ltrim($sql)), 'SELECT')) {
$this->_results = $this->_statement->fetchAll(PDO::FETCH_OBJ);
}
$this->_count = $this->_statement->rowCount();
} else {
print_r($this->_pdo->errorInfo());
$this->_error = true;
}
} else {
$this->_results = [];
}

return $this;
Expand Down
4 changes: 2 additions & 2 deletions core/classes/Database/DatabaseInitialiser.php
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private function initialiseSettings(): void {
Util::setSetting('recaptcha_type', 'Recaptcha3');
Util::setSetting('recaptcha_login', '0');
Util::setSetting('email_verification', '1');
Util::setSetting('nameless_version', '2.0.2');
Util::setSetting('nameless_version', '2.0.3');
Util::setSetting('version_checked', date('U'));
Util::setSetting('phpmailer', '0');
Util::setSetting('phpmailer_type', 'smtp');
Expand All @@ -192,7 +192,7 @@ private function initialiseSettings(): void {
Util::setSetting('external_query', '0');
Util::setSetting('followers', '0');
Util::setSetting('language', '1');
Util::setSetting('timezone', 'Europe/London');
Util::setSetting('timezone', $_SESSION['install_timezone']);
Util::setSetting('maintenance', '0');
Util::setSetting('maintenance_message', 'This website is currently in maintenance mode.');
Util::setSetting('authme', 0);
Expand Down
28 changes: 17 additions & 11 deletions core/classes/Endpoints/KeyAuthEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,25 @@ class KeyAuthEndpoint extends EndpointBase {
final public function isAuthorised(Nameless2API $api): bool {
$auth_header = HttpUtils::getHeader('Authorization');

if ($auth_header === null) {
$api->throwError(Nameless2API::ERROR_MISSING_API_KEY, 'Missing authorization header');
if ($auth_header !== null) {
$exploded = explode(' ', trim($auth_header));

if (count($exploded) !== 2 ||
strcasecmp($exploded[0], 'Bearer') !== 0) {
$api->throwError(Nameless2API::ERROR_MISSING_API_KEY, 'Authorization header not in expected format');
}

$api_key = $exploded[1];
} else {
// Some hosting providers remove the Authorization header, fall back to non-standard X-API-Key heeader
$api_key_header = HttpUtils::getHeader('X-API-Key');
if ($api_key_header === null) {
$api->throwError(Nameless2API::ERROR_MISSING_API_KEY, 'Missing authorization header');
}

$api_key = $api_key_header;
}

$exploded = explode(' ', trim($auth_header));

if (count($exploded) !== 2 ||
strcasecmp($exploded[0], 'Bearer') !== 0) {
$api->throwError(Nameless2API::ERROR_MISSING_API_KEY, 'Authorization header not in expected format');
}

$api_key = $exploded[1];

return $this->validateKey($api, $api_key);
}

Expand Down
4 changes: 2 additions & 2 deletions core/classes/Group_Sync/GroupSyncManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class GroupSyncManager extends Instanceable {
*/
public function registerInjector(GroupSyncInjector $injector): void {
if (in_array($injector->getColumnName(), $this->getColumnNames())) {
throw new RuntimeException("GroupSyncInjector column name {$injector->getColumnName()} already taken, {$class} tried to use it as well.");
throw new RuntimeException("GroupSyncInjector column name {$injector->getColumnName()} already taken.");
}

$this->_injectors[$injector->getColumnName()] = $injector;
Expand Down Expand Up @@ -168,7 +168,7 @@ public function broadcastChange(User $user, string $sending_injector_class, arra
if (count($group_ids) === 0) {
return [];
}

break;
}
}
Expand Down
13 changes: 12 additions & 1 deletion core/classes/Misc/HttpUtils.php
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public static function getProtocol(): string {
$x_forwarded_proto = self::getHeader('X-Forwarded-Proto');
if ($x_forwarded_proto !== null) {
if ($x_forwarded_proto !== 'http' && $x_forwarded_proto !== 'https') {
die('Invalid X-Forwarded-Proto header, should be "http" or "https" but it is "' . Output::getClean($proto) . '".');
die('Invalid X-Forwarded-Proto header, should be "http" or "https" but it is "' . Output::getClean($x_forwarded_proto) . '".');
}
return $x_forwarded_proto;
}
Expand All @@ -118,6 +118,17 @@ public static function getPort(): ?int {
return (int) $x_forwarded_port;
}

// Some hosts don't set X-Forwarded-Port, but do set X-Forwarded-Proto.
// Assume the default port for https or http is used, in that case.
$x_forwarded_proto = self::getHeader('X-Forwarded-Proto');
if ($x_forwarded_proto !== null) {
if ($x_forwarded_proto === 'https') {
return 443;
} else if ($x_forwarded_proto === 'http') {
return 80;
}
}

if (isset($_SERVER['SERVER_PORT'])) {
return (int) $_SERVER['SERVER_PORT'];
}
Expand Down
Loading

0 comments on commit 5a79b61

Please sign in to comment.