From b0df0addbf3781ee787a71458831d73684a1f7fc Mon Sep 17 00:00:00 2001 From: filipnyquist Date: Mon, 2 Jul 2018 15:43:16 +0200 Subject: [PATCH 1/4] Started work on the next version of tipbot. --- .gitignore | 91 ++- .prettierignore | 1 - LICENSE | 20 - README.md | 74 --- bin/tipbot.js | 325 ---------- config/config.sample.yml | 80 --- config/default.example.json | 13 + index.js | 209 ++++++ package-lock.json | 1198 ----------------------------------- package.json | 52 +- yarn.lock | 651 +++++++++++++++++++ 11 files changed, 958 insertions(+), 1756 deletions(-) delete mode 100644 .prettierignore delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 bin/tipbot.js delete mode 100644 config/config.sample.yml create mode 100644 config/default.example.json create mode 100644 index.js delete mode 100644 package-lock.json create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore index 7f3991e..76345ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1,76 @@ -# Created by http://www.gitignore.io - -### Node ### -lib-cov -lcov.info -*.seed -*.log -*.csv -*.dat -*.out -*.pid -*.gz - -pids +# Logs logs -results -build +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids +*.pid +*.seed +*.pid.lock +.idea/ +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt -node_modules -config/config.yml +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless + +# Configurations +default.json \ No newline at end of file diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 685b187..0000000 --- a/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -/lib/ \ No newline at end of file diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 3e2f8e0..0000000 --- a/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2014 unek - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -'Software'), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md deleted file mode 100644 index 27fb395..0000000 --- a/README.md +++ /dev/null @@ -1,74 +0,0 @@ -This is a fork of node-tip-bot-twitter, an open-source node.js twitter bot for tipping with altcoins. -In particular, this fork is for [LBC](https://lbry.io/). LBRY.io, the network behind it, describes -itself as: - -``` -...a free, open, and community-run digital marketplace. -You own your data. You control the network. Indeed, you are the network. -Hollywood films, college lessons, amazing streamers and more are on the first media network ruled by you. -``` - -If you want to get started with LBRY.io, go to https://lbry.io/get. If you wish to set up your own twitter -tip bot, it may be more beneficial to start with the [original node-tip-bot-twitter](https://github.com/gameunits/node-tip-bot-twitter). - -# Installation -To install node-tip-bot simply clone this repo and install dependencies: -```bash -git clone https://github.com/gameunits/node-tip-bot-twitter -cd node-tip-bot-twitter -npm install -``` -After installation proceed to the configuration. - -# Configuration -To configure, copy the `config/config.sample.yml` file to `config/config.yml`. - -## twitter -Create an application at dev.twitter.com and fill in your keys. -* **consumer_key: '' -* **consumer_secret: '' -* **access_token_key: '' -* **access_token_secret: '' - -## log -Logging settings. -* **file** - file to log to. Set to `false` to disable logging to file. - -## rpc -JSON RPC API connection info. -* **host** - JSON RPC API hostname -* **port** - API port (by default 1337) -* **user** - API username -* **pass** - API password (keep that secure) - -## coin -Basic coin settings. -* **withdrawal_fee** - fee charged on withdraw to cover up txfee, the rest goes to bot's wallet. -* **min_withdraw** - minimum amount of coins to withdraw -* **min_confirmations** - minimum amount of confirmations needed to tip/withdraw coins -* **min_tip** - minimum amount of coins to tip - -# How to run it? -Before running the bot, you have to be running your coin daemon with JSON-RPC API enabled. To enable, add this to your coin daemon configuration file (eg. `~/.gameunits/gameunits.conf`): -```ini -server=1 -daemon=1 -rpcuser= -rpcpassword= -rpcallowip= -``` -To run the bot simply use `node bin/tipbot` or `npm start`. - -## Commands -Commands are executed by placing gameunits in a tweet. - -| **Command** | **Arguments** | **Description** -|-------------|-------------------|-------------------------------------------------------------------- -| `balance` | | displays your current wallet balance -| `address` | | displays address where you can send your funds to the tip bot -| `withdraw` | `
` | withdraws your whole wallet balance to specified address -| `tip` | ` ` | sends the specified amount of coins to the specified nickname -| `help` | | displays configured help message (by default similiar to this one) -| `terms` | | displays terms and conditions for using the tip bot - - diff --git a/bin/tipbot.js b/bin/tipbot.js deleted file mode 100644 index 76d203c..0000000 --- a/bin/tipbot.js +++ /dev/null @@ -1,325 +0,0 @@ -const winston = require('winston'), - fs = require('fs'), - yaml = require('js-yaml'), - coind = require('node-gameunits'); - -const Twitter = require('twitter'); -// check if the config file exists -if (!fs.existsSync('./config/config.yml')) { - winston.error("Configuration file doesn't exist! Please read the README.md file first."); - process.exit(1); -} -// load settings -const settings = yaml.load(fs.readFileSync('./config/config.yml', 'utf-8')); -// load winston's cli defaults -winston.cli(); -// write logs to file -if (settings.log.file) { - winston.add(winston.transports.File, { - filename: settings.log.file, - level: 'debug' - }); -} -// connect to coin json-rpc -winston.info('Connecting to coind...'); -let coin = coind({ - host: settings.rpc.host, - port: settings.rpc.port, - user: settings.rpc.user, - pass: settings.rpc.pass -}); -// checking if we are connected. - -coin.getBalance(function (err, balance) { - if (err) { - winston.error('Could not connect to %s RPC API! ', settings.coin.full_name, err); - process.exit(1); - return; - } - var balance = typeof balance == 'object' ? balance.result : balance; - winston.info('Connected to JSON RPC API. Current total balance is %d' + settings.coin.short_name, balance); -}); - -// connect to twitter -winston.info('Connecting to Twitter'); -var client = new Twitter({ - consumer_key: settings.twitter.consumer_key, - consumer_secret: settings.twitter.consumer_secret, - access_token_key: settings.twitter.access_token_key, - access_token_secret: settings.twitter.access_token_secret -}); -// -client.get('followers/ids', function (error, tweets, response) { - if (error) { - console.log(error); - } - winston.info('Connected to Twitter. Followers:' + tweets.ids.length); -}); - -// basic handlers -var locks = []; - -function makeid() { - var text = ''; - var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; - for (var i = 0; i < 5; i++) text += possible.charAt(Math.floor(Math.random() * possible.length)); - return text; -} - -function replytweet(to, replyid, themessage) { - winston.info('Preparing tweet' + '@' + to + ' :' + themessage); - var newtweet = '@' + to + ' ' + themessage + ' \nMsg_ID:(' + makeid() + ')'; - winston.info('' + '@' + to + ' :' + newtweet); - client.post('statuses/update', { - status: newtweet, - in_reply_to_status_id: replyid - }, function (error, params, response) { - if (error) { - console.log(error); - //throw error; - } - - console.log('Tweeting'); - }); -} - -function getAddress(nickname, callback) { - winston.debug('Requesting address for %s', nickname); - coin.send('getaccountaddress', settings.rpc.prefix + nickname.toLowerCase(), function (err, address) { - if (err) { - winston.error('Something went wrong while getting address. ' + err); - callback(err); - return false; - } - callback(false, address); - }); -} - -String.prototype.expand = function (values) { - var global = { - nick: settings.twitter.twittername - }; - return this.replace(/%([a-zA-Z_]+)%/g, function (str, variable) { - return typeof values[variable] == 'undefined' ? (typeof settings.coin[variable] == 'undefined' ? (typeof global[variable] == 'undefined' ? str : global[variable]) : settings.coin[variable]) : values[variable]; - }); -}; -client.stream('statuses/filter', {track: settings.twitter.twitterkeyword}, function (stream) { - stream.on('error', function (error) { - winston.error('Something went wrong with the twitter streaming api.'); - winston.error(error); - }); - stream.on('end', function (reason) { - winston.error('Twitter streaming api failed with'); - winston.error(reason); - }); - stream.on('data', function (tweet) { - console.log('@' + tweet.user.screen_name + '|' + tweet.text); - if (tweet.text.substring(0, 2) === 'RT') { - console.log('Retweet Ingrored'); - return; - } - var regex = new RegExp('(' + settings.twitter.twitterkeyword + ')(\\s)([a-zA-Z]+)', 'i'); - var match = tweet.text.match(regex); - if (match == null) return; - var command = match[3]; - var from = tweet.user.screen_name; - var msg = tweet.txt; - var message = tweet.text; - var replyid = tweet.id_str; - - if (command == 'help' || command == 'terms') { - for (var i = 0; i < settings.messages[command].length; i++) { - replytweet(from, replyid, settings.messages[command][i].expand({})); - } - return; - } - - switch (command) { - case 'tip': - var regex = new RegExp('(' + settings.twitter.twitterkeyword + ')(\\s)([a-zA-Z]+)(\\s)(\\@)(.+)(\\s)(.+)', 'i'); //Uglyfix - var match = tweet.text.match(regex); - console.log('tip'); - console.log(match[0] + ',' + match[1] + ',' + match[2] + ',' + match[3] + ',' + match[4] + ',' + match[5] + ',' + match[6] + ',' + match[7] + ',' + match[8]); - if (match == null || match.length < 3) { - replytweet(from, replyid, 'Usage: nameofbot tip '); - return; - } - var to = match[6]; - var amount = Number(match[8]); - console.log('To:' + amount); - // lock - if (locks.hasOwnProperty(from.toLowerCase()) && locks[from.toLowerCase()]) return; - locks[from.toLowerCase()] = true; - - if (isNaN(amount)) { - locks[from.toLowerCase()] = null; - replytweet(from, replyid, settings.messages.invalid_amount.expand({name: from, amount: match[8]})); - return; - } - - if (to.toLowerCase() == from.toLowerCase()) { - locks[from.toLowerCase()] = null; - replytweet(from, replyid, settings.messages.tip_self.expand({name: from})); - return; - } - if (amount < settings.coin.min_tip) { - locks[from.toLowerCase()] = null; - replytweet(from, replyid, settings.messages.tip_too_small.expand({ - from: from, - to: to, - amount: amount - })); - return; - } - // check balance with min. 5 confirmations - coin.getBalance(settings.rpc.prefix + from.toLowerCase(), settings.coin.min_confirmations, function (err, balance) { - if (err) { - locks[from.toLowerCase()] = null; - winston.error('Error in tip command.', err); - - replytweet(from, replyid, settings.messages.error.expand({name: from})); - return; - } - var balance = typeof balance == 'object' ? balance.result : balance; - if (balance >= amount) { - coin.send('move', settings.rpc.prefix + from.toLowerCase(), settings.rpc.prefix + to.toLowerCase(), amount, function (err, reply) { - locks[from.toLowerCase()] = null; - if (err || !reply) { - winston.error('Error in tip command', err); - replytweet(from, replyid, settings.messages.error.expand({name: from})); - return; - } - winston.info('%s tipped %s %d%s', from, to, amount, settings.coin.short_name); - replytweet(from, replyid, settings.messages.tipped.expand({ - from: from, - to: to, - amount: amount - })); - }); - } else { - locks[from.toLowerCase()] = null; - winston.info('%s tried to tip %s %d, but has only %d', from, to, amount, balance); - replytweet(from, replyid, settings.messages.no_funds.expand({ - name: from, - balance: balance, - short: amount - balance, - amount: amount - })); - } - }); - break; - case 'deposit': - case 'address': - console.log('adress'); - var user = from.toLowerCase(); - getAddress(user, function (err, address) { - if (err) { - winston.error('Error in address command', err); - replytweet(from, replyid, settings.messages.error.expand({name: from})); - return; - } - replytweet(from, replyid, settings.messages.deposit_address.expand({name: user, address: address})); - }); - break; - case 'balance': - console.log('balance'); - var user = from.toLowerCase(); - coin.getBalance(settings.rpc.prefix + user, settings.coin.min_confirmations, function (err, balance) { - if (err) { - winston.error('Error in balance command', err); - replytweet(from, replyid, settings.messages.error.expand({name: from})); - return; - } - var balance = typeof balance == 'object' ? balance.result : balance; - coin.getBalance(settings.rpc.prefix + user, 0, function (err, unconfirmed_balance) { - if (err) { - winston.error('Error in balance command', err); - replytweet(from, replyid, settings.messages.balance.expand({balance: balance, name: user})); - return; - } - var unconfirmed_balance = typeof unconfirmed_balance == 'object' ? unconfirmed_balance.result : unconfirmed_balance; - replytweet(from, replyid, settings.messages.balance_unconfirmed.expand({ - balance: balance, - name: user, - unconfirmed: unconfirmed_balance - balance - })); - }); - }); - break; - case 'withdraw': - console.log('withdrawl'); - var user = from.toLowerCase(); - var match = message.match(/.?withdraw (\S+)$/); - if (match == null) { - replytweet(from, replyid, 'Usage: withdraw <' + settings.coin.full_name + ' address>'); - return; - } - var address = match[1]; - coin.validateAddress(address, function (err, reply) { - if (err) { - winston.error('Error in withdraw command', err); - replytweet(from, replyid, settings.messages.error.expand({name: from})); - return; - } - if (reply.isvalid) { - coin.getBalance(settings.rpc.prefix + from.toLowerCase(), settings.coin.min_confirmations, function (err, balance) { - if (err) { - winston.error('Error in withdraw command', err); - replytweet(from, replyid, settings.messages.error.expand({name: from})); - return; - } - var balance = typeof balance == 'object' ? balance.result : balance; - if (balance < settings.coin.min_withdraw) { - winston.warn('%s tried to withdraw %d, but min is set to %d', from, balance, settings.coin.min_withdraw); - replytweet(from, replyid, settings.messages.withdraw_too_small.expand({ - name: from, - balance: balance - })); - return; - } - coin.sendFrom(settings.rpc.prefix + from.toLowerCase(), address, balance - settings.coin.withdrawal_fee, function (err, reply) { - if (err) { - winston.error('Error in withdraw command', err); - replytweet(from, replyid, settings.messages.error.expand({name: from})); - return; - } - var values = { - name: from, - address: address, - balance: balance, - amount: balance - settings.coin.withdrawal_fee, - transaction: reply - }; - for (var i = 0; i < settings.messages.withdraw_success.length; i++) { - var msg = settings.messages.withdraw_success[i]; - replytweet(from, replyid, msg.expand(values)); - } - // transfer the rest (withdrawal fee - txfee) to bots wallet - coin.getBalance(settings.rpc.prefix + from.toLowerCase(), function (err, balance) { - if (err) { - winston.error('Something went wrong while transferring fees', err); - return; - } - var balance = typeof balance == 'object' ? balance.result : balance; - // moves the rest to bot's wallet - coin.move(settings.rpc.prefix + from.toLowerCase(), settings.rpc.prefix + settings.twitter.twittername.toLowerCase(), balance); - }); - }); - }); - } else { - winston.warn('%s tried to withdraw to an invalid address', from); - replytweet(from, replyid, settings.messages.invalid_address.expand({ - address: address, - name: from - })); - } - }); - break; - default: - winston.warn('Invalid Command' + command); - replytweet(from, replyid, 'Invalid command. Tweet "@LBC_TipBot lbryian help" for list of commands or see reply below'); - - break; - } - }); -}); diff --git a/config/config.sample.yml b/config/config.sample.yml deleted file mode 100644 index a69810b..0000000 --- a/config/config.sample.yml +++ /dev/null @@ -1,80 +0,0 @@ -twitter: - consumer_key: '' - consumer_secret: '' - access_token_key: '' - access_token_secret: '' - twittername: '' - twitterkeyword: 'gameunitsbot' -log: - file: tipbot.log -rpc: - host: localhost - port: 1337 - user: gameunitsrpc - pass: pass - prefix: '' -coin: - withdrawal_fee: 1 - min_withdraw: 1 - min_confirmations: 10 - min_tip: 0.1 - min_rain: 1 - short_name: ' UNITS' - full_name: Gameunits -webadmin: - enabled: false - port: 8080 - users: - unek: supersecretpassword - admintwo: password -commands: - help: - pm: true - channel: false - tip: - pm: true - channel: true - balance: - pm: true - channel: false - withdraw: - pm: true - channel: false - address: - pm: true - channel: false - terms: - pm: true - channel: false - rain: - pm: false - channel: true - rain_on_last_active: 0 # amount in seconds. rain tips will fall only on users active within x seconds. leave 0 for no such behavior. -messages: - error: 'Sorry %name%, something went wrong.' - no_funds: "Sorry %name%, you don't have enough funds (you're %short%%short_name% short)" - not_identified: '%name%: You need to be identified with NickServ to tip.' - tipped: ' Tipped @%to% %amount%%short_name%! "tweet @%nick% gameunits help" to claim.' - balance: '%name% has %balance%%short_name%.' - balance_unconfirmed: '%name% has %balance%%short_name% (unconfirmed: %unconfirmed%%short_name%)' - deposit_address: Your deposit address %address% - withdraw_too_small: 'Sorry %name%, you need to withdraw at least %min_withdraw%%short_name% (you have %balance%%short_name%)' - invalid_address: 'Sorry %name%, the address you specified is invalid (%address%).' - tip_too_small: 'Sorry %from%, your tip to %to% (%amount%%short_name%) is too small (min. %min_tip%%short_name%).' - tip_self: "Sorry %name%, you can't tip yourself!" - invalid_amount: 'Sorry %name%, "%amount%" is not a correct amount.' - withdraw_success: - - '%name%: %amount%%short_name% has been withdrawn from your account to %address%' - - 'You have been charged %withdrawal_fee%%short_name% withdrawal fee.' - - 'Transaction %transaction% completed.' - help: - - 'You can use following commands:' - - 'balance - displays your current wallet balance' - - 'address - displays %full_name% your depositaddress' - - 'withdraw <%full_name% address> - withdraws your whole wallet balance to specified address (minus %withdrawal_fee%%short_name% withdrawal fee)' - - 'tip - sends the specified amount of %full_name% to nickname' - - 'terms - displays terms and conditions for using %nick%' - - 'payout - How can I withdraw my Gameunits from tipbot ? Just Download Gameunits client from : http://gameunits.org/#downloads' - terms: - - 'There are no fees to use %nick%, with the exception of %withdrawal_fee%%short_name% fee on withdrawals.' - - 'In no event shall %nick% be responsible in the event of lost, stolen or misdirected funds.' diff --git a/config/default.example.json b/config/default.example.json new file mode 100644 index 0000000..a8429d3 --- /dev/null +++ b/config/default.example.json @@ -0,0 +1,13 @@ +{ + "twitter": { + "consumer_key": "****", + "consumer_secret": "****", + "access_token": "****", + "access_token_secret": "****" + }, + "lbrycrd": { + "username": "lbry", + "password": "lbry", + "port": 9245 + } +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..46cd410 --- /dev/null +++ b/index.js @@ -0,0 +1,209 @@ +const Twit = require("twit"); +const config = require("config"); +const winston = require("winston"); +require("winston-daily-rotate-file"); +const Client = require("bitcoin-core"); +const lbry = new Client({ + version: "0.12.0", + username: config.get("lbrycrd.username"), + password: config.get("lbrycrd.password"), + port: config.get("lbrycrd.port") +}); +const logger = winston.createLogger({ + level: "info", + format: winston.format.json(), + transports: [ + new winston.transports.DailyRotateFile({ + filename: "tipbot-%DATE%.log", + dirname: "./logs", + datePattern: "YYYY-MM-DD-HH", + zippedArchive: true, + maxSize: "20m", + maxFiles: "14d" + }), + new winston.transports.Console({ + format: winston.format.simple(), + level: "debug" + }) + ] +}); + +const T = new Twit({ + consumer_key: config.get("twitter.consumer_key"), + consumer_secret: config.get("twitter.consumer_secret"), + access_token: config.get("twitter.access_token"), + access_token_secret: config.get("twitter.access_token_secret"), + timeout_ms: 60 * 1000, // optional HTTP request timeout to apply to all requests. + strictSSL: true // optional - requires SSL certificates to be valid. +}); + +var stream = T.stream("statuses/filter", { track: "@devlbctipbot" }); +logger.info("Started LBRY twitter tipbot."); + +stream.on("tweet", function(tweet) { + let msg = checkTrunc(tweet); + msg = msg.slice(msg.indexOf("@devlbctipbot")).split(" "); + checkTweet(tweet, msg); +}); + +function checkTweet(tweet, msg) { + switch (msg[1]) { + case "help": + doHelp(tweet, msg); + break; + case "balance": + doBalance(tweet, msg); + break; + case "deposit": + doDeposit(tweet, msg); + break; + case "withdraw": + doWithdraw(tweet, msg); + break; + case "tip": + doTip(tweet, msg); + break; + } +} + +async function doHelp(tweet, msg) { + try { + let post = await T.post("statuses/update", { + status: + "All commands should be called with @ devlbctipbot \n" + + "help - Shows this command. \n" + + "balance - Get your balance. \n" + + "deposit - Get address for your deposits. \n" + + "withdraw ADDRESS AMOUNT - Withdraw AMOUNT credits to ADDRESS. \n" + + "tip USER AMOUNT - Tip USER AMOUNT.", + in_reply_to_status_id: tweet.id_str + }); + logger.info( + `Sent help to ${tweet.user.screen_name}, tweet id: ${tweet.id_str}` + ); + } catch (e) { + logger.error(e); + } +} +async function doBalance(tweet, msg) { + try { + const balance = await lbry.getBalance(tweet.user.id_str, 3); + const post = await T.post("statuses/update", { + status: `You have ${balance} LBC.`, + in_reply_to_status_id: tweet.id_str + }); + logger.info( + `Sent balance command to ${tweet.user.screen_name}, tweet id: ${ + tweet.id_str + }` + ); + } catch (e) { + logger.error(e); + } +} +async function doDeposit(tweet, msg) { + try { + const post = await T.post("statuses/update", { + status: `Your deposit address is ${await getAddress(tweet.user.id_str)}.`, + in_reply_to_status_id: tweet.id_str + }); + logger.info( + `Sent deposit address to ${tweet.user.screen_name}, tweet id: ${ + tweet.id_str + }` + ); + } catch (e) { + logger.error(e); + } +} +async function doWithdraw(tweet, msg) { + if (msg.length < 4) return doHelp(tweet, msg); + let address = msg[2]; + let amount = getValidatedAmount(msg[3]); + if (amount === null) { + return await T.post("statuses/update", { + status: `I don´t know how to withdraw that many credits...`, + in_reply_to_status_id: tweet.id_str + }); + } + let txId = await lbry.sendFrom(tweet.user.id_str, address, amount); + await T.post("statuses/update", { + status: `You withdrew ${amount} LBC to ${address}. \n${txLink(txId)}`, + in_reply_to_status_id: tweet.id_str + }); + logger.info( + `User ${ + tweet.user.screen_name + } withdraw ${amount} LBC to ${address}, tweet id: ${tweet.id_str}` + ); + try { + } catch (e) { + logger.error(e); + } +} +async function doTip(tweet, msg) { + try { + if (msg.length < 3) { + return doHelp(tweet, msg); + } + const amount = getValidatedAmount(msg[3]); + if (amount === null) { + return await T.post("statuses/update", { + status: `I don´t know how to tip that many credits...`, + in_reply_to_status_id: tweet.id_str + }); + } + const userToTip = userToTip(tweet, msg); + const userToTipAddress = getAddress(userToTip); + if (userToTip === null) { + return await T.post("statuses/update", { + status: `I could not find that user...`, + in_reply_to_status_id: tweet.id_str + }); + } + const txId = await lbry.sendFrom( + tweet.user.id_str, + userToTipAddress, + Number(amount), + null, + null + ); + logger.info( + `@${tweet.user.screen_name}(${tweet.user.id_str}) tipped ${ + msg[2] + }(${userToTip}) ${amount} LBC.` + ); + } catch (e) { + logger.error(e); + } +} + +async function getAddress(userId) { + try { + let uAddresses = await lbry.getAddressesByAccount(userId); + if (uAddresses.length > 0) return uAddresses[0]; + let nAddress = await lbry.getNewAddress(userId); + return nAddress; + } catch (e) { + logger.error(e); + } +} +function userToTip(tweet, msg) { + const username = msg[2]; + const users = tweet.entities.user_mentions; + return users.find(u => `@${u.screen_name}` === username).id_str; +} +function getValidatedAmount(amount) { + amount = amount.trim(); + if (amount.toLowerCase().endsWith("lbc")) { + amount = amount.substring(0, amount.length - 3); + } + return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null; +} +function txLink(txId) { + return `https://explorer.lbry.io/tx/${txId}`; +} +function checkTrunc(tweet) { + if (tweet.truncated) return tweet.extended_tweet.full_text; + return tweet.text; +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 0ace8f6..0000000 --- a/package-lock.json +++ /dev/null @@ -1,1198 +0,0 @@ -{ - "name": "node-tip-bot-twitter", - "version": "1.0.2", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "accepts": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", - "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", - "requires": { - "mime-types": "2.1.18", - "negotiator": "0.5.3" - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "1.0.3" - } - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", - "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" - }, - "base64-url": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.2.1.tgz", - "integrity": "sha1-GZ/WYXAqDnt9yubgaYuwicUvbXg=" - }, - "basic-auth": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", - "integrity": "sha1-Awk1sB3nyblKgksp8/zLdQ06UpA=" - }, - "basic-auth-connect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz", - "integrity": "sha1-/bC0OWLKe0BFanwrtI/hc9otISI=" - }, - "batch": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.3.tgz", - "integrity": "sha1-PzQU84AyF0O/wQQvmoP/HVgk1GQ=" - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "body-parser": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.13.3.tgz", - "integrity": "sha1-wIzzMMM1jhUQFqBXRvE/ApyX+pc=", - "requires": { - "bytes": "2.1.0", - "content-type": "1.0.4", - "debug": "2.2.0", - "depd": "1.0.1", - "http-errors": "1.3.1", - "iconv-lite": "0.4.11", - "on-finished": "2.3.0", - "qs": "4.0.0", - "raw-body": "2.1.7", - "type-is": "1.6.16" - } - }, - "bytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.1.0.tgz", - "integrity": "sha1-rJPEEOL/ycx89LRks4KJBn9eR7Q=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "colors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", - "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=" - }, - "commander": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", - "integrity": "sha1-nfflL7Kgyw+4kFjugMMQQiXzfh0=" - }, - "compressible": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.13.tgz", - "integrity": "sha1-DRAgq5JLL9tNYnmHXH1tq6a6p6k=", - "requires": { - "mime-db": "1.33.0" - } - }, - "compression": { - "version": "1.5.2", - "resolved": "http://registry.npmjs.org/compression/-/compression-1.5.2.tgz", - "integrity": "sha1-sDuNhub4rSloPLqN+R3cb/x3s5U=", - "requires": { - "accepts": "1.2.13", - "bytes": "2.1.0", - "compressible": "2.0.13", - "debug": "2.2.0", - "on-headers": "1.0.1", - "vary": "1.0.1" - } - }, - "connect": { - "version": "2.30.2", - "resolved": "https://registry.npmjs.org/connect/-/connect-2.30.2.tgz", - "integrity": "sha1-jam8vooFTT0xjXTf7JA7XDmhtgk=", - "requires": { - "basic-auth-connect": "1.0.0", - "body-parser": "1.13.3", - "bytes": "2.1.0", - "compression": "1.5.2", - "connect-timeout": "1.6.2", - "content-type": "1.0.4", - "cookie": "0.1.3", - "cookie-parser": "1.3.5", - "cookie-signature": "1.0.6", - "csurf": "1.8.3", - "debug": "2.2.0", - "depd": "1.0.1", - "errorhandler": "1.4.3", - "express-session": "1.11.3", - "finalhandler": "0.4.0", - "fresh": "0.3.0", - "http-errors": "1.3.1", - "method-override": "2.3.10", - "morgan": "1.6.1", - "multiparty": "3.3.2", - "on-headers": "1.0.1", - "parseurl": "1.3.2", - "pause": "0.1.0", - "qs": "4.0.0", - "response-time": "2.3.2", - "serve-favicon": "2.3.2", - "serve-index": "1.7.3", - "serve-static": "1.10.3", - "type-is": "1.6.16", - "utils-merge": "1.0.0", - "vhost": "3.0.2" - } - }, - "connect-timeout": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/connect-timeout/-/connect-timeout-1.6.2.tgz", - "integrity": "sha1-3ppexh4zoStu2qt7XwYumMWZuI4=", - "requires": { - "debug": "2.2.0", - "http-errors": "1.3.1", - "ms": "0.7.1", - "on-headers": "1.0.1" - } - }, - "content-disposition": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz", - "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4=" - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz", - "integrity": "sha1-5zSlwUF/zkctWu+Cw4HKu2TRpDU=" - }, - "cookie-parser": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz", - "integrity": "sha1-nXVVcPtdF4kHcSJ6AjFNm+fPg1Y=", - "requires": { - "cookie": "0.1.3", - "cookie-signature": "1.0.6" - } - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "crc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/crc/-/crc-3.3.0.tgz", - "integrity": "sha1-+mIuG8OIvyVzCQgta2UgDOZwkLo=" - }, - "csrf": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.0.6.tgz", - "integrity": "sha1-thEg3c7q/JHnbtUxO7XAsmZ7cQo=", - "requires": { - "rndm": "1.2.0", - "tsscmp": "1.0.5", - "uid-safe": "2.1.4" - } - }, - "csurf": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.8.3.tgz", - "integrity": "sha1-I/KhO/HY/OHQyZZYg5RELLqGpWo=", - "requires": { - "cookie": "0.1.3", - "cookie-signature": "1.0.6", - "csrf": "3.0.6", - "http-errors": "1.3.1" - } - }, - "cycle": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", - "integrity": "sha1-IegLK+hYD5i0aPN5QwZisEbDStI=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "1.0.0" - } - }, - "debug": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", - "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", - "requires": { - "ms": "0.7.1" - } - }, - "deep-extend": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.0.tgz", - "integrity": "sha1-bvSgmwX5iw41jW2T1Mo8rsZnKAM=" - }, - "depd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", - "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "errorhandler": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.4.3.tgz", - "integrity": "sha1-t7cO2PNZ6duICS8tIMD4MUIK2D8=", - "requires": { - "accepts": "1.3.5", - "escape-html": "1.0.3" - }, - "dependencies": { - "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "requires": { - "mime-types": "2.1.18", - "negotiator": "0.6.1" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - } - } - }, - "escape-html": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.2.tgz", - "integrity": "sha1-130y+pjjjC9BroXpJ44ODmuhAiw=" - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" - }, - "etag": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", - "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=" - }, - "express": { - "version": "3.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-3.21.2.tgz", - "integrity": "sha1-DCkD7lxU5j1lqWFwdkcDVQZlo94=", - "requires": { - "basic-auth": "1.0.4", - "commander": "2.6.0", - "connect": "2.30.2", - "content-disposition": "0.5.0", - "content-type": "1.0.4", - "cookie": "0.1.3", - "cookie-signature": "1.0.6", - "debug": "2.2.0", - "depd": "1.0.1", - "escape-html": "1.0.2", - "etag": "1.7.0", - "fresh": "0.3.0", - "merge-descriptors": "1.0.0", - "methods": "1.1.2", - "mkdirp": "0.5.1", - "parseurl": "1.3.2", - "proxy-addr": "1.0.10", - "range-parser": "1.0.3", - "send": "0.13.0", - "utils-merge": "1.0.0", - "vary": "1.0.1" - } - }, - "express-session": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.11.3.tgz", - "integrity": "sha1-XMmPP1/4Ttg1+Ry/CqvQxxB0AK8=", - "requires": { - "cookie": "0.1.3", - "cookie-signature": "1.0.6", - "crc": "3.3.0", - "debug": "2.2.0", - "depd": "1.0.1", - "on-headers": "1.0.1", - "parseurl": "1.3.2", - "uid-safe": "2.0.0", - "utils-merge": "1.0.0" - }, - "dependencies": { - "uid-safe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.0.0.tgz", - "integrity": "sha1-p/PGymSh9qXQTsDvPkw9U2cxcTc=", - "requires": { - "base64-url": "1.2.1" - } - } - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "eyes": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", - "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "finalhandler": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.0.tgz", - "integrity": "sha1-llpS2ejQXSuFdUhUH7ibU6JJfZs=", - "requires": { - "debug": "2.2.0", - "escape-html": "1.0.2", - "on-finished": "2.3.0", - "unpipe": "1.0.0" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", - "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" - } - }, - "http-errors": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz", - "integrity": "sha1-GX4izevUGYWF6GlO9nhhl7ke2UI=", - "requires": { - "inherits": "2.0.3", - "statuses": "1.5.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.14.1" - } - }, - "iconv-lite": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz", - "integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ipaddr.js": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz", - "integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "js-yaml": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", - "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.0.tgz", - "integrity": "sha1-IWnPdTjhsMyH+4jhUC2EdLv3mGQ=" - }, - "method-override": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.10.tgz", - "integrity": "sha1-49r41d7hDdLc59SuiNYrvud0drQ=", - "requires": { - "debug": "2.6.9", - "methods": "1.1.2", - "parseurl": "1.3.2", - "vary": "1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - } - } - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" - }, - "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", - "requires": { - "mime-db": "1.33.0" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "morgan": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.6.1.tgz", - "integrity": "sha1-X9gYOYxoGcuiinzWZk8pL+HAu/I=", - "requires": { - "basic-auth": "1.0.4", - "debug": "2.2.0", - "depd": "1.0.1", - "on-finished": "2.3.0", - "on-headers": "1.0.1" - } - }, - "ms": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", - "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" - }, - "multiparty": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-3.3.2.tgz", - "integrity": "sha1-Nd5oBNwZZD5SSfPT473GyM4wHT8=", - "requires": { - "readable-stream": "1.1.14", - "stream-counter": "0.2.0" - } - }, - "negotiator": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", - "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=" - }, - "node-gameunits": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/node-gameunits/-/node-gameunits-0.3.9.tgz", - "integrity": "sha1-UFwJK/+WTRvco43oV+aZdrZDhv0=" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" - }, - "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" - }, - "pause": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/pause/-/pause-0.1.0.tgz", - "integrity": "sha1-68ikqGGf8LioGsFRPDQ0/0af23Q=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "prettier": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.12.0.tgz", - "integrity": "sha512-Wz0SMncgaglBzDcohH3ZIAi4nVpzOIEweFzCOmgVEoRSeO72b4dcKGfgxoRGVMaFlh1r7dlVaJ+f3CIHfeH6xg==", - "dev": true - }, - "proxy-addr": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz", - "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=", - "requires": { - "forwarded": "0.1.2", - "ipaddr.js": "1.0.5" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "qs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz", - "integrity": "sha1-wx2bdOwn33XlQ6hseHKO2NRiNgc=" - }, - "random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" - }, - "range-parser": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", - "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=" - }, - "raw-body": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", - "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", - "requires": { - "bytes": "2.4.0", - "iconv-lite": "0.4.13", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", - "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" - }, - "iconv-lite": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", - "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" - } - } - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "response-time": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.2.tgz", - "integrity": "sha1-/6cbq5UtYvfB1Jt0NDVfvGjf/Fo=", - "requires": { - "depd": "1.1.2", - "on-headers": "1.0.1" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - } - } - }, - "rndm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", - "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "send": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.13.0.tgz", - "integrity": "sha1-UY+SGusFYK7H3KspkLFM9vPM5d4=", - "requires": { - "debug": "2.2.0", - "depd": "1.0.1", - "destroy": "1.0.3", - "escape-html": "1.0.2", - "etag": "1.7.0", - "fresh": "0.3.0", - "http-errors": "1.3.1", - "mime": "1.3.4", - "ms": "0.7.1", - "on-finished": "2.3.0", - "range-parser": "1.0.3", - "statuses": "1.2.1" - }, - "dependencies": { - "destroy": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz", - "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk=" - }, - "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" - }, - "statuses": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", - "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" - } - } - }, - "serve-favicon": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.3.2.tgz", - "integrity": "sha1-3UGeJo3gEqtysxnTN/IQUBP5OB8=", - "requires": { - "etag": "1.7.0", - "fresh": "0.3.0", - "ms": "0.7.2", - "parseurl": "1.3.2" - }, - "dependencies": { - "ms": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" - } - } - }, - "serve-index": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.7.3.tgz", - "integrity": "sha1-egV/xu4o3GP2RWbl+lexEahq7NI=", - "requires": { - "accepts": "1.2.13", - "batch": "0.5.3", - "debug": "2.2.0", - "escape-html": "1.0.3", - "http-errors": "1.3.1", - "mime-types": "2.1.18", - "parseurl": "1.3.2" - }, - "dependencies": { - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - } - } - }, - "serve-static": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz", - "integrity": "sha1-zlpuzTEB/tXsCYJ9rCKpwpv7BTU=", - "requires": { - "escape-html": "1.0.3", - "parseurl": "1.3.2", - "send": "0.13.2" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" - }, - "send": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz", - "integrity": "sha1-dl52B8gFVFK7pvCwUllTUJhgNt4=", - "requires": { - "debug": "2.2.0", - "depd": "1.1.2", - "destroy": "1.0.4", - "escape-html": "1.0.3", - "etag": "1.7.0", - "fresh": "0.3.0", - "http-errors": "1.3.1", - "mime": "1.3.4", - "ms": "0.7.1", - "on-finished": "2.3.0", - "range-parser": "1.0.3", - "statuses": "1.2.1" - } - }, - "statuses": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz", - "integrity": "sha1-3e1FzBglbVHtQK7BQkidXGECbSg=" - } - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "sshpk": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", - "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - } - }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stream-counter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.2.0.tgz", - "integrity": "sha1-3tJmVWMZyLDiIoErnPOyb6fZR94=", - "requires": { - "readable-stream": "1.1.14" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, - "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", - "requires": { - "punycode": "1.4.1" - } - }, - "tsscmp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", - "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc=" - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - }, - "twitter": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/twitter/-/twitter-1.7.1.tgz", - "integrity": "sha1-B2I3jx3BwFDkj2ZqypBOJLGpYvQ=", - "requires": { - "deep-extend": "0.5.0", - "request": "2.85.0" - }, - "dependencies": { - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "requires": { - "hoek": "4.2.1" - } - }, - "combined-stream": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", - "requires": { - "delayed-stream": "1.0.0" - } - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.2.1" - } - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.6", - "mime-types": "2.1.18" - } - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.1", - "sntp": "2.1.0" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" - }, - "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.6", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" - } - }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "requires": { - "hoek": "4.2.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "5.1.1" - } - }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" - } - } - }, - "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "2.1.18" - } - }, - "uid-safe": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.4.tgz", - "integrity": "sha1-Otbzg2jG1MjHXsF2I/t5qh0HHYE=", - "requires": { - "random-bytes": "1.0.0" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" - }, - "vary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", - "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - } - }, - "vhost": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/vhost/-/vhost-3.0.2.tgz", - "integrity": "sha1-L7HezUxGaqiLD5NBrzPcGv8keNU=" - }, - "winston": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.2.tgz", - "integrity": "sha512-4S/Ad4ZfSNl8OccCLxnJmNISWcm2joa6Q0YGDxlxMzH0fgSwWsjMt+SmlNwCqdpaPg3ev1HKkMBsIiXeSUwpbA==", - "requires": { - "async": "1.0.0", - "colors": "1.0.3", - "cycle": "1.0.3", - "eyes": "0.1.8", - "isstream": "0.1.2", - "stack-trace": "0.0.10" - } - } - } -} diff --git a/package.json b/package.json index c78ef7b..5681f0b 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,17 @@ { - "name": "node-tip-bot-twitter", - "version": "1.0.2", - "description": "node.js based tipping bot for any coin", - "main": "bin/tipbot", "dependencies": { - "express": "^3.21.2", - "js-yaml": "^3.11.0", - "node-gameunits": "^0.3.5", - "twitter": "^1.7.1", - "winston": "^2.4.2" + "bitcoin-core": "^2.0.0", + "config": "^1.30.0", + "twit": "^2.2.11", + "winston": "3", + "winston-daily-rotate-file": "^3.2.3" }, - "devDependencies": { - "prettier": "^1.12.0" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "start": "node bin/tipbot", - "prettier": "prettier --write \"{bot,.}/**/*.{js,json}\" --single-quote --print-width 240", - "build": "babel bot -d dist", - "prod": "babel bot -d dist & node dist/bot.js", - "lint": "prettier --write \"{bot,.}/**/*.{js,json}\" --single-quote --print-width 240", - "precommit": "prettier --write \"{bot,.}/**/*.{js,json}\" --single-quote --print-width 240" - }, - "repository": { - "type": "git", - "url": "http://github.com/gameunits/node-tip-bot" - }, - "author": "gameunits", + "name": "lbry-twitter-tipbot", + "version": "1.0.0", + "description": "A twitter tipbot for LBRY", + "main": "index.js", + "repository": "https://github.com/lbryio/twitter-tipbot/", + "author": "filipnyquist ", "license": "MIT", - "bugs": { - "url": "https://github.com/gameunits/node-tip-bot/issues" - }, - "homepage": "https://github.com/gameunits/node-tip-bot", - "keywords": [ - "gameunits", - "bitcoin", - "litecoin", - "altcoin", - "tip", - "tipbot", - "irc", - "bot" - ] + "private": false } diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..8a8eca5 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,651 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@uphold/request-logger@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@uphold/request-logger/-/request-logger-2.0.0.tgz#c585c0bdb94210198945c6597e4fe23d6e63e084" + dependencies: + uuid "^3.0.1" + +ajv@^5.1.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" + dependencies: + co "^4.6.0" + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +async@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610" + dependencies: + lodash "^4.17.10" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + +aws4@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + dependencies: + tweetnacl "^0.14.3" + +bignumber.js@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1" + +bitcoin-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/bitcoin-core/-/bitcoin-core-2.0.0.tgz#defcd4b3bfb6738ea88051b5fe5a944e32c09df0" + dependencies: + "@uphold/request-logger" "^2.0.0" + bluebird "^3.4.1" + debugnyan "^1.0.0" + json-bigint "^0.2.0" + lodash "^4.0.0" + request "^2.53.0" + semver "^5.1.0" + standard-error "^1.1.0" + +bluebird@^3.1.5, bluebird@^3.4.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +bunyan@^1.8.1: + version "1.8.12" + resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.12.tgz#f150f0f6748abdd72aeae84f04403be2ef113797" + optionalDependencies: + dtrace-provider "~0.8" + moment "^2.10.6" + mv "~2" + safe-json-stringify "~1" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +color-convert@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd" + +color-name@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color@0.8.x: + version "0.8.0" + resolved "https://registry.yarnpkg.com/color/-/color-0.8.0.tgz#890c07c3fd4e649537638911cf691e5458b6fca5" + dependencies: + color-convert "^0.5.0" + color-string "^0.3.0" + +colornames@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/colornames/-/colornames-0.0.2.tgz#d811fd6c84f59029499a8ac4436202935b92be31" + +colors@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.0.tgz#5f20c9fef6945cb1134260aab33bfbdc8295e04e" + +colorspace@1.0.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.0.1.tgz#c99c796ed31128b9876a52e1ee5ee03a4a719749" + dependencies: + color "0.8.x" + text-hex "0.0.x" + +combined-stream@1.0.6, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" + dependencies: + delayed-stream "~1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +config@^1.30.0: + version "1.30.0" + resolved "https://registry.yarnpkg.com/config/-/config-1.30.0.tgz#1d60a9f35348a13c175798d384e81a5a16c3ba6e" + dependencies: + json5 "0.4.0" + os-homedir "1.0.2" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cycle@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +debug@^2.2.0: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +debugnyan@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/debugnyan/-/debugnyan-1.0.0.tgz#90386d5ebc2c63588f17f272be5c2a93b7665d83" + dependencies: + bunyan "^1.8.1" + debug "^2.2.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +diagnostics@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/diagnostics/-/diagnostics-1.1.0.tgz#e1090900b49523e8527be20f081275205f2ae36a" + dependencies: + colorspace "1.0.x" + enabled "1.0.x" + kuler "0.0.x" + +dtrace-provider@~0.8: + version "0.8.7" + resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.7.tgz#dc939b4d3e0620cfe0c1cd803d0d2d7ed04ffd04" + dependencies: + nan "^2.10.0" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +enabled@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93" + dependencies: + env-variable "0.0.x" + +env-variable@0.0.x: + version "0.0.4" + resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.4.tgz#0d6280cf507d84242befe35a512b5ae4be77c54e" + +extend@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + +fast-deep-equal@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + +fast-safe-stringify@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.4.tgz#4fe828718aa61dbcf9119c3c24e79cc4dea973b2" + +fecha@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd" + +file-stream-rotator@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/file-stream-rotator/-/file-stream-rotator-0.2.1.tgz#0d6fea1a9a7aba25a87cfd31b6e269e44e8f0af2" + dependencies: + moment "^2.11.2" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" + dependencies: + asynckit "^0.4.0" + combined-stream "1.0.6" + mime-types "^2.1.12" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob@^6.0.1: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + +har-validator@~5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" + dependencies: + ajv "^5.1.0" + har-schema "^2.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +json-bigint@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-0.2.3.tgz#118d7f6ff1d38659f19f94cf73e64a75a3f988a8" + dependencies: + bignumber.js "^4.0.0" + +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +kuler@0.0.x: + version "0.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-0.0.0.tgz#b66bb46b934e550f59d818848e0abba4f7f5553c" + dependencies: + colornames "0.0.2" + +lodash@^4.0.0, lodash@^4.17.10: + version "4.17.10" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" + +logform@^1.6.0, logform@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-1.9.1.tgz#58b29d7b11c332456d7a217e17b48a13ad69d60a" + dependencies: + colors "^1.2.1" + fast-safe-stringify "^2.0.4" + fecha "^2.3.3" + ms "^2.1.1" + triple-beam "^1.2.0" + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-types@^2.1.12, mime-types@~2.1.17: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + dependencies: + mime-db "~1.33.0" + +mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + +"minimatch@2 || 3": + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +moment@^2.10.6, moment@^2.11.2: + version "2.22.2" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + +mv@~2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2" + dependencies: + mkdirp "~0.5.1" + ncp "~2.0.0" + rimraf "~2.4.0" + +nan@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" + +ncp@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" + +oauth-sign@~0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +one-time@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-0.0.4.tgz#f8cdf77884826fe4dff93e3a9cc37b1e4480742e" + +os-homedir@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~6.5.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + +readable-stream@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +request@^2.53.0, request@^2.68.0: + version "2.87.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.6.0" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.1" + forever-agent "~0.6.1" + form-data "~2.3.1" + har-validator "~5.0.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.17" + oauth-sign "~0.8.2" + performance-now "^2.1.0" + qs "~6.5.1" + safe-buffer "^5.1.1" + tough-cookie "~2.3.3" + tunnel-agent "^0.6.0" + uuid "^3.1.0" + +rimraf@~2.4.0: + version "2.4.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da" + dependencies: + glob "^6.0.1" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + +safe-json-stringify@~1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz#356e44bc98f1f93ce45df14bcd7c01cda86e0afd" + +safer-buffer@^2.0.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + +semver@^5.1.0, semver@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" + +sshpk@^1.7.0: + version "1.14.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + safer-buffer "^2.0.2" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + +standard-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/standard-error/-/standard-error-1.1.0.tgz#23e5168fa1c0820189e5812701a79058510d0d34" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + dependencies: + safe-buffer "~5.1.0" + +text-hex@0.0.x: + version "0.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-0.0.0.tgz#578fbc85a6a92636e42dd17b41d0218cce9eb2b3" + +tough-cookie@~2.3.3: + version "2.3.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" + dependencies: + punycode "^1.4.1" + +triple-beam@^1.2.0, triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +twit@^2.2.11: + version "2.2.11" + resolved "https://registry.yarnpkg.com/twit/-/twit-2.2.11.tgz#554343d1cf343ddf503280db821f61be5ab407c3" + dependencies: + bluebird "^3.1.5" + mime "^1.3.4" + request "^2.68.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +uuid@^3.0.1, uuid@^3.1.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +winston-compat@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/winston-compat/-/winston-compat-0.1.4.tgz#599b4ce807ffe728713ecc25ede3f6b89425b739" + dependencies: + cycle "~1.0.3" + logform "^1.6.0" + triple-beam "^1.2.0" + +winston-daily-rotate-file@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-3.2.3.tgz#9f80e7a421ab32b073c1217bae62e762001197d6" + dependencies: + file-stream-rotator "^0.2.1" + semver "^5.5.0" + triple-beam "^1.3.0" + winston-compat "^0.1.4" + winston-transport "^4.2.0" + +winston-transport@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.2.0.tgz#a20be89edf2ea2ca39ba25f3e50344d73e6520e5" + dependencies: + readable-stream "^2.3.6" + triple-beam "^1.2.0" + +winston@3: + version "3.0.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.0.0.tgz#1f0b24a96586798bcf0cd149fb07ed47cb01a1b2" + dependencies: + async "^2.6.0" + diagnostics "^1.0.1" + is-stream "^1.1.0" + logform "^1.9.0" + one-time "0.0.4" + readable-stream "^2.3.6" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.2.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" From 559478cc40679aa318c65894da1dfd97e0aa9b08 Mon Sep 17 00:00:00 2001 From: filipnyquist Date: Thu, 5 Jul 2018 11:37:04 +0200 Subject: [PATCH 2/4] Fixed tipping, tipping message, better error handeling, README and LICENSE. --- LICENSE | 15 ++++++++ README.md | 42 ++++++++++++++++++++++ config/default.example.json | 4 +++ index.js | 69 +++++++++++++++++++++++-------------- 4 files changed, 104 insertions(+), 26 deletions(-) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e838957 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +The MIT License (MIT) + +Copyright (c) 2018 LBRY Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d01d311 --- /dev/null +++ b/README.md @@ -0,0 +1,42 @@ +# Twitter tipbot - A twitter tipbot for LBRY + +This repo contains the twitter tipbot used by LBRY. This bot allows users to tip each other LBC on twitter. + +## Installation +### Prerequisites +* Lbrycrd-daemon +* Node.js v8+ +* Yarn +* A twitter application on the tipbot account + +>To get started you should clone the git: +``` +git clone https://github.com/lbryio/twitter-tipbot +``` +>Install all modules with yarn: +``` +yarn install +``` +>Rename default.example.json to default.json and enter the twitter tokens and daemon settings. + +>Run the bot with: +``` +node index.js +``` + + +## Contributing + +Contributions to this project are welcome, encouraged, and compensated. For more details, see [lbry.io/faq/contributing](https://lbry.io/faq/contributing) + +## License +This project is MIT Licensed © [LBRYio](https://github.com/lbryio) + +## Security + +We take security seriously. Please contact security@lbry.io regarding any security issues. +Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it. + +## Contact + +The primary contact for this project is [@filipnyquist](https://github.com/filipnyquist) (filip@lbry.io) diff --git a/config/default.example.json b/config/default.example.json index a8429d3..4580188 100644 --- a/config/default.example.json +++ b/config/default.example.json @@ -1,4 +1,8 @@ { + "bot":{ + "handle": "@devlbctipbot", + "requiredConfirms": 2 + }, "twitter": { "consumer_key": "****", "consumer_secret": "****", diff --git a/index.js b/index.js index 46cd410..12e27dd 100644 --- a/index.js +++ b/index.js @@ -37,12 +37,13 @@ const T = new Twit({ strictSSL: true // optional - requires SSL certificates to be valid. }); -var stream = T.stream("statuses/filter", { track: "@devlbctipbot" }); +const stream = T.stream("statuses/filter", { track: config.get("bot.handle") }); logger.info("Started LBRY twitter tipbot."); stream.on("tweet", function(tweet) { + if(tweet.user.screen_name === config.get("bot.handle").substring(1)) return; let msg = checkTrunc(tweet); - msg = msg.slice(msg.indexOf("@devlbctipbot")).split(" "); + msg = msg.slice(msg.indexOf(config.get("bot.handle"))).split(" "); checkTweet(tweet, msg); }); @@ -63,6 +64,9 @@ function checkTweet(tweet, msg) { case "tip": doTip(tweet, msg); break; + case "terms": + doTerms(tweet, msg); + break; } } @@ -70,7 +74,8 @@ async function doHelp(tweet, msg) { try { let post = await T.post("statuses/update", { status: - "All commands should be called with @ devlbctipbot \n" + + `@${tweet.user.screen_name} `+ + "All commands should be called with @ + subcommand \n" + "help - Shows this command. \n" + "balance - Get your balance. \n" + "deposit - Get address for your deposits. \n" + @@ -85,12 +90,15 @@ async function doHelp(tweet, msg) { logger.error(e); } } +async function doTerms(tweet, msg){ +// ADD terms +} async function doBalance(tweet, msg) { try { - const balance = await lbry.getBalance(tweet.user.id_str, 3); + const balance = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms")); // Amount of confirms before we can use it. const post = await T.post("statuses/update", { - status: `You have ${balance} LBC.`, - in_reply_to_status_id: tweet.id_str + in_reply_to_status_id: tweet.id_str, + status: `@${tweet.user.screen_name} You have ${balance} LBC.` }); logger.info( `Sent balance command to ${tweet.user.screen_name}, tweet id: ${ @@ -104,7 +112,7 @@ async function doBalance(tweet, msg) { async function doDeposit(tweet, msg) { try { const post = await T.post("statuses/update", { - status: `Your deposit address is ${await getAddress(tweet.user.id_str)}.`, + status: `@${tweet.user.screen_name} Your deposit address is ${await getAddress(id(tweet.user.id_str))}.`, in_reply_to_status_id: tweet.id_str }); logger.info( @@ -117,18 +125,19 @@ async function doDeposit(tweet, msg) { } } async function doWithdraw(tweet, msg) { + try { if (msg.length < 4) return doHelp(tweet, msg); let address = msg[2]; let amount = getValidatedAmount(msg[3]); if (amount === null) { return await T.post("statuses/update", { - status: `I don´t know how to withdraw that many credits...`, + status: `@${tweet.user.screen_name} I don´t know how to withdraw that many credits...`, in_reply_to_status_id: tweet.id_str }); } - let txId = await lbry.sendFrom(tweet.user.id_str, address, amount); + let txId = await lbry.sendFrom(id(tweet.user.id_str), address, amount); await T.post("statuses/update", { - status: `You withdrew ${amount} LBC to ${address}. \n${txLink(txId)}`, + status: `@${tweet.user.screen_name} You withdrew ${amount} LBC to ${address}. \n${txLink(txId)}`, in_reply_to_status_id: tweet.id_str }); logger.info( @@ -136,7 +145,6 @@ async function doWithdraw(tweet, msg) { tweet.user.screen_name } withdraw ${amount} LBC to ${address}, tweet id: ${tweet.id_str}` ); - try { } catch (e) { logger.error(e); } @@ -149,25 +157,35 @@ async function doTip(tweet, msg) { const amount = getValidatedAmount(msg[3]); if (amount === null) { return await T.post("statuses/update", { - status: `I don´t know how to tip that many credits...`, + status: `@${tweet.user.screen_name} I don´t know how to tip that many credits...`, in_reply_to_status_id: tweet.id_str }); } - const userToTip = userToTip(tweet, msg); - const userToTipAddress = getAddress(userToTip); + const userToTip = tweet.entities.user_mentions.find(u => `@${u.screen_name}` === msg[2]).id_str; if (userToTip === null) { return await T.post("statuses/update", { - status: `I could not find that user...`, + status: `@${tweet.user.screen_name} I could not find that user...`, in_reply_to_status_id: tweet.id_str }); } - const txId = await lbry.sendFrom( - tweet.user.id_str, - userToTipAddress, - Number(amount), - null, - null + const balanceFromUser = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms")); + if (balanceFromUser < amount) { + return await T.post("statuses/update", { + status: `@${tweet.user.screen_name} You tried to tip, but you are missing ${amount-balanceFromUser} LBC.`, + in_reply_to_status_id: tweet.id_str + }); + } + const txId = await lbry.move( + id(tweet.user.id_str), + id(userToTip), + Number(amount) ); + await T.post("statuses/update", { + status: `@${tweet.user.screen_name} Tipped ${ + msg[2] + } ${amount} LBC! \n See https://lbry.io/faq/tipbot-twitter for more information.`, + in_reply_to_status_id: tweet.id_str + }); logger.info( `@${tweet.user.screen_name}(${tweet.user.id_str}) tipped ${ msg[2] @@ -188,11 +206,6 @@ async function getAddress(userId) { logger.error(e); } } -function userToTip(tweet, msg) { - const username = msg[2]; - const users = tweet.entities.user_mentions; - return users.find(u => `@${u.screen_name}` === username).id_str; -} function getValidatedAmount(amount) { amount = amount.trim(); if (amount.toLowerCase().endsWith("lbc")) { @@ -207,3 +220,7 @@ function checkTrunc(tweet) { if (tweet.truncated) return tweet.extended_tweet.full_text; return tweet.text; } + +function id(usrId){ + return `t-${usrId}`; +} From 2f348e20511385efa6122a7063be8605854652bf Mon Sep 17 00:00:00 2001 From: filipnyquist Date: Fri, 6 Jul 2018 12:03:28 +0200 Subject: [PATCH 3/4] Started work on the next version of tipbot. --- .gitignore | 4 ++- README.md | 6 +++- index.js | 15 +++++++- move_helper.js | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 move_helper.js diff --git a/.gitignore b/.gitignore index 76345ff..5807a7b 100644 --- a/.gitignore +++ b/.gitignore @@ -73,4 +73,6 @@ typings/ .serverless # Configurations -default.json \ No newline at end of file +default.json + +.idea/* \ No newline at end of file diff --git a/README.md b/README.md index d01d311..7f3b693 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,11 @@ yarn install ``` node index.js ``` - +>If you want to move over accounts from the old tipbot format which used usernames as identifier, run move_helper.js: +``` +node move_helper.js +``` +>It will automatically move over the old accounts to the new id based system. ## Contributing diff --git a/index.js b/index.js index 12e27dd..8d88110 100644 --- a/index.js +++ b/index.js @@ -67,6 +67,10 @@ function checkTweet(tweet, msg) { case "terms": doTerms(tweet, msg); break; + case "lbryian": + logger.info("Got a command with the old format, handling it..."); + checkTweet(tweet, msg.splice(1)); + break; } } @@ -75,7 +79,7 @@ async function doHelp(tweet, msg) { let post = await T.post("statuses/update", { status: `@${tweet.user.screen_name} `+ - "All commands should be called with @ + subcommand \n" + + `All commands should be called with ${config.get("bot.handle")} + subcommand \n` + "help - Shows this command. \n" + "balance - Get your balance. \n" + "deposit - Get address for your deposits. \n" + @@ -92,6 +96,13 @@ async function doHelp(tweet, msg) { } async function doTerms(tweet, msg){ // ADD terms + await T.post("statuses/update", { + status: + `@${tweet.user.screen_name} `+ + "There are no fees to use this bot except the automatic daemon fee. \n"+ + "In no event shall LBRY Inc be responsible in the event of lost, stolen or misdirected funds.", + in_reply_to_status_id: tweet.id_str + }); } async function doBalance(tweet, msg) { try { @@ -162,6 +173,7 @@ async function doTip(tweet, msg) { }); } const userToTip = tweet.entities.user_mentions.find(u => `@${u.screen_name}` === msg[2]).id_str; + await getAddress(id(userToTip)) // Call this to ensure user has an account. if (userToTip === null) { return await T.post("statuses/update", { status: `@${tweet.user.screen_name} I could not find that user...`, @@ -206,6 +218,7 @@ async function getAddress(userId) { logger.error(e); } } + function getValidatedAmount(amount) { amount = amount.trim(); if (amount.toLowerCase().endsWith("lbc")) { diff --git a/move_helper.js b/move_helper.js new file mode 100644 index 0000000..20b0437 --- /dev/null +++ b/move_helper.js @@ -0,0 +1,97 @@ +// This file helps with moving over accounts from the old username system to the id system. +// It uses the same configuration files as index.js +// Checks for the old format, gets their id from twitter, creates new acc, moves balance. +const Twit = require("twit"); +const config = require("config"); +const winston = require("winston"); +require("winston-daily-rotate-file"); +const Client = require("bitcoin-core"); +const lbry = new Client({ + version: "0.12.0", + username: config.get("lbrycrd.username"), + password: config.get("lbrycrd.password"), + port: config.get("lbrycrd.port") +}); +const logger = winston.createLogger({ + level: "info", + format: winston.format.json(), + transports: [ + new winston.transports.DailyRotateFile({ + filename: "move-helper-%DATE%.log", + dirname: "./logs", + datePattern: "YYYY-MM-DD-HH", + zippedArchive: true, + maxSize: "20m", + maxFiles: "14d" + }), + new winston.transports.Console({ + format: winston.format.simple(), + level: "debug" + }) + ] +}); +let notSynced = []; + +const T = new Twit({ + consumer_key: config.get("twitter.consumer_key"), + consumer_secret: config.get("twitter.consumer_secret"), + access_token: config.get("twitter.access_token"), + access_token_secret: config.get("twitter.access_token_secret"), + timeout_ms: 60 * 1000, // optional HTTP request timeout to apply to all requests. + strictSSL: true // optional - requires SSL certificates to be valid. +}); + +async function main(){ + let accs = await getAccounts(); + logger.info(`Trying to move ${accs.length} accounts...`) + for (let i in accs){ + try { + //Get user details from twitter. + let data = await T.get('users/show', { screen_name: accs[i] }); + //Create a account for the user by id. + let usr = data.data.id_str; + await getAddress(id(usr)); + //Move over from old account to the new account + const balanceFromOld = await lbry.getBalance(`twttr-${accs[i]}`); + if (balanceFromOld !== 0) { + let res = await lbry.move( + `twttr-${accs[i]}`, + id(usr), + Number(balanceFromOld) + ); + // If move is successful, log it! + if (res) logger.info(`Transferred ${balanceFromOld} LBC from twttr-${accs[i]} to ${id(usr)}!`); + } + }catch(e){ + logger.info(`Could not sync ${accs[i]}, error occured:`, e.allErrors); + notSynced.push({ user: accs[i], error: e.allErrors}); + logger.info("Could not sync these:"+JSON.stringify(notSynced)); + } + } +} +// Get a list of all twitter accounts on lbrycrd. +async function getAccounts(){ + let accs = await lbry.listAccounts(); + accs = Object.entries(accs); + let accsArr = []; + for (let i in accs){ + if(accs[i][0].startsWith('twttr-')) accsArr.push(accs[i][0].substring(6)); + } + return accsArr; +} + +async function getAddress(userId) { + try { + let uAddresses = await lbry.getAddressesByAccount(userId); + if (uAddresses.length > 0) return; + await lbry.getNewAddress(userId); + return; + } catch (e) { + logger.error(e); + } +} + +function id(usrId){ + return `t-${usrId}`; +} +main(); From 8166a4da5ec9d3cee49bde0a81b0bb3770da643e Mon Sep 17 00:00:00 2001 From: filipnyquist Date: Fri, 6 Jul 2018 15:47:49 +0200 Subject: [PATCH 4/4] Started work on the next version of tipbot. --- index.js | 20 ++++++++------------ move_helper.js | 3 +-- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/index.js b/index.js index 8d88110..4e0f63f 100644 --- a/index.js +++ b/index.js @@ -4,7 +4,6 @@ const winston = require("winston"); require("winston-daily-rotate-file"); const Client = require("bitcoin-core"); const lbry = new Client({ - version: "0.12.0", username: config.get("lbrycrd.username"), password: config.get("lbrycrd.password"), port: config.get("lbrycrd.port") @@ -44,7 +43,7 @@ stream.on("tweet", function(tweet) { if(tweet.user.screen_name === config.get("bot.handle").substring(1)) return; let msg = checkTrunc(tweet); msg = msg.slice(msg.indexOf(config.get("bot.handle"))).split(" "); - checkTweet(tweet, msg); + if (msg.length >= 2) checkTweet(tweet, msg); }); function checkTweet(tweet, msg) { @@ -84,7 +83,8 @@ async function doHelp(tweet, msg) { "balance - Get your balance. \n" + "deposit - Get address for your deposits. \n" + "withdraw ADDRESS AMOUNT - Withdraw AMOUNT credits to ADDRESS. \n" + - "tip USER AMOUNT - Tip USER AMOUNT.", + "tip USER AMOUNT - Tip USER AMOUNT.\n"+ + "terms - Sends you the TOS.", in_reply_to_status_id: tweet.id_str }); logger.info( @@ -100,7 +100,7 @@ async function doTerms(tweet, msg){ status: `@${tweet.user.screen_name} `+ "There are no fees to use this bot except the automatic daemon fee. \n"+ - "In no event shall LBRY Inc be responsible in the event of lost, stolen or misdirected funds.", + "Under no circumstances shall LBRY Inc. be held responsible for lost, stolen or misdirected funds.", in_reply_to_status_id: tweet.id_str }); } @@ -173,7 +173,7 @@ async function doTip(tweet, msg) { }); } const userToTip = tweet.entities.user_mentions.find(u => `@${u.screen_name}` === msg[2]).id_str; - await getAddress(id(userToTip)) // Call this to ensure user has an account. + let tipToAddress = await getAddress(id(userToTip)) // Call this to ensure user has an account. if (userToTip === null) { return await T.post("statuses/update", { status: `@${tweet.user.screen_name} I could not find that user...`, @@ -183,19 +183,15 @@ async function doTip(tweet, msg) { const balanceFromUser = await lbry.getBalance(id(tweet.user.id_str), config.get("bot.requiredConfirms")); if (balanceFromUser < amount) { return await T.post("statuses/update", { - status: `@${tweet.user.screen_name} You tried to tip, but you are missing ${amount-balanceFromUser} LBC.`, + status: `@${tweet.user.screen_name} You tried tipping more than you have! You are ${amount-balanceFromUser} LBC short.`, in_reply_to_status_id: tweet.id_str }); } - const txId = await lbry.move( - id(tweet.user.id_str), - id(userToTip), - Number(amount) - ); + const txId = await lbry.sendFrom(id(tweet.user.id_str), tipToAddress, Number(amount), 1); await T.post("statuses/update", { status: `@${tweet.user.screen_name} Tipped ${ msg[2] - } ${amount} LBC! \n See https://lbry.io/faq/tipbot-twitter for more information.`, + } ${amount} LBC! \nTransaction: ${txLink(txId)} \nSee https://lbry.io/faq/tipbot-twitter for more information.`, in_reply_to_status_id: tweet.id_str }); logger.info( diff --git a/move_helper.js b/move_helper.js index 20b0437..5dc63d8 100644 --- a/move_helper.js +++ b/move_helper.js @@ -85,9 +85,8 @@ async function getAddress(userId) { let uAddresses = await lbry.getAddressesByAccount(userId); if (uAddresses.length > 0) return; await lbry.getNewAddress(userId); - return; } catch (e) { - logger.error(e); + throw("Something went wrong while creating an account for the user: ", e); } }