@thetypefounders/continue-with-google 1.3.2 → 1.4.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.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +46 -29
- package/package.json +1 -1
- package/src/index.ts +57 -37
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?:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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().replace(':', '-');
|
|
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
|
|
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
|
|
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
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?:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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().replace(':', '-');
|
|
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:
|
|
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
|
|
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
|
|
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
|
-
}
|