You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
3.0 KiB
82 lines
3.0 KiB
6 years ago
|
import PromiseRouter from "express-promise-router";
|
||
|
|
||
|
import ApiError from "@common/ApiError";
|
||
|
import { ErrorCode } from "@common/ErrorCode";
|
||
|
import * as httpApi from "@common/httpApi";
|
||
|
import * as authentication from "@server/authentication";
|
||
|
import { User } from "@server/entities";
|
||
|
import { verifyAuthorization } from "@server/express/verifyAuthorization";
|
||
|
import { ServerState } from "@server/state";
|
||
|
|
||
|
export function token(state: ServerState) {
|
||
|
const router = PromiseRouter();
|
||
|
|
||
|
async function passwordGrant(body: httpApi.TokenGrantPasswordRequest, res: Express.Response): Promise<User> {
|
||
|
const { username, password } = body;
|
||
|
if (!body || !username || !password) {
|
||
|
throw new ApiError("Must specify username and password");
|
||
|
}
|
||
|
const user = await state.database.users.findByUsername(username);
|
||
|
if (!user) {
|
||
|
throw new ApiError("User does not exist");
|
||
|
}
|
||
|
const passwordMatches = await user.comparePassword(password);
|
||
|
if (passwordMatches) {
|
||
|
return user;
|
||
|
} else {
|
||
|
throw new ApiError("Invalid user credentials");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async function refreshGrant(body: httpApi.TokenGrantRefreshRequest, res: Express.Response): Promise<User> {
|
||
|
const { refresh_token } = body;
|
||
|
if (!body || !refresh_token) {
|
||
|
throw new ApiError("Must specify a refresh_token", ErrorCode.BadToken);
|
||
|
}
|
||
|
const claims = await authentication.verifyToken(refresh_token);
|
||
|
if (claims.type !== "refresh") {
|
||
|
throw new ApiError("Not a refresh token", ErrorCode.BadToken);
|
||
|
}
|
||
|
const user = await state.database.users.findOne(claims.aud);
|
||
|
if (!user) {
|
||
|
throw new ApiError("User no longer exists", ErrorCode.BadToken);
|
||
|
}
|
||
|
return user;
|
||
|
}
|
||
|
|
||
|
router.post("/grant", async (req, res) => {
|
||
|
const body: httpApi.TokenGrantRequest = req.body;
|
||
|
let user: User;
|
||
|
if (body.grant_type === "password") {
|
||
|
user = await passwordGrant(body, res);
|
||
|
} else if (body.grant_type === "refresh") {
|
||
|
user = await refreshGrant(body, res);
|
||
|
} else {
|
||
|
throw new ApiError("Invalid grant_type");
|
||
|
}
|
||
|
const [access_token, refresh_token] = await Promise.all([
|
||
|
await authentication.generateAccessToken(user),
|
||
|
await authentication.generateRefreshToken(user),
|
||
|
]);
|
||
|
const response: httpApi.TokenGrantResponse = {
|
||
|
access_token, refresh_token,
|
||
|
};
|
||
|
res.json(response);
|
||
|
});
|
||
|
|
||
|
router.post("/grant_device_reg", verifyAuthorization(), async (req, res) => {
|
||
|
// tslint:disable-next-line:no-shadowed-variable
|
||
|
const token = await authentication.generateDeviceRegistrationToken();
|
||
|
res.json({ token });
|
||
|
});
|
||
|
|
||
|
router.post("/verify", verifyAuthorization(), async (req, res) => {
|
||
|
res.json({
|
||
|
ok: true,
|
||
|
token: req.token,
|
||
|
});
|
||
|
});
|
||
|
|
||
|
return router;
|
||
|
}
|