mirror of
https://github.com/Akif9748/akf-forum.git
synced 2024-11-22 03:50:41 +03:00
Added discord auth support
This commit is contained in:
parent
e1aeb8fd14
commit
598e48e25d
16 changed files with 115 additions and 12 deletions
|
@ -1 +1,2 @@
|
|||
MONGO_DB_URL = mongodb://localhost:27017/akf-forum
|
||||
DISCORD_CLIENT = discord_app_id
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -4,6 +4,9 @@ node_modules/
|
|||
# Environment variables
|
||||
.env
|
||||
|
||||
# Config files
|
||||
config.json
|
||||
|
||||
# Test files
|
||||
test.js
|
||||
|
||||
|
|
14
README.md
14
README.md
|
@ -4,11 +4,18 @@ A Node.js based forum software.
|
|||
## Installation
|
||||
- Clone or download this repo.
|
||||
- Run `npm i` to install **dependencies**.
|
||||
- Enter your database credentials in `.env`.
|
||||
- Run `npm start` for run it.
|
||||
|
||||
### Extra
|
||||
Run `node util/reset` to **reset the database** for duplicate key errors, and run `node util/admin` for give admin perms to first member.
|
||||
Edit `config.json` for default themes of users, and forum name...
|
||||
Edit `config.json` for default themes (`black` or `default`) of users, and forum name, meta description, character limits, discord auth enabler, global ratelimit.
|
||||
|
||||
### DISCORD AUTH:
|
||||
`discord_auth: true` in config.json.
|
||||
Enter application id to `.env`.
|
||||
Create a redirect url in discord developer portal:
|
||||
`https://forum_url.com/discord_auth/hash`
|
||||
|
||||
## API
|
||||
Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn about API in `APIDOCS.md`.
|
||||
|
@ -35,11 +42,12 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
|
|||
| To do | Is done? |
|
||||
| ----- | -------- |
|
||||
| Profile Message | ⚪ |
|
||||
| Better Auth | ⚪ |
|
||||
| Better Auth for API way | ⚪ |
|
||||
| mod role, permissions | ⚪ |
|
||||
| upload other photos, model for it | ⚪ |
|
||||
| categories page is need a update | ⚪ |
|
||||
| categories page is need a update, thread count in category | ⚪ |
|
||||
| preview for send messages in markdown format | ⚪ |
|
||||
| DC auth will store code for taking tokens, and create secret model setting | ⚪ |
|
||||
|
||||
## Major Version History
|
||||
- V4: Caching
|
||||
|
|
|
@ -12,5 +12,7 @@
|
|||
"enabled": true,
|
||||
"max": 25,
|
||||
"windowMs": 60000
|
||||
}
|
||||
},
|
||||
"discord_auth": true
|
||||
|
||||
}
|
17
config.json.example
Normal file
17
config.json.example
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"def_theme": "default",
|
||||
"forum_name": "akf",
|
||||
"description": "Akf-forum!",
|
||||
"limits": {
|
||||
"title": 128,
|
||||
"message": 1024,
|
||||
"names": 25,
|
||||
"desp": 256
|
||||
},
|
||||
"global_ratelimit": {
|
||||
"enabled": true,
|
||||
"max": 25,
|
||||
"windowMs": 60000
|
||||
},
|
||||
"discord_auth": false
|
||||
}
|
10
index.js
10
index.js
|
@ -4,7 +4,7 @@ const { urlencoded: BP } = require('body-parser'),
|
|||
SES = require('express-session');
|
||||
|
||||
const
|
||||
{ def_theme, forum_name, description, limits, global_ratelimit: RLS } = require("./config.json"),
|
||||
{ def_theme, forum_name, description, limits, global_ratelimit: RLS, discord_auth } = require("./config.json"),
|
||||
{ UserModel, BanModel } = require("./models"),
|
||||
port = process.env.PORT || 3000,
|
||||
mongoose = require("mongoose"),
|
||||
|
@ -50,4 +50,10 @@ for (const file of fs.readdirSync("./routes"))
|
|||
|
||||
app.all("*", (req, res) => res.error(404, "We have not got this page."));
|
||||
|
||||
app.listen(port, () => console.log(`${forum_name}-forum on port:`, port));
|
||||
const server = app.listen(port, () => console.log(`${forum_name}-forum on port:`, port));
|
||||
|
||||
if (discord_auth) {
|
||||
const { address } = server.address();
|
||||
console.log(`https://discord.com/api/oauth2/authorize?client_id=${process.env.DISCORD_CLIENT}&redirect_uri=http%3A%2F%2F${address == '::' ? 'localhost:' + port : address}%2Fdiscord_auth%2Fhash&response_type=token&scope=identify`)
|
||||
app.set("discord_auth", `https://discord.com/api/oauth2/authorize?client_id=${process.env.DISCORD_CLIENT}&redirect_uri=http%3A%2F%2F${address == '::' ? 'localhost:' + port : address}%2Fdiscord_auth%2Fhash&response_type=token&scope=identify`);
|
||||
}
|
|
@ -2,6 +2,7 @@ const mongoose = require("mongoose")
|
|||
const { def_theme } = require("../config.json");
|
||||
const schema = new mongoose.Schema({
|
||||
id: { type: String, unique: true },
|
||||
discordID: { type: String, unique: true },
|
||||
name: { type: String, maxlength: 25 },
|
||||
avatar: { type: String, default: "/images/avatars/default.jpg" },
|
||||
time: { type: Date, default: Date.now },
|
||||
|
|
1
package-lock.json
generated
1
package-lock.json
generated
|
@ -18,6 +18,7 @@
|
|||
"express-session": "^1.17.2",
|
||||
"mongoose": "^6.6.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-fetch": "^2.6.7",
|
||||
"request-ip": "^3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"express-session": "^1.17.2",
|
||||
"mongoose": "^6.6.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-fetch": "^2.6.7",
|
||||
"request-ip": "^3.3.0"
|
||||
}
|
||||
}
|
||||
|
|
58
routes/discord_auth.js
Normal file
58
routes/discord_auth.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
const { Router } = require("express")
|
||||
const { UserModel } = require("../models");
|
||||
const fetch = require("node-fetch");
|
||||
const app = Router();
|
||||
|
||||
app.get("/hash", (req, res) => res.send('<script>location.href=location.href.replace("#","?").replace("discord_auth/hash","discord_auth");</script>'))
|
||||
|
||||
app.get("/", async (req, res) => {
|
||||
const { access_token, token_type } = req.query;
|
||||
if (!access_token) return;
|
||||
try {
|
||||
const discord = await fetch('https://discord.com/api/users/@me', {
|
||||
headers: { authorization: `${token_type} ${access_token}` }
|
||||
}).then(res => res.json());
|
||||
|
||||
const forum = await UserModel.findOne({ discordID: discord.id });
|
||||
|
||||
|
||||
if (req.user) {
|
||||
if (req.user.discordID)
|
||||
return res.error(403, "Your forum account is already linked to a discord account.");
|
||||
|
||||
if (forum)
|
||||
return res.error(403, "This discord account is already linked to a forum account.");
|
||||
|
||||
req.user.discordID = discord.id;
|
||||
await req.user.save();
|
||||
return res.send("Your discord account has been linked to your forum account.");
|
||||
}
|
||||
|
||||
|
||||
if (forum) {
|
||||
req.session.userID = forum.id;
|
||||
return res.redirect("/");
|
||||
}
|
||||
|
||||
let name = discord.username + discord.discriminator;
|
||||
while (await UserModel.findOne({ name }))
|
||||
name += Math.floor(Math.random() * 2);
|
||||
|
||||
const user2 = new UserModel({
|
||||
name, discordID: discord.id,
|
||||
avatar: `https://cdn.discordapp.com/avatars/${discord.id}/${discord.avatar}.png?size=256`
|
||||
});
|
||||
|
||||
await user2.takeId();
|
||||
await user2.save();
|
||||
|
||||
req.session.userID = user2.id;
|
||||
|
||||
res.redirect("/");
|
||||
} catch (error) {
|
||||
res.error(500, "Something went wrong");
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = app;
|
|
@ -3,7 +3,7 @@ const { Router } = require("express");
|
|||
const app = Router();
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
app.get("/", (req, res) => res.reply("login", { redirect: req.query.redirect, user: null }));
|
||||
app.get("/", (req, res) => res.reply("login", { redirect: req.query.redirect, user: null, discord: req.app.get("discord_auth") }));
|
||||
|
||||
app.post("/", async (req, res) => {
|
||||
req.session.userID = null;
|
||||
|
|
|
@ -4,7 +4,7 @@ const bcrypt = require("bcrypt");
|
|||
const rateLimit = require('express-rate-limit');
|
||||
const app = Router();
|
||||
|
||||
app.get("/", (req, res) => res.reply("register", { user: null }));
|
||||
app.get("/", (req, res) => res.reply("register", { user: null, discord: req.app.get("discord_auth") }));
|
||||
|
||||
app.post("/", rateLimit({
|
||||
windowMs: 24 * 60 * 60_000, max: 5, standardHeaders: true, legacyHeaders: false,
|
||||
|
|
|
@ -27,7 +27,7 @@ app.get("/:id", async (req, res) => {
|
|||
|
||||
const message = await MessageModel.count({ authorID: id });
|
||||
const thread = await ThreadModel.count({ authorID: id });
|
||||
res.reply("user", { member, counts: { message, thread } })
|
||||
res.reply("user", { member, counts: { message, thread}, discord: req.app.get("discord_auth") })
|
||||
}
|
||||
else res.error(404, `We don't have any user with id ${id}.`);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
<link rel="stylesheet" href="/css/login.css" />
|
||||
|
||||
<%- include("extra/navbar") %>
|
||||
<a href="<%=discord%>" class="btn-outline-primary">Login with discord</a>
|
||||
|
||||
<h1 class="title">Login</h1>
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@
|
|||
<link rel="stylesheet" href="/css/login.css" />
|
||||
|
||||
<%- include("extra/navbar") %>
|
||||
<a href="<%=discord%>" class="btn-outline-primary">Login with discord</a>
|
||||
|
||||
<h1 class="title">Register</h1>
|
||||
|
||||
|
||||
<form action="/register" method="post">
|
||||
<input type="text" name="username" maxlength="25" placeholder="Username" class="input" required>
|
||||
<input type="password" name="password" maxlength="25" placeholder="Password" class="input" required>
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
|
||||
|
||||
<div class="content">
|
||||
|
||||
<% if (!member.discordID && user?.id === member.id) { %>
|
||||
<a href="<%=discord%>" class="btn-outline-primary">Login with discord</a>
|
||||
<% } %>
|
||||
<% if (user?.admin || user?.id === member.id) { %>
|
||||
<a href="/users/<%=member.id%>/avatar" class="btn-outline-primary">Upload avatar</a>
|
||||
<link rel="stylesheet" href="/css/modal.css" />
|
||||
|
|
Loading…
Reference in a new issue