# `Aker.SignedCall`
[🔗](https://github.com/udin-io/aker/blob/v0.1.0/lib/aker/signed_call.ex#L1)

A call to the licensing server signed by the install key, and the check a
server runs on one.

A signed call carries four headers:

  * `x-licence-install-key`: the install public key, base64;
  * `x-licence-timestamp`: Unix seconds;
  * `x-licence-nonce`: 16 random bytes, base64;
  * `x-licence-signature`: the install key's DER signature, base64, of
    `signed_string/5`.

`verify/2` answers the install public key only when the signature holds.
The server then looks that key up itself: a valid signature proves the
caller holds the key, not that the server knows it.

# `headers`

```elixir
@spec headers({module(), keyword()}, String.t(), String.t(), binary(), keyword()) ::
  {:ok, [{String.t(), String.t()}]} | {:error, atom()}
```

The four headers for a call of `method` to `path` with `body`, signed by
`install_key` (`{module, opts}`). `:now` (Unix seconds) sets the
timestamp, for tests.

# `signed_string`

```elixir
@spec signed_string(String.t(), String.t(), String.t(), String.t(), binary()) ::
  binary()
```

The text the install key signs for one call: the method, the path, the
timestamp, the nonce and the body's SHA-256 in hex, one per line.

# `verify`

```elixir
@spec verify(map(), keyword()) :: {:ok, binary()} | {:error, atom()}
```

Checks a signed call as a server receives it: `%{method:, path:,
headers:, body:}`, where `headers` is a list of `{name, value}` with
lowercase names, as Plug gives them.

Options:

  * `:nonce_fresh?` (required): a 1-arity function over the nonce's text
    that answers true the first time it sees a nonce and false after, kept
    over the server's own nonce table. It runs only once every other check
    has passed, so a forged call records no nonce. A timestamp may sit up to
    `:window_s` ahead of now, so keep each nonce for twice `:window_s`.
  * `:now`: Unix seconds (default now);
  * `:window_s`: how far the timestamp may sit from now (default 600).

Answers `{:ok, install_public_key}`, or `{:error, reason}` with reason
`:unsigned`, `:bad_key`, `:bad_nonce`, `:stale`, `:bad_signature` or
`:replayed`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
