fix: use nanoid instead of shortid

shortid is deprecated and they recommend nanoid instead.
We're not sure if this has to do with possible name
collisions or enumerability, but to be sure and on the
safe side, we're changing this. nanoid seems quite safe
since it uses node's crypto module underneath.

Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
Erik Michelson 2025-05-05 18:13:58 +02:00
parent 5fdc09512a
commit 833c6d66c5
No known key found for this signature in database
GPG key ID: DB99ADDDC5C0AF82
7 changed files with 16 additions and 21 deletions

View file

@ -7,7 +7,7 @@ const base64url = require('base64url')
const md = require('markdown-it')() const md = require('markdown-it')()
const metaMarked = require('@hedgedoc/meta-marked') const metaMarked = require('@hedgedoc/meta-marked')
const cheerio = require('cheerio') const cheerio = require('cheerio')
const shortId = require('shortid') const nanoid = require('nanoid')
const Sequelize = require('sequelize') const Sequelize = require('sequelize')
const async = require('async') const async = require('async')
const moment = require('moment') const moment = require('moment')
@ -37,7 +37,7 @@ module.exports = function (sequelize, DataTypes) {
type: DataTypes.STRING, type: DataTypes.STRING,
unique: true, unique: true,
allowNull: false, allowNull: false,
defaultValue: shortId.generate defaultValue: () => nanoid.nanoid(10)
}, },
alias: { alias: {
type: DataTypes.STRING, type: DataTypes.STRING,
@ -297,7 +297,7 @@ module.exports = function (sequelize, DataTypes) {
parseNoteIdByShortId: function (_callback) { parseNoteIdByShortId: function (_callback) {
// try to parse note id by shortId // try to parse note id by shortId
try { try {
if (shortId.isValid(noteId)) { if (noteId && noteId.length === 10) {
Note.findOne({ Note.findOne({
where: utils.isMySQL(sequelize) where: utils.isMySQL(sequelize)
? sequelize.where(sequelize.fn('BINARY', sequelize.col('shortid')), noteId) ? sequelize.where(sequelize.fn('BINARY', sequelize.col('shortid')), noteId)

View file

@ -4,7 +4,7 @@ const Sequelize = require('sequelize')
const async = require('async') const async = require('async')
const moment = require('moment') const moment = require('moment')
const childProcess = require('child_process') const childProcess = require('child_process')
const shortId = require('shortid') const nanoid = require('nanoid')
const path = require('path') const path = require('path')
const Op = Sequelize.Op const Op = Sequelize.Op
@ -44,7 +44,7 @@ function createDmpWorker () {
function sendDmpWorker (data, callback) { function sendDmpWorker (data, callback) {
if (!dmpWorker) dmpWorker = createDmpWorker() if (!dmpWorker) dmpWorker = createDmpWorker()
const cacheKey = Date.now() + '_' + shortId.generate() const cacheKey = Date.now() + '_' + nanoid.nanoid()
dmpCallbackCache[cacheKey] = callback dmpCallbackCache[cacheKey] = callback
data = Object.assign(data, { data = Object.assign(data, {
cacheKey cacheKey

View file

@ -1,13 +1,13 @@
'use strict' 'use strict'
// external modules // external modules
const shortId = require('shortid') const nanoid = require('nanoid')
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const Temp = sequelize.define('Temp', { const Temp = sequelize.define('Temp', {
id: { id: {
type: DataTypes.STRING, type: DataTypes.STRING,
primaryKey: true, primaryKey: true,
defaultValue: shortId.generate defaultValue: nanoid.nanoid
}, },
data: { data: {
type: DataTypes.TEXT type: DataTypes.TEXT

View file

@ -2,7 +2,7 @@ const models = require('../../models')
const logger = require('../../logger') const logger = require('../../logger')
const config = require('../../config') const config = require('../../config')
const errors = require('../../errors') const errors = require('../../errors')
const shortId = require('shortid') const nanoid = require('nanoid')
const moment = require('moment') const moment = require('moment')
const querystring = require('querystring') const querystring = require('querystring')
@ -36,7 +36,7 @@ exports.createGist = function createGist (req, res, note) {
client_id: config.github.clientID, client_id: config.github.clientID,
redirect_uri: config.serverURL + '/auth/github/callback/' + models.Note.encodeNoteId(note.id) + '/gist', redirect_uri: config.serverURL + '/auth/github/callback/' + models.Note.encodeNoteId(note.id) + '/gist',
scope: 'gist', scope: 'gist',
state: shortId.generate() state: nanoid.nanoid()
} }
const query = querystring.stringify(data) const query = querystring.stringify(data)
res.redirect('https://github.com/login/oauth/authorize?' + query) res.redirect('https://github.com/login/oauth/authorize?' + query)

View file

@ -72,6 +72,7 @@
"moment": "2.30.1", "moment": "2.30.1",
"morgan": "1.10.0", "morgan": "1.10.0",
"mysql2": "3.14.0", "mysql2": "3.14.0",
"nanoid": "3.3.11",
"node-fetch": "2.7.0", "node-fetch": "2.7.0",
"passport": "patch:passport@npm%3A0.7.0#~/.yarn/patches/passport-npm-0.7.0-df02531736.patch", "passport": "patch:passport@npm%3A0.7.0#~/.yarn/patches/passport-npm-0.7.0-df02531736.patch",
"passport-dropbox-oauth2": "1.1.0", "passport-dropbox-oauth2": "1.1.0",
@ -95,7 +96,6 @@
"sanitize-filename": "1.6.3", "sanitize-filename": "1.6.3",
"scrypt-kdf": "2.0.1", "scrypt-kdf": "2.0.1",
"sequelize": "5.22.5", "sequelize": "5.22.5",
"shortid": "2.2.17",
"socket.io": "2.5.1", "socket.io": "2.5.1",
"sqlite3": "5.1.7", "sqlite3": "5.1.7",
"store": "2.0.12", "store": "2.0.12",

View file

@ -2,6 +2,10 @@
## <i class="fa fa-tag"></i> 1.x.x <i class="fa fa-calendar-o"></i> UNRELEASED ## <i class="fa fa-tag"></i> 1.x.x <i class="fa fa-calendar-o"></i> UNRELEASED
### Enhancements
- Switch from deprecated shortid to nanoid module, with 10 character long aliases in "public" links
## <i class="fa fa-tag"></i> 1.10.3 <i class="fa fa-calendar-o"></i> 2025-04-09 ## <i class="fa fa-tag"></i> 1.10.3 <i class="fa fa-calendar-o"></i> 2025-04-09
### Security fixes ### Security fixes

View file

@ -1461,6 +1461,7 @@ __metadata:
moment: "npm:2.30.1" moment: "npm:2.30.1"
morgan: "npm:1.10.0" morgan: "npm:1.10.0"
mysql2: "npm:3.14.0" mysql2: "npm:3.14.0"
nanoid: "npm:3.3.11"
node-fetch: "npm:2.7.0" node-fetch: "npm:2.7.0"
optimize-css-assets-webpack-plugin: "npm:6.0.1" optimize-css-assets-webpack-plugin: "npm:6.0.1"
passport: "patch:passport@npm%3A0.7.0#~/.yarn/patches/passport-npm-0.7.0-df02531736.patch" passport: "patch:passport@npm%3A0.7.0#~/.yarn/patches/passport-npm-0.7.0-df02531736.patch"
@ -1491,7 +1492,6 @@ __metadata:
scrypt-kdf: "npm:2.0.1" scrypt-kdf: "npm:2.0.1"
select2: "npm:3.5.2-browserify" select2: "npm:3.5.2-browserify"
sequelize: "npm:5.22.5" sequelize: "npm:5.22.5"
shortid: "npm:2.2.17"
socket.io: "npm:2.5.1" socket.io: "npm:2.5.1"
socket.io-client: "npm:2.5.0" socket.io-client: "npm:2.5.0"
spin.js: "npm:4.1.2" spin.js: "npm:4.1.2"
@ -11233,7 +11233,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"nanoid@npm:^3.3.8": "nanoid@npm:3.3.11, nanoid@npm:^3.3.8":
version: 3.3.11 version: 3.3.11
resolution: "nanoid@npm:3.3.11" resolution: "nanoid@npm:3.3.11"
bin: bin:
@ -14963,15 +14963,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"shortid@npm:2.2.17":
version: 2.2.17
resolution: "shortid@npm:2.2.17"
dependencies:
nanoid: "npm:^3.3.8"
checksum: 10/5c85635e31c08f8c6824b1802a0abb4cd26b39a5c84498dacc91b865f9a860979b010420423e5a4c0abf966aedf197a664a610e813745a6df1497f1376a72350
languageName: node
linkType: hard
"side-channel-list@npm:^1.0.0": "side-channel-list@npm:^1.0.0":
version: 1.0.0 version: 1.0.0
resolution: "side-channel-list@npm:1.0.0" resolution: "side-channel-list@npm:1.0.0"