diff --git a/assets/elements.css b/assets/elements.css
index 89b9f12..03c863d 100644
--- a/assets/elements.css
+++ b/assets/elements.css
@@ -77,7 +77,7 @@ a {
text-decoration: underline solid currentColor 1px;
}
-code {
+code, kbd {
display: inline-block;
max-width: 100%;
box-sizing: border-box;
@@ -109,7 +109,7 @@ select {
outline: 1ch solid var(--color-text);
}
-input[type=text], input[type=url], textarea, select {
+input[type=text], input[type=url], input[type=password], textarea, select {
padding-inline: 1ch;
border-inline: 1ch solid var(--color-accent);
background-color: var(--color-bg-scrim);
diff --git a/assets/fonts/Lexend/Lexend.ttf b/assets/fonts/Lexend/Lexend.ttf
new file mode 100644
index 0000000..e895baf
Binary files /dev/null and b/assets/fonts/Lexend/Lexend.ttf differ
diff --git a/assets/print.css b/assets/print.css
new file mode 100644
index 0000000..b326180
--- /dev/null
+++ b/assets/print.css
@@ -0,0 +1,15 @@
+footer,
+.matkap_ascii,
+.noprint {
+ display: none !important;
+}
+
+@font-face {
+ font-family: "Lexend";
+ font-weight: regular;
+ src: url("./Lexend/Lexend.ttf");
+}
+
+html {
+ font-family: "Lexend";
+}
\ No newline at end of file
diff --git a/index.js b/index.js
index 39bbcbd..bc5fa63 100644
--- a/index.js
+++ b/index.js
@@ -8,6 +8,7 @@ import { JSDOM } from "jsdom";
import Parser from "rss-parser";
import nacl from "tweetnacl";
import expressBasicAuth from "express-basic-auth";
+import crypto from "node:crypto";
import { getRelativeTime } from "./modules/relativeTime.js";
import { fromHex } from "./modules/fromHex.js";
@@ -487,6 +488,98 @@ app.get('/updates', async (req, res) => {
});
});
+const enc_key = Buffer.from(process.env.RESUME_ENCRYPTION_KEY, "hex");
+
+app.get('/resumeEnc', async (req, res) => {
+ const iv = crypto.randomBytes(16);
+ const cipher = crypto.createCipheriv(
+ "aes-256-cbc", enc_key, iv
+ );
+
+ let encrypted = cipher.update(req.query.text, 'utf8', 'hex');
+ encrypted += cipher.final('hex');
+
+ res.send(encrypted + "\n" + iv.toString('hex'));
+});
+
+function decipher(file, key) {
+ let hexKey;
+ try {
+ hexKey = Buffer.from(key, "hex");
+ } catch (err) {
+ throw err;
+ }
+
+ const [enc, iv] = file.split("\n");
+
+ let decipher;
+ try {
+ decipher = crypto.createDecipheriv(
+ "aes-256-cbc", hexKey, Buffer.from(iv, "hex")
+ );
+ } catch (err) {
+ throw err;
+ }
+
+ let decrypted = decipher.update(enc, 'hex', 'utf8');
+ decrypted += decipher.final('utf8');
+
+ let decryptedJSON;
+ try {
+ decryptedJSON = JSON.parse(decrypted);
+ } catch (err) {
+ throw err;
+ }
+ return decryptedJSON;
+}
+
+app.get('/resume', async (req, res) => {
+ if (req.query.key == null || req.query.key.length < 1) return res.render('resumeEntry', { badError: false });
+ const encryptedPD = await fetch(process.env.RESUME_DATA)
+ .catch(() => res.status(500).send())
+ .then((res) => res.text());
+ const encryptedJobs = await fetch(process.env.RESUME_JOBS)
+ .catch(() => res.status(500).send())
+ .then((res) => res.text());
+ const encryptedEducation = await fetch(process.env.RESUME_EDU)
+ .catch(() => res.status(500).send())
+ .then((res) => res.text());
+ const unencryptedOrgs = await fetch(process.env.RESUME_ORGS)
+ .catch(() => res.status(500).send())
+ .then((res) => res.json());
+
+ let unencryptedPD;
+ try {
+ unencryptedPD = decipher(encryptedPD, req.query.key);
+ } catch (err) {
+ console.error(err);
+ return res.render('resumeEntry', { badError: true });
+ }
+ let unencryptedJobs;
+ try {
+ unencryptedJobs = decipher(encryptedJobs, req.query.key);
+ } catch (err) {
+ console.error(err);
+ return res.render('resumeEntry', { badError: true });
+ }
+ let unencryptedEducation;
+ try {
+ unencryptedEducation = decipher(encryptedEducation, req.query.key);
+ } catch (err) {
+ console.error(err);
+ return res.render('resumeEntry', { badError: true });
+ }
+
+ console.log(unencryptedOrgs)
+
+ res.render('resume', {
+ pd: unencryptedPD,
+ jobs: unencryptedJobs,
+ education: unencryptedEducation,
+ orgs: unencryptedOrgs
+ });
+});
+
app.get('/sites', async (req, res) => {
const buttonsJson = await fetch("https://cdn.abtmtr.link/site_content/buttons.json")
.catch(() => res.status(500).send())
diff --git a/sitemap.json b/sitemap.json
index 517af61..102c564 100644
--- a/sitemap.json
+++ b/sitemap.json
@@ -23,6 +23,10 @@
"link": "sites",
"description": "a collection of other sites in the form of 88x31s."
},
+ {
+ "link": "resume",
+ "description": "my job history, in general."
+ },
{
"link": "about",
"description": "who runs abtmtr.link?"
diff --git a/views/components/page-head.ejs b/views/components/page-head.ejs
index 7591766..057768b 100644
--- a/views/components/page-head.ejs
+++ b/views/components/page-head.ejs
@@ -4,7 +4,9 @@
abtmtr.link
-
+
+
+
diff --git a/views/pages/resume.ejs b/views/pages/resume.ejs
new file mode 100644
index 0000000..a69f49e
--- /dev/null
+++ b/views/pages/resume.ejs
@@ -0,0 +1,159 @@
+
+
+ <%- include("../components/page-head.ejs") %>
+
+
+
+ <%= pd.name[0] %> <%= pd.name[1][0] %>. <%= pd.name[2] %>
+
+
+ <%= pd.phone.region %> (<%= pd.phone.area %>) <%= pd.phone.local %>
+ /
+
+ <%= pd.email %>
+
+
+
+ <%= pd.address.street_address %>
+ <%= pd.address.city %>,
+ <%= pd.address.state %>
+ <%= pd.address.postal %>
+
+
+
+ Hint: Use CTRL P to print this page and get a more readable layout.
+
+
+ Organizations / Volunteering
+
+ Education
+
+ <% education.forEach((school) => { %>
+ -
+
+
+
+ <%= school.address.street_address %>,
+ <%= school.address.city %>,
+ <%= school.address.state %>
+ <%= school.address.postal %>
+
+
+
+ <%= school.start || "???" %> - <%= school.end || "Present" %>
+ Learned <%= school.experience.join(", ") %>
+
+
+ <% }); %>
+
+ Experience
+
+ <% jobs.forEach((job) => { %>
+ -
+
+
+
+ <%= job.address.street_address %>,
+ <%= job.address.city %>,
+ <%= job.address.state %>
+ <%= job.address.postal %>
+
+
+
+
+ Learned <%= job.experience.join(", ") %>
+
+
+ <% }); %>
+
+
+ <%- include("../components/footer.ejs") %>
+ <%- include("../components/post-main.ejs") %>
+
+
\ No newline at end of file
diff --git a/views/pages/resumeEntry.ejs b/views/pages/resumeEntry.ejs
new file mode 100644
index 0000000..402d8ce
--- /dev/null
+++ b/views/pages/resumeEntry.ejs
@@ -0,0 +1,27 @@
+
+
+ <%- include("../components/page-head.ejs") %>
+
+
+ resume
+ my job history, in general.
+ enter a key
+ you are attempting to access my resume.
+ this information is key-protected and will remain that way for some amount of time.
+
+
+ <%- include("../components/footer.ejs") %>
+ <%- include("../components/post-main.ejs") %>
+
+
\ No newline at end of file