diff --git a/client/pages/login.vue b/client/pages/login.vue
index 52feedb6..27bdc63b 100644
--- a/client/pages/login.vue
+++ b/client/pages/login.vue
@@ -37,6 +37,15 @@
{{ processing ? 'Checking...' : $strings.ButtonSubmit }}
+
+
@@ -132,11 +141,7 @@ export default {
location.reload()
},
-<<<<<<< HEAD
- setUser({ user, userDefaultLibraryId, serverSettings, Source }) {
-=======
setUser({ user, userDefaultLibraryId, serverSettings, Source, ereaderDevices }) {
->>>>>>> origin/master
this.$store.commit('setServerSettings', serverSettings)
this.$store.commit('setSource', Source)
this.$store.commit('libraries/setEReaderDevices', ereaderDevices)
@@ -166,10 +171,7 @@ export default {
else this.error = 'Unknown Error'
return false
})
-<<<<<<< HEAD
console.log('Auth res', authRes)
-=======
->>>>>>> origin/master
if (authRes?.error) {
this.error = authRes.error
} else if (authRes) {
@@ -222,6 +224,11 @@ export default {
}
},
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')) {
var userfound = await this.checkAuth()
if (userfound) return // if valid user no need to check status
diff --git a/server/Auth.js b/server/Auth.js
index 0885c88a..ceeddb36 100644
--- a/server/Auth.js
+++ b/server/Auth.js
@@ -6,14 +6,14 @@ const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt
const GoogleStrategy = require('passport-google-oauth20').Strategy
const OpenIDConnectStrategy = require('passport-openidconnect')
+const Database = require('./Database')
/**
* @class Class for handling all the authentication related functionality.
*/
class Auth {
- constructor(db) {
- this.db = db
+ constructor() {
}
/**
@@ -31,10 +31,10 @@ class Auth {
clientID: global.ServerSettings.authGoogleOauth20ClientID,
clientSecret: global.ServerSettings.authGoogleOauth20ClientSecret,
callbackURL: global.ServerSettings.authGoogleOauth20CallbackURL
- }, (function (accessToken, refreshToken, profile, done) {
+ }, (async function (accessToken, refreshToken, profile, done) {
// TODO: what to use as username
// 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) {
done(null, null)
@@ -61,7 +61,7 @@ class Auth {
(function (issuer, profile, done) {
// TODO: what to use as username
// 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) {
done(null, null)
@@ -86,16 +86,17 @@ class Auth {
return cb(null, JSON.stringify({
"username": user.username,
"id": user.id,
+ "email": user.email,
}))
})
})
// define how to deseralize a user (use the username to get it from the database)
passport.deserializeUser((function (user, cb) {
- process.nextTick((function () {
+ process.nextTick((async function () {
const parsedUserInfo = JSON.parse(user)
// 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)
}).bind(this))
}).bind(this))
@@ -108,9 +109,9 @@ class Auth {
initAuthRoutes(router) {
// Local strategy login route (takes username and password)
router.post('/login', passport.authenticate('local'),
- (function (req, res) {
+ (async function (req, res) {
// 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)
)
@@ -120,9 +121,12 @@ class Auth {
// google-oauth20 strategy callback route (this receives the token from google)
router.get('/auth/google/callback',
passport.authenticate('google'),
- (function (req, res) {
+ (async function (req, res) {
// 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)
)
@@ -132,9 +136,12 @@ class Auth {
// openid strategy callback route (this receives the token from the configured openid login provider)
router.get('/auth/openid/callback',
passport.authenticate('openidconnect'),
- (function (req, res) {
+ (async function (req, res) {
// 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)
)
@@ -176,6 +183,20 @@ class Auth {
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.
*/
@@ -203,7 +224,7 @@ class Auth {
* @param {function} 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) {
done(null, null)
@@ -220,7 +241,7 @@ class Auth {
* @param {function} 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) {
done(null, null)
@@ -269,7 +290,8 @@ class Auth {
* @param {string} username
* @returns {string} jsonPayload
*/
- getUserLoginResponsePayload(user) {
+ async getUserLoginResponsePayload(user) {
+ const libraryIds = await Database.libraryModel.getAllLibraryIds()
return {
user: user.toJSONForBrowser(),
userDefaultLibraryId: user.getDefaultLibraryId(libraryIds),
diff --git a/server/Server.js b/server/Server.js
index 9156c021..89985768 100644
--- a/server/Server.js
+++ b/server/Server.js
@@ -161,7 +161,8 @@ class Server {
this.server = http.createServer(app)
- router.use(this.auth.cors)
+
+
router.use(fileUpload({
defCharset: 'utf8',
defParamCharset: 'utf8',
@@ -195,6 +196,9 @@ class Server {
this.rssFeedManager.getFeedItem(req, res)
})
+ // Auth routes
+ this.auth.initAuthRoutes(router)
+
// Client dynamic routes
const dyanimicRoutes = [
'/item/:id',
diff --git a/server/SocketAuthority.js b/server/SocketAuthority.js
index 5c3c8715..81136ecf 100644
--- a/server/SocketAuthority.js
+++ b/server/SocketAuthority.js
@@ -1,6 +1,9 @@
const SocketIO = require('socket.io')
const Logger = require('./Logger')
const Database = require('./Database')
+const Auth = require('./Auth')
+const passport = require('passport')
+const expressSession = require('express-session')
class SocketAuthority {
constructor() {
@@ -81,6 +84,24 @@ class SocketAuthority {
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.clients[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
// for this the client will send a 'auth' event that includes the users API 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) {
Logger.error('Cannot validate socket - invalid token')
return socket.emit('invalid_token')
diff --git a/server/models/User.js b/server/models/User.js
index 6f457aa5..5e184fc7 100644
--- a/server/models/User.js
+++ b/server/models/User.js
@@ -194,6 +194,25 @@ class User extends Model {
return this.getOldUser(user)
}
+ /**
+ * Get user by email case insensitive
+ * @param {string} username
+ * @returns {Promise} 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
* @param {string} userId