2024-09-15 17:44:53 +00:00
|
|
|
let servers
|
|
|
|
module.exports = async (client, apex, app) => {
|
|
|
|
const util = require('./util')(apex),
|
|
|
|
constant = require('./constant'),
|
|
|
|
schedule = require('node-schedule'),
|
|
|
|
workers = constant.workers,
|
|
|
|
getAccount = api => {
|
|
|
|
if (api && api.contact_account.acct) {
|
|
|
|
const acct = api.contact_account.acct.split('@')
|
|
|
|
if (acct.length > 1) {
|
|
|
|
return `https://${acct[1]}/users/${acct[0]}`
|
|
|
|
} else {
|
|
|
|
return `https://${api.uri.replace(/https?:\/\//, '')}/users/${acct.join('')}`
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return ''
|
|
|
|
}
|
|
|
|
},
|
|
|
|
requestPart = async uri => {
|
2024-09-25 23:30:49 +00:00
|
|
|
const ac = new AbortController(),
|
|
|
|
timeout = setTimeout(() => {
|
2024-09-29 08:14:03 +00:00
|
|
|
setImmediate(() => ac.abort())
|
2024-10-05 22:37:12 +00:00
|
|
|
}, constant.abort_timeout)
|
|
|
|
try {
|
|
|
|
const response = await fetch(uri, {
|
2024-09-26 00:23:49 +00:00
|
|
|
headers: { 'User-Agent': constant.agent },
|
|
|
|
signal: ac.signal,
|
|
|
|
keepalive: false,
|
|
|
|
timeout: constant.timeout,
|
2024-10-08 15:05:30 +00:00
|
|
|
cache: 'no-cache',
|
|
|
|
mode: 'same-origin',
|
|
|
|
priority: 'high',
|
|
|
|
redirect: 'follow'
|
2024-09-26 00:23:49 +00:00
|
|
|
})
|
2024-10-05 22:37:12 +00:00
|
|
|
setImmediate(() => clearTimeout(timeout))
|
2024-11-10 10:51:12 +00:00
|
|
|
return await response.json()
|
2024-10-05 22:37:12 +00:00
|
|
|
} catch (e) {
|
2024-11-10 10:53:58 +00:00
|
|
|
setImmediate(() => {
|
2024-10-05 22:37:12 +00:00
|
|
|
clearTimeout(timeout)
|
|
|
|
ac.abort()
|
|
|
|
})
|
2024-11-10 10:53:58 +00:00
|
|
|
return
|
2024-10-05 22:37:12 +00:00
|
|
|
// console.error(e)
|
|
|
|
}
|
2024-09-15 17:44:53 +00:00
|
|
|
},
|
|
|
|
scanInstance = async instance => {
|
2024-09-23 22:28:58 +00:00
|
|
|
const json = await requestPart(`https://${instance}/api/v1/instance/domain_blocks`)
|
|
|
|
if (Array.isArray(json) && json.length > 0) {
|
|
|
|
const result = await client.search({
|
|
|
|
index: constant.index,
|
|
|
|
size: 1,
|
|
|
|
query: {
|
|
|
|
term: {
|
|
|
|
instance: instance
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
instancelocated = result.hits && result.hits.hits ? result.hits.hits : [],
|
|
|
|
blocks = json.map(block => {
|
|
|
|
if (block.comment && block.comment.length > 8190) {
|
|
|
|
block.comment = block.comment.slice(0, 8190)
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
2024-09-23 22:28:58 +00:00
|
|
|
return block
|
2024-09-15 17:44:53 +00:00
|
|
|
}),
|
2024-09-23 22:28:58 +00:00
|
|
|
[api, nodeinfo, peers] = await Promise.all([
|
|
|
|
requestPart(`https://${instance}/api/v1/instance`),
|
|
|
|
requestPart(`https://${instance}/nodeinfo/2.0`),
|
|
|
|
requestPart(`https://${instance}/api/v1/instance/peers`)
|
|
|
|
])
|
|
|
|
if (instancelocated.length === 0) {
|
|
|
|
await client.index({
|
|
|
|
index: constant.index,
|
|
|
|
body: {
|
|
|
|
instance,
|
|
|
|
api,
|
|
|
|
nodeinfo,
|
|
|
|
blocks,
|
|
|
|
peers,
|
|
|
|
last: new Date()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
app.locals.created++
|
2024-11-10 10:51:12 +00:00
|
|
|
return await util.sendFederatedMessage(constant.nick, 'New Fediblock Instance', `Fediblock Instance ${instance} with ${json.length} blocks - https://${constant.apexdomain}#${instance}`, getAccount(api))
|
2024-09-23 22:28:58 +00:00
|
|
|
} else {
|
|
|
|
const elasticinstance = instancelocated[0]._source.blocks || []
|
|
|
|
if (Array.isArray(elasticinstance)) {
|
|
|
|
if (json.length !== elasticinstance.length
|
|
|
|
|| (instancelocated[0]._source.last && instancelocated[0]._source.last < new Date(Date.now() - 2678400000))
|
|
|
|
|| !instancelocated[0]._source.api
|
|
|
|
|| !instancelocated[0]._source.nodeinfo
|
|
|
|
|| !instancelocated[0]._source.peers) {
|
|
|
|
await client.update({
|
2024-09-21 01:07:51 +00:00
|
|
|
index: constant.index,
|
2024-09-23 22:28:58 +00:00
|
|
|
id: instancelocated[0]._id,
|
|
|
|
doc: {
|
|
|
|
api: api ? api : instancelocated[0]._source.api,
|
|
|
|
nodeinfo: nodeinfo ? nodeinfo : instancelocated[0]._source.nodeinfo,
|
|
|
|
blocks: blocks && blocks.length > 0 ? blocks : elasticinstance,
|
|
|
|
peers: peers && peers.length > 0 ? peers : instancelocated[0]._source.peers,
|
2024-09-21 01:07:51 +00:00
|
|
|
last: new Date()
|
2024-09-23 22:28:58 +00:00
|
|
|
},
|
|
|
|
doc_as_upsert: true
|
2024-09-21 01:07:51 +00:00
|
|
|
})
|
2024-09-23 22:28:58 +00:00
|
|
|
app.locals.updated++
|
|
|
|
if (instancelocated[0]._source.api && instancelocated[0]._source.api.uri && instancelocated[0]._source.api.contact_account && instancelocated[0]._source.api.contact_account.acct) {
|
|
|
|
const difference = blocks.filter(block => block.domain && block.domain.trim().length > 0 && !elasticinstance.some(instance => block.domain === instance.domain))
|
|
|
|
if (difference.length > 0 && difference.length < 50) {
|
2024-11-10 10:51:12 +00:00
|
|
|
return await util.sendFederatedMessage(constant.nick, 'Detected #Fediblock by Fediblock Instance', `You blocked new instances: ${difference.map(d => d.domain).join(', ')} - https://${constant.apexdomain}#${instance}`, getAccount(instancelocated[0]._source.api))
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2024-09-21 01:07:51 +00:00
|
|
|
scanPart = async function* (instancesall, index) {
|
|
|
|
try {
|
|
|
|
for (const instance of instancesall) {
|
|
|
|
try {
|
|
|
|
app.locals.scan.emit('data', 'data: ' + (app.locals.scannum > 0 ? '(' + app.locals.scannum-- + ':' + (index + 1) + '): ' + instance : ': ' + instance) + '\n\n')
|
|
|
|
app.locals.peers++
|
|
|
|
await scanInstance(instance)
|
|
|
|
} catch (e) {
|
2024-10-08 15:05:30 +00:00
|
|
|
console.error('Index ' + index + ':' + instance + ': ' + e)
|
2024-09-21 01:07:51 +00:00
|
|
|
}
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
2024-09-21 01:07:51 +00:00
|
|
|
yield 0
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e)
|
|
|
|
yield 1
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
scanIndex = async (server, instancesall) => {
|
2024-09-23 22:28:58 +00:00
|
|
|
const [api, nodeinfo, blocks] = await Promise.all([
|
|
|
|
requestPart(`https://${server}/api/v1/instance`),
|
|
|
|
requestPart(`https://${server}/nodeinfo/2.0`),
|
|
|
|
requestPart(`https://${server}/api/v1/instance/domain_blocks`)
|
|
|
|
])
|
|
|
|
if (api && typeof api === 'object' && api.version) {
|
|
|
|
const result = await client.search({
|
|
|
|
index: constant.index,
|
|
|
|
size: 1,
|
|
|
|
query: {
|
|
|
|
term: {
|
|
|
|
instance: server
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
instancelocated = result.hits && result.hits.hits ? result.hits.hits : []
|
|
|
|
if (instancelocated.length === 0) {
|
|
|
|
await client.index({
|
2024-09-15 17:44:53 +00:00
|
|
|
index: constant.index,
|
2024-09-23 22:28:58 +00:00
|
|
|
body: {
|
|
|
|
instance: server,
|
|
|
|
peers: instancesall,
|
|
|
|
api,
|
|
|
|
nodeinfo,
|
|
|
|
blocks: blocks && blocks.length > 0 ? blocks : [],
|
|
|
|
last: new Date()
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
2024-09-23 22:28:58 +00:00
|
|
|
})
|
|
|
|
app.locals.created++
|
|
|
|
} else {
|
|
|
|
const elasticinstance = instancelocated[0]._source.peers || []
|
|
|
|
if (Array.isArray(elasticinstance) && Array.isArray(instancesall) && instancesall.length > 0) {
|
|
|
|
if (instancesall.length !== elasticinstance.filter(i => !constant.filterdomains.some(d => i.endsWith(d))).length) {
|
|
|
|
await client.update({
|
|
|
|
index: constant.index,
|
|
|
|
id: instancelocated[0]._id,
|
|
|
|
doc: {
|
|
|
|
peers: instancesall.length > 0 ? instancesall : elasticinstance,
|
|
|
|
api: api ? api : instancelocated[0]._source.api,
|
|
|
|
nodeinfo: nodeinfo ? nodeinfo : instancelocated[0]._source.nodeinfo,
|
|
|
|
blocks: blocks && blocks.length > 0 ? blocks : instancelocated[0]._source.blocks,
|
|
|
|
last: new Date()
|
|
|
|
},
|
|
|
|
doc_as_upsert: true
|
|
|
|
})
|
|
|
|
app.locals.updated++
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
scanReturn = async () => {
|
|
|
|
app.locals.scannum = 0
|
2024-10-14 18:13:12 +00:00
|
|
|
if (servers?.length > 0) {
|
|
|
|
await scan(servers.shift())
|
2024-09-15 17:44:53 +00:00
|
|
|
} else {
|
2024-10-14 18:13:12 +00:00
|
|
|
await scan(constant.initialscan)
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
scan = async server => {
|
|
|
|
if (server) {
|
|
|
|
try {
|
|
|
|
console.log(server)
|
|
|
|
app.locals.scan.emit('data', 'data: ' + server + ' peers...\n\n')
|
|
|
|
const instances = await requestPart(`https://${server}/api/v1/instance/peers`),
|
|
|
|
instancesall = Array.isArray(instances) && instances.length > 0
|
|
|
|
? instances.filter(i => !constant.filterdomains.some(d => i.endsWith(d)))
|
|
|
|
: [],
|
|
|
|
instancessorted = instancesall.sort((a, b) => a < b ? -1 : a > b ? 1 : 0),
|
|
|
|
parts = [],
|
|
|
|
split = workers,
|
2024-09-20 00:44:59 +00:00
|
|
|
chunkSize = Math.ceil(instancessorted.length / split)
|
2024-09-15 17:44:53 +00:00
|
|
|
await scanIndex(server, instancesall)
|
|
|
|
if (instancesall.length > 0) {
|
|
|
|
if (!servers || servers.length === 0) {
|
|
|
|
servers = instancesall.sort(() => Math.random() - 0.5)
|
|
|
|
}
|
2024-09-23 22:28:58 +00:00
|
|
|
if (server === constant.initialscan) {
|
2024-09-15 17:44:53 +00:00
|
|
|
return await scan(servers.shift())
|
|
|
|
}
|
|
|
|
app.locals.scannum = instancessorted.length
|
|
|
|
app.locals.scantotal = instancessorted.length
|
|
|
|
app.locals.server = server
|
|
|
|
app.locals.instances++
|
|
|
|
for (let i = 0; i < instancessorted.length; i += chunkSize) {
|
|
|
|
const chunk = instancessorted.slice(i, i + chunkSize)
|
|
|
|
parts.push(chunk)
|
|
|
|
}
|
2024-09-21 01:07:51 +00:00
|
|
|
await Promise.all(parts.map(async (p, i) => {
|
|
|
|
for await (const exit of scanPart(p, i)) {
|
|
|
|
console.log('Done: ' + server + ' - ' + i + ' parts with exit ' + exit + '.')
|
|
|
|
}
|
|
|
|
}))
|
2024-11-10 10:51:12 +00:00
|
|
|
return await scanReturn()
|
2024-09-15 17:44:53 +00:00
|
|
|
} else {
|
2024-11-10 10:51:12 +00:00
|
|
|
return await scanReturn()
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
|
|
|
} catch (e) {
|
2024-09-23 22:28:58 +00:00
|
|
|
// console.error(e)
|
2024-11-10 10:51:12 +00:00
|
|
|
return await scanReturn()
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
|
|
|
} else {
|
2024-11-10 10:09:13 +00:00
|
|
|
return scanReturn()
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
job = schedule.scheduleJob('0 ' + constant.schedule + ' * * *', async () => {
|
2024-10-14 18:13:12 +00:00
|
|
|
await util.sendFederatedMessage(constant.nick, null, 'Scanning ' + app.locals.server + ' instance with ' + app.locals.scantotal + ' peers\nScanned ' + app.locals.peers + ' peers from ' + app.locals.instances + ' instances, ' + app.locals.created + ' created, ' + app.locals.updated + ' updated\nhttps://' + constant.apexdomain)
|
2024-09-15 17:44:53 +00:00
|
|
|
})
|
2024-11-10 10:09:13 +00:00
|
|
|
return scanReturn()
|
2024-09-15 17:44:53 +00:00
|
|
|
}
|