OpenAuth_server/src/api/oauth/auth.ts

248 lines
8.6 KiB
TypeScript

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;
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<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) =>
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;