From 358b4bbf8fc7474271c882e078ea9e6c8aef352a Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Thu, 25 Mar 2021 14:31:29 +0100 Subject: [PATCH] Add fetcher functions --- src/fetcher/dns.js | 34 +++++++++++++++ src/fetcher/index.js | 20 +++++++++ src/fetcher/irc.js | 47 ++++++++++++++++++++ src/fetcher/matrix.js | 34 +++++++++++++++ src/fetcher/twitter.js | 37 ++++++++++++++++ src/fetcher/xmpp.js | 97 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 269 insertions(+) create mode 100644 src/fetcher/dns.js create mode 100644 src/fetcher/index.js create mode 100644 src/fetcher/irc.js create mode 100644 src/fetcher/matrix.js create mode 100644 src/fetcher/twitter.js create mode 100644 src/fetcher/xmpp.js diff --git a/src/fetcher/dns.js b/src/fetcher/dns.js new file mode 100644 index 0000000..c6afc8b --- /dev/null +++ b/src/fetcher/dns.js @@ -0,0 +1,34 @@ +/* +Copyright 2021 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const dns = require('dns') + +module.exports = async (hostname) => { + return new Promise((resolve, reject) => { + dns.resolveTxt(hostname, (err, records) => { + if (err) { + reject(err) + return + } + + resolve({ + hostname: hostname, + records: { + txt: records, + }, + }) + }) + }) +} \ No newline at end of file diff --git a/src/fetcher/index.js b/src/fetcher/index.js new file mode 100644 index 0000000..9761ac7 --- /dev/null +++ b/src/fetcher/index.js @@ -0,0 +1,20 @@ +/* +Copyright 2021 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +exports.dns = require('./dns') +exports.irc = require('./irc') +exports.matrix = require('./matrix') +exports.twitter = require('./twitter') +exports.xmpp = require('./xmpp') \ No newline at end of file diff --git a/src/fetcher/irc.js b/src/fetcher/irc.js new file mode 100644 index 0000000..836a962 --- /dev/null +++ b/src/fetcher/irc.js @@ -0,0 +1,47 @@ +/* +Copyright 2021 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const irc = require('irc-upd') + +module.exports = async (serverHostname, nickQuery, nickLogin) => { + return new Promise((resolve, reject) => { + try { + const client = new irc.Client(serverHostname, nickLogin, { + port: 6697, + secure: true, + channels: [], + }) + const reKey = /[a-zA-Z0-9\-\_]+\s+:\s(openpgp4fpr\:.*)/ + const reEnd = /End\sof\s.*\staxonomy./ + let keys = [] + + client.addListener('registered', (message) => { + client.send(`PRIVMSG NickServ :TAXONOMY ${nickQuery}`) + }) + client.addListener('notice', (nick, to, text, message) => { + if (reKey.test(text)) { + const match = text.match(reKey) + keys.push(match[1]) + } + if (reEnd.test(text)) { + client.disconnect() + resolve(keys) + } + }) + } catch (error) { + reject(error) + } + }) +} \ No newline at end of file diff --git a/src/fetcher/matrix.js b/src/fetcher/matrix.js new file mode 100644 index 0000000..25caf7d --- /dev/null +++ b/src/fetcher/matrix.js @@ -0,0 +1,34 @@ +/* +Copyright 2021 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const bent = require('bent') +const bentReq = bent('GET') + +module.exports = async (roomId, eventId, opts) => { + const url = `https://${opts.instance}/_matrix/client/r0/rooms/${roomId}/event/${eventId}?access_token=${opts.accessToken}` + + return bentReq(url, null, { + Accept: 'application/json', + }) + .then(async (data) => { + return await data.json() + }) + .then((data) => { + return data + }) + .catch((error) => { + return error + }) +} \ No newline at end of file diff --git a/src/fetcher/twitter.js b/src/fetcher/twitter.js new file mode 100644 index 0000000..f21ace7 --- /dev/null +++ b/src/fetcher/twitter.js @@ -0,0 +1,37 @@ +/* +Copyright 2021 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const bent = require('bent') +const bentReq = bent('GET') + +module.exports = async (tweetId, bearerToken) => { + return bentReq( + `https://api.twitter.com/1.1/statuses/show.json?id=${tweetId}&tweet_mode=extended`, + null, + { + Accept: 'application/json', + Authorization: `Bearer ${bearerToken}`, + } + ) + .then(async (data) => { + return await data.json() + }) + .then((data) => { + return data.full_text + }) + .catch((error) => { + return error + }) +} \ No newline at end of file diff --git a/src/fetcher/xmpp.js b/src/fetcher/xmpp.js new file mode 100644 index 0000000..4eb92b2 --- /dev/null +++ b/src/fetcher/xmpp.js @@ -0,0 +1,97 @@ +/* +Copyright 2021 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const jsdom = require('jsdom') +const { client, xml } = require('@xmpp/client') +const debug = require('@xmpp/debug') + +let xmpp = null, + iqCaller = null + +const xmppStart = async (service, username, password) => { + return new Promise((resolve, reject) => { + const xmpp = client({ + service: service, + username: username, + password: password, + }) + if (process.env.NODE_ENV !== 'production') { + debug(xmpp, true) + } + const { iqCaller } = xmpp + xmpp.start() + xmpp.on('online', (address) => { + console.log('online', address.toString()) + resolve({ xmpp: xmpp, iqCaller: iqCaller }) + }) + xmpp.on('error', (error) => { + reject(error) + }) + }) +} + +module.exports = async (id, data, opts) => { + return new Promise(async (resolve, reject) => { + if (!xmpp) { + const xmppStartRes = await xmppStart( + opts.service, + opts.username, + opts.password + ) + xmpp = xmppStartRes.xmpp + iqCaller = xmppStartRes.iqCaller + } + + const response = await iqCaller.request( + xml( + 'iq', + { type: 'get', to: id }, + xml('vCard', 'vcard-temp') + ), + 30 * 1000 + ) + + const vcardRow = response.getChild('vCard', 'vcard-temp').toString() + const dom = new jsdom.JSDOM(vcardRow) + + try { + let vcard + + switch (data.toLowerCase()) { + case 'desc': + case 'note': + vcard = dom.window.document.querySelector('note text') + if (!vcard) { + vcard = dom.window.document.querySelector('DESC') + } + if (vcard) { + vcard = vcard.textContent + } else { + throw new Error('No DESC or NOTE field found in vCard') + } + break + + default: + vcard = dom.window.document.querySelector(data) + .textContent + break + } + xmpp.stop() + resolve(vcard) + } catch (error) { + reject(error) + } + }) +} \ No newline at end of file