mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Update JWT auth extractors, add state in openid redirect, add back cors for api router
This commit is contained in:
		
							parent
							
								
									e282142d3f
								
							
						
					
					
						commit
						0d5a30b214
					
				| @ -16,6 +16,18 @@ class Auth { | ||||
|   constructor() { | ||||
|   } | ||||
| 
 | ||||
|   static cors(req, res, next) { | ||||
|     res.header('Access-Control-Allow-Origin', '*') | ||||
|     res.header("Access-Control-Allow-Methods", 'GET, POST, PATCH, PUT, DELETE, OPTIONS') | ||||
|     res.header('Access-Control-Allow-Headers', '*') | ||||
|     res.header('Access-Control-Allow-Credentials', true) | ||||
|     if (req.method === 'OPTIONS') { | ||||
|       res.sendStatus(200) | ||||
|     } else { | ||||
|       next() | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Inializes all passportjs strategies and other passportjs ralated initialization. | ||||
|    */ | ||||
| @ -78,7 +90,7 @@ class Auth { | ||||
| 
 | ||||
|     // Load the JwtStrategy (always) -> for bearer token auth 
 | ||||
|     passport.use(new JwtStrategy({ | ||||
|       jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), | ||||
|       jwtFromRequest: ExtractJwt.fromExtractors([ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('token')]), | ||||
|       secretOrKey: Database.serverSettings.tokenSecret | ||||
|     }, this.jwtAuthCheck.bind(this))) | ||||
| 
 | ||||
| @ -123,15 +135,25 @@ class Auth { | ||||
|         httpOnly: true | ||||
|       }) | ||||
| 
 | ||||
|       // persist state if passed in
 | ||||
|       if (req.query.state) { | ||||
|         res.cookie('auth_state', req.query.state, { | ||||
|           maxAge: 120000, // 2 min
 | ||||
|           httpOnly: true | ||||
|         }) | ||||
|       } | ||||
| 
 | ||||
|       const callback = req.query.redirect_uri || req.query.callback | ||||
| 
 | ||||
|       // check if we are missing a callback parameter - we need one if isRest=false
 | ||||
|       if (!req.query.callback) { | ||||
|       if (!callback) { | ||||
|         res.status(400).send({ | ||||
|           message: 'No callback parameter' | ||||
|         }) | ||||
|         return | ||||
|       } | ||||
|       // store the callback url to the auth_cb cookie 
 | ||||
|       res.cookie('auth_cb', req.query.callback, { | ||||
|       res.cookie('auth_cb', callback, { | ||||
|         maxAge: 120000, // 2 min
 | ||||
|         httpOnly: true | ||||
|       }) | ||||
| @ -155,9 +177,10 @@ class Auth { | ||||
|     } else { | ||||
|       // UI request -> check if we have a callback url
 | ||||
|       // TODO: do we want to somehow limit the values for auth_cb?
 | ||||
|       if (req.cookies.auth_cb?.startsWith('http')) { | ||||
|       if (req.cookies.auth_cb) { | ||||
|         let stateQuery = req.cookies.auth_state ? `&state=${req.cookies.auth_state}` : '' | ||||
|         // UI request -> redirect to auth_cb url and send the jwt token as parameter
 | ||||
|         res.redirect(302, `${req.cookies.auth_cb}?setToken=${data_json.user.token}`) | ||||
|         res.redirect(302, `${req.cookies.auth_cb}?setToken=${data_json.user.token}${stateQuery}`) | ||||
|       } else { | ||||
|         res.status(400).send('No callback or already expired') | ||||
|       } | ||||
| @ -201,10 +224,9 @@ class Auth { | ||||
| 
 | ||||
|     // openid strategy callback route (this receives the token from the configured openid login provider)
 | ||||
|     router.get('/auth/openid/callback', | ||||
|       passport.authenticate('openidconnect', { failureRedirect: '/login', failureMessage: true }), | ||||
|       passport.authenticate('openidconnect'), | ||||
|       // on a successfull login: read the cookies and react like the client requested (callback or json)
 | ||||
|       this.handleLoginSuccessBasedOnCookie.bind(this) | ||||
|     ) | ||||
|       this.handleLoginSuccessBasedOnCookie.bind(this)) | ||||
| 
 | ||||
|     // Logout route
 | ||||
|     router.post('/logout', (req, res) => { | ||||
| @ -288,9 +310,9 @@ class Auth { | ||||
|    */ | ||||
|   async jwtAuthCheck(jwt_payload, done) { | ||||
|     // load user by id from the jwt token
 | ||||
|     const user = await Database.userModel.getUserById(jwt_payload.id) | ||||
|     const user = await Database.userModel.getUserByIdOrOldId(jwt_payload.userId) | ||||
| 
 | ||||
|     if (!user || !user.isActive) { | ||||
|     if (!user?.isActive) { | ||||
|       // deny login
 | ||||
|       done(null, null) | ||||
|       return | ||||
|  | ||||
| @ -180,7 +180,7 @@ class Server { | ||||
|     router.use(express.static(Path.join(global.appRoot, 'static'))) | ||||
| 
 | ||||
|     // router.use('/api/v1', routes) // TODO: New routes
 | ||||
|     router.use('/api', this.authMiddleware.bind(this), this.apiRouter.router) | ||||
|     router.use('/api', Auth.cors, this.authMiddleware.bind(this), this.apiRouter.router) | ||||
|     router.use('/hls', this.authMiddleware.bind(this), this.hlsRouter.router) | ||||
| 
 | ||||
|     // RSS Feed temp route
 | ||||
|  | ||||
| @ -6,7 +6,7 @@ class SessionController { | ||||
|   constructor() { } | ||||
| 
 | ||||
|   async findOne(req, res) { | ||||
|     return res.json(req.session) | ||||
|     return res.json(req.playbackSession) | ||||
|   } | ||||
| 
 | ||||
|   async getAllWithUserData(req, res) { | ||||
| @ -63,32 +63,32 @@ class SessionController { | ||||
|   } | ||||
| 
 | ||||
|   async getOpenSession(req, res) { | ||||
|     const libraryItem = await Database.libraryItemModel.getOldById(req.session.libraryItemId) | ||||
|     const sessionForClient = req.session.toJSONForClient(libraryItem) | ||||
|     const libraryItem = await Database.libraryItemModel.getOldById(req.playbackSession.libraryItemId) | ||||
|     const sessionForClient = req.playbackSession.toJSONForClient(libraryItem) | ||||
|     res.json(sessionForClient) | ||||
|   } | ||||
| 
 | ||||
|   // POST: api/session/:id/sync
 | ||||
|   sync(req, res) { | ||||
|     this.playbackSessionManager.syncSessionRequest(req.user, req.session, req.body, res) | ||||
|     this.playbackSessionManager.syncSessionRequest(req.user, req.playbackSession, req.body, res) | ||||
|   } | ||||
| 
 | ||||
|   // POST: api/session/:id/close
 | ||||
|   close(req, res) { | ||||
|     let syncData = req.body | ||||
|     if (syncData && !Object.keys(syncData).length) syncData = null | ||||
|     this.playbackSessionManager.closeSessionRequest(req.user, req.session, syncData, res) | ||||
|     this.playbackSessionManager.closeSessionRequest(req.user, req.playbackSession, syncData, res) | ||||
|   } | ||||
| 
 | ||||
|   // DELETE: api/session/:id
 | ||||
|   async delete(req, res) { | ||||
|     // if session is open then remove it
 | ||||
|     const openSession = this.playbackSessionManager.getSession(req.session.id) | ||||
|     const openSession = this.playbackSessionManager.getSession(req.playbackSession.id) | ||||
|     if (openSession) { | ||||
|       await this.playbackSessionManager.removeSession(req.session.id) | ||||
|       await this.playbackSessionManager.removeSession(req.playbackSession.id) | ||||
|     } | ||||
| 
 | ||||
|     await Database.removePlaybackSession(req.session.id) | ||||
|     await Database.removePlaybackSession(req.playbackSession.id) | ||||
|     res.sendStatus(200) | ||||
|   } | ||||
| 
 | ||||
| @ -111,7 +111,7 @@ class SessionController { | ||||
|       return res.sendStatus(404) | ||||
|     } | ||||
| 
 | ||||
|     req.session = playbackSession | ||||
|     req.playbackSession = playbackSession | ||||
|     next() | ||||
|   } | ||||
| 
 | ||||
| @ -130,7 +130,7 @@ class SessionController { | ||||
|       return res.sendStatus(403) | ||||
|     } | ||||
| 
 | ||||
|     req.session = playbackSession | ||||
|     req.playbackSession = playbackSession | ||||
|     next() | ||||
|   } | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user