Updated JS stuffs.

This commit is contained in:
flash 2025-03-20 21:49:41 +00:00
parent 1363bf5bca
commit 452eeb22d6
Signed by: flash
GPG key ID: 2C9C2C574D47FE3E
21 changed files with 267 additions and 412 deletions

View file

@ -1,108 +0,0 @@
const fs = require('fs');
const path = require('path');
const readline = require('readline');
const utils = require('./utils.js');
exports.process = async function(root, options) {
const macroPrefix = options.prefix || '#';
const entryPoint = options.entry || '';
root = fs.realpathSync(root);
const included = [];
const processFile = async function(fileName) {
const fullPath = path.join(root, fileName);
if(included.includes(fullPath))
return '';
included.push(fullPath);
if(!fullPath.startsWith(root))
return '/* *** INVALID PATH: ' + fullPath + ' */';
if(!fs.existsSync(fullPath))
return '/* *** FILE NOT FOUND: ' + fullPath + ' */';
const lines = readline.createInterface({
input: fs.createReadStream(fullPath),
crlfDelay: Infinity,
});
let output = '';
let lastWasEmpty = false;
if(options.showPath)
output += "/* *** PATH: " + fullPath + " */\n";
for await(const line of lines) {
const lineTrimmed = utils.trim(line);
if(lineTrimmed === '')
continue;
if(line.startsWith(macroPrefix)) {
const args = lineTrimmed.split(' ');
const macro = utils.trim(utils.trimStart(args.shift(), macroPrefix));
switch(macro) {
case 'comment':
break;
case 'include': {
const includePath = utils.trimEnd(args.join(' '), ';');
output += utils.trim(await processFile(includePath));
output += "\n";
break;
}
case 'buildvars':
if(typeof options.buildVars === 'object') {
const bvTarget = options.buildVarsTarget || 'window';
const bvProps = [];
for(const bvName in options.buildVars)
bvProps.push(`${bvName}: { value: ${JSON.stringify(options.buildVars[bvName])} }`);
if(Object.keys(bvProps).length > 0)
output += `Object.defineProperties(${bvTarget}, { ${bvProps.join(', ')} });\n`;
}
break;
default:
output += line;
output += "\n";
break;
}
} else {
output += line;
output += "\n";
}
}
return output;
};
return await processFile(entryPoint);
};
exports.housekeep = function(assetsPath) {
const files = fs.readdirSync(assetsPath).map(fileName => {
const stats = fs.statSync(path.join(assetsPath, fileName));
return {
name: fileName,
lastMod: stats.mtimeMs,
};
}).sort((a, b) => b.lastMod - a.lastMod).map(info => info.name);
const regex = /^(.+)[\-\.]([a-f0-9]+)\.(.+)$/i;
const counts = {};
for(const fileName of files) {
const match = fileName.match(regex);
if(match) {
const name = match[1] + '-' + match[3];
counts[name] = (counts[name] || 0) + 1;
if(counts[name] > 5)
fs.unlinkSync(path.join(assetsPath, fileName));
} else console.log(`Encountered file name in assets folder with unexpected format: ${fileName}`);
}
};

24
assets/makai.js/csrf.js Normal file
View file

@ -0,0 +1,24 @@
#include html.js
const $csrf = (() => {
let elem;
const getElement = () => {
if(elem === undefined)
elem = $query('meta[name="csrf-token"]');
return elem;
};
return {
get token() {
return getElement()?.content ?? '';
},
set token(token) {
if(typeof token !== 'string')
throw 'token must be a string';
const elem = getElement();
if(elem instanceof HTMLMetaElement)
elem.content = token;
},
};
})();

View file

