Cleanup
parent
1b36a24409
commit
dbb1e78429
@ -1,62 +0,0 @@
|
|||||||
# Criterion A: Planning
|
|
||||||
|
|
||||||
## The Programmer's Hangout Unban System
|
|
||||||
|
|
||||||
### Defining the Problem
|
|
||||||
|
|
||||||
veksen is a senior moderator of TPH (The Programmer's Hangout), an online
|
|
||||||
community with over 55,000 members from all over the world. The community is on
|
|
||||||
Discord, a very popular chatting platform where people can hang out. veksen,
|
|
||||||
alongside with the rest of the TPH staff team have a rather clunky way of
|
|
||||||
handling those who misbehave, manage to get themselves *banned* from the
|
|
||||||
server, and want a second chance. Usually, they either have to create a new
|
|
||||||
account and join the server in an attempt to get in touch with the staff team,
|
|
||||||
or have to get a friend to help them out.
|
|
||||||
|
|
||||||
In September, veksen approached me and discussed the issue at hand, wanting an
|
|
||||||
unban system with an online interface, so that it is accessible for those who
|
|
||||||
can't join the community anymore. The online interface would authenticate you
|
|
||||||
with the very open Discord API, be able to validate, that a user is in fact
|
|
||||||
banned from the server, and allow users to fill out a form to appeal their
|
|
||||||
punishment(s). This seemed like a fantastic project for me to complete for my
|
|
||||||
Internal Assessment, as I would be able to solve a programming-related problem,
|
|
||||||
the actual implementation isn't going to be completely non-trivial and simple
|
|
||||||
to solve, and I would be helping out a community that has been so helpful and
|
|
||||||
useful to not only myself, but thousands of others alike.
|
|
||||||
|
|
||||||
In order to get more details, I decided to hop in a call with veksen on
|
|
||||||
September 11th, and get more information about how the system would work.
|
|
||||||
|
|
||||||
### Rationale for Proposed Solution
|
|
||||||
|
|
||||||
There is going to be three main parts to the system. Firstly, there is going to
|
|
||||||
be a REST API that their current website will hook into. This API will have
|
|
||||||
access to information about users who authorize themselves with Discord, so
|
|
||||||
that those who are appealing can be identified when filling out the request.
|
|
||||||
Next, their current website will hook up with the backend API. Finally, there
|
|
||||||
will be a "bot" on the community itself. when a request is processed, will
|
|
||||||
allow the users to rejoin with limited access, so that the staff team can
|
|
||||||
further look into their case and ask more questions.
|
|
||||||
|
|
||||||
I have decided to write the bot, as well as the backend REST API in TypeScript
|
|
||||||
because
|
|
||||||
|
|
||||||
- The rest of the staff team at TPH have experience with it
|
|
||||||
- Easy to write and maintain, especially in comparison with JavaScript, which
|
|
||||||
is purely dynamically typed
|
|
||||||
- Has great libraries available to create REST APIs, as well as Discord bots
|
|
||||||
|
|
||||||
The frontend will be written with React/Gatsby, as that's what the current
|
|
||||||
website is using, and rewriting it all from scratch will be undesirable.
|
|
||||||
|
|
||||||
### The Success Criteria
|
|
||||||
|
|
||||||
1. Allows users to authorize themselves with Discord's OAuth Api
|
|
||||||
1. Identifies whether or not users are banned on the server
|
|
||||||
1. Interfaces with the backend REST API to submit an appeal request
|
|
||||||
1. Uses an email client to inform users information about their appeal request
|
|
||||||
1. Connects with the Discord Bot (known as Contrition) to allow users limited
|
|
||||||
access on TPH
|
|
||||||
1. Has a logging system to keep track of misuse and errors
|
|
||||||
1. Has a flexible configuration system to stay flexible if the TPH server setup
|
|
||||||
is changed
|
|
@ -1,28 +1,48 @@
|
|||||||
import base64url from "base64url";
|
import base64url from "base64url";
|
||||||
|
// Module crypto gives an RNG source that is more secure (slower, more
|
||||||
|
// entropy), and better for security.
|
||||||
import * as crypto from "crypto";
|
import * as crypto from "crypto";
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { OAUTH_SCOPE } from "../config/Constants";
|
import { OAUTH_SCOPE } from "../config/Constants";
|
||||||
import { StateToken } from "../entity/StateToken";
|
import { StateToken } from "../entity/StateToken";
|
||||||
import { respond } from "./Util";
|
import { respond } from "./Util";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* genOauth is the endpoint for users to visit and authorize themselves with Discord.
|
||||||
|
* No passwords are exchanged with our servers, only receiving acknowledgement
|
||||||
|
* and identification of users, meaning that we can access their basic
|
||||||
|
* information in a safe manner.
|
||||||
|
*
|
||||||
|
* @route /api/oauth
|
||||||
|
*
|
||||||
|
*/
|
||||||
export const genOAuth = async (req: Request, res: Response) => {
|
export const genOAuth = async (req: Request, res: Response) => {
|
||||||
|
// Get application core configuration
|
||||||
const { api } = req.app.get("config");
|
const { api } = req.app.get("config");
|
||||||
|
|
||||||
|
// Generate secure token with package crypto. Make sure the token doesn't
|
||||||
|
// already exist using a simple do while {}. If the token exists, simply
|
||||||
|
// regenerate. Should not take more than 1 iteration in almost all
|
||||||
|
// situations.
|
||||||
let token: string;
|
let token: string;
|
||||||
do {
|
do {
|
||||||
token = base64url(crypto.randomBytes(18));
|
token = base64url(crypto.randomBytes(18));
|
||||||
} while ((await StateToken.count({ where: { token } })) !== 0);
|
} while ((await StateToken.count({ where: { token } })) !== 0);
|
||||||
|
|
||||||
|
// Save the generated token to the database, so it can be validated when we
|
||||||
|
// get the response back from Discord.
|
||||||
new StateToken(token).save();
|
new StateToken(token).save();
|
||||||
|
|
||||||
|
// Generate the redirect URL with the relevant information for the OAuth2
|
||||||
|
// Auth flow.
|
||||||
let url =
|
let url =
|
||||||
"https://discord.com/api/oauth2/authorize" +
|
"https://canary.discord.com/api/oauth2/authorize" +
|
||||||
`?response_type=code` +
|
`?response_type=code` +
|
||||||
`&prompt=consent` +
|
`&prompt=consent` +
|
||||||
`&client_id=${api.client_id}` +
|
`&client_id=${api.client_id}` +
|
||||||
`&scope=${encodeURIComponent(OAUTH_SCOPE)}` +
|
`&scope=${encodeURIComponent(OAUTH_SCOPE)}` + // Only get the relevant info - identity
|
||||||
`&state=${token}` +
|
`&state=${token}` + // Prevent impersonation with temporary state token
|
||||||
`&redirect_uri=${encodeURIComponent(api.redirect_uri)}`;
|
`&redirect_uri=${encodeURIComponent(api.redirect_uri)}`; // {baseurl}/authorize
|
||||||
|
|
||||||
respond(res, { redirectURL: url });
|
respond(res, { redirectURL: url });
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue