diff --git a/client/pages/config/sessions.vue b/client/pages/config/sessions.vue
index 86ec7eec6..4341ea07d 100644
--- a/client/pages/config/sessions.vue
+++ b/client/pages/config/sessions.vue
@@ -66,7 +66,11 @@
{{ getPlayMethodName(session.playMethod) }}
-
+
+
+ {{ line }}
+
+
|
{{ $elapsedPrettyLocalized(session.timeListening) }}
@@ -130,7 +134,11 @@
{{ getPlayMethodName(session.playMethod) }}
|
-
+
+
+ {{ line }}
+
+
|
{{ $elapsedPretty(session.timeListening) }}
@@ -172,7 +180,11 @@
{{ getPlayMethodName(session.playMethod) }}
|
-
+
+
+ {{ line }}
+
+
|
{{ $secondsToTimestamp(session.currentTime) }}
@@ -433,16 +445,16 @@ export default {
this.selectedSession = session
this.showSessionModal = true
},
- getDeviceInfoString(deviceInfo) {
- if (!deviceInfo) return ''
- var lines = []
+ getDeviceInfoLines(deviceInfo) {
+ if (!deviceInfo) return []
+ const lines = []
if (deviceInfo.clientName) lines.push(`${deviceInfo.clientName} ${deviceInfo.clientVersion || ''}`)
if (deviceInfo.osName) lines.push(`${deviceInfo.osName} ${deviceInfo.osVersion}`)
if (deviceInfo.browserName) lines.push(deviceInfo.browserName)
if (deviceInfo.manufacturer && deviceInfo.model) lines.push(`${deviceInfo.manufacturer} ${deviceInfo.model}`)
if (deviceInfo.sdkVersion) lines.push(`SDK Version: ${deviceInfo.sdkVersion}`)
- return lines.join(' ')
+ return lines
},
getPlayMethodName(playMethod) {
if (playMethod === this.$constants.PlayMethod.DIRECTPLAY) return 'Direct Play'
diff --git a/client/pages/config/users/_id/sessions.vue b/client/pages/config/users/_id/sessions.vue
index 060f34be8..cb18f5ee3 100644
--- a/client/pages/config/users/_id/sessions.vue
+++ b/client/pages/config/users/_id/sessions.vue
@@ -38,8 +38,12 @@
{{ getPlayMethodName(session.playMethod) }}
|
-
- |
+
+
+
{{ line }}
+
+
+
{{ $elapsedPrettyLocalized(session.timeListening) }}
|
@@ -193,16 +197,16 @@ export default {
this.selectedSession = session
this.showSessionModal = true
},
- getDeviceInfoString(deviceInfo) {
- if (!deviceInfo) return ''
- var lines = []
+ getDeviceInfoLines(deviceInfo) {
+ if (!deviceInfo) return []
+ const lines = []
if (deviceInfo.clientName) lines.push(`${deviceInfo.clientName} ${deviceInfo.clientVersion || ''}`)
if (deviceInfo.osName) lines.push(`${deviceInfo.osName} ${deviceInfo.osVersion}`)
if (deviceInfo.browserName) lines.push(deviceInfo.browserName)
if (deviceInfo.manufacturer && deviceInfo.model) lines.push(`${deviceInfo.manufacturer} ${deviceInfo.model}`)
if (deviceInfo.sdkVersion) lines.push(`SDK Version: ${deviceInfo.sdkVersion}`)
- return lines.join('
')
+ return lines
},
getPlayMethodName(playMethod) {
if (playMethod === this.$constants.PlayMethod.DIRECTPLAY) return 'Direct Play'
diff --git a/server/objects/DeviceInfo.js b/server/objects/DeviceInfo.js
index ceff6c32e..22ebfbea4 100644
--- a/server/objects/DeviceInfo.js
+++ b/server/objects/DeviceInfo.js
@@ -1,6 +1,10 @@
-const uuidv4 = require("uuid").v4
+const uuidv4 = require('uuid').v4
+const { stripAllTags } = require('../utils/htmlSanitizer')
class DeviceInfo {
+ /** @type {string[]} Fields to sanitize when loading from stored data */
+ static stringFields = ['deviceId', 'clientVersion', 'manufacturer', 'model', 'sdkVersion', 'clientName', 'deviceName']
+
constructor(deviceInfo = null) {
this.id = null
this.userId = null
@@ -31,7 +35,7 @@ class DeviceInfo {
construct(deviceInfo) {
for (const key in deviceInfo) {
if (deviceInfo[key] !== undefined && this[key] !== undefined) {
- this[key] = deviceInfo[key]
+ this[key] = DeviceInfo.stringFields.includes(key) ? stripAllTags(deviceInfo[key]) : deviceInfo[key]
}
}
}
@@ -63,7 +67,8 @@ class DeviceInfo {
}
get deviceDescription() {
- if (this.model) { // Set from mobile apps
+ if (this.model) {
+ // Set from mobile apps
if (this.sdkVersion) return `${this.model} SDK ${this.sdkVersion} / v${this.clientVersion}`
return `${this.model} / v${this.clientVersion}`
}
@@ -72,18 +77,7 @@ class DeviceInfo {
// When client doesn't send a device id
getTempDeviceId() {
- const keys = [
- this.userId,
- this.browserName,
- this.browserVersion,
- this.osName,
- this.osVersion,
- this.clientVersion,
- this.manufacturer,
- this.model,
- this.sdkVersion,
- this.ipAddress
- ].map(k => k || '')
+ const keys = [this.userId, this.browserName, this.browserVersion, this.osName, this.osVersion, this.clientVersion, this.manufacturer, this.model, this.sdkVersion, this.ipAddress].map((k) => k || '')
return 'temp-' + Buffer.from(keys.join('-'), 'utf-8').toString('base64')
}
@@ -99,12 +93,12 @@ class DeviceInfo {
this.osVersion = ua?.os.version || null
this.deviceType = ua?.device.type || null
- this.clientVersion = clientDeviceInfo?.clientVersion || serverVersion
- this.manufacturer = clientDeviceInfo?.manufacturer || null
- this.model = clientDeviceInfo?.model || null
- this.sdkVersion = clientDeviceInfo?.sdkVersion || null
+ this.clientVersion = stripAllTags(clientDeviceInfo?.clientVersion) || serverVersion
+ this.manufacturer = stripAllTags(clientDeviceInfo?.manufacturer) || null
+ this.model = stripAllTags(clientDeviceInfo?.model) || null
+ this.sdkVersion = stripAllTags(clientDeviceInfo?.sdkVersion) || null
- this.clientName = clientDeviceInfo?.clientName || null
+ this.clientName = stripAllTags(clientDeviceInfo?.clientName) || null
if (this.sdkVersion) {
if (!this.clientName) this.clientName = 'Abs Android'
this.deviceName = `${this.manufacturer || 'Unknown'} ${this.model || ''}`
@@ -149,4 +143,4 @@ class DeviceInfo {
return hasUpdates
}
}
-module.exports = DeviceInfo
\ No newline at end of file
+module.exports = DeviceInfo
diff --git a/server/objects/settings/ServerSettings.js b/server/objects/settings/ServerSettings.js
index a03e17c75..99f5b76aa 100644
--- a/server/objects/settings/ServerSettings.js
+++ b/server/objects/settings/ServerSettings.js
@@ -3,6 +3,7 @@ const packageJson = require('../../../package.json')
const { BookshelfView } = require('../../utils/constants')
const Logger = require('../../Logger')
const User = require('../../models/User')
+const { sanitize } = require('../../utils/htmlSanitizer')
class ServerSettings {
constructor(settings) {
@@ -126,7 +127,7 @@ class ServerSettings {
this.version = settings.version || null
this.buildNumber = settings.buildNumber || 0 // Added v2.4.5
- this.authLoginCustomMessage = settings.authLoginCustomMessage || null // Added v2.8.0
+ this.authLoginCustomMessage = sanitize(settings.authLoginCustomMessage) || null // Added v2.8.0
this.authActiveAuthMethods = settings.authActiveAuthMethods || ['local']
this.authOpenIDIssuerURL = settings.authOpenIDIssuerURL || null
@@ -309,7 +310,7 @@ class ServerSettings {
get authFormData() {
const clientFormData = {
- authLoginCustomMessage: this.authLoginCustomMessage
+ authLoginCustomMessage: sanitize(this.authLoginCustomMessage)
}
if (this.authActiveAuthMethods.includes('openid')) {
clientFormData.authOpenIDButtonText = this.authOpenIDButtonText
@@ -327,6 +328,9 @@ class ServerSettings {
update(payload) {
let hasUpdates = false
for (const key in payload) {
+ if (key === 'authLoginCustomMessage') {
+ payload[key] = sanitize(payload[key])
+ }
if (key === 'sortingPrefixes') {
// Sorting prefixes are updated with the /api/sorting-prefixes endpoint
continue
diff --git a/server/utils/htmlSanitizer.js b/server/utils/htmlSanitizer.js
index 4ed30e727..be839b7c2 100644
--- a/server/utils/htmlSanitizer.js
+++ b/server/utils/htmlSanitizer.js
@@ -5,11 +5,10 @@ const { entities } = require('./htmlEntities')
*
* @param {string} html
* @returns {string}
- * @throws {Error} if input is not a string
*/
function sanitize(html) {
if (typeof html !== 'string') {
- throw new Error('sanitizeHtml: input must be a string')
+ return ''
}
const sanitizerOptions = {
@@ -27,6 +26,8 @@ function sanitize(html) {
module.exports.sanitize = sanitize
function stripAllTags(html, shouldDecodeEntities = true) {
+ if (typeof html !== 'string') return ''
+
const sanitizerOptions = {
allowedTags: [],
disallowedTagsMode: 'discard'