senec 0.22.1 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,8 +40,8 @@ module Senec
40
40
  )
41
41
 
42
42
  # Manual HTTP needed for Keycloak cross-domain form handling
43
- login_form_url = fetch_login_form_url(auth_url)
44
- redirect_url = submit_credentials(login_form_url)
43
+ form_type, form_url = fetch_login_form(auth_url)
44
+ redirect_url = submit_credentials(form_type, form_url)
45
45
  authorization_code = extract_authorization_code(redirect_url)
46
46
 
47
47
  self.oauth_token =
@@ -80,15 +80,19 @@ module Senec
80
80
 
81
81
  attr_accessor :oauth_token
82
82
 
83
- def fetch_login_form_url(auth_url)
83
+ def fetch_login_form(auth_url)
84
84
  response = http_request(:get, auth_url)
85
85
  store_cookies(response) # Required for Keycloak CSRF protection
86
- extract_login_form_action_url(response.body) || raise('Login form not found')
86
+ detect_login_form(response.body) || raise('Login form not found')
87
87
  end
88
88
 
89
- def submit_credentials(form_url)
90
- credentials = { username:, password: }
91
- response = http_request(:post, form_url, data: credentials)
89
+ def submit_credentials(form_type, form_url)
90
+ case form_type
91
+ when :username_and_password
92
+ response = http_request(:post, form_url, data: { username:, password: })
93
+ when :username_only
94
+ response = submit_username_then_password(form_url)
95
+ end
92
96
 
93
97
  if response.status == 200
94
98
  # Check if MFA is required
@@ -108,6 +112,20 @@ module Senec
108
112
  handle_redirect_response(response)
109
113
  end
110
114
 
115
+ def submit_username_then_password(form_url)
116
+ response = http_request(:post, form_url, data: { username: })
117
+ store_cookies(response)
118
+
119
+ raise 'Password form not found' unless response.status == 200
120
+
121
+ password_form_url = find_form_action_url(response.body) do |f|
122
+ f.match(/name=["']?password["']?/i)
123
+ end
124
+ raise 'Password form not found' unless password_form_url
125
+
126
+ http_request(:post, password_form_url, data: { username:, password: })
127
+ end
128
+
111
129
  def submit_totp_form(form_url)
112
130
  totp = build_totp_from_uri(totp_uri)
113
131
 
@@ -124,12 +142,21 @@ module Senec
124
142
  params['code'] || raise('No authorization code found')
125
143
  end
126
144
 
127
- def extract_login_form_action_url(html)
128
- find_form_action_url(html) do |form|
129
- # Look for a form with username and password fields
145
+ def detect_login_form(html)
146
+ # Check for combined form first (backward compatible with old SENEC flow)
147
+ url = find_form_action_url(html) do |form|
130
148
  form.match(/name=["']?username["']?/i) &&
131
149
  form.match(/name=["']?password["']?/i)
132
150
  end
151
+ return [:username_and_password, url] if url
152
+
153
+ # Check for username-only form (new two-step SENEC flow)
154
+ url = find_form_action_url(html) do |form|
155
+ form.match(/name=["']?username["']?/i)
156
+ end
157
+ return [:username_only, url] if url
158
+
159
+ nil
133
160
  end
134
161
 
135
162
  def extract_totp_form_action_url(html)
data/lib/senec/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Senec
2
- VERSION = '0.22.1'.freeze
2
+ VERSION = '0.23.0'.freeze
3
3
  end
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: senec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.22.1
4
+ version: 0.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georg Ledermann
@@ -98,7 +98,6 @@ files:
98
98
  - ".ruby-lsp/Gemfile.lock"
99
99
  - ".ruby-lsp/last_updated"
100
100
  - ".ruby-lsp/main_lockfile_hash"
101
- - ".ruby-lsp/needs_update"
102
101
  - ".vscode/settings.json"
103
102
  - CODE_OF_CONDUCT.md
104
103
  - LICENSE
@@ -166,6 +165,7 @@ files:
166
165
  - pkg/senec-0.20.0.gem
167
166
  - pkg/senec-0.21.0.gem
168
167
  - pkg/senec-0.22.0.gem
168
+ - pkg/senec-0.22.1.gem
169
169
  - pkg/senec-0.3.0.gem
170
170
  - pkg/senec-0.4.0.gem
171
171
  - pkg/senec-0.5.0.gem
@@ -199,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
199
199
  - !ruby/object:Gem::Version
200
200
  version: '0'
201
201
  requirements: []
202
- rubygems_version: 3.7.1
202
+ rubygems_version: 4.0.7
203
203
  specification_version: 4
204
204
  summary: Unofficial Ruby Client for SENEC Home
205
205
  test_files: []
File without changes