coffeeinabit 0.0.26 → 0.0.29
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/Makefile +3 -0
- package/cloud_auth.js +170 -170
- package/linkedin_automation.js +1 -2
- package/package.json +35 -35
- package/public/dashboard.html +1 -1
- package/public/login.html +126 -126
- package/public/styles.css +490 -490
- package/server.js +217 -217
- package/tools/comment_post.js +155 -155
- package/tools/context_paths.js +24 -24
- package/tools/cookie_manager.js +149 -149
- package/tools/get_daily_linkedin_connections.js +203 -203
- package/tools/get_linkedin_search_results.js +142 -142
- package/tools/get_linkedin_updates.js +51 -51
- package/tools/get_messages.js +362 -362
- package/tools/get_new_messages.js +424 -424
- package/tools/get_profile.js +112 -39
- package/tools/human_mouse.js +198 -194
- package/tools/human_typing.js +67 -67
- package/tools/like_post.js +99 -99
- package/tools/navigation.js +32 -32
- package/tools/send_connection_request.js +238 -238
- package/tools/send_messages.js +417 -417
package/Makefile
ADDED
package/cloud_auth.js
CHANGED
|
@@ -1,170 +1,170 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
|
|
3
|
-
export class CloudAuth {
|
|
4
|
-
constructor() {
|
|
5
|
-
this.sessionSecret = process.env.SESSION_SECRET || 'coffeeinabit-secret-key-change-in-production';
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
async getLoginUrl(redirectUri) {
|
|
9
|
-
try {
|
|
10
|
-
const params = new URLSearchParams({
|
|
11
|
-
client_id: '4rhqg2pjfhjkq42mr7iilpnmsu',
|
|
12
|
-
response_type: 'code',
|
|
13
|
-
redirect_uri: redirectUri,
|
|
14
|
-
scope: 'openid email profile'
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const loginUrl = `https://coffeeinabit.auth.us-east-1.amazoncognito.com/login?${params.toString()}`;
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
success: true,
|
|
21
|
-
loginUrl: loginUrl
|
|
22
|
-
};
|
|
23
|
-
} catch (error) {
|
|
24
|
-
return {
|
|
25
|
-
success: false,
|
|
26
|
-
error: error.message
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async exchangeCodeForTokens(code, redirectUri) {
|
|
32
|
-
try {
|
|
33
|
-
console.log('[CloudAuth] Received authorization code:', code.substring(0, 10) + '...');
|
|
34
|
-
console.log('[CloudAuth] Using redirect_uri:', redirectUri);
|
|
35
|
-
|
|
36
|
-
const response = await axios.get(`https://api.coffeeinabit.com/auth/token?code=${encodeURIComponent(code)}&redirect_url=${encodeURIComponent(redirectUri)}`);
|
|
37
|
-
|
|
38
|
-
if (response.data.error) {
|
|
39
|
-
throw new Error(response.data.error);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const { id_token, access_token, refresh_token } = response.data;
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
success: true,
|
|
46
|
-
tokens: {
|
|
47
|
-
idToken: id_token,
|
|
48
|
-
accessToken: access_token,
|
|
49
|
-
refreshToken: refresh_token
|
|
50
|
-
},
|
|
51
|
-
user: this.extractUserFromToken(id_token)
|
|
52
|
-
};
|
|
53
|
-
} catch (error) {
|
|
54
|
-
console.error('[CloudAuth] Token exchange failed:', error.response?.status, error.response?.data);
|
|
55
|
-
return {
|
|
56
|
-
success: false,
|
|
57
|
-
error: error.message
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async refreshTokens(refreshToken) {
|
|
63
|
-
try {
|
|
64
|
-
const response = await axios.get(
|
|
65
|
-
`https://api.coffeeinabit.com/auth/refresh?refresh_token=${encodeURIComponent(refreshToken)}`
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
if (response.data.error) {
|
|
69
|
-
throw new Error(response.data.error);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
success: true,
|
|
74
|
-
tokens: {
|
|
75
|
-
idToken: response.data.id_token,
|
|
76
|
-
accessToken: response.data.access_token,
|
|
77
|
-
refreshToken: response.data.refresh_token || refreshToken
|
|
78
|
-
},
|
|
79
|
-
user: this.extractUserFromToken(response.data.id_token)
|
|
80
|
-
};
|
|
81
|
-
} catch (error) {
|
|
82
|
-
return {
|
|
83
|
-
success: false,
|
|
84
|
-
error: error.message
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
extractUserFromToken(idToken) {
|
|
90
|
-
if (!idToken) return null;
|
|
91
|
-
|
|
92
|
-
try {
|
|
93
|
-
const payload = JSON.parse(Buffer.from(idToken.split('.')[1], 'base64').toString());
|
|
94
|
-
return {
|
|
95
|
-
email: payload.email || payload['cognito:username'],
|
|
96
|
-
userId: payload.sub
|
|
97
|
-
};
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error('[CloudAuth] Error extracting user from token:', error.message);
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
isTokenExpired(token) {
|
|
105
|
-
if (!token) return true;
|
|
106
|
-
|
|
107
|
-
try {
|
|
108
|
-
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
109
|
-
if (!payload || !payload.exp) return true;
|
|
110
|
-
|
|
111
|
-
const bufferTime = 5 * 60;
|
|
112
|
-
return payload.exp < (Date.now() / 1000) + bufferTime;
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error('[CloudAuth] Error checking token expiration:', error.message);
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async ensureValidToken(session) {
|
|
120
|
-
if (!session.tokens?.idToken) {
|
|
121
|
-
return { valid: false, error: 'No token available' };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (this.isTokenExpired(session.tokens.idToken)) {
|
|
125
|
-
console.log('[CloudAuth] Token expired or expiring soon, attempting refresh...');
|
|
126
|
-
|
|
127
|
-
if (!session.tokens.refreshToken) {
|
|
128
|
-
return { valid: false, error: 'No refresh token available' };
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const result = await this.refreshTokens(session.tokens.refreshToken);
|
|
132
|
-
|
|
133
|
-
if (result.success) {
|
|
134
|
-
this.storeTokensInSession(session, result.tokens, result.user);
|
|
135
|
-
return { valid: true };
|
|
136
|
-
} else {
|
|
137
|
-
return { valid: false, error: result.error };
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return { valid: true };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
storeTokensInSession(session, tokens, user) {
|
|
145
|
-
session.tokens = tokens;
|
|
146
|
-
session.user = user;
|
|
147
|
-
console.log('[CloudAuth] Tokens stored in session for user:', user?.email);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
clearSession(session) {
|
|
151
|
-
session.tokens = null;
|
|
152
|
-
session.user = null;
|
|
153
|
-
console.log('[CloudAuth] Session cleared');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
isAuthenticated(session) {
|
|
157
|
-
return !!(session.tokens && session.tokens.idToken && session.tokens.accessToken);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
getAuthStatus(session) {
|
|
161
|
-
if (this.isAuthenticated(session)) {
|
|
162
|
-
return {
|
|
163
|
-
authenticated: true,
|
|
164
|
-
user: session.user || null
|
|
165
|
-
};
|
|
166
|
-
} else {
|
|
167
|
-
return { authenticated: false };
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
|
|
3
|
+
export class CloudAuth {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.sessionSecret = process.env.SESSION_SECRET || 'coffeeinabit-secret-key-change-in-production';
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async getLoginUrl(redirectUri) {
|
|
9
|
+
try {
|
|
10
|
+
const params = new URLSearchParams({
|
|
11
|
+
client_id: '4rhqg2pjfhjkq42mr7iilpnmsu',
|
|
12
|
+
response_type: 'code',
|
|
13
|
+
redirect_uri: redirectUri,
|
|
14
|
+
scope: 'openid email profile'
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const loginUrl = `https://coffeeinabit.auth.us-east-1.amazoncognito.com/login?${params.toString()}`;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
success: true,
|
|
21
|
+
loginUrl: loginUrl
|
|
22
|
+
};
|
|
23
|
+
} catch (error) {
|
|
24
|
+
return {
|
|
25
|
+
success: false,
|
|
26
|
+
error: error.message
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async exchangeCodeForTokens(code, redirectUri) {
|
|
32
|
+
try {
|
|
33
|
+
console.log('[CloudAuth] Received authorization code:', code.substring(0, 10) + '...');
|
|
34
|
+
console.log('[CloudAuth] Using redirect_uri:', redirectUri);
|
|
35
|
+
|
|
36
|
+
const response = await axios.get(`https://api.coffeeinabit.com/auth/token?code=${encodeURIComponent(code)}&redirect_url=${encodeURIComponent(redirectUri)}`);
|
|
37
|
+
|
|
38
|
+
if (response.data.error) {
|
|
39
|
+
throw new Error(response.data.error);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const { id_token, access_token, refresh_token } = response.data;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
success: true,
|
|
46
|
+
tokens: {
|
|
47
|
+
idToken: id_token,
|
|
48
|
+
accessToken: access_token,
|
|
49
|
+
refreshToken: refresh_token
|
|
50
|
+
},
|
|
51
|
+
user: this.extractUserFromToken(id_token)
|
|
52
|
+
};
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('[CloudAuth] Token exchange failed:', error.response?.status, error.response?.data);
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
error: error.message
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async refreshTokens(refreshToken) {
|
|
63
|
+
try {
|
|
64
|
+
const response = await axios.get(
|
|
65
|
+
`https://api.coffeeinabit.com/auth/refresh?refresh_token=${encodeURIComponent(refreshToken)}`
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (response.data.error) {
|
|
69
|
+
throw new Error(response.data.error);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
success: true,
|
|
74
|
+
tokens: {
|
|
75
|
+
idToken: response.data.id_token,
|
|
76
|
+
accessToken: response.data.access_token,
|
|
77
|
+
refreshToken: response.data.refresh_token || refreshToken
|
|
78
|
+
},
|
|
79
|
+
user: this.extractUserFromToken(response.data.id_token)
|
|
80
|
+
};
|
|
81
|
+
} catch (error) {
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: error.message
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
extractUserFromToken(idToken) {
|
|
90
|
+
if (!idToken) return null;
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const payload = JSON.parse(Buffer.from(idToken.split('.')[1], 'base64').toString());
|
|
94
|
+
return {
|
|
95
|
+
email: payload.email || payload['cognito:username'],
|
|
96
|
+
userId: payload.sub
|
|
97
|
+
};
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error('[CloudAuth] Error extracting user from token:', error.message);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
isTokenExpired(token) {
|
|
105
|
+
if (!token) return true;
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString());
|
|
109
|
+
if (!payload || !payload.exp) return true;
|
|
110
|
+
|
|
111
|
+
const bufferTime = 5 * 60;
|
|
112
|
+
return payload.exp < (Date.now() / 1000) + bufferTime;
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error('[CloudAuth] Error checking token expiration:', error.message);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async ensureValidToken(session) {
|
|
120
|
+
if (!session.tokens?.idToken) {
|
|
121
|
+
return { valid: false, error: 'No token available' };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (this.isTokenExpired(session.tokens.idToken)) {
|
|
125
|
+
console.log('[CloudAuth] Token expired or expiring soon, attempting refresh...');
|
|
126
|
+
|
|
127
|
+
if (!session.tokens.refreshToken) {
|
|
128
|
+
return { valid: false, error: 'No refresh token available' };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const result = await this.refreshTokens(session.tokens.refreshToken);
|
|
132
|
+
|
|
133
|
+
if (result.success) {
|
|
134
|
+
this.storeTokensInSession(session, result.tokens, result.user);
|
|
135
|
+
return { valid: true };
|
|
136
|
+
} else {
|
|
137
|
+
return { valid: false, error: result.error };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return { valid: true };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
storeTokensInSession(session, tokens, user) {
|
|
145
|
+
session.tokens = tokens;
|
|
146
|
+
session.user = user;
|
|
147
|
+
console.log('[CloudAuth] Tokens stored in session for user:', user?.email);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
clearSession(session) {
|
|
151
|
+
session.tokens = null;
|
|
152
|
+
session.user = null;
|
|
153
|
+
console.log('[CloudAuth] Session cleared');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
isAuthenticated(session) {
|
|
157
|
+
return !!(session.tokens && session.tokens.idToken && session.tokens.accessToken);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
getAuthStatus(session) {
|
|
161
|
+
if (this.isAuthenticated(session)) {
|
|
162
|
+
return {
|
|
163
|
+
authenticated: true,
|
|
164
|
+
user: session.user || null
|
|
165
|
+
};
|
|
166
|
+
} else {
|
|
167
|
+
return { authenticated: false };
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
package/linkedin_automation.js
CHANGED
|
@@ -543,7 +543,6 @@ export class LinkedInAutomation {
|
|
|
543
543
|
try {
|
|
544
544
|
const screenshot = await this.page.screenshot({
|
|
545
545
|
fullPage: false,
|
|
546
|
-
clip: { x: 0, y: 0, width: 1200, height: 800 },
|
|
547
546
|
type: 'png',
|
|
548
547
|
timeout: 60000
|
|
549
548
|
});
|
|
@@ -963,7 +962,7 @@ export class LinkedInAutomation {
|
|
|
963
962
|
|
|
964
963
|
const launchOptions = {
|
|
965
964
|
headless: this.headless || false,
|
|
966
|
-
viewport: null,
|
|
965
|
+
viewport: (this.headless || false) ? { width: 1920, height: 1080 } : null,
|
|
967
966
|
ignoreHTTPSErrors: true,
|
|
968
967
|
args: [
|
|
969
968
|
'--disable-blink-features=AutomationControlled',
|
package/package.json
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "coffeeinabit",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "CoffeeInABit App",
|
|
5
|
-
"main": "server.js",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"automation",
|
|
9
|
-
"linkedin",
|
|
10
|
-
"windows",
|
|
11
|
-
"playwright"
|
|
12
|
-
],
|
|
13
|
-
"author": "Azam Alamov <azam.alamov@icloud.com>",
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"bin": {
|
|
16
|
-
"coffeeinabit": "./server.js"
|
|
17
|
-
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"start": "node server.js",
|
|
20
|
-
"dev": "nodemon server.js",
|
|
21
|
-
"postinstall": "npx playwright install chromium"
|
|
22
|
-
},
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"axios": "^1.6.0",
|
|
25
|
-
"dotenv": "^16.3.1",
|
|
26
|
-
"express": "^4.18.2",
|
|
27
|
-
"express-session": "^1.17.3",
|
|
28
|
-
"playwright": "^1.40.0",
|
|
29
|
-
"session-file-store": "^1.5.0",
|
|
30
|
-
"socket.io": "^4.7.5"
|
|
31
|
-
},
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"nodemon": "^3.0.1"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "coffeeinabit",
|
|
3
|
+
"version": "0.0.29",
|
|
4
|
+
"description": "CoffeeInABit App",
|
|
5
|
+
"main": "server.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"automation",
|
|
9
|
+
"linkedin",
|
|
10
|
+
"windows",
|
|
11
|
+
"playwright"
|
|
12
|
+
],
|
|
13
|
+
"author": "Azam Alamov <azam.alamov@icloud.com>",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"bin": {
|
|
16
|
+
"coffeeinabit": "./server.js"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"start": "node server.js",
|
|
20
|
+
"dev": "nodemon server.js",
|
|
21
|
+
"postinstall": "npx playwright install chromium"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"axios": "^1.6.0",
|
|
25
|
+
"dotenv": "^16.3.1",
|
|
26
|
+
"express": "^4.18.2",
|
|
27
|
+
"express-session": "^1.17.3",
|
|
28
|
+
"playwright": "^1.40.0",
|
|
29
|
+
"session-file-store": "^1.5.0",
|
|
30
|
+
"socket.io": "^4.7.5"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"nodemon": "^3.0.1"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/public/dashboard.html
CHANGED
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
<small class="text-muted" id="screenshotTimestamp">Last updated: --</small>
|
|
111
111
|
</div>
|
|
112
112
|
<div class="text-center">
|
|
113
|
-
<img id="browserScreenshot" class="img-fluid border rounded shadow-sm" style="max-width: 100%; max-height: 400px;" alt="Browser Screenshot">
|
|
113
|
+
<img id="browserScreenshot" class="img-fluid border rounded shadow-sm" style="max-width: 100%; max-height: 400px; object-fit: contain;" alt="Browser Screenshot">
|
|
114
114
|
</div>
|
|
115
115
|
</div>
|
|
116
116
|
</div>
|