commit d5d05b266744887e16171b8224aea67374a3ab10 Author: towards-a-new-leftypol Date: Thu Aug 24 18:07:37 2023 -0400 Initial commit - static website for SpamNoticer - mainline_http_script stolen from other project to base our pages off of, it's like a very small framework for a single page application diff --git a/index.html b/index.html new file mode 100644 index 0000000..1c33214 --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + + +

Hello World

+
+
+ + + diff --git a/jwt.base_64.txt b/jwt.base_64.txt new file mode 100644 index 0000000..0b26918 --- /dev/null +++ b/jwt.base_64.txt @@ -0,0 +1 @@ +eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic3BhbV9ub3RpY2VyIn0.j6-6HSBh-Wf5eQovT9cF1ZCNuxkQOqzBFtE3C8aTG3A diff --git a/mainline_http_script.js b/mainline_http_script.js new file mode 100644 index 0000000..5f0091c --- /dev/null +++ b/mainline_http_script.js @@ -0,0 +1,637 @@ +function prepend(elem, children) { + var child = elem.firstChild; + + if (child) { + elem.insertBefore(children, child); + } else { + elem.appendChild(children); + } +} + + +function _log() { + for (var arg of arguments) { + var pre = document.createElement('pre'); + pre.appendChild(text(arg.toString())); + document.body.appendChild(pre); + try { + prepend(document.body, pre); + } catch (e) { + var pre = document.createElement('pre'); + pre.appendChild(text(e.toString())); + document.body.appendChild(pre); + } + + } +} + +/* +var console = { + log: _log, + error: _log +}; +*/ + +var CurrentScore = null; + +var global_elements; +var GlobalElemSelectors = + [ 'style' + , 'style.loading' + , '.info' + ] + +var pageInfoText; + +var GlobalCancellableEvents = []; +var cancel = GlobalCancellableEvents.push.bind(GlobalCancellableEvents); + +/** + * Router + */ + +// [ fpart : next ], content +function RoutePart(fparts, content) { + return { + fparts, + content + } +} + +function iter(iarray) { + var i = 0; + + return function (f, g) { + console.log(i, iarray.length, iarray); + if (i < iarray.length) { + console.log("calling", f, "with", iarray[i]); + f(iarray[i++]); + } else { + console.log("calling", g); + g(); + } + } +} + +function resolvePath(routes, path, query_params) { + console.log("resolvePath:", arguments); + var next = iter(path); + + function goRoute(path_data, route_part, path_part) { + var found = false; + + console.log(arguments); + for (var [fpart, next_route_part] of route_part.fparts) { + var parsed_part = fpart(path_part); + + if (parsed_part) { + console.log("parsed part:", parsed_part); + path_data.push(parsed_part); + + next( + goRoute.bind(this, path_data, next_route_part), + resolve.bind(this, path_data, next_route_part) + ); + + found = true; + } + } + + if (!found) { + throw new Error("404 " + path_data.join('/') + '/' + path_part); + } + } + + function resolve(path_data, route_part) { + console.log('calling content'); + console.log(path_data, route_part); + route_part.content(path_data, query_params); + } + + var p = []; + next(goRoute.bind(this, p, routes), resolve.bind(this, p, routes)); +} + +function match(re) { + return function (s) { + if (re.test(s)) { + return s; + } + } +} + +var ROUTES = RoutePart([ + [match(/^s$/), new RoutePart([], handleSearch)], + [match(/^[a-f0-9]{40}$/), new RoutePart([], handleInfo)] +], loadTop); + +/** + * Functions + */ + +function resolveResponse(resolve, reject) { + return function(e) { + var status = e.target.getResponseHeader("Status"); + if (status != null) { + var 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)); + } + } else { + if (e.target.status >= 200 && e.target.status < 300) { + return resolve(e.target.responseText); + } else { + reject(new Error('API responded with ' + e.target.status)); + } + } + } +} + +function cancelGlobalEvts() { + while (GlobalCancellableEvents.length) { + GlobalCancellableEvents.pop().abort(); + } +} + +function get(url, xhr_req_follower) { + return new Promise(function (resolve, reject) { + var req = new XMLHttpRequest(); + xhr_req_follower(req); + req.onload = resolveResponse(resolve, reject); + req.onerror = reject; + req.open('GET', url); + req.send(); + }); +} + +var HexArray = "0123456789abcdef"; + +function bytesToHex(uint8arr) { + var hex_encoded = ""; + + for (var i=0; i < uint8arr.length; i++) { + var j = uint8arr[i] & 0xFF; + hex_encoded += HexArray[j >>> 4]; + hex_encoded += HexArray[j & 0x0F]; + } + + return hex_encoded; +} + +var ESC_STR = '$ESCAPE_PIPE_SYMBOL'; + +function splitRawRow(raw_row) { + return raw_row + .replace('\\|', ESC_STR) + .split('|') + .map(function(s) { + return s.replace(ESC_STR, '|') + .trim(); + }) +} + +function parseTable(results) { + var raw_rows = results.split('\n').slice(0, -1); + var headers = splitRawRow(raw_rows[0]); + + return raw_rows.slice(2, -1) + .map(splitRawRow) + .map(function(row) { + return row.reduce(function(acc, val, i) { + acc[headers[i]] = val; + return acc; + }, + {}); + }) +} + + +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); +} + +function _mkelem(etype, child) { + var elem = document.createElement(etype); + + if (child) { + elem.appendChild(child); + } + + return elem; +} + +var div = _mkelem.bind(this, 'div'); +var li = _mkelem.bind(this, 'li'); +var span = _mkelem.bind(this, 'span'); +var italic = _mkelem.bind(this, 'i'); +var bold = _mkelem.bind(this, 'b'); +var ul = document.createElement.bind(document, 'ul'); + +function magnetLinkHash(m) { + return m.split(':').slice(-1)[0]; +} + +function name(r) { + var info_hash = magnetLinkHash(r.magnet); + var a = document.createElement('a'); + a.href = window.location.origin + + '/' + info_hash + '?dn=' + encodeURIComponent(r.name.slice(0, 75)); + a.addEventListener('click', aClickNav); + a.appendChild(text(r.name)); + + return a; +} + +function magnet(r) { + var a = document.createElement('a'); + + a.href = r.magnet + '&dn=' + encodeURIComponent(r.name.slice(0, 75)); + a.appendChild(text(String.fromCodePoint(129522) + ':?xt')); + + return a; +} + +/* +calculateScore :: Int -> POSIXTime -> Double +calculateScore n t = (e ** ((log maxDbl / endt) * (x - t0)) - 1) * (fromIntegral n) + where + maxDbl = 10 ** 300 + t0 = 1572391617 + endt = t0 + (1.577 * 10**10) + x = realToFrac t + e = exp 1 + +inverseScore :: Double -> Integer +inverseScore score = round $ ((log (score + 1)) / (log maxDbl / endt) + t0) + where + maxDbl = 10 ** 300 + t0 = 1572391617 + endt = t0 + (1.577 * 10**10) +*/ + +function currentScore() { + var t0 = 1572391617; + var x = Date.now() / 1000; + var endt = t0 + (1.577 * 10**10) + + return Math.E ** ((Math.log(10 ** 300) / endt) * ((x - t0) - 1)) +} + +function score(r) { + score = Number(r.score); + return text((Math.log(score / CurrentScore)).toFixed(2)); +} + +function invertScore(score) { + var t0 = 1572391617; + var maxDbl = 10 ** 300 + var endt = t0 + (1.577 * 10 ** 10) + return Math.round((Math.log(score + 1) / (Math.log(maxDbl) / endt)) + t0); +} + +var TableHeadings = + [ ['Name', name ] + , ['Size', function(r) { return text(r.total_size) }] + , ['Files', function(r) { return text(r.filecount) }] + , ['', magnet] + , ['Score', score] + ]; + +var TableHeadingNames = TableHeadings.map(function(t){ return t[0]; }); + +function keepElements(elem_selectors) { + var document_root = document.querySelector('p'); + document_root.innerHTML = ''; + + for (var i=0; i < elem_selectors.length; i++) { + var sel = elem_selectors[i]; + var elem = global_elements[sel]; + + document_root.appendChild(elem); + } +} + +function ensureElementExist(selector) { + var document_root = document.querySelector('p'); + var elem = document_root.querySelector(selector); + + if (!elem) { + document_root.appendChild(global_elements[selector]); + } + +} + +function loadTop() { + //TODO: dispatch changeurl event + cancelGlobalEvts(); + ensureElementExist('style.loading'); + pageInfoText.innerText = 'Loading Top 100...'; + get('/cgi-bin/top_100', cancel) + .then(function(response) { + CurrentScore = currentScore(); + console.log("Current score:", CurrentScore); + + var document_root = document.querySelector('p'); + var t = parseTable(response); + console.log(t); + keepElements(['style', '.info']); + pageInfoText.innerText = 'Top 100'; + document_root.appendChild(assembleTable(t)); + }) + .catch(caught.bind(this, "Failed to load top 100: ")); +} + +function caught(m, e) { + console.error(m); + console.error(e); + alert(new Error(m + e.message)); +}; + +function loadInfo(info_hash) { + var preLoad_executed = false; + var page = document.createElement('div'); + + function preLoad() { + if (preLoad_executed) { + return; + } + + preLoad_executed = true; + keepElements(['style', '.info']); + pageInfoText.innerText = info_hash; + document.querySelector('p').appendChild(page); + } + + ensureElementExist('style.loading'); + pageInfoText.innerText = 'Loading info for ' + info_hash; + + cancelGlobalEvts(); + + get('/cgi-bin/files?i=' + info_hash, cancel) + .then(function(response) { + preLoad(); + var files = parseTable(response); + console.log(files); + var h = document.createElement('h2'); + h.innerText = 'Contents'; + page.appendChild(h); + var t = renderTree(files); + page.appendChild(t); + }) + .catch(caught.bind(this, "Failed to info details. Reason:")); + + get('/cgi-bin/info?i=' + info_hash, cancel) + .then(function(response) { + preLoad(); + var info = parseTable(response)[0]; + pageInfoText.innerText = info.name; + var first_seen = new Date(info.added.split('.')[0]+'Z'); + var mlink = magnet(info); + mlink.innerText = mlink.href; + + var last_seen = new Date(Math.min( + invertScore(Number(info.score)) * 1000, + new Date().getTime()) + ); + + prepend(page, div(text('First Indexed: ' + first_seen))); + prepend(page, div(text('Approximately last seen: ' + last_seen))); + var filecount = div(text('Files: ')); + filecount.appendChild(bold(text(info.filecount))) + prepend(page, filecount); + var total_size = div(text('Total Size: ')); + total_size.appendChild(bold(text(info.total_size))) + prepend(page, total_size); + prepend(page, div(mlink)); + }) + .catch(caught.bind(this, "Failed to load file list. Details:")); +} + +function loadResults(search_query) { + var encoder = new TextEncoder(); + var hex = bytesToHex(encoder.encode(search_query)); + console.log(hex); + cancelGlobalEvts(); + ensureElementExist('style.loading'); + pageInfoText.innerText = 'Loading results for "' + search_query + '"...'; + get('/cgi-bin/search?q=' + hex, cancel) + .then(function(response) { + CurrentScore = currentScore(); + console.log("Current score:", CurrentScore); + + var t = assembleTable(parseTable(response)); + var document_root = document.querySelector('p'); + + keepElements(['style', '.info']) + pageInfoText.innerText = 'Results for "' + search_query + '"'; + document_root.appendChild(t); + }) + .catch(caught.bind(this, "Failed to results: ")); +} + +function changeUrl(path, search_query) { + var event = new CustomEvent( + 'urlchange', + { + detail: { + path: path, + query: search_query + } + }); + + window.dispatchEvent(event); +} + +function searchInputHandler() { + var input = document.querySelector("input"); + var btn = document.querySelector("button"); + + btn.addEventListener('click', function() { + var search_query = input.value; + window.history.pushState(null, "", + window.location.origin + + '/s?q=' + encodeURIComponent(search_query)); + changeUrl('/s', { q: search_query }); + }); + + input.addEventListener('keydown', function(e) { + if (e.keyCode === 13) { + e.preventDefault(); + btn.click(); + } + }); +} + +function handleSearch(_, query_params) { + var search_query = query_params.q; + + if (!search_query) { + console.log("nothing to query"); + return; + } else { + console.log(search_query); + loadResults(search_query); + } +} + +function handleInfo(parts, query_params) { + console.log('info request', parts, query_params); + loadInfo(parts[0]); +} + +function onUrlChange(e) { + var path = e.detail.path.split('/').filter(function(s){ return s.length; }); + console.log(e, e.detail, path); + resolvePath(ROUTES, path, e.detail.query); +} + +function aClickNav(e) { + e.preventDefault(); + e.stopPropagation(); + console.log(this, this.href); + window.history.pushState(null, "", this.href); + onRealUrlChange(); +} + +function bindEventHandlers() { + window.addEventListener('urlchange', onUrlChange); + window.addEventListener('popstate', onRealUrlChange); +} + +function gatherElements() { + global_elements = {}; + var qs; + + for (var i=0; i < GlobalElemSelectors.length; i++) { + var sel = GlobalElemSelectors[i]; + var elem = document.querySelector(sel); + global_elements[sel] = elem; + } +} + +function parseQueryParams(querystring) { + return querystring.split('&') + .map(function(part) { + return part.split('=').map(decodeURIComponent); + }) + .reduce(function(acc, pair) { return { [pair[0]]: pair[1] } }, {}); +} + +function onRealUrlChange() { + var path = window.location.pathname; + var query_params = parseQueryParams(window.location.search.substring(1)); + changeUrl(path, query_params); +} + +function initPageInfoText() { + pageInfoText = document.createElement('div'); + pageInfoText.className = 'info'; + prepend(document.querySelector('p'), pageInfoText); +} + +/** + * Init + */ + +initPageInfoText(); +gatherElements(); +bindEventHandlers(); +searchInputHandler(); +onRealUrlChange(); + diff --git a/script.js b/script.js new file mode 100644 index 0000000..10acc51 --- /dev/null +++ b/script.js @@ -0,0 +1,733 @@ +function prepend(elem, children) { + var child = elem.firstChild; + + if (child) { + elem.insertBefore(children, child); + } else { + elem.appendChild(children); + } +} + + +function _log() { + for (var arg of arguments) { + var pre = document.createElement('pre'); + pre.appendChild(text(arg.toString())); + document.body.appendChild(pre); + try { + prepend(document.body, pre); + } catch (e) { + var pre = document.createElement('pre'); + pre.appendChild(text(e.toString())); + document.body.appendChild(pre); + } + + } +} + +/* +var console = { + log: _log, + error: _log +}; +*/ + +var CurrentScore = null; + +var global_elements; +var GlobalElemSelectors = + [ 'style' + , 'style.loading' + , '.info' + ] + +var GlobalVars = {}; + +var pageInfoText; + +var GlobalCancellableEvents = []; +var cancel = GlobalCancellableEvents.push.bind(GlobalCancellableEvents); + +/** + * Router + */ + +// [ fpart : next ], content +function RoutePart(fparts, content) { + return { + fparts, + content + } +} + +function iter(iarray) { + var i = 0; + + return function (f, g) { + console.log(i, iarray.length, iarray); + if (i < iarray.length) { + console.log("calling", f, "with", iarray[i]); + f(iarray[i++]); + } else { + console.log("calling", g); + g(); + } + } +} + +function resolvePath(routes, path, query_params) { + console.log("resolvePath:", arguments); + var next = iter(path); + + function goRoute(path_data, route_part, path_part) { + var found = false; + + console.log("Route part:", route_part); + console.log("Route part fparts:", route_part.fparts); + + for (var [fpart, next_route_part] of route_part.fparts) { + var parsed_part = fpart(path_part); + + if (parsed_part) { + console.log("parsed part:", parsed_part); + path_data.push(parsed_part); + + next( + goRoute.bind(this, path_data, next_route_part), + resolve.bind(this, path_data, next_route_part) + ); + + found = true; + } + } + + if (!found) { + throw new Error("404 " + path_data.join('/') + '/' + path_part); + } + } + + function resolve(path_data, route_part) { + console.log('calling content'); + console.log(path_data, route_part); + route_part.content(path_data, query_params); + } + + var p = []; + next(goRoute.bind(this, p, routes), resolve.bind(this, p, routes)); +} + +function match(re) { + return function (s) { + if (re.test(s)) { + return s; + } + } +} + +/* +var ROUTES = RoutePart([ + [match(/^s$/), new RoutePart([], handleSearch)], + [match(/^[a-f0-9]{40}$/), new RoutePart([], handleInfo)] +], loadTop); +*/ + +var ROUTES = RoutePart( + [ + [ match(/^static$/) + , new RoutePart( + [ + [ match(/^index\.html$/) + , new RoutePart([], handlePageRoot) + ] + ] + , null + ) + ] + ] + , null +); + +/** + * Functions + */ + +function resolveResponse(resolve, reject) { + return function(e) { + var status = e.target.getResponseHeader("Status"); + if (status != null) { + var 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)); + } + } else { + if (e.target.status >= 200 && e.target.status < 300) { + return resolve(e.target.responseText); + } else { + reject(new Error('API responded with ' + e.target.status)); + } + } + } +} + +function cancelGlobalEvts() { + while (GlobalCancellableEvents.length) { + GlobalCancellableEvents.pop().abort(); + } +} + +function get(url, 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('GET', url); + + if (headers) { + Object.entries(headers) + .forEach(function([header_name, header_value]) { + req.setRequestHeader(header_name, header_value); + }); + } + + req.send(); + }); +} + +var HexArray = "0123456789abcdef"; + +function bytesToHex(uint8arr) { + var hex_encoded = ""; + + for (var i=0; i < uint8arr.length; i++) { + var j = uint8arr[i] & 0xFF; + hex_encoded += HexArray[j >>> 4]; + hex_encoded += HexArray[j & 0x0F]; + } + + return hex_encoded; +} + +var ESC_STR = '$ESCAPE_PIPE_SYMBOL'; + +function splitRawRow(raw_row) { + return raw_row + .replace('\\|', ESC_STR) + .split('|') + .map(function(s) { + return s.replace(ESC_STR, '|') + .trim(); + }) +} + +function parseTable(results) { + var raw_rows = results.split('\n').slice(0, -1); + var headers = splitRawRow(raw_rows[0]); + + return raw_rows.slice(2, -1) + .map(splitRawRow) + .map(function(row) { + return row.reduce(function(acc, val, i) { + acc[headers[i]] = val; + return acc; + }, + {}); + }) +} + + +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); +} + +function _mkelem(etype, child) { + var elem = document.createElement(etype); + + if (child) { + elem.appendChild(child); + } + + return elem; +} + +var div = _mkelem.bind(this, 'div'); +var li = _mkelem.bind(this, 'li'); +var span = _mkelem.bind(this, 'span'); +var italic = _mkelem.bind(this, 'i'); +var bold = _mkelem.bind(this, 'b'); +var ul = document.createElement.bind(document, 'ul'); + +function magnetLinkHash(m) { + return m.split(':').slice(-1)[0]; +} + +function name(r) { + var info_hash = magnetLinkHash(r.magnet); + var a = document.createElement('a'); + a.href = window.location.origin + + '/' + info_hash + '?dn=' + encodeURIComponent(r.name.slice(0, 75)); + a.addEventListener('click', aClickNav); + a.appendChild(text(r.name)); + + return a; +} + +function magnet(r) { + var a = document.createElement('a'); + + a.href = r.magnet + '&dn=' + encodeURIComponent(r.name.slice(0, 75)); + a.appendChild(text(String.fromCodePoint(129522) + ':?xt')); + + return a; +} + +/* +calculateScore :: Int -> POSIXTime -> Double +calculateScore n t = (e ** ((log maxDbl / endt) * (x - t0)) - 1) * (fromIntegral n) + where + maxDbl = 10 ** 300 + t0 = 1572391617 + endt = t0 + (1.577 * 10**10) + x = realToFrac t + e = exp 1 + +inverseScore :: Double -> Integer +inverseScore score = round $ ((log (score + 1)) / (log maxDbl / endt) + t0) + where + maxDbl = 10 ** 300 + t0 = 1572391617 + endt = t0 + (1.577 * 10**10) +*/ + +function currentScore() { + var t0 = 1572391617; + var x = Date.now() / 1000; + var endt = t0 + (1.577 * 10**10) + + return Math.E ** ((Math.log(10 ** 300) / endt) * ((x - t0) - 1)) +} + +function score(r) { + score = Number(r.score); + return text((Math.log(score / CurrentScore)).toFixed(2)); +} + +function invertScore(score) { + var t0 = 1572391617; + var maxDbl = 10 ** 300 + var endt = t0 + (1.577 * 10 ** 10) + return Math.round((Math.log(score + 1) / (Math.log(maxDbl) / endt)) + t0); +} + +var TableHeadings = + [ ['Name', name ] + , ['Size', function(r) { return text(r.total_size) }] + , ['Files', function(r) { return text(r.filecount) }] + , ['', magnet] + , ['Score', score] + ]; + +var TableHeadingNames = TableHeadings.map(function(t){ return t[0]; }); + +function keepElements(elem_selectors) { + var document_root = document.querySelector('main'); + document_root.innerHTML = ''; + + for (var i=0; i < elem_selectors.length; i++) { + var sel = elem_selectors[i]; + var elem = global_elements[sel]; + + document_root.appendChild(elem); + } +} + +function ensureElementExist(selector) { + var document_root = document.querySelector('main'); + var elem = document_root.querySelector(selector); + + if (!elem) { + document_root.appendChild(global_elements[selector]); + } + +} + +function loadJwt() { + cancelGlobalEvts(); +} + +function loadTop() { + //TODO: dispatch changeurl event + cancelGlobalEvts(); + ensureElementExist('style.loading'); + pageInfoText.innerText = 'Loading Top 100...'; + get('/cgi-bin/top_100', cancel) + .then(function(response) { + CurrentScore = currentScore(); + console.log("Current score:", CurrentScore); + + var document_root = document.querySelector('main'); + var t = parseTable(response); + console.log(t); + keepElements(['style', '.info']); + pageInfoText.innerText = 'Top 100'; + document_root.appendChild(assembleTable(t)); + }) + .catch(caught.bind(this, "Failed to load top 100: ")); +} + +function caught(m, e) { + console.error(m); + console.error(e); + alert(new Error(m + e.message)); +}; + +function mkSpamImgElement(img_description) { + console.log(img_description); + var img_elem = document.createElement('img'); + var mime = img_description.mimetype; + var thumb_url = `/bin/?path=${img_description.thumbnail}&mimetype=image/jpeg` + var image_url = `/bin/?path=${img_description.filename}&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 img_container_elem = document.createElement('div'); + img_container_elem.appendChild(a_elem); + return img_container_elem; +} + +function loadKnownSpamImages() { + pageInfoText.innerText = 'Loading known spam images'; + cancelGlobalEvts(); + + var url = GlobalVars.settings.postgrest_url + '/known_spam_attachments' + var headers = { + 'Authorization': 'Bearer ' + GlobalVars.settings.jwt + }; + + return get(url, cancel, headers) + .then(function(response) { + console.log("have known spam images:", response); + var json = JSON.parse(response); + console.log("have known spam images:", json); + + var imgTags = json.map(mkSpamImgElement); + imgTags.forEach(function(imgTag) { + document.querySelector('main').appendChild(imgTag); + }); + + pageInfoText.innerText = 'Have these known spam images:'; + }) + .catch(caught.bind(this, "Failed to load known spam images. Reason:")); +} + +function loadInfo(info_hash) { + var preLoad_executed = false; + var page = document.createElement('div'); + + function preLoad() { + if (preLoad_executed) { + return; + } + + preLoad_executed = true; + keepElements(['style', '.info']); + pageInfoText.innerText = info_hash; + document.querySelector('main').appendChild(page); + } + + ensureElementExist('style.loading'); + pageInfoText.innerText = 'Loading info for ' + info_hash; + + cancelGlobalEvts(); + + get('/cgi-bin/files?i=' + info_hash, cancel) + .then(function(response) { + preLoad(); + var files = parseTable(response); + console.log(files); + var h = document.createElement('h2'); + h.innerText = 'Contents'; + page.appendChild(h); + var t = renderTree(files); + page.appendChild(t); + }) + .catch(caught.bind(this, "Failed to info details. Reason:")); + + get('/cgi-bin/info?i=' + info_hash, cancel) + .then(function(response) { + preLoad(); + var info = parseTable(response)[0]; + pageInfoText.innerText = info.name; + var first_seen = new Date(info.added.split('.')[0]+'Z'); + var mlink = magnet(info); + mlink.innerText = mlink.href; + + var last_seen = new Date(Math.min( + invertScore(Number(info.score)) * 1000, + new Date().getTime()) + ); + + prepend(page, div(text('First Indexed: ' + first_seen))); + prepend(page, div(text('Approximately last seen: ' + last_seen))); + var filecount = div(text('Files: ')); + filecount.appendChild(bold(text(info.filecount))) + prepend(page, filecount); + var total_size = div(text('Total Size: ')); + total_size.appendChild(bold(text(info.total_size))) + prepend(page, total_size); + prepend(page, div(mlink)); + }) + .catch(caught.bind(this, "Failed to load file list. Details:")); +} + +function loadResults(search_query) { + var encoder = new TextEncoder(); + var hex = bytesToHex(encoder.encode(search_query)); + console.log(hex); + cancelGlobalEvts(); + ensureElementExist('style.loading'); + pageInfoText.innerText = 'Loading results for "' + search_query + '"...'; + get('/cgi-bin/search?q=' + hex, cancel) + .then(function(response) { + CurrentScore = currentScore(); + console.log("Current score:", CurrentScore); + + var t = assembleTable(parseTable(response)); + var document_root = document.querySelector('main'); + + keepElements(['style', '.info']) + pageInfoText.innerText = 'Results for "' + search_query + '"'; + document_root.appendChild(t); + }) + .catch(caught.bind(this, "Failed to results: ")); +} + +function changeUrl(path, search_query) { + var event = new CustomEvent( + 'urlchange', + { + detail: { + path: path, + query: search_query + } + }); + + window.dispatchEvent(event); +} + +function searchInputHandler() { + var input = document.querySelector("input"); + var btn = document.querySelector("button"); + + btn.addEventListener('click', function() { + var search_query = input.value; + window.history.pushState(null, "", + window.location.origin + + '/s?q=' + encodeURIComponent(search_query)); + changeUrl('/s', { q: search_query }); + }); + + input.addEventListener('keydown', function(e) { + if (e.keyCode === 13) { + e.preventDefault(); + btn.click(); + } + }); +} + +function handlePageRoot(_, query_params) { + console.log("handlePageRoot", query_params); + return loadKnownSpamImages(); +} + +function handleSearch(_, query_params) { + var search_query = query_params.q; + + if (!search_query) { + console.log("nothing to query"); + return; + } else { + console.log(search_query); + loadResults(search_query); + } +} + +function handleInfo(parts, query_params) { + console.log('info request', parts, query_params); + loadInfo(parts[0]); +} + +function onUrlChange(e) { + var path = e.detail.path.split('/').filter(function(s){ return s.length; }); + console.log(e, e.detail, path); + resolvePath(ROUTES, path, e.detail.query); +} + +function aClickNav(e) { + e.preventDefault(); + e.stopPropagation(); + console.log(this, this.href); + window.history.pushState(null, "", this.href); + onRealUrlChange(); +} + +function bindEventHandlers() { + window.addEventListener('urlchange', onUrlChange); + window.addEventListener('popstate', onRealUrlChange); +} + +function gatherElements() { + global_elements = {}; + var qs; + + for (var i=0; i < GlobalElemSelectors.length; i++) { + var sel = GlobalElemSelectors[i]; + var elem = document.querySelector(sel); + global_elements[sel] = elem; + } +} + +function parseQueryParams(querystring) { + return querystring.split('&') + .map(function(part) { + return part.split('=').map(decodeURIComponent); + }) + .reduce(function(acc, pair) { return { [pair[0]]: pair[1] } }, {}); +} + +function onRealUrlChange() { + var path = window.location.pathname; + var query_params = parseQueryParams(window.location.search.substring(1)); + changeUrl(path, query_params); +} + +function initPageInfoText() { + pageInfoText = document.createElement('div'); + pageInfoText.className = 'info'; + prepend(document.querySelector('.info-container'), pageInfoText); +} + +function getSettings() { + cancelGlobalEvts(); + pageInfoText.innerText = 'Loading settings'; + return get('/static/settings.json', cancel) + .then(function(response) { + var result = JSON.parse(response); + console.log("settings response:", result); + GlobalVars.settings = result; + pageInfoText.innerText = 'Have settings.'; + }) + .catch(caught.bind(this, "Failed to load JWT: ")); +} + +/** + * Init + */ + +initPageInfoText(); +// gatherElements(); +bindEventHandlers(); +// searchInputHandler(); + +getSettings() + .then(onRealUrlChange); diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..4d6dc67 --- /dev/null +++ b/settings.json @@ -0,0 +1,4 @@ +{ + "postgrest_url": "http://localhost:3000", + "jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoic3BhbV9ub3RpY2VyIn0.j6-6HSBh-Wf5eQovT9cF1ZCNuxkQOqzBFtE3C8aTG3A" +}