Ensure case-sensitive DB queries on MySQL/MariaDB

MySQLs string comparisons are case-insensitive by default.
This allows to hide notes by creating a new note with an alias that
equals the lower-cased alias of another note.
The new note is returned first by MySQL, so the original one is not
accessible anymore.

This fixes the problem by using an explicit binary comparison in the
affected queries.

See https://dev.mysql.com/doc/refman/8.0/en/case-sensitivity.html

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2023-10-01 20:40:15 +02:00
parent c543dc1f23
commit 380587b7fd
2 changed files with 15 additions and 6 deletions

View file

@ -18,6 +18,7 @@ const S = require('string')
// core // core
const config = require('../config') const config = require('../config')
const logger = require('../logger') const logger = require('../logger')
const utils = require('../utils')
// ot // ot
const ot = require('../ot') const ot = require('../ot')
@ -191,9 +192,11 @@ module.exports = function (sequelize, DataTypes) {
parseNoteIdByAlias: function (_callback) { parseNoteIdByAlias: function (_callback) {
// try to parse note id by alias (e.g. doc) // try to parse note id by alias (e.g. doc)
Note.findOne({ Note.findOne({
where: { where: utils.isMySQL(sequelize)
alias: noteId ? sequelize.where(sequelize.fn('BINARY', sequelize.col('alias')), noteId)
} : {
alias: noteId
}
}).then(function (note) { }).then(function (note) {
if (note) { if (note) {
const filePath = path.join(config.docsPath, path.basename(noteId) + '.md') const filePath = path.join(config.docsPath, path.basename(noteId) + '.md')
@ -296,9 +299,11 @@ module.exports = function (sequelize, DataTypes) {
try { try {
if (shortId.isValid(noteId)) { if (shortId.isValid(noteId)) {
Note.findOne({ Note.findOne({
where: { where: utils.isMySQL(sequelize)
shortid: noteId ? sequelize.where(sequelize.fn('BINARY', sequelize.col('shortid')), noteId)
} : {
shortid: noteId
}
}).then(function (note) { }).then(function (note) {
if (!note) return _callback(null, null) if (!note) return _callback(null, null)
return callback(null, note.id) return callback(null, note.id)

View file

@ -4,6 +4,10 @@ exports.isSQLite = function isSQLite (sequelize) {
return sequelize.options.dialect === 'sqlite' return sequelize.options.dialect === 'sqlite'
} }
exports.isMySQL = function isMySQL (sequelize) {
return ['mysql', 'mariadb'].includes(sequelize.options.dialect)
}
exports.getImageMimeType = function getImageMimeType (imagePath) { exports.getImageMimeType = function getImageMimeType (imagePath) {
const fileExtension = /[^.]+$/.exec(imagePath) const fileExtension = /[^.]+$/.exec(imagePath)