This commit is contained in:
Ondřej Nývlt 2022-12-22 21:09:40 +01:00
parent b32cd53356
commit eb499d5cf8
7 changed files with 50 additions and 39 deletions

View file

@ -1,6 +1,8 @@
import { isLeft } from "fp-ts/Either"
import * as D from "io-ts/Decoder"
export const API_URL = "https://discord.com/api/v10"
export class HttpError extends Error {
status: number | null = null
constructor(status: number) {

View file

@ -1,8 +1,7 @@
import * as D from "io-ts/Decoder"
import { APP_URL, CLIENT_ID, CLIENT_SECRET } from "../env"
import { expectJson } from "../api/helpers"
import { API_URL, expectJson } from "../api/helpers"
const API_URL = "https://discord.com/api/v10"
const REDIRECT_URL = `${APP_URL}/authorize`
export const AUTH_URL = `${API_URL}/oauth2/authorize?${new URLSearchParams({
@ -35,27 +34,3 @@ export const fetchToken = (code: string): Promise<TokenResponse> => {
}),
}).then(expectJson(TokenResponse))
}
const User = D.struct({
id: D.string,
username: D.string,
avatar: D.string,
discriminator: D.string,
})
export type User = D.TypeOf<typeof User>
const VerifyResponse = D.struct({
user: User,
})
type VerifyResponse = D.TypeOf<typeof VerifyResponse>
export const verifyToken = (token: string): Promise<VerifyResponse> => {
return fetch(`${API_URL}/oauth2/@me`, {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
}).then(expectJson(VerifyResponse))
}

View file

@ -1,13 +1,14 @@
import { AUTH_URL, fetchToken, verifyToken } from "./auth.api"
import { HttpError } from "../api/helpers"
import type { RequestHandler } from "express"
import path from "path"
import { AUTH_URL, fetchToken } from "./auth.api"
import { HttpError } from "../api/helpers"
import { fetchMe } from "../user/user.api"
import type { RequestHandler } from "express"
// -----------------------------------------------------------------------------
// Middleware
// -----------------------------------------------------------------------------
export const verifyUser: RequestHandler = async (req, res, next) => {
export const requireAuth: RequestHandler = async (req, res, next) => {
const token = req.cookies.token
if (!token) {
@ -16,8 +17,8 @@ export const verifyUser: RequestHandler = async (req, res, next) => {
}
try {
const { user } = await verifyToken(token)
;(req as any).user = user
const { user } = await fetchMe(token)
req.user = user
next()
} catch (error) {
if (error instanceof HttpError && error.status === 401) {

View file

@ -7,7 +7,7 @@ import cookieParser from "cookie-parser"
import express from "express"
import layouts from "express-ejs-layouts"
import { authorize, getLogin, logout, verifyUser } from "./auth/auth.handlers"
import { authorize, getLogin, logout, requireAuth } from "./auth/auth.handlers"
import { getMembers } from "./members/members.handlers"
import { handleError, handleNotFound } from "./errors/errors.handlers"
@ -37,7 +37,7 @@ app.get("/authorize", authorize)
app.post("/logout", logout)
// Members
app.get("/members", verifyUser, getMembers)
app.get("/members", requireAuth, getMembers)
app.get("/test-error", () => {
throw new Error("Error 1")

View file

@ -4,7 +4,7 @@ import { Client, Events, GatewayIntentBits } from "discord.js"
import type { RequestHandler } from "express"
import type { Role } from "discord.js"
import type { User } from "../auth/auth.api"
import type { User } from "../user/user.api"
import path from "path"
// -----------------------------------------------------------------------------
@ -54,14 +54,12 @@ export const getRolesAndMembers = () =>
export const getMembers: RequestHandler = async (req, res) => {
const roles = await getRolesAndMembers()
const user: User = (req as any).user
res.render(path.join(__dirname, "members.view.ejs"), {
layout: path.join(process.cwd(), "src/views/_layout"),
roles: processRoles(roles),
user: {
...user,
avatarUrl: getAvatarUrl(user),
...req.user,
avatarUrl: req.user ? getAvatarUrl(req.user) : null,
},
})
}

9
src/types.d.ts vendored Normal file
View file

@ -0,0 +1,9 @@
import type { User } from "./user/user.api"
declare global {
namespace Express {
interface Request {
user?: User
}
}
}

26
src/user/user.api.ts Normal file
View file

@ -0,0 +1,26 @@
import * as D from "io-ts/Decoder"
import { API_URL, expectJson } from "../api/helpers"
const User = D.struct({
id: D.string,
username: D.string,
avatar: D.string,
discriminator: D.string,
})
export type User = D.TypeOf<typeof User>
const VerifyResponse = D.struct({
user: User,
})
type VerifyResponse = D.TypeOf<typeof VerifyResponse>
export const fetchMe = (token: string): Promise<VerifyResponse> => {
return fetch(`${API_URL}/oauth2/@me`, {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
}).then(expectJson(VerifyResponse))
}