fakefilter 1.1.10 → 1.1.12
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/apiserver/inc/shared.js +3 -1
- package/apiserver/inc/worker_fakefilter.js +3 -3
- package/apiserver/public/img/test.html +48 -0
- package/chart-update.js +156 -74
- package/config.js +2 -2
- package/demos/visitor0/index.js +41 -0
- package/demos/visitor0/renderedDOM.html +8 -0
- package/elements/demo.js +78 -0
- package/elements/renderedDOM.html +6459 -0
- package/elements/screenshots/afterclick.png +0 -0
- package/elements/screenshots/goto.png +0 -0
- package/fetch.js +4 -1
- package/package.json +6 -3
- package/providers/10-minute-mail.com.js +2 -1
- package/providers/10-minuten-mail.de.js +2 -1
- package/providers/10mails.net.js +2 -1
- package/providers/10minut.com.pl.js +2 -1
- package/providers/10minutemail.co.za.js +2 -1
- package/providers/10minutesemail.net.js +2 -2
- package/providers/10minutesmail.us.js +2 -1
- package/providers/22.do.js +25 -0
- package/providers/abandonmail.com.js +2 -1
- package/providers/akmail.in.js +3 -3
- package/providers/altaddress.org.js +50 -0
- package/providers/anonymmail.net.js +47 -0
- package/providers/awgarstone.com.js +15 -0
- package/providers/brodilla.email.js +3 -2
- package/providers/chacuo.net.js +38 -0
- package/providers/dispemail.com.js +3 -2
- package/providers/disposableemail.us.js +2 -1
- package/providers/dispostable.com.js +2 -1
- package/providers/emailnator.com.js +37 -0
- package/providers/etempmail.com.js +36 -0
- package/providers/fakemail.io.js +2 -1
- package/providers/faxmail.co.js +47 -0
- package/providers/findtempmail.com.js +3 -2
- package/providers/foxiomail.com.js +3 -2
- package/providers/getnada.cc.js +37 -0
- package/providers/gmailcity.com.js +37 -0
- package/providers/hottempmail.com.js +3 -2
- package/providers/instantemailaddress.com.js +3 -2
- package/providers/internxt.com.js +47 -0
- package/providers/jooko.info.js +2 -1
- package/providers/kopeechka.store.js +0 -10
- package/providers/kuku.lu.js +37 -0
- package/providers/linshiyou.com.js +25 -0
- package/providers/linshiyouxiang.net.js +36 -0
- package/providers/mail.td.js +13 -13
- package/providers/mail.tm.js +1 -1
- package/providers/mail1.js +44 -0
- package/providers/mail4qa.com.js +37 -0
- package/providers/muellmail.com.js +7 -8
- package/providers/snapmail.cc.js +42 -0
- package/providers/static.js +32 -0
- package/providers/temp-inbox.me.js +47 -0
- package/providers/temp-mail.org.2.js +60 -0
- package/providers/temp-mail.org.js +36 -0
- package/providers/temp-mailbox.com.js +35 -0
- package/providers/tempmail.adguard.com.js +31 -0
- package/providers/tempmail.io.js +38 -0
- package/providers/tempmail.quest.js +45 -0
- package/providers/temporary-email.org.js +36 -0
- package/providers/tuamaeaquelaursa.com.js +25 -0
- package/providers/youxiang.dev.js +25 -0
- package/repo-update.js +26 -13
- package/shared.js +225 -48
- package/update-repo.sh +6 -19
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
const { Sentry } = require('../config')
|
|
3
|
+
const { initiateEmpty, launch, emailBy_id_innerText, emailBy_querySelector_innerHTML, emailBy_id_value } = require('../shared')
|
|
4
|
+
const vars = require('./../vars')
|
|
5
|
+
const URL = 'https://temporary-email.org'
|
|
6
|
+
|
|
7
|
+
function start(headless=true,waitTime=3) {
|
|
8
|
+
return new Promise(async function (resolve,reject) {
|
|
9
|
+
try {
|
|
10
|
+
let {page,browser} = await launch(headless,URL,waitTime)
|
|
11
|
+
let email = await emailBy_id_value(page,'trsh_mail')
|
|
12
|
+
if (browser) await browser.close()
|
|
13
|
+
if (email) return resolve({
|
|
14
|
+
email,
|
|
15
|
+
URL,
|
|
16
|
+
t:Date.now()
|
|
17
|
+
})
|
|
18
|
+
return resolve(null)
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.log(err)
|
|
21
|
+
Sentry.captureException(err)
|
|
22
|
+
resolve(false)
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// for cli usage - development
|
|
28
|
+
if (require.main==module) {
|
|
29
|
+
start(false).then(res=>console.log(res))
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
vars.providers.push({
|
|
33
|
+
name:'temporary-email.org',
|
|
34
|
+
init:initiateEmpty,
|
|
35
|
+
start:start
|
|
36
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { findByIdValue, initiateEmpty } = require('../shared')
|
|
2
|
+
const vars = require('./../vars')
|
|
3
|
+
const URL = 'https://tuamaeaquelaursa.com/'
|
|
4
|
+
|
|
5
|
+
function start(headless = true, waitTime = 3) {
|
|
6
|
+
return new Promise(async function (resolve, reject) {
|
|
7
|
+
return resolve({
|
|
8
|
+
email: [`any@tuamaeaquelaursa.com`],
|
|
9
|
+
URL,
|
|
10
|
+
t: Date.now()
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// for cli usage - development
|
|
17
|
+
if (require.main == module) {
|
|
18
|
+
start(false).then(res => console.log(res))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
vars.providers.push({
|
|
22
|
+
name: 'tuamaeaquelaursa.com',
|
|
23
|
+
init: initiateEmpty,
|
|
24
|
+
start: start
|
|
25
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { findByIdValue, initiateEmpty } = require('../shared')
|
|
2
|
+
const vars = require('./../vars')
|
|
3
|
+
const URL = 'https://youxiang.dev/'
|
|
4
|
+
|
|
5
|
+
function start(headless = true, waitTime = 3) {
|
|
6
|
+
return new Promise(async function (resolve, reject) {
|
|
7
|
+
return resolve({
|
|
8
|
+
email: [`any@youxiang.dev`],
|
|
9
|
+
URL,
|
|
10
|
+
t: Date.now()
|
|
11
|
+
})
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
// for cli usage - development
|
|
17
|
+
if (require.main == module) {
|
|
18
|
+
start(false).then(res => console.log(res))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
vars.providers.push({
|
|
22
|
+
name: 'youxiang.dev',
|
|
23
|
+
init: initiateEmpty,
|
|
24
|
+
start: start
|
|
25
|
+
})
|
package/repo-update.js
CHANGED
|
@@ -49,11 +49,13 @@ async function start() {
|
|
|
49
49
|
try {
|
|
50
50
|
await getConfig()
|
|
51
51
|
|
|
52
|
+
// we only pull domains harvested last 365 days, so domains
|
|
53
|
+
let rows = await pullDomains(isLocal() ? 10 : 600, logger)
|
|
54
|
+
let [ combined,expiredDomains ] = await combineDomains(rows, true, 365)
|
|
52
55
|
|
|
53
|
-
let
|
|
54
|
-
let combined = await combineDomains(rows, true)
|
|
55
|
-
let json2domains = perDomain(combined)
|
|
56
|
+
let json2domains = perDomain(combined,true)
|
|
56
57
|
let markdown = `# Providers\n\n`
|
|
58
|
+
let markdownExpired = `# Providers Expired Domains\nOur service removes domains from fakefilter after a year of inactivity. If these domains reappear, they are reinstated in our database for a minimum of 365 days.\n\n`
|
|
57
59
|
let now = Math.round(Date.now() / 1000)
|
|
58
60
|
let json = {
|
|
59
61
|
version: 1,
|
|
@@ -69,39 +71,50 @@ async function start() {
|
|
|
69
71
|
let updated = `Last Update: ${new Date().toISOString()}`
|
|
70
72
|
let txt = `# Fake and Temp Mail Providers\n# https://github.com/7c/fakefilter\n# ${updated}\n\n\n`
|
|
71
73
|
|
|
74
|
+
// generate json v1 & markdown
|
|
72
75
|
for (let provider of Object.keys(combined)) {
|
|
73
76
|
let domains = combined[provider]
|
|
74
|
-
var t = new Table()
|
|
77
|
+
// var t = new Table()
|
|
75
78
|
console.log(chalk.bold.yellow(provider))
|
|
76
79
|
markdown += `## ${provider}\n`
|
|
80
|
+
markdownExpired += `## ${provider}\n`
|
|
77
81
|
txt += `## ${provider}\n`
|
|
78
82
|
|
|
79
83
|
for (let domain of Object.keys(domains)) {
|
|
80
84
|
let data = domains[domain]
|
|
81
85
|
domain = domain.toLowerCase()
|
|
86
|
+
let lastSeenAgo = Math.floor((now - data.lastseen)/60/60/24) // days
|
|
82
87
|
|
|
83
88
|
for (let host of Object.keys(data.hosts)) {
|
|
84
89
|
// json v1 format - which is host based format
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
if (!data.expired) {
|
|
91
|
+
json.domains[host] = {
|
|
92
|
+
provider,
|
|
93
|
+
firstseen: data.hosts[host].firstseen,
|
|
94
|
+
lastseen: data.hosts[host].lastseen,
|
|
95
|
+
}
|
|
96
|
+
markdown += `- ${host} (lastseen ${lastSeenAgo} days ago)\n`
|
|
97
|
+
txt += `${host}\n`
|
|
98
|
+
} else {
|
|
99
|
+
markdownExpired += `- ${host} (expired ${lastSeenAgo} days ago)\n`
|
|
89
100
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
t.newRow()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
// t.newRow()
|
|
94
104
|
}
|
|
95
105
|
}
|
|
96
106
|
markdown += `\n`
|
|
107
|
+
markdownExpired += `\n`
|
|
97
108
|
txt += `\n`
|
|
98
109
|
// console.log(t.toString())
|
|
99
110
|
}
|
|
100
111
|
markdown += `\n\n${updated}\n`
|
|
101
112
|
// deploy to file
|
|
102
113
|
if (!argv.dry) {
|
|
103
|
-
// markdown
|
|
114
|
+
// markdown not expired
|
|
104
115
|
writeToFile(path.join(__dirname, 'repo/markdown/README.md'), markdown)
|
|
116
|
+
// markdown expired
|
|
117
|
+
writeToFile(path.join(__dirname, 'repo/markdown/EXPIRED.md'),markdownExpired)
|
|
105
118
|
// json v1
|
|
106
119
|
writeToFile(path.join(__dirname, 'repo/json/data.json'), JSON.stringify(json))
|
|
107
120
|
// json v2
|
package/shared.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const debug = require('debug')('_shared')
|
|
1
2
|
const punycode = require('punycode/')
|
|
2
3
|
const { Op } = require("sequelize")
|
|
3
4
|
const { parseDomain, ParseResultType } = require("parse-domain")
|
|
@@ -5,7 +6,7 @@ const argv = require('minimist')(process.argv.slice(2))
|
|
|
5
6
|
const chalk = require('chalk')
|
|
6
7
|
var dns = require('dns')
|
|
7
8
|
const vars = require('./vars')
|
|
8
|
-
const { wait, validEmail } = require('mybase');
|
|
9
|
+
const { wait, validEmail, isLocal, utcnow } = require('mybase');
|
|
9
10
|
const puppeteer = require('puppeteer-extra')
|
|
10
11
|
const RecaptchaPlugin = require('puppeteer-extra-plugin-recaptcha')
|
|
11
12
|
var { randomUseragent, UseragentByFamily } = require('useragentsdata');
|
|
@@ -52,7 +53,8 @@ const promiseTimeout = function (ms, promise) {
|
|
|
52
53
|
])
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
function launch(headless, url, waitTime = 3, CLICK_SELECTOR = false, captchaPlugin = false, waitUntil = 'load') {
|
|
56
|
+
function launch(headless, url, waitTime = 3, CLICK_SELECTOR = false, captchaPlugin = false, waitUntil = 'load', socks5 = '') {
|
|
57
|
+
debug(`launching ${url}`)
|
|
56
58
|
return new Promise(async function (resolve, reject) {
|
|
57
59
|
try {
|
|
58
60
|
if (captchaPlugin) puppeteer.use(
|
|
@@ -65,8 +67,18 @@ function launch(headless, url, waitTime = 3, CLICK_SELECTOR = false, captchaPlug
|
|
|
65
67
|
})
|
|
66
68
|
)
|
|
67
69
|
puppeteer.use(StealthPlugin())
|
|
70
|
+
debug(`launching browser`)
|
|
71
|
+
|
|
72
|
+
const args = ['--no-sandbox']
|
|
73
|
+
if (argv.socks5 || socks5 !== '') {
|
|
74
|
+
argv.socks5 = argv.socks5 || socks5
|
|
75
|
+
debug(`using socks5 proxy ${argv.socks5}`)
|
|
76
|
+
args.push(`--proxy-server=socks5://${argv.socks5}`)
|
|
77
|
+
}
|
|
78
|
+
|
|
68
79
|
const browser = await puppeteer.launch({
|
|
69
|
-
args
|
|
80
|
+
args,
|
|
81
|
+
devtools: isLocal(), // This line opens the DevTools
|
|
70
82
|
// args: [
|
|
71
83
|
// // '--disable-features=IsolateOrigins,site-per-process',
|
|
72
84
|
// // '--flag-switches-begin --disable-site-isolation-trials --flag-switches-end',
|
|
@@ -77,14 +89,23 @@ function launch(headless, url, waitTime = 3, CLICK_SELECTOR = false, captchaPlug
|
|
|
77
89
|
headless: headless ? true : false
|
|
78
90
|
})
|
|
79
91
|
vars.browsers.push(browser)
|
|
92
|
+
debug(`opening new page`)
|
|
80
93
|
const page = await browser.newPage()
|
|
94
|
+
debug(`setting useragent`)
|
|
81
95
|
await page.setUserAgent(UA)
|
|
96
|
+
debug(`going to ${url} waituntil: ${waitUntil}`)
|
|
82
97
|
await page.goto(url, { waitUntil });
|
|
83
|
-
if (argv.ss) await page.screenshot({ path: 'screenshots/goto.png', fullPage: true })
|
|
84
98
|
|
|
99
|
+
if (argv.ss) {
|
|
100
|
+
debug(`taking screenshot as goto.png`)
|
|
101
|
+
await page.screenshot({ path: 'screenshots/goto.png', fullPage: true })
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
debug(`waiting ${waitTime} seconds`)
|
|
85
105
|
await wait(waitTime)
|
|
106
|
+
debug(`waiting ended`)
|
|
86
107
|
if (CLICK_SELECTOR) {
|
|
87
|
-
|
|
108
|
+
debug(`clicking ${CLICK_SELECTOR}`)
|
|
88
109
|
// await page.waitForNavigation()
|
|
89
110
|
try {
|
|
90
111
|
// we use puppeeter click function
|
|
@@ -103,8 +124,13 @@ function launch(headless, url, waitTime = 3, CLICK_SELECTOR = false, captchaPlug
|
|
|
103
124
|
|
|
104
125
|
// await page.waitForNavigation()
|
|
105
126
|
await wait(waitTime)
|
|
106
|
-
|
|
127
|
+
|
|
128
|
+
}
|
|
129
|
+
if (argv.ss) {
|
|
130
|
+
debug(`taking screenshot as afterclick.png`)
|
|
131
|
+
await page.screenshot({ path: 'screenshots/afterclick.png', fullPage: true })
|
|
107
132
|
}
|
|
133
|
+
debug(`finished launching`)
|
|
108
134
|
return resolve({ page, browser })
|
|
109
135
|
} catch (err) {
|
|
110
136
|
console.log(err)
|
|
@@ -126,6 +152,7 @@ function resolveMx(host) {
|
|
|
126
152
|
|
|
127
153
|
|
|
128
154
|
async function emailBy_querySelector_innerText(page, Selector, raw = false) {
|
|
155
|
+
debug(`emailBy_querySelector_innerText '${Selector}'`)
|
|
129
156
|
if (!page) return false
|
|
130
157
|
let got = await page.evaluate((Selector) => {
|
|
131
158
|
let response = []
|
|
@@ -133,6 +160,7 @@ async function emailBy_querySelector_innerText(page, Selector, raw = false) {
|
|
|
133
160
|
response.push(item.innerText)
|
|
134
161
|
return response
|
|
135
162
|
}, Selector)
|
|
163
|
+
debug(`got ${got}`)
|
|
136
164
|
// await page.screenshot({path: 'screenshots/after.png', fullPage: true})
|
|
137
165
|
if (raw) return got
|
|
138
166
|
// console.log(got)
|
|
@@ -141,7 +169,21 @@ async function emailBy_querySelector_innerText(page, Selector, raw = false) {
|
|
|
141
169
|
return false
|
|
142
170
|
}
|
|
143
171
|
|
|
172
|
+
async function clickto_element_withText(page, element, text) {
|
|
173
|
+
debug(`clickto_element_withText ${element} ${text}`)
|
|
174
|
+
if (argv.ss) await page.screenshot({ path: 'screenshots/clickto_element_withText.png', fullPage: true })
|
|
175
|
+
const got = await page.evaluate((element, text) => {
|
|
176
|
+
const spanElement = Array.from(document.querySelectorAll(element))
|
|
177
|
+
.find(span => span.textContent.trim() === text);
|
|
178
|
+
|
|
179
|
+
if (spanElement) spanElement.click()
|
|
180
|
+
return spanElement
|
|
181
|
+
}, element, text)
|
|
182
|
+
debug(`clickto_element_withText ${got}`)
|
|
183
|
+
}
|
|
184
|
+
|
|
144
185
|
async function emailBy_querySelector_innerHTML(page, Selector, raw = false) {
|
|
186
|
+
debug(`emailBy_querySelector_innerHTML '${Selector}'`)
|
|
145
187
|
if (!page) return false
|
|
146
188
|
let got = await page.evaluate((Selector) => {
|
|
147
189
|
let response = []
|
|
@@ -173,6 +215,7 @@ async function emailBy_querySelector_placeholder(page, Selector, raw = false) {
|
|
|
173
215
|
}
|
|
174
216
|
|
|
175
217
|
async function emailBy_querySelector_value(page, Selector, raw = false) {
|
|
218
|
+
debug(`emailBy_querySelector_value '${Selector}'`)
|
|
176
219
|
if (!page) return false
|
|
177
220
|
let got = await page.evaluate((Selector) => {
|
|
178
221
|
let response = []
|
|
@@ -180,22 +223,58 @@ async function emailBy_querySelector_value(page, Selector, raw = false) {
|
|
|
180
223
|
response.push(item.value)
|
|
181
224
|
return response
|
|
182
225
|
}, Selector)
|
|
226
|
+
debug(`got '${got}'`)
|
|
183
227
|
if (raw) return got
|
|
184
228
|
for (let item of got)
|
|
185
|
-
if (validEmail(item.trim())) return item.toLowerCase().trim()
|
|
229
|
+
if (item && validEmail(item.trim())) return item.toLowerCase().trim()
|
|
186
230
|
return false
|
|
187
231
|
}
|
|
188
232
|
|
|
189
233
|
async function emailBy_id_value(page, tagId) {
|
|
190
|
-
|
|
234
|
+
debug(`emailBy_id_value ${tagId} ${page}`)
|
|
235
|
+
if (!page) {
|
|
236
|
+
debug(`no page found`)
|
|
237
|
+
return false
|
|
238
|
+
}
|
|
239
|
+
debug(`page.evaluate '${tagId}'`)
|
|
191
240
|
let got = await page.evaluate((tagId) => {
|
|
192
|
-
return document.getElementById(tagId)
|
|
241
|
+
return document.getElementById(tagId)?.value
|
|
193
242
|
}, tagId)
|
|
194
|
-
|
|
195
|
-
if (validEmail(got
|
|
243
|
+
debug(`got ${got}`)
|
|
244
|
+
if (validEmail(got?.trim())) return got.toLowerCase().trim()
|
|
196
245
|
return false
|
|
197
246
|
}
|
|
198
247
|
|
|
248
|
+
async function email_recursive_search(page, selector) {
|
|
249
|
+
if (!page) return false
|
|
250
|
+
let emails = await page.evaluate((selector) => {
|
|
251
|
+
function findAllEmails(element, regex, emails = []) {
|
|
252
|
+
// Check the current element
|
|
253
|
+
if (regex.test(element.innerText)) {
|
|
254
|
+
if (!emails.includes(element.innerText)) emails.push(element.innerText);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Recursively search in each child
|
|
258
|
+
for (let child of element.children) {
|
|
259
|
+
findAllEmails(child, regex, emails);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return emails;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let emailRegex = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;
|
|
266
|
+
// https://stackoverflow.com/questions/46155/how-can-i-validate-an-email-address-in-javascript
|
|
267
|
+
let emails = []
|
|
268
|
+
for (let item of document.querySelectorAll(selector)) {
|
|
269
|
+
findAllEmails(item, emailRegex, emails);
|
|
270
|
+
}
|
|
271
|
+
return emails
|
|
272
|
+
}, selector)
|
|
273
|
+
emails = emails.filter(e => validEmail(e))
|
|
274
|
+
return emails
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
|
|
199
278
|
async function emailBy_id_innerText(page, tagId, raw = false) {
|
|
200
279
|
if (!page) return false
|
|
201
280
|
let got = await page.evaluate((tagId) => {
|
|
@@ -241,7 +320,8 @@ function findByIdValue(headless, url, tagId, waitTime = 3) {
|
|
|
241
320
|
})
|
|
242
321
|
}
|
|
243
322
|
|
|
244
|
-
function emailFrom_combobox_selector(page, Selector, replaceRX = false) {
|
|
323
|
+
function emailFrom_combobox_selector(page, Selector, replaceRX = false, raw = false) {
|
|
324
|
+
debug(`emailFrom_combobox_selector ${Selector}`)
|
|
245
325
|
return new Promise(async function (resolve, reject) {
|
|
246
326
|
if (!page) return resolve(false)
|
|
247
327
|
let got = await page.evaluate((Selector) => {
|
|
@@ -249,12 +329,15 @@ function emailFrom_combobox_selector(page, Selector, replaceRX = false) {
|
|
|
249
329
|
// console.log(`>>`,Selector)
|
|
250
330
|
// console.log(document.querySelectorAll(Selector))
|
|
251
331
|
for (let option of document.querySelectorAll(Selector)[0].children) {
|
|
252
|
-
console.log(`option`, option)
|
|
253
332
|
let txt = option.innerText.toLowerCase().trim()
|
|
254
|
-
response.push(`any
|
|
333
|
+
if (txt.search(/^@/) == 0) response.push(`any` + txt); else
|
|
334
|
+
response.push(`any@` + txt)
|
|
335
|
+
console.log(`option`, option, response)
|
|
255
336
|
}
|
|
256
337
|
return response
|
|
257
338
|
}, Selector)
|
|
339
|
+
debug(`got ${got}`)
|
|
340
|
+
// if (raw) return got
|
|
258
341
|
let email = []
|
|
259
342
|
for (let item of got) {
|
|
260
343
|
if (replaceRX) item = item.replace(replaceRX, '').toLowerCase().trim()
|
|
@@ -386,90 +469,180 @@ function getProviderDetails(name) {
|
|
|
386
469
|
return null
|
|
387
470
|
}
|
|
388
471
|
|
|
389
|
-
function combineDomains(rows,obfuscateTime=true) {
|
|
472
|
+
function combineDomains(rows, obfuscateTime = true, expiration_days = 2 * 365) {
|
|
473
|
+
let profile = {
|
|
474
|
+
punycode: 0,
|
|
475
|
+
domainparse: 0,
|
|
476
|
+
progressbar: 0,
|
|
477
|
+
whitelistcheck: 0,
|
|
478
|
+
emailvalidation: 0,
|
|
479
|
+
total: 0
|
|
480
|
+
}
|
|
481
|
+
let domainparse_cache = {
|
|
482
|
+
|
|
483
|
+
}
|
|
390
484
|
return new Promise(async function (resolve, reject) {
|
|
391
485
|
let result = {} // provider/domain
|
|
392
486
|
const progress = require('progressbar').create().step('combining')
|
|
393
487
|
progress.setTotal(rows.length)
|
|
488
|
+
const started = Date.now()
|
|
489
|
+
let cnt = 0
|
|
394
490
|
for (let row of rows) {
|
|
491
|
+
// if (row.domain!=='maitrimony.com') continue
|
|
492
|
+
cnt++
|
|
493
|
+
|
|
494
|
+
|
|
395
495
|
// detect IDN domains
|
|
496
|
+
let time0 = Date.now()
|
|
396
497
|
let pc = punycode.toASCII(row.domain)
|
|
397
|
-
if (pc!==row.domain) {
|
|
498
|
+
if (pc !== row.domain) {
|
|
398
499
|
console.log(`IDN Domain found: ${row.domain} provider: ${row.provider}`)
|
|
399
500
|
row.unicodeDomain = row.domain
|
|
400
501
|
row.domain = pc
|
|
401
502
|
}
|
|
503
|
+
profile.punycode += Date.now() - time0
|
|
402
504
|
|
|
403
|
-
|
|
404
|
-
|
|
505
|
+
time0 = Date.now()
|
|
506
|
+
if (Math.random() * 500 < 1) {
|
|
507
|
+
await wait(1 / 10000)
|
|
508
|
+
progress.setTick(cnt)
|
|
509
|
+
// if (cnt>100000) break
|
|
510
|
+
}
|
|
511
|
+
profile.progressbar += Date.now() - time0
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
// parse domains with psl
|
|
515
|
+
time0 = Date.now()
|
|
405
516
|
let hostname = row.domain.toLowerCase()
|
|
517
|
+
let domainparse
|
|
406
518
|
// parse domains with psl
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
519
|
+
if (domainparse_cache.hasOwnProperty(hostname)) {
|
|
520
|
+
domainparse = domainparse_cache[hostname]
|
|
521
|
+
} else {
|
|
522
|
+
domainparse = psl.parse(hostname)
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (!domainparse || !domainparse?.domain) {
|
|
526
|
+
console.log(`Not parseable hostname : ${hostname} - detected id: ${row.id} - provider: ${row.provider} - ${chalk.red('deleting')}`)
|
|
527
|
+
try { await vars.models.Harvested.destroy({ where: { id: row.id } }) } catch (_) { } // DELETE
|
|
410
528
|
continue
|
|
411
529
|
}
|
|
530
|
+
domainparse_cache[hostname] = domainparse
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
|
|
412
534
|
// lets take the domain of the hostname
|
|
413
535
|
let domain = domainparse.domain
|
|
414
|
-
let domain_pc = punycode.toASCII(domain)
|
|
536
|
+
// let domain_pc = punycode.toASCII(domain)
|
|
537
|
+
profile.domainparse += Date.now() - time0
|
|
415
538
|
|
|
416
539
|
// not listed tld found, not listed tlds are made up ones
|
|
417
540
|
if (!domainparse.listed) {
|
|
418
541
|
console.log(`Not listed TLD: ${domain} - detected id: ${row.id} - provider: ${row.provider} `)
|
|
419
542
|
// what to do with those
|
|
420
543
|
}
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
|
|
421
547
|
// ignore whitelisted domains
|
|
548
|
+
time0 = Date.now()
|
|
422
549
|
if (vars.config.ignore_domains.includes(domain)) {
|
|
423
550
|
try { await vars.models.Harvested.destroy({ where: { id: row.id } }) } catch (_) { } // DELETE
|
|
424
551
|
console.log(chalk.red(`Ignoring whitelisted domain:${domain} at row: ${row.id} provider:${row.provider} - DELETED`))
|
|
425
552
|
continue
|
|
426
553
|
}
|
|
554
|
+
profile.whitelistcheck += Date.now() - time0
|
|
555
|
+
|
|
427
556
|
|
|
428
557
|
// make sure email address is valid by validator library
|
|
558
|
+
time0 = Date.now()
|
|
429
559
|
if (!isEmail(`any@${domain}`)) {
|
|
430
560
|
try { await vars.models.Harvested.destroy({ where: { id: row.id } }) } catch (_) { } // DELETE
|
|
431
561
|
console.log(`Invalid domain: ${domain} - detected id: ${row.id} - DELETED`)
|
|
432
562
|
continue
|
|
433
563
|
}
|
|
564
|
+
profile.emailvalidation += Date.now() - time0
|
|
434
565
|
|
|
435
566
|
// create the provider
|
|
436
567
|
if (!result.hasOwnProperty(row.provider)) result[row.provider] = {}
|
|
437
|
-
|
|
568
|
+
|
|
438
569
|
// create the domain inside provider
|
|
439
570
|
if (!result[row.provider].hasOwnProperty(domain))
|
|
440
571
|
result[row.provider][domain] = {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (!result[row.provider][domain].hosts.hasOwnProperty(hostname))
|
|
448
|
-
result[row.provider][domain].hosts[hostname]={
|
|
572
|
+
// domain level firstseen & lastseen
|
|
573
|
+
firstseen: 5645821813648,
|
|
574
|
+
lastseen: 0,
|
|
575
|
+
|
|
576
|
+
hosts: {
|
|
577
|
+
[hostname]: {
|
|
449
578
|
firstseen: 5645821813648,
|
|
450
579
|
lastseen: 0,
|
|
451
580
|
}
|
|
581
|
+
}
|
|
452
582
|
}
|
|
583
|
+
else {
|
|
584
|
+
if (!result[row.provider][domain].hosts.hasOwnProperty(hostname))
|
|
585
|
+
result[row.provider][domain].hosts[hostname] = {
|
|
586
|
+
firstseen: 5645821813648,
|
|
587
|
+
lastseen: 0,
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (row.unicodeDomain)
|
|
592
|
+
result[row.provider][domain].unicodeDomain = punycode.toUnicode(domain)
|
|
453
593
|
|
|
454
|
-
if (row.unicodeDomain)
|
|
455
|
-
result[row.provider][domain].unicodeDomain = punycode.toUnicode(domain)
|
|
456
|
-
|
|
457
|
-
// result[row.provider][domain].isSubdomain = domainparse.domain !== hostname ? true : false
|
|
458
|
-
// if (result[row.provider][domain].isSubdomain) {
|
|
459
|
-
// result[row.provider][domain].domain = domainparse.domain
|
|
460
|
-
// result[row.provider][domain].tld = domainparse.tld
|
|
461
|
-
// // console.log(`provider: ${row.provider} hostname:${hostname} - domain:${domainparse.domain}`)
|
|
462
|
-
// }
|
|
463
|
-
|
|
464
|
-
// let providerDetails = getProviderDetails(row.provider)
|
|
465
|
-
// if (providerDetails && providerDetails.randomSubdomain === true) result[row.provider][domain].randomSubdomain = true
|
|
466
594
|
let t = obfuscateTime ? obfuscatedTime(row.t) : row.t
|
|
467
|
-
|
|
595
|
+
|
|
596
|
+
// firstseen of domain
|
|
597
|
+
if (t < result[row.provider][domain].firstseen) result[row.provider][domain].firstseen = t
|
|
598
|
+
// lastseen update of domain
|
|
599
|
+
if (t > result[row.provider][domain].lastseen) result[row.provider][domain].lastseen = t
|
|
600
|
+
|
|
601
|
+
// firstseen of hostname
|
|
468
602
|
if (t < result[row.provider][domain].hosts[hostname].firstseen) result[row.provider][domain].hosts[hostname].firstseen = t
|
|
469
|
-
|
|
603
|
+
|
|
604
|
+
// lastseen update of hostname
|
|
470
605
|
if (t > result[row.provider][domain].hosts[hostname].lastseen) result[row.provider][domain].hosts[hostname].lastseen = t
|
|
471
606
|
}
|
|
472
|
-
|
|
607
|
+
profile.total = Date.now() - started
|
|
608
|
+
console.log(profile)
|
|
609
|
+
|
|
610
|
+
// routine to detect and remove expired domains from the results
|
|
611
|
+
// based on lastseen property
|
|
612
|
+
let expiredDomains = {
|
|
613
|
+
|
|
614
|
+
}
|
|
615
|
+
if (expiration_days > 0) {
|
|
616
|
+
for (let provider of Object.keys(result)) {
|
|
617
|
+
let inner = result[provider]
|
|
618
|
+
for (let domain of Object.keys(inner)) {
|
|
619
|
+
let inner2 = inner[domain]
|
|
620
|
+
if (!inner2?.lastseen || !inner2?.firstseen) {
|
|
621
|
+
console.log(chalk.red(`📌 domain without lastseen or firstseen: ${domain} - provider: ${provider}`))
|
|
622
|
+
continue
|
|
623
|
+
}
|
|
624
|
+
// we check domain level expiration
|
|
625
|
+
// for now expiration implementation rudimentary
|
|
626
|
+
let lastseenDaysAgo = Math.round((utcnow() - inner2.lastseen) / 60 / 60 / 24)
|
|
627
|
+
if (lastseenDaysAgo > expiration_days) {
|
|
628
|
+
if (!expiredDomains.hasOwnProperty(domain)) expiredDomains[domain] = {}
|
|
629
|
+
if (!expiredDomains[domain].hasOwnProperty(provider)) expiredDomains[domain][provider] = {
|
|
630
|
+
firstseen: inner2.firstseen,
|
|
631
|
+
lastseen: inner2.lastseen,
|
|
632
|
+
}
|
|
633
|
+
result[provider][domain].expired = true
|
|
634
|
+
|
|
635
|
+
// console.log(`expired domain: ${chalk.yellow(domain)} @ ${chalk.blue(provider)} - firstseen: ${new Date(inner2.firstseen * 1000).toISOString()} - lastseen: ${new Date(inner2.lastseen * 1000).toISOString()} (${lastseenDaysAgo} days ago)`)
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
progress.finish()
|
|
643
|
+
console.log(`✅ finished ${rows.length} rows, took ${(Math.floor(Date.now() - started) / 1000)} seconds`)
|
|
644
|
+
console.log(`✅ expired domains: ${Object.keys(expiredDomains).length}`)
|
|
645
|
+
return resolve([result, expiredDomains])
|
|
473
646
|
})
|
|
474
647
|
}
|
|
475
648
|
|
|
@@ -532,11 +705,13 @@ module.exports = {
|
|
|
532
705
|
|
|
533
706
|
|
|
534
707
|
emailBy_id_innerText,
|
|
708
|
+
emailBy_id_value,
|
|
709
|
+
|
|
535
710
|
emailBy_querySelector_innerHTML,
|
|
536
711
|
emailBy_querySelector_innerText,
|
|
537
712
|
emailBy_querySelector_placeholder,
|
|
538
713
|
emailBy_querySelector_value,
|
|
539
|
-
|
|
714
|
+
|
|
540
715
|
|
|
541
716
|
emailFrom_combobox_id,
|
|
542
717
|
emailFrom_combobox_selector,
|
|
@@ -555,5 +730,7 @@ module.exports = {
|
|
|
555
730
|
obfuscatedTime,
|
|
556
731
|
domainFromEmail,
|
|
557
732
|
eventsOfProvider,
|
|
558
|
-
is_domain_banned
|
|
733
|
+
is_domain_banned,
|
|
734
|
+
email_recursive_search,
|
|
735
|
+
clickto_element_withText
|
|
559
736
|
}
|
package/update-repo.sh
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
source /opt/coadmin-peer/inc/shared.sh
|
|
2
3
|
optstring=":v"
|
|
3
4
|
verbose=
|
|
4
5
|
while getopts ${optstring} arg; do
|
|
@@ -7,25 +8,11 @@ while getopts ${optstring} arg; do
|
|
|
7
8
|
esac
|
|
8
9
|
done
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
test -e /opt/coadmin-peer/tools/report_test.js && {
|
|
15
|
-
test -z $verbose || echo "✅ $id"
|
|
16
|
-
node /opt/coadmin-peer/tools/report_test.js --project 'fakefilter' --group 'update-repo.sh' --id "$id" --result "ok" --details "$details"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
11
|
+
pkill -f repo-update.js
|
|
12
|
+
pkill -f chart-update.js
|
|
13
|
+
pkill -f repo-update.js
|
|
14
|
+
pkill -f chart-update.js
|
|
19
15
|
|
|
20
|
-
report_test_error() {
|
|
21
|
-
local id="$1"
|
|
22
|
-
local details="$2"
|
|
23
|
-
test -z $2 && details="-"
|
|
24
|
-
test -e /opt/coadmin-peer/tools/report_test.js && {
|
|
25
|
-
test -z $verbose || echo "❌ $id"
|
|
26
|
-
node /opt/coadmin-peer/tools/report_test.js --project 'fakefilter' --group 'update-repo.sh' --id "$id" --result "error" --details "$details"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
16
|
|
|
30
17
|
cd /opt/fakefilter && {
|
|
31
18
|
node chart-update.js
|
|
@@ -33,7 +20,7 @@ cd /opt/fakefilter && {
|
|
|
33
20
|
if cd repo/; then
|
|
34
21
|
# git add assets/img/*.png
|
|
35
22
|
report_test_ok "repo folder exists"
|
|
36
|
-
if ./release.sh 'auto update'
|
|
23
|
+
if ./release.sh 'auto update'; then
|
|
37
24
|
report_test_ok "npm published"
|
|
38
25
|
else
|
|
39
26
|
report_test_error "npm published"
|