Substitute illegal attachments with redacted thumbnail

This commit is contained in:
towards-a-new-leftypol 2023-08-24 18:07:37 -04:00
parent f2bdf5a279
commit 30fecd588f
3 changed files with 139 additions and 106 deletions

BIN
redacted.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

231
script.js
View File

@ -298,19 +298,21 @@ function parseRangeHeader(rangeHeader) {
function resolveResponse(resolve, reject) {
return function(e) {
var status = e.target.getResponseHeader("Status");
const status = e.target.getResponseHeader("Status");
if (status != null) {
var status_code = Number(status.split(" ")[0]);
const status_code = Number(status.split(" ")[0]);
if (status_code >= 200 && status_code < 300) {
resolve(e.target.responseText);
} else {
reject(new Error('API responded with ' + status));
reject(new Error('API responded with ' + status + ". " + e.target.responseText));
}
} else {
if (e.target.status >= 200 && e.target.status < 300) {
return resolve(e.target);
} else {
reject(new Error('API responded with ' + e.target.status));
reject(new Error('API responded with ' + e.target.status + ". " + e.target.responseText));
}
}
}
@ -341,6 +343,31 @@ function get(url, xhr_req_follower, headers) {
});
}
function post(url, body, xhr_req_follower, headers) {
return new Promise(function (resolve, reject) {
var req = new XMLHttpRequest();
xhr_req_follower(req);
req.onload = resolveResponse(resolve, reject);
req.onerror = reject;
req.open('POST', url);
if (headers) {
Object.entries(headers)
.forEach(function([header_name, header_value]) {
req.setRequestHeader(header_name, header_value);
});
}
req.setRequestHeader('Content-Type', 'application/json');
if (body) {
req.send(JSON.stringify(body));
} else {
req.send();
}
});
}
// Given a BigInt that is packed bytes, unpack the bytes into an ArrayBuffer
function unpackBytes(bigint) {
const buffer = new ArrayBuffer(8);
@ -384,100 +411,6 @@ function hammingDistance(buffer1, buffer2) {
return distance;
}
function parseFilePath(s) {
return JSON.parse(s);
}
function FileSize(s) {
this.filesize = s;
}
function tree(rows) {
var c = {};
for (var row of rows) {
var path = parseFilePath(row.path);
var tree = c;
var previous = c;
var filename = 'NOPATH';
for (var p of path) {
previous = tree;
if (p in tree) {
tree = tree[p];
} else {
var newtree = {};
tree[p] = newtree;
tree = newtree;
}
filename = p;
}
previous[filename] = new FileSize(row.filesize);
}
console.log(c);
return c;
}
function renderTree(rows) {
var list_elem = ul();
function draw(list_elem, t) {
Object.entries(t)
.forEach(function([key, val]) {
if (val instanceof FileSize) {
var contents = div(span(text(key)));
contents.appendChild(italic(text(val.filesize)));
list_elem.appendChild(contents);
} else {
var new_list = ul();
var elem = li(text(key));
elem.appendChild(new_list);
list_elem.appendChild(elem);
draw(new_list, val);
}
});
}
draw(list_elem, tree(rows));
return list_elem;
}
function assembleTable(rows) {
var t = document.createElement('table');
rows.forEach(function(r) {
var row = t.insertRow();
TableHeadings.forEach(function(header) {
var cell = row.insertCell();
cell.appendChild(header[1](r));
});
});
var thead = t.createTHead().insertRow();
TableHeadingNames.forEach(function(header) {
var th = document.createElement('th');
th.appendChild(text(header));
thead.appendChild(th);
});
var countElem = div(text(rows.length + ' rows'))
var wrapper = div();
wrapper.appendChild(t);
wrapper.appendChild(countElem);
return wrapper;
}
function text(s) {
return document.createTextNode(s);
}
@ -527,20 +460,31 @@ function mkSpamImgElement(img_description) {
var mime = img_description.mimetype;
var thumb_url;
if (mime == "audio/mpeg") {
var illegal = img_description.illegal;
console.log('img_description.illegal', img_description.illegal);
if (illegal) {
thumb_url = `/bin/?path=${GlobalVars.settings.redacted_thumbnail_path}&mimetype=image/jpeg`
} else if (mime == "audio/mpeg") {
thumb_url = `/bin/?path=${GlobalVars.settings.audio_mpeg_thumbnail_path}&mimetype=image/jpeg`
} else {
thumb_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}_thumbnail.jpg&mimetype=image/jpeg`
}
var image_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}.attachment&mimetype=${mime}`
img_elem.setAttribute('src', thumb_url);
img_elem.setAttribute('decoding', 'async');
img_elem.setAttribute('loading', 'lazy');
var a_elem = document.createElement('a');
a_elem.setAttribute('href', image_url);
a_elem.appendChild(img_elem);
var a_elem;
if (!illegal) {
var image_url = `/bin/?path=${GlobalVars.settings.content_directory}/${img_description.md5_hash}.attachment&mimetype=${mime}`
a_elem = document.createElement('a');
a_elem.setAttribute('href', image_url);
a_elem.appendChild(img_elem);
} else {
a_elem = div(img_elem);
}
var img_container_elem = div(a_elem);
img_container_elem.classList.add('post--image_container');
@ -570,6 +514,49 @@ function linkToBoard(website_name, board_name, thread_id) {
}
}
function attachmentCanBeMarkedIllegal(attachment) {
return attachment.phash != null && !attachment.illegal;
}
function shouldDisplayMarkIllegalButton(post) {
let result = false;
for (let attachment of (post.known_spam_post_attachment || [])) {
result = result || attachmentCanBeMarkedIllegal(attachment);
}
return result;
}
function isIllegal(post) {
let result = false;
for (let attachment of (post.known_spam_post_attachment || [])) {
result = result || attachment.illegal;
}
return result;
}
async function onClickMarkIllegal(phashes, e) {
console.log('CLICK', phashes);
e.stopPropagation();
e.preventDefault();
const url = new URL('/illegal', window.location.origin);
phashes.forEach(function(p) {
console.log('onClickMarkIllegal', typeof p, p);
url.searchParams.append('phash', p);
});
await post(url.toString(), null, cancel)
.then(function() {
location.reload();
})
.catch(caught.bind(this, "Failed to mark post illegal because:"));
}
function renderPostElem(post) {
const postContainer = div();
postContainer.classList.add('post');
@ -599,6 +586,34 @@ function renderPostElem(post) {
postHeader.appendChild(span(text((new Date(post.time_stamp).toUTCString()))));
if (shouldDisplayMarkIllegalButton(post)) {
const mark_illegal = span()
mark_illegal.classList.add('post--mark_illegal');
const mark_illegal_a = document.createElement('a');
mark_illegal_a.appendChild(text('Mark Illegal'));
mark_illegal_a.setAttribute('href', '#');
mark_illegal_a.setAttribute('title', 'Permanently delete associated pictures and thumbnails but keep metadata for future matching');
mark_illegal.appendChild(text('['));
mark_illegal.appendChild(mark_illegal_a);
mark_illegal.appendChild(text(']'));
const phashes = (post.known_spam_post_attachment || [])
.map(function(p) {
return bufferToHex(unpackBytes(BigInt(p.phash)));
});
mark_illegal_a.addEventListener('click',
onClickMarkIllegal.bind(this, phashes));
postHeader.appendChild(mark_illegal);
} else if (isIllegal(post)) {
const mark_illegal = span(text('illegal'))
mark_illegal.classList.add('post--is_illegal');
postHeader.appendChild(mark_illegal);
}
postContainer.appendChild(postHeader);
const postElem = div();
@ -767,9 +782,13 @@ function loadKnownSpamPosts(params) {
json.forEach(function (post) {
var postElem = renderOverviewPost(post);
postElem.addEventListener('click', function() {
changeUrl('/spam_post/' + post.text_post_id, new URLSearchParams(), true);
});
postElem.addEventListener('click',
changeUrl.bind(
this,
'/spam_post/' + post.text_post_id,
new URLSearchParams(),
true
));
mainElem.appendChild(postElem);
});

View File

@ -64,6 +64,20 @@ header {
flex: 1;
}
.post--header span.post--mark_illegal {
flex-basis: fit-content;
flex-grow: 0;
}
.post--header span.post--is_illegal {
flex-basis: fit-content;
flex-grow: 0;
color: orange;
font-weight: bold;
font-family: monospace;
text-transform: uppercase;
}
nav a {
margin: 1rem;
font-size: 1.5em;