This post is a pretty large deviation from content that I’ve posted in the past, but it’s much more relevant to the work I’ve been doing recently. The project is designed to effectively execute and tweet the side effects of code found in mentions (this is when someone tweets a reply towards you) towards your twitter. The premise is pretty simple and all the code involves is some basic knowledge of OAuth, Twitter API, and ruby.
I will commence a brief walk through of the code. The OAuthAgent class is entirely dedicated to handling the initial security handshaking required to use the Twitter API. In short, you provide the class with your secret and key, and from there it handles the security signatures that will be attached to all communications with the Twitter server. The TwitterAgent class is very simple and currently only includes two methods. The first method simply allows tweeting and the second polls to get the most recent mentions. TweetToCompileVm is the final class and it is trivial as well. It uses a regex to parse the code from the tweet (it expects this format ) and then has another function that redirects stdout and calls eval to execute the code.
A couple of things to consider if you decide to employ the code or even just the general technique. First of all you’ll probably want to implement a true polling mechanism in TweetToCompileVm that will alert you when a new mention occurs thus allowing you to be proactive in your responses to mentions. As a side effect of this, it becomes virtually impossible to monitor the type of code that someone is trying to make your system execute. Because of this, you will need to sandbox the ruby interpreter in order to prevent people from completing malicious acts on your system.
And yes I realize that TweetToCompile is a misleading name and that TweetToRun or TweetToExecute would have been a more proper name. Here’s the code.
=begin
TweetToCompile a project that let's you run short scripts
using Twitter.
Aaron Burrow (burrows@mit.edu)
=end
gem 'oauth'
require 'oauth'
require 'oauth/consumer'
require 'rexml/document'
require 'stringio'
class OAuthAgent
attr_accessor :key, :secret, :url
def initialize(key=nil, secret=nil, url=nil)
@key, @secret, @url = key, secret, url
if @key.nil? == @secret.nil? and @secret.nil? == @url.nil? and @url != nil
@consumer = OAuth::Consumer.new key, secret, :site => url
else
@consumer = nil
end
end
def getRequestToken
if @consumer.nil?
@consumer = OAuth::Consumer.new @key, @secret, :site => @url
end
@consumer.get_request_token
end
def getPin(requestToken)
puts "Go to this URL and get the pin.\n#{requestToken.authorize_url}"
gets.chomp
end
def getAccessToken
requestToken = getRequestToken
pin = getPin(requestToken)
@accessToken = requestToken.get_access_token(:oauth_verifier => pin)
end
end
class TwitterAgent < OAuthAgent
=begin
Need to add code that will do error checking for the return of
RESTful requests.
=end
def updateFeed(text)
response = @accessToken.post '/statuses/update.xml', :status => text
end
def getMostRecentMention
response = @accessToken.get '/statuses/mentions.xml', "count" => "1"
doc = REXML::Document.new(response.body)
doc.root.elements[1].elements["text"].text
end
end
class TweetToCompileVm
attr_accessor :accountName
def initialize(accountName="TweetToCompile")
@accountName = accountName
end
def parseTweet(tweet)
@code = tweet.sub(/@#{@accountName}\s+/i, "")
end
def executeCode
sio = StringIO.new
oldStdout, $stdout = $stdout, sio
eval(@code)
$stdout = oldStdout
sio.string
end
end
Example usage…
agent = TwitterAgent.new key, secret, "https://api.twitter.com" agent.getAccessToken tweet = agent.getMostRecentMention vm = TweetToCompileVm.new vm.parseTweet(tweet)
Until later.