]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/auth/oauth.ts
External auth can update user on login
[github/Chocobozzz/PeerTube.git] / server / lib / auth / oauth.ts
index 5b6130d567301d802ea49292b508911e38ad4395..2905c79a21ea9df187b6bd99b9fe07adbe185c65 100644 (file)
@@ -1,5 +1,5 @@
-import * as express from 'express'
-import {
+import express from 'express'
+import OAuth2Server, {
   InvalidClientError,
   InvalidGrantError,
   InvalidRequestError,
@@ -7,21 +7,35 @@ import {
   Response,
   UnauthorizedClientError,
   UnsupportedGrantTypeError
-} from 'oauth2-server'
-import { randomBytesPromise, sha1 } from '@server/helpers/core-utils'
+} from '@node-oauth/oauth2-server'
+import { randomBytesPromise } from '@server/helpers/core-utils'
+import { isOTPValid } from '@server/helpers/otp'
+import { CONFIG } from '@server/initializers/config'
 import { MOAuthClient } from '@server/types/models'
-import { OAUTH_LIFETIME } from '../../initializers/constants'
+import { sha1 } from '@shared/extra-utils'
+import { HttpStatusCode } from '@shared/models'
+import { OTP } from '../../initializers/constants'
 import { BypassLogin, getClient, getRefreshToken, getUser, revokeToken, saveToken } from './oauth-model'
 
+class MissingTwoFactorError extends Error {
+  code = HttpStatusCode.UNAUTHORIZED_401
+  name = 'missing_two_factor'
+}
+
+class InvalidTwoFactorError extends Error {
+  code = HttpStatusCode.BAD_REQUEST_400
+  name = 'invalid_two_factor'
+}
+
 /**
  *
  * Reimplement some functions of OAuth2Server to inject external auth methods
  *
  */
-
-const oAuthServer = new (require('oauth2-server'))({
-  accessTokenLifetime: OAUTH_LIFETIME.ACCESS_TOKEN,
-  refreshTokenLifetime: OAUTH_LIFETIME.REFRESH_TOKEN,
+const oAuthServer = new OAuth2Server({
+  // Wants seconds
+  accessTokenLifetime: CONFIG.OAUTH2.TOKEN_LIFETIME.ACCESS_TOKEN / 1000,
+  refreshTokenLifetime: CONFIG.OAUTH2.TOKEN_LIFETIME.REFRESH_TOKEN / 1000,
 
   // See https://github.com/oauthjs/node-oauth2-server/wiki/Model-specification for the model specifications
   model: require('./oauth-model')
@@ -81,19 +95,17 @@ async function handleOAuthToken (req: express.Request, options: { refreshTokenAu
   })
 }
 
-async function handleOAuthAuthenticate (
+function handleOAuthAuthenticate (
   req: express.Request,
-  res: express.Response,
-  authenticateInQuery = false
+  res: express.Response
 ) {
-  const options = authenticateInQuery
-    ? { allowBearerTokensInQueryString: true }
-    : {}
-
-  return oAuthServer.authenticate(new Request(req), new Response(res), options)
+  return oAuthServer.authenticate(new Request(req), new Response(res))
 }
 
 export {
+  MissingTwoFactorError,
+  InvalidTwoFactorError,
+
   handleOAuthToken,
   handleOAuthAuthenticate
 }
@@ -118,6 +130,16 @@ async function handlePasswordGrant (options: {
   const user = await getUser(request.body.username, request.body.password, bypassLogin)
   if (!user) throw new InvalidGrantError('Invalid grant: user credentials are invalid')
 
+  if (user.otpSecret) {
+    if (!request.headers[OTP.HEADER_NAME]) {
+      throw new MissingTwoFactorError('Missing two factor header')
+    }
+
+    if (await isOTPValid({ encryptedSecret: user.otpSecret, token: request.headers[OTP.HEADER_NAME] }) !== true) {
+      throw new InvalidTwoFactorError('Invalid two factor header')
+    }
+  }
+
   const token = await buildToken()
 
   return saveToken(token, client, user, { bypassLogin })
@@ -162,10 +184,10 @@ function generateRandomToken () {
 
 function getTokenExpiresAt (type: 'access' | 'refresh') {
   const lifetime = type === 'access'
-    ? OAUTH_LIFETIME.ACCESS_TOKEN
-    : OAUTH_LIFETIME.REFRESH_TOKEN
+    ? CONFIG.OAUTH2.TOKEN_LIFETIME.ACCESS_TOKEN
+    : CONFIG.OAUTH2.TOKEN_LIFETIME.REFRESH_TOKEN
 
-  return new Date(Date.now() + lifetime * 1000)
+  return new Date(Date.now() + lifetime)
 }
 
 async function buildToken () {