Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: stackernews/booger
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.0.2-sigma
Choose a base ref
...
head repository: stackernews/booger
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
  • 7 commits
  • 27 files changed
  • 1 contributor

Commits on Jun 25, 2023

  1. deployment changes

    huumn committed Jun 25, 2023
    Copy the full SHA
    7ac8aaf View commit details
  2. fix plugs bugs

    huumn committed Jun 25, 2023
    Copy the full SHA
    5afe266 View commit details

Commits on Jun 26, 2023

  1. Copy the full SHA
    2427f54 View commit details
  2. correct casing on nip11 json

    huumn committed Jun 26, 2023
    Copy the full SHA
    eac24ba View commit details

Commits on Jun 27, 2023

  1. Copy the full SHA
    fc8a964 View commit details
  2. Copy the full SHA
    259496b View commit details

Commits on Aug 9, 2023

  1. Copy the full SHA
    482bbd1 View commit details
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -11,6 +11,12 @@ booger
booger.jsonc
release/

# deployment files
copilot/
db.pem
Dockerfile
.dockerignore

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -104,7 +104,7 @@ corresponding values provided in `./booger.jsonc`

| name | booger.jsonc name |
| ----------- | ----------------------- |
| `BIND` | bind |
| `HOSTNAME` | hostname |
| `PORT` | port |
| `DB` | db |
| `DB_STATS` | plugs.builtin.stats.db |
@@ -133,7 +133,7 @@ Options:
write default config to ./booger.jsonc
-c, --config <path>
path to booger config file (default: ./booger.jsonc)
-b, --bind <ip or hostname>
-b, --hostname <ip or hostname>
interface to listen on (default: 127.0.0.1)
0.0.0.0 for all interfaces
-p, --port <port>
39 changes: 18 additions & 21 deletions conf.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { parse as jsoncParse } from 'std/jsonc/mod.ts'
import { parse as flagsParse } from 'std/flags/mod.ts'
import { loadSync } from 'std/dotenv/mod.ts'
import { deepMerge } from 'std/collections/deep_merge.ts'
import { deepMerge, envLoadSync, flagsParse, jsoncParse } from './deps.ts'

