bluesky-social / pds

Bluesky PDS (Personal Data Server) container image, compose file, and documentation
Other
1.48k stars 134 forks source link

pdsadmin/account.sh create should have an --override option for reserved names #64

Open mcclure opened 7 months ago

mcclure commented 7 months ago

Repro

Say I have just set up my new PDS server bsky.example.com. The first thing I want to do is create a user account for testing. I see that I can use the script pdsadmin/account.sh in this repo to create an account. So I run:

$ bash ../pdsadmin/account.sh create
Enter an email address (e.g. alice@bsky.example.com): admin+temporary3@exxample.com
Enter a handle (e.g. alice.bsky.example.com): test.bsky.example.com
ERROR: Reserved handle
Usage: ../pdsadmin/account.sh create <EMAIL> <HANDLE>

"test" is on a list of reserved handles built into the atproto source code. Fair enough. But there is a problem: This is the administrator interface. In theory, I am the exact person these handles are being "reserved" for.

This is especially inconvenient in the case of the prepackaged docker container, where there is no straightforward access to the source (to, for example, remove items from the reserved list).

"Expected behavior"

admin.sh create should support an --override flag. /xrpc/com.atproto.server.createAccount should have some way to verify the caller is an administrator and should be allowed to bypass the usual rules about what is a legal handle; since admin.sh has access to .env and therefore the admin password, it should be able to perform this verification automatically when --override is passed.

Related problems

There are two problems connected to this one; I don't know if they deserve their own issues.

  1. In addition to the reserved list, account.sh create appears to restrict to subdomains of the server. Imagine despite hosting my server at bsky.example.com, I happen to control the separate domain example.net and want to use it as a bsky handle:

    $ bash ../pdsadmin/account.sh create Enter an email address (e.g. alice@bsky.example.com): admin+temporary3@example.com Enter a handle (e.g. alice.bsky.example.com): example.net ERROR: Not a supported handle domain Usage: ../pdsadmin/account.sh create

    Ideally, the --override should also make it possible for an administrator to register an account on a separate domain they are setting up a DID for. (But I don't know if this would be more complicated to implement for some reason.)

  2. Minor, but something about the way account.sh create is implemented means that every time account.sh create is called unsuccessfully, an invite code is generated and thrown away. So having run this script 8 times trying to get it to work and then filing this bug, it turns out I've dropped 8 invite codes in my database that will never be redeemed. The script does not indicate to the user this has happened.

Logs

Here's what running with the "test" test case at the top of this issue looks like in the journalctl logs.

{
  "level": 30,
  "time": 1713911337241,
  "pid": 110769,
  "hostname": [redacted],
  "name": "pds",
  "req": {
    "id": 1793,
    "method": "POST",
    "url": "/xrpc/com.atproto.server.createInviteCode",
    "query": {},
    "params": {},
    "headers": {
      "host": "localhost:3002",
      "authorization": "Basic admin",
      "user-agent": "curl/7.68.0",
      "accept": "*/*",
      "content-type": "application/json",
      "x-forwarded-for": [redacted],
      "x-forwarded-host": "bsky.example.com",
      "x-forwarded-server": "bsky.example.com",
      "content-length": "15",
      "connection": "Keep-Alive"
    }
  },
  "res": {
    "statusCode": 200,
    "headers": {
      "x-powered-by": "Express",
      "access-control-allow-origin": "*",
      "content-type": "application/json; charset=utf-8",
      "content-length": "40",
      "etag": [redacted],
      "vary": "Accept-Encoding"
    }
  },
  "responseTime": 1,
  "msg": "request completed"
}
{
  "level": 50,
  "time": 1713911337274,
  "pid": 110769,
  "hostname": [redacted],
  "name": "HandleNotAvailable",
  "status": 400,
  "message": "Reserved handle",
  "msg": "error in xrpc method com.atproto.server.createAccount"
}
{
  "level": 30,
  "time": 1713911337275,
  "pid": 110769,
  "hostname": [redacted],
  "name": "pds",
  "req": {
    "id": 1794,
    "method": "POST",
    "url": "/xrpc/com.atproto.server.createAccount",
    "query": {},
    "params": {},
    "headers": {
      "host": "localhost:3002",
      "user-agent": "curl/7.68.0",
      "accept": "*/*",
      "content-type": "application/json",
      "x-forwarded-for": [redacted],
      "x-forwarded-host": "bsky.example.com",
      "x-forwarded-server": "bsky.example.com",
      "content-length": "161",
      "connection": "Keep-Alive"
    }
  },
  "res": {
    "statusCode": 400,
    "headers": {
      "x-powered-by": "Express",
      "access-control-allow-origin": "*",
      "content-type": "application/json; charset=utf-8",
      "content-length": "58",
      "etag": [redacted],
      "vary": "Accept-Encoding"
    }
  },
  "responseTime": 4,
  "msg": "request completed"
}

Because github is public, I have replaced all instances of my personal domain in this issue with "example.com". If you need unredacted logs I can get you some.

mcclure commented 7 months ago

Note: With my custom domain ("example.net" above) I was able to create an account named "temporary1" and then switch to the custom domain. With "test" I could not do this (switching to name "test" says "Reserved Handle" and saying I have my own domain and entering it as test.bsky.example.com says "Unable to Resolve Handle"). I still have not figured out how to create an account as a subdomain of my PDS server named "test".

(Reminder, "example.com" in these posts is a standin for my real domain, and I have unredacted logs of failed switching if they would be helpful to see.)

bnewbold commented 7 months ago

Had a reply drafted but lost it, apologies for the slow reply, and thanks for the detailed report.

As some context, for historical reasons the flow for all custom handles and reserved prefixes on our service was to register with a temporary "local" handle, then have the account do a self-serve handle update in the app (eg, to a separate domain), or for an admin to use the com.atproto.admin.updateAccountHandle to change the handle, which bypasses some checks and restrictions.

That flow was partially motivated by ensuring that account sign-up would reliably go smoothly (don't need to bounce over to DNS panels or wait for propagation in the middle of account sign-up), and partially common behaviors (setting up a test account to explore before bothering with special handles). These don't make as much sense for non-Bluesky PDS instances, though I think it is still helpful to have the PDS do some checks to ensure an account is "valid" as often as possible during setup. There are some chicken/egg issues around generating a PLC DID when there isn't a known/valid handle, but not being able to configure the handle until the DID is known, and things like that.

My initial thought is that exposing the admin version of updateAccountHandle would help with a bunch of use cases. Maybe making it easier to use restricted/reserved handles via configuration would make sense, though all handles do end up visible in the account, and we had a lot of complaints about slur-handles in the past, so i'm a bit hesitant to make it very-low-friction to bypass those reserved handles (though of course bad actors can patch/bypass any such speedbumps).