Auth flow overhaul

This commit is contained in:
Jemma
2024-04-13 19:11:19 -05:00
parent 4a2a315992
commit cec41754b6
26 changed files with 252 additions and 431 deletions

View File

@@ -1,172 +0,0 @@
const config = require('../../config.json');
const util = require('../util');
const moment = require('moment/moment');
const db = require('../database');
async function auth(request, response, next) {
const discovery = await db.getEndPoint(config.server_environment);
if (!discovery || discovery.status !== 0) {
let message = '';
const status = discovery ? discovery.status : -1;
switch (status) {
case 3:
message = 'Juxtaposition is currently under maintenance. Please try again later.';
break;
case 4:
message = 'Juxtaposition is now closed. Thank you for your support!';
break;
default:
message = 'Juxtaposition is currently unavailable. Please try again later.';
break;
}
if (request.directory === 'web') {
return response.render('web/login.ejs', {toast: message, cdnURL: config.CDN_domain,});
} else {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: message
});
}
}
// Get pid and fetch user data
if (request.cookies.access_token && request.directory === 'web') {
try {
request.user = await util.data.getUserDataFromToken(request.cookies.access_token);
} catch (e) {
response.clearCookie('access_token');
response.clearCookie('refresh_token');
if (request.path === '/login') {
request.lang = util.data.processLanguage();
request.token = request.cookies.access_token;
request.paramPackData = null;
return next();
} else {
//return response.render('web/login.ejs', {toast: 'Unable to reach the account server. Try again later.', cdnURL: config.CDN_domain,});
return response.redirect('/login');
}
}
request.pid = request.user ? request.user.pid : null;
} else if (request.headers['x-nintendo-servicetoken'] && request.directory !== 'web') {
request.pid = request.headers['x-nintendo-servicetoken'] ? await util.data.processServiceToken(request.headers['x-nintendo-servicetoken']) : null;
request.user = request.pid ? await util.data.getUserDataFromPid(request.pid) : null;
} else {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Juxtaposition is currently unavailable. Please try again later.'
});
}
// Set headers
request.paramPackData = request.headers['x-nintendo-parampack'] ? util.data.decodeParamPack(request.headers['x-nintendo-parampack']) : null;
response.header('X-Nintendo-WhiteList', config.whitelist);
// Ban check
if (request.user) {
if (config.server_environment !== 'prod' && request.user.serverAccessLevel !== 'test' && request.user.serverAccessLevel !== 'dev') {
response.status(500);
return response.send('No access. Must be tester or dev');
}
// Set moderator status
request.moderator = request.user.accessLevel == 2 || request.user.accessLevel == 3;
const user = await db.getUserSettings(request.pid);
if (user && moment(user.ban_lift_date) <= moment() && user.account_status !== 3) {
user.account_status = 0;
await user.save();
}
// This includes ban checks for both Juxt specifically and the account server, ideally this should be squashed
// assuming we support more gradual bans on PNID's
if (user && (user.account_status < 0 || user.account_status > 1 || request.user.accessLevel < 0)) {
if (includes(request, 'juxt')) {
let banMessage = '';
switch (user.account_status) {
case 2:
banMessage = `${request.user.username} has been banned until: ${ moment(user.ban_lift_date) }. \n\nReason: ${user.ban_reason}. \n\nIf you have any questions contact the developers in the Discord server.`;
break;
case 3:
banMessage = `${request.user.username} has been banned forever. \n\nReason: ${user.ban_reason}. \n\nIf you have any questions contact the developers in the Discord server.`;
break;
default:
banMessage = `${request.user.username} has been banned. \n\nIf you have any questions contact the developers in the Discord server.`;
}
return response.render('web/login.ejs', {toast: banMessage, cdnURL: config.CDN_domain,});
} else {
response.render(request.directory + '/partials/ban_notification.ejs', {
user: user,
moment: moment,
cdnURL: config.CDN_domain,
lang: request.lang,
pid: request.pid
});
}
}
}
// Juxt Website
if (request.directory === 'web') {
request.token = request.cookies.access_token;
// Open access pages
if (isStartOfPath(request.path, '/users/') ||
(isStartOfPath(request.path, '/titles/') && request.path !== '/titles/show') ||
(isStartOfPath(request.path, '/posts/') && !request.path.includes('/empathy'))) {
if (!request.pid) {
request.pid = 1000000000;
}
return next();
}
// Login endpoint
if (request.path === '/login') {
if (request.pid) {
return response.redirect('/titles/show?src=login');
}
return next();
}
if (!request.pid) {
return response.redirect('/login');
}
return next();
} else {
// This section includes checks if a user is a developer and adds exceptions for these cases
if (!request.pid) {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Unable to parse service token. Are you using a Nintendo Network ID?'
});
}
if (!request.user) {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Unable to fetch user data. Please try again later.'
});
}
if (request.user.accessLevel < 3 && !request.paramPackData) {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Missing auth headers'
});
}
const userAgent = request.headers['user-agent'];
if (request.user.accessLevel < 3 && (request.cookies.access_token || (!userAgent.includes('Nintendo WiiU') && !userAgent.includes('Nintendo 3DS')))) {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Invalid authentication method used.'
});
}
request.lang = util.data.processLanguage(request.paramPackData);
return next();
}
}
function isStartOfPath(path, value) {
return path.indexOf(value) === 0;
}
function includes(request, domain) {
return request.subdomains.findIndex(element => element.includes(domain)) !== -1;
}
module.exports = auth;