@ -1,111 +0,0 @@
const $t = document.createTextNode.bind(document);
const $er = (type, props, ...children) => $e({ tag: type, attrs: props, child: children });
const $e = function(info, attrs, child, created) {
info = info || {};
if(typeof info === 'string') {
info = {tag: info};
if(attrs)
info.attrs = attrs;
if(child)
info.child = child;
if(created)
info.created = created;
}
const elem = document.createElement(info.tag || 'div');
if(info.attrs) {
const attrs = info.attrs;
for(let key in attrs) {
const attr = attrs[key];
if(attr === undefined || attr === null)
continue;
switch(typeof attr) {
case 'function':
if(key.substring(0, 2) === 'on')
key = key.substring(2).toLowerCase();
elem.addEventListener(key, attr);
break;
case 'object':
if(attr instanceof Array) {
if(key === 'class')
key = 'classList';
const prop = elem[key];
let addFunc = null;
if(prop instanceof Array)
addFunc = prop.push.bind(prop);
else if(prop instanceof DOMTokenList)
addFunc = prop.add.bind(prop);
if(addFunc !== null) {
for(let j = 0; j < attr.length; ++j)
addFunc(attr[j]);
} else {
if(key === 'classList')
key = 'class';
elem.setAttribute(key, attr.toString());
}
} else {
for(const attrKey in attr)
elem[key][attrKey] = attr[attrKey];
}
break;
case 'boolean':
if(attr)
elem.setAttribute(key, '');
break;
default:
if(key === 'className')
key = 'class';
elem.setAttribute(key, attr.toString());
break;
}
}
}
if(info.child) {
let children = info.child;
if(!Array.isArray(children))
children = [children];
for(const child of children) {
switch(typeof child) {
case 'string':
elem.appendChild($t(child));
break;
case 'object':
if(child instanceof Element)
elem.appendChild(child);
else if(child.getElement) {
const childElem = child.getElement();
if(childElem instanceof Element)
elem.appendChild(childElem);
else
elem.appendChild($e(child));
} else
elem.appendChild($e(child));
break;
default:
elem.appendChild($t(child.toString()));
break;
}
}
}
if(info.created)
info.created(elem);
return elem;
};

View file

@ -1,13 +1,10 @@
#include elem.js
#include xhr.js
const MakaiSiteHeaderImages = function() {
const url = '/header-bgs.json';
let headers;
const all = async () => {
if(!Array.isArray(headers))
headers = (await $x.get('/header-bgs.json')).json();
headers = (await $xhr.get('/header-bgs.json', { type: 'json' })).body;
return headers;
};
@ -59,18 +56,19 @@ const MakaiSiteHeader = function(element) {
if(t < 1)
requestAnimationFrame(updateTransition);
else {
$r(prevImage);
prevImage.remove();
resolve();
}
};
prevImage.style.zIndex = '2';
const nextImage = $e({
tag: 'img',
attrs: {
const nextImage = $element(
'img',
{
alt: url,
src: url,
style: { zIndex: '1' },
onerror: () => {
prevImage.style.opacity = null;
prevImage.style.zIndex = null;
@ -81,8 +79,7 @@ const MakaiSiteHeader = function(element) {
requestAnimationFrame(updateTransition);
},
},
style: { zIndex: '1' },
});
);
bgElem.appendChild(nextImage);
});
};

View file

@ -105,7 +105,7 @@ const MakaiSideListElement = function(element) {
};
const clearBody = insertEmpty => {
$rc(bodyElem);
$removeChildren(bodyElem);
insertEmptyElement();
};

139
assets/makai.js/html.js Normal file
View file

