first commit (ty gemini)
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
links*
|
||||||
21
description.md
Normal file
21
description.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
This project is a checker for the Caddy On Demand TLS service.
|
||||||
|
This is intended to be used with Caddy as the server to check if a domain is valid.
|
||||||
|
All domains should be allowed.
|
||||||
|
However, each domain should have a maximum of 100 certificates for it.
|
||||||
|
|
||||||
|
ie:
|
||||||
|
example.com, test.example.com, and testing.tester.example.com count as 3 certificates for example.com
|
||||||
|
|
||||||
|
The domain should also have a maximum of 5 parts
|
||||||
|
1.2.3.example.com is valid
|
||||||
|
1.2.3.4.example.com is not valid
|
||||||
|
|
||||||
|
If a domain is already in the database, it should return a 200 and not add it to the database.
|
||||||
|
|
||||||
|
As an example:
|
||||||
|
/check?domain=example.com -> 200 & added to database
|
||||||
|
/check?domain=example.com -> 200
|
||||||
|
/check?domain=1.example.com -> 200 & added to database
|
||||||
|
/check?domain=this.is.a.long.domain.example.com -> 400
|
||||||
|
... after 100 domains
|
||||||
|
/check ?domain=100.example.com -> 400
|
||||||
91
index.js
Normal file
91
index.js
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import { Database } from "bun:sqlite";
|
||||||
|
import express from "express";
|
||||||
|
const port = process.env.PORT || 3000;
|
||||||
|
|
||||||
|
const db = new Database("links.sqlite");
|
||||||
|
db.exec("PRAGMA journal_mode = WAL;");
|
||||||
|
|
||||||
|
db.run(`
|
||||||
|
CREATE TABLE IF NOT EXISTS links (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
link TEXT,
|
||||||
|
base_domain TEXT
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
db.exec("CREATE UNIQUE INDEX IF NOT EXISTS unique_link ON links(link);");
|
||||||
|
db.exec("CREATE INDEX IF NOT EXISTS idx_base_domain ON links(base_domain);");
|
||||||
|
|
||||||
|
// Migration for existing databases
|
||||||
|
try {
|
||||||
|
const columns = db.query("PRAGMA table_info(links)").all();
|
||||||
|
if (!columns.find(c => c.name === "base_domain")) {
|
||||||
|
db.run("ALTER TABLE links ADD COLUMN base_domain TEXT");
|
||||||
|
db.run("CREATE INDEX IF NOT EXISTS idx_base_domain ON links(base_domain)");
|
||||||
|
// Backfill would go here, but skipping for brevity/performance on startup
|
||||||
|
// In a real app, we'd run a migration script.
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const domainCount = db.prepare(
|
||||||
|
"SELECT COUNT(*) AS count FROM links WHERE base_domain = $base"
|
||||||
|
);
|
||||||
|
const duplicateLink = db.prepare(
|
||||||
|
"SELECT 1 FROM links WHERE link = $link LIMIT 1"
|
||||||
|
);
|
||||||
|
const insert = db.prepare("INSERT OR IGNORE INTO links (link, base_domain) VALUES ($link, $base_domain)");
|
||||||
|
|
||||||
|
const getBaseDomain = (hostname) => {
|
||||||
|
let parts = hostname.split(".");
|
||||||
|
if (parts.length <= 2) {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
return parts.slice(-2).join(".");
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseDomain = (input) => {
|
||||||
|
if (!input.includes("://")) {
|
||||||
|
input = "https://" + input;
|
||||||
|
}
|
||||||
|
return new URL(input);
|
||||||
|
};
|
||||||
|
|
||||||
|
app.get("/check", async (req, res) => {
|
||||||
|
if (!req.query.domain) {
|
||||||
|
return res.status(400).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain;
|
||||||
|
try {
|
||||||
|
domain = parseDomain(req.query.domain);
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(400).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const hostname = domain.hostname.toLowerCase();
|
||||||
|
if (hostname.split(".").length > 5) {
|
||||||
|
return res.status(400).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duplicateLink.get({ $link: hostname })) {
|
||||||
|
return res.status(200).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseDomain = getBaseDomain(hostname);
|
||||||
|
const { count } = domainCount.get({ $base: baseDomain });
|
||||||
|
if (count >= 3) {
|
||||||
|
return res.status(400).end();
|
||||||
|
}
|
||||||
|
|
||||||
|
insert.run({ $link: hostname, $base_domain: baseDomain });
|
||||||
|
|
||||||
|
return res.status(200).end();
|
||||||
|
});
|
||||||
|
|
||||||
|
const server = app.listen(port, () => {
|
||||||
|
console.log("Express is online.");
|
||||||
|
console.log("- http://localhost:" + port);
|
||||||
|
});
|
||||||
12
package.json
Normal file
12
package.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "caddy-byod-v2",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"author": "",
|
||||||
|
"type": "commonjs",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user