← observatory

kind 35128 · don't trust, verify

4398393cd480ff0fb15c3892872318227e3d2f534b8f47eafbe771528ee5ecfe

{
  "id": "4398393cd480ff0fb15c3892872318227e3d2f534b8f47eafbe771528ee5ecfe",
  "pubkey": "c2f1ab4e6a577dd8980b57e15986ed92830b95a94f374192235563532b5cac20",
  "created_at": 1791837768,
  "kind": 35128,
  "tags": [
    [
      "path",
      "/index.html",
      "3faf78ea33242510710f1d1ba66b3f9540f35e6ecf4757ea5663a46c8ed69095"
    ],
    [
      "path",
      "/__MACOSX/._index.html",
      "4608814208335b43aee90fafaa92e9812482edc19c11c53fc814b71594d301c0"
    ],
    [
      "path",
      "/404.html",
      "3faf78ea33242510710f1d1ba66b3f9540f35e6ecf4757ea5663a46c8ed69095"
    ],
    [
      "server",
      "https://nsite.run"
    ],
    [
      "server",
      "https://nostr.download"
    ],
    [
      "server",
      "https://blssm.us"
    ],
    [
      "server",
      "https://blossom.yakihonne.com"
    ],
    [
      "server",
      "https://zencrown.relay2aeon.quest/"
    ],
    [
      "relay",
      "wss://nsite.run"
    ],
    [
      "relay",
      "wss://nostr.bitcoiner.social"
    ],
    [
      "relay",
      "wss://purplepag.es"
    ],
    [
      "relay",
      "wss://relay.primal.net"
    ],
    [
      "relay",
      "wss://zencrown.relay2aeon.quest"
    ],
    [
      "d",
      "x400"
    ],
    [
      "title",
      "X400Nostr turns old-school X.400 corporate email addresses into Nostr profiles you can actually message."
    ],
    [
      "description",
      "X400Nostr is a small web app that bridges two very different worlds. On one side is X.400, the formal addressing scheme enterprises used for decades: strings like /C=US/ADMD=TELMAIL/PRMD=CORP/O=ACME/CN=JSmith/. On the other side is Nostr, the open protocol where identity is a public key and messages travel through relays instead of servers.\n\nYou paste an X.400 address. The app parses it, normalizes it, asks a directory server whether that person has a Nostr identity, and if so, shows you their public key and the relays where they can be reached. That's it. No accounts. No signup. No tracking. Just a lookup.\n\nWHY IT EXISTS\n\nCompanies still have X.400 directories. Governments and telcos and airlines still route messages through them. But those directories are closed, and the people inside them have no way to receive a message from the open internet. Nostr gives them one. This app is the missing bridge \u2014 a way to look up a formal corporate address and get back a decentralized identity you can talk to.\n\nHOW TO USE IT\n\nOpen the app in any modern browser. You'll see a text field, a table, and a relay status panel.\n\nType or paste an X.400 OR-address into the field. The format is a slash-separated list of attributes. The only one you must include is CN, the common name. Everything else \u2014 country, administration management domain, private management domain, organization, organizational units, domain-defined attribute \u2014 is optional but useful.\n\nPress Resolve. The app parses your input, checks that it's well-formed, derives a NIP-05 identifier from the common name and the configured directory domain, and asks that domain's well-known endpoint for a matching public key. If it finds one, the row turns green, the public key appears as an npub, and the person's preferred relays are added to the connection pool.\n\nIf the directory doesn't know the address, you get a clear reason: no record found, network error, timeout, or malformed input. Nothing crashes. Nothing goes silent. You always know what happened.\n\nWHAT IT SHOWS YOU\n\nThe directory table has six columns. The first is the canonical X.400 address after normalization. The second is the person's common name, or their profile display name if the app has fetched one from the network. The third is their Nostr public key encoded as an npub \u2014 short enough to copy, long enough to identify. The fourth tells you how many relays the person publishes to. The fifth is a status badge. The sixth is a Remove button so you can clean up the list.\n\nBelow the table is the relay panel. Every relay the app has connected to appears there with its current state: idle, connecting, connected, reconnecting, error, or closed. You can watch connections come up, drop, and recover in real time. The app never opens more than four relay sockets at once, backs off exponentially when a relay misbehaves, and gives up on a connection that takes longer than eight seconds to establish.\n\nHOW IT WORKS UNDER THE HOOD\n\nThe app is a single HTML file. There is no build step. There is no server component. You can save it, email it, or host it anywhere static, and it will run.\n\nIt has four moving parts.\n\nThe first is the X.400 parser. It takes a raw string, splits it on slashes, checks each segment for a known key and a printable ASCII value, uppercases the attributes that convention says should be uppercased, preserves the case of the common name because proper names deserve their capitals, and rejects anything malformed. Duplicates are refused. Missing CN is refused. Unknown keys are refused. It returns either a parsed object or a specific error explaining exactly which segment was wrong and why.\n\nThe second is the normalizer. It takes the parsed object and produces a canonical address string with attributes in a fixed order: country, then ADMD, then PRMD, then organization, then each organizational unit in the order given, then common name, then domain-defined attribute. Two inputs that mean the same thing produce the same output. That matters because the address is the table's key.\n\nThe third is the NIP-05 resolver. NIP-05 is the part of the Nostr spec that maps an email-shaped identifier like jsmith@example.com to a public key. The resolver builds the well-known URL, fetches it with a hard timeout, refuses to follow redirects because the spec says it must not, validates the JSON response with a schema, and extracts the public key and the list of relays the person publishes to. Every step is guarded. A bad server can't crash the app. A slow server can't hang the UI. A hostile response can't inject anything, because nothing gets used until it passes validation.\n\nThe fourth is the relay connection manager. It owns every WebSocket the app ever opens. It enforces the connection ceiling. It schedules reconnects with exponential backoff and jitter so a fleet of clients doesn't hammer a struggling relay in lockstep. It drops messages that don't parse, messages that parse but don't match the expected shape, and messages from relays that were never asked for anything. Every inbound frame is validated before it's allowed to affect anything. Every listener that might throw is wrapped so one bad subscriber can't take down the pool.\n\nEverything else \u2014 the table, the form, the relay panel \u2014 is presentation over those four parts.\n\nTHE DESIGN PRINCIPLES\n\nStrict types, validated boundaries. Nothing enters the app from the outside world without being checked. Not user input, not network responses, not WebSocket frames, not anything from browser storage. If a value can't be validated, it doesn't get to exist inside the app.\n\nNo impossible states. The UI is modeled as a set of discriminated states, not a pile of booleans. A row is either unresolved, invalid, resolving, resolved, or failed \u2014 never two of those at once, never none of them. When a new state is added, the compiler and the runtime both scream until every site that handles the state is updated.\n\nFailures are visible. Every error path either reports to telemetry with structured context or renders a clear message to the user. There are no empty catch blocks. There is no silent swallowing. If something went wrong, you can find out what.\n\nNothing runs forever. Every fetch has an abort controller. Every subscription has a teardown. Every timer is cleared. When you leave the page, nothing keeps running in the background.\n\nAccessibility is not optional. Live regions announce state changes. Every button is keyboard reachable. Focus rings are visible. The color contrast meets the standard. The table has a caption and column headers. The form has a label and a hint. Screen reader users get the same information sighted users get.\n\nWHAT IT DOESN'T DO\n\nIt doesn't send messages. It doesn't sign anything. It doesn't hold your private key. It doesn't store anything on a server. It doesn't track you. It doesn't phone home. It doesn't need JavaScript frameworks or a bundler or a package manager. It doesn't require you to trust the person who runs it, because you can read the whole thing in a text editor and see exactly what it does.\n\nWHAT YOU NEED TO RUN IT\n\nA browser. That's the whole list. Chrome, Firefox, Safari, Edge \u2014 any browser from the last few years will work. The app will attempt to reach public Nostr relays over WebSocket and a directory server over HTTPS. If your network blocks either, the relay panel will show you why, and the directory lookups will tell you they timed out. Everything degrades gracefully.\n\nTO CONNECT IT TO A REAL DIRECTORY\n\nThe app ships pointing at a placeholder domain. To make it useful, host a JSON file at /.well-known/nostr.json on a domain you control. The file maps each common name to a hex public key and optionally lists the relays that key publishes to. Point the app at that domain and it will start resolving real addresses.\n\nThe format is defined by NIP-05 in the Nostr specification. A minimal file looks like a names object mapping lowercase local parts to sixty-four character hex public keys, plus an optional relays object mapping each public key to an array of wss URLs.\n\nWHERE IT FITS IN THE NOSTR ECOSYSTEM\n\nNostr is a protocol, not a platform. Anyone can write a client. Anyone can run a relay. Anyone can extend the spec with a NIP. This app is one small piece of that ecosystem \u2014 a bridge from a legacy addressing scheme into the network, so that people who still live inside corporate directories can be reached by people who don't.\n\nIt uses NIP-01 for event shape, NIP-05 for identity resolution, and NIP-65 for relay list discovery. It doesn't invent anything new. It just wires existing pieces together in a way that solves a real problem.\n\nLICENSE AND CREDIT\n\nThe Nostr protocol and its specifications are community work. The X.400 standard belongs to the ITU. This app is a thin layer of glue between them, and it belongs to whoever finds it useful."
    ],
    [
      "client",
      "nsite.run"
    ]
  ],
  "content": "",
  "sig": "bba7b4656c4c9ee61e7f5b0b6047b357e99745231144ce1549fcade4646fe580053b2ab1b85ddafe77d6157a4ab53f2d19371b4c480b04135dd9048a77c6949a"
}