@ -0,0 +1,139 @@
const $id = document.getElementById.bind(document);
const $query = document.querySelector.bind(document);
const $queryAll = document.querySelectorAll.bind(document);
const $text = document.createTextNode.bind(document);
const $insertBefore = function(target, element) {
target.parentNode.insertBefore(element, target);
};
const $appendChild = function(element, child) {
switch(typeof child) {
case 'undefined':
break;
case 'string':
element.appendChild($text(child));
break;
case 'function':
$appendChild(element, child());
break;
case 'object':
if(child === null)
break;
if(child instanceof Node)
element.appendChild(child);
else if(child?.element instanceof Node)
element.appendChild(child.element);
else if(typeof child?.toString === 'function')
element.appendChild($text(child.toString()));
break;
default:
element.appendChild($text(child.toString()));
break;
}
};
const $appendChildren = function(element, ...children) {
for(const child of children)
$appendChild(element, child);
};
const $removeChildren = function(element) {
while(element.lastChild)
element.removeChild(element.lastChild);
};
const $fragment = function(props, ...children) {
const fragment = document.createDocumentFragment();
$appendChildren(fragment, ...children);
return fragment;
};
const $element = function(type, props, ...children) {
if(typeof type === 'function')
return new type(props ?? {}, ...children);
const element = document.createElement(type ?? 'div');
if(props)
for(let key in props) {
const prop = props[key];
if(prop === undefined || prop === null)
continue;
switch(typeof prop) {
case 'function':
if(key.substring(0, 2) === 'on')
key = key.substring(2).toLowerCase();
element.addEventListener(key, prop);
break;
case 'object':
if(prop instanceof Array) {
if(key === 'class')
key = 'classList';
const attr = element[key];
let addFunc = null;
if(attr instanceof Array)
addFunc = attr.push.bind(attr);
else if(attr instanceof DOMTokenList)
addFunc = attr.add.bind(attr);
if(addFunc !== null) {
for(let j = 0; j < prop.length; ++j)
addFunc(prop[j]);
} else {
if(key === 'classList')
key = 'class';
element.setAttribute(key, prop.toString());
}
} else {
if(key === 'class' || key === 'className')
key = 'classList';
let setFunc = null;
if(element[key] instanceof DOMTokenList)
setFunc = (ak, av) => { if(av) element[key].add(ak); };
else if(element[key] instanceof CSSStyleDeclaration)
setFunc = (ak, av) => {
if(ak.includes('-'))
element[key].setProperty(ak, av);
else
element[key][ak] = av;
};
else
setFunc = (ak, av) => { element[key][ak] = av; };
for(const attrKey in prop) {
const attrValue = prop[attrKey];
if(attrValue)
setFunc(attrKey, attrValue);
}
}
break;
case 'boolean':
if(prop)
element.setAttribute(key, '');
break;
default:
if(key === 'className')
key = 'class';
element.setAttribute(key, prop.toString());
break;
}
}
$appendChildren(element, ...children);
return element;
};

View file

