mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-08-14 13:47:16 +02:00
merged
This commit is contained in:
commit
5a6609150c
@ -1,6 +1,3 @@
|
|||||||
|
|
||||||
import Vue from 'vue'
|
|
||||||
|
|
||||||
const defaultSSOSettings = {
|
const defaultSSOSettings = {
|
||||||
oidc: {
|
oidc: {
|
||||||
issuer: "",
|
issuer: "",
|
||||||
@ -10,7 +7,7 @@ const defaultSSOSettings = {
|
|||||||
clientID: "",
|
clientID: "",
|
||||||
clientSecret: "",
|
clientSecret: "",
|
||||||
callbackURL: "/oidc/callback",
|
callbackURL: "/oidc/callback",
|
||||||
scope: "openid email profile"
|
scope: "openid email profile"
|
||||||
},
|
},
|
||||||
user: {
|
user: {
|
||||||
createNewUser: false,
|
createNewUser: false,
|
||||||
|
12
index.js
12
index.js
@ -13,12 +13,12 @@ if (isDev) {
|
|||||||
process.env.AUDIOBOOK_PATH = devEnv.AudiobookPath
|
process.env.AUDIOBOOK_PATH = devEnv.AudiobookPath
|
||||||
process.env.FFMPEG_PATH = devEnv.FFmpegPath
|
process.env.FFMPEG_PATH = devEnv.FFmpegPath
|
||||||
process.env.FFPROBE_PATH = devEnv.FFProbePath
|
process.env.FFPROBE_PATH = devEnv.FFProbePath
|
||||||
process.env.OIDC_CLIENT_ID = devEnv.OIDC.ClientID
|
process.env.OIDC_CLIENT_ID = devEnv.OIDC ? devEnv.OIDC.ClientID : ''
|
||||||
process.env.OIDC_CLIENT_SECRET = devEnv.OIDC.ClientSecret
|
process.env.OIDC_CLIENT_SECRET = devEnv.OIDC ? devEnv.OIDC.ClientSecret : ''
|
||||||
process.env.OIDC_ISSUER = devEnv.OIDC.Issuer
|
process.env.OIDC_ISSUER = devEnv.OIDC ? devEnv.OIDC.Issuer : ''
|
||||||
process.env.OIDC_AUTHORIZATION_URL = devEnv.OIDC.AuthorizationURL
|
process.env.OIDC_AUTHORIZATION_URL = devEnv.OIDC ? devEnv.OIDC.AuthorizationURL : ''
|
||||||
process.env.OIDC_TOKEN_URL = devEnv.OIDC.TokenURL
|
process.env.OIDC_TOKEN_URL = devEnv.OIDC ? devEnv.OIDC.TokenURL : ''
|
||||||
process.env.OIDC_USER_INFO_URL = devEnv.OIDC.UserInfoURL
|
process.env.OIDC_USER_INFO_URL = devEnv.OIDC ? devEnv.OIDC.UserInfoURL : ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const PORT = process.env.PORT || 80
|
const PORT = process.env.PORT || 80
|
||||||
|
17
njodb.properties
Normal file
17
njodb.properties
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"datadir": "data",
|
||||||
|
"dataname": "data",
|
||||||
|
"datastores": 2,
|
||||||
|
"tempdir": "tmp",
|
||||||
|
"lockoptions": {
|
||||||
|
"stale": 5000,
|
||||||
|
"update": 1000,
|
||||||
|
"retries": {
|
||||||
|
"retries": 5000,
|
||||||
|
"minTimeout": 250,
|
||||||
|
"maxTimeout": 5000,
|
||||||
|
"factor": 0.15,
|
||||||
|
"randomize": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
const bcrypt = require('bcryptjs')
|
const bcrypt = require('bcryptjs')
|
||||||
const jwt = require('jsonwebtoken')
|
const jwt = require('jsonwebtoken')
|
||||||
const passport = require('passport')
|
|
||||||
const Logger = require('./Logger')
|
const Logger = require('./Logger')
|
||||||
|
const User = require('./objects/User')
|
||||||
|
|
||||||
class Auth {
|
class Auth {
|
||||||
constructor(db) {
|
constructor(db) {
|
||||||
@ -52,7 +52,7 @@ class Auth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req.user = user
|
req.user = user
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,5 +213,34 @@ class Auth {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleOIDCVerification(issuer, profile, cb) {
|
||||||
|
Logger.debug(`[Auth] handleOIDCVerification ${issuer}`)
|
||||||
|
|
||||||
|
let user = this.db.users.find(u => u.id === profile.id)
|
||||||
|
if (!user && this.db.SSOSettings.createNewUser) {
|
||||||
|
// create a user
|
||||||
|
let account = {}
|
||||||
|
account.id = profile.id
|
||||||
|
account.username = profile.username
|
||||||
|
account.isActive = true
|
||||||
|
account.type = "guest"
|
||||||
|
account.permissions = this.db.SSOSettings.getNewUserPermissions()
|
||||||
|
account.pash = await this.hashPass(getId(profile.id))
|
||||||
|
account.token = await this.generateAccessToken({ userId: account.id })
|
||||||
|
account.createdAt = Date.now()
|
||||||
|
user = new User(account)
|
||||||
|
const success = await this.db.insertEntity('user', user)
|
||||||
|
if (!success) {
|
||||||
|
cb('Failed to save new user')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!user || !user.isActive) {
|
||||||
|
Logger.debug(`[Auth] Failed login attempt`)
|
||||||
|
cb("Invalid user or password")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cb(null, user)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module.exports = Auth
|
module.exports = Auth
|
17
server/Db.js
17
server/Db.js
@ -31,7 +31,6 @@ class Db {
|
|||||||
this.sessionsDb = new njodb.Database(this.SessionsPath)
|
this.sessionsDb = new njodb.Database(this.SessionsPath)
|
||||||
this.librariesDb = new njodb.Database(this.LibrariesPath, { datastores: 2 })
|
this.librariesDb = new njodb.Database(this.LibrariesPath, { datastores: 2 })
|
||||||
this.settingsDb = new njodb.Database(this.SettingsPath, { datastores: 2 })
|
this.settingsDb = new njodb.Database(this.SettingsPath, { datastores: 2 })
|
||||||
this.SSODb = new njodb.Database(this.SSODb, { datastores: 2 })
|
|
||||||
this.collectionsDb = new njodb.Database(this.CollectionsPath, { datastores: 2 })
|
this.collectionsDb = new njodb.Database(this.CollectionsPath, { datastores: 2 })
|
||||||
this.authorsDb = new njodb.Database(this.AuthorsPath)
|
this.authorsDb = new njodb.Database(this.AuthorsPath)
|
||||||
|
|
||||||
@ -132,6 +131,11 @@ class Db {
|
|||||||
this.serverSettings = new ServerSettings()
|
this.serverSettings = new ServerSettings()
|
||||||
await this.insertEntity('settings', this.serverSettings)
|
await this.insertEntity('settings', this.serverSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.SSOSettings) {
|
||||||
|
this.SSOSettings = new SSOSettings()
|
||||||
|
await this.insertEntity('settings', this.SSOSettings)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async load() {
|
async load() {
|
||||||
@ -150,6 +154,7 @@ class Db {
|
|||||||
let p4 = this.settingsDb.select(() => true).then((results) => {
|
let p4 = this.settingsDb.select(() => true).then((results) => {
|
||||||
if (results.data && results.data.length) {
|
if (results.data && results.data.length) {
|
||||||
this.settings = results.data
|
this.settings = results.data
|
||||||
|
|
||||||
let serverSettings = this.settings.find(s => s.id === 'server-settings')
|
let serverSettings = this.settings.find(s => s.id === 'server-settings')
|
||||||
if (serverSettings) {
|
if (serverSettings) {
|
||||||
this.serverSettings = new ServerSettings(serverSettings)
|
this.serverSettings = new ServerSettings(serverSettings)
|
||||||
@ -159,6 +164,11 @@ class Db {
|
|||||||
this.previousVersion = this.serverSettings.version || '1.0.0'
|
this.previousVersion = this.serverSettings.version || '1.0.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ssoSettings = this.settings.find(s => s.id === 'sso-settings')
|
||||||
|
if (ssoSettings) {
|
||||||
|
this.SSOSettings = new SSOSettings(ssoSettings)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let p5 = this.collectionsDb.select(() => true).then((results) => {
|
let p5 = this.collectionsDb.select(() => true).then((results) => {
|
||||||
@ -169,10 +179,7 @@ class Db {
|
|||||||
this.authors = results.data.map(l => new Author(l))
|
this.authors = results.data.map(l => new Author(l))
|
||||||
Logger.info(`[DB] ${this.authors.length} Authors Loaded`)
|
Logger.info(`[DB] ${this.authors.length} Authors Loaded`)
|
||||||
})
|
})
|
||||||
let p7 = this.SSODb.select(() => true).then((results) => {
|
await Promise.all([p1, p2, p3, p4, p5, p6])
|
||||||
this.SSOSettings = new SSOSettings(results.data)
|
|
||||||
})
|
|
||||||
await Promise.all([p1, p2, p3, p4, p5, p6, p7])
|
|
||||||
|
|
||||||
// Update server version in server settings
|
// Update server version in server settings
|
||||||
if (this.previousVersion) {
|
if (this.previousVersion) {
|
||||||
|
@ -7,8 +7,8 @@ const SocketIO = require('socket.io')
|
|||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const fileUpload = require('express-fileupload')
|
const fileUpload = require('express-fileupload')
|
||||||
const rateLimit = require('express-rate-limit')
|
const rateLimit = require('express-rate-limit')
|
||||||
const passport = require('passport');
|
const passport = require('passport')
|
||||||
const OidcStrategy = require('passport-openidconnect').Strategy;
|
const OidcStrategy = require('passport-openidconnect').Strategy
|
||||||
|
|
||||||
const { version } = require('../package.json')
|
const { version } = require('../package.json')
|
||||||
|
|
||||||
@ -32,7 +32,6 @@ const RssFeeds = require('./RssFeeds')
|
|||||||
const DownloadManager = require('./DownloadManager')
|
const DownloadManager = require('./DownloadManager')
|
||||||
const CoverController = require('./CoverController')
|
const CoverController = require('./CoverController')
|
||||||
const CacheManager = require('./CacheManager')
|
const CacheManager = require('./CacheManager')
|
||||||
const User = require('./objects/User')
|
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
constructor(PORT, UID, GID, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH) {
|
constructor(PORT, UID, GID, CONFIG_PATH, METADATA_PATH, AUDIOBOOK_PATH) {
|
||||||
@ -44,10 +43,6 @@ class Server {
|
|||||||
this.AudiobookPath = Path.normalize(AUDIOBOOK_PATH)
|
this.AudiobookPath = Path.normalize(AUDIOBOOK_PATH)
|
||||||
this.MetadataPath = Path.normalize(METADATA_PATH)
|
this.MetadataPath = Path.normalize(METADATA_PATH)
|
||||||
|
|
||||||
console.info(this.ConfigPath)
|
|
||||||
console.info(this.MetadataPath)
|
|
||||||
console.info(this.AudiobookPath)
|
|
||||||
|
|
||||||
fs.ensureDirSync(CONFIG_PATH, 0o774)
|
fs.ensureDirSync(CONFIG_PATH, 0o774)
|
||||||
fs.ensureDirSync(METADATA_PATH, 0o774)
|
fs.ensureDirSync(METADATA_PATH, 0o774)
|
||||||
fs.ensureDirSync(AUDIOBOOK_PATH, 0o774)
|
fs.ensureDirSync(AUDIOBOOK_PATH, 0o774)
|
||||||
@ -74,55 +69,6 @@ class Server {
|
|||||||
this.io = null
|
this.io = null
|
||||||
|
|
||||||
this.clients = {}
|
this.clients = {}
|
||||||
passport.serializeUser((user, next) => {
|
|
||||||
next(null, {userId: user.id});
|
|
||||||
});
|
|
||||||
|
|
||||||
passport.deserializeUser((obj, next) => {
|
|
||||||
const user = this.db.users.find(u => u.id === obj.userId)
|
|
||||||
next(null, obj);
|
|
||||||
});
|
|
||||||
passport.use(new OidcStrategy({
|
|
||||||
issuer: process.env.OIDC_ISSUER,
|
|
||||||
authorizationURL: process.env.OIDC_AUTHORIZATION_URL,
|
|
||||||
tokenURL: process.env.OIDC_TOKEN_URL,
|
|
||||||
userInfoURL: process.env.OIDC_USER_INFO_URL,
|
|
||||||
clientID: process.env.OIDC_CLIENT_ID,
|
|
||||||
clientSecret: process.env.OIDC_CLIENT_SECRET,
|
|
||||||
callbackURL: '/oidc/callback',
|
|
||||||
scope: "openid email profile"
|
|
||||||
}, async (issuer, profile, cb) => {
|
|
||||||
let user = this.db.users.find(u => u.id === profile.id)
|
|
||||||
if (!user) {
|
|
||||||
// create a user
|
|
||||||
let account = {}
|
|
||||||
account.id = profile.id
|
|
||||||
account.username = profile.username
|
|
||||||
account.type = "guest"
|
|
||||||
account.permissions = {
|
|
||||||
download: false,
|
|
||||||
update: false,
|
|
||||||
delete: false,
|
|
||||||
upload: false,
|
|
||||||
accessAllLibraries: false
|
|
||||||
}
|
|
||||||
account.pash = await this.auth.hashPass(getId(profile.id))
|
|
||||||
account.token = await this.auth.generateAccessToken({ userId: account.id })
|
|
||||||
account.createdAt = Date.now()
|
|
||||||
user = new User(account)
|
|
||||||
const success = await this.db.insertEntity('user', user)
|
|
||||||
if (!success) {
|
|
||||||
cb('Failed to save new user')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!user || !user.isActive) {
|
|
||||||
Logger.debug(`[Auth] Failed login attempt`)
|
|
||||||
cb("Invalid user or password")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cb(null, user)
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get audiobooks() {
|
get audiobooks() {
|
||||||
@ -187,6 +133,26 @@ class Server {
|
|||||||
|
|
||||||
this.watcher.initWatcher(this.libraries)
|
this.watcher.initWatcher(this.libraries)
|
||||||
this.watcher.on('files', this.filesChanged.bind(this))
|
this.watcher.on('files', this.filesChanged.bind(this))
|
||||||
|
|
||||||
|
this.passportInit()
|
||||||
|
}
|
||||||
|
|
||||||
|
passportInit() {
|
||||||
|
if (this.db.SSOSettings.isOIDCConfigured) {
|
||||||
|
Logger.debug(`[Server] passportInit OIDC is configured - init`)
|
||||||
|
|
||||||
|
passport.serializeUser((user, next) => {
|
||||||
|
next(null, user);
|
||||||
|
})
|
||||||
|
passport.deserializeUser((obj, next) => {
|
||||||
|
next(null, obj);
|
||||||
|
})
|
||||||
|
|
||||||
|
// Initialize passport OIDC verification
|
||||||
|
passport.use(new OidcStrategy(this.db.SSOSettings.getOIDCSettings(), this.auth.handleOIDCVerification))
|
||||||
|
} else {
|
||||||
|
Logger.debug(`[Server] passportInit OIDC not configured`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async start() {
|
async start() {
|
||||||
@ -219,7 +185,7 @@ class Server {
|
|||||||
token = authHeader && authHeader.split(' ')[1]
|
token = authHeader && authHeader.split(' ')[1]
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Static path to generated nuxt
|
// Static path to generated nuxt
|
||||||
const distPath = Path.join(global.appRoot, '/client/dist')
|
const distPath = Path.join(global.appRoot, '/client/dist')
|
||||||
app.use(express.static(distPath))
|
app.use(express.static(distPath))
|
||||||
@ -296,10 +262,10 @@ class Server {
|
|||||||
|
|
||||||
app.get("/oidc/login", passport.authenticate('openidconnect'))
|
app.get("/oidc/login", passport.authenticate('openidconnect'))
|
||||||
|
|
||||||
app.get("/oidc/callback",
|
app.get("/oidc/callback",
|
||||||
passport.authenticate('openidconnect', { failureRedirect: '/oidc/login', failureMessage: true }),
|
passport.authenticate('openidconnect', { failureRedirect: '/oidc/login', failureMessage: true }),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const token = this.auth.generateAccessToken({userId: req.user.id})
|
const token = this.auth.generateAccessToken({ userId: req.user.id })
|
||||||
res.cookie('sso', true, { httpOnly: false /* TODO: Set secure: true */ });
|
res.cookie('sso', true, { httpOnly: false /* TODO: Set secure: true */ });
|
||||||
|
|
||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
|
@ -1,68 +1,73 @@
|
|||||||
const { CoverDestination, BookCoverAspectRatio, BookshelfView } = require('../utils/constants')
|
|
||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const User = require('./User')
|
const User = require('./User')
|
||||||
|
const { isObject } = require('../utils')
|
||||||
|
|
||||||
const defaultSettings = {
|
const defaultSettings = {
|
||||||
oidc: {
|
oidc: {
|
||||||
issuer: "",
|
issuer: process.env.OIDC_ISSUER || '',
|
||||||
authorizationURL: "",
|
authorizationURL: process.env.OIDC_AUTHORIZATION_URL || '',
|
||||||
tokenURL: "",
|
tokenURL: process.env.OIDC_TOKEN_URL || '',
|
||||||
userInfoURL: "",
|
userInfoURL: process.env.OIDC_USER_INFO_URL || '',
|
||||||
clientID: "",
|
clientID: process.env.OIDC_CLIENT_ID || '',
|
||||||
clientSecret: "",
|
clientSecret: process.env.OIDC_CLIENT_SECRET || '',
|
||||||
callbackURL: "/oidc/callback",
|
callbackURL: "/oidc/callback",
|
||||||
scope: "openid email profile"
|
scope: "openid email profile"
|
||||||
},
|
},
|
||||||
user: {
|
createNewUser: false,
|
||||||
createNewUser: false,
|
userPermissions: User.getDefaultUserPermissions('guest')
|
||||||
isActive: true,
|
|
||||||
userSettings: {
|
|
||||||
mobileOrderBy: 'recent',
|
|
||||||
mobileOrderDesc: true,
|
|
||||||
mobileFilterBy: 'all',
|
|
||||||
orderBy: 'book.title',
|
|
||||||
orderDesc: false,
|
|
||||||
filterBy: 'all',
|
|
||||||
playbackRate: 1,
|
|
||||||
bookshelfCoverSize: 120,
|
|
||||||
collapseSeries: false
|
|
||||||
},
|
|
||||||
permissions: {
|
|
||||||
download: false,
|
|
||||||
update: false,
|
|
||||||
delete: false,
|
|
||||||
upload: false,
|
|
||||||
accessAllLibraries: false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SSOSettings {
|
class SSOSettings {
|
||||||
constructor(settings=defaultSettings) {
|
constructor(settings = defaultSettings) {
|
||||||
this.id = 'sso-settings'
|
this.id = 'sso-settings'
|
||||||
this.oidc = {...settings.oidc}
|
this.oidc = { ...settings.oidc }
|
||||||
this.user = {...settings.user}
|
this.createNewUser = !!settings.createNewUser
|
||||||
|
this.userPermissions = { ...settings.userPermissions }
|
||||||
|
}
|
||||||
|
|
||||||
|
get isOIDCConfigured() {
|
||||||
|
// Check required OIDC settings are set
|
||||||
|
return !['issue', 'authorizationURL', 'tokenURL', 'clientID', 'clientSecret'].some(key => !this.oidc[key])
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
oidc: {...this.oidc},
|
id: this.id,
|
||||||
user: {...this.user}
|
oidc: { ...this.oidc },
|
||||||
|
createNewUser: this.createNewUser,
|
||||||
|
userPermissions: { ...this.userPermissions }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
update(payload) {
|
update(payload) {
|
||||||
let hasUpdates = false
|
let hasUpdates = false
|
||||||
for (const key in payload) {
|
for (const key in payload) {
|
||||||
for (const setting in payload) {
|
if (isObject(payload[key])) {
|
||||||
if (!this[key] || this[key][setting] === payload[key][setting]) {
|
for (const setting in payload[key]) {
|
||||||
continue
|
if (!this[key] || this[key][setting] === payload[key][setting]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
this[key][setting] = payload[key][setting]
|
||||||
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
this[key][setting] = payload[key][setting]
|
} else if (this[key] !== undefined && this[key] !== payload[key]) {
|
||||||
|
this[key] = payload[key]
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hasUpdates
|
return hasUpdates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNewUserPermissions() {
|
||||||
|
return {
|
||||||
|
...this.userPermissions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getOIDCSettings() {
|
||||||
|
return {
|
||||||
|
...this.oidc
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module.exports = SSOSettings
|
module.exports = SSOSettings
|
@ -46,7 +46,7 @@ class User {
|
|||||||
return !!this.pash && !!this.pash.length
|
return !!this.pash && !!this.pash.length
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultUserSettings() {
|
static getDefaultUserSettings() {
|
||||||
return {
|
return {
|
||||||
mobileOrderBy: 'recent',
|
mobileOrderBy: 'recent',
|
||||||
mobileOrderDesc: true,
|
mobileOrderDesc: true,
|
||||||
@ -60,12 +60,12 @@ class User {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getDefaultUserPermissions() {
|
static getDefaultUserPermissions(type) {
|
||||||
return {
|
return {
|
||||||
download: true,
|
download: type !== 'guest',
|
||||||
update: true,
|
update: type !== 'guest',
|
||||||
delete: this.type === 'root',
|
delete: type === 'root',
|
||||||
upload: this.type === 'root' || this.type === 'admin',
|
upload: type === 'root' || type === 'admin',
|
||||||
accessAllLibraries: true
|
accessAllLibraries: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,8 +152,8 @@ class User {
|
|||||||
this.isLocked = user.type === 'root' ? false : !!user.isLocked
|
this.isLocked = user.type === 'root' ? false : !!user.isLocked
|
||||||
this.lastSeen = user.lastSeen || null
|
this.lastSeen = user.lastSeen || null
|
||||||
this.createdAt = user.createdAt || Date.now()
|
this.createdAt = user.createdAt || Date.now()
|
||||||
this.settings = user.settings || this.getDefaultUserSettings()
|
this.settings = user.settings || User.getDefaultUserSettings()
|
||||||
this.permissions = user.permissions || this.getDefaultUserPermissions()
|
this.permissions = user.permissions || User.getDefaultUserPermissions(this.type)
|
||||||
// Upload permission added v1.1.13, make sure root user has upload permissions
|
// Upload permission added v1.1.13, make sure root user has upload permissions
|
||||||
if (this.type === 'root' && !this.permissions.upload) this.permissions.upload = true
|
if (this.type === 'root' && !this.permissions.upload) this.permissions.upload = true
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user