mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-07 18:01:42 +00:00
fix: harden browse cursor validation
This commit is contained in:
parent
36170d0fcb
commit
f24bd19cb7
2 changed files with 33 additions and 2 deletions
|
|
@ -2,14 +2,26 @@ function encodeBrowseCursor(payload) {
|
|||
return Buffer.from(JSON.stringify(payload)).toString('base64url')
|
||||
}
|
||||
|
||||
function invalidBrowseCursor() {
|
||||
return new Error('Invalid browse cursor')
|
||||
}
|
||||
|
||||
function decodeBrowseCursor(cursor) {
|
||||
const decoded = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'))
|
||||
let decoded
|
||||
|
||||
try {
|
||||
decoded = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'))
|
||||
} catch (error) {
|
||||
throw invalidBrowseCursor()
|
||||
}
|
||||
|
||||
if (!Array.isArray(decoded.keys) || !Array.isArray(decoded.values) || decoded.keys.length !== decoded.values.length) {
|
||||
throw new Error('Cursor is missing the full ordered key set')
|
||||
}
|
||||
|
||||
if (!decoded.keys.length || decoded.keys[decoded.keys.length - 1] !== 'id') {
|
||||
const tieBreakerIndex = decoded.keys.length - 1
|
||||
|
||||
if (!decoded.keys.length || decoded.keys[tieBreakerIndex] !== 'id' || decoded.values[tieBreakerIndex] == null || decoded.values[tieBreakerIndex] === '') {
|
||||
throw new Error('Cursor is missing the tie-breaker value')
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,4 +40,23 @@ describe('libraryBrowseCursor', () => {
|
|||
values: ['Dune']
|
||||
}))).to.throw('tie-breaker')
|
||||
})
|
||||
|
||||
it('rejects a cursor when the id tie-breaker value is null', () => {
|
||||
expect(() => decodeBrowseCursor(encodeBrowseCursor({
|
||||
sortBy: 'media.metadata.title',
|
||||
desc: false,
|
||||
keys: ['titleIgnorePrefix', 'id'],
|
||||
values: ['Dune', null]
|
||||
}))).to.throw('tie-breaker')
|
||||
})
|
||||
|
||||
it('rejects a malformed cursor string with a controlled invalid-cursor error', () => {
|
||||
expect(() => decodeBrowseCursor('%%%not-base64%%%')).to.throw('Invalid browse cursor')
|
||||
})
|
||||
|
||||
it('rejects malformed cursor json with a controlled invalid-cursor error', () => {
|
||||
const malformedJsonCursor = Buffer.from('{"sortBy":', 'utf8').toString('base64url')
|
||||
|
||||
expect(() => decodeBrowseCursor(malformedJsonCursor)).to.throw('Invalid browse cursor')
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue