@thetypefounders/continue-with-google 1.3.2 → 1.4.1

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/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export type Options = {
8
8
  challengeTimeoutSeconds?: number;
9
9
  trialCount?: number;
10
10
  trialTimeoutSeconds?: number;
11
- screenshot?: boolean | string;
11
+ screenshot?: string;
12
12
  waitForSelector?: WaitForSelectorOptions;
13
13
  };
14
14
  export declare function authenticate(page: Page, email: string, password: string, secret: string, selector: string, options?: Options, logger?: Logger): Promise<ElementHandle | null>;
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { generateToken } from 'authenticator';
2
+ import { writeFile } from 'fs/promises';
2
3
  import { setTimeout } from 'node:timers/promises';
3
4
  const DEFAULTS = {
4
5
  challengeCount: 3,
@@ -9,23 +10,23 @@ const DEFAULTS = {
9
10
  export async function authenticate(page, email, password, secret, selector, options = DEFAULTS, logger = console) {
10
11
  const mergedOptions = { ...DEFAULTS, ...options };
11
12
  logger.info('Waiting to enter the email...');
12
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
13
+ await showScreenshot(page, mergedOptions.screenshot, logger);
13
14
  await page.waitForSelector('input[type=email]', { visible: true });
14
15
  logger.info('Entering the email...');
15
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
16
+ await showScreenshot(page, mergedOptions.screenshot, logger);
16
17
  await page.type('input[type=email]', email);
17
18
  await page.keyboard.press('Enter');
18
19
  logger.info('Waiting to enter the password...');
19
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
20
+ await showScreenshot(page, mergedOptions.screenshot, logger);
20
21
  await page.waitForSelector('input[type=password]', { visible: true });
21
22
  logger.info('Entering the password...');
22
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
23
+ await showScreenshot(page, mergedOptions.screenshot, logger);
23
24
  await page.type('input[type=password]', password);
24
25
  await page.keyboard.press('Enter');
25
26
  for (let attempt = 0, found = false; attempt < mergedOptions.challengeCount && !found; attempt++) {
26
27
  if (attempt > 0) {
27
28
  logger.warn(`Challenged on attempt ${attempt}. Entering the code...`);
28
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
29
+ await showScreenshot(page, mergedOptions.screenshot, logger);
29
30
  if (attempt > 1) {
30
31
  await setTimeout(1000 * mergedOptions.challengeTimeoutSeconds);
31
32
  }
@@ -49,41 +50,57 @@ export async function authenticate(page, email, password, secret, selector, opti
49
50
  }
50
51
  return await page.$(selector);
51
52
  }
53
+ async function saveImage(data) {
54
+ const timestamp = new Date(Date.now()).toISOString().replaceAll(':', '-');
55
+ const path = `continue-with-google-${timestamp}.png`;
56
+ const buffer = Buffer.from(data, 'base64');
57
+ await writeFile(path, buffer);
58
+ }
59
+ async function showScreenshot(page, mode, logger) {
60
+ if (mode === 'log') {
61
+ const content = await takeContent(page, logger);
62
+ if (content)
63
+ logger.info(content);
64
+ }
65
+ else if (mode === 'file') {
66
+ const image = await takeImage(page, logger);
67
+ if (image)
68
+ await saveImage(image);
69
+ }
70
+ }
71
+ async function takeContent(page, logger) {
72
+ try {
73
+ return await page.evaluate(() => document.body.innerText);
74
+ }
75
+ catch (error) {
76
+ logger.warn(`Failed to take the content (${error}).`);
77
+ return undefined;
78
+ }
79
+ }
80
+ async function takeImage(page, logger) {
81
+ try {
82
+ const content = '* { caret-color: transparent !important; }';
83
+ await page.addStyleTag({ content });
84
+ return await page.screenshot({ encoding: 'base64' });
85
+ }
86
+ catch (error) {
87
+ logger.warn(`Failed to take a screenshot (${error}).`);
88
+ return undefined;
89
+ }
90
+ }
52
91
  async function waitForTrial(page, attemptCount, attemptTimeoutSeconds, screenshot, logger) {
53
92
  for (let attempt = -1, previous = undefined, current = undefined; attempt < attemptCount && (current === undefined || previous !== current); attempt++) {
54
93
  if (attempt > 0) {
55
94
  logger.warn(`Tried on attempt ${attempt}. Waiting to finish...`);
56
- await takeScreenshotToDisplay(page, screenshot, logger);
95
+ await showScreenshot(page, screenshot, logger);
57
96
  }
58
97
  if (attempt > -1) {
59
98
  await setTimeout(1000 * attemptTimeoutSeconds);
60
99
  }
61
- const future = await takeScreenshotToCompare(page);
100
+ const future = await takeImage(page, logger);
62
101
  if (future) {
63
102
  previous = current;
64
103
  current = future;
65
104
  }
66
105
  }
67
106
  }
68
- async function takeScreenshotToCompare(page) {
69
- try {
70
- const content = '* { caret-color: transparent !important; }';
71
- await page.addStyleTag({ content });
72
- return await page.screenshot({ encoding: 'base64' });
73
- }
74
- catch {
75
- return undefined;
76
- }
77
- }
78
- async function takeScreenshotToDisplay(page, mode, logger) {
79
- const timestamp = new Date(Date.now()).toISOString();
80
- if (mode === 'log') {
81
- const content = await page.evaluate(() => document.body.innerText);
82
- logger.info(`${timestamp}:\n${content}\n`);
83
- }
84
- else if (mode) {
85
- const path = `continue-with-google-${timestamp.replace(':', '-')}.png`;
86
- // @ts-ignore
87
- await page.screenshot({ path });
88
- }
89
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thetypefounders/continue-with-google",
3
- "version": "1.3.2",
3
+ "version": "1.4.1",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Ivan Ukhov <ivan.ukhov@gmail.com>",
6
6
  "description": "Two-factor authentication with Google via Puppeteer",
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { generateToken } from 'authenticator';
2
+ import { writeFile } from 'fs/promises';
2
3
  import { setTimeout } from 'node:timers/promises';
3
4
  import { type ElementHandle, Page, WaitForSelectorOptions } from 'puppeteer';
4
5
 
@@ -12,7 +13,7 @@ export type Options = {
12
13
  challengeTimeoutSeconds?: number;
13
14
  trialCount?: number;
14
15
  trialTimeoutSeconds?: number;
15
- screenshot?: boolean | string;
16
+ screenshot?: string;
16
17
  waitForSelector?: WaitForSelectorOptions;
17
18
  };
18
19
 
@@ -35,20 +36,20 @@ export async function authenticate(
35
36
  const mergedOptions = { ...DEFAULTS, ...options };
36
37
 
37
38
  logger.info('Waiting to enter the email...');
38
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
39
+ await showScreenshot(page, mergedOptions.screenshot, logger);
39
40
  await page.waitForSelector('input[type=email]', { visible: true });
40
41
 
41
42
  logger.info('Entering the email...');
42
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
43
+ await showScreenshot(page, mergedOptions.screenshot, logger);
43
44
  await page.type('input[type=email]', email);
44
45
  await page.keyboard.press('Enter');
45
46
 
46
47
  logger.info('Waiting to enter the password...');
47
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
48
+ await showScreenshot(page, mergedOptions.screenshot, logger);
48
49
  await page.waitForSelector('input[type=password]', { visible: true });
49
50
 
50
51
  logger.info('Entering the password...');
51
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
52
+ await showScreenshot(page, mergedOptions.screenshot, logger);
52
53
  await page.type('input[type=password]', password);
53
54
  await page.keyboard.press('Enter');
54
55
 
@@ -59,7 +60,7 @@ export async function authenticate(
59
60
  ) {
60
61
  if (attempt > 0) {
61
62
  logger.warn(`Challenged on attempt ${attempt}. Entering the code...`);
62
- await takeScreenshotToDisplay(page, mergedOptions.screenshot, logger);
63
+ await showScreenshot(page, mergedOptions.screenshot, logger);
63
64
  if (attempt > 1) {
64
65
  await setTimeout(1000 * mergedOptions.challengeTimeoutSeconds!);
65
66
  }
@@ -91,11 +92,58 @@ export async function authenticate(
91
92
  return await page.$(selector);
92
93
  }
93
94
 
95
+ async function saveImage(data: string): Promise<void> {
96
+ const timestamp = new Date(Date.now()).toISOString().replaceAll(':', '-');
97
+ const path = `continue-with-google-${timestamp}.png`;
98
+ const buffer = Buffer.from(data, 'base64');
99
+ await writeFile(path, buffer);
100
+ }
101
+
102
+ async function showScreenshot(
103
+ page: Page,
104
+ mode: string | undefined,
105
+ logger: Logger
106
+ ): Promise<void> {
107
+ if (mode === 'log') {
108
+ const content = await takeContent(page, logger);
109
+ if (content) logger.info(content);
110
+ } else if (mode === 'file') {
111
+ const image = await takeImage(page, logger);
112
+ if (image) await saveImage(image);
113
+ }
114
+ }
115
+
116
+ async function takeContent(
117
+ page: Page,
118
+ logger: Logger
119
+ ): Promise<string | undefined> {
120
+ try {
121
+ return await page.evaluate(() => document.body.innerText);
122
+ } catch (error) {
123
+ logger.warn(`Failed to take the content (${error}).`);
124
+ return undefined;
125
+ }
126
+ }
127
+
128
+ async function takeImage(
129
+ page: Page,
130
+ logger: Logger
131
+ ): Promise<string | undefined> {
132
+ try {
133
+ const content = '* { caret-color: transparent !important; }';
134
+ await page.addStyleTag({ content });
135
+ return await page.screenshot({ encoding: 'base64' });
136
+ } catch (error) {
137
+ logger.warn(`Failed to take a screenshot (${error}).`);
138
+ return undefined;
139
+ }
140
+ }
141
+
94
142
  async function waitForTrial(
95
143
  page: Page,
96
144
  attemptCount: number,
97
145
  attemptTimeoutSeconds: number,
98
- screenshot: boolean | string | undefined,
146
+ screenshot: string | undefined,
99
147
  logger: Logger
100
148
  ): Promise<void> {
101
149
  for (
@@ -105,43 +153,15 @@ async function waitForTrial(
105
153
  ) {
106
154
  if (attempt > 0) {
107
155
  logger.warn(`Tried on attempt ${attempt}. Waiting to finish...`);
108
- await takeScreenshotToDisplay(page, screenshot, logger);
156
+ await showScreenshot(page, screenshot, logger);
109
157
  }
110
158
  if (attempt > -1) {
111
159
  await setTimeout(1000 * attemptTimeoutSeconds);
112
160
  }
113
- const future = await takeScreenshotToCompare(page);
161
+ const future = await takeImage(page, logger);
114
162
  if (future) {
115
163
  previous = current;
116
164
  current = future;
117
165
  }
118
166
  }
119
167
  }
120
-
121
- async function takeScreenshotToCompare(
122
- page: Page
123
- ): Promise<string | undefined> {
124
- try {
125
- const content = '* { caret-color: transparent !important; }';
126
- await page.addStyleTag({ content });
127
- return await page.screenshot({ encoding: 'base64' });
128
- } catch {
129
- return undefined;
130
- }
131
- }
132
-
133
- async function takeScreenshotToDisplay(
134
- page: Page,
135
- mode: boolean | string | undefined,
136
- logger: Logger
137
- ): Promise<void> {
138
- const timestamp = new Date(Date.now()).toISOString();
139
- if (mode === 'log') {
140
- const content = await page.evaluate(() => document.body.innerText);
141
- logger.info(`${timestamp}:\n${content}\n`);
142
- } else if (mode) {
143
- const path = `continue-with-google-${timestamp.replace(':', '-')}.png`;
144
- // @ts-ignore
145
- await page.screenshot({ path });
146
- }
147
- }