mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-12-26 10:20:23 +01:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c46ff42f6 | ||
|
|
89e059a084 | ||
|
|
fecd84d1a0 | ||
|
|
00e48803a6 | ||
|
|
a788bd1344 | ||
|
|
9f38692369 | ||
|
|
0bffd3d93c | ||
|
|
9c250b78b0 | ||
|
|
7d04e95226 | ||
|
|
f295174e07 | ||
|
|
459bc52338 | ||
|
|
39e009c05a | ||
|
|
747cb1f0a1 | ||
|
|
48c9f4470f | ||
|
|
66aa31698f | ||
|
|
1d5eff2365 | ||
|
|
25ae58e8a0 | ||
|
|
d17d4ec09b |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,3 +1,28 @@
|
||||
#### v2.8.2 (2023-01-13)
|
||||
|
||||
##### Chores
|
||||
|
||||
* incrementing version number - v2.8.1 (727f879e)
|
||||
* update changelog for v2.8.1 (d17d4ec0)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* move call to `filter:middleware.buildHeader` out of parallel so that req can be overridden by plugins prior to loading config (25ae58e8)
|
||||
|
||||
#### v2.8.1 (2022-12-30)
|
||||
|
||||
##### Chores
|
||||
|
||||
* fallbacks for new language string (8a69e740)
|
||||
* remove extraneous lines from changelog (bbaf26ce)
|
||||
* incrementing version number - v2.8.0 (8e77673d)
|
||||
* update changelog for v2.8.0 (a5c2edb9)
|
||||
|
||||
##### Bug Fixes
|
||||
|
||||
* vulnerability in socket.io nested namespaces (#11117) (586eed14)
|
||||
* lock post/reply similar to user.create (1ea9481a)
|
||||
|
||||
#### v2.8.0 (2022-12-21)
|
||||
|
||||
##### Chores
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "nodebb",
|
||||
"license": "GPL-3.0",
|
||||
"description": "NodeBB Forum",
|
||||
"version": "2.8.1",
|
||||
"version": "2.8.3",
|
||||
"homepage": "http://www.nodebb.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -148,7 +148,7 @@
|
||||
"zxcvbn": "4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apidevtools/swagger-parser": "10.0.3",
|
||||
"@apidevtools/swagger-parser": "9.0.0",
|
||||
"@commitlint/cli": "17.3.0",
|
||||
"@commitlint/config-angular": "17.3.0",
|
||||
"coveralls": "3.1.1",
|
||||
|
||||
@@ -307,18 +307,17 @@ async function isPrivilegedOrSelfAndPasswordMatch(caller, data) {
|
||||
async function processDeletion({ uid, method, password, caller }) {
|
||||
const isTargetAdmin = await user.isAdministrator(uid);
|
||||
const isSelf = parseInt(uid, 10) === parseInt(caller.uid, 10);
|
||||
const isAdmin = await user.isAdministrator(caller.uid);
|
||||
const hasAdminPrivilege = await privileges.admin.can('admin:users', caller.uid);
|
||||
|
||||
if (isSelf && meta.config.allowAccountDelete !== 1) {
|
||||
throw new Error('[[error:account-deletion-disabled]]');
|
||||
} else if (!isSelf && !isAdmin) {
|
||||
} else if (!isSelf && !hasAdminPrivilege) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
} else if (isTargetAdmin) {
|
||||
throw new Error('[[error:cant-delete-admin]');
|
||||
}
|
||||
|
||||
// Privilege checks -- only deleteAccount is available for non-admins
|
||||
const hasAdminPrivilege = await privileges.admin.can('admin:users', caller.uid);
|
||||
if (!hasAdminPrivilege && ['delete', 'deleteContent'].includes(method)) {
|
||||
throw new Error('[[error:no-privileges]]');
|
||||
}
|
||||
|
||||
@@ -99,6 +99,10 @@ Categories.getModerators = async function (cid) {
|
||||
};
|
||||
|
||||
Categories.getModeratorUids = async function (cids) {
|
||||
// Only check active categories
|
||||
const disabled = (await Categories.getCategoriesFields(cids, ['disabled'])).map(obj => obj.disabled);
|
||||
// cids = cids.filter((_, idx) => !disabled[idx]);
|
||||
|
||||
const groupNames = cids.reduce((memo, cid) => {
|
||||
memo.push(`cid:${cid}:privileges:moderate`);
|
||||
memo.push(`cid:${cid}:privileges:groups:moderate`);
|
||||
@@ -120,9 +124,13 @@ Categories.getModeratorUids = async function (cids) {
|
||||
const uniqGroups = _.uniq(_.flatten(sets.groupNames));
|
||||
const groupUids = await groups.getMembersOfGroups(uniqGroups);
|
||||
const map = _.zipObject(uniqGroups, groupUids);
|
||||
const moderatorUids = cids.map(
|
||||
(cid, index) => _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))))
|
||||
);
|
||||
const moderatorUids = cids.map((cid, index) => {
|
||||
if (disabled[index]) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return _.uniq(sets.uids[index].concat(_.flatten(sets.groupNames[index].map(g => map[g]))));
|
||||
});
|
||||
return moderatorUids;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@ try {
|
||||
if (!semver.satisfies(version, defaultPackage.dependencies[packageName])) {
|
||||
const e = new TypeError(`Incorrect dependency version: ${packageName}`);
|
||||
e.code = 'DEP_WRONG_VERSION';
|
||||
// delete the module from require cache so it doesn't break rest of the upgrade
|
||||
// https://github.com/NodeBB/NodeBB/issues/11173
|
||||
const resolvedModule = require.resolve(packageName);
|
||||
if (require.cache[resolvedModule]) {
|
||||
delete require.cache[resolvedModule];
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -40,14 +40,24 @@ async function linkModules() {
|
||||
await Promise.all(Object.keys(modules).map(async (relPath) => {
|
||||
const srcPath = path.join(__dirname, '../../', modules[relPath]);
|
||||
const destPath = path.join(__dirname, '../../build/public/src/modules', relPath);
|
||||
const destDir = path.dirname(destPath);
|
||||
|
||||
const [stats] = await Promise.all([
|
||||
fs.promises.stat(srcPath),
|
||||
mkdirp(path.dirname(destPath)),
|
||||
mkdirp(destDir),
|
||||
]);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
await file.linkDirs(srcPath, destPath, true);
|
||||
} else {
|
||||
await fs.promises.copyFile(srcPath, destPath);
|
||||
// Get the relative path to the destination directory
|
||||
const relPath = path.relative(destDir, srcPath)
|
||||
// and convert to a posix path
|
||||
.split(path.sep).join(path.posix.sep);
|
||||
|
||||
// Instead of copying file, create a new file re-exporting it
|
||||
// This way, imports in modules are resolved correctly
|
||||
await fs.promises.writeFile(destPath, `export * from '${relPath}'`);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -34,10 +34,11 @@ middleware.buildHeader = helpers.try(async (req, res, next) => {
|
||||
if (req.method === 'GET') {
|
||||
await require('./index').applyCSRFasync(req, res);
|
||||
}
|
||||
|
||||
({ req, locals: res.locals } = await plugins.hooks.fire('filter:middleware.buildHeader', { req: req, locals: res.locals }));
|
||||
const [config, canLoginIfBanned] = await Promise.all([
|
||||
controllers.api.loadConfig(req),
|
||||
user.bans.canLoginIfBanned(req.uid),
|
||||
plugins.hooks.fire('filter:middleware.buildHeader', { req: req, locals: res.locals }),
|
||||
]);
|
||||
|
||||
if (!canLoginIfBanned && req.loggedIn) {
|
||||
|
||||
@@ -66,6 +66,7 @@ privsAdmin.routeMap = {
|
||||
uploadDefaultAvatar: 'admin:settings',
|
||||
};
|
||||
privsAdmin.routePrefixMap = {
|
||||
'dashboard/': 'admin:dashboard',
|
||||
'manage/categories/': 'admin:categories',
|
||||
'manage/privileges/': 'admin:privileges',
|
||||
'manage/groups/': 'admin:groups',
|
||||
|
||||
@@ -827,16 +827,17 @@ describe('Categories', () => {
|
||||
});
|
||||
|
||||
describe('Categories.getModeratorUids', () => {
|
||||
before((done) => {
|
||||
async.series([
|
||||
async.apply(groups.create, { name: 'testGroup' }),
|
||||
async.apply(groups.join, 'cid:1:privileges:groups:moderate', 'testGroup'),
|
||||
async.apply(groups.join, 'testGroup', 1),
|
||||
], done);
|
||||
let cid;
|
||||
|
||||
before(async () => {
|
||||
({ cid } = await Categories.create({ name: 'foobar' }));
|
||||
await groups.create({ name: 'testGroup' });
|
||||
await groups.join(`cid:${cid}:privileges:groups:moderate`, 'testGroup');
|
||||
await groups.join('testGroup', 1);
|
||||
});
|
||||
|
||||
it('should retrieve all users with moderator bit in category privilege', (done) => {
|
||||
Categories.getModeratorUids([1, 2], (err, uids) => {
|
||||
Categories.getModeratorUids([cid, 2], (err, uids) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(uids.length, 2);
|
||||
assert(uids[0].includes('1'));
|
||||
@@ -851,7 +852,7 @@ describe('Categories', () => {
|
||||
async.apply(groups.join, 'cid:1:privileges:groups:moderate', 'testGroup2'),
|
||||
async.apply(groups.join, 'testGroup2', 1),
|
||||
function (next) {
|
||||
Categories.getModeratorUids([1, 2], (err, uids) => {
|
||||
Categories.getModeratorUids([cid, 2], (err, uids) => {
|
||||
assert.ifError(err);
|
||||
assert(uids[0].includes('1'));
|
||||
next();
|
||||
@@ -860,10 +861,18 @@ describe('Categories', () => {
|
||||
], done);
|
||||
});
|
||||
|
||||
it('should not return moderators of disabled categories', async () => {
|
||||
const payload = {};
|
||||
payload[cid] = { disabled: 1 };
|
||||
await Categories.update(payload);
|
||||
const uids = await Categories.getModeratorUids([cid, 2]);
|
||||
assert(!uids[0].includes('1'));
|
||||
});
|
||||
|
||||
after((done) => {
|
||||
async.series([
|
||||
async.apply(groups.leave, 'cid:1:privileges:groups:moderate', 'testGroup'),
|
||||
async.apply(groups.leave, 'cid:1:privileges:groups:moderate', 'testGroup2'),
|
||||
async.apply(groups.leave, `cid:${cid}:privileges:groups:moderate`, 'testGroup'),
|
||||
async.apply(groups.leave, `cid:${cid}:privileges:groups:moderate`, 'testGroup2'),
|
||||
async.apply(groups.destroy, 'testGroup'),
|
||||
async.apply(groups.destroy, 'testGroup2'),
|
||||
], done);
|
||||
|
||||
Reference in New Issue
Block a user