import { Database } from "bun:sqlite";
function escapeHtml(str: string): string {
return str
.replace(/&/g, "&")
.replace(//g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
function homeHtml() {
return `
strings
strings
minimal pastebin
+ New Paste
API
curl -u user:pass -X POST https://strings.witcc.dev/api/paste \\
-H "Content-Type: text/plain" \\
-H "X-Filename: example.py" \\
-d 'print("hello world")'
curl -u user:pass -X POST https://strings.witcc.dev/api/paste \\
-H "Content-Type: application/json" \\
-d '{"content": "print(1)", "filename": "test.py", "slug": "my-snippet"}'
cat myfile.rs | curl -u user:pass -X POST https://strings.witcc.dev/api/paste \\
-H "X-Filename: myfile.rs" \\
--data-binary @-
`;
}
function errorPage(message: string) {
const escaped = escapeHtml(message);
return `
Error - strings
`;
}
function renderPaste(paste: Paste) {
const lang = paste.language || "plaintext";
const filename = paste.filename ? escapeHtml(paste.filename) : paste.id;
const title = `${filename} - strings`;
const content = escapeHtml(paste.content);
return `
${title}
`;
}
function newPastePage(error?: string) {
const errorHtml = error ? `${escapeHtml(error)}
` : "";
return `
New Paste - strings
`;
}
type Paste = {
id: string;
content: string;
filename: string | null;
language: string | null;
created_at: number;
};
// Config from environment
const PORT = parseInt(process.env.PORT || "3000");
const DB_PATH = process.env.DB_PATH || "./strings.db";
const USERNAME = process.env.AUTH_USERNAME || "admin";
// Load auth password from file or env
async function loadPassword(): Promise {
if (process.env.AUTH_PASSWORD_FILE) {
try {
const file = Bun.file(process.env.AUTH_PASSWORD_FILE);
return (await file.text()).trim();
} catch (e) {
console.error("Failed to read AUTH_PASSWORD_FILE:", e);
process.exit(1);
}
}
return process.env.AUTH_PASSWORD || "changeme";
}
const PASSWORD = await loadPassword();
// Initialize database
const db = new Database(DB_PATH);
db.run(`
CREATE TABLE IF NOT EXISTS pastes (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
filename TEXT,
language TEXT,
created_at INTEGER DEFAULT (unixepoch())
)
`);
// Generate random ID
function generateId(length = 8): string {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789";
let result = "";
for (let i = 0; i < length; i++) {
result += chars[Math.floor(Math.random() * chars.length)];
}
return result;
}
// Validate custom slug
function isValidSlug(slug: string): boolean {
return /^[a-zA-Z0-9_-]{1,64}$/.test(slug);
}
// Check if ID exists
function idExists(id: string): boolean {
const row = db.query("SELECT 1 FROM pastes WHERE id = ?").get(id);
return row !== null;
}
// Infer language from filename
function inferLanguage(filename?: string): string | undefined {
if (!filename) return undefined;
const ext = filename.split(".").pop()?.toLowerCase();
const langMap: Record = {
js: "javascript",
ts: "typescript",
jsx: "javascript",
tsx: "typescript",
py: "python",
rb: "ruby",
rs: "rust",
go: "go",
java: "java",
c: "c",
cpp: "cpp",
h: "c",
hpp: "cpp",
cs: "csharp",
php: "php",
swift: "swift",
kt: "kotlin",
scala: "scala",
sh: "bash",
bash: "bash",
zsh: "bash",
fish: "fish",
ps1: "powershell",
sql: "sql",
html: "html",
css: "css",
scss: "scss",
sass: "sass",
less: "less",
json: "json",
yaml: "yaml",
yml: "yaml",
toml: "toml",
xml: "xml",
md: "markdown",
markdown: "markdown",
nix: "nix",
dockerfile: "dockerfile",
makefile: "makefile",
cmake: "cmake",
ex: "elixir",
exs: "elixir",
erl: "erlang",
hs: "haskell",
lua: "lua",
r: "r",
jl: "julia",
vim: "vim",
tf: "hcl",
};
return ext ? langMap[ext] : undefined;
}
// Basic auth helper
function checkAuth(req: Request): boolean {
const authHeader = req.headers.get("Authorization");
if (!authHeader || !authHeader.startsWith("Basic ")) {
return false;
}
const base64Credentials = authHeader.slice(6);
const credentials = atob(base64Credentials);
const [username, password] = credentials.split(":");
return username === USERNAME && password === PASSWORD;
}
function unauthorizedResponse(): Response {
return new Response("Unauthorized", {
status: 401,
headers: {
"WWW-Authenticate": 'Basic realm="Secure Area"',
},
});
}
function getOrCreateId(customSlug?: string): string {
if (customSlug) {
if (!isValidSlug(customSlug)) {
throw new Error("Invalid slug. Use 1-64 alphanumeric characters, hyphens, or underscores.");
}
if (idExists(customSlug)) {
throw new Error("Slug already taken");
}
return customSlug;
}
let id: string;
do {
id = generateId();
} while (idExists(id));
return id;
}
// Router
async function handleRequest(req: Request): Promise {
const url = new URL(req.url);
const path = url.pathname;
const method = req.method;
// Create paste - API
if (method === "POST" && path === "/api/paste") {
if (!checkAuth(req)) return unauthorizedResponse();
const contentType = req.headers.get("Content-Type") || "";
let content: string;
let filename: string | undefined;
let language: string | undefined;
let customSlug: string | undefined;
if (contentType.includes("application/json")) {
const body = await req.json();
content = body.content;
filename = body.filename;
language = body.language;
customSlug = body.slug;
} else {
content = await req.text();
filename = req.headers.get("X-Filename") || undefined;
language = req.headers.get("X-Language") || undefined;
customSlug = req.headers.get("X-Slug") || undefined;
}
if (!content) {
return Response.json({ error: "Content is required" }, { status: 400 });
}
let id: string;
try {
id = getOrCreateId(customSlug);
} catch (e: any) {
const status = e.message.includes("taken") ? 409 : 400;
return Response.json({ error: e.message }, { status });
}
if (!language && filename) {
language = inferLanguage(filename);
}
db.run(
"INSERT INTO pastes (id, content, filename, language) VALUES (?, ?, ?, ?)",
[id, content, filename || null, language || null]
);
const baseUrl = process.env.BASE_URL || `http://localhost:${PORT}`;
return Response.json({
id,
url: `${baseUrl}/${id}`,
raw: `${baseUrl}/${id}/raw`,
});
}
// Create paste - Form submission
if (method === "POST" && path === "/new") {
if (!checkAuth(req)) return unauthorizedResponse();
const form = await req.formData();
const content = form.get("content") as string;
const filename = (form.get("filename") as string) || undefined;
const language = (form.get("language") as string) || undefined;
const customSlug = (form.get("slug") as string) || undefined;
if (!content) {
return new Response(newPastePage("Content is required"), {
status: 400,
headers: { "Content-Type": "text/html" },
});
}
let id: string;
try {
id = getOrCreateId(customSlug);
} catch (e: any) {
const status = e.message.includes("taken") ? 409 : 400;
return new Response(newPastePage(e.message), {
status,
headers: { "Content-Type": "text/html" },
});
}
const inferredLang = language || inferLanguage(filename || undefined);
db.run(
"INSERT INTO pastes (id, content, filename, language) VALUES (?, ?, ?, ?)",
[id, content, filename || null, inferredLang || null]
);
return Response.redirect(`${url.origin}/${id}`, 302);
}
// New paste form
if (method === "GET" && path === "/new") {
if (!checkAuth(req)) return unauthorizedResponse();
return new Response(newPastePage(), {
headers: { "Content-Type": "text/html" },
});
}
// Delete paste
if (method === "DELETE" && path.match(/^\/[^/]+$/)) {
if (!checkAuth(req)) return unauthorizedResponse();
const id = path.slice(1);
const result = db.run("DELETE FROM pastes WHERE id = ?", [id]);
if (result.changes === 0) {
return Response.json({ error: "Paste not found" }, { status: 404 });
}
return Response.json({ deleted: true });
}
// Get raw paste
if (method === "GET" && path.match(/^\/[^/]+\/raw$/)) {
const id = path.slice(1, -4);
const paste = db.query("SELECT * FROM pastes WHERE id = ?").get(id) as Paste | null;
if (!paste) {
return new Response("Paste not found", { status: 404 });
}
return new Response(paste.content, {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
}
// Get paste (HTML view)
if (method === "GET" && path.match(/^\/[^/]+$/)) {
const id = path.slice(1);
if (id === "new" || id === "api") {
return new Response(errorPage("Not found"), {
status: 404,
headers: { "Content-Type": "text/html" },
});
}
const paste = db.query("SELECT * FROM pastes WHERE id = ?").get(id) as Paste | null;
if (!paste) {
return new Response(errorPage("Paste not found"), {
status: 404,
headers: { "Content-Type": "text/html" },
});
}
return new Response(renderPaste(paste), {
headers: { "Content-Type": "text/html" },
});
}
// Home page
if (method === "GET" && path === "/") {
return new Response(homeHtml(), {
headers: { "Content-Type": "text/html" },
});
}
return new Response(errorPage("Not found"), {
status: 404,
headers: { "Content-Type": "text/html" },
});
}
console.log(`strings running on http://localhost:${PORT}`);
export default {
port: PORT,
fetch: handleRequest,
};