Merge commit '51096ad2345fb1d1380bec0a447113489ef6c359' into v3.x

This commit is contained in:
Misty Release Bot
2023-05-15 16:43:35 +00:00
11 changed files with 70 additions and 25 deletions

View File

@@ -47,6 +47,7 @@ jobs:
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}.x
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch,enable=${{ github.event.repository.default_branch != github.ref }}
- name: Build and push Docker images
uses: docker/build-push-action@v4

View File

@@ -1,3 +1,17 @@
#### v3.1.2 (2023-05-12)
##### Chores
* incrementing version number - v3.1.1 (40250733)
* update changelog for v3.1.1 (ccd6f48c)
* incrementing version number - v3.1.0 (0cb386bd)
* incrementing version number - v3.0.1 (26f6ea49)
* incrementing version number - v3.0.0 (224e08cd)
##### Bug Fixes
* #11595, use default value (28740de7)
#### v3.1.1 (2023-05-11)
##### Chores

View File

@@ -235,15 +235,14 @@ define('forum/chats', [
}
});
mousetrap.bind('up', function (e) {
if (e.target === components.get('chat/input').get(0)) {
const inputEl = components.get('chat/input');
if (e.target === inputEl.get(0) && !inputEl.val()) {
// Retrieve message id from messages list
const message = components.get('chat/messages').find('.chat-message[data-self="1"]').last();
if (!message.length) {
return;
}
const lastMid = message.attr('data-mid');
const inputEl = components.get('chat/input');
messages.prepEdit(inputEl, lastMid, ajaxify.data.roomId);
}
});

View File

@@ -176,6 +176,11 @@ define('forum/chats/messages', [
autoCompleteEl.destroy();
}
}
textarea.on('keyup', (e) => {
if (e.key === 'Escape') {
finishEdit();
}
});
editEl.find('[data-action="cancel"]').on('click', finishEdit);
editEl.find('[data-action="save"]').on('click', function () {

View File

@@ -15,6 +15,9 @@ app = window.app || {};
reconnectionDelay: config.reconnectionDelay,
transports: config.socketioTransports,
path: config.relative_path + '/socket.io',
query: {
_csrf: config.csrf_token,
},
};
window.socket = io(config.websocketAddress, ioParams);

View File

@@ -89,9 +89,9 @@ Themes.set = async (data) => {
switch (data.type) {
case 'local': {
const current = await Meta.configs.get('theme:id');
const score = await db.sortedSetScore('plugins:active', current);
await db.sortedSetRemove('plugins:active', current);
const numPlugins = await db.sortedSetCard('plugins:active');
await db.sortedSetAdd('plugins:active', numPlugins, data.id);
await db.sortedSetAdd('plugins:active', score || 0, data.id);
if (current !== data.id) {
const pathToThemeJson = path.join(nconf.get('themes_path'), data.id, 'theme.json');
@@ -103,9 +103,9 @@ Themes.set = async (data) => {
config = JSON.parse(config);
const activePluginsConfig = nconf.get('plugins:active');
if (!activePluginsConfig) {
const score = await db.sortedSetScore('plugins:active', current);
await db.sortedSetRemove('plugins:active', current);
const numPlugins = await db.sortedSetCard('plugins:active');
await db.sortedSetAdd('plugins:active', numPlugins, data.id);
await db.sortedSetAdd('plugins:active', score || 0, data.id);
} else if (!activePluginsConfig.includes(data.id)) {
// This prevents changing theme when configuration doesn't include it, but allows it otherwise
winston.error(`When defining active plugins in configuration, changing themes requires adding the theme '${data.id}' to the list of active plugins before updating it in the ACP`);

View File

@@ -5,12 +5,15 @@ const { csrfSync } = require('csrf-sync');
const {
generateToken,
csrfSynchronisedProtection,
isRequestValid,
} = csrfSync({
getTokenFromRequest: (req) => {
if (req.headers['x-csrf-token']) {
return req.headers['x-csrf-token'];
} else if (req.body.csrf_token) {
} else if (req.body && req.body.csrf_token) {
return req.body.csrf_token;
} else if (req.query) {
return req.query._csrf;
}
},
size: 64,
@@ -19,4 +22,5 @@ const {
module.exports = {
generateToken,
csrfSynchronisedProtection,
isRequestValid,
};

View File

@@ -34,13 +34,25 @@ Sockets.init = async function (server) {
}
}
io.use(authorize);
io.on('connection', onConnection);
const opts = {
transports: nconf.get('socket.io:transports') || ['polling', 'websocket'],
cookie: false,
allowRequest: (req, callback) => {
authorize(req, (err) => {
if (err) {
return callback(err);
}
const csrf = require('../middleware/csrf');
const isValid = csrf.isRequestValid({
session: req.session || {},
query: req._query,
headers: req.headers,
});
callback(null, isValid);
});
},
};
/*
* Restrict socket.io listener to cookie domain. If none is set, infer based on url.
@@ -62,7 +74,11 @@ Sockets.init = async function (server) {
};
function onConnection(socket) {
socket.ip = (socket.request.headers['x-forwarded-for'] || socket.request.connection.remoteAddress || '').split(',')[0];
socket.uid = socket.request.uid;
socket.ip = (
socket.request.headers['x-forwarded-for'] ||
socket.request.connection.remoteAddress || ''
).split(',')[0];
socket.request.ip = socket.ip;
logger.io_one(socket, socket.uid);
@@ -231,9 +247,7 @@ async function validateSession(socket, errorMsg) {
const cookieParserAsync = util.promisify((req, callback) => cookieParser(req, {}, err => callback(err)));
async function authorize(socket, callback) {
const { request } = socket;
async function authorize(request, callback) {
if (!request) {
return callback(new Error('[[error:not-authorized]]'));
}
@@ -246,15 +260,13 @@ async function authorize(socket, callback) {
});
const sessionData = await getSessionAsync(sessionId);
request.session = sessionData;
let uid = 0;
if (sessionData && sessionData.passport && sessionData.passport.user) {
request.session = sessionData;
socket.uid = parseInt(sessionData.passport.user, 10);
} else {
socket.uid = 0;
uid = parseInt(sessionData.passport.user, 10);
}
request.uid = socket.uid;
callback();
request.uid = uid;
callback(null, uid);
}
Sockets.in = function (room) {

View File

@@ -199,13 +199,17 @@ function setupHelmet(app) {
}
if (meta.config['hsts-enabled']) {
options.hsts = {
maxAge: meta.config['hsts-maxage'],
maxAge: Math.max(0, meta.config['hsts-maxage']),
includeSubDomains: !!meta.config['hsts-subdomains'],
preload: !!meta.config['hsts-preload'],
};
}
app.use(helmet(options));
try {
app.use(helmet(options));
} catch (err) {
winston.error(`[startup] unable to initialize helmet \n${err.stack}`);
}
}

View File

@@ -96,7 +96,7 @@ helpers.logoutUser = function (jar, callback) {
});
};
helpers.connectSocketIO = function (res, callback) {
helpers.connectSocketIO = function (res, csrf_token, callback) {
const io = require('socket.io-client');
let cookies = res.headers['set-cookie'];
cookies = cookies.filter(c => /express.sid=[^;]+;/.test(c));
@@ -107,6 +107,9 @@ helpers.connectSocketIO = function (res, callback) {
Origin: nconf.get('url'),
Cookie: cookie,
},
query: {
_csrf: csrf_token,
},
});
socket.on('connect', () => {

View File

@@ -73,7 +73,7 @@ describe('socket.io', () => {
}, (err, res) => {
assert.ifError(err);
helpers.connectSocketIO(res, (err, _io) => {
helpers.connectSocketIO(res, body.csrf_token, (err, _io) => {
io = _io;
assert.ifError(err);