iobroker.google-sharedlocations2 0.3.1 → 0.3.3

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.
package/README.md CHANGED
@@ -27,6 +27,12 @@ Copyright and trademark of Google are property of Google.
27
27
  Placeholder for the next version (at the beginning of the line):
28
28
  ### **WORK IN PROGRESS**
29
29
  -->
30
+ ### 0.3.3 (2026-02-17)
31
+ * (Garfonso) if deleting cookies, also delete cookies in Browser to force login with username & password.
32
+
33
+ ### 0.3.2 (2026-02-09)
34
+ * (Garfonso) refresh with browser ignores cookies from adapter
35
+
30
36
  ### 0.3.1 (2026-02-09)
31
37
  * (Garfonso) improved logging during login.
32
38
  * (Garfonso) handle situation where browser logs in with his cookie, so we only need to read the cookie.
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "google-sharedlocations2",
4
- "version": "0.3.1",
4
+ "version": "0.3.3",
5
5
  "news": {
6
+ "0.3.3": {
7
+ "en": "if deleting cookies, also delete cookies in Browser to force login with username & password.",
8
+ "de": "wenn Sie Cookies löschen, löschen Sie auch Cookies im Browser, um die Anmeldung mit Benutzername & Passwort zu zwingen.",
9
+ "ru": "при удалении файлов cookie также удаляйте файлы cookie в браузере, чтобы заставить войти в систему с именем пользователя и паролем.",
10
+ "pt": "se excluir cookies, também excluir cookies no Navegador para forçar login com nome de usuário e senha.",
11
+ "nl": "als u cookies verwijdert, verwijdert u ook cookies in de browser om inloggen met gebruikersnaam en wachtwoord te forceren.",
12
+ "fr": "si vous supprimez les cookies, supprimez également les cookies dans le navigateur pour forcer la connexion avec le nom d'utilisateur et le mot de passe.",
13
+ "it": "se la cancellazione dei cookie, anche eliminare i cookie in Browser per forzare il login con nome utente e password.",
14
+ "es": "si elimina las cookies, también eliminar las cookies en Browser para forzar el login con el nombre de usuario & contraseña.",
15
+ "pl": "jeśli usuniesz pliki cookie, usuń je również w przeglądarce, aby wymusić logowanie z nazwą użytkownika i hasłem.",
16
+ "uk": "якщо видаліть файли cookie, також видаліть файли cookie у браузері, щоб захистити логін з ім'ям користувача та паролем.",
17
+ "zh-cn": "如果删除 cookie, 也可以在浏览器中删除 cookie, 以强制用户名和密码登录 ."
18
+ },
19
+ "0.3.2": {
20
+ "en": "refresh with browser ignores cookies from adapter",
21
+ "de": "mit browser aktualisieren ignoriert cookies vom adapter",
22
+ "ru": "обновление с браузером игнорирует файлы cookie от адаптера",
23
+ "pt": "atualizar com o navegador ignora cookies do adaptador",
24
+ "nl": "vernieuwen met browser negeert cookies van adapter",
25
+ "fr": "rafraîchir avec le navigateur ignore les cookies de l'adaptateur",
26
+ "it": "aggiornare con il browser ignora i cookie dall'adattatore",
27
+ "es": "refresco con el navegador ignora las cookies del adaptador",
28
+ "pl": "odświeżenie z przeglądarką ignoruje pliki cookie z adaptera",
29
+ "uk": "оновлення з браузером ігнорує файли cookie з адаптера",
30
+ "zh-cn": "用浏览器刷新忽略适配器的 cookie"
31
+ },
6
32
  "0.3.1": {
7
33
  "en": "improved logging during login.\nhandle situation where browser logs in with his cookie, so we only need to read the cookie.",
8
34
  "de": "verbessertes logging während des logins.\nkorrektes bearbeiten der situation, in der sich browser mit seinem cookie einloggt, wir müssen nur das cookie lesen.",
@@ -67,32 +93,6 @@
67
93
  "pl": "dodane: wsparcie dla miejsc\ndodane: wsparcie dla ogrodzeń\nspróbuj zapobiec logowaniu jak najwięcej.",
68
94
  "uk": "додано: підтримка місць\nдоданий: підтримка парканів\nнамагатися попередити логін якомога простіше.",
69
95
  "zh-cn": "添加:对位置的支持\n添加:支持围栏\n尽量防止登录."
70
- },
71
- "0.0.3": {
72
- "en": "prevent login if no username and password is set\nfix tests",
73
- "de": "verhindern login, wenn kein benutzername und passwort eingestellt ist\ntests repariert",
74
- "ru": "предотвратить вход в систему, если имя пользователя и пароль не установлены\nисправление",
75
- "pt": "impedir o login se nenhum nome de usuário e senha estiver definido\ncorrigir os testes",
76
- "nl": "login voorkomen als er geen gebruikersnaam en wachtwoord is ingesteld\nvastleggen van tests",
77
- "fr": "empêcher le login si aucun nom d'utilisateur et mot de passe n'est défini\nessais de correction",
78
- "it": "impedire il login se non viene impostato nessun nome utente e password\ntest di correzione",
79
- "es": "previene el inicio de sesión si no se establece el nombre de usuario y la contraseña\npruebas de reparación",
80
- "pl": "zapobiec logowaniu, jeśli nie jest ustawiona nazwa użytkownika i hasło\nbadania naprawcze",
81
- "uk": "заборонити логін, якщо не встановлено ім’я користувача та пароль\nфіксувати тести",
82
- "zh-cn": "如果没有设置用户名和密码, 请防止登录\n固定测试"
83
- },
84
- "0.0.2": {
85
- "en": "store password encrypted",
86
- "de": "speicher passwort verschlüsselt",
87
- "ru": "зашифрованный пароль",
88
- "pt": "guardar a senha encriptada",
89
- "nl": "wachtwoord versleuteld opslaan",
90
- "fr": "crypté du mot de passe de stockage",
91
- "it": "negozio password crittografato",
92
- "es": "almacenar contraseña cifrada",
93
- "pl": "przechowywać zaszyfrowane hasło",
94
- "uk": "зашифрований паролем",
95
- "zh-cn": "存储加密密码"
96
96
  }
97
97
  },
