Format files

This commit is contained in:
E 2024-04-29 13:17:25 +01:00
parent 224929828a
commit d942d7942d
No known key found for this signature in database
GPG Key ID: 9D57A2D583601371
13 changed files with 431 additions and 367 deletions

38
app.js
View File

@ -4,7 +4,7 @@ var path = require('path');
var cookieParser = require('cookie-parser'); var cookieParser = require('cookie-parser');
var mLogger = require('morgan'); var mLogger = require('morgan');
var logger = require('./config/winston'); var logger = require('./config/winston');
const helmet = require("helmet"); const helmet = require('helmet');
var indexRouter = require('./routes/index'); var indexRouter = require('./routes/index');
var aboutRouter = require('./routes/about'); var aboutRouter = require('./routes/about');
@ -12,7 +12,8 @@ var contactRouter = require('./routes/contact');
var app = express(); var app = express();
if (process.env.IS_DOCKER != 'true') app.set('trust proxy', 'loopback,uniquelocal'); if (process.env.IS_DOCKER != 'true')
app.set('trust proxy', 'loopback,uniquelocal');
app.disable('x-powered-by'); app.disable('x-powered-by');
// view engine setup // view engine setup
@ -20,7 +21,7 @@ app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug'); app.set('view engine', 'pug');
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
app.use(mLogger("common", { "stream": logger.stream })); app.use(mLogger('common', { stream: logger.stream }));
} else { } else {
app.use(mLogger('dev')); app.use(mLogger('dev'));
} }
@ -30,11 +31,28 @@ app.use(
helmet.contentSecurityPolicy({ helmet.contentSecurityPolicy({
directives: { directives: {
defaultSrc: ["'self'"], defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "'unsafe-eval'", "https://hcaptcha.com", "https://*.hcaptcha.com", "https://cdn.ravenjs.com/"], scriptSrc: [
imgSrc: ["'self'", "https://blog.pastel.codes", "https://static.ghost.org", "https://secure.gravatar.com"], "'self'",
styleSrc: ["'self'", "'unsafe-inline'", "https://hcaptcha.com", "https://*.hcaptcha.com"], "'unsafe-inline'",
fontSrc: ["'self'", "data:"], "'unsafe-eval'",
frameSrc: ["https://hcaptcha.com", "https://*.hcaptcha.com"], 'https://hcaptcha.com',
'https://*.hcaptcha.com',
'https://cdn.ravenjs.com/',
],
imgSrc: [
"'self'",
'https://blog.pastel.codes',
'https://static.ghost.org',
'https://secure.gravatar.com',
],
styleSrc: [
"'self'",
"'unsafe-inline'",
'https://hcaptcha.com',
'https://*.hcaptcha.com',
],
fontSrc: ["'self'", 'data:'],
frameSrc: ['https://hcaptcha.com', 'https://*.hcaptcha.com'],
objectSrc: ["'none'"], objectSrc: ["'none'"],
upgradeInsecureRequests: [], upgradeInsecureRequests: [],
}, },
@ -56,14 +74,14 @@ app.use(function(req, res, next) {
}); });
// error handler // error handler
app.use(function(err, req, res, next) { app.use(function (err, req, res, _next) {
// set locals, only providing error in development // set locals, only providing error in development
res.locals.message = err.message; res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {}; res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page // render the error page
res.status(err.status || 500); res.status(err.status || 500);
res.render('error', { title: 'Error', description: "Error" }); res.render('error', { title: 'Error', description: 'Error' });
}); });
module.exports = app; module.exports = app;

View File

@ -59,9 +59,7 @@ function onError(error) {
throw error; throw error;
} }
var bind = typeof port === 'string' var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages // handle specific listen errors with friendly messages
switch (error.code) { switch (error.code) {
@ -84,8 +82,6 @@ function onError(error) {
function onListening() { function onListening() {
var addr = server.address(); var addr = server.address();
var bind = typeof addr === 'string' var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind); debug('Listening on ' + bind);
} }

View File

@ -10,21 +10,21 @@ var logger = new winston.createLogger({
json: true, json: true,
maxsize: 5242880, //5MB maxsize: 5242880, //5MB
maxFiles: 5, maxFiles: 5,
colorize: false colorize: false,
}), }),
new winston.transports.Console({ new winston.transports.Console({
level: 'debug', level: 'debug',
handleExceptions: true, handleExceptions: true,
json: false, json: false,
colorize: true colorize: true,
}) }),
], ],
exitOnError: false exitOnError: false,
}); });
logger.stream = { logger.stream = {
write: function(message, encoding){ write: function (message, _encoding) {
logger.info(message); logger.info(message);
} },
}; };
module.exports = logger module.exports = logger;

