diff --git a/README.md b/README.md index 242b130..f38b08c 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ network = "caddy" restart = "unless-stopped" extra_args = ["--network=postgres"] environment = """ -DATABASE_URI=postgres://nowaybuddy:nowaybuddy@postgres:5432/api +DATABASE_URL=postgres://nowaybuddy:nowaybuddy@postgres:5432/api """ ``` diff --git a/index.js b/index.js index 15b9e52..bd1f427 100644 --- a/index.js +++ b/index.js @@ -6,12 +6,12 @@ import cookieParser from 'cookie-parser' const app = express() -if (!process.env.DATABASE_URI) { +if (!process.env.DATABASE_URL) { console.log("FATAL: DATABASE_URI must be set") process.exit(1) } -const db = postgres(process.env.DATABASE_URI) +const db = postgres(process.env.DATABASE_URL) const globalConfig = await db`select content from config where id = ${process.env.CONFIG_OVERRIDE ?? 'production'}`.then(response => {return response[0]["content"]}).catch(error => { console.log(`FATAL: Error occured in downloading configuration: ${error}`) diff --git a/routes/dynamic.js b/routes/dynamic.js new file mode 100644 index 0000000..905777b --- /dev/null +++ b/routes/dynamic.js @@ -0,0 +1,11 @@ +import { app, fs } from "../index.js" + +app.get("/dynamic/icon/*", (rreq, rres) => { + try { + let file = fs.readFileSync(process.cwd()+`/website/dynamic/icons/${rreq.path.split("/")[3]}.svg`,"utf-8") + file = file.replace("", "#"+rreq.path.split("/")[4].slice(0,6)) + rres.setHeader("Content-Type","image/svg+xml").send(file) + } catch { + rres.sendStatus(404) + } +}) \ No newline at end of file diff --git a/routes/helpdesk.js b/routes/helpdesk.js index d456bb5..3d97927 100644 --- a/routes/helpdesk.js +++ b/routes/helpdesk.js @@ -1,11 +1,24 @@ -import { app } from "../index.js" +import { app, fs } from "../index.js" +import { marked } from "marked" app.get("/helpdesk", (rreq, rres) => { rres.sendFile(process.cwd()+"/website/helpdesk/templates/landing.html") }) +app.get("/helpdesk/articles", (rreq, rres) => { + rres.send("miau") +}) + app.get("/helpdesk/articles/*", (rreq, rres) => { - rres.sendFile(process.cwd()+"/website/helpdesk/kbas/"+rreq.url.replace("/helpdesk/articles/","")) + if (rreq.url.endsWith(".md")) { + let file = fs.readFileSync(process.cwd() + "/website/helpdesk/templates/article.html", "utf-8") + file = file.replace("", `https://enstrayed.com${rreq.url}`) + file = file.replaceAll("", rreq.url.replace("/posts/", "").slice(9).replace(/-/g, " ").replace(".md", "")) + file = file.replace("", marked.parse(fs.readFileSync(process.cwd() + "/website/helpdesk/kbas/" + rreq.url.replace("/helpdesk/articles/", ""), "utf-8"))) + rres.send(file) + } else { + rres.sendFile(process.cwd() + "/website/helpdesk/kbas" + rreq.url.replace("/helpdesk/articles/", "")) + } }) app.get("/helpdesk/ticket/new", (rreq,rres) => { diff --git a/website/static/icons/arrow-right.svg b/website/dynamic/icons/arrow-right.svg similarity index 87% rename from website/static/icons/arrow-right.svg rename to website/dynamic/icons/arrow-right.svg index 1094594..a4071e9 100644 --- a/website/static/icons/arrow-right.svg +++ b/website/dynamic/icons/arrow-right.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/website/static/icons/external.svg b/website/dynamic/icons/external.svg similarity index 89% rename from website/static/icons/external.svg rename to website/dynamic/icons/external.svg index afc5079..ef0cbf9 100644 --- a/website/static/icons/external.svg +++ b/website/dynamic/icons/external.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/website/static/icons/github.svg b/website/dynamic/icons/github.svg similarity index 92% rename from website/static/icons/github.svg rename to website/dynamic/icons/github.svg index 90e3f81..4fb64e5 100644 --- a/website/static/icons/github.svg +++ b/website/dynamic/icons/github.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/website/static/icons/link.svg b/website/dynamic/icons/link.svg similarity index 89% rename from website/static/icons/link.svg rename to website/dynamic/icons/link.svg index ff2f0dc..899c12e 100644 --- a/website/static/icons/link.svg +++ b/website/dynamic/icons/link.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/website/static/icons/post.svg b/website/dynamic/icons/post.svg similarity index 88% rename from website/static/icons/post.svg rename to website/dynamic/icons/post.svg index e96c37b..57416d4 100644 --- a/website/static/icons/post.svg +++ b/website/dynamic/icons/post.svg @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/website/static/icons/twitter.svg b/website/dynamic/icons/twitter.svg similarity index 91% rename from website/static/icons/twitter.svg rename to website/dynamic/icons/twitter.svg index e08ec79..d567755 100644 --- a/website/static/icons/twitter.svg +++ b/website/dynamic/icons/twitter.svg @@ -1,3 +1,3 @@ - + \ No newline at end of file diff --git a/website/helpdesk/kbas/ECLS-Change_Password.md b/website/helpdesk/kbas/ECLS-Change_Password.md new file mode 100644 index 0000000..ca5068c --- /dev/null +++ b/website/helpdesk/kbas/ECLS-Change_Password.md @@ -0,0 +1,11 @@ +# Change your ECLS password + +1. Login to your ECLS account at https://login.enstrayed.com +2. Select the settings icon in the top right of your screen
+![Screenshot showing where the settings icon is on the screen](https://i.enstrayed.com/20250714-555ab544.jpg) +3. Enter your new password twice and press 'Save' to change your password
+![Screenshot showing the password change screen](https://i.enstrayed.com/20250714-55e8b1a8.jpg) + +## I can't login to my ECLS account + +[Click here for information about how to reset your ECLS password](https://enstrayed.com/helpdesk/articles/ECLS-Reset_Password.md) \ No newline at end of file diff --git a/website/helpdesk/kbas/Enstrayed_Cloud-App_Passwords.md b/website/helpdesk/kbas/Enstrayed_Cloud-App_Passwords.md new file mode 100644 index 0000000..18586a7 --- /dev/null +++ b/website/helpdesk/kbas/Enstrayed_Cloud-App_Passwords.md @@ -0,0 +1,17 @@ +# Using App Passwords on Enstrayed Cloud + +App Passwords are credentials used to access your Enstrayed Cloud account from a specific application or device. They are created automatically for many Nextcloud clients, or can be created manually using the steps below. + +**As Enstrayed Cloud exclusively uses ECLS for sign on, you will need to create app passwords for any device that does not support browser login.** + +To create an App Password: + +1. Login to Enstrayed Cloud +2. Select your profile image in the top right of the page and select 'Personal Settings'
+![Screenshot showing steps to access Personal Settings in Enstrayed Cloud](https://i.enstrayed.com/20250716-55f5388f.jpg) +3. In the sidebar on the left side of the page, select 'Security'
+![Screenshot highlighting the Security tab on the left sidebar](https://i.enstrayed.com/20250716-55ad5071.jpg) +4. Enter a description for the app password, such as the device name or application, then select 'Create new app password'
+![Screenshot showing steps to create an app password](https://i.enstrayed.com/20250716-5512d99f.jpg) +5. You will be presented with a username and unique password; You will use these credentials to access Enstrayed Cloud from your application.
+![Screenshot showing the prompt displaying the newly created app password](https://i.enstrayed.com/20250716-55dc2a4d.jpg) \ No newline at end of file diff --git a/website/helpdesk/templates/article.html b/website/helpdesk/templates/article.html new file mode 100644 index 0000000..58075b8 --- /dev/null +++ b/website/helpdesk/templates/article.html @@ -0,0 +1,32 @@ + + + + + + Enstrayed Helpdesk - <!--SSR_REPLACE_TITLE--> + + + + + +
+

Enstrayed Helpdesk

+ Open Ticket + Knowledgebase + +
+ +
+
+
+
+ +
+
+ +

Warning

+

This is a warning

+ +
+ + \ No newline at end of file diff --git a/website/helpdesk/templates/landing.html b/website/helpdesk/templates/landing.html index 16ba4b7..b181f65 100644 --- a/website/helpdesk/templates/landing.html +++ b/website/helpdesk/templates/landing.html @@ -25,20 +25,20 @@
I'm filing a legal request, such as a DMCA takedown or other legal matter
- Click here to start a Legal Request + Click here to start a Legal Request
I'm responsibly disclosing a problem, such a security vulnerability
- Click here to start a Responsible Disclosure + Click here to start a Responsible Disclosure
I need help logging into my ECLS account
- Click here to reset your ECLS password
- Click here to start ECLS account recovery + Click here to reset your ECLS password
+ Click here to start ECLS account recovery
I have another question or need to get in contact
- Click here to start a General Inquiry + Click here to start a General Inquiry
@@ -47,19 +47,19 @@
How do I use Security Keys in ECLS?
- Important ECLS FIDO2/Webauthn/Passkey Information + Important ECLS FIDO2/Webauthn/Passkey Information
How do I login to Jellyfin?
- Logging into Jellyfin + Logging into Jellyfin
How do I change my ECLS password?
- Change ECLS Password + Change ECLS Password
How do I use federation features in Enstrayed Cloud?
- Enstrayed Cloud Federation Features + Enstrayed Cloud Federation Features
diff --git a/website/posts/20240409-API-Documentation.html b/website/posts/20240409-API-Documentation.html index cee6fdf..d3196bd 100644 --- a/website/posts/20240409-API-Documentation.html +++ b/website/posts/20240409-API-Documentation.html @@ -16,19 +16,12 @@ Return to enstrayed.com

API Documentation

-

This page was last updated 2025-04-26.

+

This page was last updated 2025-07-08.

Source Code & Issue Tracker: github.com/enstrayed/enstrayedapi


-
-

Important Note

-
- -

Multiple API endpoints are being rewritten/added, especially relating to authentication & authorization, as part of a database change to Postgres. These changes are being made in the new-db branch.

- -

/api/nowplaying

nowplaying.js @@ -140,6 +133,21 @@

Internal Use Only. This is the endpoint used by ECLS to finish the login flow. It will write the newly created token to the APIToken cookie as well as performing the action set by state, see login endpoint.

+
+

/api/helpdesk/forms/*

+ helpdesk.js:15 +
GET
+
+ +

Internal Use Only. Serves all files in the website/helpdesk/forms directory for use in the Helpdesk frontend.

+ + \ No newline at end of file diff --git a/website/posts/20250619-UniFi-Network-on-Orange-Pi-Zero-3.md b/website/posts/20250619-UniFi-Network-on-Orange-Pi-Zero-3.md new file mode 100644 index 0000000..81fbc43 --- /dev/null +++ b/website/posts/20250619-UniFi-Network-on-Orange-Pi-Zero-3.md @@ -0,0 +1,54 @@ +# Setting up the UniFi Network Controller on an Orange Pi Zero 3 + +This page covers the steps I went through to setup the UniFi Network controller on an Orange Pi Zero 3. For no reason obvious to me, this process was overcomplicated and very annoying. + +## Background / The Problem +I purchased the Orange Pi Zero 3 because it was cheap and I wanted to move my UniFi controller out of the Docker container on my main server. The idea was to create a DIY UniFi CloudKey, hence I called mine `shitty-cloudkey`. On the surface, this is rather trivial; Ubiquiti's apt repository includes `arm64` packages and the UniFi controller itself is a Java application, making it rather portable. + +The problem is that the UniFi controller depends on MongoDB for its database, and [MongoDB's system requirements](https://www.mongodb.com/docs/manual/administration/production-notes/#arm64) require the ARM V8.4-A microarchitecture at minimum (in english: Cortex A73 cores or later). The Zero 3 has Cortex A53 cores, which do not have the instruction sets required. I never really investigated the reasoning for this, but given that this makes Mongo's published builds incompatible with the Raspberry Pi 4, I find it rather strange, since that doesn't really strike me as an especially old SBC? + +## Part 1: Installing Armbian +I'll be honest, I normally don't mess around with SBCs so had no idea what the go-to distro was for RasPi clones. After what was probably less than 30 seconds of searching, I decided to use Armbian since it did exactly what I needed: Debian 12 ready to go. + +1. the boring shit + * `winget install balena.etcher` + 1. Download https://dl.armbian.com/orangepizero3/Bookworm_current_minimal + 2. select the file, select your sd card, press flash, blah blah blah +2. the slightly less boring shit + 1. plug in the SD card, ethernet & power, wait for it to startup + 2. go to your dhcp server and find whatever IP it grabbed for itself + 3. `ssh root@`, default password is `1234` (Thank you armbian devs for letting you do the install process remotely) + 4. Go through the setup process, now is a great time to do a `apt update && apt upgrade`, set a hostname and possibly static IP address + 5. reboot for good measure + +## Part 2: Installing MongoDB the dumb way + +1. Download and install `libssl1.1`, I don't actually know if this is required anymore but it stops apt from complaining + 1. `curl -OL https://archive.debian.org/debian/pool/main/o/openssl/libssl1.1_1.1.1n-0+deb10u3_arm64.deb` + 2. `sudo dpkg -i libs` +2. Download and install some old version of MongoDB I found; Won't actually be using the binary from this, but it gives us the systemd unit file and resolves the dependency in apt + 1. `curl -OL https://repo.mongodb.org/apt/ubuntu/dists/bionic/mongodb-org/4.4/multiverse/binary-arm64/mongodb-org-server_4.4.29_arm64.deb` + 2. `sudo dpkg -i mong` +3. Download a `mongod` binary that actually works from a [MongoDB employee's personal GitHub](https://github.com/themattman/mongodb-raspberrypi-binaries) yes really + * You may want to check for a more up to date build but w/e, select the one marked `pi4` + 1. `curl -OL https://github.com/themattman/mongodb-raspberrypi-binaries/releases/download/r7.0.14-rpi-unofficial/mongodb.ce.pi4.r7.0.14.tar.gz` + 2. `tar xvf mong` + 3. `sudo mv mongod /usr/bin/mongod` +* Side note that I discovered later: UniFi manages the mongod process directly so you can keep the systemd service disabled. + +## Part 3: Installing UniFi Network +This next section is loosly modified from Ubiquiti's official setup instructions: https://help.ui.com/hc/en-us/articles/220066768-Updating-and-Installing-Self-Hosted-UniFi-Network-Servers-Linux + +1. `sudo apt-get update && sudo apt-get install ca-certificates apt-transport-https` +2. `echo 'deb [ arch=amd64,arm64 ] https://www.ui.com/downloads/unifi/debian stable ubiquiti' | sudo tee /etc/apt/sources.list.d/100-ubnt-unifi.list` +3. `curl -L -o /etc/apt/trusted.gpg.d/unifi-repo.gpg https://dl.ui.com/unifi/unifi-repo.gpg` +4. `sudo apt update` +5. `sudo apt install unifi` + +## The End +UniFi should be up and running by this point, if it isn't then bash it with `sudo systemctl restart unifi` until it shows something at `https://:8443`. If that still doesnt work, `sudo cat /usr/lib/unifi/logs/server.log` may provide a clue, or maybe it wont. FEW MORE THINGS: + +* If you are migrating from another UniFi network install, FOR THE LOVE OF GOD DO NOT USE THE RESTORE BUTTON DURING THE INITIAL SETUP. Go through the setup process, *set your password*, and then go into Settings > System > Backups and use the restore button there. +* If you, like me, did the above and found out that everything breaks, you can factory reset it by changing `is_default=` to `true` in `/var/lib/unifi/system.properties`. Don't forget to change it back after you run through the setup again. +* I shat out this article at 1 AM so basically did no proof-reading or fact checking so the section about MongoDB's system requirements is probably wrong, LOL. +* Armbian has a lot of warnings about using community editions and I got a rather loud warning during my install saying that I was using an automated build that wasn't for production use. It wasn't marked as such on the website and frankly I don't care. I have to assume this is supposed to be normie-proofing but it, like this entire ordeal, strikes me as bizarre. Recommendation: make sure to take backups somewhat often. \ No newline at end of file diff --git a/website/static/bridge2.jpg b/website/static/bridge2.jpg new file mode 100644 index 0000000..ede0ac7 Binary files /dev/null and b/website/static/bridge2.jpg differ diff --git a/website/static/helpdesk/helpdesk.css b/website/static/helpdesk/helpdesk.css index 084a94a..6a4e234 100644 --- a/website/static/helpdesk/helpdesk.css +++ b/website/static/helpdesk/helpdesk.css @@ -51,6 +51,25 @@ body { margin: 0 0 0.5em 0; } +.articlecontent { + background-color: #fff; + padding: 2em; + margin: 2em 0 2em; + max-width: 100ch; +} + +.articlecontent > h1 { + margin: 0 0 0.5em; +} + +.articlecontent > ol > li { + margin: 0 0 0.2em; +} + +.articlecontent img { + max-width: 100%; +} + .linkColumn { display: flex; flex-direction: column; diff --git a/website/static/newindex.css b/website/static/newindex.css index ca7755d..eaf5234 100644 --- a/website/static/newindex.css +++ b/website/static/newindex.css @@ -1,14 +1,26 @@ +html { + background-color: #0f0f0f; + background-image: url('/static/bridge2.jpg'); + /*! background-size: 100%; */ + background-position-y: 50%; + background-position-x: center; + height: 100%; +} + body { margin: 0; - font-family: 'Segoe UI Variable', sans-serif; + font-family: 'Segoe UI Variable Text', sans-serif; + height: 100%; - background-color: #282828; display: grid; place-items: center; - + backdrop-filter: blur(10px); + + color: #fff; + } .mainContent { @@ -18,13 +30,18 @@ body { gap: 2.5em; padding: 2em; - background-color: #fdfdfd; - box-shadow: 0 0 1em 0 #202020; + background-color: #0f0f0f; + box-shadow: 0 0 1em 0 #0f0f0f; + position: relative; margin-top: 96px; } +.mainContent > div > h1, h2 { + margin: 0 0 0.5em; +} + .linkColumn { display: flex; flex-direction: column; @@ -63,19 +80,27 @@ body { } .blogPostsList > ul { - list-style-image: url('/static/icons/post.svg'); + list-style-image: url('/dynamic/icon/post/7CB342'); list-style-position: inside; padding: 0; margin: 0; - gap: 0.5em; +} + +.blogPostsList > ul > li { + margin: 0.5em 0 0; + font-family: Consolas, monospace; +} + +.blogPostsList > ul > li > a { + font-family: 'Segoe UI Variable', sans-serif; } a, a:link { - color: #366FFF; + color: #7CB342; } a:hover { - color: #ff8266; + color: #9CCC65; } a > img { diff --git a/website/static/newposts.css b/website/static/newposts.css index b7f53c9..8eb053c 100644 --- a/website/static/newposts.css +++ b/website/static/newposts.css @@ -6,7 +6,7 @@ html { body { margin: 2em 0 0 0; - font-family: 'Segoe UI Variable', sans-serif; + font-family: 'Segoe UI Variable Text', sans-serif; background-color: #202020; color: #F1F1F1; @@ -40,4 +40,23 @@ a:hover { padding: 0.2rem; color: white; background-color: #f06445; +} + +p { + line-height: 120%; +} + +code { + background: #181818; + line-height: 130%; + padding: 0 0.1rem 0; + font-family: Consolas, monospace; +} + +pre code { + display: block; + overflow-x: auto; + white-space: pre-wrap; + background: #181818; + padding: 1rem; } \ No newline at end of file diff --git a/website/templates/construction.html b/website/templates/construction.html index 658f7c2..ad7055a 100644 --- a/website/templates/construction.html +++ b/website/templates/construction.html @@ -16,6 +16,7 @@ height: 100%; color: #fff; background-color: #0b0b0b; + font-family: sans-serif; } body > div { diff --git a/website/templates/newindextemplate.html b/website/templates/newindextemplate.html index eeea358..211a85e 100644 --- a/website/templates/newindextemplate.html +++ b/website/templates/newindextemplate.html @@ -37,20 +37,20 @@