-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlib.ts
More file actions
138 lines (124 loc) · 5.25 KB
/
lib.ts
File metadata and controls
138 lines (124 loc) · 5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
const jwt = require('jsonwebtoken');
const cookie = require('cookie');
const ms = require('ms');
import { Datastore, httpRequest, httpResponse, nextFunction, filestore } from 'codehooks-js';
import { AuthSettings } from './types';
// Helper function to get the JWT from Authorization header
function getTokenFromAuthorizationHeader(authorizationHeader) {
if (authorizationHeader && authorizationHeader.startsWith('Bearer ')) {
return authorizationHeader.slice(7);
}
return null;
}
// Refresh access token
export const refreshAccessToken = async (req: httpRequest, res: httpResponse, settings: AuthSettings) => {
try {
let token = getTokenFromAuthorizationHeader(req.headers['authorization'])
if (req.headers.cookie) {
const cookies = cookie.parse(req.headers.cookie);
token = cookies['refresh-token']
}
if (!token) {
console.error('Missing refresh token', req.headers)
return res.status(401).json({error: "Missing refresh token"})
}
const decoded = jwt.verify(token, settings.JWT_REFRESH_TOKEN_SECRET);
const claims:any = {}
if (decoded.email) {
claims.email = decoded.email
claims.id = decoded.id
}
const access_token = jwt.sign(claims, settings.JWT_ACCESS_TOKEN_SECRET,
{ expiresIn: settings.JWT_ACCESS_TOKEN_SECRET_EXPIRE })
res.setHeader('Set-Cookie', cookie.serialize('access-token', access_token, {
sameSite: "none",
path: '/',
secure: true,
httpOnly: true,
maxAge: Number(ms(settings.JWT_ACCESS_TOKEN_SECRET_EXPIRE)) / 1000
}));
res.json({access_token})
} catch (error) {
if (error.name === "TokenExpiredError") {
return res.status(401).json({token_error: "Token lifetime exceeded!"})
}
console.error('refreshAccessToken', error)
res.status(401).json({error: error.message})
}
}
// Get JWT for access token
export const getJwtForAccessToken = async (req: httpRequest, res: httpResponse, Datastore: Datastore) => {
console.debug('getJwtForAccessToken', req.body)
const {access_token} = req.body;
const conn = await Datastore.open()
const jwt = await conn.get(`refresh-token:${access_token}`, {keyspace: 'codehooks-auth'})
console.debug('Refresh JWT for token', jwt)
if (jwt) {
res.json(jwt)
} else {
res.status(404).json({message: "No jwt for access key"})
}
}
// Verify access token middleware
export const verifyAccessToken = (settings: AuthSettings) => {
return async function(req: httpRequest, res: httpResponse, next: nextFunction) {
try {
const db = await Datastore.open();
let token = getTokenFromAuthorizationHeader(req.headers['authorization'])
if (req.headers.cookie) {
const cookies = cookie.parse(req.headers.cookie);
token = cookies['access-token']
}
if (token) {
try {
const decoded = jwt.verify(token, settings.JWT_ACCESS_TOKEN_SECRET);
req.headers['x-jwt-decoded'] = decoded;
console.debug('lookup user', { email: decoded.email, active: true })
const aUser = await db.getOne(settings.userCollection, { email: decoded.email, active: true });
console.debug('verified access token', decoded, aUser);
next()
} catch (error) {
console.error('verifyAccessToken', error)
if (error.name === "TokenExpiredError") {
return next("Token lifetime exceeded!")
}
if (error.error) {
return next(error.error)
}
next(error);
}
} else {
next('Missing token')
}
} catch (error) {
console.log('verifyAccessToken Error', error)
next(error.message)
}
}
}
export function setAuthCookies(res: httpResponse, token: string, refreshToken: string, settings: AuthSettings) {
if (!settings.useCookie) return;
const refreshTokenCookie = cookie.serialize('refresh-token', refreshToken, {
sameSite: "none",
path: '/auth/refreshtoken',
secure: true,
httpOnly: true,
maxAge: Number(ms(settings.JWT_REFRESH_TOKEN_SECRET_EXPIRE)) / 1000
});
const accessTokenCookie = cookie.serialize('access-token', token, {
sameSite: "none",
path: '/',
secure: true,
httpOnly: true,
maxAge: Number(ms(settings.JWT_ACCESS_TOKEN_SECRET_EXPIRE)) / 1000
});
res.setHeader('Set-Cookie', [refreshTokenCookie, accessTokenCookie]);
}
const ONE_DAY = 86400000;
export const setCacheHeaders = (res:httpResponse) => {
// Set cache headers
res.set('Cache-Control', `public, max-age=${ONE_DAY*15}, s-maxage=${ONE_DAY*15}, immutable`);
res.setHeader("Expires", new Date(Date.now() + ONE_DAY*15).toUTCString());
res.removeHeader('Pragma');
res.removeHeader('Surrogate-Control');
}