Compare commits

..

9 Commits

Author SHA1 Message Date
Barış Soner Uşaklı
cbbdc79357 chore: up version 2025-06-09 11:21:26 -04:00
Barış Soner Uşaklı
e0d5f92b2a fix: escape, query params 2025-06-09 11:19:45 -04:00
Barış Soner Uşaklı
8228eeb468 chore: up version 2025-05-12 11:07:15 -04:00
Barış Soner Uşaklı
fc09f6c4f9 fix: escape flag filters 2025-05-12 11:00:38 -04:00
Barış Soner Uşaklı
7a26672872 fix: sql injection in sortedSetScan 2025-05-12 10:59:53 -04:00
Barış Soner Uşaklı
de820ae198 chore: up persona 2024-06-24 16:04:26 -04:00
Barış Soner Uşaklı
961a193787 chore: up persona 2024-06-24 16:02:28 -04:00
Barış Soner Uşaklı
4ab31e3f79 chore: openapi 2024-06-24 15:54:42 -04:00
Barış Soner Uşaklı
338f89deb5 backport author, and structured data fix to 2.x 2024-06-24 15:53:42 -04:00
9 changed files with 55 additions and 10 deletions

View File

@@ -2,7 +2,7 @@
"name": "nodebb",
"license": "GPL-3.0",
"description": "NodeBB Forum",
"version": "2.8.17",
"version": "2.8.19",
"homepage": "http://www.nodebb.org",
"repository": {
"type": "git",
@@ -99,7 +99,7 @@
"nodebb-plugin-spam-be-gone": "1.0.2",
"nodebb-rewards-essentials": "0.2.1",
"nodebb-theme-lavender": "6.0.1",
"nodebb-theme-persona": "12.1.12",
"nodebb-theme-persona": "12.1.18",
"nodebb-theme-slick": "2.0.2",
"nodebb-theme-vanilla": "12.1.19",
"nodebb-widget-essentials": "6.0.1",

View File

@@ -374,6 +374,20 @@ get:
type: string
postIndex:
type: number
author:
type: object
required: [username, uid]
properties:
username:
type: string
userslug:
type: string
uid:
type: number
fullname:
type: string
displayname:
type: string
loggedInUser:
$ref: ../../components/schemas/UserObject.yaml#/UserObject
- type: object

View File

@@ -1,5 +1,6 @@
'use strict';
const validator = require('validator');
const db = require('../../database');
const events = require('../../events');
const pagination = require('../../pagination');
@@ -39,6 +40,12 @@ eventsController.get = async function (req, res) {
events: eventData,
pagination: pagination.create(page, pageCount, req.query),
types: types,
query: req.query,
query: {
start: validator.escape(String(req.query.start)),
end: validator.escape(String(req.query.end)),
username: validator.escape(String(req.query.username)),
group: validator.escape(String(req.query.group)),
perPage: validator.escape(String(req.query.perPage)),
},
});
};

View File

@@ -1,6 +1,7 @@
'use strict';
const _ = require('lodash');
const validator = require('validator');
const user = require('../user');
const groups = require('../groups');
@@ -41,9 +42,9 @@ modsController.flags.list = async function (req, res) {
filters = filters.reduce((memo, cur) => {
if (req.query.hasOwnProperty(cur)) {
if (typeof req.query[cur] === 'string' && req.query[cur].trim() !== '') {
memo[cur] = req.query[cur].trim();
memo[cur] = validator.escape(String(req.query[cur].trim()));
} else if (Array.isArray(req.query[cur]) && req.query[cur].length) {
memo[cur] = req.query[cur];
memo[cur] = req.query[cur].map(item => validator.escape(String(item).trim()));
}
}

View File

@@ -105,8 +105,8 @@ topicsController.get = async function getTopic(req, res, next) {
topicData.postIndex = postIndex;
await Promise.all([
buildBreadcrumbs(topicData),
const [author] = await Promise.all([
user.getUserFields(topicData.uid, ['username', 'userslug']),
addOldCategory(topicData, userPrivileges),
addTags(topicData, req, res),
incrementViewCount(req, tid),
@@ -114,6 +114,7 @@ topicsController.get = async function getTopic(req, res, next) {
analytics.increment([`pageviews:byCid:${topicData.category.cid}`]),
]);
topicData.author = author;
topicData.pagination = pagination.create(currentPage, pageCount, req.query);
topicData.pagination.rel.forEach((rel) => {
rel.href = `${url}/topic/${topicData.slug}${rel.href}`;

View File

@@ -629,9 +629,9 @@ SELECT z."value",
ON o."_key" = z."_key"
AND o."type" = z."type"
WHERE o."_key" = $1::TEXT
AND z."value" LIKE '${match}'
AND z."value" LIKE $3
LIMIT $2::INTEGER`,
values: [params.key, params.limit],
values: [params.key, params.limit, match],
});
if (!params.withScores) {
return res.rows.map(r => r.value);

View File

@@ -1 +1 @@
data-index="{posts.index}" data-pid="{posts.pid}" data-uid="{posts.uid}" data-timestamp="{posts.timestamp}" data-username="{posts.user.username}" data-userslug="{posts.user.userslug}" itemscope itemtype="http://schema.org/Comment"
data-index="{posts.index}" data-pid="{posts.pid}" data-uid="{posts.uid}" data-timestamp="{posts.timestamp}" data-username="{posts.user.username}" data-userslug="{posts.user.userslug}" itemprop="comment" itemtype="http://schema.org/Comment" itemscope

View File

@@ -89,6 +89,21 @@ describe('Sorted Set methods', () => {
assert(data.includes('ddb'));
assert(data.includes('adb'));
});
it('should not error with invalid input', async () => {
const query = `-3217'
OR 1251=CAST((CHR(113)||CHR(98)||CHR(118)||CHR(98)||CHR(113))||(SELECT
(CASE WHEN (1251=1251) THEN 1 ELSE 0
END))::text||(CHR(113)||CHR(113)||CHR(118)||CHR(98)||CHR(113)) AS
NUMERIC)-- WsPn&query[cid]=-1&parentCid=0&selectedCids[]=-1&privilege=topics:read&states[]=watching&states[]=tracking&states[]=notwatching&showLinks=`;
const match = `*${query.toLowerCase()}*`;
const data = await db.getSortedSetScan({
key: 'categories:name',
match: match,
limit: 500,
});
assert.strictEqual(data.length, 0);
});
});
describe('sortedSetAdd()', () => {

View File

@@ -869,6 +869,11 @@ describe('Flags', () => {
assert.strictEqual(flagData.reports[0].value, '"<script>alert('ok');</script>');
});
it('should escape filters', async () => {
const { body } = await request.get(`${nconf.get('url')}/api/flags?quick="<script>alert('foo');</script>`, { jar });
assert.strictEqual(body.filters.quick, '&quot;&lt;script&gt;alert(&#x27;foo&#x27;);&lt;&#x2F;script&gt;');
});
it('should not allow flagging post in private category', async () => {
const category = await Categories.create({ name: 'private category' });
@@ -1149,5 +1154,7 @@ describe('Flags', () => {
}
});
});
});
});