98
98
  "titleLang": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.google-sharedlocations2",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Share your location with iobroker via google maps.",
5
5
  "author": {
6
6
  "name": "Garfonso",
package/src/lib/Cookie.ts CHANGED
@@ -169,12 +169,15 @@ export class Cookie {
169
169
  }
170
170
  }
171
171
 
172
+ // seems puppeteer sets expires to -1 if not present.
172
173
  this.cookies
173
- .filter(c => c.expires && c.expires < Date.now() / 1000)
174
+ .filter(c => c.expires && c.expires > 0 && c.expires < Date.now() / 1000)
174
175
  .forEach(c =>
175
- this.log.debug(`Cookie ${c.name} expired at ${new Date(c.expires! * 1000).toISOString()}`),
176
+ this.log.debug(
177
+ `Cookie ${c.name} expired at ${new Date(c.expires! * 1000).toISOString()} - ${c.expires}`,
178
+ ),
176
179
  );
177
- this.cookies = this.cookies.filter(c => !c.expires || c.expires > Date.now() / 1000); //remove expired cookies
180
+ this.cookies = this.cookies.filter(c => !c.expires || c.expires < 0 || c.expires > Date.now() / 1000); //remove expired cookies
178
181
 
179
182
  this.log?.debug(`Cookie updated. Length: ${oldLength} -> ${this.cookies.length}`);
180
183
  return this.storeCookie();
