X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;ds=sidebyside;f=server%2Flib%2Fauth%2Foauth.ts;h=887c4f7c9449ca7d9f4adb2ae8afb8e59a3a688a;hb=e364e31e25bd1d4b8d801c845a96d6be708f0a18;hp=5b6130d567301d802ea49292b508911e38ad4395;hpb=e62f03ae0412f4efa62917d8741bc1a39e8ed7fc;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/auth/oauth.ts b/server/lib/auth/oauth.ts index 5b6130d56..887c4f7c9 100644 --- a/server/lib/auth/oauth.ts +++ b/server/lib/auth/oauth.ts @@ -1,5 +1,5 @@ -import * as express from 'express' -import { +import express from 'express' +import OAuth2Server, { InvalidClientError, InvalidGrantError, InvalidRequestError, @@ -7,21 +7,46 @@ 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 { UserRegistrationModel } from '@server/models/user/user-registration' import { MOAuthClient } from '@server/types/models' -import { OAUTH_LIFETIME } from '../../initializers/constants' +import { sha1 } from '@shared/extra-utils' +import { HttpStatusCode, ServerErrorCode, UserRegistrationState } 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 = ServerErrorCode.MISSING_TWO_FACTOR +} + +class InvalidTwoFactorError extends Error { + code = HttpStatusCode.BAD_REQUEST_400 + name = ServerErrorCode.INVALID_TWO_FACTOR +} + +class RegistrationWaitingForApproval extends Error { + code = HttpStatusCode.BAD_REQUEST_400 + name = ServerErrorCode.ACCOUNT_WAITING_FOR_APPROVAL +} + +class RegistrationApprovalRejected extends Error { + code = HttpStatusCode.BAD_REQUEST_400 + name = ServerErrorCode.ACCOUNT_APPROVAL_REJECTED +} + /** * * 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 +106,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 } @@ -116,7 +139,27 @@ 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) { + const registration = await UserRegistrationModel.loadByEmailOrUsername(request.body.username) + + if (registration?.state === UserRegistrationState.REJECTED) { + throw new RegistrationApprovalRejected('Registration approval for this account has been rejected') + } else if (registration?.state === UserRegistrationState.PENDING) { + throw new RegistrationWaitingForApproval('Registration for this account is awaiting approval') + } + + 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() @@ -162,10 +205,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 () {