Storehouse.Local (Storehouse v0.2.0)

Copy Markdown View Source

A Storehouse.Adapter that keeps files in a directory on the local disk.

# config/config.exs
config :storehouse, adapter: Storehouse.Local

# config/runtime.exs, in the :prod block
if config_env() == :prod do
  config :storehouse, Storehouse.Local,
    root: System.get_env("UPLOADS", "/var/lib/my_app/uploads"),
    url_prefix: "/uploads"
end

# config/dev.exs
config :storehouse, Storehouse.Local, root: Path.expand("../tmp/uploads", __DIR__)
  • :root - the directory for the files (required). In production, give an absolute path outside the release, from the :prod block of config/runtime.exs (runtime.exs runs in every environment, so outside that block it replaces the development root). A relative path is relative to the current working directory, and in a release the files would go into the release directory and be lost on the next deploy.

  • :url_prefix - the path at which the files are served. The default is "/uploads". When Storehouse.Local.Plug serves the files, this is a path, not a full URL: the plug matches requests under it.

  • :secret - a secret of at least 32 bytes, for signed URLs (Storehouse.signed_url/2) and uploads straight from the browser (Storehouse.presign_upload/4): the plug serves and takes only what it signed. Give one from the environment in production, as the endpoint's secret_key_base is:

    config :storehouse, Storehouse.Local, secret: System.fetch_env!("STOREHOUSE_SECRET")

Serve the files with Storehouse.Local.Plug. Any other way to serve them must send X-Content-Type-Options: nosniff, a content type from the allow-list of Storehouse.Check, and Content-Disposition: attachment for every type that is not an image, a PDF or a video, as the plug does. A key is always a relative path under the root: a key that Storehouse.valid_key?/1 refuses gives {:error, :invalid_key}, so a key cannot reach a file outside the root.

Summary

Functions

Defines a store of its own, with a config of its own: a second bucket beside the first (public and private files, media on R2, files kept in another region).

Returns the path on disk of the file with key, or {:error, :invalid_key}.

Returns the configured root directory, as an absolute path.

Returns the configured URL prefix, by default "/uploads".

Functions

__using__(opts)

(macro)

Defines a store of its own, with a config of its own: a second bucket beside the first (public and private files, media on R2, files kept in another region).

defmodule MyApp.PrivateFiles, do: use Storehouse.Local

config :storehouse, MyApp.PrivateFiles, root: "/var/lib/my_app/scratch", url_prefix: "/scratch", secret: …

The module is a Storehouse.Adapter: give it as adapter: (or a field's store:, Storehouse.Ecto.File), and serve its files with a plug of their own, plug Storehouse.Local.Plug, store: MyApp.Scratch. With otp_app: :my_app, its config is config :my_app, MyApp.PrivateFiles, ….

path(key)

@spec path(Storehouse.Adapter.key()) :: {:ok, Path.t()} | {:error, :invalid_key}

Returns the path on disk of the file with key, or {:error, :invalid_key}.

root()

@spec root() :: Path.t()

Returns the configured root directory, as an absolute path.

Raises ArgumentError when no root is configured.

url_prefix()

@spec url_prefix() :: String.t()

Returns the configured URL prefix, by default "/uploads".