@@ -311,9 +314,10 @@ export class Cookie {
311
314
  /**
312
315
  * Refresh the current cookie by using puppeteer to load Google Maps with existing cookie.
313
316
  *
317
+ * @param withCookies - if true, will try to set existing cookies in browser before loading page, default is false. This can help if cookies are still valid but not complete enough to work without browser session.
314
318
  * @returns true if refresh was successful
315
319
  */
316
- async refreshCookieWithBrowser(): Promise<boolean> {
320
+ async refreshCookieWithBrowser(withCookies: boolean = false): Promise<boolean> {
317
321
  if (this.browser) {
318
322
  this.log.info('Seems we are already trying to log in. Aborting new login attempt.');
319
323
  return false;
@@ -323,50 +327,75 @@ export class Cookie {
323
327
  const page = await this.startBrowser();
324
328
  if (!page) {
325
329
  this.log.error('Could not start browser for cookie refresh.');
330
+ await this.cleanUp();
326
331
  return false;
327
332
  }
328
333
 
329
- const cookieArray = [...this.cookies];
330
- // somehow we stored wrong cookies... :-/ Try to clean up here.
331
- while (cookieArray.length > 0) {
332
- try {
333
- //await page.setCookie(...cookieArray);
334
- await this.browser!.setCookie(...cookieArray);
335
- break;
336
- } catch (e) {
337
- this.log.error(`Error setting cookies in browser: ${(e as Error).message}, trying again...`);
338
- const cookie = cookieArray.pop(); //remove last cookie and try again, maybe some cookies are not valid for puppeteer or something.
339
- console.log('Removed cookie:', cookie);
334
+ if (withCookies) {
335
+ const cookieArray = [...this.cookies];
336
+ // somehow we stored wrong cookies... :-/ Try to clean up here.
337
+ while (cookieArray.length > 0) {
338
+ try {
339
+ //await page.setCookie(...cookieArray);
340
+ await this.browser!.setCookie(...cookieArray);
341
+ break;
342
+ } catch (e) {
343
+ this.log.error(`Error setting cookies in browser: ${(e as Error).message}, trying again...`);
344
+ const cookie = cookieArray.pop(); //remove last cookie and try again, maybe some cookies are not valid for puppeteer or something.
345
+ console.log('Removed cookie:', cookie);
346
+ }
340
347
  }
341
348
  }
342
349
 
343
350
  try {
344
- await page.goto('https://www.google.com/maps', { waitUntil: 'networkidle2', timeout: 60000 });
351
+ this.log.debug('Loading Google login page to refresh cookie.');
352
+ await page.goto(
353
+ 'https://accounts.google.com/ServiceLogin?hl=de&continue=https://www.google.com/maps&gae=cb-eomtm',
354
+ { waitUntil: 'networkidle2', timeout: 60000 },
355
+ );
356
+ this.log.debug(
357
+ 'Waiting for page to load, currently waiting fixed 5 seconds, because network never gets idle for maps',
358
+ );
345
359
  await new Promise(r => setTimeout(r, 5000));
346
-
347
- await this.sendRequest();
348
- await this.getCookiesFromPage(page);
349
- return true;
360
+ if (!page.url().includes('accounts.google.com')) {
361
+ this.log.debug('Browser logged in, refreshing cookie.');
362
+ await this.getCookiesFromPage(page);
363
+ const results = await this.sendRequest();
364
+ if (results && results.length > 0) {
365
+ await this.cleanUp();
366
+ return true;
367
+ }
368
+ }
350
369
  } catch (e) {
351
370
  this.log.error(
352
371
  `Error during cookie refresh: ${(e as Error).message}, ${e instanceof Error ? e.stack : ''}`,
353
372
  );
354
- return false;
355
373
  }
374
+ await this.cleanUp();
375
+ return false;
356
376
  }
357
377
 
358
378
  /**
359
379
  * Login to Google using puppeteer to get new cookies.
380
+ *
381
+ * @param forceLogin - if true, will try to login even if current cookie seems valid, default is false
360
382
  */
361
- async loginToGetNewCookies(): Promise<boolean> {
383
+ async loginToGetNewCookies(forceLogin: boolean = false): Promise<boolean> {
362
384
  let currentStep;
363
385
  try {
364
- if (this.isValid()) {
365
- this.log.info('Current cookie seems valid, trying refresh.');
366
- await this.refreshCookieWithBrowser();
367
- if (this.isValid()) {
386
+ // try to refresh cookie from browser session first:
387
+ if (!forceLogin) {
388
+ let result = await this.refreshCookieWithBrowser();
389
+ if (result) {
368
390
  this.log.info('Cookie refresh successful, no need to login again.');
369
391
  return true;
392
+ } else if (this.isValid()) {
393
+ this.log.info('Current cookie seems valid, trying refresh.');
394
+ result = await this.refreshCookieWithBrowser(true);
395
+ if (result) {
396
+ this.log.info('Cookie refresh with existing cookies successful, no need to login again.');
397
+ return true;
398
+ }
370
399
  }
371
400
  }
372
401
 
@@ -384,6 +413,7 @@ export class Cookie {
384
413
  const page = await this.startBrowser();
385
414
  if (!page) {
386
415
  this.log.error('Could not start browser for login.');
416
+ await this.cleanUp();
387
417
  return false;
388
418
  }
389
419
 
@@ -391,6 +421,13 @@ export class Cookie {
391
421
  currentStep = msg;
392
422
  this.log.debug(msg);
393
423
  };
424
+
425
+ if (forceLogin) {
426
+ logDebug('Force login enabled, clearing cookies and local storage.');
427
+ const cookies = await this.browser!.cookies();
428
+ await this.browser!.deleteCookie(...cookies);
429
+ }
430
+
394
431
  logDebug('going to google login page.');
395
432
  await page.goto(
396
433
  'https://accounts.google.com/ServiceLogin?hl=de&continue=https://www.google.com/maps&gae=cb-eomtm',
@@ -405,7 +442,13 @@ export class Cookie {
405
442
  if (!page.url().includes('accounts.google.com')) {
406
443
  logDebug('Already logged in, refreshing cookie.');
407
444
  await this.getCookiesFromPage(page);
408
- return true;
445
+ await this.cleanUp();
446
+ const results = await this.sendRequest();
447
+ if (results && results.length > 0) {
448
+ this.log.info('Login successful with existing session, no need to fill in credentials.');
449
+ return true;
450
+ }
451
+ return false;
409
452
  }
410
453
 
411
454
  logDebug('filling in username.');
@@ -432,19 +475,18 @@ export class Cookie {
432
475
  await page.goto('https://www.google.com/maps');
433
476
  logDebug('getting cookies.');
434
477
  await this.getCookiesFromPage(page);
435
- return true;
478
+ await this.cleanUp();
479
+ const results = await this.sendRequest();
480
+ if (results && results.length > 0) {
481
+ this.log.info('Login successful with existing session, no need to fill in credentials.');
482
+ return true;
483
+ }
484
+ return false;
436
485
  } catch (e) {
437
486
  this.log.error(`Error in puppeteer: ${(e as Error).message}`);
438
487
  this.log.error(`The step puppeteer failed was: ${currentStep}`);
439
488
  // try to close browser if open
440
- if (this.browser) {
441
- try {
442
- await this.browser.close();
443
- } catch {
444
- /* ignore */
445
- }
446
- }
447
- this.browser = null;
489
+ await this.cleanUp();
448
490
  }
449
491
  return false;
450
492
  }
@@ -453,9 +495,13 @@ export class Cookie {
453
495
  * Clean up on unload.
454
496
  */
455
497
  async cleanUp(): Promise<void> {
456
- if (this.browser) {
457
- await this.browser.close();
458
- this.browser = null;
498
+ try {
499
+ if (this.browser) {
500
+ await this.browser.close();
501
+ this.browser = null;
502
+ }
503
+ } catch (e) {
504
+ this.log.error(`Error closing browser: ${(e as Error).message} - ${e instanceof Error ? e.stack : ''}`);
459
505
  }
460
506
  }
461
507
 
package/src/main.ts CHANGED
@@ -141,6 +141,9 @@ export class GoogleSharedlocations2 extends utils.Adapter {
141
141
  await this.setState('info.connection', false, true);
142
142
  if (this._successFullPolls > 0) {
143
143
  //try to get new cookie:
144
+ this.log.debug(
145
+ `Polling failed, trying to obtain new cookies, because got ${this._successFullPolls} valid results before.`,
146
+ );
144
147
  this._successFullPolls = 0;
145
148
  await this.cookie.loginToGetNewCookies();
146
149
  }
@@ -365,7 +368,7 @@ export class GoogleSharedlocations2 extends utils.Adapter {
365
368
  this.log.info('Current cookies state was cleared, trying to obtain new cookies.');
366
369
  this._successFullPolls = 0;
367
370
  this.cookie.readCookieFromString(''); //clear old cookie
368
- await this.cookie.loginToGetNewCookies();
371
+ await this.cookie.loginToGetNewCookies(true);
369
372
  } else {
370
373
  this.log.info(
371
374
  'Current cookies state was changed from outside the adapter, updating internal cookie store.',