mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-15 05:41:34 +00:00
enable log in via either token or through proxy auth
This commit is contained in:
parent
eae72ed29a
commit
49c1b8f106
3 changed files with 108 additions and 28 deletions
|
|
@ -1,8 +1,11 @@
|
||||||
|
const uuidv4 = require("uuid").v4
|
||||||
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 Database = require('./Database')
|
const Database = require('./Database')
|
||||||
|
const User = require('./objects/user/User')
|
||||||
|
|
||||||
class Auth {
|
class Auth {
|
||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
@ -53,16 +56,46 @@ class Auth {
|
||||||
token = authHeader && authHeader.split(' ')[1]
|
token = authHeader && authHeader.split(' ')[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token == null) {
|
let proxyUsername = null
|
||||||
Logger.error('Api called without a token', req.path)
|
if (Database.serverSettings.proxyAuthEnabled) {
|
||||||
|
const uHeader = Database.serverSettings.proxyAuthUsernameHeader.toLowerCase()
|
||||||
|
proxyUsername = uHeader ? req.headers[uHeader] : null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token == null && proxyUsername == null) {
|
||||||
|
Logger.error('Api called without a token and proxy auth is disabled', req.path)
|
||||||
return res.sendStatus(401)
|
return res.sendStatus(401)
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await this.verifyToken(token)
|
let user
|
||||||
if (!user) {
|
if (token) {
|
||||||
Logger.error('Verify Token User Not Found', token)
|
user = await this.verifyToken(token)
|
||||||
return res.sendStatus(404)
|
if (!user) {
|
||||||
|
Logger.error('Verify Token User Not Found', token)
|
||||||
|
return res.sendStatus(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
user.isFromProxy = false
|
||||||
|
} else if (proxyUsername) {
|
||||||
|
const eHeader = Database.serverSettings.proxyAuthEmailHeader.toLowerCase()
|
||||||
|
const proxyEmail = eHeader ? req.headers[eHeader] : null
|
||||||
|
|
||||||
|
user = await this.getProxyUser(proxyUsername, proxyEmail)
|
||||||
|
if (!user) {
|
||||||
|
Logger.error('Cannot get user from proxy headers', proxyUsername)
|
||||||
|
return res.sendStatus(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
user.isFromProxy = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we got here, we should have a valid user in `user`
|
||||||
|
if (!user) {
|
||||||
|
Logger.error('Unknown error getting user')
|
||||||
|
return res.sendStatus(401)
|
||||||
|
}
|
||||||
|
|
||||||
|
// is the user active
|
||||||
if (!user.isActive) {
|
if (!user.isActive) {
|
||||||
Logger.error('Verify Token User is disabled', token, user.username)
|
Logger.error('Verify Token User is disabled', token, user.username)
|
||||||
return res.sendStatus(403)
|
return res.sendStatus(403)
|
||||||
|
|
@ -110,6 +143,49 @@ class Auth {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getProxyUser(username, email) {
|
||||||
|
const user = await Database.userModel.getUserByUsername(username)
|
||||||
|
if (user) {
|
||||||
|
return user
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!email) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const account = {
|
||||||
|
username,
|
||||||
|
email,
|
||||||
|
type: 'user',
|
||||||
|
isActive: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.createUser(account)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create and return a new user from an object with lots of user properties defined
|
||||||
|
async createUser(account) {
|
||||||
|
const username = account.username
|
||||||
|
const usernameExists = await Database.userModel.getUserByUsername(username)
|
||||||
|
if (usernameExists) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
account.id = uuidv4()
|
||||||
|
|
||||||
|
const password = account.password || uuidv4()
|
||||||
|
delete account.password
|
||||||
|
|
||||||
|
account.pash = await this.hashPass(password)
|
||||||
|
|
||||||
|
account.token = await this.generateAccessToken({ userId: account.id, username })
|
||||||
|
account.createdAt = Date.now()
|
||||||
|
const newUser = new User(account)
|
||||||
|
|
||||||
|
const success = await Database.createUser(newUser)
|
||||||
|
return success ? await Database.userModel.getUserById(newUser.id) : null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payload returned to a user after successful login
|
* Payload returned to a user after successful login
|
||||||
* @param {oldUser} user
|
* @param {oldUser} user
|
||||||
|
|
@ -187,8 +263,9 @@ class Auth {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// proxy users can change their password without knowing their old password
|
||||||
const compare = await this.comparePassword(password, matchingUser)
|
const compare = await this.comparePassword(password, matchingUser)
|
||||||
if (!compare) {
|
if (!compare && !req.user.isFromProxy) {
|
||||||
return res.json({
|
return res.json({
|
||||||
error: 'Invalid password'
|
error: 'Invalid password'
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
const uuidv4 = require("uuid").v4
|
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const SocketAuthority = require('../SocketAuthority')
|
const SocketAuthority = require('../SocketAuthority')
|
||||||
const Database = require('../Database')
|
const Database = require('../Database')
|
||||||
|
|
||||||
const User = require('../objects/user/User')
|
|
||||||
|
|
||||||
const { toNumber } = require('../utils/index')
|
const { toNumber } = require('../utils/index')
|
||||||
|
|
||||||
class UserController {
|
class UserController {
|
||||||
|
|
@ -97,15 +94,8 @@ class UserController {
|
||||||
return res.status(500).send('Username already taken')
|
return res.status(500).send('Username already taken')
|
||||||
}
|
}
|
||||||
|
|
||||||
account.id = uuidv4()
|
const newUser = await this.auth.createUser(account)
|
||||||
account.pash = await this.auth.hashPass(account.password)
|
if (newUser) {
|
||||||
delete account.password
|
|
||||||
account.token = await this.auth.generateAccessToken({ userId: account.id, username })
|
|
||||||
account.createdAt = Date.now()
|
|
||||||
const newUser = new User(account)
|
|
||||||
|
|
||||||
const success = await Database.createUser(newUser)
|
|
||||||
if (success) {
|
|
||||||
SocketAuthority.adminEmitter('user_added', newUser.toJSONForBrowser())
|
SocketAuthority.adminEmitter('user_added', newUser.toJSONForBrowser())
|
||||||
res.json({
|
res.json({
|
||||||
user: newUser.toJSONForBrowser()
|
user: newUser.toJSONForBrowser()
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,11 @@ class ServerSettings {
|
||||||
this.timeFormat = 'HH:mm'
|
this.timeFormat = 'HH:mm'
|
||||||
this.language = 'en-us'
|
this.language = 'en-us'
|
||||||
|
|
||||||
|
// Reverse Proxy
|
||||||
|
this.proxyAuthEnabled = false
|
||||||
|
this.proxyAuthUsernameHeader = ''
|
||||||
|
this.proxyAuthEmailHeader = ''
|
||||||
|
|
||||||
this.logLevel = Logger.logLevel
|
this.logLevel = Logger.logLevel
|
||||||
|
|
||||||
this.version = null
|
this.version = null
|
||||||
|
|
@ -94,6 +99,11 @@ class ServerSettings {
|
||||||
this.dateFormat = settings.dateFormat || 'MM/dd/yyyy'
|
this.dateFormat = settings.dateFormat || 'MM/dd/yyyy'
|
||||||
this.timeFormat = settings.timeFormat || 'HH:mm'
|
this.timeFormat = settings.timeFormat || 'HH:mm'
|
||||||
this.language = settings.language || 'en-us'
|
this.language = settings.language || 'en-us'
|
||||||
|
|
||||||
|
this.proxyAuthEnabled = !!settings.proxyAuthEnabled
|
||||||
|
this.proxyAuthUsernameHeader = settings.proxyAuthUsernameHeader || ''
|
||||||
|
this.proxyAuthEmailHeader = settings.proxyAuthEmailHeader || ''
|
||||||
|
|
||||||
this.logLevel = settings.logLevel || Logger.logLevel
|
this.logLevel = settings.logLevel || Logger.logLevel
|
||||||
this.version = settings.version || null
|
this.version = settings.version || null
|
||||||
|
|
||||||
|
|
@ -151,6 +161,9 @@ class ServerSettings {
|
||||||
sortingIgnorePrefix: this.sortingIgnorePrefix,
|
sortingIgnorePrefix: this.sortingIgnorePrefix,
|
||||||
sortingPrefixes: [...this.sortingPrefixes],
|
sortingPrefixes: [...this.sortingPrefixes],
|
||||||
chromecastEnabled: this.chromecastEnabled,
|
chromecastEnabled: this.chromecastEnabled,
|
||||||
|
proxyAuthEnabled: this.proxyAuthEnabled,
|
||||||
|
proxyAuthUsernameHeader: this.proxyAuthUsernameHeader,
|
||||||
|
proxyAuthEmailHeader: this.proxyAuthEmailHeader,
|
||||||
dateFormat: this.dateFormat,
|
dateFormat: this.dateFormat,
|
||||||
timeFormat: this.timeFormat,
|
timeFormat: this.timeFormat,
|
||||||
language: this.language,
|
language: this.language,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue