@@ -3,22 +3,25 @@ import * as Sentry from '@sentry/node';
3
3
import bcrypt from 'bcrypt' ;
4
4
import {
5
5
User ,
6
- ServiceTokenData
6
+ ServiceTokenData ,
7
+ APIKeyData
7
8
} from '../models' ;
8
9
import {
9
10
JWT_AUTH_LIFETIME ,
10
11
JWT_AUTH_SECRET ,
11
12
JWT_REFRESH_LIFETIME ,
12
- JWT_REFRESH_SECRET ,
13
- SALT_ROUNDS
13
+ JWT_REFRESH_SECRET
14
14
} from '../config' ;
15
15
import {
16
16
AccountNotFoundError ,
17
17
ServiceTokenDataNotFoundError ,
18
- UnauthorizedRequestError ,
19
- BadRequestError
18
+ APIKeyDataNotFoundError ,
19
+ UnauthorizedRequestError
20
20
} from '../utils/errors' ;
21
21
22
+ // TODO 1: check if API key works
23
+ // TODO 2: optimize middleware
24
+
22
25
/**
23
26
* Validate that auth token value [authTokenValue] falls under one of
24
27
* accepted auth modes [acceptedAuthModes].
@@ -40,6 +43,9 @@ const validateAuthMode = ({
40
43
case 'st' :
41
44
authMode = 'serviceToken' ;
42
45
break ;
46
+ case 'ak' :
47
+ authMode = 'apiKey' ;
48
+ break ;
43
49
default :
44
50
authMode = 'jwt' ;
45
51
break ;
@@ -106,18 +112,18 @@ const getAuthSTDPayload = async ({
106
112
107
113
// TODO: optimize double query
108
114
serviceTokenData = await ServiceTokenData
109
- . findById ( TOKEN_IDENTIFIER , 'secretHash expiresAt' ) ;
115
+ . findById ( TOKEN_IDENTIFIER , '+ secretHash + expiresAt' ) ;
110
116
111
- if ( serviceTokenData ?. expiresAt && new Date ( serviceTokenData . expiresAt ) < new Date ( ) ) {
117
+ if ( ! serviceTokenData ) {
118
+ throw ServiceTokenDataNotFoundError ( { message : 'Failed to find service token data' } ) ;
119
+ } else if ( serviceTokenData ?. expiresAt && new Date ( serviceTokenData . expiresAt ) < new Date ( ) ) {
112
120
// case: service token expired
113
121
await ServiceTokenData . findByIdAndDelete ( serviceTokenData . _id ) ;
114
122
throw UnauthorizedRequestError ( {
115
123
message : 'Failed to authenticate expired service token'
116
124
} ) ;
117
125
}
118
126
119
- if ( ! serviceTokenData ) throw ServiceTokenDataNotFoundError ( { message : 'Failed to find service token data' } ) ;
120
-
121
127
const isMatch = await bcrypt . compare ( TOKEN_SECRET , serviceTokenData . secretHash ) ;
122
128
if ( ! isMatch ) throw UnauthorizedRequestError ( {
123
129
message : 'Failed to authenticate service token'
@@ -136,6 +142,50 @@ const getAuthSTDPayload = async ({
136
142
return serviceTokenData ;
137
143
}
138
144
145
+ /**
146
+ * Return API key data payload corresponding to API key [authTokenValue]
147
+ * @param {Object } obj
148
+ * @param {String } obj.authTokenValue - API key value
149
+ * @returns {APIKeyData } apiKeyData - API key data
150
+ */
151
+ const getAuthAPIKeyPayload = async ( {
152
+ authTokenValue
153
+ } : {
154
+ authTokenValue : string ;
155
+ } ) => {
156
+ let user ;
157
+ try {
158
+ const [ _ , TOKEN_IDENTIFIER , TOKEN_SECRET ] = < [ string , string , string ] > authTokenValue . split ( '.' , 3 ) ;
159
+
160
+ const apiKeyData = await APIKeyData
161
+ . findById ( TOKEN_IDENTIFIER , '+secretHash +expiresAt' )
162
+ . populate ( 'user' , '+publicKey' ) ;
163
+
164
+ if ( ! apiKeyData ) {
165
+ throw APIKeyDataNotFoundError ( { message : 'Failed to find API key data' } ) ;
166
+ } else if ( apiKeyData ?. expiresAt && new Date ( apiKeyData . expiresAt ) < new Date ( ) ) {
167
+ // case: API key expired
168
+ await APIKeyData . findByIdAndDelete ( apiKeyData . _id ) ;
169
+ throw UnauthorizedRequestError ( {
170
+ message : 'Failed to authenticate expired API key'
171
+ } ) ;
172
+ }
173
+
174
+ const isMatch = await bcrypt . compare ( TOKEN_SECRET , apiKeyData . secretHash ) ;
175
+ if ( ! isMatch ) throw UnauthorizedRequestError ( {
176
+ message : 'Failed to authenticate API key'
177
+ } ) ;
178
+
179
+ user = apiKeyData . user ;
180
+ } catch ( err ) {
181
+ throw UnauthorizedRequestError ( {
182
+ message : 'Failed to authenticate API key'
183
+ } ) ;
184
+ }
185
+
186
+ return user ;
187
+ }
188
+
139
189
/**
140
190
* Return newly issued (JWT) auth and refresh tokens to user with id [userId]
141
191
* @param {Object } obj
@@ -229,6 +279,7 @@ export {
229
279
validateAuthMode ,
230
280
getAuthUserPayload ,
231
281
getAuthSTDPayload ,
282
+ getAuthAPIKeyPayload ,
232
283
createToken ,
233
284
issueTokens ,
234
285
clearTokens
0 commit comments