import { App } from '../lib' ; import * as oauth2orize from 'oauth2orize' ; import * as crypto from 'crypto' ; import * as passport from 'passport' ; import { Strategy as ClientPasswordStrategy } from 'passport-oauth2-client-password' ; import { Strategy as BearerStrategy } from 'passport-http-bearer' ; export class OAuth { server : any ; tokens : Array < { username : string ; expires_in : Date ; token : string ; scope : string [ ] ; } > = [ ] ; get token ( ) { if ( ! this . app . rootPassword ) { return ( req , res , next ) => res . status ( 200 ) . send ( { access_token : null } ) ; } return [ passport . authenticate ( [ 'clientPassword' ] , { session : false } ) , this . server . token ( ) , this . server . errorHandler ( ) ] ; } get isAuth ( ) { if ( ! this . app . rootPassword ) { return ( req , res , next ) => next ( ) ; } return passport . authenticate ( 'accessToken' , { session : false } ) ; } constructor ( private app ) { this . server = oauth2orize . createServer ( ) ; } initialize ( ) { this . app . server . expressApp . use ( passport . initialize ( ) ) ; this . app . server . expressApp . use ( passport . session ( ) ) ; this . server . exchange ( oauth2orize . exchange . clientCredentials ( ( client , scope , done ) => this . generateToken ( ) . then ( token => { const tokenHash = crypto . createHash ( 'sha1' ) . update ( token ) . digest ( 'hex' ) ; this . tokens . push ( { token : tokenHash , expires_in : new Date ( new Date ( ) . getTime ( ) + 3600 * 48 * 1000 ) , username : 'admin' , scope : [ '*' ] } ) ; return done ( null , token , null , null ) ; } ) ) ) ; passport . use ( 'clientPassword' , new ClientPasswordStrategy ( this . verifyLogin . bind ( this ) ) ) ; passport . use ( 'accessToken' , new BearerStrategy ( this . verifyToken . bind ( this ) ) ) ; } static getTokenFromHeaders ( req ) { const h = req . headers [ 'Authorization' ] ; const prefix = 'Bearer ' ; if ( ! h . startWith ( prefix ) ) { return null ; } return h . substr ( prefix . length ) ; } verifyLogin ( clientId , clientSecret , done ) { if ( clientId == 'admin' && clientSecret == this . app . rootPassword ) { return done ( null , { username : 'admin' } ) ; } else { return done ( null , false ) ; } } verifyToken ( accessToken , done ) { if ( ! accessToken ) { return done ( null , false ) ; } const accessTokenHash = crypto . createHash ( 'sha1' ) . update ( accessToken ) . digest ( 'hex' ) ; const token = this . tokens . find ( t => t . token == accessTokenHash ) ; if ( ! token ) { return done ( null , false ) ; } if ( new Date ( ) > token . expires_in ) { this . clearExpiredTokens ( ) ; done ( null , false ) ; } else { const info = { scope : '*' } ; done ( null , { username : 'admin' } , info ) ; } } private clearExpiredTokens ( ) { this . tokens = this . tokens . filter ( token => { return token . expires_in . getTime ( ) <= new Date ( ) . getTime ( ) ; } ) ; } private generateToken ( { stringBase = 'base64' , byteLength = 32 } = { } ) { return new Promise ( ( resolve , reject ) => { crypto . randomBytes ( byteLength , ( err , buffer ) => { if ( err ) { reject ( err ) ; } else { resolve ( buffer . toString ( stringBase ) ) ; } } ) ; } ) ; } }