mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-27 03:31:46 +00:00
Forward Auth refactor and adding PROXY_FORWARD_AUTH_LOGOUT_URI env
This commit is contained in:
parent
8558baf30a
commit
73a61872fa
9 changed files with 139 additions and 68 deletions
|
|
@ -75,9 +75,8 @@ export default {
|
||||||
this.$setLanguageCode(lang)
|
this.$setLanguageCode(lang)
|
||||||
},
|
},
|
||||||
logout() {
|
logout() {
|
||||||
var rootSocket = this.$root.socket || {}
|
|
||||||
const logoutPayload = {
|
const logoutPayload = {
|
||||||
socketId: rootSocket.id
|
socketId: (this.$root.socket || {}).id
|
||||||
}
|
}
|
||||||
this.$axios.$post('/logout', logoutPayload).catch((error) => {
|
this.$axios.$post('/logout', logoutPayload).catch((error) => {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
|
|
@ -87,7 +86,13 @@ export default {
|
||||||
}
|
}
|
||||||
this.$store.commit('libraries/setUserPlaylists', [])
|
this.$store.commit('libraries/setUserPlaylists', [])
|
||||||
this.$store.commit('libraries/setCollections', [])
|
this.$store.commit('libraries/setCollections', [])
|
||||||
|
|
||||||
|
if (this.$store.getters['user/getForwardAuthLogoutURI']) {
|
||||||
|
// Redirect to forward auth logout uri
|
||||||
|
location.replace(this.$store.getters['user/getForwardAuthLogoutURI'])
|
||||||
|
} else {
|
||||||
this.$router.push('/login')
|
this.$router.push('/login')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
resetForm() {
|
resetForm() {
|
||||||
this.password = null
|
this.password = null
|
||||||
|
|
|
||||||
|
|
@ -144,20 +144,20 @@ export default {
|
||||||
* Checks for forward proxy authentication
|
* Checks for forward proxy authentication
|
||||||
*/
|
*/
|
||||||
async checkForwardAuth() {
|
async checkForwardAuth() {
|
||||||
this.processing = true;
|
this.processing = true
|
||||||
this.error = null;
|
this.error = null
|
||||||
|
|
||||||
var authRes = await this.$axios.$post('/forwardauth').catch((error) => {
|
var authRes = await this.$axios.$post('/forwardauth').catch((error) => {
|
||||||
console.error('Failed', error.response)
|
console.error('Failed', error.response)
|
||||||
if (error.response) this.error = error.response.data
|
if (error.response) this.error = error.response.data
|
||||||
else this.error = 'Unknown Error'
|
else this.error = 'Unknown Error'
|
||||||
return false
|
return false
|
||||||
});
|
})
|
||||||
|
|
||||||
if (authRes && authRes.disabled) {
|
if (authRes && authRes.disabled) {
|
||||||
// disabled == true - proxy auth has not been configured on the server, nothing further to do.
|
// disabled == true - proxy auth has not been configured on the server, nothing further to do.
|
||||||
this.processing = false;
|
this.processing = false
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authRes && authRes.error) {
|
if (authRes && authRes.error) {
|
||||||
|
|
@ -166,17 +166,16 @@ export default {
|
||||||
this.setUser(authRes)
|
this.setUser(authRes)
|
||||||
}
|
}
|
||||||
this.processing = false
|
this.processing = false
|
||||||
|
|
||||||
},
|
},
|
||||||
async submitForm() {
|
async submitForm() {
|
||||||
this.error = null
|
this.error = null
|
||||||
this.processing = true
|
this.processing = true
|
||||||
|
|
||||||
var payload = {
|
const payload = {
|
||||||
username: this.username,
|
username: this.username,
|
||||||
password: this.password || ''
|
password: this.password || ''
|
||||||
}
|
}
|
||||||
var authRes = await this.$axios.$post('/login', payload).catch((error) => {
|
const authRes = await this.$axios.$post('/login', payload).catch((error) => {
|
||||||
console.error('Failed', error.response)
|
console.error('Failed', error.response)
|
||||||
if (error.response) this.error = error.response.data
|
if (error.response) this.error = error.response.data
|
||||||
else this.error = 'Unknown Error'
|
else this.error = 'Unknown Error'
|
||||||
|
|
@ -190,7 +189,7 @@ export default {
|
||||||
this.processing = false
|
this.processing = false
|
||||||
},
|
},
|
||||||
checkAuth() {
|
checkAuth() {
|
||||||
var token = localStorage.getItem('token')
|
const token = localStorage.getItem('token')
|
||||||
if (!token) return false
|
if (!token) return false
|
||||||
|
|
||||||
this.processing = true
|
this.processing = true
|
||||||
|
|
@ -203,43 +202,44 @@ export default {
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.setUser(res)
|
this.setUser(res)
|
||||||
this.processing = false
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Authorize error', error)
|
console.error('Authorize error', error)
|
||||||
this.processing = false
|
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.processing = false
|
||||||
|
})
|
||||||
},
|
},
|
||||||
checkStatus() {
|
checkStatus() {
|
||||||
this.processing = true
|
this.processing = true
|
||||||
this.$axios
|
this.$axios
|
||||||
.$get('/status')
|
.$get('/status')
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.processing = false
|
|
||||||
this.isInit = res.isInit
|
this.isInit = res.isInit
|
||||||
this.showInitScreen = !res.isInit
|
this.showInitScreen = !res.isInit
|
||||||
this.$setServerLanguageCode(res.language)
|
this.$setServerLanguageCode(res.language)
|
||||||
if (this.showInitScreen) {
|
if (this.showInitScreen) {
|
||||||
this.ConfigPath = res.ConfigPath || ''
|
this.ConfigPath = res.ConfigPath || ''
|
||||||
this.MetadataPath = res.MetadataPath || ''
|
this.MetadataPath = res.MetadataPath || ''
|
||||||
|
} else if (res.forwardAuthUserResponse) {
|
||||||
|
// User was returned from forward auth
|
||||||
|
this.setUser(res.forwardAuthUserResponse)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Status check failed', error)
|
console.error('Status check failed', error)
|
||||||
this.processing = false
|
|
||||||
this.criticalError = 'Status check failed'
|
this.criticalError = 'Status check failed'
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.processing = false
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
|
||||||
// Check for proxy auth
|
|
||||||
this.checkForwardAuth();
|
|
||||||
|
|
||||||
if (localStorage.getItem('token')) {
|
if (localStorage.getItem('token')) {
|
||||||
var userfound = await this.checkAuth()
|
const userfound = await this.checkAuth()
|
||||||
if (userfound) return // if valid user no need to check status
|
if (userfound) return // if valid user no need to check status
|
||||||
}
|
}
|
||||||
this.checkStatus()
|
this.checkStatus()
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@ export const state = () => ({
|
||||||
export const getters = {
|
export const getters = {
|
||||||
getIsRoot: (state) => state.user && state.user.type === 'root',
|
getIsRoot: (state) => state.user && state.user.type === 'root',
|
||||||
getIsAdminOrUp: (state) => state.user && (state.user.type === 'admin' || state.user.type === 'root'),
|
getIsAdminOrUp: (state) => state.user && (state.user.type === 'admin' || state.user.type === 'root'),
|
||||||
|
getIsForwardAuth: (state) => state.user && state.user.isForwardAuth,
|
||||||
|
getForwardAuthLogoutURI: (state) => state.user ? state.user.forwardAuthLogoutURI : null,
|
||||||
getToken: (state) => {
|
getToken: (state) => {
|
||||||
return state.user ? state.user.token : null
|
return state.user ? state.user.token : null
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -261,13 +261,16 @@ Middleware relating to CORS will cause the app to report Unknown Error when logg
|
||||||
From [@Dondochaka](https://discord.com/channels/942908292873723984/942914154254176257/945074590374318170) and [@BeastleeUK](https://discord.com/channels/942908292873723984/942914154254176257/970366039294611506)
|
From [@Dondochaka](https://discord.com/channels/942908292873723984/942914154254176257/945074590374318170) and [@BeastleeUK](https://discord.com/channels/942908292873723984/942914154254176257/970366039294611506)
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|
||||||
### Forward Proxy Authentication
|
### Forward Proxy Authentication
|
||||||
|
|
||||||
Users can be authenticated via an external proxy such as Authentik.
|
Users can be authenticated via an external proxy such as Authentik.
|
||||||
To use forward authentication you need to set the following environment variables:
|
To use forward authentication you need to set the following environment variables:
|
||||||
|
|
||||||
* `PROXY_FORWARD_AUTH_ENABLED` - enable/disable forward authentication
|
* `PROXY_FORWARD_AUTH_ENABLED` - enable/disable forward authentication
|
||||||
* `PROXY_FORWARD_AUTH_USERNAME` - the name of the header containing the authenticated user's username. For example, by default in Authentik the value would be `X-authentik-username`.
|
* `PROXY_FORWARD_AUTH_USERNAME` - the name of the header containing the authenticated user's username. For example, by default in Authentik the value would be `X-authentik-username`.
|
||||||
* `PROXY_FORWARD_AUTH_CREATE` - automatically create users if they don't exist.
|
* `PROXY_FORWARD_AUTH_CREATE` - automatically create users if they don't exist (with account type of `user`).
|
||||||
|
* `PROXY_FORWARD_AUTH_LOGOUT_URI` - path to redirect to when logging out.
|
||||||
|
|
||||||
# Run from source
|
# Run from source
|
||||||
|
|
||||||
|
|
|
||||||
110
server/Auth.js
110
server/Auth.js
|
|
@ -1,10 +1,12 @@
|
||||||
const bcrypt = require('./libs/bcryptjs')
|
const bcrypt = require('./libs/bcryptjs')
|
||||||
const jwt = require('./libs/jsonwebtoken')
|
const jwt = require('./libs/jsonwebtoken')
|
||||||
const requestIp = require('./libs/requestIp')
|
const requestIp = require('./libs/requestIp')
|
||||||
|
|
||||||
const Logger = require('./Logger')
|
const Logger = require('./Logger')
|
||||||
|
const SocketAuthority = require('./SocketAuthority')
|
||||||
|
|
||||||
const User = require('./objects/user/User')
|
const User = require('./objects/user/User')
|
||||||
const { getId } = require('./utils/index')
|
const { getId } = require('./utils/index')
|
||||||
const { parseBool } = require('./utils/parseBool')
|
|
||||||
|
|
||||||
class Auth {
|
class Auth {
|
||||||
constructor(db) {
|
constructor(db) {
|
||||||
|
|
@ -97,6 +99,10 @@ class Auth {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generateRandomPasswordHash() {
|
||||||
|
return hashPass(getId())
|
||||||
|
}
|
||||||
|
|
||||||
generateAccessToken(payload) {
|
generateAccessToken(payload) {
|
||||||
return jwt.sign(payload, global.ServerSettings.tokenSecret);
|
return jwt.sign(payload, global.ServerSettings.tokenSecret);
|
||||||
}
|
}
|
||||||
|
|
@ -180,59 +186,83 @@ class Auth {
|
||||||
* Checks for an environment variable of PROXY_FORWARD_AUTH_ENABLED and if enabled
|
* Checks for an environment variable of PROXY_FORWARD_AUTH_ENABLED and if enabled
|
||||||
* will authenticate the user from the proxy headers.
|
* will authenticate the user from the proxy headers.
|
||||||
* @param {*} req
|
* @param {*} req
|
||||||
* @param {*} res
|
* @param {Array} feeds
|
||||||
* @param {*} feeds
|
* @returns {Promise<(Object|false)>} User login response payload or false
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
async getUserFromProxyAuth(req, res, feeds) {
|
async getUserFromProxyAuth(req, feeds) {
|
||||||
var username = null;
|
if (!global.ForwardAuth.Enabled) {
|
||||||
var user = null;
|
return false
|
||||||
|
|
||||||
// Check if $PROXY_FORWARD_AUTH_ENABLED is defined
|
|
||||||
if (!parseBool(process.env.PROXY_FORWARD_AUTH_ENABLED)) {
|
|
||||||
Logger.debug("$PROXY_FORWARD_AUTH_ENABLED not set.");
|
|
||||||
// Respond with disabled: true - client will check for it and ignore forward auth
|
|
||||||
return res.json({ disabled: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the proxy username header is set
|
let username = req.headers[global.ForwardAuth.UsernameHeader]
|
||||||
if (!process.env.PROXY_FORWARD_AUTH_USERNAME) {
|
|
||||||
Logger.info("$PROXY_FORWARD_AUTH_ENABLED is set, but $PROXY_FORWARD_AUTH_USERNAME has not been defined. Forward Authentication will not proceed.");
|
if (!username) {
|
||||||
return res.json({ disabled: true });
|
Logger.warn(`[Auth] Forward Auth username header ${global.ForwardAuth.UsernameHeader} has no username`)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.debug('Found $PROXY_FORWARD_AUTH_USERNAME header:', process.env.PROXY_FORWARD_AUTH_USERNAME);
|
let user = this.users.find(u => u.username.toLowerCase() === username)
|
||||||
username = req.headers[process.env.PROXY_FORWARD_AUTH_USERNAME.toLowerCase()];
|
|
||||||
Logger.debug('Found Forwarded Username ', username);
|
|
||||||
|
|
||||||
if (!username)
|
|
||||||
return res.status(401).send(`Username not found in headers (Header: ${process.env.PROXY_FORWARD_AUTH_USERNAME}`);
|
|
||||||
|
|
||||||
var user = this.users.find(u => u.username.toLowerCase() === username)
|
|
||||||
|
|
||||||
// If the user doesn't exist and PROXY_FORWARD AUTH_CREATE is enabled, create the user
|
// If the user doesn't exist and PROXY_FORWARD AUTH_CREATE is enabled, create the user
|
||||||
if (!user && parseBool(process.env.PROXY_FORWARD_AUTH_CREATE)) {
|
if (!user && global.ForwardAuth.CreateUser) {
|
||||||
Logger.debug('User not found, creating user', username);
|
Logger.debug(`[Auth] Forward Auth User not found with username "${username}" - creating it`)
|
||||||
// TODO - user type:
|
|
||||||
// this could come from the proxy (eg a user attribute), or could be configurable from an environment variable
|
const newUserData = {
|
||||||
var account = {
|
|
||||||
id: getId('usr'),
|
id: getId('usr'),
|
||||||
username: username,
|
username,
|
||||||
|
pash: this.generateRandomPasswordHash(), // Random password will need to be reset by admin if wanting to use regular login
|
||||||
createdAt: Date.now(),
|
createdAt: Date.now(),
|
||||||
type: 'user'
|
type: 'user'
|
||||||
};
|
}
|
||||||
account.token = await this.generateAccessToken({ userId: account.id, username: account.username });
|
newUserData.token = await this.generateAccessToken({ userId: newUserData.id, username: newUserData.username })
|
||||||
user = new User(account);
|
|
||||||
var success = await this.db.insertEntity('user', user);
|
user = new User(newUserData)
|
||||||
if (!success)
|
|
||||||
return res.status(500).send("Could not create user.");
|
const success = await this.db.insertEntity('user', user)
|
||||||
|
if (!success) {
|
||||||
|
Logger.error(`[Auth] Forward Auth failed to insert new user in DB`, user.toJSON())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
SocketAuthority.adminEmitter('user_added', user)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user)
|
if (!user) {
|
||||||
return res.status(401).send(`User "${username}" not found`);
|
Logger.error(`[Auth] Forward Auth user not found with username "${username}"`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
return res.json(this.getUserLoginResponsePayload(user, feeds))
|
user.isForwardAuth = true
|
||||||
|
|
||||||
|
Logger.debug(`[Auth] Forward Auth success for username "${username}"`)
|
||||||
|
return this.getUserLoginResponsePayload(user, feeds)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the user in req.user is valid with forward auth headers.
|
||||||
|
* @param {*} req
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
validateForwardAuthUser(req) {
|
||||||
|
if (!global.ForwardAuth.Enabled) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let username = req.headers[global.ForwardAuth.UsernameHeader]
|
||||||
|
|
||||||
|
if (!username) {
|
||||||
|
Logger.error(`[Auth] validate: Forward Auth username header ${global.ForwardAuth.UsernameHeader} has no username`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mismatch username in header with username from token
|
||||||
|
if (req.user.username.toLowerCase() !== username) {
|
||||||
|
Logger.error(`[Auth] validate: Forward Auth username "${username}" from header ${global.ForwardAuth.UsernameHeader} does not match username "${req.user.username.toLowerCase()}" from token`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user.isForwardAuth = true
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
comparePassword(password, user) {
|
comparePassword(password, user) {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ const { version } = require('../package.json')
|
||||||
// Utils
|
// Utils
|
||||||
const dbMigration = require('./utils/dbMigration')
|
const dbMigration = require('./utils/dbMigration')
|
||||||
const filePerms = require('./utils/filePerms')
|
const filePerms = require('./utils/filePerms')
|
||||||
|
const { parseBool } = require('./utils/parseBool')
|
||||||
const Logger = require('./Logger')
|
const Logger = require('./Logger')
|
||||||
|
|
||||||
const Auth = require('./Auth')
|
const Auth = require('./Auth')
|
||||||
|
|
@ -45,6 +46,12 @@ class Server {
|
||||||
global.ConfigPath = Path.normalize(CONFIG_PATH)
|
global.ConfigPath = Path.normalize(CONFIG_PATH)
|
||||||
global.MetadataPath = Path.normalize(METADATA_PATH)
|
global.MetadataPath = Path.normalize(METADATA_PATH)
|
||||||
global.RouterBasePath = ROUTER_BASE_PATH
|
global.RouterBasePath = ROUTER_BASE_PATH
|
||||||
|
global.ForwardAuth = {
|
||||||
|
Enabled: parseBool(process.env.PROXY_FORWARD_AUTH_ENABLED) && process.env.PROXY_FORWARD_AUTH_USERNAME,
|
||||||
|
UsernameHeader: (process.env.PROXY_FORWARD_AUTH_USERNAME || '').toLowerCase(),
|
||||||
|
CreateUser: parseBool(process.env.PROXY_FORWARD_AUTH_CREATE),
|
||||||
|
LogoutURI: process.env.PROXY_FORWARD_AUTH_LOGOUT_URI
|
||||||
|
}
|
||||||
|
|
||||||
// Fix backslash if not on Windows
|
// Fix backslash if not on Windows
|
||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32') {
|
||||||
|
|
@ -221,7 +228,7 @@ class Server {
|
||||||
}
|
}
|
||||||
this.initializeServer(req, res)
|
this.initializeServer(req, res)
|
||||||
})
|
})
|
||||||
router.get('/status', (req, res) => {
|
router.get('/status', async (req, res) => {
|
||||||
// status check for client to see if server has been initialized
|
// status check for client to see if server has been initialized
|
||||||
// server has been initialized if a root user exists
|
// server has been initialized if a root user exists
|
||||||
const payload = {
|
const payload = {
|
||||||
|
|
@ -231,7 +238,14 @@ class Server {
|
||||||
if (!payload.isInit) {
|
if (!payload.isInit) {
|
||||||
payload.ConfigPath = global.ConfigPath
|
payload.ConfigPath = global.ConfigPath
|
||||||
payload.MetadataPath = global.MetadataPath
|
payload.MetadataPath = global.MetadataPath
|
||||||
|
return res.json(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check forward auth for user
|
||||||
|
if (global.ForwardAuth.Enabled) {
|
||||||
|
payload.forwardAuthUserResponse = await this.auth.getUserFromProxyAuth(req, this.rssFeedManager.feedsArray)
|
||||||
|
}
|
||||||
|
|
||||||
res.json(payload)
|
res.json(payload)
|
||||||
})
|
})
|
||||||
router.get('/ping', (req, res) => {
|
router.get('/ping', (req, res) => {
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,13 @@ class MiscController {
|
||||||
Logger.error('Invalid user in authorize')
|
Logger.error('Invalid user in authorize')
|
||||||
return res.sendStatus(401)
|
return res.sendStatus(401)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When authorizing an API token and forward auth is enabled then validate user using forward auth headers
|
||||||
|
if (global.ForwardAuth.Enabled && !this.auth.validateForwardAuthUser(req)) {
|
||||||
|
Logger.error(`[MiscController] Authorize token with forward auth enabled failed for user "${req.user.username}"`)
|
||||||
|
return res.sendStatus(403)
|
||||||
|
}
|
||||||
|
|
||||||
const userResponse = this.auth.getUserLoginResponsePayload(req.user, this.rssFeedManager.feedsArray)
|
const userResponse = this.auth.getUserLoginResponsePayload(req.user, this.rssFeedManager.feedsArray)
|
||||||
res.json(userResponse)
|
res.json(userResponse)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,9 @@ class User {
|
||||||
this.librariesAccessible = [] // Library IDs (Empty if ALL libraries)
|
this.librariesAccessible = [] // Library IDs (Empty if ALL libraries)
|
||||||
this.itemTagsAccessible = [] // Empty if ALL item tags accessible
|
this.itemTagsAccessible = [] // Empty if ALL item tags accessible
|
||||||
|
|
||||||
|
// Temporary values not persisted to the Db
|
||||||
|
this.isForwardAuth = false
|
||||||
|
|
||||||
if (user) {
|
if (user) {
|
||||||
this.construct(user)
|
this.construct(user)
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +105,7 @@ class User {
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSONForBrowser() {
|
toJSONForBrowser() {
|
||||||
return {
|
const json = {
|
||||||
id: this.id,
|
id: this.id,
|
||||||
username: this.username,
|
username: this.username,
|
||||||
type: this.type,
|
type: this.type,
|
||||||
|
|
@ -117,8 +120,15 @@ class User {
|
||||||
settings: this.settings, // TODO: Remove after mobile release v0.9.61-beta
|
settings: this.settings, // TODO: Remove after mobile release v0.9.61-beta
|
||||||
permissions: this.permissions,
|
permissions: this.permissions,
|
||||||
librariesAccessible: [...this.librariesAccessible],
|
librariesAccessible: [...this.librariesAccessible],
|
||||||
itemTagsAccessible: [...this.itemTagsAccessible]
|
itemTagsAccessible: [...this.itemTagsAccessible],
|
||||||
|
isForwardAuth: this.isForwardAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.isForwardAuth) {
|
||||||
|
json.forwardAuthLogoutURI = global.ForwardAuth.LogoutURI || null
|
||||||
|
}
|
||||||
|
|
||||||
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data broadcasted
|
// Data broadcasted
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
const true_values = ["true", "yes", "y", "1", "on"];
|
const true_values = ["true", "yes", "y", "1", "on"]
|
||||||
|
|
||||||
module.exports.parseBool = (value) => {
|
module.exports.parseBool = (value) => {
|
||||||
if (Object.is(value, null) || value === undefined) {
|
if (Object.is(value, null) || value === undefined) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
return true_values.includes(String(value).toLowerCase());
|
return true_values.includes(String(value).toLowerCase())
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue