Skip to content

Commit

Permalink
chore: merge from develop
Browse files Browse the repository at this point in the history
  • Loading branch information
samerton committed Jan 12, 2025
2 parents 38ff084 + 1e4031d commit d6568bf
Show file tree
Hide file tree
Showing 24 changed files with 240 additions and 56 deletions.
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/bug-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ body:
description: From StaffCP -> Overview
options:
- Development version
- 2.1.0
- < 2.1.0
- 2.1.3
- <= 2.1.2
validations:
required: true

Expand Down
10 changes: 5 additions & 5 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ The following NamelessMC releases are supported by the development team

| Version | Supported |
|-----------|--------------------|
| 2.1.x | :white_check_mark: |
| <= 2.0.3 | :x: |
| 2.1.3 | :white_check_mark: |
| <= 2.1.2 | :x: |
| <= 1.0.22 | :x: |

## Reporting a Vulnerability

Currently, the best place to report a vulnerability is either via email or Discord.
Currently, the best place to report a vulnerability is on GitHub.

- huntr.dev - https://huntr.dev/repos/namelessmc/nameless
- Discord server: https://discord.gg/nameless -> Samerton#9433
- GitHub - https://github.com/NamelessMC/Nameless/security/advisories/new
- Discord server: https://discord.gg/nameless -> Samerton
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
# NamelessMC v2 Changelog

## [Unreleased](https://github.com/NamelessMC/Nameless/compare/v2.1.2...develop)
## [Unreleased](https://github.com/NamelessMC/Nameless/compare/v2.1.3...develop)
> [Milestone](https://github.com/NamelessMC/Nameless/milestone/22)
## [2.1.3](https://github.com/NamelessMC/Nameless/compare/v2.1.2...v2.1.3) - 2025-01-08
### Added
- No additions this release

### Changed
- No changes this release

### Fixed
- Purify custom fields before display
- Fix empty reset code being usable

## [2.1.2](https://github.com/NamelessMC/Nameless/compare/v2.1.1...v2.1.2) - 2023-09-30
### Added
- No additions this release
Expand Down
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-2023 NamelessMC Contributors
Copyright © 2014-2025 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
93 changes: 93 additions & 0 deletions core/classes/Core/HttpClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,99 @@ public static function post(string $url, $data, array $options = []): HttpClient
);
}

/**
* Make a PUT request to a URL.
* Failures will automatically be logged along with the error.
*
* @param string $url URL to send request to.
* @param string|array $data JSON request body to attach to request, or array of key value pairs if form-urlencoded.
* @param array $options Options to set with the GuzzleClient.
* @return HttpClient New HttpClient instance.
*/
public static function put(string $url, $data, array $options = []): HttpClient
{
$guzzleClient = self::createClient($options);

$error = '';

try {
$response = $guzzleClient->put($url, [
// if the data is an array, we assume they want to send it as form-urlencoded, otherwise it's json
is_array($data) ? 'form_params' : 'body' => $data,
]);
} catch (GuzzleException $exception) {
$error = $exception->getMessage();
Log::getInstance()->log(Log::Action('misc/curl_error'), $exception->getMessage());
}

return new HttpClient(
$response ?? null,
$error
);
}

/**
* Make a PATCH request to a URL.
* Failures will automatically be logged along with the error.
*
* @param string $url URL to send request to.
* @param string|array $data JSON request body to attach to request, or array of key value pairs if form-urlencoded.
* @param array $options Options to set with the GuzzleClient.
* @return HttpClient New HttpClient instance.
*/
public static function patch(string $url, $data, array $options = []): HttpClient
{
$guzzleClient = self::createClient($options);

$error = '';

try {
$response = $guzzleClient->patch($url, [
// if the data is an array, we assume they want to send it as form-urlencoded, otherwise it's json
is_array($data) ? 'form_params' : 'body' => $data,
]);
} catch (GuzzleException $exception) {
$error = $exception->getMessage();
Log::getInstance()->log(Log::Action('misc/curl_error'), $exception->getMessage());
}

return new HttpClient(
$response ?? null,
$error
);
}

/**
* Make a DELETE request to a URL.
* Failures will automatically be logged along with the error.
*
* @param string $url URL to send request to.
* @param string|array $data JSON request body to attach to request, or array of key value pairs if form-urlencoded.
* @param array $options Options to set with the GuzzleClient.
* @return HttpClient New HttpClient instance.
*/
public static function delete(string $url, $data, array $options = []): HttpClient
{
$guzzleClient = self::createClient($options);

$error = '';

try {
$response = $guzzleClient->delete($url, [
// if the data is an array, we assume they want to send it as form-urlencoded, otherwise it's json
is_array($data) ? 'form_params' : 'body' => $data,
]);
} catch (GuzzleException $exception) {
$error = $exception->getMessage();
Log::getInstance()->log(Log::Action('misc/curl_error'), $exception->getMessage());
}

return new HttpClient(
$response ?? null,
$error
);
}