const args = flagsParse(Deno.args, {
string: [
'config',
'port',
'bind',
'hostname',
'db',
'db-stats',
'db-limits',
@@ -20,7 +17,7 @@ const args = flagsParse(Deno.args, {
alias: {
c: 'config',
p: 'port',
b: 'bind',
b: 'hostname',
d: 'db',
s: 'db-stats',
l: 'db-limits',
@@ -47,20 +44,20 @@ const CONFIG = `// default configuration file for booger
// the port to listen on (precedence cli > env(PORT) > config file)
"port": 8006,
// the ip or hostname to listen on (precedence cli > env(BIND) > config file)
"bind": "127.0.0.1",
// the ip or hostname to listen on (precedence cli > env(HOSTNAME) > config file)
"hostname": "127.0.0.1",
// postgres url for nostr data (precedence cli > env(DB) > config file)
// if this db does not exist, booger will try to create it for you
"db": "postgres://127.0.0.1:5432/booger",
// exactly how booger will respond to nip-11 requests
"nip11": {
"Name": "booger",
"Description": "a booger relay",
"PubKey": "",
"Contact": "",
"SupportedNIPs": [
"name": "booger",
"description": "a booger relay",
"pubkey": "",
"contact": "",
"supported_nips": [
1,
2,
4,
@@ -75,8 +72,8 @@ const CONFIG = `// default configuration file for booger
33,
40
],
"Software": "https://github.com/stackernews/booger",
"Version": "${VERSION}"
"software": "https://github.com/stackernews/booger",
"version": "${VERSION}"
},
// configuration related to booger plugs
@@ -197,8 +194,8 @@ Options:
write default config to ./booger.jsonc
-c, --config <path>
path to booger config file (default: ./booger.jsonc)
-b, --bind <ip or hostname>
interface to listen on (default: ${config.bind})
-b, --hostname <ip or hostname>
interface to listen on (default: ${config.hostname})
0.0.0.0 for all interfaces
-p, --port <port>
port to listen on (default: ${config.port})
@@ -274,7 +271,7 @@ const delUndefined = (obj) => JSON.parse(JSON.stringify(obj))

const cliConfig = delUndefined({
port: args.port,
bind: args.bind,
hostname: args.hostname,
db: args['db'],
plugs: {
dir: args['plugs'],
@@ -291,12 +288,12 @@ const cliConfig = delUndefined({
})

if (args.dotenv) {
loadSync({
envLoadSync({
export: true,
envPath: args.dotenv,
restrictEnvAccessTo: [
'PORT',
'BIND',
'HOSTNAME',
'DB',
'DB_STATS',
'DB_LIMITS',
@@ -307,7 +304,7 @@ if (args.dotenv) {
const envConfig = delUndefined({
version: VERSION,
port: Deno.env.get('PORT'),
bind: Deno.env.get('BIND'),
hostname: Deno.env.get('HOSTNAME'),
db: Deno.env.get('DB'),
plugs: {
builtin: {
2 changes: 1 addition & 1 deletion deno.jsonc
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@

// sub-secure-task adds restricted permissions via $DENO_PERMS then runs the deno task provided in $DENO_TASK
// XXX the postgres module attempts to access an *abundance* of env vars related to postgres (and there's no way to silently deny them)
"sub-secure-task": "DENO_PERMS='--allow-net=127.0.0.1,localhost --allow-read=./booger.jsonc,./plugs --allow-write=./booger.jsonc --allow-env=BIND,PORT,DB,DB_STATS,DB_LIMITS,PGHOST,PGPORT,PGDATABASE,PGUSERNAME,PGUSER,PGPASSWORD,PGIDLE_TIMEOUT,PGCONNECT_TIMEOUT,PGMAX,PGMAX_LIFETIME,PGMAX_PIPELINE,PGSSL,PGBACKOFF,PGKEEP_ALIVE,PGPREPARE,PGDEBUG,PGFETCH_TYPES,PGPUBLICATIONS,PGTARGET_SESSION_ATTRS,PGTARGETSESSIONATTRS,USERNAME,USER,LOGNAME' deno task $DENO_TASK",
"sub-secure-task": "DENO_PERMS='--allow-net=127.0.0.1,localhost --allow-read=./booger.jsonc,./plugs,./index.html --allow-write=./booger.jsonc --allow-env=HOSTNAME,PORT,DB,DB_STATS,DB_LIMITS,PGHOST,PGPORT,PGDATABASE,PGUSERNAME,PGUSER,PGPASSWORD,PGIDLE_TIMEOUT,PGCONNECT_TIMEOUT,PGMAX,PGMAX_LIFETIME,PGMAX_PIPELINE,PGSSL,PGBACKOFF,PGKEEP_ALIVE,PGPREPARE,PGDEBUG,PGFETCH_TYPES,PGPUBLICATIONS,PGTARGET_SESSION_ATTRS,PGTARGETSESSIONATTRS,USERNAME,USER,LOGNAME' deno task $DENO_TASK",
// sub-normal-task adds permissive permissions via $DENO_PERMS and runs the deno task provided in $DENO_TASK
"sub-normal-task": "DENO_PERMS=-A deno task $DENO_TASK",
// sub-run takes $DENO_EXT and $DENO_PERMS and runs deno run
9 changes: 9 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export { walk } from 'std/fs/walk.ts'
export { globToRegExp } from 'std/path/glob.ts'
export { readLines } from 'std/io/read_lines.ts'
export { basename, dirname } from 'std/path/mod.ts'
export { parse as jsoncParse } from 'std/jsonc/mod.ts'
export { parse as flagsParse } from 'std/flags/mod.ts'
export { loadSync as envLoadSync } from 'std/dotenv/mod.ts'
export { crypto, toHashString } from 'std/crypto/mod.ts'
export { deepMerge } from 'std/collections/deep_merge.ts'

export { default as postgres } from 'postgres'
export { z } from 'zod'
export { schnorr } from 'secp'
export { DB as sqlite } from 'sqlite'

88 changes: 88 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>booger pro - a nostr relay</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="a nostr relay">
<meta property="og:title" content="booger pro">
<meta property="og:image" content="https://repository-images.githubusercontent.com/600535448/9137f473-3d04-4a50-aa38-687294dc1500">
<meta property="og:url" content="https://booger.pro">
<meta name="twitter:card" content="summary_large_image">
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAMAAABHPGVmAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAMAUExURQAAACmUEJTYUhqWDITTU4nRXEOkIF2zNDmqDzinG2afYlykUx2PEJztLpTmIIHEXCygDjWbFy6YGiydGBaGECeYEheXCxKGDCWYEguFByaWEBONCSSSEFvYL4DKUCeYDFiqQgBgAajqRYfTShqUCheeCyu1FkWuIVKyLoi3io3mIX/PRYLROwiABV21QFOwNg+ADAtxCSKmDHzdFpneM57gKgOWAm7LID6lHCS2FErIJIPdJXzVKj+sHEO3IKXaWWHCN0LONz7EDDS0EEu+LEHEKo7eLmG3J2e+K1CvGWrDLWa5K1ywIQKDAD2sA1+zJgiJAFq4IVLJCFayHgN9ACmfAFu8HG7BMmq9Lky9B0yvFTemAh+MAD6gCUm2CF+9JEimEzWbA1KzGgadAFmuIkOyBgWQAFG2FmvkGnbLOSCaAE3EBk2qGBWrARmwAVrCGIXVJVvRDhmUAxyhA2jUIAF3AGS8J1rcD27HLy+WAVa4GVC5DjOgAnXPNla9FFSqHlLDCWHSFSWUAIj0KUCmCnLFNUqxD2e3H3zRQE+jGnrMJmHBG1rKDzazB3HLNFG+DXzeDC2lA47ZJJXYJXzWI2LKHmLXEW/UFQiXAUWrDGOzH3fGJo/sD47vKmTcGTTCA2rOJn/aQmzcHW+/JBiHAG/MGkDdB4jeSGTEJWLKEyWpAimOADybCmvFG3zSHJrkIxKOACmyBTOsAY/pRFHQClLYDie9BYPtJ5X4K4TVL57xFVnDD57tR3TgIKTwODDPA577OGu9H2LoEWzLLXfUOHLTL0G6BXruJgmkAHbeMjzQBzO6BrT1VYPcGI3iG4TlDBOAAI7aMhObAZzhPQauABW5AyXHBUfLB3TFH4DcOKr7RX/3HLj+Qan7UKr+O8v/WESeEZnZMwNwAovkN6fzSoLlMTDYC0LFCeD/U232D5PyD3TpJxTIAJDoM331RJH+OT66FJvvPX7RKqf4Fn7kIUrfF378K173KFbwFvT/ZJLoU6/lIrX0LHbrFsb+Sc//N8R29Q4AAADNdFJOUwBkOq4PLykDCBRAZ2398CEdMqLAn33diVjli9BN/YNBVvz+UvLE6LycSeRsofGNcL3T8uzU6fnY7vb10b7bzrrH3NPLz9LM//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////7wvxhLAAANpUlEQVRo3s3ZZ1RbZ5oAYBEIxYYY9+7Yjp14kkmcZCaTSWYyMzu7e656r0hIAiSBRBFqIESTRDVIovfeqzG9VwOmGhtMMQbcbdwdl9hxEmfmE5td58fuj7nAOfuewzkSP+6j7/3K+957EYj/N2G1ed8ui13vOtr+z39s7Bwd7WzX6vp2u7bv2XL0cx9vn9mZHZbbLXbtsrC3377T8uiOHXs/3Wb/rt3qCduNfzmT19gSdvf06dN3vy/tmZ0t7ZmZfXl79rb5y4Pp4T/s3Wm92jQdM8T/9HP389S55byx5ry8vJ7R0pUYBdHT03P79oNp0W5729UZadl37jz0PLPs6Tm3vJzX7OO9Ej7/Fd7Dw9MzD2ZEuJ2rUY6ntd/5OWdk5MYTBweHnJyW1x7+/k1NjU3+uR7m8J/L83Fzm/ZJX43y9pftdxZ7n4yDuNm9wuS0tITltOSsRGtOS5eH/6i3SDTjhrOHjXxy7h8/dT/pHB9futQa1jJ0fyjsTbQMtYQNdXUV5jbV4UQzot2bYRqbvnz2U3f3k4YfGm515fo3NYI0gTXmAf5O+698BWkrLMz1r8Ole+O2wUzYe2fbT3V3NxQUjBQWyjxZLE9yo//C6camRn9/jyEP/8a5ueU5WW5aWmodzjv943fhIQfutZ9yeFIWPT/Ssni5Sxunlelyw7pkMpnH67DLlxe7PMkgZKlpabIpERiKDRzD5rft7Q4ONwaCR0ZaW3tbtIFxKfn5KVJNiDTOE4RBy40jp6ZqDWlpaWdEw27wZsXqz/cmTj2cN/UPFr4e8pBm8J3oPJIrytU9MjxciGfjuR0VFUqlNFCXVqNTpHuLtsOa9z+1TyTeCkb3K2UeL5QavhfJj0dCOTllhLODgoIyQpQjI4P55XR3aVpNmjHdO32vI5xd8uGzicRkdHm+TrYwlM8LxTJMSBIw2Oz6BD1NmKJU5g8OBEOu9JLkZPKU97BoFxzknfZTifk8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" />
<style>
body {
background-color: #171717;
margin: 0;
}

.grid {
width: 100dvw;
height: 100dvh;
display: grid;
grid-template-rows: 1fr auto;
}

.img-row {
grid-row: 1;
display: grid;
align-items: center;
justify-items: center;
padding: 1rem;
}

img {
inline-size: 100%;
max-inline-size: 800px;
block-size: auto;
aspect-ratio: 2/1;
object-fit: contain;
}

.link-row {
grid-row: 2;
display: flex;
inline-size: 100%;
max-inline-size: 800px;
margin: auto;
justify-content: space-around;
font-size: max(16px, min(4vw, 24px));
font-family: monospace;
padding: 3rem 0rem;
}

input {
all: unset;
color: #c4c4c4;
cursor: text;
}

a:hover {
text-decoration: wavy underline #9999ff;
}

a {
color: #9999ff;
text-decoration: none;
}
</style>
<script>
const url = new URL(window.location.href);
url.protocol = url.protocol.replace('http', 'ws');
url.pathname = '';
window.addEventListener("DOMContentLoaded", (event) => {
document.querySelector('input').value = url.href.slice(0, -1);
});
</script>
</head>
<body>
<div class="grid">
<div class="img-row">
<img width="1280" height="640" src="https://repository-images.githubusercontent.com/600535448/9137f473-3d04-4a50-aa38-687294dc1500" alt="booger pro - a nostr relay">
</div>
<div class="link-row">
<input onclick="this.select();" value="wss://booger.pro" readonly>
<a href="https://github.com/stackernews/booger">source code</a>
</div>
</div>
</body>
</html>
Loading