<commit_before>const express = require('express');
const Ratelimit = require('express-brute');
const ratelimitStore = require('../util/RatelimitStore');
const config = require('../config/config');
const jwt = require('jwt-simple');
const passport = require('passport');
require('../util/passport')(passport);
const User = require('../models/user');

function PublicRouter(app) {
    const responseFactory = require("../util/ResponseFactory")(app);

    let router = express.Router()

    router.use(function(req, res, next) { // Force user to pick a username
        if(req.url == "/signout" || req.url == "/pick-username") return next(); // Allow the user to sign out or POST their new username
        if(req.user && !req.user.usernameSet && req.user.OAuthName) { // If the user has no username...
            return responseFactory.sendRenderedResponse("public/pick-username", req, res, { captcha: app.enableCaptcha, username: req.user.OAuthName.replace(/[^[a-zA-Z0-9-_]/g, "-").substring(0, 20), user: {name: ""}}); // Send the username picker
        }
        next(); // Otherwise, carry on...
    });

    router.post('/pick-username', function(req, res) {
        function renderResponse(errorMsg) {
            return responseFactory.sendRenderedResponse("public/pick-username", req, res, { captcha: app.enableCaptcha, error: { message: errorMsg || "An unknown error occurred" }, username: req.body.username, user: {name: ""} });
        }
        if(!req.user) res.redirect("/signup");
        if(req.user.usernameSet) res.redirect("/");
        let user = req.user;
        user.name = req.body.username;
        function doPickUsername() {
            user.setUserName(user.name, function(err) {
                if(err) return renderResponse(err.message);
                req.login(user, function(err) {
                    if (err) {
                        app.reportError("Unknown user login error.");
                        return renderResponse("An unknown error occurred.");
                    }
                    res.redirect("/?signedin=1");
                });
            });
        }
        if(app.enableCaptcha) {
            app.recaptcha.verify(req, error => {
                if(error) return renderResponse("Please fill in the captcha properly.");
                doPickUsername();
            });
        } else doPickUsername();
    });

    const ratelimitCallback = function (req, res, next, nextValidRequestDate) {
        function renderResponse(errorMsg) {
            return responseFactory.sendRenderedResponse("public/signup", req, res, { captcha: app.enableCaptcha, error: { message: errorMsg || "An unknown error occurred" }, username: req.body.username });
        }
        res.status(429);
        return renderResponse("You're doing that too fast.");
    }

    const signupRatelimit = new Ratelimit(ratelimitStore, {
        freeRetries: 3, // 3 signups per hour
        attachResetToRequest: false,
        refreshTimeoutOnRequest: false,
        minWait: 60*60*1000, // 1 hour
        maxWait: 60*60*1000, // 1 hour, 
        failCallback: ratelimitCallback,
        handleStoreError: error => app.reportError("Rate limit store error: " + error),
        proxyDepth: config.trustProxyDepth
    });

    router.get('/', function(req, res) {
        return responseFactory.sendRenderedResponse("public/index", req, res);
    });

    router.get('/deactivated', function(req, res) {
        if(req.user) res.redirect("/");
        return responseFactory.sendRenderedResponse("public/deactivated", req, res);
    });

    router.get('/sitemap.xml', function(req, res, next) {
        if(typeof config.host === undefined) return next();
        return responseFactory.sendRenderedResponse("public/sitemap.xml.html", req, res, null, "text/xml");
    });

    router.get('/signin', function(req, res) {
        if (req.user) return res.redirect("/");
        return responseFactory.sendRenderedResponse("public/signin", req, res);
    });

    router.post('/signin', function(req, res, next) {
        if (req.user) return res.redirect("/");
        if (!req.body.username || !req.body.password) return responseFactory.sendRenderedResponse("public/signin", req, res, { error: { message: "A username and password are required." }, username: req.body.username });
        passport.authenticate('local', function(err, user, info) {
            if (!user) return responseFactory.sendRenderedResponse("public/signin", req, res, { error: info.error || { message: "An unknown error occurred." }, username: req.body.username });
            req.login(user, function(err) {
                if (err) return responseFactory.sendRenderedResponse("public/signin", req, res, { error: { message: "An unknown error occurred." }, username: req.body.username });
                return res.redirect("/?signedin=1");
            });
        })(req, res, next);
    });

    router.get('/signup', function(req, res) {
        if (req.user) return res.redirect("/");
        return responseFactory.sendRenderedResponse("public/signup", req, res, { captcha: app.enableCaptcha });
    });

    router.get('/account', function(req, res) {
        if (!req.user) return res.redirect("/signin");
        res.redirect("/user/" + req.user.id);
    });

    router.get('/user/:userID', function(req, res) {
        User.findById(req.params.userID).then(user => {
            user.getLatestAvailablePixel().then(pixel => {
                return responseFactory.sendRenderedResponse("public/account", req, res, { profileUser: user, pixel: pixel, isLatestPixel: pixel ? ~((pixel.lastModified - user.lastPlace) / 1000) <= 3 : false, hasNewPassword: req.query.hasNewPassword });
            }).catch(err => {
                return responseFactory.sendRenderedResponse("public/account", req, res, { profileUser: user, pixel: null, isLatestPixel: false, hasNewPassword: req.query.hasNewPassword });            
            });
        }).catch(err => res.redirect("/"))
    });

    router.post('/signup', signupRatelimit.prevent, function(req, res, next) {
        function renderResponse(errorMsg) {
            return responseFactory.sendRenderedResponse("public/signup", req, res, { captcha: app.enableCaptcha, error: { message: errorMsg || "An unknown error occurred" }, username: req.body.username });
        }
        function doSignup() {
            User.register(req.body.username, req.body.password, function(user, error) {
                if(!user) return renderResponse(error.message);
                req.login(user, function(err) {
                    if (err) return renderResponse(null);
                    return res.redirect("/?signedup=1");
                });
            });
        }
        if (req.user) return res.redirect("/");
        if (!req.body.username || !req.body.password || !req.body.passwordverify) return renderResponse("Please fill out all the fields.")
        if (req.body.password != req.body.passwordverify) return renderResponse("The passwords you entered did not match.");
        if(app.enableCaptcha) {
            app.recaptcha.verify(req, error => {
                if(error) return renderResponse("Please fill in the captcha properly.");
                doSignup();
            });<commit_msg>Better looking profile page URLs, and don't show profile page for banned or deactivated users<commit_after>const express = require('express');
const Ratelimit = require('express-brute');
const ratelimitStore = require('../util/RatelimitStore');
const config = require('../config/config');
const jwt = require('jwt-simple');
const passport = require('passport');
require('../util/passport')(passport);
const User = require('../models/user');

function PublicRouter(app) {
    const responseFactory = require("../util/ResponseFactory")(app);

    let router = express.Router()

    router.use(function(req, res, next) { // Force user to pick a username
        if(req.url == "/signout" || req.url == "/pick-username") return next(); // Allow the user to sign out or POST their new username
        if(req.user && !req.user.usernameSet && req.user.OAuthName) { // If the user has no username...
            return responseFactory.sendRenderedResponse("public/pick-username", req, res, { captcha: app.enableCaptcha, username: req.user.OAuthName.replace(/[^[a-zA-Z0-9-_]/g, "-").substring(0, 20), user: {name: ""}}); // Send the username picker
        }
        next(); // Otherwise, carry on...
    });

    router.post('/pick-username', function(req, res) {
        function renderResponse(errorMsg) {
            return responseFactory.sendRenderedResponse("public/pick-username", req, res, { captcha: app.enableCaptcha, error: { message: errorMsg || "An unknown error occurred" }, username: req.body.username, user: {name: ""} });
        }
        if(!req.user) res.redirect("/signup");
        if(req.user.usernameSet) res.redirect("/");
        let user = req.user;
        user.name = req.body.username;
        function doPickUsername() {
            user.setUserName(user.name, function(err) {
                if(err) return renderResponse(err.message);
                req.login(user, function(err) {
                    if (err) {
                        app.reportError("Unknown user login error.");
                        return renderResponse("An unknown error occurred.");
                    }
                    res.redirect("/?signedin=1");
                });
            });
        }
        if(app.enableCaptcha) {
            app.recaptcha.verify(req, error => {
                if(error) return renderResponse("Please fill in the captcha properly.");
                doPickUsername();
            });
        } else doPickUsername();
    });

    const ratelimitCallback = function (req, res, next, nextValidRequestDate) {
        function renderResponse(errorMsg) {
            return responseFactory.sendRenderedResponse("public/signup", req, res, { captcha: app.enableCaptcha, error: { message: errorMsg || "An unknown error occurred" }, username: req.body.username });
        }
        res.status(429);
        return renderResponse("You're doing that too fast.");
    }

    const signupRatelimit = new Ratelimit(ratelimitStore, {
        freeRetries: 3, // 3 signups per hour
        attachResetToRequest: false,
        refreshTimeoutOnRequest: false,
        minWait: 60*60*1000, // 1 hour
        maxWait: 60*60*1000, // 1 hour, 
        failCallback: ratelimitCallback,
        handleStoreError: error => app.reportError("Rate limit store error: " + error),
        proxyDepth: config.trustProxyDepth
    });

    router.get('/', function(req, res) {
        return responseFactory.sendRenderedResponse("public/index", req, res);
    });

    router.get('/deactivated', function(req, res) {
        if(req.user) res.redirect("/");
        return responseFactory.sendRenderedResponse("public/deactivated", req, res);
    });

    router.get('/sitemap.xml', function(req, res, next) {
        if(typeof config.host === undefined) return next();
        return responseFactory.sendRenderedResponse("public/sitemap.xml.html", req, res, null, "text/xml");
    });

    router.get('/signin', function(req, res) {
        if (req.user) return res.redirect("/");
        return responseFactory.sendRenderedResponse("public/signin", req, res);
    });

    router.post('/signin', function(req, res, next) {
        if (req.user) return res.redirect("/");
        if (!req.body.username || !req.body.password) return responseFactory.sendRenderedResponse("public/signin", req, res, { error: { message: "A username and password are required." }, username: req.body.username });
        passport.authenticate('local', function(err, user, info) {
            if (!user) return responseFactory.sendRenderedResponse("public/signin", req, res, { error: info.error || { message: "An unknown error occurred." }, username: req.body.username });
            req.login(user, function(err) {
                if (err) return responseFactory.sendRenderedResponse("public/signin", req, res, { error: { message: "An unknown error occurred." }, username: req.body.username });
                return res.redirect("/?signedin=1");
            });
        })(req, res, next);
    });

    router.get('/signup', function(req, res) {
        if (req.user) return res.redirect("/");
        return responseFactory.sendRenderedResponse("public/signup", req, res, { captcha: app.enableCaptcha });
    });

    router.get('/account', function(req, res) {
        if (!req.user) return res.redirect("/signin");
        res.redirect("/@" + req.user.name);
    });

    router.get('/user/:userID', function(req, res) {
        User.findById(req.params.userID).then(user => {
            res.redirect(`/@${user.name}`);
        }).catch(err => res.redirect("/"))
    });

    router.get('/@:username', function(req, res) {
        User.findOne({name: req.params.username, banned: false, deactivated: false}).then(user => {
            user.getLatestAvailablePixel().then(pixel => {
                return responseFactory.sendRenderedResponse("public/account", req, res, { profileUser: user, pixel: pixel, isLatestPixel: pixel ? ~((pixel.lastModified - user.lastPlace) / 1000) <= 3 : false, hasNewPassword: req.query.hasNewPassword });
            }).catch(err => {
                return responseFactory.sendRenderedResponse("public/account", req, res, { profileUser: user, pixel: null, isLatestPixel: false, hasNewPassword: req.query.hasNewPassword });            
            });
        }).catch(err => res.redirect("/"))
    });

    router.post('/signup', signupRatelimit.prevent, function(req, res, next) {
        function renderResponse(errorMsg) {
            return responseFactory.sendRenderedResponse("public/signup", req, res, { captcha: app.enableCaptcha, error: { message: errorMsg || "An unknown error occurred" }, username: req.body.username });
        }
        function doSignup() {
            User.register(req.body.username, req.body.password, function(user, error) {
                if(!user) return renderResponse(error.message);
                req.login(user, function(err) {
                    if (err) return renderResponse(null);
                    return res.redirect("/?signedup=1");
                });
            });
        }
        if (req.user) return res.redirect("/");
        if (!req.body.username || !req.body.password || !req.body.passwordverify) return renderResponse("Please fill out all the fields.")
        if (req.body.password != req.body.passwordverify) return renderResponse("The passwords you entered did not match.");
        if(app.enableCaptcha) {
            app.recaptcha.verify(req, error => {
                if(error) return renderResponse("Please fill in the captcha properly.");
                doSignup();
            });
{'fraction_non_alphanumeric': 0.14911394110908968, 'fraction_numerical': 0.004851425106124924, 'mean_word_length': 2.6701285855588526, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4178971', 'n_tokens_mistral': 4161, 'n_tokens_neox': 4005, 'n_words': 942}