Skip to content
Subdomain registrar for the Blockstack network
JavaScript Dockerfile
Branch: master
Clone or download
Latest commit 03450b2 Mar 15, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.circleci add circleci definition Dec 17, 2018
src increase timeout for issuing a batch. add timeout to registration. Dec 19, 2018
tests/src
.babelrc
.dockerignore a bunch of changes to configurability. ability to publish zonefile di… Feb 8, 2018
.eslintrc fixed linter. added test coverage outputs. added tests Feb 7, 2018
.flowconfig fix flow in the circle build Dec 17, 2018
.gitignore a bunch of changes to configurability. ability to publish zonefile di… Feb 8, 2018
Dockerfile Adding sqlite3 to image Mar 15, 2019
LICENSE Initial commit Feb 13, 2018
README.md Should be .json, not .js May 24, 2018
config-sample.json add configuration option for minimum accepted name length Jul 20, 2018
docker-compose.yaml Update docker instructions Feb 14, 2018
package-lock.json
package.json bump version Dec 17, 2018

README.md

Install

To install from source:

$ git clone https://github.com/blockstack/subdomain-registrar.git
$ npm i

Starting up the registrar

You can run the registrar in place from its source directory, and you can specify your config file via the BSK_SUBDOMAIN_CONFIG environment parameter.

BSK_SUBDOMAIN_CONFIG=/home/aaron/devel/subdomain-registrar/my-local-config.json npm run start

You can also install the subdomain registrar globally. It should install as the program blockstack-subdomain-registrar.

$ sudo npm i -g   # or, "sudo npm link"
$ which blockstack-subdomain-registrar
/usr/bin/blockstack-subdomain-registrar

Basic Operation

The subdomain registrar functions roughly as follows --- you give the registrar a domain to register subdomains under, you fund a wallet to submit registrations with, it accepts registration requests, and then it periodically issues batches of name registrations.

Setting the Domain Name

For example, if I want to register names like alice.people.id or bob.people.id, I have to:

  1. Already own people.id
  2. Set the BSK_SUBDOMAIN_OWNER_KEY to the private key hex string which owns people.id (this is a 64-character hex-string with 01 appended if the address is compressed, which is usually the case)
  3. Set the domain name property in the config.json to people.id

Funding a wallet

Each batch of registrations is an update transaction -- the Bitcoin transaction fee for this must be paid by the registrar. This requires a payment-address. You must:

  1. Set the BSK_SUBDOMAIN_PAYMENT_KEY to a private key hex string (again, a 64-character hex string with 01 appended if the address is compressed, which is usually the case).
  2. Send Bitcoin funds to the address which corresponds to that private key.

Waiting for a batch

When a batch is issued, it take 6-7 bitcoin blocks before the rest of the Blockstack network will pick up and process the transaction. This means that it is usually a little over an hour before the registrations within a given batch will appear on other services (e.g., the blockstack-browser, blockstack explorer, etc.).

Spam Counter Measures

You can deploy many different spam protection schemes via a front-end service, however, this subdomain registrar also supports performing some spam protection on its own. You can configure IP limiting (i.e., limiting the number of names registered by a given IP) and social proof verification.

Social proof verification performs the normal Blockstack JWT verification and social proof checks, provided by blockstack.js.

In order to support registration requests from "trusted sources", you can use the apiKeys configuration option to add an array of allowed api keys. Requests with an Authorization: bearer <apiKey> header will then be able to skip the spam countermeasures.

Private Key Storage

You can either store your private key hexes in your config.json, or pass them in via environment variables BSK_SUBDOMAIN_OWNER_KEY and BSK_SUBDOMAIN_PAYMENT_KEY, and then clear those after the process starts.

Private Key Formatting

A common issue when configuring the subdomain registrar relates to private key formatting. A bare private key hex string is 64-characters (corresponding to a 32-byte ECDSA private key), for example:

9bffeccf649d21814ce6a605ad5cb1bdf1ac9ee44c53ef08a292af82875154df

Now -- this key actually corresponds to two different bitcoin addresses -- a compressed and an uncomprossed address. Most bitcoin addresses in use (and the kind used by the Blockstack Browser) are compressed. The standard way to denote that the corresponding public-key should be compressed is by appending 01 to the private key: this results in a 66-character hex string private key.

For example, these are the two different addresses for the above key:

var bsk = require('blockstack')
bsk.hexStringToECPair('9bffeccf649d21814ce6a605ad5cb1bdf1ac9ee44c53ef08a292af82875154df01').getAddress()
'1QJM5ESqzWKW6pF2Ho7BGBX7MpepmxedU2'
bsk.hexStringToECPair('9bffeccf649d21814ce6a605ad5cb1bdf1ac9ee44c53ef08a292af82875154df').getAddress()
'14K3MSHixgt9FSjPEgLD8YrMEk3ss5QyYN'

In most cases, you want to use the compressed key.

Configuring Instantaneous Resolution

Per the design outlined here, the subdomain registrar can be configured so that blockstack indexer nodes will respond with HTTP 301 status codes for missing subdomains. The 301 redirect will send the name lookup request to a URI designated by the domain name. In a standard setup, this would allow nearly instantaneous resolution of subdomain names. (Note: these names will not have been committed to the blockchain yet, and therefore the response from the designated endpoint do not have the same security properties as committed names).

To support this, the subdomain registrar is capable of responding to /v1/names/foo.bar.id style requests, and can be configured to set the _resolver URI entry in each zonefile that it publishes. To enable this behavior, set the resolverUri setting in your config.json file to a public-facing URL for your registrar. We recommend placing this GET /v1/names/ endpoint behind a caching layer of some kind.

Sample Curl Scripts

Queue a registration:

$ curl -X POST -H 'Authorization: bearer API-KEY-IF-USED' -H 'Content-Type: application/json' --data '{"zonefile": "$ORIGIN spqr\n$TTL 3600\n_https._tcp URI 10 1 \"https://gaia.blockstack.org/hub/1HgW81v6MxGD76UwNbHXBi6Zre2fK8TwNi/profile.json\"\n", "name": "spqr", "owner_address": "1HgW81v6MxGD76UwNbHXBi6Zre2fK8TwNi"}' http://localhost:3000/register/

Force a batch:

$ curl http://localhost:3000/issue_batch -X POST -H 'Authorization: bearer PASSWORDHERE'

Force zonefile check:

$ curl http://localhost:3000/check_zonefile -X POST -H 'Authorization: bearer PASSWORDHERE'

Check subdomain status:

$ curl http://localhost:3000/status/spqr | jq .

{
  "status": "Your subdomain was registered in transaction 6652bd350f048cd190ff04a5f0cdebbc166b13f3fd0e1126eacec8c600c25c6f -- it should propagate on the network once it has 6 confirmations."
}

Running with Docker

First copy the config file into a data directory and modify it to suit your needs:

mkdir -p data
cp config-sample.json data/config.json
vi config.json

Once that is done you can spin up the instance using docker-compose. The file will build the image as well:

docker-compose up -d 

If you would like to run w/o compose you can do the same with docker:

# First build the image
docker build . --tag bsk-subdomain-registrar

# Then run it with the proper volumes mounted
docker run -d -v data:/root/ -e BSK_SUBDOMAIN_CONFIG=/root/config.json -p 3000:3000 bsk-subdomain-registrar

Root stores the sqlite database that the subdomain uses to queue registrations, and watch zonefiles for broadcasting. To test connectivity for this setup run the following curl command:

$ curl http://localhost:3000/index | jq
{
  "status": true
}
You can’t perform that action at this time.