This commit is contained in:
2026-09-13 04:05:59 +02:00
parent 90860b9279
commit 340c825019
48 changed files with 2727 additions and 532 deletions
+36 -10
View File
@@ -4,6 +4,7 @@ import lib from "../lib.mjs";
import f0cklib from "../routeinc/f0cklib.mjs";
import { createI18n } from "../i18n.mjs";
import { render502 } from "../private_items.mjs";
import { canAnonDo, canAnonMode, isAnonSession, isAnonymizeSession } from "../settings.mjs";
const auth = async (req, res, next) => {
if (!req.session)
@@ -13,9 +14,9 @@ const auth = async (req, res, next) => {
export default (router, tpl) => {
router.get(/\/user\/(?<user>[^/]+)\/?$/, async (req, res) => {
// When guest anonymization is active, user profiles must not be accessible without a session
if (cfg.main.guest_anonymize && !req.session) {
return res.redirect('/login');
// When anonymization is active, user profiles must not be accessible without an authenticated regular session
if (isAnonymizeSession(req.session)) {
return req.session ? res.redirect('/') : res.redirect('/login');
}
const user = decodeURIComponent(req.params.user);
const mime = req.cookies.mime !== undefined ? req.cookies.mime : (req.query?.mime || req.url.qs?.mime || null);
@@ -228,17 +229,24 @@ export default (router, tpl) => {
return res.reply({ code: 404, body: tpl.render('error', { message: 'Not found', tmp: null }, req) });
}
// When guest anonymization is active, user gallery pages must require authentication
if (cfg.main.guest_anonymize && !req.session && req.params.user && req.params.mode) {
return res.redirect('/login');
}
// Redirect anonymous users requesting /user/anonymous/favs to their personal shadow username favs
if (req.params.mode === 'favs' && req.params.user?.toLowerCase() === 'anonymous' && req.session?.is_anon && req.session?.login) {
res.writeHead(302, { Location: `/user/${encodeURIComponent(req.session.login.toLowerCase())}/favs` });
return res.end();
}
// When anonymization is active, user gallery pages must require authentication and hide other users
if (isAnonymizeSession(req.session) && req.params.user && req.params.mode) {
const targetUser = decodeURIComponent(req.params.user).toLowerCase();
const isSelf = req.session?.user && (
targetUser === req.session.user.toLowerCase() ||
(req.session.login && targetUser === req.session.login.toLowerCase())
);
if (!isSelf) {
return req.session ? res.redirect('/') : res.redirect('/login');
}
}
// Auto-persist strict mode from URL to session if it's there
if (req.session && (req.query?.strict !== undefined || req.url.qs?.strict !== undefined)) {
req.session.strict_mode = (req.query?.strict === '1' || req.url.qs?.strict === '1');
@@ -247,6 +255,11 @@ export default (router, tpl) => {
// Decode tag param once — browsers send title%3A... on hard reload, title:... via AJAX
const reqTag = req.params.tag ? decodeURIComponent(req.params.tag) : req.params.tag;
// Track tag browsing interest in user affinity profile
if (reqTag && req.session?.id && !reqTag.startsWith('title:')) {
f0cklib.updateUserTagAffinity({ user_id: req.session.id, tag: reqTag, scoreDelta: 2.0 }).catch(() => {});
}
const data = await (req.params.itemid ? f0cklib.getf0ck : f0cklib.getf0cks)({
user: req.params.user,
tag: reqTag,
@@ -405,8 +418,8 @@ export default (router, tpl) => {
// Hall columns for display
data.halls_slugs = Array.isArray(item.halls) ? item.halls.map(h => h.slug).join(',') : '';
data.user_halls_slugs = Array.isArray(item.user_halls) ? item.user_halls.map(h => h.slug).join(',') : '';
// When guest anonymization is active, suppress uploader identity, banner, avatar, and source URL
if (cfg.main.guest_anonymize && !req.session) {
// When guest or anon anonymization is active, suppress uploader identity, banner, avatar, and source URL
if (isAnonymizeSession(req.session)) {
if (item.src) item.src = null;
item.username = 'anonymous';
item.author_banner_file = null;
@@ -632,6 +645,19 @@ export default (router, tpl) => {
const modeMatch = req.url.pathname.match(/^\/mode\/(\d)/);
const mode = modeMatch ? +modeMatch[1] : 0;
if (isAnonSession(req.session)) {
if (!canAnonDo('filter') || !canAnonMode(mode)) {
if (req.headers['x-requested-with'] === 'XMLHttpRequest') {
return res.reply({
code: 403,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ success: false, msg: 'Mode not permitted for anonymous users' })
});
}
return res.redirect('/');
}
}
if (cfg.allowedModes[mode]) {
if (req.session) {
req.session.mode = mode;