Class: Pandoru::Credentials

Inherits:
Object
  • Object
show all
Defined in:
lib/pandoru/credentials.rb

Overview

Resolves Pandora account credentials from the first source that supplies a complete pair, so the client/CLI works whether you prefer env vars, the OS secret store, or a config file. Empty values count as absent, so an unset/blank env var gracefully falls through to the next source rather than half-authenticating.

Precedence (highest first), mirroring the common config-resolution standard (explicit wins; env for 12-factor/CI; XDG Base Directory for the file):

1. Explicit values passed in (tests, embedding).
2. ENV PANDORA_USERNAME / PANDORA_PASSWORD.
3. The OS secret store (Keychain / libsecret), if a credential is stored.
4. A JSON file { "username": ..., "password": ... } at the first that
   exists, in order:
     $PANDORU_CREDENTIALS                       (explicit path override)
     $XDG_CONFIG_HOME/pandoru/credentials.json  (XDG; default ~/.config)

A future tier should delegate to Pandoru::ClientBuilders for the existing pydora ‘.cfg` / pianobar config files rather than reimplementing that parsing — tracked as a follow-up.

Defined Under Namespace

Classes: NotFound, Resolved

Constant Summary collapse

USERNAME_KEYS =
%w[username user email].freeze
PASSWORD_KEYS =
%w[password pass].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(env: ENV, home: Dir.home, secret_store: SecretStore) ⇒ Credentials

Returns a new instance of Credentials.



37
38
39
40
41
# File 'lib/pandoru/credentials.rb', line 37

def initialize(env: ENV, home: Dir.home, secret_store: SecretStore)
  @env = env
  @home = home
  @secret_store = secret_store
end

Class Method Details

.resolve(username: nil, password: nil, env: ENV, home: Dir.home, secret_store: SecretStore) ⇒ Object



32
33
34
35
# File 'lib/pandoru/credentials.rb', line 32

def self.resolve(username: nil, password: nil, env: ENV, home: Dir.home, secret_store: SecretStore)
  new(env: env, home: home, secret_store: secret_store)
    .resolve(username: username, password: password)
end

Instance Method Details

#candidate_filesObject

Ordered list of JSON credential paths to try.



68
69
70
71
72
73
# File 'lib/pandoru/credentials.rb', line 68

def candidate_files
  paths = []
  paths << @env['PANDORU_CREDENTIALS'] if present?(@env['PANDORU_CREDENTIALS'])
  paths << File.join(xdg_config_home, 'pandoru', 'credentials.json')
  paths.uniq
end

#resolve(username: nil, password: nil) ⇒ Object

Raises:



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/pandoru/credentials.rb', line 43

def resolve(username: nil, password: nil)
  if present?(username) && present?(password)
    return Resolved.new(username: username, password: password, source: :explicit)
  end

  if present?(@env['PANDORA_USERNAME']) && present?(@env['PANDORA_PASSWORD'])
    return Resolved.new(username: @env['PANDORA_USERNAME'],
                        password: @env['PANDORA_PASSWORD'], source: :env)
  end

  if @secret_store && (creds = @secret_store.fetch)
    return Resolved.new(username: creds[0], password: creds[1], source: :secret_store)
  end

  candidate_files.each do |path|
    next unless File.file?(path)
    creds = parse_file(path)
    next unless creds
    return Resolved.new(username: creds[0], password: creds[1], source: path)
  end

  raise NotFound, not_found_message
end