From 8e769996e13ace583d484358959502122eb7395c Mon Sep 17 00:00:00 2001
From: Enstrayed <48845980+Enstrayed@users.noreply.github.com>
Date: Sun, 23 Jun 2024 12:54:57 -0700
Subject: [PATCH 1/4] working changes for new auth
---
Caddyfile | 1 +
etydFrontend/_static/etyd.js | 58 ++++++++++++++++++++------
etydFrontend/_static/index.css | 7 +++-
etydFrontend/index.html | 75 ++++++++++++----------------------
liberals/auth.js | 36 ++++++++++++++++
routes/etyd.js | 12 ++----
routes/mailjet.js | 7 ++--
7 files changed, 121 insertions(+), 75 deletions(-)
create mode 100644 liberals/auth.js
diff --git a/Caddyfile b/Caddyfile
index eb42a99..aea8b6c 100644
--- a/Caddyfile
+++ b/Caddyfile
@@ -10,6 +10,7 @@
}
handle @staticpaths {
+ respond /favicon.ico 204
root ./etydFrontend
file_server
}
diff --git a/etydFrontend/_static/etyd.js b/etydFrontend/_static/etyd.js
index 5879b9d..79483e7 100644
--- a/etydFrontend/_static/etyd.js
+++ b/etydFrontend/_static/etyd.js
@@ -1,11 +1,22 @@
-//Firefox check
window.onload = function() {
- document.getElementById('resultfeed').value = "hii :3"
if (navigator.userAgent.includes("Firefox")) {
- document.getElementById('resultfeed').value += `\nClipboard functionality does not work on Firefox.`
- document.getElementById('clipboard1').disabled = true
- document.getElementById('clipboard2').disabled = true
+ document.getElementById('resultfeed').value += `\nClipboard buttons only work on Firefox >127.`
}
+
+ // Event listeners can only be added after the page is loaded
+ document.getElementById("actiondropdown").addEventListener("change", function() {
+ if (document.getElementById("actiondropdown").value === "POST") {
+ document.getElementById("randomizationtoggle").disabled = false
+ document.getElementById("valuefield").disabled = false
+ } else if (document.getElementById("actiondropdown").value === "DELETE") {
+ document.getElementById("randomizationtoggle").disabled = true
+ document.getElementById("randomizationtoggle").checked = false
+ randomUrlTick()
+ document.getElementById("valuefield").disabled = true
+ } else {
+ console.error("UI Code Error: Action dropdown event listener function reached impossible state")
+ }
+ })
}
function makeRandomHex(amount) {
@@ -19,6 +30,8 @@ function makeRandomHex(amount) {
return result
}
+
+
function randomUrlTick() {
if (document.getElementById("randomizationtoggle").checked == true) {
document.getElementById("targetfield").disabled = true
@@ -29,9 +42,9 @@ function randomUrlTick() {
}
}
-function buttonCopyResult() {
- navigator.clipboard.writeText(`${document.location.href}${document.getElementById("urlfield").value}`)
-}
+// function buttonCopyResult() {
+// navigator.clipboard.writeText(`${document.location.href}${document.getElementById("urlfield").value}`)
+// }
function buttonFillFromClipboard() {
navigator.clipboard.readText().then(res => {
@@ -39,9 +52,29 @@ function buttonFillFromClipboard() {
})
}
-function postData() {
- fetch("http://nrdesktop:8081/etydwrite", {
- method: "POST",
+// Changes the buttons text to OK for 500ms for action feedback
+// "internal" in this context just means not called from the page
+function internalButtonConfirmation(element) {
+ let normalValue = document.getElementById(element).innerHTML
+ document.getElementById(element).innerHTML = "Ok"
+ setTimeout(function() {
+ document.getElementById(element).innerHTML = normalValue
+ }, 500)
+}
+
+function buttonCopyUrl() {
+ navigator.clipboard.writeText(`this doesn't work rn lol`)
+ internalButtonConfirmation("buttonCopyUrl")
+}
+
+function buttonClearLog() {
+ document.getElementById("resultfeed").value = ""
+ internalButtonConfirmation("buttonClearLog")
+}
+
+function submitData() {
+ fetch(`http://nrdesktop:8081/etyd${document.getElementById("targetfield").value}`, {
+ method: document.getElementById("actiondropdown").value,
mode: "cors",
headers: {
"Authorization": document.getElementById("authfield").value
@@ -57,5 +90,4 @@ function postData() {
}).catch(error => {
document.getElementById("resultfeed").value += `\nError: ${error}`
})
-}
-
+}
\ No newline at end of file
diff --git a/etydFrontend/_static/index.css b/etydFrontend/_static/index.css
index 66ddd02..b4b4698 100644
--- a/etydFrontend/_static/index.css
+++ b/etydFrontend/_static/index.css
@@ -11,6 +11,10 @@ body {
margin-right: 1em;
}
+.marginbottom1em {
+ margin-bottom: 1em;
+}
+
.resultfeed {
height: 100%;
}
@@ -30,7 +34,8 @@ body {
input, select, textarea, button {
background: none;
color: white;
- border: 2px solid white;
+ border: 1px solid white;
+ padding: 1px 2px;
}
input:disabled, button:disabled {
diff --git a/etydFrontend/index.html b/etydFrontend/index.html
index 4b9026d..64e4571 100644
--- a/etydFrontend/index.html
+++ b/etydFrontend/index.html
@@ -1,3 +1,4 @@
+
@@ -7,66 +8,44 @@
etyd.cc
-
etyd.cc URL Shortener
-
-
+
+
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
Instructions
-
- 1. Enter your API Key in the 'Authorization' field
- 2. Enter the shortened URL you want to act upon under the 'URL' field
- 3. Enter the URL that the user will be redirected to under the 'Value' field
- 4. Change 'Action' depending if you want to create or delete a URL
- 5. Press 'POST Data' to submit the form to the server
-
-
-
-
-
Status Code Reference
-
- 400: Bad Request - You will see this if you try and delete a non-existent URL
- 401: Unauthorized - Did you enter your API key?
- 409: Conflict - The entered URL already exists, tick 'Random' and try again
- 500: Internal Server Error - If this happens something has gone very wrong
- 502: Bad Gateway - If you see this the backend is down/unreachable by Caddy
-
-
diff --git a/liberals/auth.js b/liberals/auth.js
new file mode 100644
index 0000000..115523c
--- /dev/null
+++ b/liberals/auth.js
@@ -0,0 +1,36 @@
+const { globalConfig } = require("../index.js")
+
+async function checkToken(token,scope) {
+ return await fetch(`http://${globalConfig.couchdb.host}/auth/sessions`, {
+ headers: {
+ "Authorization": `Basic ${btoa(globalConfig.couchdb.authorization)}`
+ }
+ }).then(fetchRes => {
+
+ // CouchDB should only ever return 200/304 for success so this should work
+ // https://docs.couchdb.org/en/stable/api/document/common.html#get--db-docid
+ if (fetchRes.status !== 200 || fetchRes.status !== 304) {
+ console.log(`ERROR: auth.js: Database request returned ${fetchRes.status}`)
+ return false
+ } else {
+
+ return fetchRes.json().then(dbRes => {
+
+ if (dbRes.sessions[token] == undefined) { // If the token is not on the sessions list then reject
+ return false
+ } else if (dbRes.sessions[token].scopes.includes(scope)) { // If the token is on the seesions list and includes the scope then accept
+ return true
+ } else { // Otherwise reject
+ return false
+ }
+
+ })
+ }
+
+ }).catch(error => {
+ console.log("ERROR: auth.js: " + error)
+ return false
+ })
+}
+
+module.exports = {checkToken}
\ No newline at end of file
diff --git a/routes/etyd.js b/routes/etyd.js
index ca39d10..87ed09a 100644
--- a/routes/etyd.js
+++ b/routes/etyd.js
@@ -1,5 +1,5 @@
const { app, globalConfig } = require("../index.js") // Get globals from index
-const { checkAuthorization } = require("../liberals/authorization.js")
+const { checkToken } = require("../liberals/auth.js")
app.get("/etyd*", (rreq,rres) => {
fetch(`http://${globalConfig.couchdb.host}/etyd${rreq.path.replace("/etyd","")}`, {
@@ -30,9 +30,8 @@ app.delete("/etyd*", (rreq,rres) => {
if (rreq.get("Authorization") === undefined) {
rres.sendStatus(400)
} else {
- checkAuthorization(globalConfig.etyd.authKeysDoc,rreq.get("Authorization")).then(authRes => {
+ checkToken(rreq.get("Authorization"),"etyd").then(authRes => {
if (authRes === false) {
- console.log(`${rreq.get("cf-connecting-ip")} DELETE ${rreq.path} returned 401`) // Log unauthorized requests
rres.sendStatus(401)
} else if (authRes === true) { // Authorization successful
@@ -82,14 +81,12 @@ app.post("/etyd*", (rreq,rres) => {
if (rreq.get("Authorization") === undefined) {
rres.sendStatus(400)
} else {
- checkAuthorization(globalConfig.etyd.authKeysDoc,rreq.get("Authorization")).then(authRes => {
+ checkToken(rreq.get("Authorization"),"etyd").then(authRes => {
if (authRes === false) {
- console.log(`${rreq.get("cf-connecting-ip")} POST ${rreq.path} returned 401`) // Log unauthorized requests
rres.sendStatus(401)
} else if (authRes === true) { // Authorization successful
if (rreq.body["url"] == undefined) {
- console.log(`${rreq.get("cf-connecting-ip")} POST ${rreq.path} returned 400 KEY: ${rreq.get("Authorization")}`)
rres.sendStatus(400)
} else {
fetch(`http://${globalConfig.couchdb.host}/etyd${rreq.path.replace("/etyd", "")}`, {
@@ -106,12 +103,10 @@ app.post("/etyd*", (rreq,rres) => {
switch(dbRes.status) {
case 409:
- console.log(`${rreq.get("cf-connecting-ip")} POST ${rreq.path} returned 409 KEY: ${rreq.get("Authorization")}`)
rres.sendStatus(409)
break;
case 201:
- console.log(`${rreq.get("cf-connecting-ip")} POST ${rreq.path} returned 200 KEY: ${rreq.get("Authorization")}`)
rres.status(200).send(rreq.path.replace("/etyd", ""))
break;
@@ -132,5 +127,4 @@ app.post("/etyd*", (rreq,rres) => {
})
-
module.exports = {app} // export routes to be imported by index for execution
\ No newline at end of file
diff --git a/routes/mailjet.js b/routes/mailjet.js
index b26e9d5..19d5e35 100644
--- a/routes/mailjet.js
+++ b/routes/mailjet.js
@@ -1,9 +1,9 @@
const { app, globalConfig } = require("../index.js") // Get globals from index
-const { checkAuthorization } = require("../liberals/authorization.js")
+const { checkToken } = require("../liberals/auth.js")
app.post("/sendemail", (rreq,rres) => {
- checkAuthorization(globalConfig.mailjet.authKeysDoc,rreq.get("Authorization")).then(authRes => {
+ checkToken(rreq.get("Authorization"),"mailjet").then(authRes => {
if (authRes === false) { // If the supplied authorization is invalid or an error occured
console.log(`${rreq.get("cf-connecting-ip")} POST /sendemail returned 401`) // Log the request
@@ -21,8 +21,7 @@ app.post("/sendemail", (rreq,rres) => {
"Messages": [
{
"From": {
- "Email": globalConfig.mailjet.senderAddress,
- "Name": globalConfig.mailjet.senderName,
+ "Email": globalConfig.mailjet.senderAddress
},
"To": [
{
--
2.49.1
From 9a7a5b69ee356061834b4195aee1a94ab25c04b4 Mon Sep 17 00:00:00 2001
From: = <=>
Date: Wed, 26 Jun 2024 16:48:05 -0700
Subject: [PATCH 2/4] Repo maintenance & add nowplaying
---
.gitignore | 4 ++-
config.example.json | 27 +++++++++++---------
liberals/nowplaying.js | 26 ++++++++++++++++++++
package-lock.json | 56 ++++++++++++++++++++++++++++--------------
package.json | 2 +-
routes/nowplaying.js | 28 ++++++++++++++++++---
6 files changed, 109 insertions(+), 34 deletions(-)
create mode 100644 liberals/nowplaying.js
diff --git a/.gitignore b/.gitignore
index b068519..c4978fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,6 @@
node_modules/
config.json
bun.lockb
-GITVERSION
\ No newline at end of file
+GITVERSION
+todo.txt
+proto.js
\ No newline at end of file
diff --git a/config.example.json b/config.example.json
index 2192d6e..7725a1f 100644
--- a/config.example.json
+++ b/config.example.json
@@ -8,12 +8,6 @@
"host": "hazeldale:5984",
"authorization": ""
},
-
- "cider": {
- "targetHosts": ["localhost:10769"],
-
- "authKeysDoc": "cider"
- },
"mailjet": {
"apiKey": "",
@@ -23,14 +17,25 @@
"authKeysDoc": "mailjet"
},
- "etyd": {
- "randomHexLength": 6,
- "authKeyInDb": "apiAuthKeys.etyd"
- },
-
"blog": {
"postsDirectory": "C:/Users/natha/Downloads/proto/posts",
"postsDirUrl": "/posts"
+ },
+
+ "nowplaying": {
+ "lastfm": {
+ "apiKey": "",
+ "target": "enstrayed"
+ },
+ "jellyfin": {
+ "apiKey": "",
+ "host": "",
+ "target": ""
+ },
+ "cider": {
+ "apiKeys": [],
+ "hosts": []
+ }
}
}
\ No newline at end of file
diff --git a/liberals/nowplaying.js b/liberals/nowplaying.js
new file mode 100644
index 0000000..ab7ec30
--- /dev/null
+++ b/liberals/nowplaying.js
@@ -0,0 +1,26 @@
+const { globalConfig } = require("../index.js")
+
+async function queryLastfm() {
+ return await fetch(`https://ws.audioscrobbler.com/2.0/?format=json&method=user.getrecenttracks&limit=1&api_key=${globalConfig.nowplaying.lastfm.apiKey}&user=${globalConfig.nowplaying.lastfm.target}`).then(response => response.json()).then(response => {
+ if (response["recenttracks"] == undefined) {
+ return 1
+ } else {
+ if (response.recenttracks.track[0]["@attr"] == undefined) {
+ return 1
+ } else {
+ return {
+ "json": {
+ "songName": response.recenttracks.track[0].name,
+ "artistName": response.recenttracks.track[0].artist["#text"],
+ "albumName": response.recenttracks.track[0].album["#text"],
+ "artUrl": response.recenttracks.track[0].image[3]["#text"],
+ "link": response.recenttracks.track[0].url
+ },
+ "html": `
I'm listening to
${response.recenttracks.track[0].name} by ${response.recenttracks.track[0].artist["#text"]}
from ${response.recenttracks.track[0].album["#text"]}