2020-12-28 18:09:42 +01:00
|
|
|
import jwt from 'jsonwebtoken'
|
2020-12-29 01:55:44 +01:00
|
|
|
import { Socket } from 'socket.io'
|
2020-12-28 18:09:42 +01:00
|
|
|
|
|
|
|
class UnauthorizedError extends Error {
|
|
|
|
public inner: { message: string }
|
2020-12-29 03:32:28 +01:00
|
|
|
public data: { message: string, code: string, type: 'UnauthorizedError' }
|
2020-12-28 18:09:42 +01:00
|
|
|
|
2020-12-29 03:32:28 +01:00
|
|
|
constructor (code: string, error: { message: string }) {
|
2020-12-28 18:09:42 +01:00
|
|
|
super(error.message)
|
|
|
|
this.message = error.message
|
|
|
|
this.inner = error
|
|
|
|
this.data = {
|
|
|
|
message: this.message,
|
|
|
|
code,
|
|
|
|
type: 'UnauthorizedError'
|
|
|
|
}
|
|
|
|
Object.setPrototypeOf(this, UnauthorizedError.prototype)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-29 03:32:28 +01:00
|
|
|
interface ExtendedError extends Error {
|
|
|
|
data?: any
|
2020-12-29 01:55:44 +01:00
|
|
|
}
|
2020-12-28 18:09:42 +01:00
|
|
|
|
2020-12-29 03:32:28 +01:00
|
|
|
type SocketIOMiddleware = (
|
|
|
|
socket: Socket,
|
|
|
|
next: (err?: ExtendedError) => void
|
|
|
|
) => void
|
2020-12-28 18:09:42 +01:00
|
|
|
|
2020-12-29 03:32:28 +01:00
|
|
|
interface AuthorizeOptions {
|
|
|
|
secret: string
|
2020-12-28 18:09:42 +01:00
|
|
|
}
|
|
|
|
|
2020-12-29 03:32:28 +01:00
|
|
|
export const authorize = (options: AuthorizeOptions): SocketIOMiddleware => {
|
|
|
|
const { secret } = options
|
|
|
|
return (socket, next) => {
|
|
|
|
let token: string | null = null
|
|
|
|
const authorizationHeader = socket.request.headers.authorization
|
|
|
|
if (authorizationHeader != null) {
|
|
|
|
const tokenSplitted = authorizationHeader.split(' ')
|
|
|
|
if (tokenSplitted.length !== 2 || tokenSplitted[0] !== 'Bearer') {
|
|
|
|
return next(
|
|
|
|
new UnauthorizedError('credentials_bad_format', {
|
|
|
|
message: 'Format is Authorization: Bearer [token]'
|
|
|
|
})
|
|
|
|
)
|
2020-12-28 18:09:42 +01:00
|
|
|
}
|
2020-12-29 03:32:28 +01:00
|
|
|
token = tokenSplitted[1]
|
2020-12-28 18:09:42 +01:00
|
|
|
}
|
2020-12-29 03:32:28 +01:00
|
|
|
if (token == null) {
|
|
|
|
return next(
|
|
|
|
new UnauthorizedError('credentials_required', {
|
|
|
|
message: 'no token provided'
|
2020-12-28 18:09:42 +01:00
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
// Store encoded JWT
|
2020-12-29 03:32:28 +01:00
|
|
|
socket = Object.assign(socket, { encodedToken: token })
|
|
|
|
let payload: any
|
|
|
|
try {
|
|
|
|
payload = jwt.verify(token, secret)
|
|
|
|
} catch {
|
|
|
|
return next(
|
|
|
|
new UnauthorizedError('invalid_token', {
|
|
|
|
message: 'Unauthorized: Token is missing or invalid Bearer'
|
|
|
|
})
|
|
|
|
)
|
2020-12-29 01:55:44 +01:00
|
|
|
}
|
2020-12-29 03:32:28 +01:00
|
|
|
// Store decoded JWT
|
|
|
|
socket = Object.assign(socket, { decodedToken: payload })
|
|
|
|
return next()
|
2020-12-29 01:55:44 +01:00
|
|
|
}
|
|
|
|
}
|