diff --git a/src/bot.js b/src/bot.js index 383671b..00d8b2f 100644 --- a/src/bot.js +++ b/src/bot.js @@ -3,6 +3,8 @@ import striptags from 'striptags' import pull from 'pull-stream' import toPull from 'stream-to-pull-stream' import request from 'request' +import commandFilter from './commandFilter' +import decodePrivate from './decodePrivate' function setCallbackTimeout(cb, onTimeout, waitingTime = 5000) { const checker = setTimeout(onTimeout, waitingTime) @@ -25,6 +27,7 @@ Link: [{link}]({link}) export default config => (err, sbot) => { if (err) throw err const { feedMonitor, feedUrls, postTemplate = defaultPostTemplate } = config; + let id, userStream; const createFeedMonitor = feedMonitor.create; const onPostPublished = (err, msg) => { @@ -122,10 +125,22 @@ export default config => (err, sbot) => { ) } + const onSbotCommand = (data) => { + return true + } + const onSbotConnect = (_, keys) => { + id = keys.id + userStream = sbot.createUserStream({ live: true, id }) + pull( + userStream, + pull.asyncMap(decodePrivate(sbot)), + pull.filter(commandFilter), + pull.take(onSbotCommand) + ) console.log( 'feedMonitor user ID:', - keys.id + id ) } diff --git a/src/bot.test.js b/src/bot.test.js index 14ad945..290a17b 100644 --- a/src/bot.test.js +++ b/src/bot.test.js @@ -386,4 +386,40 @@ test('publish a post using template on sbot', t => { } bot(config)(null, sbot) }); +}) + +test.skip('deny when a non-admin tries to add a feed', async t => { + t.plan(5) + const fakeId = '@fakeId' + const fakePost = { + key: '%someKey', + content: 'Pl**eas****e add feed ht****t***ps*:**/**/*ww*w.feedfo***ral***l.com/samp****le.*xml' + } + const createUserStream = ({ live, id }) => { + t.is(live, true) + t.is(id, fakeId) + return pull.values([fakePost]) + } + const whoami = cb => cb(null, { id: fakeId }) + const feedMonitor = { + create() { }, + destroy() { }, + } + const config = { + feedMonitor, + feedUrls: [], + } + const publish = (post) => { + t.is(post.type, 'post') + t.is(post.text, 'Sorry, you\'re not allowed to do this') + } + return new Promise((resolve) => { + const unbox = (cypher, cb) => { + t.is(cypher, fakePost.content) + resolve(); + cb(null, cypher.replaceAll(/\*/g, '')) + } + const sbot = { publish, unbox, createUserStream, whoami } + bot(config)(null, sbot) + }); }) \ No newline at end of file diff --git a/src/commandFilter.js b/src/commandFilter.js new file mode 100644 index 0000000..7652c2d --- /dev/null +++ b/src/commandFilter.js @@ -0,0 +1,18 @@ +export const commands = [ + 'add', + 'delete', + 'remove' +] + +function toRegex(commands) { + return commands.join('|') +} + +export default function commandFilter(data) { + const regex = new RegExp(toRegex(commands)) + return ( + data && + data.content && + data.content.match(regex) + ) +} \ No newline at end of file diff --git a/src/commandFilter.test.js b/src/commandFilter.test.js new file mode 100644 index 0000000..233cb34 --- /dev/null +++ b/src/commandFilter.test.js @@ -0,0 +1,34 @@ +import test from "ava" +import pull from 'pull-stream' +import commandFilter from './commandFilter' + +function doCommandTest(content, result, t) { + return new Promise((resolve) => { + const mock = { content } + const onResult = (e, res) => { + t.is(result, res.length) + resolve(); + } + pull( + pull.values([mock]), + pull.filter(commandFilter), + pull.collect(onResult) + ) + }); +} + +test('commandFilter ignore no related msgs', (t) => { + return doCommandTest('foo bar', 0, t) +}) + +test('commandFilter filter valid add', (t) => { + return doCommandTest('add http://foobar', 1, t) +}) + +test('commandFilter filter valid delete', (t) => { + return doCommandTest('delete http://foobar', 1, t) +}) + +test('commandFilter filter valid remove', (t) => { + return doCommandTest('remove http://foobar', 1, t) +}) diff --git a/src/decodePrivate.js b/src/decodePrivate.js new file mode 100644 index 0000000..ba944ec --- /dev/null +++ b/src/decodePrivate.js @@ -0,0 +1,15 @@ +export default (sbot) => (data, cb) => { + if (typeof data.content === 'string') { + sbot.unbox(data.content, (err, unboxed) => { + cb( + err, + { + ...data, + content: unboxed + } + ) + }) + } else { + cb(null, data) + } +} \ No newline at end of file diff --git a/src/decodePrivate.test.js b/src/decodePrivate.test.js new file mode 100644 index 0000000..d467b3f --- /dev/null +++ b/src/decodePrivate.test.js @@ -0,0 +1,45 @@ +import test from "ava" +import decodePrivate from './decodePrivate.js' + +function uncrypt(data) { + return data.replace(/\*/g, '') +} + +test('ignore not encrypted msgs', (t) => { + const data = { + content: {} + } + return new Promise((resolve) => { + const done = (err, d) => { + t.is(null, err) + t.is(data, d) + resolve(); + } + const sbot = {} + decodePrivate(sbot)(data, done) + }); +}) + +test('decode encrypted msgs', (t) => { + t.plan(3) + const data = { + content: "e*n*cry**p*t*e*dmsg" + } + const sbot = { + unbox(cypher, cb) { + t.is(cypher, data.content) + cb(null, { text: uncrypt(cypher) }) + } + } + return new Promise((resolve) => { + const done = (err, d) => { + t.is(err, null) + t.is( + d.content.text, + uncrypt(data.content) + ) + resolve() + } + decodePrivate(sbot)(data, done) + }); +}) \ No newline at end of file