# [`nfsn-utils`][]

Interact with [NearlyFreeSpeech.NET][]'s [API][] from the command line.

[`nfsn-utils`]: https://git.rcrnstn.net/rcrnstn/nfsn-utils
[NearlyFreeSpeech.NET]: https://www.nearlyfreespeech.net
[API]: https://en.wikipedia.org/wiki/API

## Goals

`nfsn-utils` has three main goals:

1.  **Be portable** (even to things like [routers][]).

    POSIX shell is used as glue for standard utilities. See
    [dependencies](#dependencies).

2.  **Be modular** where it makes sense.

    [`nfsn-send`](#nfsn-send) is a general purpose [NearlyFreeSpeech.NET][]
    [API][] wrapper. [`nfsn-dns-update`](#nfsn-dns-update) is a general purpose
    [NearlyFreeSpeech.NET][] DNS update utility.

3.  **Be opinionated with sane defaults** where it makes sense.

    The smaller utilities assume things like that you want to use [standard
    email addresses][].

4.  **Be easily auditable**.

    The scripts are well abstracted and no more than about 100 lines of code.

[routers]: https://openwrt.org
[standard email addresses]: https://www.ietf.org/rfc/rfc2142.txt

## Prerequisites

### API key

As described in the [NearlyFreeSpeech.NET][] [documentation][], one needs to
submit a [free assistance request][] to obtain an API key.

Place the credentials in the environment variables `NFSN_LOGIN` and
`NFSN_API_KEY` or in the file `./.nfsn-api` or `$HOME/.nfsn-api` (location
overridable by the `NFSN_CREDENTIALS_PATH` environment variable). This file
should be a JSON file consisting of an object with the keys `login` and
`api-key`. (The file format and default location is compatible with
[WebService::NFSN][] and [python-nfsn][].)

[documentation]: https://members.nearlyfreespeech.net/wiki/API/Introduction
[free assistance request]: https://members.nearlyfreespeech.net/support/assist?tag=apikey
[WebService::NFSN]: https://metacpan.org/pod/WebService::NFSN#INTERFACE
[python-nfsn]: https://github.com/ktdreyer/python-nfsn#authentication

### Dependencies

-  Unix-like environment (in particular, `/dev/urandom`).
-  [POSIX utilities][] with `date` supporting `+%s` (such as GNU `date`).
-  `sha1sum` (for instance, the one in `coreutils`).
-  [curl][].
-  [jq][].
-  `certbot` (only needed for `nfsn-dns-certbot*`).

[POSIX utilities]: http://pubs.opengroup.org/onlinepubs/9699919799/idx/utilities.html
[curl]: https://curl.haxx.se
[jq]: https://github.com/stedolan/jq

## Included programs

Dependency graph:

![included programs](doc/included-programs.dot.png)

### `nfsn-send`

Wraps the Requests, Responses and Authentication described in the
[NearlyFreeSpeech.NET][] [documentation][].

### `nfsn-dns-update`

Updates several DNS records and outputs what data was actually changed.

### `nfsn-dns-a`

Updates DNS [A][] records, used to map hostnames to an IPv4 address.

[A]: https://en.wikipedia.org/wiki/List_of_DNS_record_types#A

### `nfsn-dns-spf`

Updates DNS [SPF][] records, used for email authorization (specifying who is
allowed to send mail from a domain).

[SPF]: https://en.wikipedia.org/wiki/Sender_Policy_Framework

### `nfsn-dns-dkim`

Updates DNS [DKIM][] records, used for email authentication (using digital
signatures).

[DKIM]: https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail

### `nfsn-dns-dmarc`

Updates DNS [DMARC][] records, extending [SPF][] and [DKIM][] by specifying
failure policy and reporting.

See also the [dmarc.org FAQ][].

[DMARC]: https://en.wikipedia.org/wiki/DMARC
[dmarc.org FAQ]: https://dmarc.org/wiki/FAQ#Sender_Questions

### `nfsn-dns-certbot*`

`nfsn-dns-certbot` calls [certbot][] (the [Electronic Frontier Foundation][]'s
(EFF) [Let's Encrypt][] client, for getting HTTPS certificates) in [manual
mode][] to make it use `nfsn-utils` to update DNS records in order to fullfill
the [`dns-01` challenge][]. It does this by registering
`nfsn-dns-certbot-{auth,cleanup}` as [hooks][].

By default, the `auth` hook sleeps for 30 seconds to let the DNS records
propagate. This can be overridden with the environment variable
`NFSN_DNS_CERTBOT_AUTH_SLEEP`.

Given that `nfsn-dns-certbot` has successfully run once, running `certbot
renew` will suffice to renew the certificates.

[certbot]: https://certbot.eff.org
[Electronic Frontier Foundation]: https://www.eff.org
[Let's Encrypt]: https://letsencrypt.org
[manual mode]: https://certbot.eff.org/docs/using.html#manual
[`dns-01` challenge]: https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.4
[hooks]: https://certbot.eff.org/docs/using.html#hooks

## License

Licensed under the [ISC License][] unless otherwise noted, see the
[`LICENSE`][] file.

[ISC License]: https://choosealicense.com/licenses/isc
[`LICENSE`]: LICENSE
