# `Lotus.Visibility.Mask`
[🔗](https://github.com/elixir-lotus/lotus/blob/v1.1.0/lib/lotus/visibility/mask.ex#L1)

Applies a column mask strategy to one value.

`Lotus.Runner` masks the values of a result column with this module when the
column policy is `action: :mask`. A middleware plug that masks values itself,
at `:after_query` for example, can call `apply/2` to get the same output.

## Strategies

- `:null` - replaces the value with `nil`
- `:sha256` - replaces the value with its SHA-256 digest in lowercase hex
- `{:fixed, value}` - replaces the value with `value`
- `{:partial, opts}` - keeps the ends of the value and masks the middle:
  - `keep_first: n` - keeps the first n characters (default: 0)
  - `keep_last: n` - keeps the last n characters (default: 4)
  - `replacement: str` - the string for each masked character (default: `"*"`)
  - `keep_domain: true` - keeps `@` and the domain after the last `@`, and
    applies the options above to the local part only. A value with no `@` is
    masked completely.

## Values

`:sha256` and `{:partial, opts}` operate on a string. A binary is used as its
bytes, `nil` becomes the empty string, and any other value is rendered with
`Lotus.Value.to_display_string/1`.

Partial masking never lets a value through unchanged. When `keep_first` plus
`keep_last` covers the whole value, or the whole local part with
`keep_domain: true`, nothing is kept. A binary that is not valid UTF-8 has no
readable prefix or suffix, so it becomes one replacement per byte.

A strategy that this module does not know replaces the value with `nil`, so
an invalid policy never shows the value.

# `apply`

```elixir
@spec apply(term(), Lotus.Visibility.Policy.mask_strategy()) :: term()
```

Masks `value` with `strategy`.

## Examples

    iex> Lotus.Visibility.Mask.apply("secret", {:fixed, "REDACTED"})
    "REDACTED"

    iex> Lotus.Visibility.Mask.apply("555-123-4567", {:partial, keep_last: 4})
    "********4567"

    iex> Lotus.Visibility.Mask.apply("alice@example.com", {:partial, keep_domain: true, keep_first: 1, keep_last: 0})
    "a****@example.com"

---

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