n8n-nodes-jygse-vw-weconnect 0.1.9 → 0.1.11
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.
|
@@ -146,6 +146,19 @@ const VW_CLIENT_ID = 'a24fba63-34b3-4d43-b181-942111e6bda8@apps_vw-dilab_com';
|
|
|
146
146
|
const VW_SCOPE = 'openid profile badge cars dealers vin';
|
|
147
147
|
const VW_REDIRECT_URI = 'weconnect://authenticated';
|
|
148
148
|
const VW_RESPONSE_TYPE = 'code id_token token';
|
|
149
|
+
// WeConnect App User-Agent and headers (critical for authentication)
|
|
150
|
+
// Using exact version from WeConnect-python
|
|
151
|
+
const VW_USER_AGENT = 'Volkswagen/3.51.1-android/14';
|
|
152
|
+
const VW_APP_PACKAGE = 'com.volkswagen.weconnect';
|
|
153
|
+
const VW_ACCEPT_LANGUAGE = 'de-de';
|
|
154
|
+
function generateTraceId() {
|
|
155
|
+
// Generate UUID v4 format
|
|
156
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
157
|
+
const r = Math.random() * 16 | 0;
|
|
158
|
+
const v = c === 'x' ? r : (r & 0x3 | 0x8);
|
|
159
|
+
return v.toString(16);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
149
162
|
// Generate PKCE code verifier and challenge
|
|
150
163
|
function generateCodeVerifier() {
|
|
151
164
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~';
|
|
@@ -163,29 +176,28 @@ async function generateCodeChallenge(verifier) {
|
|
|
163
176
|
}
|
|
164
177
|
async function vwLogin(context, email, password) {
|
|
165
178
|
try {
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
const
|
|
170
|
-
|
|
179
|
+
const traceId = generateTraceId();
|
|
180
|
+
const nonce = generateNonce();
|
|
181
|
+
// Common headers used for all requests (matching WeConnect-python exactly)
|
|
182
|
+
const commonHeaders = {
|
|
183
|
+
'User-Agent': VW_USER_AGENT,
|
|
184
|
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
185
|
+
'Accept-Language': VW_ACCEPT_LANGUAGE,
|
|
186
|
+
'Cache-Control': 'no-cache',
|
|
187
|
+
'x-android-package-name': VW_APP_PACKAGE,
|
|
188
|
+
'weconnect-trace-id': traceId,
|
|
189
|
+
};
|
|
190
|
+
// Step 1: Get authorization page via CARIAD BFF
|
|
191
|
+
// WeConnect-python only sends redirect_uri and nonce to this endpoint
|
|
171
192
|
const authorizeUrl = 'https://emea.bff.cariad.digital/user-login/v1/authorize';
|
|
172
193
|
const authorizeParams = new URLSearchParams({
|
|
173
|
-
client_id: VW_CLIENT_ID,
|
|
174
|
-
scope: VW_SCOPE,
|
|
175
|
-
response_type: VW_RESPONSE_TYPE,
|
|
176
194
|
redirect_uri: VW_REDIRECT_URI,
|
|
177
|
-
nonce:
|
|
178
|
-
state: stateParam,
|
|
179
|
-
code_challenge: codeChallenge,
|
|
180
|
-
code_challenge_method: 'plain',
|
|
195
|
+
nonce: nonce,
|
|
181
196
|
});
|
|
182
197
|
const authorizeResponse = await context.helpers.httpRequest({
|
|
183
198
|
method: 'GET',
|
|
184
199
|
url: `${authorizeUrl}?${authorizeParams.toString()}`,
|
|
185
|
-
headers:
|
|
186
|
-
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
187
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
188
|
-
},
|
|
200
|
+
headers: commonHeaders,
|
|
189
201
|
encoding: 'text',
|
|
190
202
|
returnFullResponse: true,
|
|
191
203
|
ignoreHttpStatusErrors: true,
|
|
@@ -238,10 +250,7 @@ async function vwLogin(context, email, password) {
|
|
|
238
250
|
const followResponse = await context.helpers.httpRequest({
|
|
239
251
|
method: 'GET',
|
|
240
252
|
url: followUrl,
|
|
241
|
-
headers:
|
|
242
|
-
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
243
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
244
|
-
},
|
|
253
|
+
headers: commonHeaders,
|
|
245
254
|
encoding: 'text',
|
|
246
255
|
returnFullResponse: true,
|
|
247
256
|
ignoreHttpStatusErrors: true,
|
|
@@ -347,7 +356,7 @@ async function vwLogin(context, email, password) {
|
|
|
347
356
|
method: 'POST',
|
|
348
357
|
url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/identifier',
|
|
349
358
|
headers: {
|
|
350
|
-
'User-Agent':
|
|
359
|
+
'User-Agent': VW_USER_AGENT,
|
|
351
360
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
352
361
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
353
362
|
},
|
|
@@ -383,7 +392,7 @@ async function vwLogin(context, email, password) {
|
|
|
383
392
|
method: 'POST',
|
|
384
393
|
url: 'https://identity.vwgroup.io/signin-service/v1/signin/login/authenticate',
|
|
385
394
|
headers: {
|
|
386
|
-
'User-Agent':
|
|
395
|
+
'User-Agent': VW_USER_AGENT,
|
|
387
396
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
388
397
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
389
398
|
},
|
|
@@ -444,8 +453,7 @@ async function vwLogin(context, email, password) {
|
|
|
444
453
|
method: 'POST',
|
|
445
454
|
url: `https://identity.vwgroup.io/u/login?state=${encodeURIComponent(stateToken)}`,
|
|
446
455
|
headers: {
|
|
447
|
-
|
|
448
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
456
|
+
...commonHeaders,
|
|
449
457
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
450
458
|
'Origin': 'https://identity.vwgroup.io',
|
|
451
459
|
'Referer': `https://identity.vwgroup.io/u/login?state=${encodeURIComponent(stateToken)}`,
|
|
@@ -523,9 +531,7 @@ async function vwLogin(context, email, password) {
|
|
|
523
531
|
const followResponse = await context.helpers.httpRequest({
|
|
524
532
|
method: 'GET',
|
|
525
533
|
url: redirectUrl.startsWith('http') ? redirectUrl : `https://identity.vwgroup.io${redirectUrl}`,
|
|
526
|
-
headers:
|
|
527
|
-
'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-G973F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.120 Mobile Safari/537.36',
|
|
528
|
-
},
|
|
534
|
+
headers: commonHeaders,
|
|
529
535
|
encoding: 'text',
|
|
530
536
|
returnFullResponse: true,
|
|
531
537
|
ignoreHttpStatusErrors: true,
|
|
@@ -558,28 +564,30 @@ async function vwLogin(context, email, password) {
|
|
|
558
564
|
maxRedirects--;
|
|
559
565
|
}
|
|
560
566
|
if (!authCode) {
|
|
561
|
-
throw new Error(`Could not obtain authorization code. Last redirect: ${redirectUrl || 'none'}.
|
|
567
|
+
throw new Error(`Could not obtain authorization code. Last redirect: ${redirectUrl || 'none'}. Auth HTML preview: ${authHtml.substring(0, 500)}`);
|
|
562
568
|
}
|
|
563
|
-
// Step 4: Exchange auth code for tokens
|
|
564
|
-
//
|
|
569
|
+
// Step 4: Exchange auth code for tokens via CARIAD login endpoint
|
|
570
|
+
// The state parameter should come from the authorize response, not our generated one
|
|
565
571
|
let tokenResponse;
|
|
566
572
|
try {
|
|
567
573
|
const cariadResponse = await context.helpers.httpRequest({
|
|
568
574
|
method: 'POST',
|
|
569
575
|
url: 'https://emea.bff.cariad.digital/user-login/login/v1',
|
|
570
576
|
headers: {
|
|
571
|
-
'User-Agent':
|
|
577
|
+
'User-Agent': VW_USER_AGENT,
|
|
572
578
|
'Accept': 'application/json',
|
|
579
|
+
'Accept-Language': VW_ACCEPT_LANGUAGE,
|
|
573
580
|
'Content-Type': 'application/json',
|
|
581
|
+
'x-android-package-name': VW_APP_PACKAGE,
|
|
582
|
+
'weconnect-trace-id': traceId,
|
|
574
583
|
},
|
|
575
584
|
body: {
|
|
576
|
-
state:
|
|
585
|
+
state: stateToken,
|
|
577
586
|
id_token: idToken,
|
|
578
587
|
redirect_uri: VW_REDIRECT_URI,
|
|
579
588
|
region: 'emea',
|
|
580
589
|
access_token: accessToken,
|
|
581
590
|
authorizationCode: authCode,
|
|
582
|
-
code_verifier: codeVerifier,
|
|
583
591
|
},
|
|
584
592
|
});
|
|
585
593
|
tokenResponse = cariadResponse;
|
|
@@ -590,8 +598,9 @@ async function vwLogin(context, email, password) {
|
|
|
590
598
|
method: 'POST',
|
|
591
599
|
url: 'https://tokenrefreshservice.apps.emea.vwapps.io/exchangeAuthCode',
|
|
592
600
|
headers: {
|
|
593
|
-
'User-Agent':
|
|
601
|
+
'User-Agent': VW_USER_AGENT,
|
|
594
602
|
'Accept': 'application/json',
|
|
603
|
+
'Accept-Language': VW_ACCEPT_LANGUAGE,
|
|
595
604
|
'Content-Type': 'application/json',
|
|
596
605
|
'X-Client-Id': VW_CLIENT_ID,
|
|
597
606
|
},
|
|
@@ -599,7 +608,6 @@ async function vwLogin(context, email, password) {
|
|
|
599
608
|
auth_code: authCode,
|
|
600
609
|
id_token: idToken || '',
|
|
601
610
|
brand: 'vw',
|
|
602
|
-
code_verifier: codeVerifier,
|
|
603
611
|
},
|
|
604
612
|
});
|
|
605
613
|
}
|
|
@@ -632,7 +640,7 @@ async function getHomeRegion(context, session, vin) {
|
|
|
632
640
|
method: 'GET',
|
|
633
641
|
url: `https://mal-1a.prd.ece.vwg-connect.com/api/cs/vds/v1/vehicles/${vin}/homeRegion`,
|
|
634
642
|
headers: {
|
|
635
|
-
'User-Agent':
|
|
643
|
+
'User-Agent': VW_USER_AGENT,
|
|
636
644
|
'Accept': 'application/json',
|
|
637
645
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
638
646
|
},
|
|
@@ -655,7 +663,7 @@ async function getPosition(context, session, vin) {
|
|
|
655
663
|
method: 'GET',
|
|
656
664
|
url: `https://emea.bff.cariad.digital/vehicle/v1/vehicles/${vin}/parkingposition`,
|
|
657
665
|
headers: {
|
|
658
|
-
'User-Agent':
|
|
666
|
+
'User-Agent': VW_USER_AGENT,
|
|
659
667
|
'Accept': 'application/json',
|
|
660
668
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
661
669
|
},
|
|
@@ -675,7 +683,7 @@ async function getPosition(context, session, vin) {
|
|
|
675
683
|
method: 'GET',
|
|
676
684
|
url: `${homeRegion}/api/bs/cf/v1/VW/DE/vehicles/${vin}/position`,
|
|
677
685
|
headers: {
|
|
678
|
-
'User-Agent':
|
|
686
|
+
'User-Agent': VW_USER_AGENT,
|
|
679
687
|
'Accept': 'application/json',
|
|
680
688
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
681
689
|
},
|
|
@@ -702,7 +710,7 @@ async function getVehicleStatus(context, session, vin) {
|
|
|
702
710
|
method: 'GET',
|
|
703
711
|
url: `https://emea.bff.cariad.digital/vehicle/v1/vehicles/${vin}/selectivestatus?jobs=all`,
|
|
704
712
|
headers: {
|
|
705
|
-
'User-Agent':
|
|
713
|
+
'User-Agent': VW_USER_AGENT,
|
|
706
714
|
'Accept': 'application/json',
|
|
707
715
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
708
716
|
},
|
|
@@ -722,7 +730,7 @@ async function getVehicleStatus(context, session, vin) {
|
|
|
722
730
|
method: 'GET',
|
|
723
731
|
url: `${homeRegion}/api/bs/vsr/v1/VW/DE/vehicles/${vin}/status`,
|
|
724
732
|
headers: {
|
|
725
|
-
'User-Agent':
|
|
733
|
+
'User-Agent': VW_USER_AGENT,
|
|
726
734
|
'Accept': 'application/json',
|
|
727
735
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
728
736
|
},
|
|
@@ -749,7 +757,7 @@ async function getHeaterStatus(context, session, vin) {
|
|
|
749
757
|
method: 'GET',
|
|
750
758
|
url: `${homeRegion}/api/bs/climatisation/v1/VW/DE/vehicles/${vin}/climater`,
|
|
751
759
|
headers: {
|
|
752
|
-
'User-Agent':
|
|
760
|
+
'User-Agent': VW_USER_AGENT,
|
|
753
761
|
'Accept': 'application/json',
|
|
754
762
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
755
763
|
},
|
|
@@ -776,7 +784,7 @@ async function controlHeater(context, session, vin, spin, action, duration) {
|
|
|
776
784
|
method: 'GET',
|
|
777
785
|
url: `${homeRegion}/api/rolesrights/authorization/v2/vehicles/${vin}/services/rclima_v1/operations/P_START_CLIMA_AU/security-pin-auth-requested`,
|
|
778
786
|
headers: {
|
|
779
|
-
'User-Agent':
|
|
787
|
+
'User-Agent': VW_USER_AGENT,
|
|
780
788
|
'Accept': 'application/json',
|
|
781
789
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
782
790
|
},
|
|
@@ -789,7 +797,7 @@ async function controlHeater(context, session, vin, spin, action, duration) {
|
|
|
789
797
|
method: 'POST',
|
|
790
798
|
url: `${homeRegion}/api/rolesrights/authorization/v2/security-pin-auth-completed`,
|
|
791
799
|
headers: {
|
|
792
|
-
'User-Agent':
|
|
800
|
+
'User-Agent': VW_USER_AGENT,
|
|
793
801
|
'Accept': 'application/json',
|
|
794
802
|
'Content-Type': 'application/json',
|
|
795
803
|
'Authorization': `Bearer ${session.accessToken}`,
|
|
@@ -820,7 +828,7 @@ async function controlHeater(context, session, vin, spin, action, duration) {
|
|
|
820
828
|
};
|
|
821
829
|
}
|
|
822
830
|
const headers = {
|
|
823
|
-
'User-Agent':
|
|
831
|
+
'User-Agent': VW_USER_AGENT,
|
|
824
832
|
'Accept': 'application/json',
|
|
825
833
|
'Content-Type': 'application/json',
|
|
826
834
|
'Authorization': `Bearer ${session.accessToken}`,
|
package/package.json
CHANGED