20
eslint.config.mjs Normal file
View File

@ -0,0 +1,20 @@
import globals from 'globals';
import pluginJs from '@eslint/js';
export default [
{ files: ['**/*.js'], languageOptions: { sourceType: 'commonjs' } },
{ languageOptions: { globals: { ...globals.browser, ...globals.node } } },
pluginJs.configs.recommended,
{
rules: {
'no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_',
},
],
},
},
];

32
package-lock.json generated
View File

@ -28,8 +28,10 @@
"winston": "^3.3.3" "winston": "^3.3.3"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.1.1",
"eslint": "^9.1.1", "eslint": "^9.1.1",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"globals": "^15.1.0",
"husky": "^9.0.11", "husky": "^9.0.11",
"lint-staged": "^15.2.2", "lint-staged": "^15.2.2",
"prettier": "^3.2.5", "prettier": "^3.2.5",
@ -217,6 +219,18 @@
} }
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
"engines": {
"node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@ -2118,9 +2132,9 @@
} }
}, },
"node_modules/globals": { "node_modules/globals": {
"version": "14.0.0", "version": "15.1.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-15.1.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "integrity": "sha512-926gJqg+4mkxwYKiFvoomM4J0kWESfk3qfTvRL2/oc/tK/eTDBbrfcKnSa2KtfdxB5onoL7D3A3qIHQFpd4+UA==",
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@ -5212,6 +5226,12 @@
"ms": "2.1.2" "ms": "2.1.2"
} }
}, },
"globals": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true
},
"strip-json-comments": { "strip-json-comments": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@ -6605,9 +6625,9 @@
} }
}, },
"globals": { "globals": {
"version": "14.0.0", "version": "15.1.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "resolved": "https://registry.npmjs.org/globals/-/globals-15.1.0.tgz",
"integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "integrity": "sha512-926gJqg+4mkxwYKiFvoomM4J0kWESfk3qfTvRL2/oc/tK/eTDBbrfcKnSa2KtfdxB5onoL7D3A3qIHQFpd4+UA==",
"dev": true "dev": true
}, },
"globby": { "globby": {

View File

@ -41,8 +41,10 @@
"winston": "^3.3.3" "winston": "^3.3.3"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.1.1",
"eslint": "^9.1.1", "eslint": "^9.1.1",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"globals": "^15.1.0",
"husky": "^9.0.11", "husky": "^9.0.11",
"lint-staged": "^15.2.2", "lint-staged": "^15.2.2",
"prettier": "^3.2.5", "prettier": "^3.2.5",

View File

@ -1,6 +1,3 @@
module.exports = { module.exports = {
plugins: [ plugins: [require('tailwindcss'), require('autoprefixer')],
require('tailwindcss'), };
require('autoprefixer')
]
}

View File

@ -94,7 +94,6 @@ main
font-size: 2rem font-size: 2rem
margin-bottom: 5px margin-bottom: 5px
footer footer
text-align: center text-align: center
font-size: 1rem font-size: 1rem
@ -151,7 +150,6 @@ footer
margin-bottom: 3vh margin-bottom: 3vh
margin-top: 1vh margin-top: 1vh
.pr-text .pr-text
a a
color: $pink color: $pink
@ -287,9 +285,7 @@ footer
.ff .ff
min-height: 82.8vh !important min-height: 82.8vh !important
@media only screen and (max-height: 815px) @media only screen and (max-height: 815px)
.ef .ef
max-height: none !important max-height: none !important
min-height: 0 !important min-height: 0 !important

View File

@ -3,23 +3,33 @@ const axios = require('axios');
var router = express.Router(); var router = express.Router();
/* GET home page. */ /* GET home page. */
router.get('/', function(req, res, next) { router.get('/', function (req, res, _next) {
const GHOST_KEY = process.env.GHOST_KEY const GHOST_KEY = process.env.GHOST_KEY;
const base_url = `https://blog.pastel.codes/ghost/api/v3/content/posts/?key=${GHOST_KEY}` const base_url = `https://blog.pastel.codes/ghost/api/v3/content/posts/?key=${GHOST_KEY}`;
axios.all([ axios
.all([
axios.get(`${base_url}&limit=3`), axios.get(`${base_url}&limit=3`),
axios.get(`${base_url}&limit=3&filter=tag:project`), axios.get(`${base_url}&limit=3&filter=tag:project`),
]) ])
.then(axios.spread((response1, response2) => { .then(
var base = { title: 'About', description: 'Who??? What??? AAAAaaa, about me.'}; axios.spread((response1, response2) => {
var blog = JSON.parse(JSON.stringify(response1.data).split('"posts":').join('"blog":')); var base = {
var projects = JSON.parse(JSON.stringify(response2.data).split('"posts":').join('"project":')); title: 'About',
description: 'Who??? What??? AAAAaaa, about me.',
};
var blog = JSON.parse(
JSON.stringify(response1.data).split('"posts":').join('"blog":')
);
var projects = JSON.parse(
JSON.stringify(response2.data).split('"posts":').join('"project":')
);
var out = Object.assign(base, blog, projects); var out = Object.assign(base, blog, projects);
res.render('about', out); res.render('about', out);
})) })
.catch(error => { )
.catch((error) => {
console.log(error); console.log(error);
}); });
}); });

View File

@ -1,7 +1,6 @@
var express = require('express'); var express = require('express');
var rate_limit = require("express-rate-limit") var rate_limit = require('express-rate-limit');
const { verify } = require('hcaptcha'); const { verify } = require('hcaptcha');
const nodemailer = require('nodemailer')
var router = express.Router(); var router = express.Router();
const sgMail = require('@sendgrid/mail'); const sgMail = require('@sendgrid/mail');
@ -10,23 +9,23 @@ sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const contact_rate_limit = rate_limit({ const contact_rate_limit = rate_limit({
windowMs: 10 * 60 * 1000, // 10 minutes windowMs: 10 * 60 * 1000, // 10 minutes
max: 5, // limit each IP to 10 requests per windowMs max: 5, // limit each IP to 10 requests per windowMs
message: "Too many contact requests, try again later.", message: 'Too many contact requests, try again later.',
handler: function (req, res /*, next*/) { handler: function (req, res /*, next*/) {
res.render('error', { res.render('error', {
title: "Error", title: 'Error',
message: "Too many contact requests, try again later.", message: 'Too many contact requests, try again later.',
error: {status: null} error: { status: null },
}) });
}, },
}); });
// POST route from contact form // POST route from contact form
router.post('/', contact_rate_limit, (req, res) => { router.post('/', contact_rate_limit, (req, res) => {
const TO_MAIL_USER = process.env.TO_MAIL_USER const TO_MAIL_USER = process.env.TO_MAIL_USER;
const FROM_MAIL_USER = process.env.FROM_MAIL_USER const FROM_MAIL_USER = process.env.FROM_MAIL_USER;
const HCAPTCHA_KEY = process.env.HCAPTCHA_KEY const HCAPTCHA_KEY = process.env.HCAPTCHA_KEY;
const REPLY_TO_MAIL = process.env.REPLY_TO_MAIL const REPLY_TO_MAIL = process.env.REPLY_TO_MAIL;
const token = req.body["g-recaptcha-response"]; const token = req.body['g-recaptcha-response'];
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
verify(HCAPTCHA_KEY, token) verify(HCAPTCHA_KEY, token)
@ -36,7 +35,7 @@ router.post('/', contact_rate_limit, (req, res) => {
to: TO_MAIL_USER, to: TO_MAIL_USER,
from: FROM_MAIL_USER, from: FROM_MAIL_USER,
subject: 'New message from contact form at pastel.codes', subject: 'New message from contact form at pastel.codes',
text: `${req.body.firstname} ${req.body.lastname} (${req.body.email})\nsays: ${req.body.message}\n\nip: ${ip}` text: `${req.body.firstname} ${req.body.lastname} (${req.body.email})\nsays: ${req.body.message}\n\nip: ${ip}`,
}; };
sgMail sgMail
@ -44,30 +43,38 @@ router.post('/', contact_rate_limit, (req, res) => {
.then(() => { .then(() => {
res.render('contact', { res.render('contact', {
title: 'Contact', title: 'Contact',
message: "I will get back to you soon!", message: 'I will get back to you soon!',
success: "Make sure the email is from ", success: 'Make sure the email is from ',
email: REPLY_TO_MAIL email: REPLY_TO_MAIL,
}) });
}) })
.catch(error => { .catch((error) => {
console.log(error) console.log(error);
res.render('error', {title: 'Contact', message: "Email did not send"}) res.render('error', {
title: 'Contact',
message: 'Email did not send',
});
}); });
} else { } else {
// rerender with same info in the text box and show error message // rerender with same info in the text box and show error message
res.render('contact', {title: 'Contact', message: "Captcha failed, try again"}); res.render('contact', {
title: 'Contact',
message: 'Captcha failed, try again',
});
} }
}) })
.catch(error => { .catch((error) => {
console.log(error); console.log(error);
res.render('contact', {title: 'Contact', message: "Something wrong happened, try again later"}); res.render('contact', {
title: 'Contact',
message: 'Something wrong happened, try again later',
});
});
}); });
})
/* GET home page. */ /* GET home page. */
router.get('/', function (req, res, next) { router.get('/', function (req, res, _next) {
res.render('contact', {title: 'Contact', description: "Contact me!"}); res.render('contact', { title: 'Contact', description: 'Contact me!' });
}); });
module.exports = router; module.exports = router;

