Adding Basic API Documentation
This commit is contained in:
@ -1,29 +1,60 @@
|
||||
import { Router, Request } from "express";
|
||||
import { GetUserMiddleware } from "../middlewares/user";
|
||||
import RequestError, { HttpStatusCode } from "../../helper/request_error";
|
||||
import promiseMiddleware from "../../helper/promiseMiddleware";
|
||||
import Client from "../../models/client";
|
||||
import User from "../../models/user";
|
||||
import verify, { Types } from "../middlewares/verify";
|
||||
import { randomBytes } from "crypto";
|
||||
|
||||
|
||||
const ClientRouter: Router = Router();
|
||||
ClientRouter.use(GetUserMiddleware(true, true), (req: Request, res, next) => {
|
||||
if (!req.isAdmin) res.sendStatus(HttpStatusCode.FORBIDDEN)
|
||||
else next()
|
||||
});
|
||||
ClientRouter.route("/")
|
||||
/**
|
||||
* @api {get} /admin/client
|
||||
* @apiName AdminGetClients
|
||||
*
|
||||
* @apiGroup admin_client
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Object[]} clients
|
||||
* @apiSuccess {String} clients._id The internally used id
|
||||
* @apiSuccess {String} clients.maintainer
|
||||
* @apiSuccess {Boolean} clients.internal
|
||||
* @apiSuccess {String} clients.name
|
||||
* @apiSuccess {String} clients.redirect_url
|
||||
* @apiSuccess {String} clients.website
|
||||
* @apiSuccess {String} clients.logo
|
||||
* @apiSuccess {String} clients.client_id Client ID used outside of DB
|
||||
* @apiSuccess {String} clients.client_secret
|
||||
*/
|
||||
.get(promiseMiddleware(async (req, res) => {
|
||||
let clients = await Client.find({});
|
||||
//ToDo check if user is required!
|
||||
res.json(clients);
|
||||
}))
|
||||
.delete(promiseMiddleware(async (req, res) => {
|
||||
let { id } = req.query;
|
||||
await Client.delete(id);
|
||||
res.json({ success: true });
|
||||
}))
|
||||
/**
|
||||
* @api {get} /admin/client
|
||||
* @apiName AdminAddClients
|
||||
*
|
||||
* @apiGroup admin_client
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiParam {Boolean} internal Is it an internal app
|
||||
* @apiParam {String} name
|
||||
* @apiParam {String} redirect_url
|
||||
* @apiParam {String} website
|
||||
* @apiParam {String} logo
|
||||
*
|
||||
* @apiSuccess {Object[]} clients
|
||||
* @apiSuccess {String} clients._id The internally used id
|
||||
* @apiSuccess {String} clients.maintainer
|
||||
* @apiSuccess {Boolean} clients.internal
|
||||
* @apiSuccess {String} clients.name
|
||||
* @apiSuccess {String} clients.redirect_url
|
||||
* @apiSuccess {String} clients.website
|
||||
* @apiSuccess {String} clients.logo
|
||||
* @apiSuccess {String} clients.client_id Client ID used outside of DB
|
||||
* @apiSuccess {String} clients.client_secret
|
||||
*/
|
||||
.post(verify({
|
||||
internal: {
|
||||
type: Types.BOOLEAN,
|
||||
@ -49,11 +80,48 @@ ClientRouter.route("/")
|
||||
await Client.save(client)
|
||||
res.json(client);
|
||||
}))
|
||||
|
||||
ClientRouter.route("/:id")
|
||||
/**
|
||||
* @api {delete} /admin/client/:id
|
||||
* @apiParam {String} id Client _id
|
||||
* @apiName AdminDeleteClient
|
||||
*
|
||||
* @apiGroup admin_client
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Boolean} success
|
||||
*/
|
||||
.delete(promiseMiddleware(async (req, res) => {
|
||||
let { id } = req.params;
|
||||
await Client.delete(id);
|
||||
res.json({ success: true });
|
||||
}))
|
||||
/**
|
||||
* @api {put} /admin/client/:id
|
||||
* @apiParam {String} id Client _id
|
||||
* @apiName AdminUpdateClient
|
||||
*
|
||||
* @apiGroup admin_client
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiParam {Boolean} internal Is it an internal app
|
||||
* @apiParam {String} name
|
||||
* @apiParam {String} redirect_url
|
||||
* @apiParam {String} website
|
||||
* @apiParam {String} logo
|
||||
*
|
||||
* @apiSuccess {String} _id The internally used id
|
||||
* @apiSuccess {String} maintainer UserID of client maintainer
|
||||
* @apiSuccess {Boolean} internal Defines if it is a internal client
|
||||
* @apiSuccess {String} name The name of the Client
|
||||
* @apiSuccess {String} redirect_url Redirect URL after login
|
||||
* @apiSuccess {String} website Website of Client
|
||||
* @apiSuccess {String} logo The Logo of the Client (optional)
|
||||
* @apiSuccess {String} client_id Client ID used outside of DB
|
||||
* @apiSuccess {String} client_secret The client secret, that can be used to obtain token
|
||||
*/
|
||||
.put(verify({
|
||||
id: {
|
||||
type: Types.STRING,
|
||||
query: true
|
||||
},
|
||||
internal: {
|
||||
type: Types.BOOLEAN,
|
||||
optional: true
|
||||
@ -85,4 +153,5 @@ ClientRouter.route("/")
|
||||
res.json(client);
|
||||
}))
|
||||
|
||||
|
||||
export default ClientRouter;
|
@ -3,8 +3,16 @@ import ClientRoute from "./client";
|
||||
import UserRoute from "./user";
|
||||
import RegCodeRoute from "./regcode";
|
||||
import PermissionRoute from "./permission";
|
||||
import { GetUserMiddleware } from "../middlewares/user";
|
||||
import RequestError, { HttpStatusCode } from "../../helper/request_error";
|
||||
|
||||
const AdminRoute: Router = Router();
|
||||
|
||||
AdminRoute.use(GetUserMiddleware(true, true), (req: Request, res, next) => {
|
||||
if (!req.isAdmin) throw new RequestError("You have no permission to access this API", HttpStatusCode.FORBIDDEN);
|
||||
else next()
|
||||
});
|
||||
|
||||
AdminRoute.use("/client", ClientRoute);
|
||||
AdminRoute.use("/regcode", RegCodeRoute)
|
||||
AdminRoute.use("/user", UserRoute)
|
||||
|
@ -8,13 +8,22 @@ import Client from "../../models/client";
|
||||
import { ObjectID } from "bson";
|
||||
|
||||
const PermissionRoute: Router = Router();
|
||||
PermissionRoute.use(GetUserMiddleware(true, true), (req: Request, res, next) => {
|
||||
if (!req.isAdmin) res.sendStatus(HttpStatusCode.FORBIDDEN)
|
||||
else next()
|
||||
});
|
||||
|
||||
|
||||
PermissionRoute.route("/")
|
||||
/**
|
||||
* @api {get} /admin/permission
|
||||
* @apiName AdminGetPermissions
|
||||
*
|
||||
* @apiParam client Optionally filter by client _id
|
||||
*
|
||||
* @apiGroup admin_permission
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Object[]} permissions
|
||||
* @apiSuccess {String} permissions._id The ID
|
||||
* @apiSuccess {String} permissions.name Permission name
|
||||
* @apiSuccess {String} permissions.description A description, that makes it clear to the user, what this Permission allows to do
|
||||
* @apiSuccess {String} permissions.client The ID of the owning client
|
||||
*/
|
||||
.get(promiseMiddleware(async (req, res) => {
|
||||
let query = {};
|
||||
if (req.query.client) {
|
||||
@ -23,6 +32,23 @@ PermissionRoute.route("/")
|
||||
let permission = await Permission.find(query);
|
||||
res.json(permission);
|
||||
}))
|
||||
/**
|
||||
* @api {post} /admin/permission
|
||||
* @apiName AdminAddPermission
|
||||
*
|
||||
* @apiParam client The ID of the owning client
|
||||
* @apiParam name Permission name
|
||||
* @apiParam description A description, that makes it clear to the user, what this Permission allows to do
|
||||
*
|
||||
* @apiGroup admin_permission
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Object[]} permissions
|
||||
* @apiSuccess {String} permissions._id The ID
|
||||
* @apiSuccess {String} permissions.name Permission name
|
||||
* @apiSuccess {String} permissions.description A description, that makes it clear to the user, what this Permission allows to do
|
||||
* @apiSuccess {String} permissions.client The ID of the owning client
|
||||
*/
|
||||
.post(verify({
|
||||
client: {
|
||||
type: Types.STRING
|
||||
@ -45,7 +71,19 @@ PermissionRoute.route("/")
|
||||
});
|
||||
await Permission.save(permission);
|
||||
res.json(permission);
|
||||
})).delete(promiseMiddleware(async (req, res) => {
|
||||
}))
|
||||
/**
|
||||
* @api {delete} /admin/permission
|
||||
* @apiName AdminDeletePermission
|
||||
*
|
||||
* @apiParam id The permission ID
|
||||
*
|
||||
* @apiGroup admin_permission
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Boolean} success
|
||||
*/
|
||||
.delete(promiseMiddleware(async (req, res) => {
|
||||
let { id } = req.query;
|
||||
await Permission.delete(id);
|
||||
res.json({ success: true });
|
||||
|
@ -7,20 +7,49 @@ import { GetUserMiddleware } from "../middlewares/user";
|
||||
import { HttpStatusCode } from "../../helper/request_error";
|
||||
|
||||
const RegCodeRoute: Router = Router();
|
||||
RegCodeRoute.use(GetUserMiddleware(true, true), (req: Request, res, next) => {
|
||||
if (!req.isAdmin) res.sendStatus(HttpStatusCode.FORBIDDEN)
|
||||
else next()
|
||||
});
|
||||
RegCodeRoute.route("/")
|
||||
/**
|
||||
* @api {get} /admin/regcode
|
||||
* @apiName AdminGetRegcodes
|
||||
*
|
||||
* @apiGroup admin_regcode
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Object[]} regcodes
|
||||
* @apiSuccess {String} permissions._id The ID
|
||||
* @apiSuccess {String} permissions.token The Regcode Token
|
||||
* @apiSuccess {String} permissions.valid Defines if the Regcode is valid
|
||||
* @apiSuccess {String} permissions.validTill Expiration date of RegCode
|
||||
*/
|
||||
.get(promiseMiddleware(async (req, res) => {
|
||||
let regcodes = await RegCode.find({});
|
||||
res.json(regcodes);
|
||||
}))
|
||||
/**
|
||||
* @api {delete} /admin/regcode
|
||||
* @apiName AdminDeleteRegcode
|
||||
*
|
||||
* @apiParam {String} id The id of the RegCode
|
||||
*
|
||||
* @apiGroup admin_regcode
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Boolean} success
|
||||
*/
|
||||
.delete(promiseMiddleware(async (req, res) => {
|
||||
let { id } = req.query;
|
||||
await RegCode.delete(id);
|
||||
res.json({ success: true });
|
||||
}))
|
||||
/**
|
||||
* @api {post} /admin/regcode
|
||||
* @apiName AdminAddRegcode
|
||||
*
|
||||
* @apiGroup admin_regcode
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {String} code The newly created code
|
||||
*/
|
||||
.post(promiseMiddleware(async (req, res) => {
|
||||
let regcode = RegCode.new({
|
||||
token: randomBytes(10).toString("hex"),
|
||||
|
@ -14,10 +14,37 @@ UserRoute.use(GetUserMiddleware(true, true), (req: Request, res, next) => {
|
||||
})
|
||||
|
||||
UserRoute.route("/")
|
||||
/**
|
||||
* @api {get} /admin/user
|
||||
* @apiName AdminGetUsers
|
||||
*
|
||||
* @apiGroup admin_user
|
||||
* @apiPermission admin
|
||||
* @apiSuccess {Object[]} user
|
||||
* @apiSuccess {String} user._id The internal id of the user
|
||||
* @apiSuccess {String} user.uid The public UID of the user
|
||||
* @apiSuccess {String} user.username The username
|
||||
* @apiSuccess {String} user.name The real name
|
||||
* @apiSuccess {Date} user.birthday The birthday
|
||||
* @apiSuccess {Number} user.gender 0 = none, 1 = male, 2 = female, 3 = other
|
||||
* @apiSuccess {Boolean} user.admin Is admin or not
|
||||
*/
|
||||
.get(promiseMiddleware(async (req, res) => {
|
||||
let users = await User.find({});
|
||||
users.forEach(e => delete e.password && delete e.salt && delete e.encryption_key);
|
||||
res.json(users);
|
||||
}))
|
||||
/**
|
||||
* @api {delete} /admin/user
|
||||
* @apiName AdminDeleteUser
|
||||
*
|
||||
* @apiParam {String} id The User ID
|
||||
*
|
||||
* @apiGroup admin_user
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Boolean} success
|
||||
*/
|
||||
.delete(promiseMiddleware(async (req, res) => {
|
||||
let { id } = req.query;
|
||||
let user = await User.findById(id);
|
||||
@ -32,7 +59,23 @@ UserRoute.route("/")
|
||||
|
||||
await User.delete(user);
|
||||
res.json({ success: true });
|
||||
})).put(promiseMiddleware(async (req, res) => {
|
||||
}))
|
||||
/**
|
||||
* @api {put} /admin/user
|
||||
* @apiName AdminChangeUser
|
||||
*
|
||||
* @apiParam {String} id The User ID
|
||||
*
|
||||
* @apiGroup admin_user
|
||||
* @apiPermission admin
|
||||
*
|
||||
* @apiSuccess {Boolean} success
|
||||
*
|
||||
* @apiDescription Flipps the user role:
|
||||
* admin -> user
|
||||
* user -> admin
|
||||
*/
|
||||
.put(promiseMiddleware(async (req, res) => {
|
||||
let { id } = req.query;
|
||||
let user = await User.findById(id);
|
||||
user.admin = !user.admin;
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { Request, Response, Router } from "express"
|
||||
import Stacker from "../middlewares/stacker";
|
||||
import { GetClientAuthMiddleware } from "../middlewares/client";
|
||||
import { GetUserMiddleware } from "../middlewares/user";
|
||||
import { createJWT } from "../../keys";
|
||||
|
||||
|
||||
const ClientRouter = Router();
|
||||
/**
|
||||
* @api {get} /client/user
|
||||
* @apiName ClientUser
|
||||
*
|
||||
* @apiGroup client
|
||||
* @apiPermission user_client Requires ClientID and Authenticated User
|
||||
*
|
||||
* @apiParam {String} redirect_uri URL to redirect to on success
|
||||
*/
|
||||
ClientRouter.get("/user", Stacker(GetClientAuthMiddleware(false), GetUserMiddleware(true, false), async (req: Request, res: Response) => {
|
||||
let jwt = await createJWT({
|
||||
client: req.client.client_id,
|
||||
uid: req.user.uid,
|
||||
username: req.user.username
|
||||
}, 30); //after 30 seconds this token is invalid
|
||||
res.redirect(req.query.redirect_uri + "?jwt=" + jwt)
|
||||
}));
|
||||
|
||||
export default ClientRouter;
|
@ -1,14 +0,0 @@
|
||||
import { Request, Response } from "express"
|
||||
import Stacker from "../middlewares/stacker";
|
||||
import { GetClientAuthMiddleware } from "../middlewares/client";
|
||||
import { GetUserMiddleware } from "../middlewares/user";
|
||||
import { createJWT } from "../../keys";
|
||||
|
||||
export const AuthGetUser = Stacker(GetClientAuthMiddleware(false), GetUserMiddleware(true, false), async (req: Request, res: Response) => {
|
||||
let jwt = await createJWT({
|
||||
client: req.client.client_id,
|
||||
uid: req.user.uid,
|
||||
username: req.user.username
|
||||
}, 30); //after 30 seconds this token is invalid
|
||||
res.redirect(req.query.redirect_uri + "?jwt=" + jwt)
|
||||
});
|
@ -3,7 +3,7 @@ import AdminRoute from "./admin";
|
||||
import UserRoute from "./user";
|
||||
import InternalRoute from "./internal";
|
||||
import Login from "./user/login";
|
||||
import { AuthGetUser } from "./client/user";
|
||||
import ClientRouter from "./client";
|
||||
import * as cors from "cors";
|
||||
import OAuthRoute from "./oauth";
|
||||
|
||||
@ -14,10 +14,10 @@ ApiRouter.use("/user", UserRoute);
|
||||
ApiRouter.use("/internal", InternalRoute);
|
||||
ApiRouter.use("/oauth", OAuthRoute);
|
||||
|
||||
ApiRouter.use("/client/user", AuthGetUser);
|
||||
ApiRouter.use("/client", ClientRouter);
|
||||
|
||||
// Legacy reasons (deprecated)
|
||||
ApiRouter.use("/user", AuthGetUser);
|
||||
ApiRouter.use("/", ClientRouter);
|
||||
|
||||
// Legacy reasons (deprecated)
|
||||
ApiRouter.post("/login", Login);
|
||||
|
@ -3,6 +3,28 @@ import { OAuthInternalApp } from "./oauth";
|
||||
import PasswordAuth from "./password";
|
||||
|
||||
const InternalRoute: Router = Router();
|
||||
/**
|
||||
* @api {get} /internal/oauth
|
||||
* @apiName ClientInteralOAuth
|
||||
*
|
||||
* @apiGroup client_internal
|
||||
* @apiPermission client_internal Only ClientID
|
||||
*
|
||||
* @apiParam {String} redirect_uri Redirect URI called after success
|
||||
* @apiParam {String} state State will be set in RedirectURI for the client to check
|
||||
*/
|
||||
InternalRoute.get("/oauth", OAuthInternalApp);
|
||||
|
||||
/**
|
||||
* @api {post} /internal/password
|
||||
* @apiName ClientInteralPassword
|
||||
*
|
||||
* @apiGroup client_internal
|
||||
* @apiPermission client_internal Requires ClientID and Secret
|
||||
*
|
||||
* @apiParam {String} username Username (either username or UID)
|
||||
* @apiParam {String} uid User ID (either username or UID)
|
||||
* @apiParam {String} password Hashed and Salted according to specification
|
||||
*/
|
||||
InternalRoute.post("/password", PasswordAuth)
|
||||
export default InternalRoute;
|
@ -5,9 +5,59 @@ import Public from "./public";
|
||||
import RefreshTokenRoute from "./refresh";
|
||||
|
||||
const OAuthRoue: Router = Router();
|
||||
/**
|
||||
* @api {post} /oauth/auth
|
||||
* @apiName OAuthAuth
|
||||
*
|
||||
* @apiGroup oauth
|
||||
* @apiPermission user Special required
|
||||
*
|
||||
* @apiParam {String} response_type must be "code" others are not supported
|
||||
* @apiParam {String} client_id ClientID
|
||||
* @apiParam {String} redirect_uri The URI to redirect with code
|
||||
* @apiParam {String} scope Scope that contains the requested permissions (comma seperated list of permissions)
|
||||
* @apiParam {String} state State, that will be passed to redirect_uri for client
|
||||
* @apiParam {String} nored Deactivates the Redirect response from server and instead returns the redirect URI in JSON response
|
||||
*/
|
||||
OAuthRoue.post("/auth", AuthRoute);
|
||||
|
||||
/**
|
||||
* @api {get} /oauth/jwt
|
||||
* @apiName OAuthJwt
|
||||
*
|
||||
* @apiGroup oauth
|
||||
* @apiPermission none
|
||||
*
|
||||
* @apiParam {String} refreshtoken
|
||||
*
|
||||
* @apiSuccess {String} token The JWT that allowes the application to access the recources granted for refresh token
|
||||
*/
|
||||
OAuthRoue.get("/jwt", JWTRoute)
|
||||
|
||||
/**
|
||||
* @api {get} /oauth/public
|
||||
* @apiName OAuthPublic
|
||||
*
|
||||
* @apiGroup oauth
|
||||
* @apiPermission none
|
||||
*
|
||||
* @apiSuccess {String} public_key The applications public_key. Used to verify JWT.
|
||||
*/
|
||||
OAuthRoue.get("/public", Public)
|
||||
|
||||
/**
|
||||
* @api {get} /oauth/refresh
|
||||
* @apiName OAuthRefreshGet
|
||||
*
|
||||
* @apiGroup oauth
|
||||
*/
|
||||
OAuthRoue.get("/refresh", RefreshTokenRoute);
|
||||
|
||||
/**
|
||||
* @api {post} /oauth/refresh
|
||||
* @apiName OAuthRefreshPost
|
||||
*
|
||||
* @apiGroup oauth
|
||||
*/
|
||||
OAuthRoue.post("/refresh", RefreshTokenRoute);
|
||||
export default OAuthRoue;
|
@ -3,7 +3,6 @@ import promiseMiddleware from "../../helper/promiseMiddleware";
|
||||
import RequestError, { HttpStatusCode } from "../../helper/request_error";
|
||||
import RefreshToken from "../../models/refresh_token";
|
||||
import User from "../../models/user";
|
||||
import Permission from "../../models/permissions";
|
||||
import Client from "../../models/client";
|
||||
import getOAuthJWT from "../../helper/jwt";
|
||||
|
||||
@ -16,7 +15,9 @@ const JWTRoute = promiseMiddleware(async (req: Request, res: Response) => {
|
||||
|
||||
let user = await User.findById(token.user);
|
||||
if (!user) {
|
||||
//TODO handle error!
|
||||
token.valid = false;
|
||||
await RefreshToken.save(token);
|
||||
throw new RequestError(req.__("Invalid token"), HttpStatusCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
let client = await Client.findById(token.client);
|
||||
|
@ -5,10 +5,91 @@ import TwoFactorRoute from "./twofactor";
|
||||
import { GetToken, DeleteToken } from "./token";
|
||||
|
||||
const UserRoute: Router = Router();
|
||||
|
||||
/**
|
||||
* @api {post} /user/register
|
||||
* @apiName UserRegister
|
||||
*
|
||||
* @apiGroup user
|
||||
* @apiPermission none
|
||||
*
|
||||
* @apiParam {String} mail EMail linked to this Account
|
||||
* @apiParam {String} username The new Username
|
||||
* @apiParam {String} password Password hashed and salted like specification
|
||||
* @apiParam {String} salt The Salt used for password hashing
|
||||
* @apiParam {String} regcode The regcode, that should be used
|
||||
* @apiParam {String} gender Gender can be: "male", "female", "other", "none"
|
||||
* @apiParam {String} name The real name of the User
|
||||
*
|
||||
* @apiSuccess {Boolean} success
|
||||
*
|
||||
* @apiErrorExample {Object} Error-Response:
|
||||
{
|
||||
error: [
|
||||
{
|
||||
message: "Some Error",
|
||||
field: "username"
|
||||
}
|
||||
],
|
||||
status: 400
|
||||
}
|
||||
*/
|
||||
UserRoute.post("/register", Register);
|
||||
|
||||
/**
|
||||
* @api {post} /user/login?type=:type
|
||||
* @apiName UserLogin
|
||||
*
|
||||
* @apiParam {String} type Type could be either "username" or "password"
|
||||
*
|
||||
* @apiGroup user
|
||||
* @apiPermission none
|
||||
*
|
||||
* @apiParam {String} username Username (either username or uid required)
|
||||
* @apiParam {String} uid (either username or uid required)
|
||||
* @apiParam {String} password Password hashed and salted like specification (only on type password)
|
||||
*
|
||||
* @apiSuccess {String} uid On type = "username"
|
||||
* @apiSuccess {String} salt On type = "username"
|
||||
*
|
||||
* @apiSuccess {String} login On type = "password". Login Token
|
||||
* @apiSuccess {String} special On type = "password". Special Token
|
||||
* @apiSuccess {Object[]} tfa Will be set when TwoFactorAuthentication is required
|
||||
* @apiSuccess {String} tfa.id The ID of the TFA Method
|
||||
* @apiSuccess {String} tfa.name The name of the TFA Method
|
||||
* @apiSuccess {String} tfa.type The type of the TFA Method
|
||||
*/
|
||||
UserRoute.post("/login", Login)
|
||||
UserRoute.use("/twofactor", TwoFactorRoute);
|
||||
|
||||
/**
|
||||
* @api {get} /user/token
|
||||
* @apiName UserGetToken
|
||||
*
|
||||
* @apiGroup user
|
||||
* @apiPermission user
|
||||
*
|
||||
* @apiSuccess {Object[]} token
|
||||
* @apiSuccess {String} token.id The Token ID
|
||||
* @apiSuccess {String} token.special Identifies Special Token
|
||||
* @apiSuccess {String} token.ip IP the token was optained from
|
||||
* @apiSuccess {String} token.browser The Browser the token was optained from (User Agent)
|
||||
* @apiSuccess {Boolean} token.isthis Shows if it is token used by this session
|
||||
*/
|
||||
UserRoute.get("/token", GetToken);
|
||||
UserRoute.delete("/token", DeleteToken);
|
||||
|
||||
/**
|
||||
* @api {delete} /user/token/:id
|
||||
* @apiParam {String} id The id of the token to be deleted
|
||||
*
|
||||
* @apiName UserDeleteToken
|
||||
*
|
||||
* @apiParam {String} type Type could be either "username" or "password"
|
||||
*
|
||||
* @apiGroup user
|
||||
* @apiPermission user
|
||||
*
|
||||
* @apiSuccess {Boolean} success
|
||||
*/
|
||||
UserRoute.delete("/token/:id", DeleteToken);
|
||||
export default UserRoute;
|
@ -3,9 +3,7 @@ import User, { IUser } from "../../models/user";
|
||||
import { randomBytes } from "crypto";
|
||||
import moment = require("moment");
|
||||
import LoginToken from "../../models/login_token";
|
||||
import RequestError, { HttpStatusCode } from "../../helper/request_error";
|
||||
import promiseMiddleware from "../../helper/promiseMiddleware";
|
||||
import * as speakeasy from "speakeasy";
|
||||
import TwoFactor from "../../models/twofactor";
|
||||
|
||||
const Login = promiseMiddleware(async (req: Request, res: Response) => {
|
||||
@ -19,49 +17,49 @@ const Login = promiseMiddleware(async (req: Request, res: Response) => {
|
||||
res.json({ salt: user.salt, uid: user.uid });
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (type === "password") {
|
||||
const sendToken = async (user: IUser, tfa?: any[]) => {
|
||||
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
||||
let client = {
|
||||
ip: Array.isArray(ip) ? ip[0] : ip,
|
||||
browser: req.headers["user-agent"]
|
||||
}
|
||||
|
||||
const sendToken = async (user: IUser, tfa?: any[]) => {
|
||||
let ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
||||
let client = {
|
||||
ip: Array.isArray(ip) ? ip[0] : ip,
|
||||
browser: req.headers["user-agent"]
|
||||
let token_str = randomBytes(16).toString("hex");
|
||||
let tfa_exp = moment().add(5, "minutes").toDate()
|
||||
let token_exp = moment().add(6, "months").toDate()
|
||||
let token = LoginToken.new({
|
||||
token: token_str,
|
||||
valid: true,
|
||||
validTill: tfa ? tfa_exp : token_exp,
|
||||
user: user._id,
|
||||
validated: tfa ? false : true,
|
||||
...client
|
||||
});
|
||||
await LoginToken.save(token);
|
||||
|
||||
let special_str = randomBytes(24).toString("hex");
|
||||
let special_exp = moment().add(30, "minutes").toDate()
|
||||
let special = LoginToken.new({
|
||||
token: special_str,
|
||||
valid: true,
|
||||
validTill: tfa ? tfa_exp : special_exp,
|
||||
special: true,
|
||||
user: user._id,
|
||||
validated: tfa ? false : true,
|
||||
...client
|
||||
});
|
||||
await LoginToken.save(special);
|
||||
|
||||
res.json({
|
||||
login: { token: token_str, expires: token.validTill.toUTCString() },
|
||||
special: { token: special_str, expires: special.validTill.toUTCString() },
|
||||
tfa
|
||||
});
|
||||
}
|
||||
|
||||
let token_str = randomBytes(16).toString("hex");
|
||||
let tfa_exp = moment().add(5, "minutes").toDate()
|
||||
let token_exp = moment().add(6, "months").toDate()
|
||||
let token = LoginToken.new({
|
||||
token: token_str,
|
||||
valid: true,
|
||||
validTill: tfa ? tfa_exp : token_exp,
|
||||
user: user._id,
|
||||
validated: tfa ? false : true,
|
||||
...client
|
||||
});
|
||||
await LoginToken.save(token);
|
||||
|
||||
let special_str = randomBytes(24).toString("hex");
|
||||
let special_exp = moment().add(30, "minutes").toDate()
|
||||
let special = LoginToken.new({
|
||||
token: special_str,
|
||||
valid: true,
|
||||
validTill: tfa ? tfa_exp : special_exp,
|
||||
special: true,
|
||||
user: user._id,
|
||||
validated: tfa ? false : true,
|
||||
...client
|
||||
});
|
||||
await LoginToken.save(special);
|
||||
|
||||
res.json({
|
||||
login: { token: token_str, expires: token.validTill.toUTCString() },
|
||||
special: { token: special_str, expires: special.validTill.toUTCString() },
|
||||
tfa
|
||||
});
|
||||
}
|
||||
|
||||
if (type === "password") {
|
||||
let { username, password, uid } = req.body;
|
||||
|
||||
let user = await User.findOne(username ? { username: username.toLowerCase() } : { uid: uid })
|
||||
|
@ -6,7 +6,6 @@ import TwoFactor from "../../../models/twofactor";
|
||||
import * as moment from "moment"
|
||||
import RequestError, { HttpStatusCode } from "../../../helper/request_error";
|
||||
|
||||
|
||||
const TwoFactorRouter = Router();
|
||||
|
||||
TwoFactorRouter.get("/", Stacker(GetUserMiddleware(true, true), async (req, res) => {
|
||||
|
@ -82,9 +82,10 @@ export default class Web {
|
||||
private registerErrorHandler() {
|
||||
this.server.use((error, req: express.Request, res, next) => {
|
||||
if (!(error instanceof RequestError)) {
|
||||
Logging.error(error);
|
||||
error = new RequestError(error.message, HttpStatusCode.INTERNAL_SERVER_ERROR);
|
||||
} else if (error.status === 500 && !(<any>error).nolog) {
|
||||
error = new RequestError(error.message, error.status || HttpStatusCode.INTERNAL_SERVER_ERROR, error.nolog || false);
|
||||
}
|
||||
|
||||
if (error.status === 500 && !(<any>error).nolog) {
|
||||
Logging.error(error);
|
||||
} else {
|
||||
Logging.log(typeof error.message === "string" ? error.message.split("\n", 1)[0] : error.message);
|
||||
|
Reference in New Issue
Block a user