gsdf
This commit is contained in:
+59
-11
@@ -1353,7 +1353,7 @@ class CommentSystem {
|
||||
} else if (currentUserId) {
|
||||
inputSection = this.renderInput();
|
||||
} else {
|
||||
inputSection = '<div class="login-placeholder"><a href="/login" class="login-trigger-btn">Login</a> to comment</div>';
|
||||
inputSection = '<div class="login-placeholder"></div>';
|
||||
}
|
||||
|
||||
const isLegacy = document.body.classList.contains('layout-legacy') || document.body.classList.contains('legacy-view');
|
||||
@@ -2237,15 +2237,22 @@ class CommentSystem {
|
||||
? `<div class="comment-avatar"><img src="/a/default.png"></div>`
|
||||
: `<div class="comment-avatar">${comment.username ? `<a href="/user/${comment.username}">` : ''}<img src="${comment.avatar_file ? `/a/${comment.avatar_file}` : (comment.avatar ? `/t/${comment.avatar}.webp` : '/a/default.png')}">${comment.username ? `</a>` : ''}</div>`;
|
||||
|
||||
const authorHtml = isAnonGuest
|
||||
? `<span class="comment-author">anonymous</span>`
|
||||
const isAnon = isAnonGuest || comment.is_anon || comment.anon_fingerprint || comment.username === 'anonymous' || (comment.username && comment.username.startsWith('anon_'));
|
||||
const anonFp = comment.anon_fingerprint || '';
|
||||
const anonShortFp = comment.anon_short_fingerprint || (anonFp ? anonFp.slice(7, 15) : '');
|
||||
const anonTripcodeHtml = anonShortFp
|
||||
? ` <span class="anon-tripcode" data-fingerprint="${this.escapeHtml(anonFp)}" tooltip="${this.escapeHtml(anonFp)} (OpenSSH Ed25519)">[${this.escapeHtml(anonShortFp)}]</span>`
|
||||
: '';
|
||||
|
||||
const authorHtml = isAnon
|
||||
? `<span class="comment-author">anonymous</span>${anonTripcodeHtml}`
|
||||
: (comment.username
|
||||
? `<a href="/user/${comment.username}" class="comment-author" tooltip="ID: ${authorUserId ?? ''}" ${authorUsernameColor ? `style="color: ${authorUsernameColor}"` : ''}>${this.escapeHtml(comment.display_name || comment.username)}</a>`
|
||||
: '<span class="comment-author">System</span>');
|
||||
|
||||
const anonDataAttrs = isAnonGuest ? '' : `data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}"`;
|
||||
const anonDataAttrs = isAnon ? '' : `data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}"`;
|
||||
|
||||
return `<div class="${commentClass} ${isDeleted ? 'deleted' : ''} ${isPinned ? 'pinned' : ''}" id="c${comment.id}" ${bannerStyle}>${avatarHtml}<div class="comment-body"><div class="comment-header"><div class="comment-header-left">${pinnedBadge}${authorHtml}${contextMarker}${backlinkHtml}</div><a href="#c${comment.id}" class="comment-time timeago" tooltip="${fullDate}" data-iso="${isoDate}" data-id="${comment.id}" ${anonDataAttrs}>${timeAgo}</a></div><div class="comment-content" data-raw="${this.escapeHtml(comment.content)}">${content}</div>${this.renderCommentAttachments(comment.files, comment.content)}${this.renderCommentPoll(comment.poll, comment.id, isAnonGuest ? null : comment.username)}<div class="comment-footer"><div class="comment-footer-right"><div class="comment-actions">${!isDeleted ? `${currentUserId ? `<button class="reply-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Reply"><i class="fa-solid fa-reply"></i></button><button class="quote-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Quote with Text"><i class="fa-solid fa-quote-left"></i></button>` : ''}<button class="report-comment-btn" data-id="${comment.id}" title="Report Comment" style="background:none;border:none;color:inherit;cursor:pointer;opacity:0.75;padding:0;"><i class="fa-solid fa-triangle-exclamation"></i></button>` : ''}${adminButtons}${userDeleteButton}</div></div></div></div><a href="#c${comment.id}" class="comment-permalink" title="Permalink" data-id="${comment.id}" ${anonDataAttrs}>#${comment.id}</a></div>${repliesHtml}`;
|
||||
return `<div class="${commentClass} ${isDeleted ? 'deleted' : ''} ${isPinned ? 'pinned' : ''}" id="c${comment.id}" ${bannerStyle}>${avatarHtml}<div class="comment-body"><div class="comment-header"><div class="comment-header-left">${pinnedBadge}${authorHtml}${contextMarker}${backlinkHtml}</div><a href="#c${comment.id}" class="comment-time timeago" tooltip="${fullDate}" data-iso="${isoDate}" data-id="${comment.id}" ${anonDataAttrs}>${timeAgo}</a></div><div class="comment-content" data-raw="${this.escapeHtml(comment.content)}">${content}</div>${this.renderCommentAttachments(comment.files, comment.content)}${this.renderCommentPoll(comment.poll, comment.id, isAnon ? null : comment.username)}<div class="comment-footer"><div class="comment-footer-right"><div class="comment-actions">${!isDeleted ? `${(currentUserId || window.f0ckAnonSSH?.pubkey) ? `<button class="reply-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Reply"><i class="fa-solid fa-reply"></i></button><button class="quote-btn" data-id="${comment.id}" data-username="${comment.username}" data-display="${this.escapeHtml(comment.display_name || '')}" title="Quote with Text"><i class="fa-solid fa-quote-left"></i></button>` : ''}<button class="report-comment-btn" data-id="${comment.id}" title="Report Comment" style="background:none;border:none;color:inherit;cursor:pointer;opacity:0.75;padding:0;"><i class="fa-solid fa-triangle-exclamation"></i></button>` : ''}${adminButtons}${userDeleteButton}</div></div></div></div><a href="#c${comment.id}" class="comment-permalink" title="Permalink" data-id="${comment.id}" ${anonDataAttrs}>#${comment.id}</a></div>${repliesHtml}`;
|
||||
}
|
||||
|
||||
timeAgo(date) {
|
||||
@@ -3461,18 +3468,59 @@ class CommentSystem {
|
||||
params.append('has_poll', '1');
|
||||
}
|
||||
|
||||
const csrfToken = window.f0ckSession?.csrf_token || '';
|
||||
let csrfToken = window.f0ckSession?.csrf_token || document.querySelector('meta[name="csrf-token"]')?.content || '';
|
||||
if (csrfToken) params.append('csrf_token', csrfToken);
|
||||
|
||||
const res = await fetch('/api/comments', {
|
||||
const fetchHeaders = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {})
|
||||
};
|
||||
|
||||
if ((!window.f0ckSession?.user || window.f0ckSession?.is_anon) && window.f0ckAnonSSH) {
|
||||
try {
|
||||
const ident = window.f0ckAnonSSH.getIdentity();
|
||||
if (ident && ident.pubkey) {
|
||||
const ts = Date.now();
|
||||
const msg = `anon-auth:${ts}:${ident.pubkey}`;
|
||||
const sig = await window.f0ckAnonSSH.sign(msg);
|
||||
fetchHeaders['X-SSH-Pubkey'] = ident.pubkey;
|
||||
fetchHeaders['X-SSH-Timestamp'] = String(ts);
|
||||
fetchHeaders['X-SSH-Signature'] = sig;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[ANON_COMMENTS] Failed to sign comment:', e);
|
||||
}
|
||||
}
|
||||
|
||||
let res = await fetch('/api/comments', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {})
|
||||
},
|
||||
headers: fetchHeaders,
|
||||
body: params
|
||||
});
|
||||
|
||||
// Auto-recovery if CSRF token drifted
|
||||
if (res.status === 403) {
|
||||
const errJson = await res.clone().json().catch(() => ({}));
|
||||
if (errJson.msg === 'Invalid CSRF token' || errJson.message === 'Invalid CSRF token') {
|
||||
try {
|
||||
const idRes = await fetch('/api/v2/anon/identity', { credentials: 'same-origin' });
|
||||
const idData = await idRes.json();
|
||||
if (idData && idData.csrf_token) {
|
||||
if (window.f0ckSession) window.f0ckSession.csrf_token = idData.csrf_token;
|
||||
const mCsrf = document.querySelector('meta[name="csrf-token"]');
|
||||
if (mCsrf) mCsrf.content = idData.csrf_token;
|
||||
params.set('csrf_token', idData.csrf_token);
|
||||
fetchHeaders['X-CSRF-Token'] = idData.csrf_token;
|
||||
res = await fetch('/api/comments', {
|
||||
method: 'POST',
|
||||
headers: fetchHeaders,
|
||||
body: params
|
||||
});
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (!res.ok) {
|
||||
if (res.status >= 500) {
|
||||
throw new Error(`Server returned ${res.status}`);
|
||||
|
||||
Reference in New Issue
Block a user