-- Leo's gemini proxy

-- Connecting to git.thebackupbox.net:1965...

-- Connected

-- Sending request

-- Meta line: 20 text/gemini

repo: nostr
action: commit
revision:
path_from:
revision_from: dcd949c36658df03c6ac2861664af7d052e8e87a:
path_to:
revision_to:

git.thebackupbox.net

nostr

git://git.thebackupbox.net/nostr

commit dcd949c36658df03c6ac2861664af7d052e8e87a
Author: epoch <epoch@thebackupbox.net>
Date:   Wed Apr 26 02:42:49 2023 +0000

    went too long without putting this in a repo

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..2ed413eb3cf75be48f5c2ff4619de17fdd691702
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,5 @@
+PREFIX:=/usr/local
+
+install:
+	install -Dt $(PREFIX)/libexec/ nostr-relay.sh
+	install -Dt $(PREFIX)/libexec/ nostr-relay-req.sh
diff --git a/client.html b/client.html
new file mode 100755
index 0000000000000000000000000000000000000000..ab81a722c19b4d72d649f3c7d78ff228f3d72947
--- /dev/null
+++ b/client.html
@@ -0,0 +1,183 @@
+<html>
+  <head>
+    <title></title>
+  </head>
+<style>
+body {
+  font-family: sans-serif;
+}
+.post {
+  border-style: solid;
+  border-width: 3px;
+}
+</style>
+<script>
+
+event_kind = Array();
+event_kind[0] = "Metadata";
+event_kind[1] = "Short Text Note";
+event_kind[2] = "Recommend Relay";
+event_kind[3] = "Contacts";
+event_kind[4] = "Encrypted Direct Messages";
+event_kind[5] = "Event Deletion";
+event_kind[6] = "Resposts";
+event_kind[7] = "Reaction";
+event_kind[8] = "Badge Award";
+event_kind[40] = "Channel Creation";
+event_kind[41] = "Channel Metadata";
+event_kind[42] = "Channel Message";
+event_kind[43] = "Channel Hide Message";
+event_kind[44] = "Channel Mute User";
+event_kind[1063] = "File Metadata";
+event_kind[1984] = "Reporting";
+event_kind[9734] = "Zap Request";
+event_kind[9735] = "Zap";
+event_kind[10000] = "Mute List";
+event_kind[10001] = "Pin List";
+event_kind[10002] = "Relay List Metadata";
+event_kind[22242] = "Client Authentication";
+event_kind[24133] = "Nostr Connect";
+event_kind[30000] = "Categorized People List";
+event_kind[30001] = "Categorized Bookmark List";
+event_kind[30008] = "Profile Badges";
+event_kind[30009] = "Badge Definition";
+event_kind[30017] = "Create or update a stall";
+event_kind[30018] = "Create or update a product";
+event_kind[30023] = "Long-form Content";
+event_kind[30078] = "Application-specific Data";
+
+var i=0;
+var public_key="";
+var relays;
+
+var open_subs=[];
+
+function set_public_key(x) {
+  public_key=x;
+  document.getElementById("pubkey").value=x;
+}
+
+function send_req(ws) {
+  uuid=crypto.randomUUID();
+  msg=["REQ",crypto.randomUUID(),{"kinds":[4],"#p":[public_key],"limit":1000}];
+  ws.send(JSON.stringify(msg));
+  open_subs.push([msg,ws]);
+}
+
+function set_plaintext(node, str) {
+  node.textContent = str;
+}
+
+function handle_message(x) {
+  msg=JSON.parse(x.data);
+  if(msg[0] != "EVENT") {
+    console.log(msg);
+    return;
+  }
+  feed=document.getElementById("feed");
+  post=document.createElement("div");
+  post.setAttribute("class","post");
+  post.appendChild(document.createTextNode("msg type: " + msg[0]));
+  post.appendChild(document.createElement("br"));
+  post.appendChild(document.createTextNode("from " + x.originalTarget.url));
+  post.appendChild(document.createElement("br"));
+  post.created_at = msg[2].created_at;
+  post.appendChild(document.createTextNode("created at:" + msg[2].created_at));
+  post.appendChild(document.createElement("br"));
+  post.appendChild(document.createTextNode("sub id:" + msg[1]));
+  post.appendChild(document.createElement("br"));
+  post.appendChild(document.createTextNode("event kind: " + event_kind[msg[2].kind] + "(" + msg[2].kind + ")"));
+  post.appendChild(document.createElement("br"));
+  author = msg[2].pubkey;
+  post.appendChild(document.createTextNode("author: " + author));
+  post.appendChild(document.createElement("br"));
+  if(msg[2].kind == 0) { // metadata
+    metadata=JSON.parse(msg[2].content);
+    picture=document.createElement("img");
+    picture.setAttribute("src",metadata.picture);
+    post.appendChild(picture);
+    post.appendChild(document.createTextNode("metadata: " + msg[2].content));
+    post.appendChild(document.createElement("br"));
+  }
+  if(msg[2].kind == 1) { // short text note
+    post.appendChild(document.createTextNode("event content: " + msg[2].content));
+    post.appendChild(document.createElement("br"));
+  }
+  if(msg[2].kind == 4) { // encrypted direct message
+    post.appendChild(document.createTextNode(x.data));
+    mine=0;
+    for(i=0;i<msg[2].tags.length && !mine;i++) {
+      if(msg[2].tags[i][0] == "p") {
+        for(j=1;j<msg[2].tags[i].length && !mine;j++) {
+          if(msg[2].tags[i][j] == public_key) {
+            mine=1;
+          }
+        }
+      }
+    }
+    if(mine) {
+      text_node = document.createTextNode("decrypting...");
+      post.appendChild(text_node);
+      window.nostr.nip04.decrypt(msg[2].pubkey,msg[2].content).then(x => { set_plaintext(text_node, x); })
+    } else {
+      post.appendChild(document.createTextNode("not for you"));
+    }
+  }
+  if(msg[2].kind == 6) { // reposts
+    post.appendChild(document.createTextNode("repost"));
+    post.appendChild(document.createElement("br"));
+  }
+  if(msg[2].kind == 7) { // reaction
+    post.appendChild(document.createTextNode("reaction"));
+    post.appendChild(document.createElement("br"));
+  }
+  for(i=0;i<feed.children.length;i++) { //loop over all children, and insert before older
+    if(post.created_at > feed.children[i].created_at) {
+      feed.insertBefore(post,feed.children[i]);
+      return;
+    }
+  }
+  feed.appendChild(post,feed);
+}
+
+function set_relays(x) {
+  relays = x; //relays is a global
+  urls = Object.keys(relays);
+  urls.forEach(function(url) {
+    var ws = new WebSocket(url);
+    ws.onmessage = function(event) {
+      handle_message(event);
+    };
+    ws.error = function(error) {
+      console.log('websocket error: ' + error);
+    };
+    ws.onopen = function(ws) { send_req(this); };
+    ws.onclose = function(ws) { console.log("closing " + url); };
+  });
+}
+
+function nostr_onload() {
+  window.nostr.getPublicKey().then(x => { set_public_key(x); });
+  window.nostr.getRelays().then(x => { set_relays(x); });
+}
+
+function check_for_nostr() {
+  if(!window.nostr) {
+    if(i > 10) { // sure
+      alert("you do not appear to have a nostr plugin");
+    }
+    setTimeout(check_for_nostr,200);
+    i++;
+    return;
+  }
+  nostr_onload();
+}
+
+onload = check_for_nostr;
+</script>
+  <body>
+    your public key: <input id="pubkey" name="pubkey" value="loading..." />
+    <div id="feed">
+    </div>
+  </body>
+</html>
diff --git a/nip-05-test.cgi b/nip-05-test.cgi
new file mode 100755
index 0000000000000000000000000000000000000000..8dbd725c7bd907642a83c2ce275bf15f52ef0032
--- /dev/null
+++ b/nip-05-test.cgi
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+
+acct="$(uriunescape "$(query_param acct)")"
+user="$(cut -d@ -f1 <<< "$acct")"
+host="$(cut -d@ -f2 <<< "$acct")"
+url="https://${host}/.well-known/nostr.json?user=${user}"
+
+if [ "$1" = "stage2" ];then
+#  env
+  printf 'Server: %s<br/>' "$HTTP_SERVER"
+  if [ ! "$HTTP_ACCESS_CONTROL_ALLOW_ORIGIN" ];then
+    printf '<span class="warn">WARNING</span>: missing Access-Control-Allow-Origin header<br/>\n'
+  else
+    printf '<span class="good">GOOD</span>: Access-Control-Allow-Origin header present!<br/>'
+  fi
+  if [ "$HTTP_ACCESS_CONTROL_ALLOW_ORIGIN" != '*' ];then
+    printf '<details><summary><span class="warn">WARNING</span>: Access-Control-Allow-Origin header has wrong value. it is "%s" and should be "*"</summary>\n' "$HTTP_ACCESS_CONTROL_ALLOW_ORIGIN"
+    printf 'for NGINX:<br/>'
+    printf '<pre>'
+    printf 'location /.well-known/nostr.json {\n'
+    printf '	add_header Access-Control-Allow-Origin "*";\n'
+    printf '}\n'
+    printf '</pre>\n'
+    printf 'for Apache2:<br/>'
+    printf '<pre>'
+    printf 'a2enmod headers\n'
+    printf 'Header set Access-Control-Allow-Origin "*"\n'
+    printf '</pre>\n'
+    printf '</details>'
+  else
+   printf '<span class="good">GOOD</span>: Access-Control-Allow-Origin header is set right.<br/>\n'
+  fi
+  if [ "$HTTP_CONTENT_TYPE" != "application/json" ];then
+    printf '<span class="warn">WARNING</span>: content-type returned is not application/json but %s<br/>\n' "$HTTP_CONTENT_TYPE"
+  else
+    printf '<span class="good">GOOD</span>: content-type returns is application/json<br/>\n'
+  fi
+  RESP_DATA="$(cat)"
+  printf '<pre>'
+  #env
+  if jq -r . <<< "$RESP_DATA";then
+    printf '</pre>\n'
+    printf '<span class="good">GOOD</span>: properly formatted JSON.<br/>\n'
+  else
+    printf '</pre>\n'
+    printf '<span class="err">ERROR</span>: JSON failed to parse. see jq error message.<br/>\n'
+  fi
+  pubkey="$(jq -r '.names.'"$user"'//""' <<< "$RESP_DATA")"
+  if [ "${pubkey}" ];then
+    printf '<span class="good">GOOD</span>: public key found for user %s! %s<br/>' "$user" "$pubkey"
+  else
+    printf '<span class="warn">WARNING</span>: public key not found for user %s<br/>' "$user"
+  fi
+  npub="$(bech32 -e -h npub "$pubkey")"
+  printf '<a href="nostr:%s">nostr:%s</a>' "$npub" "$npub"
+  exit 0
+fi
+
+printf 'Content-Type: text/html\r\n\r\n'
+
+printf '<html><head>\n'
+printf '<title>nip-05 tester</title>\n'
+printf '<style>\n'
+cat <<EOF
+body {
+  background-color: black;
+  color: white;
+}
+.warn {
+  color: yellow;
+}
+.err {
+  color: red;
+}
+.good {
+  color: lime;
+}
+EOF
+printf '</style>\n'
+printf '</head><body>'
+
+if [ "$acct" ];then
+  printf 'spec: <a href="https://github.com/nostr-protocol/nips/blob/master/05.md">NIP-05</a><br/>'
+  printf 'user: %s<br/>' "$user"
+  printf 'host: %s<br/>' "$host"
+  printf 'url: <a href="%s">%s</a><br/>' "$url" "$url"
+  curl -A "thebackupbox.net nip-05 tester" -sig "$url" | /usr/local/libexec/read_headers $0 stage2
+fi
+
+printf '</body></html>'
diff --git a/nostr-relay-req.sh b/nostr-relay-req.sh
new file mode 100755
index 0000000000000000000000000000000000000000..42a898cbaaf4fca5af10f4d6bf542859e1caf210
--- /dev/null
+++ b/nostr-relay-req.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+db=/var/db/nostr/relay
+
+REMOTE_ADDR="$1"
+id="$2"
+shift
+shift
+# filters are now "$@"
+
+jq --unbuffered -nc 'inputs | [.[0],"'$id'",.[1]]' < "${db}"
+
+printf '["EOSE", "%s"]\n' "$id"
+
+### this won't die naturally. we need to have parent process kill it when it dies.
+
+nonblocktail <(tail -n 0 -f "${db}") | jq --unbuffered -nc 'inputs | [.[0],"'$id'",.[1]]'
diff --git a/nostr-relay.sh b/nostr-relay.sh
new file mode 100755
index 0000000000000000000000000000000000000000..28335e94613d471764e293e8632093073a676cd5
--- /dev/null
+++ b/nostr-relay.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+
+db=/var/db/nostr/relay
+
+printf '["NOTICE","hello, %s."]\n' "$REMOTE_ADDR"
+if [ "$REMOTE_ADDR" != "21.41.41.4" ];then
+	printf '["NOTICE","PLEASE DO NOT USE THIS SERVER. STILL BEING WORKED ON."]\n'
+	exit 0
+fi
+
+#i=0
+#while true;do
+#  printf '["NOTICE","%s"]\n' "$(perl -e "print 'A'x$i")"
+#  i=$[$i+1]
+#  sleep .2
+#done
+
+### w00t. thank you https://stackoverflow.com/questions/41599314/ignore-unparseable-json-with-jq
+jq -Rnc 'inputs | fromjson?' | while read -r msg;do
+	logger -p crit "nostr-relay $$ msg: $msg"
+	case "$(jq -r '.[0]//""' <<< "$msg")" in
+		EVENT)
+			if [ "$REMOTE_ADDR" != "21.41.41.4" ];then
+				printf '["NOTICE","DO NOT USE THIS SERVER. STILL BEING WORKED ON."]\n'
+				continue
+			fi
+                        printf '%s\n' "$msg" >> "${db}"
+			printf '["NOTICE","got an EVENT from you. :)"]\n'
+                        ### TODO: validate event somehow
+                        ### store this event somewhere
+                ;;
+		REQ)
+			### TODO: make the subid contain
+                        subid="$(jq -r '.[1]' <<< "$msg")"
+			printf '["NOTICE","got a REQ from you. :)"]\n'
+			#filter="$(jq -r '.[2]' <<< "$msg")" ## only supporting one filter atm
+                        ### I figure we need to fork off a background process to keep a watch on incoming events from everywhere
+                        ### not sure how well we can CLOSE those though... kill %n based on job id?
+                        stdbuf -o0 /usr/local/libexec/nostr-relay-req.sh "$REMOTE_ADDR" "${subid}" "${filter}" & 2>/dev/null
+                        ### oooooh.
+                ;;
+		CLOSE)
+                        subid="$(jq -r '.[1]' <<< "$msg")"
+			printf '["NOTICE","closing sub id: %s"]\n' "$subid"
+                        ### somehow kill the right process or job id
+                        kill "%/usr/local/libexec/nostr-replay-req.sh ${REMOTE_ADDR} ${subid}"
+                ;;
+		DEBUG)
+			cmd="$(jq -r '.[1]' <<< "$msg")"
+			printf '["NOTICE","%s"]\n' "$($cmd)"
+		;;
+		*)
+			logger -p crit "$$ unexpected message: $msg"
+                        printf '["NOTICE","unexpected message type received: '%s' msg: '%s'"]\n' "$type" "$msg"
+                        #exit 0
+                ;;
+        esac
+	logger -p crit "$$ got passed the case"
+done

-----END OF PAGE-----

-- Response ended

-- Page fetched on Sun Jun 2 14:50:07 2024