mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-04-25 01:16:40 +02:00
Updated + first rough implementation
This commit is contained in:
parent
f0f03efe17
commit
405c954b65
@ -37,6 +37,15 @@
|
|||||||
<ui-btn type="submit" :disabled="processing" color="primary" class="leading-none">{{ processing ? 'Checking...' : $strings.ButtonSubmit }}</ui-btn>
|
<ui-btn type="submit" :disabled="processing" color="primary" class="leading-none">{{ processing ? 'Checking...' : $strings.ButtonSubmit }}</ui-btn>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<hr />
|
||||||
|
<div class="w-full flex py-3">
|
||||||
|
<a href="http://localhost:3333/auth/google">
|
||||||
|
<ui-btn color="primary" class="leading-none">Login with Google</ui-btn>
|
||||||
|
</a>
|
||||||
|
<a href="http://localhost:3333/auth/openid">
|
||||||
|
<ui-btn color="primary" class="leading-none">Login with OpenId</ui-btn>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -132,11 +141,7 @@ export default {
|
|||||||
|
|
||||||
location.reload()
|
location.reload()
|
||||||
},
|
},
|
||||||
<<<<<<< HEAD
|
|
||||||
setUser({ user, userDefaultLibraryId, serverSettings, Source }) {
|
|
||||||
=======
|
|
||||||
setUser({ user, userDefaultLibraryId, serverSettings, Source, ereaderDevices }) {
|
setUser({ user, userDefaultLibraryId, serverSettings, Source, ereaderDevices }) {
|
||||||
>>>>>>> origin/master
|
|
||||||
this.$store.commit('setServerSettings', serverSettings)
|
this.$store.commit('setServerSettings', serverSettings)
|
||||||
this.$store.commit('setSource', Source)
|
this.$store.commit('setSource', Source)
|
||||||
this.$store.commit('libraries/setEReaderDevices', ereaderDevices)
|
this.$store.commit('libraries/setEReaderDevices', ereaderDevices)
|
||||||
@ -166,10 +171,7 @@ export default {
|
|||||||
else this.error = 'Unknown Error'
|
else this.error = 'Unknown Error'
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
<<<<<<< HEAD
|
|
||||||
console.log('Auth res', authRes)
|
console.log('Auth res', authRes)
|
||||||
=======
|
|
||||||
>>>>>>> origin/master
|
|
||||||
if (authRes?.error) {
|
if (authRes?.error) {
|
||||||
this.error = authRes.error
|
this.error = authRes.error
|
||||||
} else if (authRes) {
|
} else if (authRes) {
|
||||||
@ -222,6 +224,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
|
console.log(new URLSearchParams(window.location.search).get('setToken'))
|
||||||
|
if (new URLSearchParams(window.location.search).get('setToken')) {
|
||||||
|
localStorage.setItem('token', new URLSearchParams(window.location.search).get('setToken'))
|
||||||
|
console.log('hereasd')
|
||||||
|
}
|
||||||
if (localStorage.getItem('token')) {
|
if (localStorage.getItem('token')) {
|
||||||
var userfound = await this.checkAuth()
|
var 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
|
||||||
|
@ -6,14 +6,14 @@ const JwtStrategy = require('passport-jwt').Strategy
|
|||||||
const ExtractJwt = require('passport-jwt').ExtractJwt
|
const ExtractJwt = require('passport-jwt').ExtractJwt
|
||||||
const GoogleStrategy = require('passport-google-oauth20').Strategy
|
const GoogleStrategy = require('passport-google-oauth20').Strategy
|
||||||
const OpenIDConnectStrategy = require('passport-openidconnect')
|
const OpenIDConnectStrategy = require('passport-openidconnect')
|
||||||
|
const Database = require('./Database')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Class for handling all the authentication related functionality.
|
* @class Class for handling all the authentication related functionality.
|
||||||
*/
|
*/
|
||||||
class Auth {
|
class Auth {
|
||||||
|
|
||||||
constructor(db) {
|
constructor() {
|
||||||
this.db = db
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,10 +31,10 @@ class Auth {
|
|||||||
clientID: global.ServerSettings.authGoogleOauth20ClientID,
|
clientID: global.ServerSettings.authGoogleOauth20ClientID,
|
||||||
clientSecret: global.ServerSettings.authGoogleOauth20ClientSecret,
|
clientSecret: global.ServerSettings.authGoogleOauth20ClientSecret,
|
||||||
callbackURL: global.ServerSettings.authGoogleOauth20CallbackURL
|
callbackURL: global.ServerSettings.authGoogleOauth20CallbackURL
|
||||||
}, (function (accessToken, refreshToken, profile, done) {
|
}, (async function (accessToken, refreshToken, profile, done) {
|
||||||
// TODO: what to use as username
|
// TODO: what to use as username
|
||||||
// TODO: do we want to create the users which does not exist?
|
// TODO: do we want to create the users which does not exist?
|
||||||
const user = this.db.users.find(u => u.username.toLowerCase() === profile.emails[0].value.toLowerCase())
|
const user = await Database.userModel.getUserByEmail(profile.emails[0].value.toLowerCase())
|
||||||
|
|
||||||
if (!user || !user.isActive) {
|
if (!user || !user.isActive) {
|
||||||
done(null, null)
|
done(null, null)
|
||||||
@ -61,7 +61,7 @@ class Auth {
|
|||||||
(function (issuer, profile, done) {
|
(function (issuer, profile, done) {
|
||||||
// TODO: what to use as username
|
// TODO: what to use as username
|
||||||
// TODO: do we want to create the users which does not exist?
|
// TODO: do we want to create the users which does not exist?
|
||||||
var user = this.db.users.find(u => u.username.toLowerCase() === profile.emails[0].value.toLowerCase())
|
var user = Database.userModel.getUserByEmail(profile.emails[0].value.toLowerCase())
|
||||||
|
|
||||||
if (!user || !user.isActive) {
|
if (!user || !user.isActive) {
|
||||||
done(null, null)
|
done(null, null)
|
||||||
@ -86,16 +86,17 @@ class Auth {
|
|||||||
return cb(null, JSON.stringify({
|
return cb(null, JSON.stringify({
|
||||||
"username": user.username,
|
"username": user.username,
|
||||||
"id": user.id,
|
"id": user.id,
|
||||||
|
"email": user.email,
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// define how to deseralize a user (use the username to get it from the database)
|
// define how to deseralize a user (use the username to get it from the database)
|
||||||
passport.deserializeUser((function (user, cb) {
|
passport.deserializeUser((function (user, cb) {
|
||||||
process.nextTick((function () {
|
process.nextTick((async function () {
|
||||||
const parsedUserInfo = JSON.parse(user)
|
const parsedUserInfo = JSON.parse(user)
|
||||||
// TODO: do the matching on username or better on id?
|
// TODO: do the matching on username or better on id?
|
||||||
const dbUser = this.db.users.find(u => u.username.toLowerCase() === parsedUserInfo.username.toLowerCase())
|
const dbUser = await Database.userModel.getUserByUsername(parsedUserInfo.username.toLowerCase())
|
||||||
return cb(null, dbUser)
|
return cb(null, dbUser)
|
||||||
}).bind(this))
|
}).bind(this))
|
||||||
}).bind(this))
|
}).bind(this))
|
||||||
@ -108,9 +109,9 @@ class Auth {
|
|||||||
initAuthRoutes(router) {
|
initAuthRoutes(router) {
|
||||||
// Local strategy login route (takes username and password)
|
// Local strategy login route (takes username and password)
|
||||||
router.post('/login', passport.authenticate('local'),
|
router.post('/login', passport.authenticate('local'),
|
||||||
(function (req, res) {
|
(async function (req, res) {
|
||||||
// return the user login response json if the login was successfull
|
// return the user login response json if the login was successfull
|
||||||
res.json(this.getUserLoginResponsePayload(req.user))
|
res.json(await this.getUserLoginResponsePayload(req.user))
|
||||||
}).bind(this)
|
}).bind(this)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -120,9 +121,12 @@ class Auth {
|
|||||||
// google-oauth20 strategy callback route (this receives the token from google)
|
// google-oauth20 strategy callback route (this receives the token from google)
|
||||||
router.get('/auth/google/callback',
|
router.get('/auth/google/callback',
|
||||||
passport.authenticate('google'),
|
passport.authenticate('google'),
|
||||||
(function (req, res) {
|
(async function (req, res) {
|
||||||
// return the user login response json if the login was successfull
|
// return the user login response json if the login was successfull
|
||||||
res.json(this.getUserLoginResponsePayload(req.user))
|
var data_json = await this.getUserLoginResponsePayload(req.user)
|
||||||
|
// res.json(data_json)
|
||||||
|
// TODO: figure out how to redirect back to the app page
|
||||||
|
res.redirect(301, `http://localhost:3000/login?setToken=${data_json.user.token}`)
|
||||||
}).bind(this)
|
}).bind(this)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -132,9 +136,12 @@ class Auth {
|
|||||||
// openid strategy callback route (this receives the token from the configured openid login provider)
|
// openid strategy callback route (this receives the token from the configured openid login provider)
|
||||||
router.get('/auth/openid/callback',
|
router.get('/auth/openid/callback',
|
||||||
passport.authenticate('openidconnect'),
|
passport.authenticate('openidconnect'),
|
||||||
(function (req, res) {
|
(async function (req, res) {
|
||||||
// return the user login response json if the login was successfull
|
// return the user login response json if the login was successfull
|
||||||
res.json(this.getUserLoginResponsePayload(req.user))
|
var data_json = await this.getUserLoginResponsePayload(req.user)
|
||||||
|
// res.json(data_json)
|
||||||
|
// TODO: figure out how to redirect back to the app page
|
||||||
|
res.redirect(301, `http://localhost:3000/login?setToken=${data_json.user.token}`)
|
||||||
}).bind(this)
|
}).bind(this)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -176,6 +183,20 @@ class Auth {
|
|||||||
return jwt.sign({ userId: user.id, username: user.username }, global.ServerSettings.tokenSecret)
|
return jwt.sign({ userId: user.id, username: user.username }, global.ServerSettings.tokenSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to generate a jwt token for a given user.
|
||||||
|
* @param {string} token
|
||||||
|
* @returns the tokens data.
|
||||||
|
*/
|
||||||
|
static validateAccessToken(token) {
|
||||||
|
try {
|
||||||
|
return jwt.verify(token, global.ServerSettings.tokenSecret)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a token for each user.
|
* Generate a token for each user.
|
||||||
*/
|
*/
|
||||||
@ -203,7 +224,7 @@ class Auth {
|
|||||||
* @param {function} done
|
* @param {function} done
|
||||||
*/
|
*/
|
||||||
jwtAuthCheck(jwt_payload, done) {
|
jwtAuthCheck(jwt_payload, done) {
|
||||||
const user = this.db.users.find(u => u.username.toLowerCase() === jwt_payload.username.toLowerCase())
|
const user = Database.userModel.getUserByUsername(jwt_payload.username.toLowerCase())
|
||||||
|
|
||||||
if (!user || !user.isActive) {
|
if (!user || !user.isActive) {
|
||||||
done(null, null)
|
done(null, null)
|
||||||
@ -220,7 +241,7 @@ class Auth {
|
|||||||
* @param {function} done
|
* @param {function} done
|
||||||
*/
|
*/
|
||||||
async localAuthCheckUserPw(username, password, done) {
|
async localAuthCheckUserPw(username, password, done) {
|
||||||
const user = this.db.users.find(u => u.username.toLowerCase() === username.toLowerCase())
|
const user = Database.userModel.getUserByUsername(username.toLowerCase())
|
||||||
|
|
||||||
if (!user || !user.isActive) {
|
if (!user || !user.isActive) {
|
||||||
done(null, null)
|
done(null, null)
|
||||||
@ -269,7 +290,8 @@ class Auth {
|
|||||||
* @param {string} username
|
* @param {string} username
|
||||||
* @returns {string} jsonPayload
|
* @returns {string} jsonPayload
|
||||||
*/
|
*/
|
||||||
getUserLoginResponsePayload(user) {
|
async getUserLoginResponsePayload(user) {
|
||||||
|
const libraryIds = await Database.libraryModel.getAllLibraryIds()
|
||||||
return {
|
return {
|
||||||
user: user.toJSONForBrowser(),
|
user: user.toJSONForBrowser(),
|
||||||
userDefaultLibraryId: user.getDefaultLibraryId(libraryIds),
|
userDefaultLibraryId: user.getDefaultLibraryId(libraryIds),
|
||||||
|
@ -161,7 +161,8 @@ class Server {
|
|||||||
|
|
||||||
this.server = http.createServer(app)
|
this.server = http.createServer(app)
|
||||||
|
|
||||||
router.use(this.auth.cors)
|
|
||||||
|
|
||||||
router.use(fileUpload({
|
router.use(fileUpload({
|
||||||
defCharset: 'utf8',
|
defCharset: 'utf8',
|
||||||
defParamCharset: 'utf8',
|
defParamCharset: 'utf8',
|
||||||
@ -195,6 +196,9 @@ class Server {
|
|||||||
this.rssFeedManager.getFeedItem(req, res)
|
this.rssFeedManager.getFeedItem(req, res)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Auth routes
|
||||||
|
this.auth.initAuthRoutes(router)
|
||||||
|
|
||||||
// Client dynamic routes
|
// Client dynamic routes
|
||||||
const dyanimicRoutes = [
|
const dyanimicRoutes = [
|
||||||
'/item/:id',
|
'/item/:id',
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
const SocketIO = require('socket.io')
|
const SocketIO = require('socket.io')
|
||||||
const Logger = require('./Logger')
|
const Logger = require('./Logger')
|
||||||
const Database = require('./Database')
|
const Database = require('./Database')
|
||||||
|
const Auth = require('./Auth')
|
||||||
|
const passport = require('passport')
|
||||||
|
const expressSession = require('express-session')
|
||||||
|
|
||||||
class SocketAuthority {
|
class SocketAuthority {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -81,6 +84,24 @@ class SocketAuthority {
|
|||||||
methods: ["GET", "POST"]
|
methods: ["GET", "POST"]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/*
|
||||||
|
const wrap = middleware => (socket, next) => middleware(socket.request, {}, next);
|
||||||
|
|
||||||
|
io.use(wrap(expressSession({
|
||||||
|
secret: global.ServerSettings.tokenSecret,
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: false,
|
||||||
|
cookie: {
|
||||||
|
// also send the cookie if were hare not on https
|
||||||
|
secure: false
|
||||||
|
},
|
||||||
|
})));
|
||||||
|
|
||||||
|
io.use(wrap(passport.initialize()));
|
||||||
|
io.use(wrap(passport.session()));
|
||||||
|
*/
|
||||||
|
|
||||||
this.io.on('connection', (socket) => {
|
this.io.on('connection', (socket) => {
|
||||||
this.clients[socket.id] = {
|
this.clients[socket.id] = {
|
||||||
id: socket.id,
|
id: socket.id,
|
||||||
@ -147,7 +168,13 @@ class SocketAuthority {
|
|||||||
// When setting up a socket connection the user needs to be associated with a socket id
|
// When setting up a socket connection the user needs to be associated with a socket id
|
||||||
// for this the client will send a 'auth' event that includes the users API token
|
// for this the client will send a 'auth' event that includes the users API token
|
||||||
async authenticateSocket(socket, token) {
|
async authenticateSocket(socket, token) {
|
||||||
const user = await this.Server.db.users.find(u => u.token === token)
|
// TODO
|
||||||
|
const token_data = Auth.validateAccessToken(token)
|
||||||
|
if (!token_data || !token_data.username) {
|
||||||
|
Logger.error('Cannot validate socket - invalid token')
|
||||||
|
return socket.emit('invalid_token')
|
||||||
|
}
|
||||||
|
const user = await Database.userModel.getUserByUsername(token_data.username)
|
||||||
if (!user) {
|
if (!user) {
|
||||||
Logger.error('Cannot validate socket - invalid token')
|
Logger.error('Cannot validate socket - invalid token')
|
||||||
return socket.emit('invalid_token')
|
return socket.emit('invalid_token')
|
||||||
|
@ -194,6 +194,25 @@ class User extends Model {
|
|||||||
return this.getOldUser(user)
|
return this.getOldUser(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user by email case insensitive
|
||||||
|
* @param {string} username
|
||||||
|
* @returns {Promise<oldUser|null>} returns null if not found
|
||||||
|
*/
|
||||||
|
static async getUserByEmail(email) {
|
||||||
|
if (!email) return null
|
||||||
|
const user = await this.findOne({
|
||||||
|
where: {
|
||||||
|
email: {
|
||||||
|
[Op.like]: email
|
||||||
|
}
|
||||||
|
},
|
||||||
|
include: this.sequelize.models.mediaProgress
|
||||||
|
})
|
||||||
|
if (!user) return null
|
||||||
|
return this.getOldUser(user)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user by id
|
* Get user by id
|
||||||
* @param {string} userId
|
* @param {string} userId
|
||||||
|
Loading…
Reference in New Issue
Block a user