'use strict' ; import Config from '@Base/config' ; import bodyParser from 'express' ; import { Router , RequestHandler , Request , Response , NextFunction } from 'express' ; import { setupMetaverseAPI , finishMetaverseAPI , finishReturnData } from '@Route-Tools/middleware' ; import { AccountEntity } from '@Entities/AccountEntity' ; import { Accounts } from '@Entities/Accounts' ; import { Roles } from '@Entities/Sets/Roles' ; import { AuthToken } from '@Entities/AuthToken' ; import { Tokens , TokenScope } from '@Entities/Tokens' ; import { IsNullOrEmpty } from '@Tools/Misc' ; import { VKeyedCollection } from '@Tools/vTypes' ; import { Logger } from '@Tools/Logging' ; const procPostOauthToken = async ( req , resp , next ) => { let respBody ; try { const accessGrantType = req . body . grant_type ; switch ( accessGrantType ) { case 'password' : { const userName = req . body . username ; const userPassword = req . body . password ; const userScope = req . body . scope ?? TokenScope . OWNER ; if ( TokenScope . KnownScope ( userScope ) ) { let aAccount = await Accounts . getAccountWithUsername ( userName ) ; if ( IsNullOrEmpty ( aAccount ) ) { aAccount = await Accounts . getAccountWithEmail ( userName ) ; } ; if ( aAccount ) { if ( Accounts . isEnabled ( aAccount ) ) { if ( await Accounts . validatePassword ( aAccount , userPassword ) ) { Logger . debug ( `procPostOAuthToken: login of user ${ userName }` ) ; const tokenInfo = await Tokens . createToken ( aAccount . id , [ userScope ] ) ; await Tokens . addToken ( tokenInfo ) ; respBody = buildOAuthResponseBody ( aAccount , tokenInfo ) ; } else { respBody = buildOAuthErrorBody ( 'Invalid password' ) ; req . vRestResp . IsFailure = true ; } ; } else { respBody = buildOAuthErrorBody ( 'Account not verified' ) ; req . vRestResp . IsFailure = true ; } ; } else { respBody = buildOAuthErrorBody ( 'Unknown user' ) ; req . vRestResp . IsFailure = true ; } ; } else { respBody = buildOAuthErrorBody ( 'Invalid scope' ) ; req . vRestResp . IsFailure = true ; } ; break ; } ; case 'authorization_code' : { respBody = buildOAuthErrorBody ( 'Do not know what to do with an authorization_code' ) ; req . vRestResp . IsFailure = true ; break ; } ; case 'refresh_token' : { const refreshingToken = req . body . refresh_token ; const refreshToken = await Tokens . getTokenWithRefreshToken ( refreshingToken ) ; if ( Tokens . hasNotExpired ( refreshToken ) ) { const requestingAccount = await Accounts . getAccountWithAuthToken ( req . vRestResp . getAuthToken ( ) ) ; if ( requestingAccount && refreshToken . accountId === requestingAccount . id ) { const newToken = await Tokens . createToken ( req . vAuthAccount . id , refreshToken . scope ) ; await Tokens . addToken ( newToken ) ; respBody = buildOAuthResponseBody ( requestingAccount , newToken ) ; } else { respBody = buildOAuthErrorBody ( 'refresh token not owned by accessing account' ) ; req . vRestResp . IsFailure = true ; } ; } else { respBody = buildOAuthErrorBody ( 'refresh token expired' ) ; req . vRestResp . IsFailure = true ; } break ; } ; default : { respBody = buildOAuthErrorBody ( 'Unknown grant_type: ' + accessGrantType ) ; req . vRestResp . IsFailure = true ; break ; } ; } ; } catch ( err ) { respBody = buildOAuthErrorBody ( 'Exception: ' + err ) ; req . vRestResp . IsFailure = true ; } ; req . vRestResp . Data = respBody ; next ( ) ; } ; export function buildOAuthResponseBody ( pAcct , pToken ) { const body = { 'access_token' : pToken . token , 'token_type' : 'Bearer' , 'expires_in' : pToken . expirationTime . valueOf ( ) / 1000 - pToken . whenCreated . valueOf ( ) / 1000 , 'refresh_token' : pToken . refreshToken , 'scope' : pToken . scope [ 0 ] , 'created_at' : pToken . whenCreated . valueOf ( ) / 1000 , } ; if ( pAcct ) { body . account_id = pAcct . id , body . account_name = pAcct . username , body . account_roles = pAcct . roles ; } ; return body ; } ; function buildOAuthErrorBody ( pMsg ) { Logger . error ( `procPostOauthToken: returning error body: ${ pMsg }` ) ; return { 'error' : pMsg } ; } ; export const name = "/oauth/token" ; export const router = Router ( ) ; router . post ( '/oauth/token' , [ setupMetaverseAPI , bodyParser . urlencoded ( { extended : true } ) , procPostOauthToken , finishReturnData ] ) ;