fix: upgrade sequelize to latest version to fix CVE

Signed-off-by: BoHong Li <a60814billy@gmail.com>
This commit is contained in:
BoHong Li 2019-04-12 12:05:32 +08:00 committed by Sheogorath
parent 02929cd4bf
commit 63c96e7359
No known key found for this signature in database
GPG key ID: 1F05CC3635CDDFFD
6 changed files with 796 additions and 789 deletions

View file

@ -18,9 +18,10 @@ module.exports = function (sequelize, DataTypes) {
unique: true,
fields: ['noteId', 'userId']
}
],
classMethods: {
associate: function (models) {
]
})
Author.associate = function (models) {
Author.belongsTo(models.Note, {
foreignKey: 'noteId',
as: 'note',
@ -36,7 +37,6 @@ module.exports = function (sequelize, DataTypes) {
hooks: true
})
}
}
})
return Author
}

View file

@ -10,7 +10,9 @@ var config = require('../config')
var logger = require('../logger')
var dbconfig = cloneDeep(config.db)
dbconfig.logging = config.debug ? logger.info : false
dbconfig.logging = config.debug ? (data) => {
logger.info(data)
} : false
var sequelize = null

View file

@ -86,8 +86,53 @@ module.exports = function (sequelize, DataTypes) {
}
}, {
paranoid: false,
classMethods: {
associate: function (models) {
hooks: {
beforeCreate: function (note, options) {
return new Promise(function (resolve, reject) {
// if no content specified then use default note
if (!note.content) {
var body = null
let filePath = null
if (!note.alias) {
filePath = config.defaultNotePath
} else {
filePath = path.join(config.docsPath, note.alias + '.md')
}
if (Note.checkFileExist(filePath)) {
var fsCreatedTime = moment(fs.statSync(filePath).ctime)
body = fs.readFileSync(filePath, 'utf8')
note.title = Note.parseNoteTitle(body)
note.content = body
if (filePath !== config.defaultNotePath) {
note.createdAt = fsCreatedTime
}
}
}
// if no permission specified and have owner then give default permission in config, else default permission is freely
if (!note.permission) {
if (note.ownerId) {
note.permission = config.defaultPermission
} else {
note.permission = 'freely'
}
}
return resolve(note)
})
},
afterCreate: function (note, options, callback) {
return new Promise(function (resolve, reject) {
sequelize.models.Revision.saveNoteRevision(note, function (err, revision) {
if (err) {
return reject(err)
}
return resolve(note)
})
})
}
}
})
Note.associate = function (models) {
Note.belongsTo(models.User, {
foreignKey: 'ownerId',
as: 'owner',
@ -109,21 +154,21 @@ module.exports = function (sequelize, DataTypes) {
as: 'authors',
constraints: false
})
},
checkFileExist: function (filePath) {
}
Note.checkFileExist = function (filePath) {
try {
return fs.statSync(filePath).isFile()
} catch (err) {
return false
}
},
encodeNoteId: function (id) {
}
Note.encodeNoteId = function (id) {
// remove dashes in UUID and encode in url-safe base64
let str = id.replace(/-/g, '')
let hexStr = Buffer.from(str, 'hex')
return base64url.encode(hexStr)
},
decodeNoteId: function (encodedId) {
}
Note.decodeNoteId = function (encodedId) {
// decode from url-safe base64
let id = base64url.toBuffer(encodedId).toString('hex')
// add dashes between the UUID string parts
@ -134,13 +179,13 @@ module.exports = function (sequelize, DataTypes) {
idParts.push(id.substr(16, 4))
idParts.push(id.substr(20, 12))
return idParts.join('-')
},
checkNoteIdValid: function (id) {
}
Note.checkNoteIdValid = function (id) {
var uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
var result = id.match(uuidRegex)
if (result && result.length === 1) { return true } else { return false }
},
parseNoteId: function (noteId, callback) {
}
Note.parseNoteId = function (noteId, callback) {
async.series({
parseNoteIdByAlias: function (_callback) {
// try to parse note id by alias (e.g. doc)
@ -273,21 +318,21 @@ module.exports = function (sequelize, DataTypes) {
}
return callback(null, null)
})
},
parseNoteInfo: function (body) {
}
Note.parseNoteInfo = function (body) {
var parsed = Note.extractMeta(body)
var $ = cheerio.load(md.render(parsed.markdown))
return {
title: Note.extractNoteTitle(parsed.meta, $),
tags: Note.extractNoteTags(parsed.meta, $)
}
},
parseNoteTitle: function (body) {
}
Note.parseNoteTitle = function (body) {
var parsed = Note.extractMeta(body)
var $ = cheerio.load(md.render(parsed.markdown))
return Note.extractNoteTitle(parsed.meta, $)
},
extractNoteTitle: function (meta, $) {
}
Note.extractNoteTitle = function (meta, $) {
var title = ''
if (meta.title && (typeof meta.title === 'string' || typeof meta.title === 'number')) {
title = meta.title
@ -297,18 +342,18 @@ module.exports = function (sequelize, DataTypes) {
}
if (!title) title = 'Untitled'
return title
},
generateDescription: function (markdown) {
}
Note.generateDescription = function (markdown) {
return markdown.substr(0, 100).replace(/(?:\r\n|\r|\n)/g, ' ')
},
decodeTitle: function (title) {
}
Note.decodeTitle = function (title) {
return title || 'Untitled'
},
generateWebTitle: function (title) {
}
Note.generateWebTitle = function (title) {
title = !title || title === 'Untitled' ? 'CodiMD - Collaborative markdown notes' : title + ' - CodiMD'
return title
},
extractNoteTags: function (meta, $) {
}
Note.extractNoteTags = function (meta, $) {
var tags = []
var rawtags = []
if (meta.tags && (typeof meta.tags === 'string' || typeof meta.tags === 'number')) {
@ -340,8 +385,8 @@ module.exports = function (sequelize, DataTypes) {
if (!found) { tags.push(rawtags[i]) }
}
return tags
},
extractMeta: function (content) {
}
Note.extractMeta = function (content) {
var obj = null
try {
obj = metaMarked(content)
@ -354,8 +399,8 @@ module.exports = function (sequelize, DataTypes) {
}
}
return obj
},
parseMeta: function (meta) {
}
Note.parseMeta = function (meta) {
var _meta = {}
if (meta) {
if (meta.title && (typeof meta.title === 'string' || typeof meta.title === 'number')) { _meta.title = meta.title }
@ -366,8 +411,8 @@ module.exports = function (sequelize, DataTypes) {
if (meta.slideOptions && (typeof meta.slideOptions === 'object')) { _meta.slideOptions = meta.slideOptions }
}
return _meta
},
updateAuthorshipByOperation: function (operation, userId, authorships) {
}
Note.updateAuthorshipByOperation = function (operation, userId, authorships) {
var index = 0
var timestamp = Date.now()
for (let i = 0; i < operation.length; i++) {
@ -467,8 +512,8 @@ module.exports = function (sequelize, DataTypes) {
}
}
return authorships
},
transformPatchToOperations: function (patch, contentLength) {
}
Note.transformPatchToOperations = function (patch, contentLength) {
var operations = []
if (patch.length > 0) {
// calculate original content length
@ -527,45 +572,6 @@ module.exports = function (sequelize, DataTypes) {
}
return operations
}
},
hooks: {
beforeCreate: function (note, options, callback) {
// if no content specified then use default note
if (!note.content) {
var body = null
let filePath = null
if (!note.alias) {
filePath = config.defaultNotePath
} else {
filePath = path.join(config.docsPath, note.alias + '.md')
}
if (Note.checkFileExist(filePath)) {
var fsCreatedTime = moment(fs.statSync(filePath).ctime)
body = fs.readFileSync(filePath, 'utf8')
note.title = Note.parseNoteTitle(body)
note.content = body
if (filePath !== config.defaultNotePath) {
note.createdAt = fsCreatedTime
}
}
}
// if no permission specified and have owner then give default permission in config, else default permission is freely
if (!note.permission) {
if (note.ownerId) {
note.permission = config.defaultPermission
} else {
note.permission = 'freely'
}
}
return callback(null, note)
},
afterCreate: function (note, options, callback) {
sequelize.models.Revision.saveNoteRevision(note, function (err, revision) {
callback(err, note)
})
}
}
})
return Note
}

View file

@ -7,6 +7,8 @@ var childProcess = require('child_process')
var shortId = require('shortid')
var path = require('path')
var Op = Sequelize.Op
// core
var logger = require('../logger')
@ -96,9 +98,9 @@ module.exports = function (sequelize, DataTypes) {
this.setDataValue('authorship', value ? JSON.stringify(value) : value)
}
}
}, {
classMethods: {
associate: function (models) {
})
Revision.associate = function (models) {
Revision.belongsTo(models.Note, {
foreignKey: 'noteId',
as: 'note',
@ -106,8 +108,8 @@ module.exports = function (sequelize, DataTypes) {
onDelete: 'CASCADE',
hooks: true
})
},
getNoteRevisions: function (note, callback) {
}
Revision.getNoteRevisions = function (note, callback) {
Revision.findAll({
where: {
noteId: note.id
@ -126,8 +128,8 @@ module.exports = function (sequelize, DataTypes) {
}).catch(function (err) {
callback(err, null)
})
},
getPatchedNoteRevisionByTime: function (note, time, callback) {
}
Revision.getPatchedNoteRevisionByTime = function (note, time, callback) {
// find all revisions to prepare for all possible calculation
Revision.findAll({
where: {
@ -141,7 +143,7 @@ module.exports = function (sequelize, DataTypes) {
where: {
noteId: note.id,
createdAt: {
$gte: time
[Op.gte]: time
}
},
order: [['createdAt', 'DESC']]
@ -158,8 +160,8 @@ module.exports = function (sequelize, DataTypes) {
}).catch(function (err) {
return callback(err, null)
})
},
checkAllNotesRevision: function (callback) {
}
Revision.checkAllNotesRevision = function (callback) {
Revision.saveAllNotesRevision(function (err, notes) {
if (err) return callback(err, null)
if (!notes || notes.length <= 0) {
@ -168,28 +170,28 @@ module.exports = function (sequelize, DataTypes) {
Revision.checkAllNotesRevision(callback)
}
})
},
saveAllNotesRevision: function (callback) {
}
Revision.saveAllNotesRevision = function (callback) {
sequelize.models.Note.findAll({
// query all notes that need to save for revision
where: {
$and: [
[Op.and]: [
{
lastchangeAt: {
$or: {
$eq: null,
$and: {
$ne: null,
$gt: sequelize.col('createdAt')
[Op.or]: {
[Op.eq]: null,
[Op.and]: {
[Op.ne]: null,
[Op.gt]: sequelize.col('createdAt')
}
}
}
},
{
savedAt: {
$or: {
$eq: null,
$lt: sequelize.col('lastchangeAt')
[Op.or]: {
[Op.eq]: null,
[Op.lt]: sequelize.col('lastchangeAt')
}
}
}
@ -227,8 +229,8 @@ module.exports = function (sequelize, DataTypes) {
}).catch(function (err) {
return callback(err, null)
})
},
saveNoteRevision: function (note, callback) {
}
Revision.saveNoteRevision = function (note, callback) {
Revision.findAll({
where: {
noteId: note.id
@ -292,8 +294,8 @@ module.exports = function (sequelize, DataTypes) {
}).catch(function (err) {
return callback(err, null)
})
},
finishSaveNoteRevision: function (note, revision, callback) {
}
Revision.finishSaveNoteRevision = function (note, revision, callback) {
note.update({
savedAt: revision.updatedAt
}).then(function () {
@ -302,8 +304,6 @@ module.exports = function (sequelize, DataTypes) {
return callback(err, null)
})
}
}
})
return Revision
}

View file

@ -52,14 +52,13 @@ module.exports = function (sequelize, DataTypes) {
password: {
type: Sequelize.TEXT
}
}, {
instanceMethods: {
verifyPassword: function (attempt) {
})
User.prototype.verifyPassword = function (attempt) {
return scrypt.verify(Buffer.from(this.password, 'hex'), attempt)
}
},
classMethods: {
associate: function (models) {
User.associate = function (models) {
User.hasMany(models.Note, {
foreignKey: 'ownerId',
constraints: false
@ -68,14 +67,14 @@ module.exports = function (sequelize, DataTypes) {
foreignKey: 'lastchangeuserId',
constraints: false
})
},
getProfile: function (user) {
}
User.getProfile = function (user) {
if (!user) {
return null
}
return user.profile ? User.parseProfile(user.profile) : (user.email ? User.parseProfileByEmail(user.email) : null)
},
parseProfile: function (profile) {
}
User.parseProfile = function (profile) {
try {
profile = JSON.parse(profile)
} catch (err) {
@ -90,8 +89,8 @@ module.exports = function (sequelize, DataTypes) {
}
}
return profile
},
parsePhotoByProfile: function (profile, bigger) {
}
User.parsePhotoByProfile = function (profile, bigger) {
var photo = null
switch (profile.provider) {
case 'facebook':
@ -146,25 +145,25 @@ module.exports = function (sequelize, DataTypes) {
break
}
return photo
},
parseProfileByEmail: function (email) {
}
User.parseProfileByEmail = function (email) {
return {
name: email.substring(0, email.lastIndexOf('@')),
photo: generateAvatarURL('', email, false),
biggerphoto: generateAvatarURL('', email, true)
}
}
}
})
function updatePasswordHashHook (user, options, done) {
function updatePasswordHashHook (user, options) {
// suggested way to hash passwords to be able to do this asynchronously:
// @see https://github.com/sequelize/sequelize/issues/1821#issuecomment-44265819
if (!user.changed('password')) { return done() }
scrypt.kdf(user.getDataValue('password'), { logN: 15 }).then(keyBuf => {
if (!user.changed('password')) {
return Promise.resolve()
}
return scrypt.kdf(user.getDataValue('password'), { logN: 15 }).then(keyBuf => {
user.setDataValue('password', keyBuf.toString('hex'))
done()
})
}

View file

@ -31,7 +31,7 @@
"codemirror": "git+https://github.com/hackmdio/CodeMirror.git",
"compression": "^1.6.2",
"connect-flash": "^0.1.1",
"connect-session-sequelize": "^4.1.0",
"connect-session-sequelize": "^6.0.0",
"cookie": "0.3.1",
"cookie-parser": "1.4.3",
"deep-freeze": "^0.0.1",
@ -113,8 +113,7 @@
"scrypt-async": "^2.0.1",
"scrypt-kdf": "^2.0.1",
"select2": "^3.5.2-browserify",
"sequelize": "^3.28.0",
"sequelize-cli": "^2.5.1",
"sequelize": "5.3.2",
"shortid": "2.2.8",
"socket.io": "~2.1.1",
"socket.io-client": "~2.1.1",
@ -194,6 +193,7 @@
"mocha": "^5.2.0",
"mock-require": "^3.0.3",
"optimize-css-assets-webpack-plugin": "^5.0.0",
"sequelize-cli": "^5.4.0",
"script-loader": "^0.7.2",
"string-loader": "^0.0.1",
"style-loader": "^0.21.0",