Skip to content
This repository has been archived by the owner on Sep 7, 2021. It is now read-only.

Commit

Permalink
Allow fetching custom token defined in config
Browse files Browse the repository at this point in the history
  • Loading branch information
rschef committed Sep 6, 2021
1 parent c24967c commit 669490e
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 9 deletions.
30 changes: 30 additions & 0 deletions README.md
Expand Up @@ -67,6 +67,36 @@ module (e.g. `def bucket(), do: "my-bucket"`).

Authentication is done through Goth which requires credentials (https://github.com/peburrows/goth#installation).

### Custom Token Generation ###

By default, the credentials provided to Goth will be used to generate tokens.
If you have multiple sets of credentials in Goth or otherwise need more control
over token generation, you can define your own module:

```elixir
defmodule MyCredentials do
@behaviour Waffle.Storage.Google.TokenFetcher

@impl Waffle.Storage.Google.TokenFetcher
def get_token(scopes) when is_list(scopes), do: get_token(Enum.join(scopes, " "))

@impl Waffle.Storage.Google.TokenFetcher
def get_token(scope) when is_binary(scope) do
{:ok, token} = Goth.Token.for_scope({"my-user@my-gcs-account.com", scope})
token.token
end
end
```

And configure it to use this new module instead of the default token generation:

```elixir
config :waffle,
storage: Waffle.Storage.Google,
bucket: "gcs-bucket-name",
token_fetcher: MyCredentials
```

## URL Signing

If your bucket/object permissions do not allow for public access, you will need
Expand Down
22 changes: 13 additions & 9 deletions lib/waffle/storage/google/cloud_storage.ex
Expand Up @@ -14,8 +14,6 @@ defmodule Waffle.Storage.Google.CloudStorage do
otherwise some (or all) calls may fail.
"""

@full_control_scope "https://www.googleapis.com/auth/devstorage.full_control"

alias GoogleApi.Storage.V1.Connection
alias GoogleApi.Storage.V1.Api.Objects
alias GoogleApi.Storage.V1.Model.Object
Expand All @@ -39,16 +37,19 @@ defmodule Waffle.Storage.Google.CloudStorage do
|> Keyword.put(:acl, acl)
|> Enum.into(%{})

insert(conn(), bucket(definition), path, data(meta), gcs_options)
meta
|> conn()
|> insert(bucket(definition), path, data(meta), gcs_options)
end

@doc """
Delete a file from a Google Cloud Storage bucket.
"""
@spec put(Types.definition, Types.version, Types.meta) :: object_or_error
def delete(definition, version, meta) do
Objects.storage_objects_delete(
conn(),
meta
|> conn()
|> Objects.storage_objects_delete(
bucket(definition),
path_for(definition, version, meta) |> URI.encode_www_form()
)
Expand All @@ -71,10 +72,13 @@ defmodule Waffle.Storage.Google.CloudStorage do
Constructs a new connection object with scoped authentication. If no scope is
provided, the `devstorage.full_control` scope is used as a default.
"""
@spec conn(String.t) :: Tesla.Env.client
def conn(scope \\ @full_control_scope) do
{:ok, token} = Goth.Token.for_scope(scope)
Connection.new(token.token)
@spec conn(Types.meta) :: Tesla.Env.client
def conn(scope) do
token_store = Application.get_env(:waffle, :token_fetcher, Waffle.Storage.Google.Token.DefaultFetcher)

scope
|> token_store.get_token()
|> Connection.new()
end

@doc """
Expand Down
11 changes: 11 additions & 0 deletions lib/waffle/storage/google/token/default_fetcher.ex
@@ -0,0 +1,11 @@
defmodule Waffle.Storage.Google.Token.DefaultFetcher do
@behaviour Waffle.Storage.Google.Token.Fetcher

@full_control_scope "https://www.googleapis.com/auth/devstorage.full_control"

@impl Waffle.Storage.Google.Token.Fetcher
def get_token(_scope) do
{:ok, token} = Goth.Token.for_scope(@full_control_scope)
token.token
end
end
3 changes: 3 additions & 0 deletions lib/waffle/storage/google/token/fetcher.ex
@@ -0,0 +1,3 @@
defmodule Waffle.Storage.Google.Token.Fetcher do
@callback get_token(Waffle.Types.meta()) :: binary()
end

0 comments on commit 669490e

Please sign in to comment.