diff options
Diffstat (limited to 'server/controllers/api/users/token.ts')
-rw-r--r-- | server/controllers/api/users/token.ts | 131 |
1 files changed, 0 insertions, 131 deletions
diff --git a/server/controllers/api/users/token.ts b/server/controllers/api/users/token.ts deleted file mode 100644 index c6afea67c..000000000 --- a/server/controllers/api/users/token.ts +++ /dev/null | |||
@@ -1,131 +0,0 @@ | |||
1 | import express from 'express' | ||
2 | import { logger } from '@server/helpers/logger' | ||
3 | import { CONFIG } from '@server/initializers/config' | ||
4 | import { OTP } from '@server/initializers/constants' | ||
5 | import { getAuthNameFromRefreshGrant, getBypassFromExternalAuth, getBypassFromPasswordGrant } from '@server/lib/auth/external-auth' | ||
6 | import { handleOAuthToken, MissingTwoFactorError } from '@server/lib/auth/oauth' | ||
7 | import { BypassLogin, revokeToken } from '@server/lib/auth/oauth-model' | ||
8 | import { Hooks } from '@server/lib/plugins/hooks' | ||
9 | import { asyncMiddleware, authenticate, buildRateLimiter, openapiOperationDoc } from '@server/middlewares' | ||
10 | import { buildUUID } from '@shared/extra-utils' | ||
11 | import { ScopedToken } from '@shared/models/users/user-scoped-token' | ||
12 | |||
13 | const tokensRouter = express.Router() | ||
14 | |||
15 | const loginRateLimiter = buildRateLimiter({ | ||
16 | windowMs: CONFIG.RATES_LIMIT.LOGIN.WINDOW_MS, | ||
17 | max: CONFIG.RATES_LIMIT.LOGIN.MAX | ||
18 | }) | ||
19 | |||
20 | tokensRouter.post('/token', | ||
21 | loginRateLimiter, | ||
22 | openapiOperationDoc({ operationId: 'getOAuthToken' }), | ||
23 | asyncMiddleware(handleToken) | ||
24 | ) | ||
25 | |||
26 | tokensRouter.post('/revoke-token', | ||
27 | openapiOperationDoc({ operationId: 'revokeOAuthToken' }), | ||
28 | authenticate, | ||
29 | asyncMiddleware(handleTokenRevocation) | ||
30 | ) | ||
31 | |||
32 | tokensRouter.get('/scoped-tokens', | ||
33 | authenticate, | ||
34 | getScopedTokens | ||
35 | ) | ||
36 | |||
37 | tokensRouter.post('/scoped-tokens', | ||
38 | authenticate, | ||
39 | asyncMiddleware(renewScopedTokens) | ||
40 | ) | ||
41 | |||
42 | // --------------------------------------------------------------------------- | ||
43 | |||
44 | export { | ||
45 | tokensRouter | ||
46 | } | ||
47 | // --------------------------------------------------------------------------- | ||
48 | |||
49 | async function handleToken (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
50 | const grantType = req.body.grant_type | ||
51 | |||
52 | try { | ||
53 | const bypassLogin = await buildByPassLogin(req, grantType) | ||
54 | |||
55 | const refreshTokenAuthName = grantType === 'refresh_token' | ||
56 | ? await getAuthNameFromRefreshGrant(req.body.refresh_token) | ||
57 | : undefined | ||
58 | |||
59 | const options = { | ||
60 | refreshTokenAuthName, | ||
61 | bypassLogin | ||
62 | } | ||
63 | |||
64 | const token = await handleOAuthToken(req, options) | ||
65 | |||
66 | res.set('Cache-Control', 'no-store') | ||
67 | res.set('Pragma', 'no-cache') | ||
68 | |||
69 | Hooks.runAction('action:api.user.oauth2-got-token', { username: token.user.username, ip: req.ip, req, res }) | ||
70 | |||
71 | return res.json({ | ||
72 | token_type: 'Bearer', | ||
73 | |||
74 | access_token: token.accessToken, | ||
75 | refresh_token: token.refreshToken, | ||
76 | |||
77 | expires_in: token.accessTokenExpiresIn, | ||
78 | refresh_token_expires_in: token.refreshTokenExpiresIn | ||
79 | }) | ||
80 | } catch (err) { | ||
81 | logger.warn('Login error', { err }) | ||
82 | |||
83 | if (err instanceof MissingTwoFactorError) { | ||
84 | res.set(OTP.HEADER_NAME, OTP.HEADER_REQUIRED_VALUE) | ||
85 | } | ||
86 | |||
87 | return res.fail({ | ||
88 | status: err.code, | ||
89 | message: err.message, | ||
90 | type: err.name | ||
91 | }) | ||
92 | } | ||
93 | } | ||
94 | |||
95 | async function handleTokenRevocation (req: express.Request, res: express.Response) { | ||
96 | const token = res.locals.oauth.token | ||
97 | |||
98 | const result = await revokeToken(token, { req, explicitLogout: true }) | ||
99 | |||
100 | return res.json(result) | ||
101 | } | ||
102 | |||
103 | function getScopedTokens (req: express.Request, res: express.Response) { | ||
104 | const user = res.locals.oauth.token.user | ||
105 | |||
106 | return res.json({ | ||
107 | feedToken: user.feedToken | ||
108 | } as ScopedToken) | ||
109 | } | ||
110 | |||
111 | async function renewScopedTokens (req: express.Request, res: express.Response) { | ||
112 | const user = res.locals.oauth.token.user | ||
113 | |||
114 | user.feedToken = buildUUID() | ||
115 | await user.save() | ||
116 | |||
117 | return res.json({ | ||
118 | feedToken: user.feedToken | ||
119 | } as ScopedToken) | ||
120 | } | ||
121 | |||
122 | async function buildByPassLogin (req: express.Request, grantType: string): Promise<BypassLogin> { | ||
123 | if (grantType !== 'password') return undefined | ||
124 | |||
125 | if (req.body.externalAuthToken) { | ||
126 | // Consistency with the getBypassFromPasswordGrant promise | ||
127 | return getBypassFromExternalAuth(req.body.username, req.body.externalAuthToken) | ||
128 | } | ||
129 | |||
130 | return getBypassFromPasswordGrant(req.body.username, req.body.password) | ||
131 | } | ||