Prerender error pages.

This commit is contained in:
flash 2023-10-14 23:05:49 +00:00
parent d9758fb28a
commit 6484118cca
11 changed files with 338 additions and 28 deletions

6
.gitignore vendored
View file

@ -1,8 +1,14 @@
.DS_Store .DS_Store
[Dd]esktop.ini [Dd]esktop.ini
/.debug /.debug
/.migrating
/config/*.ini /config/*.ini
/vendor /vendor
/node_modules /node_modules
/public/assets /public/assets
/assets/current.json /assets/current.json
/public/error-401.html
/public/error-403.html
/public/error-404.html
/public/error-500.html
/public/error-503.html

View file

@ -2,7 +2,9 @@ const fs = require('fs');
const swc = require('@swc/core'); const swc = require('@swc/core');
const path = require('path'); const path = require('path');
const util = require('util'); const util = require('util');
const exec = util.promisify(require('child_process').exec);
const postcss = require('postcss'); const postcss = require('postcss');
const htmlminify = require('html-minifier-terser').minify;
const utils = require('./assets/utils.js'); const utils = require('./assets/utils.js');
const assproc = require('./assets/assproc.js'); const assproc = require('./assets/assproc.js');
@ -19,6 +21,14 @@ const pubAssetJSFormat = '%s-%s.js';
const isDebugBuild = fs.existsSync(path.join(rootDir, '.debug')); const isDebugBuild = fs.existsSync(path.join(rootDir, '.debug'));
const renderTemplates = [
{ in: 'errors/401', out: '/error-401.html' },
{ in: 'errors/403', out: '/error-403.html' },
{ in: 'errors/404', out: '/error-404.html' },
{ in: 'errors/500', out: '/error-500.html' },
{ in: 'errors/503', out: '/error-503.html' },
];
const swcJscOptions = { const swcJscOptions = {
target: 'es2016', target: 'es2016',
loose: false, loose: false,
@ -47,6 +57,22 @@ const swcJscOptions = {
}, },
}; };
const htmlMinifyOptions = {
collapseBooleanAttributes: true,
collapseWhitespace: true,
conservativeCollapse: false,
decodeEntities: false,
quoteCharacter: '"',
removeAttributeQuotes: true,
removeComments: true,
removeEmptyAttributes: true,
removeOptionalTags: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
sortAttributes: true,
sortClassName: true,
};
const postcssPlugins = []; const postcssPlugins = [];
if(!isDebugBuild) postcssPlugins.push(require('cssnano')); if(!isDebugBuild) postcssPlugins.push(require('cssnano'));
postcssPlugins.push(require('autoprefixer')({ postcssPlugins.push(require('autoprefixer')({
@ -103,5 +129,27 @@ fs.mkdirSync(pubAssetsFull, { recursive: true });
console.log('Writing assets info...'); console.log('Writing assets info...');
fs.writeFileSync(assetsInfo, JSON.stringify(assets)); fs.writeFileSync(assetsInfo, JSON.stringify(assets));
console.log('Housekeeping...');
assproc.housekeep(pubAssetsFull); assproc.housekeep(pubAssetsFull);
console.log('Prerendering templates...');
const renderCommand = path.join(rootDir, 'tools/render-tpl');
console.log(renderCommand);
for(const info of renderTemplates) {
console.log();
console.log(info.in);
const { stdout, stderr } = await exec(`${renderCommand} ${info.in}`);
if(stdout.trim() === '') {
console.error(stderr);
continue;
}
let body = await htmlminify(stdout, htmlMinifyOptions);
fs.writeFileSync(path.join(pubDir, info.out), body);
}
})(); })();

213
package-lock.json generated
View file

@ -8,9 +8,62 @@
"@swc/core": "^1.3.69", "@swc/core": "^1.3.69",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"cssnano": "^6.0.1", "cssnano": "^6.0.1",
"html-minifier-terser": "^7.2.0",
"postcss": "^8.4.26" "postcss": "^8.4.26"
} }
}, },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
"dependencies": {
"@jridgewell/set-array": "^1.0.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
"@jridgewell/trace-mapping": "^0.3.9"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz",
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/set-array": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/source-map": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.19",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz",
"integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@swc/core": { "node_modules/@swc/core": {
"version": "1.3.93", "version": "1.3.93",
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.93.tgz", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.93.tgz",
@ -216,6 +269,17 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/acorn": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/autoprefixer": { "node_modules/autoprefixer": {
"version": "10.4.16", "version": "10.4.16",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz",
@ -288,6 +352,20 @@
"node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
} }
}, },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"node_modules/camel-case": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
"integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
"dependencies": {
"pascal-case": "^3.1.2",
"tslib": "^2.0.3"
}
},
"node_modules/caniuse-api": { "node_modules/caniuse-api": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@ -318,6 +396,17 @@
} }
] ]
}, },
"node_modules/clean-css": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
"integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==",
"dependencies": {
"source-map": "~0.6.0"
},
"engines": {
"node": ">= 10.0"
}
},
"node_modules/colord": { "node_modules/colord": {
"version": "2.9.3", "version": "2.9.3",
"resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
@ -544,6 +633,15 @@
"url": "https://github.com/fb55/domutils?sponsor=1" "url": "https://github.com/fb55/domutils?sponsor=1"
} }
}, },
"node_modules/dot-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
"integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.4.554", "version": "1.4.554",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz",
@ -580,6 +678,34 @@
"url": "https://github.com/sponsors/rawify" "url": "https://github.com/sponsors/rawify"
} }
}, },
"node_modules/html-minifier-terser": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz",
"integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==",
"dependencies": {
"camel-case": "^4.1.2",
"clean-css": "~5.3.2",
"commander": "^10.0.0",
"entities": "^4.4.0",
"param-case": "^3.0.4",
"relateurl": "^0.2.7",
"terser": "^5.15.1"
},
"bin": {
"html-minifier-terser": "cli.js"
},
"engines": {
"node": "^14.13.1 || >=16.0.0"
}
},
"node_modules/html-minifier-terser/node_modules/commander": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"engines": {
"node": ">=14"
}
},
"node_modules/lilconfig": { "node_modules/lilconfig": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
@ -598,6 +724,14 @@
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
"integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==" "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ=="
}, },
"node_modules/lower-case": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
"dependencies": {
"tslib": "^2.0.3"
}
},
"node_modules/mdn-data": { "node_modules/mdn-data": {
"version": "2.0.30", "version": "2.0.30",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
@ -620,6 +754,15 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
} }
}, },
"node_modules/no-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
"dependencies": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
}
},
"node_modules/node-releases": { "node_modules/node-releases": {
"version": "2.0.13", "version": "2.0.13",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
@ -644,6 +787,24 @@
"url": "https://github.com/fb55/nth-check?sponsor=1" "url": "https://github.com/fb55/nth-check?sponsor=1"
} }
}, },
"node_modules/param-case": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
"integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
"dependencies": {
"dot-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/pascal-case": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
}
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -1073,6 +1234,22 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
}, },
"node_modules/relateurl": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
"integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==",
"engines": {
"node": ">= 0.10"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": { "node_modules/source-map-js": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
@ -1081,6 +1258,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/stylehacks": { "node_modules/stylehacks": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz",
@ -1119,6 +1305,33 @@
"url": "https://opencollective.com/svgo" "url": "https://opencollective.com/svgo"
} }
}, },
"node_modules/terser": {
"version": "5.21.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz",
"integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
"commander": "^2.20.0",
"source-map-support": "~0.5.20"
},
"bin": {
"terser": "bin/terser"
},
"engines": {
"node": ">=10"
}
},
"node_modules/terser/node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
},
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
},
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.0.13", "version": "1.0.13",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",

View file

@ -3,6 +3,7 @@
"@swc/core": "^1.3.69", "@swc/core": "^1.3.69",
"autoprefixer": "^10.4.14", "autoprefixer": "^10.4.14",
"cssnano": "^6.0.1", "cssnano": "^6.0.1",
"html-minifier-terser": "^7.2.0",
"postcss": "^8.4.26" "postcss": "^8.4.26"
} }
} }

View file

@ -14,17 +14,17 @@ set_exception_handler(function(\Throwable $ex) {
} }
header('Content-Type: text/html; charset=utf-8'); header('Content-Type: text/html; charset=utf-8');
echo file_get_contents(MKI_DIR_TEMPLATES . '/errors/500.html'); echo file_get_contents(MKI_DIR_PUBLIC . '/error-500.html');
exit; exit;
}); });
if(file_exists(MKI_ROOT . '/.migrating')) { if(file_exists(MKI_ROOT . '/.migrating')) {
http_response_code(503); http_response_code(503);
echo file_get_contents(MKI_DIR_TEMPLATES . '/errors/503.html'); echo file_get_contents(MKI_DIR_PUBLIC . '/error-503.html');
exit; exit;
} }
$makai->startCSRFP( $makai->getCSRFP()->setInfo(
$cfg['csrfp'] ?? 'meow', $cfg['csrfp'] ?? 'meow',
(string)filter_input(INPUT_SERVER, 'REMOTE_ADDR') (string)filter_input(INPUT_SERVER, 'REMOTE_ADDR')
); );

41
src/CSRFPContainer.php Normal file
View file

@ -0,0 +1,41 @@
<?php
namespace Makai;
use Index\Security\CSRFP;
final class CSRFPContainer {
private ?CSRFP $instance = null;
private string $secretKey = '';
private string $identity = '';
public function setInfo(
?string $secretKey = null,
?string $identity = null
): void {
if($secretKey !== null)
$this->secretKey = $secretKey;
if($identity !== null)
$this->identity = $identity;
$this->instance = null;
}
public function isAvailable(): bool {
return $this->instance !== null
|| ($this->secretKey !== '' && $this->identity !== '');
}
public function getInstance(): ?CSRFP {
if($this->instance === null)
$this->instance = new CSRFP($this->secretKey, $this->identity);
return $this->instance;
}
public function createToken(...$args): string {
return $this->getInstance()?->createToken(...$args) ?? '';
}
public function verifyToken(...$args): bool {
return $this->getInstance()?->verifyToken(...$args) ?? false;
}
}

View file

@ -6,13 +6,12 @@ use Index\Data\IDbConnection;
use Index\Data\Migration\IDbMigrationRepo; use Index\Data\Migration\IDbMigrationRepo;
use Index\Data\Migration\DbMigrationManager; use Index\Data\Migration\DbMigrationManager;
use Index\Data\Migration\FsDbMigrationRepo; use Index\Data\Migration\FsDbMigrationRepo;
use Index\Security\CSRFP;
use Sasae\SasaeEnvironment; use Sasae\SasaeEnvironment;
final class MakaiContext { final class MakaiContext {
private IDbConnection $dbConn; private IDbConnection $dbConn;
private SasaeEnvironment $templating; private SasaeEnvironment $templating;
private CSRFP $csrfp; private CSRFPContainer $csrfp;
private SiteInfo $siteInfo; private SiteInfo $siteInfo;
@ -24,6 +23,7 @@ final class MakaiContext {
$this->dbConn = $dbConn; $this->dbConn = $dbConn;
$this->siteInfo = new SiteInfo; $this->siteInfo = new SiteInfo;
$this->csrfp = new CSRFPContainer;
$this->startTemplating(); $this->startTemplating();
$this->contacts = new Contacts\Contacts($dbConn); $this->contacts = new Contacts\Contacts($dbConn);
@ -76,28 +76,26 @@ final class MakaiContext {
cache: $isDebug ? null : ['Makai', GitInfo::hash(true)], cache: $isDebug ? null : ['Makai', GitInfo::hash(true)],
debug: $isDebug, debug: $isDebug,
); );
$this->templating->addFunction('csrfp_token', fn() => $this->getCSRFP()->createToken()); $this->templating->addFunction('csrfp_token', $this->csrfp->createToken(...));
$this->templating->addFunction('csrfp_available', $this->csrfp->isAvailable(...));
$this->templating->addGlobal('globals', [ $this->templating->addGlobal('globals', [
'siteInfo' => $this->siteInfo, 'siteInfo' => $this->siteInfo,
'assetsInfo' => AssetsInfo::fromCurrent(), 'assetsInfo' => AssetsInfo::fromCurrent(),
]); ]);
} }
public function getCSRFP(): CSRFP { public function getCSRFP(): CSRFPContainer {
return $this->csrfp; return $this->csrfp;
} }
public function startCSRFP(string $secretKey, string $identity): void {
$this->csrfp = new CSRFP($secretKey, $identity);
}
public function createRouting(): RoutingContext { public function createRouting(): RoutingContext {
$routingCtx = new RoutingContext($this->templating); $routingCtx = new RoutingContext($this->templating);
$routingCtx->registerDefaultErrorPages(); $routingCtx->registerDefaultErrorPages();
$routingCtx->register(new DeveloperRoutes($this->templating, $this->contacts, $this->projects)); $routingCtx->register(new DeveloperRoutes($this->templating, $this->contacts, $this->projects));
$routingCtx->register(new AssetsRoutes($this->siteInfo)); $routingCtx->register(new AssetsRoutes($this->siteInfo));
$routingCtx->register(new Whois\WhoisRoutes($this->templating, fn() => $this->csrfp)); $routingCtx->register(new Blog\BlogRoutes($this->templating, $this->contacts, $this->projects));
$routingCtx->register(new Whois\WhoisRoutes($this->templating, $this->csrfp));
$routingCtx->register(new SSHKeys\SSHKeysRoutes($this->sshKeys)); $routingCtx->register(new SSHKeys\SSHKeysRoutes($this->sshKeys));
$routingCtx->register(new Tools\AsciiRoutes($this->templating)); $routingCtx->register(new Tools\AsciiRoutes($this->templating));
$routingCtx->register(new Tools\RandomStringRoutes); $routingCtx->register(new Tools\RandomStringRoutes);

View file

@ -22,17 +22,11 @@ class RoutingContext {
} }
public function registerDefaultErrorPages(): void { public function registerDefaultErrorPages(): void {
$this->router->get('/error-401.html', fn() => $this->templating->render('errors/401')); $this->router->addErrorHandler(401, fn($resp) => $resp->setContent(file_get_contents(MKI_DIR_PUBLIC . '/error-401.html')));
$this->router->get('/error-403.html', fn() => $this->templating->render('errors/403')); $this->router->addErrorHandler(403, fn($resp) => $resp->setContent(file_get_contents(MKI_DIR_PUBLIC . '/error-403.html')));
$this->router->get('/error-404.html', fn() => $this->templating->render('errors/404')); $this->router->addErrorHandler(404, fn($resp) => $resp->setContent(file_get_contents(MKI_DIR_PUBLIC . '/error-404.html')));
$this->router->get('/error-500.html', fn() => $this->templating->render('errors/500')); $this->router->addErrorHandler(500, fn($resp) => $resp->setContent(file_get_contents(MKI_DIR_PUBLIC . '/error-500.html')));
$this->router->get('/error-503.html', fn() => $this->templating->render('errors/503')); $this->router->addErrorHandler(503, fn($resp) => $resp->setContent(file_get_contents(MKI_DIR_PUBLIC . '/error-503.html')));
$this->router->addErrorHandler(401, fn($resp) => $resp->setContent($this->templating->render('errors/401')));
$this->router->addErrorHandler(403, fn($resp) => $resp->setContent($this->templating->render('errors/403')));
$this->router->addErrorHandler(404, fn($resp) => $resp->setContent($this->templating->render('errors/404')));
$this->router->addErrorHandler(500, fn($resp) => $resp->setContent(file_get_contents(MKI_DIR_TEMPLATES . '/errors/500.html')));
$this->router->addErrorHandler(503, fn($resp) => $resp->setContent(file_get_contents(MKI_DIR_TEMPLATES . '/errors/503.html')));
} }
public function register(IRouteHandler $handler): void { public function register(IRouteHandler $handler): void {

View file

@ -4,11 +4,12 @@ namespace Makai\Whois;
use Index\Routing\Route; use Index\Routing\Route;
use Index\Routing\RouteHandler; use Index\Routing\RouteHandler;
use Sasae\SasaeEnvironment; use Sasae\SasaeEnvironment;
use Makai\CSRFPContainer;
class WhoisRoutes extends RouteHandler { class WhoisRoutes extends RouteHandler {
public function __construct( public function __construct(
private SasaeEnvironment $templating, private SasaeEnvironment $templating,
private \Closure $csrfp, private CSRFPContainer $csrfp,
) {} ) {}
#[Route('GET', '/whois')] #[Route('GET', '/whois')]
@ -22,15 +23,14 @@ class WhoisRoutes extends RouteHandler {
return 400; return 400;
$content = $request->getContent(); $content = $request->getContent();
$csrfp = ($this->csrfp)();
if(!$csrfp->verifyToken((string)$content->getParam('_csrfp'))) if(!$this->csrfp->verifyToken((string)$content->getParam('_csrfp')))
return [ return [
'error' => true, 'error' => true,
'text' => 'Could not validate request, please refresh the page.', 'text' => 'Could not validate request, please refresh the page.',
]; ];
$response->setHeader('X-CSRFP', $csrfp->createToken()); $response->setHeader('X-CSRFP', $this->csrfp->createToken());
$target = trim((string)$content->getParam('target')); $target = trim((string)$content->getParam('target'));
if(empty($target)) if(empty($target))

View file

@ -4,7 +4,7 @@
<meta charset="{{ master_charset|default('utf-8') }}"> <meta charset="{{ master_charset|default('utf-8') }}">
{% if master_title is defined and master_title is not empty %}<title>{{ master_title }}</title>{% endif %} {% if master_title is defined and master_title is not empty %}<title>{{ master_title }}</title>{% endif %}
{% block master_head %}{% endblock %} {% block master_head %}{% endblock %}
<meta name="csrfp-token" content="{{ csrfp_token() }}"> {% if csrfp_available() %}<meta name="csrfp-token" content="{{ csrfp_token() }}">{% endif %}
{% if styles is defined and styles is iterable and styles is not empty %} {% if styles is defined and styles is iterable and styles is not empty %}
{% for style in styles|reverse %} {% for style in styles|reverse %}
<link href="{{ style }}" type="text/css" rel="stylesheet"> <link href="{{ style }}" type="text/css" rel="stylesheet">

9
tools/render-tpl Executable file
View file

@ -0,0 +1,9 @@
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../makai.php';
$makai->startTemplating();
$templating = $makai->getTemplating();
$path = implode(' ', array_slice($argv, 1));
echo $templating->render($path);