Introducing Nostr
Updates for March 18, 2023
Before I dive into Nostr, I’ll share a few updates. I may start posting these types of updates, even if I don’t have other finished projects to share, rather than posting nothing for weeks at a time. It’ll give me a chance to sum up my week and stay accountable to myself for making progress. Feel free to skip them if you aren’t interested.
Self-hosting Update
I have a few different self-hosting projects in the works, but for the previous few weeks I’ve been challenged to get any one project finished to the point where I can post about them. I spent time on:
- Tweaking Crowdsec k3s whitelists and parsing rules.
- Moving end user devices to a dedicated VLAN (off of the untagged network).
- Adjusting firewall rules to allow everyone to still do everything they could before the move.
- Trying to set up a webtop application to facilitate making my Logseq notes accessible from anywhere securely before giving up and just using Git.
- Setting up an append-only Restic repository
Business Update
A few weeks ago, an IT Managed Services client notified me that he was getting some unusual e-mails. I investigated and determined that they were probably part of a sextortion scam, but they did send him a password he actually used, most likely from a previous breach.
I also determined that this was a very simple password and it was the same password used for a number of different accounts, including his e-mail. I don’t manage his e-mail for him, so I advised him to change his password on any accounts where he used this password and enable MFA. I also reminded him that I had already sold him a company-wide password manager which, to date only, one employee had let me onboard them. He’s in his 80s and doesn’t like change.
Fast forward a week. He’s no longer able to send e-mails, they all bounce with the message “Tenant Exceeded Threshold” from Microsoft Exchange Online. I had to reset his password to find out that 1) he was using a Global Admin account as a daily driver, 2) his recovery e-mail had been changed, 3) a mail connector was set up and enabled. Before being shut down Microsoft, his tenant had sent out about 96,000 e-mails through the connector.
It was quite an adventure to get him to lock down his account(s) to the degree required for Microsoft to unblock his tenant. In the middle, he was diagnosed with Covid and handed everything over to me to handle. Did I mention he hasn’t purchased a managed e-mail plan from me? That’ll be a discussion we have in the near future.
The latter part of this week was dedicated to mitigating CVE-2023-23397 by blocking TCP 445 SMB outbound and ensuring that Office updates were applied as soon as they were available. This remote exploit allows an attacker to get Outlook to leak the NTLMv2 hash by sending a meeting request with a custom notification sound set to a UNC path that the attacker controls. It’s a critical severity vulnerability with evidence of being exploited in the wild. Fun times.
What is Nostr?
Nostr is “a lightweight, simple yet extensible open protocol that allows building truly censorship resistant and decentralized social media platforms.” It is not an app, there are many apps which use the Nostr protocol.
How does Nostr different from other federated networks such as the fediverse or Matrix? Even though they are federated and decentralized, they still require that you sign up to a specific instance to be your “home” in the network. All of your data lives on that instance so you must trust the instance owner to both maintain your privacy and not disappear. Migrating instances has gotten easier, but it still requires some preparation.
Relays
Nostr is based on public/private key cryptography and it’s encapsulated in a very simple protocol. Every event in the network is signed by your keypair and published to at least one relay. Clients only talk to relays and relays (usually) don’t talk to each other. In order to retrieve events sent by a given Nostr user, a client needs to query at least one relay to which that user has posted events.
Events
Events are the building block of the Nostr protocol. They are simply JSON objects with only a few fields:
- id - unique identifier of the event on the network
- kind - the kind of event with 1 being a plain text note (like a tweet)
- sig - the cryptographic proof that the public key associated with the event is the owner of the private key which published it
- tag - arbitrary tags which can be used to carry additional metadata depending on the kind of event
Getting Started
To get started with Nostr, you just need a client and a keypair. I generated my key with the nos2x browser extension which is usable with any web client such as Coracle. I use Amethyst on Android.
- Generate a key pair
- Save the private key somewhere safe so it can be used to login to other clients
- Publish the public key to others who wish to follow you
- Pick a couple of relays to publish and follow others
Lightning Network
Many clients have integration with the Lightning network for tips and compensating relay operators. A relay operator can specify a small fee for posting or you can send a small tip to another user, called a zap.
It was simple to set up a Lightning-compatible wallet app such as Wallet of Satoshi and add my Lightning address to my profile. I was even zapped 21 sats (< $.01) on my “Hello, World” post.
Verifying A Public Key
In order to verify that a particular Nostr public key is associated with a specific person or site, the NIP-05 specification defines a method of tying a public key to a domain name such as this one.
This verifies the key, but also allows me to use an email-like identifier (name@domain) that’s easier to remember than a public key.
I followed a simple guide to set it up. Now my Nostr profile has a check next to the link to my blog and every note shows a checkmark similar to how Twitter shows verified tweets.
Static Files
Hugo made it simple to add a static JSON file in the static/.well-known directory called nostr.json:
{
"names": {
"Lachlan": "4c01542027db0474984f3874dd243dfa9510cdd10048a4d2a72fefda9ef01c26"
},
"relays": {
"4c01542027db0474984f3874dd243dfa9510cdd10048a4d2a72fefda9ef01c26": [ "wss://nos.lol", "wss://iris.to", "wss://relay.nostriches.org", "wss://nostr.wine" ]
}
}
I also added my profile picture and banner images so I don’t have to rely on a 3rd party service such as Gravatar.
CORS
The more challenging part was to update CORS to allow Javascript-based clients to load the nostr.json file. To do this, I had to add a new nginx config which adds the header into the blog repo.
Warning: Make sure you understand what CORS does, there are security implications to doing it incorrectly.
nginx/nginx.conf:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
add_header 'Access-Control-Allow-Origin' '*';
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
I also had to update the Dockerfile which builds the container to copy the new config over the default one:
ARG HUGO_ENV_ARG=production
# Adds contents Dockerfile folder into /src and builds to the /target
# https://github.com/klakegg/docker-hugo
FROM klakegg/hugo:0.93.2-ext-onbuild AS site
# start a new image based on the nginx container
FROM nginx:alpine
# Ensure this is not cached
ARG CACHEBUST=1
# copy the built site to the site directory
COPY --from=site /target /usr/share/nginx/html
# nginx config file
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80/tcp
Join the Fun
I’ve added Nostr to my About page if you want to follow me and experiment with this new and interesting way to implement a social media network.