website/src/util.js
2023-04-03 15:29:51 +02:00

270 lines
7.6 KiB
JavaScript

const path = require('path');
const fs = require('fs-extra');
const got = require('got');
const crypto = require('crypto');
const { marked } = require('marked');
const { REST: DiscordRest } = require('@discordjs/rest');
const { Routes: DiscordRoutes } = require('discord-api-types/v10');
const merge = require('lodash.merge');
const logger = require('./logger');
const config = require('../config.json');
const baseLocale = require(`${__dirname}/../locales/en_US.json`);
const discordRest = new DiscordRest({ version: '10' }).setToken(config.discord.bot_token);
function fullUrl(request) {
return `${request.protocol}://${request.hostname}${request.originalUrl}`;
}
function getLocale(locale) {
const localeFileName = locale.replace('-', '_');
const path = `${__dirname}/../locales/${localeFileName}.json`;
if (fs.pathExistsSync(path)) {
const selectedLocale = require(path);
const finalLocale = merge({}, baseLocale, selectedLocale);
return finalLocale;
}
logger.warn(`Could not find locale ${localeFileName}! Loading en_US`);
return baseLocale;
}
function getRawDocs(locale, subpath, pageName) {
const localePath = path.join(__dirname, '../docs', locale.replace('-', '_'), subpath, `${pageName}.md`);
const defaultPath = path.join(__dirname, '../docs', 'en_US', subpath, `${pageName}.md`);
if (fs.existsSync(localePath)) {
return {
content: parseDocs(fs.readFileSync(localePath, 'utf8')),
MDLocale: locale,
};
} else if (fs.existsSync(defaultPath)) {
return {
content: parseDocs(fs.readFileSync(defaultPath, 'utf8')),
MDLocale: 'en-US'
};
}
return {
content: null,
MDLocale: null
};
}
function parseDocs(rawDocs) {
if (!rawDocs) {
return null;
}
let markedContent = marked(rawDocs);
markedContent = markedContent.replaceAll(/\[yt-iframe\]\(.{11}\)/g, (match) => {
const videoIDRegex = /(?<=\[yt-iframe\]\().*(?=\))/g;
const videoID = match.match(videoIDRegex)[0];
return `<div class="aspectratio-fallback"><iframe src="https://www.youtube-nocookie.com/embed/${videoID}" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>`;
});
const htmlContent = marked.parse(markedContent);
return htmlContent;
}
function apiGetRequest(path, headers) {
return got.get(`${config.api_base}${path}`, {
responseType: 'json',
throwHttpErrors: false,
https: {
rejectUnauthorized: false, // Needed for self-signed certificates on localhost testing
},
headers
});
}
function apiPostRequest(path, headers, json) {
return got.post(`${config.api_base}${path}`, {
responseType: 'json',
throwHttpErrors: false,
https: {
rejectUnauthorized: false, // Needed for self-signed certificates on localhost testing
},
headers,
json
});
}
function apiDeleteRequest(path, headers, json) {
return got.delete(`${config.api_base}${path}`, {
throwHttpErrors: false,
https: {
rejectUnauthorized: false, // Needed for self-signed certificates on localhost testing
},
headers,
json
});
}
async function register(registerData) {
const apiResponse = await apiPostRequest('/v1/register', {}, registerData);
if (apiResponse.statusCode !== 200) {
throw new Error(apiResponse.body.error);
}
return apiResponse.body;
}
async function login(username, password) {
const apiResponse = await apiPostRequest('/v1/login', {}, {
username,
password,
grant_type: 'password'
});
if (apiResponse.statusCode !== 200) {
throw new Error(apiResponse.body.error);
}
return apiResponse.body;
}
async function refreshLogin(request, response) {
const apiResponse = await apiPostRequest('/v1/login', {}, {
refresh_token: request.cookies.refresh_token,
grant_type: 'refresh_token'
});
if (apiResponse.statusCode !== 200) {
// TODO: Error message
throw new Error('Bad');
}
const tokens = apiResponse.body;
response.cookie('refresh_token', tokens.refresh_token, { domain: '.pretendo.network' });
response.cookie('access_token', tokens.access_token, { domain: '.pretendo.network' });
response.cookie('token_type', tokens.token_type, { domain: '.pretendo.network' });
request.cookies.refresh_token = tokens.refresh_token;
request.cookies.access_token = tokens.access_token;
request.cookies.token_type = tokens.token_type;
}
async function getUserAccountData(request, response, fromRetry=false) {
const apiResponse = await apiGetRequest('/v1/user', {
'Authorization': `${request.cookies.token_type} ${request.cookies.access_token}`
});
if (apiResponse.statusCode !== 200 && fromRetry === true) {
// TODO: Error message
throw new Error('Bad');
}
if (apiResponse.statusCode !== 200) {
await refreshLogin(request, response);
return await getUserAccountData(request, response, true);
}
return apiResponse.body;
}
async function updateDiscordConnection(discordUser, request, response, fromRetry=false) {
const apiResponse = await apiPostRequest('/v1/connections/add/discord', {
'Authorization': `${request.cookies.token_type} ${request.cookies.access_token}`
}, {
data: {
id: discordUser.id
}
});
if (apiResponse.statusCode !== 200 && fromRetry === true) {
// TODO: Error message
throw new Error('Bad');
}
if (apiResponse.statusCode !== 200) {
await refreshLogin(request, response);
await updateDiscordConnection(discordUser, request, response, true);
}
}
async function removeDiscordConnection(request, response, fromRetry = false) {
const apiResponse = await apiDeleteRequest('/v1/connections/remove/discord', {
'Authorization': `${request.cookies.token_type} ${request.cookies.access_token}`
});
if (apiResponse.statusCode !== 200 && fromRetry === true) {
// TODO: Error message
throw new Error('Bad');
}
if (apiResponse.statusCode !== 200) {
await refreshLogin(request, response);
await removeDiscordConnection(request, response, true);
}
}
function nintendoPasswordHash(password, pid) {
const pidBuffer = Buffer.alloc(4);
pidBuffer.writeUInt32LE(pid);
const unpacked = Buffer.concat([
pidBuffer,
Buffer.from('\x02\x65\x43\x46'),
Buffer.from(password)
]);
const hashed = crypto.createHash('sha256').update(unpacked).digest().toString('hex');
return hashed;
}
async function assignDiscordMemberSupporterRole(memberId, roleId) {
if (memberId && memberId.trim() !== '') {
await discordRest.put(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.supporter));
await discordRest.put(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, roleId));
}
}
async function assignDiscordMemberTesterRole(memberId) {
if (memberId && memberId.trim() !== '') {
await discordRest.put(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.tester));
}
}
async function removeDiscordMemberSupporterRole(memberId, roleId) {
if (memberId && memberId.trim() !== '') {
await discordRest.delete(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.supporter));
await discordRest.delete(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, roleId));
}
}
async function removeDiscordMemberTesterRole(memberId) {
if (memberId && memberId.trim() !== '') {
await discordRest.delete(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.tester));
}
}
module.exports = {
fullUrl,
getLocale,
getRawDocs,
parseDocs,
apiGetRequest,
apiPostRequest,
apiDeleteRequest,
register,
login,
refreshLogin,
getUserAccountData,
updateDiscordConnection,
removeDiscordConnection,
nintendoPasswordHash,
assignDiscordMemberSupporterRole,
assignDiscordMemberTesterRole,
removeDiscordMemberSupporterRole,
removeDiscordMemberTesterRole
};