/**
* Make a new Guzzle Client instance and attach it to the debug bar to display requests.
*
Expand Down
2 changes: 1 addition & 1 deletion core/classes/Core/Validate.php
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ public static function check(array $source, array $items = []): Validate
break;

case self::IS_ACTIVE:
$check = $validator->_db->get('users', [$item, $value]);
$check = $validator->_db->query('SELECT * FROM nl2_users WHERE username = ? OR email = ?', [$value, $value]);
if (!$check->count()) {
break;
}
Expand Down
8 changes: 7 additions & 1 deletion core/classes/DTO/UserProfileField.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* @package NamelessMC\DTO
* @author Aberdeener
* @version 2.0.0-pr13
* @version 2.2.0
* @license MIT
*/
class UserProfileField extends ProfileField
Expand All @@ -21,6 +21,12 @@ public function __construct(object $row)
$this->upf_id = $row->upf_id;
}

public function purifyValue(): ?string
{
// TODO: option for field to support HTML
return Output::getClean($this->value);
}

public function updated()
{
return date(DATE_FORMAT, $this->updated);
Expand Down
1 change: 1 addition & 0 deletions core/classes/Database/DatabaseInitialiser.php
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ private function initialiseTasks(): void
{
GenerateSitemap::schedule(new Language('core', 'en_UK'));
PurgeExpiredSessions::schedule(new Language('core', 'en_UK'));
PurgeInactiveUsers::schedule(new Language('core', 'en_UK'));
}

private function initialiseTemplates(): void
Expand Down
6 changes: 3 additions & 3 deletions core/classes/Misc/MentionsParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class MentionsParser
*/
public static function parse(int $author_id, string $value, string $link = null, array $alert_short = null, array $alert_full = null): string
{
if (preg_match_all('/@([A-Za-z0-9\-_!.]+)/', $value, $matches)) {
if (preg_match_all('/(?<!\/)@([A-Za-z0-9\-_!.]+)/', $value, $matches)) {
$matches = $matches[1];

foreach ($matches as $possible_username) {
Expand All @@ -33,10 +33,10 @@ public static function parse(int $author_id, string $value, string $link = null,
$user = new User($possible_username, 'nickname');

if ($user->exists()) {
$value = preg_replace('/' . preg_quote("@$possible_username", '/') . '/', '[user]' . $user->data()->id . '[/user]', $value);
$value = preg_replace('/(?<!\/)' . preg_quote("@$possible_username", '/') . '/', '[user]' . $user->data()->id . '[/user]', $value);

// Check if user is blocked by OP
if ($link && ($alert_full && $alert_short) && ($user->data()->id != $author_id) && !$user->isBlocked($user->data()->id, $author_id)) {
if ($value && $link && ($alert_full && $alert_short) && ($user->data()->id != $author_id) && !$user->isBlocked($user->data()->id, $author_id)) {
Alert::create($user->data()->id, 'tag', $alert_short, $alert_full, $link);
break;
}
Expand Down
3 changes: 3 additions & 0 deletions core/classes/Misc/Text.php
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ public static function embedSafe(?string $content): string

$content = html_entity_decode($content);

// Also strip any mentions
$content = MentionsHook::stripPost(['content' => $content])['content'];

return self::truncate($content, 512, [
'html' => true,
]);
Expand Down
5 changes: 1 addition & 4 deletions core/includes/updates/212.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ public function run(): void
{
$this->runMigrations();

PurgeExpiredSessions::schedule(new Language('core', 'en_UK'));
PurgeInactiveUsers::schedule(new Language('core', 'en_UK'));

$this->setVersion('2.2.0');
$this->setVersion('2.1.3');
}
};
13 changes: 13 additions & 0 deletions core/includes/updates/213.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

return new class() extends UpgradeScript {
public function run(): void
{
$this->runMigrations();

PurgeExpiredSessions::schedule(new Language('core', 'en_UK'));
PurgeInactiveUsers::schedule(new Language('core', 'en_UK'));

$this->setVersion('2.2.0');
}
};
18 changes: 2 additions & 16 deletions custom/panel_templates/Default/assets/js/sb-admin-2.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,6 @@

$('[data-toggle="tooltip"]').tooltip({
trigger: 'hover'
})
})

!(function (s) {
"use strict";
s(window).resize(function () {
s(window).width() < 768 && s(".sidebar .collapse").collapse("hide"),
s(window).width() < 480 && !s(".sidebar").hasClass("toggled") && (s("body").addClass("sidebar-toggled"), s(".sidebar").addClass("toggled"), s(".sidebar .collapse").collapse("hide"));
}),
s("body.fixed-nav .sidebar").on("mousewheel DOMMouseScroll wheel", function (e) {
if (768 < s(window).width()) {
var o = e.originalEvent,
l = o.wheelDelta || -o.detail;
(this.scrollTop += 30 * (l < 0 ? 1 : -1)), e.preventDefault();
}
});
})(jQuery);
// @license-end
// @license-end
2 changes: 1 addition & 1 deletion custom/panel_templates/Default/core/user.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
</td>
<td>
{if $USER_PROFILE_FIELDS[$field->id]->value}
{$USER_PROFILE_FIELDS[$field->id]->value}
{$USER_PROFILE_FIELDS[$field->id]->purifyValue()}
{else}
<i>{$NOT_SET}</i>
{/if}
Expand Down
14 changes: 13 additions & 1 deletion custom/panel_templates/Default/core/users_edit.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
<div class="col-md-3">
<span class="float-md-right">
{if isset($DELETE_USER) || isset($RESEND_ACTIVATION_EMAIL) ||
isset($VALIDATE_USER)}
isset($VALIDATE_USER) || isset($DISABLE_TFA)}
<div class="btn-group">
<button type="button" class="btn btn-primary dropdown-toggle"
data-toggle="dropdown" aria-haspopup="true"
Expand All @@ -57,6 +57,8 @@
onclick="validateUser()">{$VALIDATE_USER}</a>{/if}
{if isset($CHANGE_PASSWORD)}<a class="dropdown-item" href="#"
onclick="changePassword()">{$CHANGE_PASSWORD}</a> {/if}
{if isset($DISABLE_TFA)}<a class="dropdown-item" href="#"
onclick="disableTfa()">{$DISABLE_TFA}</a> {/if}
</div>
</div>
{/if}
Expand Down Expand Up @@ -260,6 +262,10 @@
<form style="display:none" action="{$VALIDATE_USER_LINK}" method="post" id="validateUserForm">
<input type="hidden" name="token" value="{$TOKEN}" />
</form>
<form style="display:none" action="{$DISABLE_TFA_LINK}" method="post" id="disableTfaForm">
<input type="hidden" name="token" value="{$TOKEN}" />
</form>


{include file='scripts.tpl'}

Expand All @@ -282,6 +288,12 @@
}
{/if}
{if isset($DISABLE_TFA)}
function disableTfa() {
$('#disableTfaForm').submit();
}
{/if}
$(document).ready(() => {
$('#inputGroups').select2({ placeholder: "{$NO_ITEM_SELECTED}" });
})
Expand Down
38 changes: 38 additions & 0 deletions modules/Core/hooks/MentionsHook.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,44 @@ static function (array $match) {
return $params;
}

/**
* Strips [user] tags and parses the ID to username
* e.g. [user]1[/user] would instead become (at)Username
*
* @param array $params
* @return array
*/
public static function stripPost(array $params = []): array {
if (parent::validateParams($params, ['content'])) {
$params['content'] = preg_replace_callback(
'/\[user\](.*?)\[\/user\]/ism',
static function (array $match) {
if (isset(MentionsHook::$_cache[$match[1]])) {
$userNickname = MentionsHook::$_cache[$match[1]][2];
} else {
$user = new User($match[1]);

if (!$user->exists()) {
return '@' . (new Language('core', LANGUAGE))->get('general', 'deleted_user');
}

$userId = $user->data()->id;
$userStyle = $user->getGroupStyle();
$userNickname = $user->data()->nickname;
$userProfileUrl = $user->getProfileURL();

MentionsHook::$_cache[$match[1]] = [$userId, $userStyle, $userNickname, $userProfileUrl];
}

return '@' . Output::getClean($userNickname);
},
$params['content']
);
}

return $params;
}

private static function validate(array $params): bool {
return parent::validateParams($params, ['content', 'user']);
}
Expand Down
2 changes: 1 addition & 1 deletion modules/Core/includes/endpoints/VerifyEndpoint.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function execute(Nameless2API $api, User $user): void {

$user->update([
'active' => true,
'reset_code' => ''
'reset_code' => null,
]);

EventHandler::executeEvent(new UserValidatedEvent(
Expand Down
2 changes: 2 additions & 0 deletions modules/Core/language/en_UK.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@
"admin/force_tfa": "Force Two Factor Authentication for group members?",
"admin/force_tfa_alert": "Your group requires you to have Two Factor Authentication enabled.",
"admin/force_tfa_warning": "Please ensure you know what this does, or else you risk locking out yourself and all the group members.",
"admin/edit_user_tfa_disabled": "Two factor authentication has successfully been disabled for this user.",
"admin/disable_tfa": "Disable 2FA",
"admin/force_www": "Force www?",
"admin/forgot_password_email": "Forgot Password Email",
"admin/forum_posts": "Display on Forum",
Expand Down
Loading

0 comments on commit d6568bf

Please sign in to comment.