View File

@@ -0,0 +1,63 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-var-requires */
const config = require('../../config.json');
const moment = require('moment/moment');
const db = require('../database');
async function checkBan(request, response, next) {
if (!request.user && !request.guest_access && request.path !== '/login') {
return response.status(401).send('Ban Check Failed: No user or guest access');
} else if (!request.user && (request.guest_access || request.path === '/login')) {
return next();
}
if (config.server_environment !== 'prod' && request.user.serverAccessLevel !== 'test' && request.user.serverAccessLevel !== 'dev') {
response.status(500);
if (request.directory === 'web') {
return response.render('web/login.ejs', {toast: 'No access. Must be tester or dev', cdnURL: config.CDN_domain,});
} else {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'No access. Must be tester or dev'
});
}
}
// Set moderator status
request.moderator = request.user.accessLevel == 2 || request.user.accessLevel == 3;
const user = await db.getUserSettings(request.pid);
if (user && moment(user.ban_lift_date) <= moment() && user.account_status !== 3) {
user.account_status = 0;
await user.save();
}
// This includes ban checks for both Juxt specifically and the account server, ideally this should be squashed
// assuming we support more gradual bans on PNID's
if (user && (user.account_status < 0 || user.account_status > 1 || request.user.accessLevel < 0)) {
if (request.directory === 'web') {
let banMessage = '';
switch (user.account_status) {
case 2:
banMessage = `${request.user.username} has been banned until: ${ moment(user.ban_lift_date) }. \n\nReason: ${user.ban_reason}. \n\nIf you have any questions contact the developers in the Discord server.`;
break;
case 3:
banMessage = `${request.user.username} has been banned forever. \n\nReason: ${user.ban_reason}. \n\nIf you have any questions contact the developers in the Discord server.`;
break;
default:
banMessage = `${request.user.username} has been banned. \n\nIf you have any questions contact the developers in the Discord server.`;
}
return response.render('web/login.ejs', {toast: banMessage, cdnURL: config.CDN_domain,});
} else {
return response.render(request.directory + '/partials/ban_notification.ejs', {
user: user,
moment: moment,
cdnURL: config.CDN_domain,
lang: request.lang,
pid: request.pid,
PNID: request.user.username,
networkBan: request.user.accessLevel < 0
});
}
}
next();
}
module.exports = checkBan;

View File

