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 = (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; const sendError = (type) => { if (redirect_uri === "$local") redirect_uri = "/code"; res.redirect( (redirect_uri += `?error=${type}${state ? "&state=" + state : ""}`) ); }; const scopes = scope.split(";"); 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[] = []; 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((yes, no) => GetUserMiddleware(false, true)(req, res, (err?: Error) => 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;