@ -1,11 +1,14 @@
#include elem.js
#include csrf.js
#include html.js
#include xhr.js
#include elems/head.js
#include np/init.js
#include tools/ascii.js
#include tools/whois.js
const makai = (() => {
const header = new MakaiSiteHeader($q('.js-header'));
const header = new MakaiSiteHeader($query('.js-header'));
const runIfPathStartsWith = (prefix, func, ...args) => {
if(location.pathname === prefix || location.pathname.startsWith(`${prefix}/`))

View file

@ -1,5 +1,3 @@
#include xhr.js
const MakaiNowPlaying = function(userName) {
const noCoverUrl = 'https://lastfm.freetls.fastly.net/i/u/174s/2a96cbd8b46e442fc41c2b86b821562f.png';
const fetchTarget = `https://now.flash.moe/get.php?u=${userName}`;
@ -31,15 +29,14 @@ const MakaiNowPlaying = function(userName) {
return {
fetch: async () => {
const result = await $x.get(fetchTarget);
if(result.status !== 200)
throw `http ${result.status}`;
const { status, body } = await $xhr.get(fetchTarget, { type: 'json' });
if(status !== 200)
throw `http ${status}`;
let info = result.json();
if(info.length < 1)
if(body.length < 1)
throw 'no data';
return format(info[0]);
return format(body[0]);
},
};
};

View file

@ -1,9 +1,8 @@
#include utility.js
#include np/client.js
#include np/element.jsx
const MakaiNowPlayingInit = siteHeader => {
const target = $q('.js-np-target');
const target = $query('.js-np-target');
if(!(target instanceof Element))
return;
@ -13,7 +12,7 @@ const MakaiNowPlayingInit = siteHeader => {
const client = new MakaiNowPlaying(userName);
const element = new MakaiNowPlayingElement;
$rp(target, element.element);
target.replaceWith(element.element);
const update = () => {
client.fetch().then(result => {

View file

@ -1,8 +1,6 @@
#include utility.js
const MakaiASCII = () => {
const chars = $qa('.js-ascii-char');
const search = $q('.js-ascii-search');
const chars = $queryAll('.js-ascii-char');
const search = $query('.js-ascii-search');
const charsFilter = (filter) => {
if(!filter) {

View file

@ -1,17 +1,15 @@
#include utility.js
#include xhr.js
#include elems/sidelist.jsx
const MakaiWHOIS = () => {
let locked = false;
const input = $q('.js-whois-input');
const submit = $q('.js-whois-submit');
const result = $q('.js-whois-body');
const tabs = $q('.js-whois-tabs');
const input = $query('.js-whois-input');
const submit = $query('.js-whois-submit');
const result = $query('.js-whois-body');
const tabs = $query('.js-whois-tabs');
const historic = [];
const history = (() => {
const element = $q('.js-whois-sidelist');
const element = $query('.js-whois-sidelist');
if(element instanceof Element)
return new MakaiSideListElement(element);
})();
@ -40,18 +38,17 @@ const MakaiWHOIS = () => {
if(!lock())
return;
$x.post('/tools/whois/lookup', {}, { _csrfp: $csrfp.get(), target: target }).then(output => {
let headers = output.headers();
if(headers.has('x-csrfp'))
$csrfp.set(headers.get('x-csrfp'));
$xhr.post('/tools/whois/lookup', { type: 'json' }, { _csrfp: $csrf.token, target: target }).then(output => {
if(output.headers.has('x-csrfp'))
$csrf.token = output.headers.get('x-csrfp');
let resp = output.json();
let resp = output.body;
if(resp.error)
alert(resp.text);
let count = 0;
$rc(tabs);
$removeChildren(tabs);
if(resp.result && Array.isArray(resp.result.responses) && resp.result.responses.length > 0) {
if(!historic.includes(resp.result.target)) {
@ -60,16 +57,16 @@ const MakaiWHOIS = () => {
}
for(const response of resp.result.responses) {
const tab = $e({tag: 'a'});
const tabHeader = $e();
const tabServer = $e();
const tab = $element('a');
const tabHeader = $element();
const tabServer = $element();
tab.href = 'javascript:;';
tab.className = 'whois-result-tab';
if(count === 0) tab.className += ' whois-result-tab-active';
tab.onclick = () => {
const active = $q('.whois-result-tab-active');
const active = $query('.whois-result-tab-active');
if(active) active.classList.remove('whois-result-tab-active');
tab.classList.add('whois-result-tab-active');
result.textContent = response.lines.join("\r\n").trim();

View file

@ -1,65 +0,0 @@
const $i = document.getElementById.bind(document);
const $c = document.getElementsByClassName.bind(document);
const $q = document.querySelector.bind(document);
const $qa = document.querySelectorAll.bind(document);
const $r = function(element) {
if(element && element.parentNode)
element.parentNode.removeChild(element);
};
const $ri = function(name) {
$r($i(name));
};
const $ib = function(ref, elem) {
ref.parentNode.insertBefore(elem, ref);
};
const $rc = function(element) {
while(element.lastChild)
element.removeChild(element.lastChild);
};
const $rp = function(target, replace) {
$ib(target, replace);
$r(target);
};
const $ar = function(array, index) {
array.splice(index, 1);
};
const $ari = function(array, item) {
let index;
while(array.length > 0 && (index = array.indexOf(item)) >= 0)
$ar(array, index);
};
const $arf = function(array, predicate) {
let index;
while(array.length > 0 && (index = array.findIndex(predicate)) >= 0)
$ar(array, index);
};
const $as = function(array) {
if(array.length < 2)
return;
for(let i = array.length - 1; i > 0; --i) {
let j = Math.floor(Math.random() * (i + 1)),
tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
};
const $csrfp = (function() {
const elem = $q('meta[name="csrfp-token"]');
return {
get: () => elem?.content ?? '',
set: token => {
if(elem != null)
elem.content = token?.toString() ?? '';
},
};
})();

View file

@ -1,15 +1,24 @@
const $x = (function() {
#include csrf.js
const $xhr = (function() {
const send = function(method, url, options, body) {
options ??= {};
if(options === undefined)
options = {};
else if(typeof options !== 'object')
throw 'options must be undefined or an object';
Object.freeze(options);
const xhr = new XMLHttpRequest;
const requestHeadersRaw = options?.headers ?? {};
const requestHeaders = new Map;
if(typeof requestHeadersRaw === 'object')
for(const name in requestHeadersRaw)
if(requestHeadersRaw.hasOwnProperty(name))
requestHeaders.set(name.toLowerCase(), requestHeadersRaw[name]);
if('headers' in options && typeof options.headers === 'object')
for(const name in options.headers)
if(options.headers.hasOwnProperty(name))
requestHeaders.set(name.toLowerCase(), options.headers[name]);
if(options.csrf)
requestHeaders.set('x-csrf-token', $csrf.token);
if(typeof options.download === 'function') {
xhr.onloadstart = ev => options.download(ev);
@ -29,6 +38,9 @@ const $x = (function() {
if(typeof options.timeout === 'number')
xhr.timeout = options.timeout;
if(typeof options.type === 'string')
xhr.responseType = options.type;
if(typeof options.abort === 'function')
options.abort(() => xhr.abort());
@ -39,7 +51,7 @@ const $x = (function() {
if(body instanceof URLSearchParams) {
requestHeaders.set('content-type', 'application/x-www-form-urlencoded');
} else if(body instanceof FormData) {
requestHeaders.set('content-type', 'multipart/form-data');
// content-type is implicitly set
} else if(body instanceof Blob || body instanceof ArrayBuffer || body instanceof DataView) {
if(!requestHeaders.has('content-type'))
requestHeaders.set('content-type', 'application/octet-stream');
@ -54,30 +66,33 @@ const $x = (function() {
}
return new Promise((resolve, reject) => {
let responseHeaders = undefined;
xhr.onload = ev => {
const headers = (headersString => {
const headers = new Map;
xhr.onload = ev => resolve({
status: xhr.status,
body: () => xhr.responseText,
json: () => JSON.parse(xhr.responseText),
headers: () => {
if(responseHeaders !== undefined)
return responseHeaders;
responseHeaders = new Map;
const raw = xhr.getAllResponseHeaders().trim().split(/[\r\n]+/);
const raw = headersString.trim().split(/[\r\n]+/);
for(const name in raw)
if(raw.hasOwnProperty(name)) {
const parts = raw[name].split(': ');
responseHeaders.set(parts.shift(), parts.join(': '));
headers.set(parts.shift(), parts.join(': '));
}
return responseHeaders;
},
xhr: xhr,
ev: ev,
});
return headers;
})(xhr.getAllResponseHeaders());
if(headers.has('x-csrf-token'))
$csrf.token = headers.get('x-csrf-token');
resolve({
get ev() { return ev; },
get xhr() { return xhr; },
get status() { return xhr.status; },
get headers() { return headers; },
get body() { return xhr.response; },
get text() { return xhr.responseText; },
});
};
xhr.onerror = ev => reject({
xhr: xhr,

View file

@ -1,35 +0,0 @@
const crypto = require('crypto');
exports.strtr = (str, replacements) => str.toString().replace(
/{([^}]+)}/g, (match, key) => replacements[key] || match
);
const trim = function(str, chars, flags) {
if(chars === undefined)
chars = " \n\r\t\v\0";
let start = 0,
end = str.length;
if(flags & 0x01)
while(start < end && chars.indexOf(str[start]) >= 0)
++start;
if(flags & 0x02)
while(end > start && chars.indexOf(str[end - 1]) >= 0)
--end;
return (start > 0 || end < str.length)
? str.substring(start, end)
: str;
};
exports.trimStart = (str, chars) => trim(str, chars, 0x01);
exports.trimEnd = (str, chars) => trim(str, chars, 0x02);
exports.trim = (str, chars) => trim(str, chars, 0x03);
exports.shortHash = function(text) {
const hash = crypto.createHash('sha256');
hash.update(text);
return hash.digest('hex').substring(0, 8);
};

View file

@ -11,7 +11,9 @@ const fs = require('fs');
public: pathJoin(__dirname, 'public'),
debug: isDebug,
swc: {
es: 'es2020',
es: 'es2021',
jsx: '$element',
jsxf: '$fragment',
},
};

View file

@ -1,6 +1,7 @@
<?php
namespace Makai;
use Index\Http\HttpResponseBuilder;
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
use Index\Http\Routing\Routes\ExactRoute;
use Index\Templating\TplEnvironment;
@ -17,7 +18,7 @@ class DeveloperRoutes implements RouteHandler {
) {}
#[ExactRoute('GET', '/')]
public function getIndex($response, $request) {
public function getIndex() {
$projectInfos = $this->projects->getProjects(
featuredOnly: true,
deleted: false,
@ -54,12 +55,12 @@ class DeveloperRoutes implements RouteHandler {
}
#[ExactRoute('GET', '/tools')]
public function temporaryRedirect($response): void {
public function temporaryRedirect(HttpResponseBuilder $response): void {
$response->redirect('/');
}
#[ExactRoute('GET', '/contact')]
public function permanentRedirect($response): void {
public function permanentRedirect(HttpResponseBuilder $response): void {
$response->redirect('/', true);
}
}

View file

@ -2,6 +2,7 @@
namespace Makai\SSHKeys;
use DateTimeInterface;
use Index\Http\{HttpRequest,HttpResponseBuilder};
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
use Index\Http\Routing\Routes\ExactRoute;
@ -13,7 +14,7 @@ class SSHKeysRoutes implements RouteHandler {
) {}
#[ExactRoute('GET', '/ssh_keys')]
public function getSshKeys($response, $request): array|string {
public function getSshKeys(HttpResponseBuilder $response, HttpRequest $request): array|string {
$minLevel = (int)$request->getParam('l', FILTER_SANITIZE_NUMBER_INT);
$includeComment = $request->hasParam('c');
$json = $request->hasParam('j');
@ -47,7 +48,7 @@ class SSHKeysRoutes implements RouteHandler {
}
#[ExactRoute('GET', '/authorized_keys')]
public function getAuthorisedKeys($response, $request): string {
public function getAuthorisedKeys(HttpResponseBuilder $response): string {
$response->setTypePlain();
$body = '';
@ -59,7 +60,7 @@ class SSHKeysRoutes implements RouteHandler {
}
#[ExactRoute('GET', '/git_keys_ro')]
public function getGitKeysReadOnly($response, $request): string {
public function getGitKeysReadOnly(HttpResponseBuilder $response): string {
$response->setTypePlain();
$body = '';
@ -71,7 +72,7 @@ class SSHKeysRoutes implements RouteHandler {
}
#[ExactRoute('GET', '/git_keys_rw')]
public function getGitKeysReadWrite($response, $request): string {
public function getGitKeysReadWrite(HttpResponseBuilder $response): string {
$response->setTypePlain();
$body = '';
@ -83,7 +84,7 @@ class SSHKeysRoutes implements RouteHandler {
}
#[ExactRoute('GET', '/ssh.php')]
public function getSshPhp($response, $request): void {
public function getSshPhp(HttpResponseBuilder $response, HttpRequest $request): void {
$query = [];
$minLevel = (int)$request->getParam('l', FILTER_SANITIZE_NUMBER_INT);

View file

@ -1,6 +1,7 @@
<?php
namespace Makai\Tools\Ascii;
use Index\Http\HttpResponseBuilder;
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
use Index\Http\Routing\Routes\ExactRoute;
use Index\Templating\TplEnvironment;
@ -13,7 +14,7 @@ class AsciiRoutes implements RouteHandler {
) {}
#[ExactRoute('GET', '/tools/ascii')]
public function getAsciiTable($response, $request): string {
public function getAsciiTable(HttpResponseBuilder $response): string {
return $this->templating->render('tools/ascii/index', [
'chars' => AsciiCharacter::all(),
]);
@ -21,7 +22,7 @@ class AsciiRoutes implements RouteHandler {
#[ExactRoute('GET', '/ascii')]
#[ExactRoute('GET', '/ascii.php')]
public function getAsciiPHP($response, $request): void {
public function getAsciiPHP(HttpResponseBuilder $response): void {
$response->redirect('/tools/ascii', true);
}
}

View file

@ -2,6 +2,7 @@
namespace Makai\Tools;
use Index\XString;
use Index\Http\{HttpRequest,HttpResponseBuilder};
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
use Index\Http\Routing\Routes\ExactRoute;
@ -9,7 +10,7 @@ class ToolsRoutes implements RouteHandler {
use RouteHandlerCommon;
#[ExactRoute('GET', '/tools/random')]
public function getRandomString($response, $request): string {
public function getRandomString(HttpResponseBuilder $response, HttpRequest $request): string {
$response->setTypePlain();
$length = (int)$request->getParam('length', FILTER_SANITIZE_NUMBER_INT);
@ -27,7 +28,7 @@ class ToolsRoutes implements RouteHandler {
#[ExactRoute('GET', '/tools/hajime-hash')]
#[ExactRoute('GET', '/tools/hidoi-hash')]
public function getHajimeHash($response, $request): string {
public function getHajimeHash(HttpResponseBuilder $response, HttpRequest $request): string {
$response->setTypePlain();
if(!$request->hasParam('text'))
return 'text param is empty';
@ -37,7 +38,7 @@ class ToolsRoutes implements RouteHandler {
#[ExactRoute('GET', '/key.php')]
#[ExactRoute('GET', '/rngstr')]
public function getRedirect($response, $request): void {
public function getRedirect(HttpResponseBuilder $response, HttpRequest $request): void {
$url = '/tools/random';
$length = (int)$request->getParam('length', FILTER_SANITIZE_NUMBER_INT);

View file

@ -4,7 +4,10 @@ namespace Makai\Tools\Whois;
use Exception;
use Memcached;
use Index\Cache\CacheBackends;
use Index\Http\HttpResponseBuilder;
use Index\Http\Content\FormContent;
use Index\Http\Routing\{RouteHandler,RouteHandlerCommon};
use Index\Http\Routing\Processors\Before;
use Index\Http\Routing\Routes\ExactRoute;
use Index\Templating\TplEnvironment;
use Makai\CSRFPContainer;
@ -23,17 +26,13 @@ class WhoisRoutes implements RouteHandler {
}
#[ExactRoute('GET', '/whois')]
public function getWhoisPHP($response, $request): void {
public function getWhoisPHP(HttpResponseBuilder $response): void {
$response->redirect('/tools/whois', true);
}
#[ExactRoute('POST', '/tools/whois/lookup')]
public function postLookup($response, $request) {
if(!$request->isFormContent())
return 400;
$content = $request->getContent();
#[Before('input:urlencoded')]
public function postLookup(HttpResponseBuilder $response, FormContent $content) {
if(!$this->csrfp->verifyToken((string)$content->getParam('_csrfp')))
return [
'error' => true,

View file

@ -4,7 +4,7 @@
<meta charset="{{ master_charset|default('utf-8') }}">
{% if master_title is defined and master_title is not empty %}<title>{{ master_title }}</title>{% endif %}
{% block master_head %}{% endblock %}
{% if csrfp_available() %}<meta name="csrfp-token" content="{{ csrfp_token() }}">{% endif %}
{% if csrfp_available() %}<meta name="csrf-token" content="{{ csrfp_token() }}">{% endif %}
</head>
<body>
{% block master_body %}{% endblock %}