@@ -1,41 +1,18 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable require-atomic-updates */
const config = require('../../config.json');
const util = require('../util');
const moment = require('moment/moment');
const db = require('../database');
async function auth(request, response, next) {
// Get pid and fetch user data
if (request.headers['x-nintendo-servicetoken']) {
request.pid = request.headers['x-nintendo-servicetoken'] ? await util.data.processServiceToken(request.headers['x-nintendo-servicetoken']) : null;
request.user = request.pid ? await util.data.getUserDataFromPid(request.pid) : null;
}
request.pid = request.headers['x-nintendo-servicetoken'] ? await util.data.processServiceToken(request.headers['x-nintendo-servicetoken']) : null;
request.user = request.pid ? await util.data.getUserDataFromPid(request.pid) : null;
// Set headers
request.paramPackData = request.headers['x-nintendo-parampack'] ? util.data.decodeParamPack(request.headers['x-nintendo-parampack']) : null;
response.header('X-Nintendo-WhiteList', config.whitelist);
// Ban check
if (request.user) {
// Set moderator status
request.moderator = request.user.accessLevel >= 2;
const user = await db.getUserSettings(request.pid);
if (user && moment(user.ban_lift_date) <= moment() && user.account_status !== 3) {
user.account_status = 0;
await user.save();
}
// This includes ban checks for both Juxt specifically and the account server, ideally this should be squashed
// assuming we support more gradual bans on PNID's
if (user && (user.account_status < 0 || user.account_status > 1 || request.user.accessLevel < 0)) {
response.render(request.directory + '/partials/ban_notification.ejs', {
user: user,
moment: moment,
cdnURL: config.CDN_domain,
lang: request.lang,
pid: request.pid
});
}
}
// This section includes checks if a user is a developer and adds exceptions for these cases
if (!request.pid) {
return response.render('portal/partials/ban_notification.ejs', {
@@ -43,18 +20,18 @@ async function auth(request, response, next) {
error: 'Unable to parse service token. Are you using a Nintendo Network ID?'
});
}
if (request.user.accessLevel < 3 && !request.paramPackData) {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Missing auth headers'
});
}
if (!request.user) {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Unable to fetch user data. Please try again later.'
});
}
if (request.user.accessLevel < 3 && !request.paramPackData) {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: 'Missing auth headers'
});
}
const userAgent = request.headers['user-agent'];
if (request.user.accessLevel < 3 && (request.cookies.access_token || (!userAgent.includes('Nintendo WiiU') && !userAgent.includes('Nintendo 3DS')))) {
return response.render('portal/partials/ban_notification.ejs', {
@@ -64,7 +41,6 @@ async function auth(request, response, next) {
}
request.lang = util.data.processLanguage(request.paramPackData);
request.directory = request.subdomains[1];
return next();
}

View File

@@ -0,0 +1,37 @@
const config = require('../../config.json');
const db = require('../database');
async function checkDiscovery(request, response, next) {
const discovery = await db.getEndPoint(config.server_environment);
if (!discovery || discovery.status !== 0) {
let message = '';
const status = discovery ? discovery.status : -1;
switch (status) {
case 3:
message = 'Juxtaposition is currently under maintenance. Please try again later.';
break;
case 4:
message = 'Juxtaposition is now closed. Thank you for your support!';
break;
default:
message = 'Juxtaposition is currently unavailable. Please try again later.';
break;
}
if (request.directory === 'web') {
return response.render('web/login.ejs', {toast: message, cdnURL: config.CDN_domain,});
} else {
return response.render('portal/partials/ban_notification.ejs', {
user: null,
error: message
});
}
} else {
request.guest_access = discovery ? discovery.guest_access : false;
request.new_users = discovery ? discovery.new_users : false;
}
next();
}
module.exports = checkDiscovery;

View File

@@ -1,51 +1,37 @@
const config = require('../../config.json');
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable @typescript-eslint/no-var-requires */
const util = require('../util');
const moment = require('moment/moment');
const db = require('../database');
async function auth(request, response, next) {
async function webAuth(request, response, next) {
// Get pid and fetch user data
request.lang = util.data.processLanguage();
request.paramPackData = null;
request.directory = 'web';
request.token = request.cookies.access_token;
if (request.cookies.access_token) {
try {
request.user = await util.data.getUserDataFromToken(request.token);
} catch (e) {
console.log(e);
if (request.path === '/login') {
return next();
}
return response.render('web/login.ejs', {toast: 'Unable to reach the account server. Try again later.', cdnURL: config.CDN_domain,});
try {
request.user = await util.data.getUserDataFromToken(request.cookies.access_token);
request.pid = request.user.pid;
} catch (e) {
const domain = request.get('host').replace('juxt', '');
response.clearCookie('access_token', {domain: domain, path: '/'});
response.clearCookie('refresh_token', {domain: domain, path: '/'});
response.clearCookie('token_type', {domain: domain, path: '/'});
if (request.path === '/login') {
request.lang = util.data.processLanguage();
request.token = request.cookies.access_token;
request.paramPackData = null;
return next();
}
request.pid = request.user ? request.user.pid : null;
}
// Ban check
if (request.user) {
// Set moderator status
request.moderator = request.user.accessLevel >= 2;
const user = await db.getUserSettings(request.pid);
if (user && moment(user.ban_lift_date) <= moment() && user.account_status !== 3) {
user.account_status = 0;
await user.save();
}
// This includes ban checks for both Juxt specifically and the account server, ideally this should be squashed
// assuming we support more gradual bans on PNID's
if (user && (user.account_status < 0 || user.account_status > 1 || request.user.accessLevel < 0)) {
return response.render('web/login.ejs', {toast: 'Your account has been suspended. For more information, log into https://pretendo.network/account', cdnURL: config.CDN_domain,});
}
}
request.token = request.cookies.access_token;
// Open access pages
if (isStartOfPath(request.path, '/users/') ||
(isStartOfPath(request.path, '/titles/') && request.path !== '/titles/show') ||
(isStartOfPath(request.path, '/posts/') && !request.path.includes('/empathy'))) {
if (!request.pid) {
(isStartOfPath(request.path, '/titles/') && request.path !== '/titles/show') ||
(isStartOfPath(request.path, '/posts/') && !request.path.includes('/empathy'))) {
if (!request.pid && request.guest_access) {
request.pid = 1000000000;
return next();
} else if (!request.pid) {
return response.redirect('/login');
}
return next();
}
// Login endpoint
if (request.path === '/login') {
@@ -54,8 +40,7 @@ async function auth(request, response, next) {
}
return next();
}
console.log(request.route);
if (!request.user && request.path !== '/') {
if (!request.pid) {
return response.redirect('/login');
}
@@ -66,4 +51,6 @@ function isStartOfPath(path, value) {
return path.indexOf(value) === 0;
}
module.exports = auth;
module.exports = webAuth;

View File

@@ -5,6 +5,10 @@ const endpointSchema = new Schema({
server_access_level: String,
topics: Boolean,
guest_access: Boolean,
new_users: {
type: Boolean,
default: true,
},
host: String,
api_host: String,
portal_host: String,

View File

@@ -3,7 +3,6 @@ const express = require('express');
const morgan = require('morgan');
const ejs = require('ejs');
const cookieParser = require('cookie-parser');
const detectVersion = require('./middleware/detectVersion');
const database = require('./database');
const logger = require('./logger');
const config = require('../config.json');
@@ -32,8 +31,6 @@ app.use(express.urlencoded({
}));
app.use(cookieParser());
app.use(detectVersion);
// import the servers into one
app.use(juxt_web);

View File

@@ -2,42 +2,67 @@ const express = require('express');
const subdomain = require('express-subdomain');
const logger = require('../../logger');
const routes = require('./routes');
const auth = require('../../middleware/auth');
const webAuth = require('../../middleware/webAuth');
const consoleAuth = require('../../middleware/consoleAuth');
const checkBan = require('../../middleware/checkBan');
const detectVersion = require('../../middleware/detectVersion');
const checkDiscovery = require('../../middleware/discovery');
const router = express.Router();
const console = express.Router();
const consoleRouter = express.Router();
const webRouter = express.Router();
// We want to check which domain we're running on before we fetch any files,
// but we don't care about discovery until we're making it to the consoles themselves
router.use(detectVersion);
router.use('/', routes.WEB_FILES);
router.use('/robots.txt', routes.ROBOTS);
router.use('/web', routes.PWA);
router.use(checkDiscovery);
// Create subdomains
logger.info('[JUXT-WEB] Creating \'Web\' subdomain');
router.use(subdomain('juxt', console));
router.use(subdomain('juxt-beta', console));
router.use(subdomain('juxt-dev', console));
router.use(subdomain('juxt', webRouter));
router.use(subdomain('juxt-beta', webRouter));
router.use(subdomain('juxt-dev', webRouter));
logger.info('[JUXT-WEB] Creating \'Wii U\' subdomain');
router.use(subdomain('portal.olv', console));
router.use(subdomain('portal-beta.olv', console));
router.use(subdomain('portal-dev.olv', console));
router.use(subdomain('portal.olv', consoleRouter));
router.use(subdomain('portal-beta.olv', consoleRouter));
router.use(subdomain('portal-dev.olv', consoleRouter));
logger.info('[JUXT-WEB] Creating \'3DS\' subdomain');
router.use(subdomain('ctr.olv', console));
router.use(subdomain('ctr-beta.olv', console));
router.use(subdomain('ctr-dev.olv', console));
router.use(subdomain('ctr.olv', consoleRouter));
router.use(subdomain('ctr-beta.olv', consoleRouter));
router.use(subdomain('ctr-dev.olv', consoleRouter));
// Setup routes
console.use('/titles/show', auth, routes.PORTAL_SHOW);
console.use('/titles', auth, routes.PORTAL_COMMUNITIES);
console.use('/communities', auth, routes.PORTAL_COMMUNITIES);
console.use('/topics', auth, routes.PORTAL_TOPICS);
console.use('/users', auth, routes.PORTAL_USER);
console.use('/posts', auth, routes.PORTAL_POST);
console.use('/feed', auth, routes.PORTAL_FEED);
console.use('/friend_messages', auth, routes.PORTAL_MESSAGES);
console.use('/news', auth, routes.PORTAL_NEWS);
console.use('/', routes.PORTAL_WEB);
console.use('/login', auth, routes.WEB_LOGIN);
console.use('/robots.txt', routes.ROBOTS);
console.use('/web', routes.PWA);
console.use('/admin', auth, routes.ADMIN);
// Setup routes for console
consoleRouter.use(consoleAuth);
consoleRouter.use(checkBan);
consoleRouter.use('/titles/show', routes.PORTAL_SHOW);
consoleRouter.use('/titles', routes.PORTAL_COMMUNITIES);
consoleRouter.use('/communities', routes.PORTAL_COMMUNITIES);
consoleRouter.use('/topics', routes.PORTAL_TOPICS);
consoleRouter.use('/users', routes.PORTAL_USER);
consoleRouter.use('/posts', routes.PORTAL_POST);
consoleRouter.use('/feed', routes.PORTAL_FEED);
consoleRouter.use('/friend_messages', routes.PORTAL_MESSAGES);
consoleRouter.use('/news', routes.PORTAL_NEWS);
// Setup routes for web
webRouter.use(webAuth);
webRouter.use(checkBan);
webRouter.use('/titles/show', routes.PORTAL_SHOW);
webRouter.use('/titles', routes.PORTAL_COMMUNITIES);
webRouter.use('/communities', routes.PORTAL_COMMUNITIES);
webRouter.use('/topics', routes.PORTAL_TOPICS);
webRouter.use('/users', routes.PORTAL_USER);
webRouter.use('/posts', routes.PORTAL_POST);
webRouter.use('/feed', routes.PORTAL_FEED);
webRouter.use('/friend_messages', routes.PORTAL_MESSAGES);
webRouter.use('/news', routes.PORTAL_NEWS);
webRouter.use('/login', routes.WEB_LOGIN);
webRouter.use('/admin', routes.ADMIN);
module.exports = router;

View File

@@ -41,6 +41,15 @@ const yeahLimit = rateLimit({
legacyHeaders: true,
});
router.get('/:post_id/oembed.json', async function (req, res) {
const post = await database.getPostByID(req.params.post_id.toString());
const doc = {
'author_name': post.screen_name,
'author_url': 'https://juxt.pretendo.network/users/show?pid=' + post.pid,
};
res.send(doc);
});
router.post('/empathy', yeahLimit, async function (req, res) {
const post = await database.getPostByID(req.body.postID);
if (!post) {

View File

@@ -49,7 +49,7 @@ router.get('/first', async function (req, res) {
});
router.post('/newUser', async function (req, res) {
if (req.pid === null) {
if (req.pid === null || !req.new_users || req.directory === 'web') {
return res.sendStatus(401);
}

View File

@@ -17,7 +17,32 @@ router.get('/menu', async function (req, res) {
});
router.get('/me', async function (req, res) {
await userPage(req, res, req.pid);
await userPage(req, res, req.pid);
});
router.get('/notifications.json', async function (req, res) {
const notifications = await database.getUnreadNotificationCount(req.pid);
const messagesCount = await database.getUnreadConversationCount(req.pid);
res.send(
{
message_count: messagesCount,
notification_count: notifications,
}
);
});
router.get('/downloadUserData.json', async function (req, res) {
res.set('Content-Type', 'text/json');
res.set('Content-Disposition', `attachment; filename="${req.pid}_user_data.json"`);
const posts = await POST.find({ pid: req.pid });
const userContent = await database.getUserSettings(req.pid);
const userSettings = await database.getUserContent(req.pid);
const doc = {
'user_content': userContent,
'user_settings': userSettings,
'posts': posts,
};
res.send(doc);
});
router.get('/me/settings', async function (req, res) {

View File

@@ -1,9 +1,6 @@
const express = require('express');
const router = express.Router();
const database = require('../../../../database');
const { POST } = require('../../../../models/post');
const path = require('path');
const auth = require('../../../../middleware/auth');
router.get('/', function (req, res) {
res.redirect('/titles/show');
@@ -34,127 +31,4 @@ router.get('/favicon.ico', function (req, res) {
res.sendFile('/images/favicon.ico', {root: path.join(__dirname, '../../../../webfiles/' + req.directory)});
});
router.get('/icons/:image_id.png', async function (req, res) {
res.set('Content-Type', 'image/png');
const community = await database.getCommunityByID(req.params.image_id.toString());
if (community !== null && community.browser_icon) {
if (community.browser_icon.indexOf('data:image/png;base64,') !== -1) {
res.send(Buffer.from(community.browser_icon.replace('data:image/png;base64,',''), 'base64'));
} else {
res.send(Buffer.from(community.browser_icon, 'base64'));
}
} else {
const user = await database.getUserSettings(req.params.image_id.toString());
if (user !== null) {
if (user.pfp_uri.indexOf('data:image/png;base64,') !== -1) {
res.send(Buffer.from(user.pfp_uri.replace('data:image/png;base64,',''), 'base64'));
} else {
res.send(Buffer.from(user.pfp_uri, 'base64'));
}
} else {
res.sendStatus(404);
}
}
});
router.get('/tip/:image_id.png', async function (req, res) {
res.set('Content-Type', 'image/png');
const community = await database.getCommunityByID(req.params.image_id.toString());
if (community !== null) {
if (community.browser_thumbnail.indexOf('data:image/png;base64,') !== -1) {
res.send(Buffer.from(community.browser_thumbnail.replace('data:image/png;base64,',''), 'base64'));
} else {
res.send(Buffer.from(community.browser_thumbnail, 'base64'));
}
} else {
const user = await database.getUserByPID(req.params.image_id.toString());
if (user !== null) {
if (user.pfp_uri.indexOf('data:image/png;base64,') !== -1) {
res.send(Buffer.from(user.pfp_uri.replace('data:image/png;base64,', ''), 'base64'));
} else {
res.send(Buffer.from(user.pfp_uri, 'base64'));
}
} else {
res.sendStatus(404);
}
}
});
router.get('/banner/:image_id.png', async function (req, res) {
res.set('Content-Type', 'image/png');
const community = await database.getCommunityByID(req.params.image_id.toString());
if (community !== null && community.WiiU_browser_header !== undefined) {
if (community.WiiU_browser_header.indexOf('data:image/png;base64,') !== -1) {
res.send(Buffer.from(community.WiiU_browser_header.replace('data:image/png;base64,',''), 'base64'));
} else {
res.send(Buffer.from(community.WiiU_browser_header, 'base64'));
}
} else {
res.sendStatus(404);
}
});
router.get('/screenshot/:image_id.png', async function (req, res) {
res.set('Content-Type', 'image/png');
const post = await database.getPostByID(req.params.image_id.toString());
if (post !== null && post.screenshot !== '') {
if (post.screenshot.indexOf('data:image/png;base64,') !== -1) {
res.send(Buffer.from(post.screenshot.replace('data:image/png;base64,',''), 'base64'));
} else {
res.send(Buffer.from(post.screenshot, 'base64'));
}
} else {
res.sendStatus(404);
}
});
router.get('/drawing/:image_id.png', async function (req, res) {
res.set('Content-Type', 'image/png');
const post = await database.getPostByID(req.params.image_id.toString());
if (post !== null && post.painting_uri !== '') {
if (post.painting_uri.indexOf('data:image/png;base64,') !== -1) {
res.send(Buffer.from(post.painting_uri.replace('data:image/png;base64,',''), 'base64'));
} else {
res.send(Buffer.from(post.painting_uri, 'base64'));
}
} else {
res.sendStatus(404);
}
});
router.get('/notifications.json', auth, async function (req, res) {
const notifications = await database.getUnreadNotificationCount(req.pid);
const messagesCount = await database.getUnreadConversationCount(req.pid);
res.send(
{
message_count: messagesCount,
notification_count: notifications,
}
);
});
router.get('/:post_id/oembed.json', auth, async function (req, res) {
const post = await database.getPostByID(req.params.post_id.toString());
const doc = {
'author_name': post.screen_name,
'author_url': 'https://juxt.pretendo.network/users/show?pid=' + post.pid,
};
res.send(doc);
});
router.get('/downloadUserData.json', auth, async function (req, res) {
res.set('Content-Type', 'text/json');
res.set('Content-Disposition', `attachment; filename="${req.pid}_user_data.json"`);
const posts = await POST.find({ pid: req.pid });
const userContent = await database.getUserSettings(req.pid);
const userSettings = await database.getUserContent(req.pid);
const doc = {
'user_content': userContent,
'user_settings': userSettings,
'posts': posts,
};
res.send(doc);
});
module.exports = router;

View File

@@ -1,6 +1,5 @@
module.exports = {
PORTAL_SHOW: require('./console/show'),
PORTAL_WEB: require('./console/web'),
PORTAL_COMMUNITIES: require('./console/communities'),
PORTAL_USER: require('./console/userpage'),
PORTAL_POST: require('./console/posts'),
@@ -12,4 +11,5 @@ module.exports = {
ROBOTS: require('./web/robots'),
PWA: require('./web/pwa'),
ADMIN: require('./admin/admin'),
WEB_FILES: require('./console/web'),
};

View File

@@ -38,7 +38,7 @@ router.post('/', async (req, res) => {
const pid = PNID.pid;
let discovery = await database.getEndPoint(PNID.serverAccessLevel);
let discovery = await database.getEndPoint(config.server_environment);
if (!discovery) {
discovery = {
status: 5

View File

@@ -318,7 +318,7 @@ function testOffline() {
}
function checkForUpdates() {
GET('/notifications.json', function updates(data) {
GET('/users/notifications.json', function updates(data) {
var notificationObj = JSON.parse(data.responseText);
var count =
notificationObj.message_count + notificationObj.notification_count;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -348,7 +348,7 @@ function reportPost(post) {
button.click();
}
function checkForUpdates() {
GET('/notifications.json', function updates(data) {
GET('/users/notifications.json', function updates(data) {
var notificationObj = JSON.parse(data.responseText);
var messages = document.getElementById("message-badge");
var news = document.getElementById("news-badge");

File diff suppressed because one or more lines are too long

View File

@@ -10,14 +10,17 @@
</script>
<%} else {%>
<script>
<%if(user.account_status === 1) {%>
wiiuErrorViewer.openByCodeAndMessage(5980009, '<%=user.user_id%> has been limited from posting until: \n\n<%= moment(user.ban_lift_date) %>.\n\nReason: <%=user.ban_reason%>\n\nIf you have any questions contact the developers in the Discord server.');
location.href = '/communities'
<% if(networkBan) {%>
wiiuErrorViewer.openByCodeAndMessage(5980010, '<%=PNID%> has been banned from the network.\n\nReason: <%=user.ban_reason%>\n\nIf you have any questions contact the developers in the Discord server.');
wiiuBrowser.closeApplication();
<%} else if(user.account_status === 1) {%>
wiiuErrorViewer.openByCodeAndMessage(5980009, '<%=PNID%> has been limited from posting until: \n\n<%= moment(user.ban_lift_date) %>.\n\nReason: <%=user.ban_reason%>\n\nIf you have any questions contact the developers in the Discord server.');
location.href = '/communities';
<%} else if(user.account_status === 2) {%>
wiiuErrorViewer.openByCodeAndMessage(5980010, '<%=user.user_id%> has been banned until: \n\n<%= moment(user.ban_lift_date) %>.\n\nReason: <%=user.ban_reason%>\n\nIf you have any questions contact the developers in the Discord server.');
wiiuErrorViewer.openByCodeAndMessage(5980010, '<%=PNID%> has been banned until: \n\n<%= moment(user.ban_lift_date) %>.\n\nReason: <%=user.ban_reason%>\n\nIf you have any questions contact the developers in the Discord server.');
wiiuBrowser.closeApplication();
<%} else if(user.account_status === 3) {%>
wiiuErrorViewer.openByCodeAndMessage(5980011, '<%=user.user_id%> has been banned forever.\n\nReason: <%=user.ban_reason%>\n\nIf you have any questions contact the developers in the Discord server.');
wiiuErrorViewer.openByCodeAndMessage(5980011, '<%=PNID%> has been banned forever.\n\nReason: <%=user.ban_reason%>\n\nIf you have any questions contact the developers in the Discord server.');
wiiuBrowser.closeApplication();
<%}%>
</script>

View File

@@ -87,7 +87,8 @@
</script>
<div class="wrapper">
<div class="account-form-wrapper">
<a class="logotype" href="/">
<h2>Account Creation is only available when you have a linked Wii U or 3DS.</h2>
<!--<a class="logotype" href="/">
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="39.876">
<g id="logo_type" data-name="logo type" transform="translate(-553 -467)">
<g id="logo" transform="translate(553 467)">
@@ -277,7 +278,7 @@
<button class="about-button"
onclick="window.location.replace('/titles')"><%= lang.setup.done_button %></button>
</div>
</div>
</div>-->
</div>
</div>
</div>

View File

@@ -279,7 +279,7 @@ function checkForUpdates() {
}
}
};
xhttp.open('GET', '/notifications.json', true);
xhttp.open('GET', '/users/notifications.json', true);
xhttp.send();
}
function POST(url, data, callback) {

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="/css/web.css">
<script src="/js/pjax.min.js"></script>
<script src="/js/web.js"></script>
<script src="/js/web.min.js"></script>
<link rel="manifest" href="https://juxt-web-cdn.b-cdn.net/web/manifest.json">
<!-- Global site tag (gtag.js) - Google Analytics Testing-->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-195842548-1"></script>

View File

@@ -49,7 +49,7 @@
<div class="community-page-post-box" id="post">
<div id="wrapper">
<%if(!post.removed) {%>
<% if((
<% if(pid !== 1000000000 && (
(community.permissions.open && community.type < 2) || (community.admins && community.admins.indexOf(pid) !==-1) ||
(pnid.accessLevel >= community.permissions.minimum_new_comment_access_level)
) && userSettings.account_status === 0) {%>
@@ -64,12 +64,6 @@
<% }); %>
</div>
</div>
<% if((
(community.permissions.open && community.type < 2) || (community.admins && community.admins.indexOf(pid) !==-1) ||
(pnid.accessLevel >= community.permissions.minimum_new_comment_access_level)
) && userSettings.account_status === 0) {%>
<%- include('partials/new_post', { pid, lang, id: post.community_id, name: post.screen_name, url: `/posts/${post.id}/new`, show: 'post', message_pid: '' }); %>
<%}%>
<div id="report-post-page" class="add-post-page official-user-post" style="display: none">
<form method="post" action="/posts/<%=post.id%>/report" id="report-form" name="report" data-is-own-title="1" data-is-identified="1">
<input type="hidden" name="post_id" id="report-post-id" value="<%= post.id %>"/>
@@ -104,8 +98,6 @@
<input type="submit" class="post-button fixed-bottom-button" value="Submit">
</div>
</form>
</div>
<div class="painting-wrapper">
<div id="painting-content">
<div class="tools">
<div>

View File

@@ -121,7 +121,7 @@
<%if(pnid.pid === pid) {%>
<div>
<h4>Download User Data</h4>
<h4 id="user-page-download-tab"><a href="/downloadUserData.json">Download</a></h4>
<h4 id="user-page-download-tab"><a href="/users/downloadUserData.json">Download</a></h4>
</div>
<%}%>
<% if (moderator && pnid.pid !== pid) { %>