weconnect 0.1.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.
data/snippets.rb ADDED
@@ -0,0 +1,218 @@
1
+ $LOAD_PATH.unshift File.expand_path("../wrapi/lib", __dir__)
2
+
3
+ require 'securerandom'
4
+ require 'digest'
5
+ require 'base64'
6
+
7
+ require 'uri'
8
+ require 'json'
9
+ require 'nokogiri'
10
+ require './lib/weconnect.rb'
11
+ require 'logger'
12
+ require 'yaml'
13
+ require 'dotenv'
14
+
15
+ Dotenv.load
16
+
17
+ def token_hex(len)
18
+ o = [('0'..'9'),('A'..'F')].map(&:to_a).flatten
19
+ (1..len).map{o[rand(o.length)]}.join
20
+ end
21
+ def trace_id
22
+ trace = token_hex(32)
23
+ trace[0..7] + '-' + trace[8..11] + '-' + trace[12..15] + '-' + trace[16..19] + '-' + trace[20..trace.length]
24
+ end
25
+
26
+ class CarConnectInfo
27
+ attr_reader :type, :country, :xrequest, :xclient_id, :client_id, :scope, :response_type, :redirect, :xappversion, :xappname
28
+ def initialize
29
+ @type = "Id";
30
+ @country = "DE";
31
+ @xrequest = "com.volkswagen.weconnect";
32
+ # @xrequest = "de.volkswagen.carnet.eu.eremote"
33
+ @xclientId = "";
34
+ @client_id = "a24fba63-34b3-4d43-b181-942111e6bda8@apps_vw-dilab_com";
35
+
36
+ @scope = "openid profile badge cars dealers vin";
37
+ @response_type = "code id_token token";
38
+ @redirect = "weconnect://authenticated";
39
+ @refresh_url='https://identity.vwgroup.io/oidc/v1/token',
40
+
41
+ @xappversion = "";
42
+ @xappname = "";
43
+
44
+ end
45
+ def nonce
46
+ #SecureRandom.base64
47
+ rand(10 ** 30).to_s.rjust(30,'0')
48
+ end
49
+ #base64URLEncode
50
+ def urlsafe_base64(base64_str)
51
+ base64_str.tr("+/", "-_").tr("=", "")
52
+ end
53
+ def random_string(len)
54
+ o = [('a'..'z'), ('A'..'Z'),('0'..'9')].map(&:to_a).flatten << '-'
55
+ (1..len).map{o[rand(o.length)]}.join
56
+ end
57
+ def code_challenge
58
+ code_verifier = Base64.encode64(random_string)
59
+ # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n"
60
+ urlsafe_base64(Digest::SHA256.base64digest(code_verifier))
61
+ end
62
+
63
+ def login_url(connection = nil)
64
+ if !@_login_url
65
+ params = {
66
+ nonce: nonce(),
67
+ redirect_uri: @redirect
68
+ }
69
+
70
+ r = connection.get('https://emea.bff.cariad.digital/user-login/v1/authorize',params,true) do |request|
71
+ request.headers['user-agent'] = 'WeConnect/3 CFNetwork/1331.0.7 Darwin/21.4.0'
72
+ # request.headers['weconnect-trace-id'] = trace_id
73
+ end
74
+
75
+ # @_login_url = r.env.url
76
+
77
+ if r.status == 303 #redirect
78
+ @_login_url = r['location']
79
+ else
80
+ raise Error.new 'redirect expected ' + r.to_s
81
+ end
82
+ else
83
+ @_login_url
84
+ end
85
+ end
86
+ end
87
+
88
+
89
+ def eat( connection, response, id3 )
90
+ while response.status >=300 && response.status < 400 do
91
+ url = response['location']
92
+ unless url['https:']
93
+ break if url[id3.redirect]
94
+ originates = response.env.url
95
+ url = originates.scheme + "://" + originates.host + url
96
+ end
97
+ puts "* eat: "+url
98
+ response = connection.get(url, nil, true) do |request|
99
+ # request.headers['user-agent']= 'Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36'
100
+ request.headers['x-requested-with'] = id3.xrequest
101
+ end
102
+ end
103
+ response
104
+ end
105
+
106
+
107
+
108
+ File.delete('snippets1.log') if File.exist?('snippets1.log')
109
+ logger=Logger.new('snippets1.log')
110
+
111
+ id3 = CarConnectInfo.new
112
+ c = WeConnect.client({ logger: logger, username: ENV['WECONNECT_USERNAME'], password: ENV['WECONNECT_PASSWORD']})
113
+
114
+ _params = {
115
+ client_id: id3.client_id,
116
+ redirect_uri: id3.redirect,
117
+ response_type: id3.response_type,
118
+ scope: id3.scope,
119
+ nonce: id3.nonce(),
120
+ state: SecureRandom.uuid
121
+ }
122
+
123
+
124
+ # 2
125
+ url = id3.login_url(c)
126
+ r = nil
127
+ loop do
128
+ r = c.get(url, {}, true) do |request|
129
+ # request.headers['user-agent']= 'Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36'
130
+ request.headers['x-requested-with'] = id3.xrequest
131
+ end
132
+ break unless r.status >=300 && r.status < 400
133
+ url = r['location']
134
+ end
135
+
136
+
137
+ if r.status >= 200
138
+ =begin
139
+ doc = Nokogiri::HTML( r.body )
140
+ # 1 loginform username
141
+ form = doc/'form[name="emailPasswordForm"]'
142
+ action = form.attribute('action').to_s
143
+ method = form.attribute('method').to_s
144
+ puts "form action #{method} #{action}"
145
+ fields = {}
146
+ (form/'input').each do |input|
147
+ fields[input.attribute('name').to_s] = input.attribute('value').to_s
148
+ end
149
+ =end
150
+ form = WeConnect::Authentication::PasswordFormParser.new(r.body)
151
+ fields = form.fields
152
+ fields['email'] = c.username
153
+ uri = URI.join(id3.login_url(c), form.action)
154
+ logger.info("** posting url=#{uri} + action #{form.action}")
155
+
156
+ e = nil
157
+
158
+ begin
159
+ c.format = 'x-www-form-urlencoded'
160
+ rpw = c.post(uri.to_s,fields,true) do |request|
161
+ request.headers=request.headers.merge({
162
+ # 'user-agent': 'Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/74.0.3729.185 Mobile Safari/537.36',
163
+ # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
164
+ 'x-requested-with': id3.xrequest,
165
+ 'upgrade-insecure-requests': "1"
166
+ })
167
+ end
168
+ r = eat(c, rpw, id3)
169
+ =begin
170
+ doc = Nokogiri::HTML( r.body )
171
+ # get script with IDK
172
+ scripts = doc./'script:contains("_IDK")'
173
+ # extract json part by greedy match till last '}'
174
+ m = scripts.text.gsub("\n",'').gsub(/([\w]+):/, '"\1":').match('({.*})')
175
+ idk = {}
176
+ if m.size > 1
177
+ # load with yam due to single quotes
178
+ idk = YAML.load(m[1])
179
+ raise "Incompatible api/idk #{idk}" unless idk['templateModel']
180
+ else
181
+ raise 'Incompatible api'
182
+ end
183
+ # r = self.__get_url(upr.scheme+'://'+upr.netloc+form_url.replace(idk['templateModel']['identifierUrl'],idk['templateModel']['postAction']), post=post)
184
+ template_model = idk['templateModel']
185
+
186
+ post_action = template_model['postAction']
187
+ identifier = template_model['identifierUrl']
188
+
189
+ error = template_model['error']
190
+ =end
191
+ idk = WeConnect::Authentication::IDKParser.new(r.body)
192
+ params = {
193
+ :email => c.username,
194
+ :password => c.password,
195
+ idk.idk['csrf_parameterName'] => idk.idk['csrf_token'],
196
+ :hmac => idk.template_model['hmac'],
197
+ 'relayState' => idk.template_model['relayState']
198
+ }
199
+ puts "*** form action #{uri} action= #{idk.post_action} => #{idk.post_action_uri(uri.to_s)}"
200
+ c.format = 'x-www-form-urlencoded'
201
+ rpw = c.post(idk.post_action_uri(uri.to_s),params,true) do |request|
202
+ # rpw = c.post(uri.to_s.gsub(identifier,post_action),params,true) do |request|
203
+ request.headers=request.headers.merge({
204
+ # "Content-Type": "application/x-www-form-urlencoded",
205
+ # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
206
+ 'x-requested-with': id3.xrequest,
207
+ 'upgrade-insecure-requests': "1"
208
+ })
209
+ end
210
+ rpw = eat(c, rpw, id3)
211
+ puts "yippe hi heeee #{rpw['location']}" if rpw['location']
212
+ puts "where here..."
213
+ # rescue => e
214
+ # puts e.inspect
215
+ end
216
+
217
+
218
+ end
data/weconnect.gemspec ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/weconnect/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'weconnect'
7
+ s.version = WeConnect::VERSION
8
+ s.authors = ['Janco Tanis']
9
+ s.email = 'gems@jancology.com'
10
+ s.license = 'MIT'
11
+
12
+ s.summary = 'A Ruby wrapper for the weconnect (readonly)'
13
+ s.homepage = 'https://rubygems.org/gems/weconnect'
14
+
15
+ s.required_ruby_version = Gem::Requirement.new('>= 2.6.0')
16
+
17
+ s.metadata['homepage_uri'] = s.homepage
18
+ s.metadata['source_code_uri'] = 'https://github.com/jancotanis/weconnect'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ s.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
24
+ end
25
+ s.bindir = 'exe'
26
+ s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
+ s.require_paths = ['lib']
28
+
29
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
+ s.platform = Gem::Platform::RUBY
31
+ s.add_runtime_dependency 'faraday'
32
+ s.add_runtime_dependency 'faraday-follow_redirects'
33
+ s.add_runtime_dependency 'faraday-cookie_jar'
34
+ s.add_runtime_dependency 'nokogiri'
35
+ s.add_runtime_dependency 'wrapi', ">= 0.4.2"
36
+ # s.add_runtime_dependency 'jwt'
37
+ # s.add_runtime_dependency 'oauth2'
38
+ s.add_development_dependency 'dotenv'
39
+ s.add_development_dependency 'minitest'
40
+ s.add_development_dependency 'simplecov'
41
+ s.add_development_dependency 'rubocop'
42
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: weconnect
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Janco Tanis
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-03-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday-follow_redirects
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday-cookie_jar
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: nokogiri
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: wrapi
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 0.4.2
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.4.2
83
+ - !ruby/object:Gem::Dependency
84
+ name: dotenv
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description:
140
+ email: gems@jancology.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - ".gitignore"
146
+ - CHANGELOG.md
147
+ - Gemfile
148
+ - Rakefile
149
+ - lib/weconnect.rb
150
+ - lib/weconnect/api.rb
151
+ - lib/weconnect/authorization.rb
152
+ - lib/weconnect/client.rb
153
+ - lib/weconnect/connection.rb
154
+ - lib/weconnect/const.rb
155
+ - lib/weconnect/control_operation.rb
156
+ - lib/weconnect/error.rb
157
+ - lib/weconnect/pagination.rb
158
+ - lib/weconnect/request.rb
159
+ - lib/weconnect/version.rb
160
+ - poekoerifab.doc
161
+ - snippets.rb
162
+ - weconnect.gemspec
163
+ homepage: https://rubygems.org/gems/weconnect
164
+ licenses:
165
+ - MIT
166
+ metadata:
167
+ homepage_uri: https://rubygems.org/gems/weconnect
168
+ source_code_uri: https://github.com/jancotanis/weconnect
169
+ post_install_message:
170
+ rdoc_options: []
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: 2.6.0
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubygems_version: 3.2.3
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: A Ruby wrapper for the weconnect (readonly)
188
+ test_files: []