Added unauth w/discord, and better auth

This commit is contained in:
Akif9748 2022-09-24 00:15:17 +03:00
parent 43720f0ca0
commit cf8de73e7c
8 changed files with 130 additions and 90 deletions

View file

@ -1,2 +1,3 @@
MONGO_DB_URL = mongodb://localhost:27017/akf-forum MONGO_DB_URL = mongodb://localhost:27017/akf-forum
SECRET = secret SECRET = secret
DISCORD_SECRET = yourDiscordSecret

View file

@ -67,30 +67,35 @@ You can change them in config.json.
GET ```/api/messages/0``` GET ```/api/messages/0```
#### Example API Output: #### Example API Output:
```json ```js
{ {
"_id": "63067429bc01da866fad508b", "react": {
"threadID": "0", "like": [],
"author": { "dislike": ["0"]
"id": "0",
"name": "Akif9748",
"avatar": "https://cdn.discordapp.com/avatars/539506680140922890/abd74d10aac094fc8a5ad5c86f29fdb9.png?size=1024",
"time": "2022-08-24T18:54:55.666Z",
"deleted": false,
"admin": false,
"_id": "630673ffbc01da866fad507b",
"__v": 0
}, },
"content": "deneme", "_id": "6325c216faa938c4cfc43075",
"author": {
"_id": "632e028ca4ba362ebbb75a43",
"name": "Akif9748",
"avatar": "/images/avatars/0.jpg",
"deleted": false, "deleted": false,
"edited": false, "edited": true,
"time": "2022-08-24T18:55:37.744Z", "about": "# Owner",
"admin": true,
"theme": "black",
"hideLastSeen": false,
"time": "2022-09-23T19:01:32.610Z",
"id": "0", "id": "0",
"__v": 0, "__v": 0,
"react": { "discordID": "539506680140922890"
"like": [0],
"dislike": []
}, },
"authorID": "0" "threadID": "0",
"content": "This is a thread opened via API, yes",
"deleted": false,
"edited": true,
"time": "2022-09-17T12:48:22.378Z",
"id": "0",
"__v": 4,
"oldContents": []
} }
``` ```

View file

@ -14,6 +14,7 @@ Edit `config.json` for default themes (`black` or `default`) of users, and forum
### DISCORD AUTH: ### DISCORD AUTH:
`"discord_auth": "your_app_id"` in config.json. `"discord_auth": "your_app_id"` in config.json.
Add your app secret to `.env` as `DISCORD_SECRET`.
Create a redirect url in discord developer portal: Create a redirect url in discord developer portal:
`https://forum_url.com/discord_auth/hash` `https://forum_url.com/discord_auth/hash`
@ -43,7 +44,6 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
- mod role, permissions - mod role, permissions
- upload other photos, model for it - upload other photos, model for it
- categories page is need a update, thread count in category - categories page is need a update, thread count in category
- DC auth will store code for taking tokens, and create secret model setting
- Disable last seen button for web. - Disable last seen button for web.
- email auth. - email auth.
- old contents / titles add to forum interface - old contents / titles add to forum interface

View file

