# redact
[](https://hex.pm/packages/redact)
[](https://hexdocs.pm/redact/)
```sh
gleam add redact
```
Further documentation can be found at <https://hexdocs.pm/redact>.
## Usage
The recommended usage of this library is use `secret.Secret` on the edges of IO.
For instance, if you need to store an `API_KEY` in your application's config record, wrap it with `secret.new` as soon as it is read in, and call `secret.expose` when it is needed to make a request.
Usage of `secret.expose` also allows you to easily audit your code for where your secrets are being used.
```gleam
import envoy
import gleam/int
import gleam/result
import redact/secret
pub type Error {
Required(name: String)
}
pub type Env {
Env(
database_url: secret.Secret(String),
port: Int,
secret_key: secret.Secret(String),
)
}
pub fn extract_env() -> Result(Env, Error) {
use database_url <- result.try(database_url())
let port = port()
use secret_key <- result.try(secret_key())
Ok(Env(database_url:, port:, secret_key:))
}
pub fn database_url() {
required_env("DATABASE_URL") |> result.map(secret.new)
}
pub fn port() {
envoy.get("PORT")
|> result.map(int.parse)
|> result.flatten()
|> result.unwrap(8000)
}
pub fn secret_key() {
required_env("SECRET_KEY") |> result.map(secret.new)
}
pub fn required_env(name: String) -> Result(String, Error) {
envoy.get(name)
|> result.replace_error(Required(name))
}
```
## Caveats
### string.inspect output could change at any time
The implementation of [string.inspect](https://hexdocs.pm/gleam_stdlib/gleam/string.html#inspect) is not considered stable and may change at any time. It is possible in the future that `string.inspect` may change and expose the value stored in a closure. When in doubt, verify that however you output a `secret.Secret` that it does not expose that secret.
### Not cryptographically secure
This library is **not** a cryptographically secure way to store a secret in RAM. It is a convenience. An attacker could find a way to inspect your program's memory at runtime and see the secret in the clear. If your threat model requires more secrecy, please use a different library.
### secret.Secret equality
Two instances of a `secret.Secret` with the same inner value are not equal. The test `secret.Secret("wibble") == secret.Secret("wibble")` appears to work in Erlang, but fails in JavaScript.
## Sample output
If you use the `string.inspect` method to convert a Gleam value to a string, any values of type `secret.Secret` will be hidden.
For instance, given the following record:
```gleam
pub type Env {
Env(
api_key: secret.Secret(String),
)
}
```
In the Erlang target, the Secret record looks like the following when passed to `string.inspect`
```gleam
string.inspect(
Env(api_key: secret.new(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMzEyIiwibmFtZSI6IkpvaG4gQnJvd24iLCJpYXQiOjE1MTYyMzkwMjJ9.__2EDbjt_49s6ssnr1tQgg--xEK6fbEK5bWG85OqB_c",
)),
)
// -> "Env(Secret(//fn() { ... }))"
```
In JavaScript, the result of `string.inspect` looks slightly different:
```gleam
string.inspect(
Env(api_key: secret.new(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMzEyIiwibmFtZSI6IkpvaG4gQnJvd24iLCJpYXQiOjE1MTYyMzkwMjJ9.__2EDbjt_49s6ssnr1tQgg--xEK6fbEK5bWG85OqB_c",
)),
)
// -> "Env(api_key: Secret(expose: //fn() { ... }))"
```
Using `echo` in the Erlang target will print the following:
```
test/redact_test.gleam:53
Env(Secret(//fn() { ... }))
```
In JavaScript, `echo` will print the following:
```
test/redact_test.gleam:53
Env(api_key: Secret(expose: //fn() { ... }))
```
## Development
```sh
gleam test # Run the tests
gleam test --target javascript # Run the tests
```