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.
89 lines
2.8 KiB
89 lines
2.8 KiB
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"); |
|
} |
|
// tslint:disable-next-line:variable-name |
|
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; |
|
}
|
|
|