2023-04-14 13:13:53 +00:00
import Stacker from "../middlewares/stacker" ;
import { GetUserMiddleware } from "../middlewares/user" ;
import { Request , Response } from "express" ;
import Client from "../../models/client" ;
import Logging from "@hibas123/nodelogging" ;
import Permission , { IPermission } from "../../models/permissions" ;
import ClientCode from "../../models/client_code" ;
import moment = require ( "moment" ) ;
import { randomBytes } from "crypto" ;
// import { ObjectId } from "bson";
import Grant , { IGrant } from "../../models/grants" ;
import GetAuthPage from "../../views/authorize" ;
import { ObjectId } from "mongodb" ;
// const AuthRoute = Stacker(GetUserMiddleware(true), async (req: Request, res: Response) => {
// let { response_type, client_id, redirect_uri, scope, state, nored } = req.query;
// const sendError = (type) => {
// if (redirect_uri === "$local")
// redirect_uri = "/code";
// res.redirect(redirect_uri += `?error=${type}&state=${state}`);
// }
// /**
// * error
// REQUIRED. A single ASCII [USASCII] error code from the
// following:
// invalid_request
// The request is missing a required parameter, includes an
// invalid parameter value, includes a parameter more than
// once, or is otherwise malformed.
// unauthorized_client
// The client is not authorized to request an authorization
// code using this method.
// access_denied
// The resource owner or authorization server denied the
// request.
// */
// try {
// if (response_type !== "code") {
// return sendError("unsupported_response_type");
// } else {
// let client = await Client.findOne({ client_id: client_id })
// if (!client) {
// return sendError("unauthorized_client")
// }
// if (redirect_uri && client.redirect_url !== redirect_uri) {
// Logging.log(redirect_uri, client.redirect_url);
// return res.send("Invalid redirect_uri. Please check the integrity of the site requesting and contact the administrator of the page, you want to authorize!");
// }
// let permissions: IPermission[] = [];
// if (scope) {
// let perms = (<string>scope).split(";").filter(e => e !== "read_user").map(p => new ObjectId(p));
// permissions = await Permission.find({ _id: { $in: perms } })
// if (permissions.length != perms.length) {
// return sendError("invalid_scope");
// }
// }
// let code = ClientCode.new({
// user: req.user._id,
// client: client._id,
// permissions: permissions.map(p => p._id),
// validTill: moment().add(30, "minutes").toDate(),
// code: randomBytes(16).toString("hex")
// });
// await ClientCode.save(code);
// let redir = client.redirect_url === "$local" ? "/code" : client.redirect_url;
// let ruri = redir + `?code=${code.code}&state=${state}`;
// if (nored === "true") {
// res.json({
// redirect_uri: ruri
// })
// } else {
// res.redirect(ruri);
// }
// }
// } catch (err) {
// Logging.error(err);
// sendError("server_error")
// }
// })
const GetAuthRoute = ( view = false ) = >
Stacker ( GetUserMiddleware ( false ) , async ( req : Request , res : Response ) = > {
let {
response_type ,
client_id ,
redirect_uri ,
scope = "" ,
state ,
nored ,
} = req . query as { [ key : string ] : string } ;
const sendError = ( type ) = > {
if ( redirect_uri === "$local" ) redirect_uri = "/code" ;
res . redirect (
( redirect_uri += ` ?error= ${ type } ${ state ? "&state=" + state : "" } ` )
) ;
} ;
const scopes = scope . split ( ";" ) . filter ( ( e : string ) = > e !== "" ) ;
Logging . debug ( "Scopes:" , scope ) ;
try {
if ( response_type !== "code" ) {
return sendError ( "unsupported_response_type" ) ;
} else {
let client = await Client . findOne ( { client_id : client_id } ) ;
if ( ! client ) {
return sendError ( "unauthorized_client" ) ;
}
if ( redirect_uri && client . redirect_url !== redirect_uri ) {
Logging . log ( redirect_uri , client . redirect_url ) ;
return res . send (
"Invalid redirect_uri. Please check the integrity of the site requesting and contact the administrator of the page, you want to authorize!"
) ;
}
let permissions : IPermission [ ] = [ ] ;
let proms : PromiseLike < void > [ ] = [ ] ;
if ( scopes ) {
for ( let perm of scopes . filter ( ( e ) = > e !== "read_user" ) ) {
let oid = undefined ;
try {
oid = new ObjectId ( perm ) ;
} catch ( err ) {
Logging . error ( err ) ;
continue ;
}
proms . push (
Permission . findById ( oid ) . then ( ( p ) = > {
if ( ! p ) return Promise . reject ( new Error ( ) ) ;
permissions . push ( p ) ;
} )
) ;
}
}
let err = undefined ;
await Promise . all ( proms ) . catch ( ( e ) = > {
err = e ;
} ) ;
if ( err ) {
Logging . error ( err ) ;
return sendError ( "invalid_scope" ) ;
}
let grant : IGrant | undefined = await Grant . findOne ( {
client : client._id ,
user : req.user._id ,
} ) ;
Logging . debug ( "Grant" , grant , permissions ) ;
let missing_permissions : IPermission [ ] = [ ] ;
if ( grant ) {
missing_permissions = grant . permissions
. map ( ( perm ) = > permissions . find ( ( p ) = > p . _id . equals ( perm ) ) )
. filter ( ( e ) = > ! ! e ) ;
} else {
missing_permissions = permissions ;
}
let client_granted_perm = missing_permissions . filter (
( e ) = > e . grant_type == "client"
) ;
if ( client_granted_perm . length > 0 ) {
return sendError ( "no_permission" ) ;
}
if ( ! grant && missing_permissions . length > 0 ) {
await new Promise < void > ( ( yes , no ) = >
GetUserMiddleware ( false , true ) (
req ,
res ,
( err? : Error | string ) = > ( err ? no ( err ) : yes ( ) )
)
) ; // Maybe unresolved when redirect is happening
if ( view ) {
res . send (
GetAuthPage (
req . __ ,
client . name ,
permissions . map ( ( perm ) = > {
return {
name : perm.name ,
description : perm.description ,
logo : client.logo ,
} ;
} )
)
) ;
return ;
} else {
if ( ( req . body . allow = "true" ) ) {
if ( ! grant )
grant = Grant . new ( {
client : client._id ,
user : req.user._id ,
permissions : [ ] ,
} ) ;
grant . permissions . push (
. . . missing_permissions . map ( ( e ) = > e . _id )
) ;
await Grant . save ( grant ) ;
} else {
return sendError ( "access_denied" ) ;
}
}
}
let code = ClientCode . new ( {
user : req.user._id ,
client : client._id ,
permissions : permissions.map ( ( p ) = > p . _id ) ,
validTill : moment ( ) . add ( 30 , "minutes" ) . toDate ( ) ,
code : randomBytes ( 16 ) . toString ( "hex" ) ,
} ) ;
await ClientCode . save ( code ) ;
let redir =
client . redirect_url === "$local" ? "/code" : client . redirect_url ;
let ruri =
redir + ` ?code= ${ code . code } ${ state ? "&state=" + state : "" } ` ;
if ( nored === "true" ) {
res . json ( {
redirect_uri : ruri ,
} ) ;
} else {
res . redirect ( ruri ) ;
}
}
} catch ( err ) {
Logging . error ( err ) ;
sendError ( "server_error" ) ;
}
} ) ;
export default GetAuthRoute ;