View File

@ -2,7 +2,7 @@ var express = require('express');
var router = express.Router(); var router = express.Router();
/* GET home page. */ /* GET home page. */
router.get('/', function(req, res, next) { router.get('/', function (req, res, _next) {
res.render('index', { title: 'Home', description: "Hello, I'm E" }); res.render('index', { title: 'Home', description: "Hello, I'm E" });
}); });

View File

@ -3,17 +3,17 @@
@font-face { @font-face {
font-family: 'Titling Gothic FB'; font-family: 'Titling Gothic FB';
src: url("../fonts/TITLINGGOTHICFB-WIDE.OTF") format('opentype') src: url('../fonts/TITLINGGOTHICFB-WIDE.OTF') format('opentype');
} }
@font-face { @font-face {
font-family: 'Gilroy'; font-family: 'Gilroy';
src: url("../fonts/Gilroy-ExtraBold.otf") format('opentype') src: url('../fonts/Gilroy-ExtraBold.otf') format('opentype');
} }
@font-face { @font-face {
font-family: 'Apercu Mono'; font-family: 'Apercu Mono';
src: url("../fonts/ApercuMono.ttf") format('truetype'); src: url('../fonts/ApercuMono.ttf') format('truetype');
} }
.wavy { .wavy {

View File

@ -1,13 +1,13 @@
module.exports = { module.exports = {
mode: "jit", mode: 'jit',
purge: ['views/*.pug'], purge: ['views/*.pug'],
darkMode: false, // or 'media' or 'class' darkMode: false, // or 'media' or 'class'
theme: { theme: {
extend: { extend: {
fontFamily: { fontFamily: {
'extra': ['"Titling Gothic FB"'], extra: ['"Titling Gothic FB"'],
'sans': ['Gilroy'], sans: ['Gilroy'],
'mono': ['"Apercu Mono"'], mono: ['"Apercu Mono"'],
}, },
colors: { colors: {
transparent: 'transparent', transparent: 'transparent',
@ -20,14 +20,12 @@ module.exports = {
}, },
green: { green: {
DEFAULT: '#CDE7B0', DEFAULT: '#CDE7B0',
} },
} },
}, },
}, },
variants: { variants: {
extend: {}, extend: {},
}, },
plugins: [ plugins: [require('tailwind-hamburgers')],
require('tailwind-hamburgers'), };
],
}