@@ -3,6 +3,8 @@ const vsprintf = require('./format')
3
3
const debug = require ( 'debug' ) ( 'minecraft-protocol' )
4
4
const nbt = require ( 'prismarine-nbt' )
5
5
const getValueSafely = ( obj , key , def ) => Object . hasOwn ( obj , key ) ? obj [ key ] : def
6
+ const MAX_CHAT_DEPTH = 8
7
+ const MAX_CHAT_LENGTH = 4096
6
8
7
9
function loader ( registryOrVersion ) {
8
10
const registry = typeof registryOrVersion === 'string' ? require ( 'prismarine-registry' ) ( registryOrVersion ) : registryOrVersion
@@ -296,27 +298,29 @@ function loader (registryOrVersion) {
296
298
* Flattens the message in to plain-text
297
299
* @return {String }
298
300
*/
299
- toString ( lang = defaultLang ) {
301
+ toString ( lang = defaultLang , _depth = 0 ) {
302
+ if ( _depth > MAX_CHAT_DEPTH ) return ''
300
303
let message = ''
301
304
if ( typeof this . text === 'string' || typeof this . text === 'number' ) message += this . text
302
305
else if ( this . translate !== undefined ) {
303
306
const _with = this . with ?? [ ]
304
307
305
- const args = _with . map ( entry => entry . toString ( lang ) )
308
+ const args = _with . map ( entry => entry . toString ( lang , _depth + 1 ) )
306
309
const format = getValueSafely ( lang , this . translate , this . translate )
307
310
message += vsprintf ( format , args )
308
311
}
309
312
if ( this . extra ) {
310
- message += this . extra . map ( ( entry ) => entry . toString ( lang ) ) . join ( '' )
313
+ message += this . extra . map ( ( entry ) => entry . toString ( lang , _depth + 1 ) ) . join ( '' )
311
314
}
312
- return message . replace ( / § [ 0 - 9 a - f l n m o k r ] / g, '' )
315
+ return message . replace ( / § [ 0 - 9 a - f l n m o k r ] / g, '' ) . slice ( 0 , MAX_CHAT_LENGTH )
313
316
}
314
317
315
318
valueOf ( ) {
316
319
return this . toString ( )
317
320
}
318
321
319
- toMotd ( lang = defaultLang , parent = { } ) {
322
+ toMotd ( lang = defaultLang , parent = { } , _depth = 0 ) {
323
+ if ( _depth > MAX_CHAT_DEPTH ) return ''
320
324
const codes = {
321
325
color : {
322
326
black : '§0' ,
@@ -360,16 +364,16 @@ function loader (registryOrVersion) {
360
364
const _with = this . with ?? [ ]
361
365
362
366
const args = _with . map ( entry => {
363
- const entryAsMotd = entry . toMotd ( lang , this )
367
+ const entryAsMotd = entry . toMotd ( lang , this , _depth + 1 )
364
368
return entryAsMotd + ( entryAsMotd . includes ( '§' ) ? '§r' + message : '' )
365
369
} )
366
370
const format = getValueSafely ( lang , this . translate , this . translate )
367
371
message += vsprintf ( format , args )
368
372
}
369
373
if ( this . extra ) {
370
- message += this . extra . map ( entry => entry . toMotd ( lang , this ) ) . join ( '' )
374
+ message += this . extra . map ( entry => entry . toMotd ( lang , this , _depth + 1 ) ) . join ( '' )
371
375
}
372
- return message
376
+ return message . slice ( 0 , MAX_CHAT_LENGTH )
373
377
}
374
378
375
379
toAnsi ( lang = defaultLang , codes = defaultAnsiCodes ) {
@@ -388,11 +392,12 @@ function loader (registryOrVersion) {
388
392
// ANSI from https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#rgb-colors
389
393
message = message . replace ( hexRegex , `\u001b[38;2;${ red } ;${ green } ;${ blue } m` )
390
394
}
391
- return codes [ '§r' ] + message + codes [ '§r' ]
395
+ return codes [ '§r' ] + message . slice ( 0 , MAX_CHAT_LENGTH ) + codes [ '§r' ]
392
396
}
393
397
394
398
// NOTE : Have to be be mindful here as bad HTML gen may lead to arbitrary code execution from server
395
- toHTML ( lang = registry . language , styles = cssDefaultStyles , allowedFormats = formatMembers ) {
399
+ toHTML ( lang = registry . language , styles = cssDefaultStyles , allowedFormats = formatMembers , _depth = 0 ) {
400
+ if ( _depth > MAX_CHAT_DEPTH ) return ''
396
401
let str = ''
397
402
if ( allowedFormats . some ( member => this [ member ] ) ) {
398
403
const cssProps = allowedFormats . reduce ( ( acc , cur ) => this [ cur ]
@@ -412,18 +417,21 @@ function loader (registryOrVersion) {
412
417
const params = [ ]
413
418
if ( this . with ) {
414
419
for ( const param of this . with ) {
415
- params . push ( param . toHTML ( lang , styles , allowedFormats ) )
420
+ params . push ( param . toHTML ( lang , styles , allowedFormats , _depth + 1 ) )
416
421
}
417
422
}
418
423
const format = getValueSafely ( lang , this . translate , this . translate )
419
424
str += vsprintf ( escapeHtml ( format ) , params )
420
425
}
421
426
422
427
if ( this . extra ) {
423
- str += this . extra . map ( entry => entry . toHTML ( lang , styles , allowedFormats ) ) . join ( '' )
428
+ str += this . extra . map ( entry => entry . toHTML ( lang , styles , allowedFormats , _depth + 1 ) ) . join ( '' )
424
429
}
425
430
str += '</span>'
426
- return str
431
+ // It's not safe to truncate HTML so just return unformatted text
432
+ return str > MAX_CHAT_LENGTH
433
+ ? escapeHtml ( this . toString ( ) )
434
+ : str
427
435
}
428
436
429
437
static fromNotch ( msg ) {
0 commit comments