@ -29,7 +29,7 @@ app.use(express.static("public"), express.json(), express.urlencoded({extended:t
req.user = req.session.userID ? await UserModel.findOneAndUpdate({ id: req.session.userID }, { req.user = req.session.userID ? await UserModel.findOneAndUpdate({ id: req.session.userID }, {
lastSeen: Date.now(), $addToSet: { ips: req.clientIp } lastSeen: Date.now(), $addToSet: { ips: req.clientIp }
}) : null; }): null;
res.reply = (page, options = {}, status = 200) => res.status(status) res.reply = (page, options = {}, status = 200) => res.status(status)
.render(page, { user: req.user, theme: req.user?.theme || def_theme, forum_name, description, ...options }); .render(page, { user: req.user, theme: req.user?.theme || def_theme, forum_name, description, ...options });
@ -44,7 +44,7 @@ app.use(express.static("public"), express.json(), express.urlencoded({extended:t
); );
if (discord_auth) if (discord_auth)
app.set("discord_auth", `https://discord.com/api/oauth2/authorize?client_id=${discord_auth}&redirect_uri=${host}%2Fdiscord_auth%2Fhash&response_type=token&scope=identify`); app.set("discord_auth", `https://discord.com/api/oauth2/authorize?client_id=${discord_auth}&redirect_uri=${host}%2Fauth%2Fdiscord&response_type=code&scope=identify`);
if (RLS.enabled) app.use(RL(RLS.windowMs, RLS.max)); if (RLS.enabled) app.use(RL(RLS.windowMs, RLS.max));

View file

@ -14,7 +14,8 @@ const schema = new mongoose.Schema({
lastSeen: { type: Date, default: Date.now, select: false }, lastSeen: { type: Date, default: Date.now, select: false },
hideLastSeen: { type: Boolean, default: false }, hideLastSeen: { type: Boolean, default: false },
ips: { type: [String], default: [], select: false }, ips: { type: [String], default: [], select: false },
password: { type: String, select: false } password: { type: String, select: false },
discord_code: { type: String, select: false }
}); });
schema.methods.takeId = async function () { schema.methods.takeId = async function () {

87
routes/auth.js Normal file
View file

@ -0,0 +1,87 @@
const { Router } = require("express")
const { UserModel } = require("../models");
const fetch = require("node-fetch");
const app = Router();
const { host, discord_auth } = require("../config.json")
app.get("/discord", async (req, res) => {
const client_id = discord_auth;
if (!client_id) return res.error(404, "Discord auth is disabled")
const { code } = req.query;
if (!code) return res.error(400, "No code provided");
try {
const response = await fetch('https://discord.com/api/v10/oauth2/token', {
method: 'POST',
body: new URLSearchParams({
client_id, code,
client_secret: process.env.DISCORD_SECRET,
grant_type: 'authorization_code',
redirect_uri: host + "/auth/discord",
scope: 'identify',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
if (!response.ok) return res.error(500, "Bad request to discord");
const { access_token, token_type } = await response.json();
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;
req.user.discord_code = code;
await req.user.save();
return res.redirect(`/users/${req.user.id}`)
}
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, discord_code: code,
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);
}
});
app.delete("/discord", async (req, res) => {
if (!req.user) return res.error(403, "You are not logged in");
if (!req.user.discordID) return res.error(403, "You don't have a discord account linked to your forum account.");
req.user.discordID = undefined;
req.user.discord_code = undefined;
await req.user.save();
res.send("Your discord account has been unlinked from your forum account.");
});
module.exports = app;

View file

@ -1,61 +0,0 @@
const { Router } = require("express")
const { UserModel } = require("../models");
const fetch = require("node-fetch");
const app = Router();
app.use(async (req, res, next) =>
req.app.get("discord_auth") ? next() : res.error(404,"Discord auth is disabled")
)
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;

View file

@ -14,7 +14,9 @@
<div class="content"> <div class="content">
<% if (!member.discordID && discord && user?.id === member.id) { %> <% if (!member.discordID && discord && user?.id === member.id) { %>
<a href="<%=discord%>" class="btn-outline-primary">Login with discord</a> <a href="<%=discord%>" class="btn-outline-primary">Auth with discord</a>
<% } else if(member.discordID && user?.id === member.id) { %>
<a class="btn-outline-primary" id="un_discord">Unauth with discord!</a>
<% } %> <% } %>
<% if (user?.admin || user?.id === member.id) { %> <% if (user?.admin || user?.id === member.id) { %>
<a href="/users/<%=member.id%>/avatar" class="btn-outline-primary">Upload avatar</a> <a href="/users/<%=member.id%>/avatar" class="btn-outline-primary">Upload avatar</a>
@ -62,7 +64,12 @@
if (response.deleted) return; if (response.deleted) return;
alert("User is undeleted successfully!"); alert("User is undeleted successfully!");
location.reload() location.reload()
} else if (e.target.id == "toogle") } else if (e.target.id == "un_discord") {
const response = await fetch("/auth/discord/", {method:"DELETE"});
alert(await response.text());
location.reload()
}
else if (e.target.id == "toogle")
document.getElementById('user-edit').classList.toggle('no-active') document.getElementById('user-edit').classList.toggle('no-active')
}); });