Class: Kward::RPC::AuthManager

Inherits:
Object
  • Object
show all
Defined in:
lib/kward/rpc/auth_manager.rb

Defined Under Namespace

Classes: Login

Instance Method Summary collapse

Constructor Details

#initialize(server:, oauth_factory: -> { OpenAIOAuth.new }, github_oauth_factory: -> { GithubOAuth.new }, config_manager: ConfigManager.new) ⇒ AuthManager

Returns a new instance of AuthManager.



13
14
15
16
17
18
19
20
# File 'lib/kward/rpc/auth_manager.rb', line 13

def initialize(server:, oauth_factory: -> { OpenAIOAuth.new }, github_oauth_factory: -> { GithubOAuth.new }, config_manager: ConfigManager.new)
  @server = server
  @oauth_factory = oauth_factory
  @github_oauth_factory = github_oauth_factory
  @config_manager = config_manager
  @logins = {}
  @mutex = Mutex.new
end

Instance Method Details

#login_status(login_id:) ⇒ Object



103
104
105
# File 'lib/kward/rpc/auth_manager.rb', line 103

def (login_id:)
  (())
end

#login_with_api_key(provider_id:, api_key:) ⇒ Object



40
41
42
43
44
# File 'lib/kward/rpc/auth_manager.rb', line 40

def (provider_id:, api_key:)
  provider_id = provider_id.to_s
  @config_manager.set_api_key(provider_id, api_key)
  { providerId: provider_id, message: "Saved API key for #{provider_name(provider_id)}." }
end

#login_with_oauth(provider_id:, timeout_seconds: 120) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/kward/rpc/auth_manager.rb', line 60

def (provider_id:, timeout_seconds: 120)
  provider_id = provider_id.to_s
  case provider_id
  when "openai"
    (timeout_seconds: timeout_seconds)
  when "github"
    raise "GitHub OAuth is supported in the CLI with `ruby lib/main.rb login github`, but RPC browser login is not implemented yet."
  else
    raise "Unsupported OAuth provider: #{provider_id}"
  end
end

#logout_provider(provider_id:) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/kward/rpc/auth_manager.rb', line 46

def logout_provider(provider_id:)
  provider_id = provider_id.to_s
  case provider_id
  when "openai"
    logout_openai
    { providerId: provider_id, message: "Logged out of OpenAI." }
  when "openrouter"
    @config_manager.delete_key("openrouter_api_key")
    { providerId: provider_id, message: "Logged out of OpenRouter." }
  else
    raise "Unsupported auth provider: #{provider_id}"
  end
end

#providersObject



36
37
38
# File 'lib/kward/rpc/auth_manager.rb', line 36

def providers
  { providers: [openai_provider, openrouter_provider, github_provider] }
end

#start_openai_login(timeout_seconds: 120) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/kward/rpc/auth_manager.rb', line 72

def (timeout_seconds: 120)
  oauth = @oauth_factory.call
  flow = oauth.
  pkce = flow.fetch(:pkce)
  state = flow.fetch(:state)
  server = flow.fetch(:server)
  redirect_uri = flow.fetch(:redirect_uri)
  url = flow.fetch(:authorization_url)
   = Login.new(
    id: SecureRandom.uuid,
    oauth: oauth,
    pkce: pkce,
    state: state,
    server: server,
    redirect_uri: redirect_uri,
    status: "pending"
  )
  @mutex.synchronize { @logins[.id] =  }
  .thread = Thread.new { wait_for_callback(, timeout_seconds: timeout_seconds.to_i <= 0 ? 120 : timeout_seconds.to_i) }
  { providerId: "openai", loginId: .id, authorizationUrl: url, redirectUri: redirect_uri, status: .status }
end

#statusObject



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/kward/rpc/auth_manager.rb', line 22

def status
  oauth = @oauth_factory.call
  config = stored_config
  {
    openaiOAuth: oauth.logged_in?,
    openaiAccountId: oauth.respond_to?(:account_id) ? oauth. : nil,
    openrouterApiKey: !ENV["OPENROUTER_API_KEY"].to_s.empty? || !config["openrouter_api_key"].to_s.empty?,
    openaiAccessToken: !ENV["OPENAI_ACCESS_TOKEN"].to_s.empty?,
    githubOAuth: @github_oauth_factory.call.logged_in?
  }
rescue StandardError => e
  { openaiOAuth: false, error: e.message }
end

#submit_openai_code(login_id:, code:) ⇒ Object



94
95
96
97
98
99
100
101
# File 'lib/kward/rpc/auth_manager.rb', line 94

def submit_openai_code(login_id:, code:)
   = ()
  raise "Login is not pending" unless .status == "pending"

  code = .oauth.authorization_code_from(code.to_s, expected_state: .state)
  (, code)
  ()
end