Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
333 lines (304 sloc) 11.7 KB
#!/usr/local/bin/ruby -rubygems
require 'camping'
# require 'camping/ar'
require 'camping/session'
require 'adult_friend_finder'
require 'recent'
require 'oauth'
Camping.goes :Twifter
RECENT = Recent.new unless defined?(RECENT)
module Twifter
include Camping::Session
LOG = Logger.new('request.log')
def Twifter.create
Camping::Models::Session.create_schema
end
module Models
class User < Base; end
class BasicFields < V 1.0
def self.up
create_table :twifter_users do |f|
f.string :token
f.string :secret
f.string :username
end
end
end
end
module Controllers
class Cache < R '/cache/(.+)'
MIME_TYPES = {'.js' => 'text/javascript' }
PATH = File.expand_path(File.dirname(__FILE__))
def get(path)
@headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
unless path.include? ".." # prevent directory traversal attacks
@headers['X-Sendfile'] = "#{PATH}/cache/#{path}"
else
@status = "403"
"403 - Invalid path"
end
end
end
class GoogleBot < R '/robots.txt'
PATH = File.expand_path(File.dirname(__FILE__))
def get
@headers['Content-Type'] = "text/plain"
"User-Agent: *\nDisallow: /"
end
end
class Static < R '/static/(.+)'
MIME_TYPES = {'.css' => 'text/css',
'.js' => 'text/javascript', '.json' => 'text/javascript',
'.jpg' => 'image/jpeg'}
PATH = File.expand_path(File.dirname(__FILE__))
def get(path)
@headers['Content-Type'] = MIME_TYPES[path[/\.\w+$/, 0]] || "text/plain"
unless path.include? ".." # prevent directory traversal attacks
@headers['X-Sendfile'] = "#{PATH}/static/#{path}"
else
@status = "403"
"403 - Invalid path"
end
end
end
class OAuthLogin < R '/login_with_oauth'
def self.consumer
@keys ||= YAML.load_file 'keys.yml'
# contains our app details
@consumer ||= OAuth::Consumer.new @keys['key'],
@keys['secret'], { :site => "http://twitter.com" }
end
def get
@request_token = OAuthLogin.consumer.get_request_token(:oauth_callback => "http://localhost:3301/consumer")
@state ||= {}
@state[:request_token] = @request_token.token
@state[:request_token_secret] = @request_token.secret
redirect @request_token.authorize_url
end
end
class OAuthConsumer < R '/consumer'
def get
raise "Bad session" if @state.nil? || @state == {}
@request_token = OAuth::RequestToken.new OAuthLogin.consumer,
@state[:request_token], @state[:request_token_secret]
begin
@access_token = @request_token.get_access_token(:oauth_verifier => input.oauth_verifier)
rescue OAuth::Unauthorized # refreshed?
if @state[:user_id]
return redirect("/")
else
redirect "/login_with_oauth"
end
end
@response = OAuthLogin.consumer.request(:get, '/account/verify_credentials.json',
@access_token, { :scheme => :query_string })
case @response
when Net::HTTPSuccess
user_info = JSON.parse(@response.body)
unless user_info['screen_name']
return "Bad login?"
end
# We have an authorized user, save the information to the database.
@user = User.new({ :username => user_info['screen_name'],
:token => @access_token.token,
:secret => @access_token.secret })
@user.save!
@state[:token] = @access_token.token
@state[:secret] = @access_token.secret
@state[:user_id] = @user.id
# http://localhost:3301/consumer?
redirect "/"
else
return "Authentication failed"
end
end
end
# The root slash shows the `index' view.
class Index < R '/(\w+)', '/'
def get
if @state[:user_id]
@user = User.find(@state[:user_id])
AdultFriendFinder.user = @user
@count = AdultFriendFinder.check_api_load
end
@names = input.names.to_s.split(/ and |\,|\s/).map &:strip
@ignore = input.ignore
return if @names.select { |name| name =~ /\// }.size > 0
if @names.any?
RECENT.push [@names]
begin
AdultFriendFinder.json @names
# @friends = AdultFriendFinder.compare @names
# @randoms = AdultFriendFinder.differ @names, @ignore
rescue Timeout::Error
# :( can't fetch data
rescue OpenURI::HTTPError
#@friends = "Error! Could not find one of those users."
#@randoms = []
end
end
render :index
end
end
end
module Views
# If you have a `layout' method like this, it
# will wrap the HTML in the other methods. The
# `self << yield' is where the HTML is inserted.
def layout
xhtml_strict do
head do
link :type => "text/css", :href => "/static/style.css", :rel => "Stylesheet"
link :type => "text/css", :href => "/static/slimbox.css", :rel => "Stylesheet"
script :type => "text/javascript", :src => "/static/twifter.js"
script :type => "text/javascript", :src => "/static/mootools.v1.00.js"
script :type => "text/javascript", :src => "/static/slimbox_ex_compressed.js"
# iterate over all the friends and pull their cached js
@names.each do |name|
script :type => "text/javascript", :src => "/cache/#{name}.js"
end
script :type => "text/javascript" do
self << "var compare = Twifter.compare(friends, #{@names.to_json});"
self << "var differ = Twifter.differ(friends, #{@names.to_json}, '#{@ignore}');"
end
title { 'Caboose Twifter' }
end #head
body do
div(:id=>'doc3') do
h1(:id=>'hd') do
self << a("twifter", :href => 'http://twitter.caboo.se')
self << a("login to twitter", :href => '/login_with_oauth', :class => "login") unless @state[:user_id]
self << a("Logged in as #{@user.username} [#{@count}]", :href => "http://twitter.com/#{@user.username}", :class => "login") if @user
end
self << yield
end
end
end
end
def index
# show the "Shared/unshared" crap if there are any names from the URL
shared if @names.any?
if @state[:user_id] # logged_in
# Show the form to enter new names
form(:class => 'comparator') do
h2 'How do I know you? :: Enter twitter usernames here:'
input :name => 'names', :type => 'text', :value => names.join(","), :style => 'width: 100%;font-size:200%'
p { "Separate with commas. Example: kirindave, fearoffish" }
input :type => 'submit', :value => 'do it'
end
# show the recent partial
recent
else
h2 'Login with twitter oauth first'
end
end
##################################
# Quote some text for javascript
def q(txt)
"'+#{txt}+'"
end
# Show the user info with javascript's document.write
def show_person(show_referred=false)
document_write( tr(:class => 'friend') {
td(:class=>'name') { q "compare[i]['name']" }
td { q "Twifter.link_to_person(compare[i])" }
td { q "Twifter.link_to_shared(compare[i], #{@names.to_json})" }
td { q "Twifter.link_to_all(compare[i])" }
# td { q "Twifter.link_to_iframe(compare[i])" }
td { q "Twifter.show_referred(compare[i])" } if show_referred
}) # tr
end
def document_write(txt)
"document.write('#{txt}');"
end
# This is the "shared/unshared" box. Todo: split this into a module.
def shared
div :class => 'shared' do
p do
span "Friends for "
names = @names.map do |name|
a "#{name}", :href => "/?names=#{(@names - [name]).join(",")}"
end
self << [ names.shift, names.any? ? names.join(", ") : [] ].flatten.compact.reverse.join(" and ")
span " (click to remove) "
end
end
div :class => "yui-g" do
div :class => "yui-u first" do
h1 'Shared friends'
p {
span(:id => "friend_size") { }
span " friend/s"
}
table do
script(:type=>'text/javascript') { self << "for (var i=0; i<compare.length; i++){#{show_person}}" }
end # table
end # div
div :class => "yui-u first", :id => 'unshared' do
h1 "Unshared friends"
form(:class=>'filter') do
input :type => 'hidden', :name => 'names', :value => @names.join(",")
span "hiding friends of "
select :name => 'ignore', :onchange => "this.form.submit()" do
option { "No-one" }
@names.each do |name|
option((@ignore == name ? { :selected => 'selected' } : {}).merge({ :value => name })) { name }
end
end
input :type => 'submit', :value => ">"
end
p {
span(:id => "random_size") {}
span(" random/s. Select your name to hide your existing friends.")
}
table do
script(:type=>'text/javascript') do
self << "document.getElementById('friend_size').innerHTML = compare.length; compare=differ;"
self << "document.getElementById('random_size').innerHTML = compare.length;"
self << "for (var i=0; i<compare.length; i++){#{show_person(true)}}"
end
end
div(:class=>'subfoot') do
self << "Shared acquaintances: "
9.times { |i|
span(:class=>"count_#{i}"){ i }
}
end
end
end
end # shared
def recent
div(:id => 'miframe', :style => 'height: 1px;width:1px') { self << "&nbsp" }
div :id => 'footer' do
h3 "Everyone's Recent searches"
ul do
RECENT.to_a.each do |friend|
p { a friend.join(" and "), :href => "/?names=#{friend.join(',')}" }
end # RECENT
end # ul
end
div(:id => "ft") do
div(:class=> 'yui-g') do
#div(:class=>'yui-u first') do
# a "About twifter", :href => "http://blog.caboo.se/articles/2007/4/6/twifter-find-shared-friends-on-twitter"
# span " | "
# a "Username? Password? wtf?", :href => "\#", :onclick => "$('sneaky').style.display='';return false"
#end
div(:class=>'yui-u'){ self << "&nbsp;"}
#div(:style => 'display:none',:id=>'sneaky', :class => 'yui-u') do
#p {
#self << "When you click 'add', we load up Twitter in an iframe so you can login to confirm the addition."
#self << "You should never trust boxes like this on the web; see "
#a "the wikipedia article on phishing", :href => "http://en.wikipedia.org/wiki/Phishing"
#self << ", for more information. Regardless, if you decide to trust us, click the 'add' button "
#self << " and we'll pop up an iframe for you to login to twitter. You will be logged out each time"
#self << " because of the strict referer checking at Twitter. Yes, this is a huge workaround."
#self << " Again, it's up to you whether you trust us or not. The javascript source code is available at "
#a "/static/twifter.js", :href => "/static/twifter.js"
#}
# => end
end
end # div
end #recent
end
end
Something went wrong with that request. Please try again.