Merge branch 'master' of github.com:diaspora/diaspora

This commit is contained in:
maxwell 2010-11-17 16:18:07 -08:00
commit c08a991130
11 changed files with 103 additions and 69 deletions

View file

@ -43,6 +43,7 @@ gem 'magent', :git => 'git://github.com/maxwell/magent.git'
gem 'carrierwave', :git => 'git://github.com/rsofaer/carrierwave.git' , :branch => 'master' #Untested mongomapper branch gem 'carrierwave', :git => 'git://github.com/rsofaer/carrierwave.git' , :branch => 'master' #Untested mongomapper branch
gem 'mini_magick' gem 'mini_magick'
gem 'aws' gem 'aws'
gem 'fastercsv', :require => false
group :test, :development do group :test, :development do
gem 'factory_girl_rails' gem 'factory_girl_rails'

View file

@ -48,7 +48,7 @@ GIT
GIT GIT
remote: git://github.com/maxwell/magent.git remote: git://github.com/maxwell/magent.git
revision: af5ad4b58e27fc0ca49bea8ab11ec3f746e92f33 revision: 534977e482cc6d9a205c6d67da6ccbb2486db5a8
specs: specs:
magent (0.5.1) magent (0.5.1)
em-websocket em-websocket
@ -173,6 +173,7 @@ GEM
addressable (~> 2.2.2) addressable (~> 2.2.2)
multipart-post (~> 1.0.1) multipart-post (~> 1.0.1)
rack (>= 1.1.0, < 2) rack (>= 1.1.0, < 2)
fastercsv (1.5.3)
fastthread (1.0.7) fastthread (1.0.7)
ffi (0.6.3) ffi (0.6.3)
rake (>= 0.8.7) rake (>= 0.8.7)
@ -365,6 +366,7 @@ DEPENDENCIES
em-http-request! em-http-request!
em-websocket! em-websocket!
factory_girl_rails factory_girl_rails
fastercsv
haml haml
http_accept_language! http_accept_language!
jasmine! jasmine!

View file

@ -14,6 +14,7 @@ class CommentsController < ApplicationController
@comment = current_user.comment(text, :on => target) if target @comment = current_user.comment(text, :on => target) if target
if @comment if @comment
Rails.logger.info("event=comment_create user=#{current_user.inspect} status=success comment=#{@comment.inspect}")
render :nothing => true, :status => 201 render :nothing => true, :status => 201
else else
render :nothing => true, :status => 401 render :nothing => true, :status => 401

View file

@ -104,12 +104,14 @@ class PeopleController < ApplicationController
def webfinger(account, opts = {}) def webfinger(account, opts = {})
finger = EMWebfinger.new(account) finger = EMWebfinger.new(account)
finger.on_person do |response| finger.on_person do |response|
Rails.logger.info("event=controller_webfinger status=callback response=#{response.inspect}")
if response.class == Person if response.class == Person
response.socket_to_uid(current_user.id, opts) response.socket_to_uid(current_user.id, opts)
else else
require File.join(Rails.root,'lib/diaspora/websocket') require File.join(Rails.root,'lib/diaspora/websocket')
Diaspora::WebSocket.queue_to_user(current_user.id, {:class => 'people', :status => 'fail', :query => account, :response => response}.to_json) Diaspora::WebSocket.queue_to_user(current_user.id, {:class => 'people', :status => 'fail', :query => account, :response => response}.to_json)
end end
Rails.logger.info("event=controller_webfinger status=callback_complete response=#{response.inspect}")
end end
end end
end end

View file

@ -11,8 +11,10 @@ class RegistrationsController < Devise::RegistrationsController
flash[:notice] = I18n.t 'registrations.create.success' flash[:notice] = I18n.t 'registrations.create.success'
@user.seed_aspects @user.seed_aspects
sign_in_and_redirect(:user, @user) sign_in_and_redirect(:user, @user)
Rails.logger.info("event=registration status=successful user=#{@user.inspect}")
else else
flash[:error] = @user.errors.full_messages.join(', ') flash[:error] = @user.errors.full_messages.join(', ')
Rails.logger.info("event=registration status=failure errors=#{@user.errors.full_messages.join(', ')}")
render :new render :new
end end
end end

View file

@ -29,7 +29,8 @@ class Retraction
Rails.logger.debug "Performing retraction for #{post_id}" Rails.logger.debug "Performing retraction for #{post_id}"
if self.type.constantize.find_by_id(post_id) if self.type.constantize.find_by_id(post_id)
unless Post.first(:diaspora_handle => person.diaspora_handle, :id => post_id) unless Post.first(:diaspora_handle => person.diaspora_handle, :id => post_id)
raise "#{person.inspect} is trying to retract a post they do not own" Rails.logger.info("event=retraction status=abort reason='no post found authored by retractor' sender=#{person.diaspora_handle} post_id=#{post_id}")
raise "#{person.inspect} is trying to retract a post that either doesn't exist or is not by them"
end end
begin begin
@ -38,7 +39,7 @@ class Retraction
target.unsocket_from_uid receiving_user_id if target.respond_to? :unsocket_from_uid target.unsocket_from_uid receiving_user_id if target.respond_to? :unsocket_from_uid
target.delete target.delete
rescue NameError rescue NameError
Rails.logger.info("Retraction for unknown type recieved.") Rails.logger.info("event=retraction status=abort reason='unknown type'")
end end
end end
end end

View file

@ -9,15 +9,6 @@
= f.label :password_confirmation = f.label :password_confirmation
= f.password_field :password_confirmation = f.password_field :password_confirmation
= f.fields_for :person do |p|
= p.fields_for :profile do |pr|
%p
= pr.label :first_name
= pr.text_field :first_name
%p
= pr.label :last_name
= pr.text_field :last_name
= f.hidden_field :invitation_token = f.hidden_field :invitation_token
= f.submit 'sign_up' = f.submit 'sign_up'
= render :partial => "devise/shared/links" = render :partial => "devise/shared/links"

View file

@ -22,7 +22,7 @@ module Diaspora
def receive xml, salmon_author def receive xml, salmon_author
object = Diaspora::Parser.from_xml(xml) object = Diaspora::Parser.from_xml(xml)
Rails.logger.debug("event=receive recipient=#{self.inspect} object=#{object.inspect} sender=#{salmon_author.inspect}") Rails.logger.info("event=receive status=start recipient=#{self.diaspora_handle} object=#{object.inspect} sender=#{salmon_author.diaspora_handle}")
if object.is_a?(Request) if object.is_a?(Request)
salmon_author.save salmon_author.save
@ -36,25 +36,22 @@ module Diaspora
end end
if (salmon_author.diaspora_handle != xml_author) if (salmon_author.diaspora_handle != xml_author)
raise "Malicious Post, #{salmon_author.real_name} with handle #{salmon_author.diaspora_handle} is sending a #{object.class} as #{xml_author} " Rails.logger.info("event=receive status=abort reason='author in xml does not match retrieved person' recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload=#{object.inspect}")
return
end end
if object.is_a?(Comment) || object.is_a?(Post)|| object.is_a?(Request) || object.is_a?(Retraction) || object.is_a?(Profile)
e = EMWebfinger.new(object.diaspora_handle) e = EMWebfinger.new(object.diaspora_handle)
e.on_person do |person| e.on_person do |person|
if person.class == Person if person.class == Person
object.person = person if object.respond_to? :person= object.person = person if object.respond_to? :person=
unless object.is_a?(Request) || self.contact_for(salmon_author) unless object.is_a?(Request) || self.contact_for(salmon_author)
raise "Not connected to that person" Rails.logger.info("event=receive status=abort reason='sender not connected to recipient' recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload=#{object.inspect}")
return
else else
return receive_object(object,person) return receive_object(object,person)
end end
end end
end
else
raise "you messed up"
end end
end end
@ -76,7 +73,8 @@ module Diaspora
def receive_retraction retraction def receive_retraction retraction
if retraction.type == 'Person' if retraction.type == 'Person'
unless retraction.person.id.to_s == retraction.post_id.to_s unless retraction.person.id.to_s == retraction.post_id.to_s
raise "#{retraction.diaspora_handle} trying to disconnect #{retraction.post_id} from #{self.id}" Rails.logger.info("event=receive status=abort reason='sender is not the person he is trying to retract' recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload=#{retraction.inspect}")
return
end end
Rails.logger.info( "the person id is #{retraction.post_id} the contact found is #{visible_person_by_id(retraction.post_id).inspect}") Rails.logger.info( "the person id is #{retraction.post_id} the contact found is #{visible_person_by_id(retraction.post_id).inspect}")
disconnected_by visible_person_by_id(retraction.post_id) disconnected_by visible_person_by_id(retraction.post_id)
@ -100,7 +98,10 @@ module Diaspora
end end
def receive_comment comment def receive_comment comment
raise "In receive for #{self.real_name}, signature was not valid on: #{comment.inspect}" unless comment.post.person == self.person || comment.verify_post_creator_signature unless comment.post.person == self.person || comment.verify_post_creator_signature
Rails.logger.info("event=receive status=abort reason='comment signature not valid' recipient=#{self.diaspora_handle} sender=#{salmon_author.diaspora_handle} payload=#{retraction.inspect}")
return
end
self.visible_people = self.visible_people | [comment.person] self.visible_people = self.visible_people | [comment.person]
self.save self.save
Rails.logger.debug("The person parsed from comment xml is #{comment.person.inspect}") unless comment.person.nil? Rails.logger.debug("The person parsed from comment xml is #{comment.person.inspect}") unless comment.person.nil?

View file

@ -14,11 +14,16 @@ class EMWebfinger
#raise "Identifier is invalid" if !(@account=~ /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/) #raise "Identifier is invalid" if !(@account=~ /^[a-zA-Z][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/)
end end
def fetch def fetch
raise 'you need to set a callback before calling fetch' if @callbacks.empty? if @callbacks.empty?
Rails.logger.info("event=EMWebfinger status=abort target=#{account} callbacks=empty")
raise 'you need to set a callback before calling fetch'
end
person = Person.by_account_identifier(@account) person = Person.by_account_identifier(@account)
if person if person
Rails.logger.info("event=EMWebfinger status=local target=#{account}")
process_callbacks person process_callbacks person
else else
Rails.logger.info("event=EMWebfinger status=remote target=#{account}")
get_xrd get_xrd
end end
end end
@ -77,6 +82,7 @@ class EMWebfinger
def process_callbacks(person) def process_callbacks(person)
Rails.logger.info("event=EMWebfinger status=callbacks_started response=#{person.inspect}")
@callbacks.each { |c| @callbacks.each { |c|
begin begin
c.call(person) c.call(person)
@ -84,7 +90,7 @@ class EMWebfinger
Rails.logger.info("event=EMWebfinger status=error_on_callback error=#{e.inspect}") Rails.logger.info("event=EMWebfinger status=error_on_callback error=#{e.inspect}")
end end
} }
Rails.logger.info("event=EMWebfinger status=complete person=#{person.inspect}") Rails.logger.info("event=EMWebfinger status=complete response=#{person.inspect}")
end end

View file

@ -0,0 +1,31 @@
# Copyright (c) 2010, Diaspora Inc. This file is
# licensed under the Affero General Public License version 3 or later. See
# the COPYRIGHT file.
namespace :invites do
desc 'send a bunch of invites from a csv with rows of name, email'
task :send, :filename, :number, :start do
unless args[:filename] && args[:number] && args[:start]
raise "please give me {filename} {number of people to churn}, {where to start in the file}"
end
require File.dirname(__FILE__) + '/../../config/environment'
require 'fastercsv'
filename = args[:filename]
start = args[:start].to_i || 0
number_of_backers = args[:number].to_i || 1000
offset = 1 + start
puts "emailing #{number_of_backers} listed in #{filename} starting at #{start}"
backers = FasterCSV.read("bkr.csv")
#number_of_backers.times do |n|
# backer_name = backers[n+offset][0]
# backer_email = backers[n+offset][1].gsub('.ksr', '')
# send_email(backer_name, backer_email)
#end
end
end

View file

@ -19,18 +19,16 @@ describe "attack vectors" do
context 'non-contact valid user' do context 'non-contact valid user' do
it 'raises if receives post by non-contact' do it 'does not save a post from a non-contact' do
post_from_non_contact = bad_user.build_post( :status_message, :message => 'hi') post_from_non_contact = bad_user.build_post( :status_message, :message => 'hi')
xml = bad_user.salmon(post_from_non_contact).xml_for(user.person) xml = bad_user.salmon(post_from_non_contact).xml_for(user.person)
post_from_non_contact.delete post_from_non_contact.delete
bad_user.delete bad_user.delete
post_count = Post.count post_count = Post.count
proc{ user.receive_salmon(xml) }.should raise_error /Not connected to that person/
user.receive_salmon(xml)
user.raw_visible_posts.include?(post_from_non_contact).should be false user.raw_visible_posts.include?(post_from_non_contact).should be false
Post.count.should == post_count Post.count.should == post_count
end end
@ -52,33 +50,34 @@ describe "attack vectors" do
connect_users(user, aspect, user3, aspect3) connect_users(user, aspect, user3, aspect3)
end end
describe 'mass assignment on id' do
it 'overwrites messages with a different user' do it "does not save a message over an old message with a different author" do
original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id
user.receive_salmon(user2.salmon(original_message).xml_for(user.person)) user.receive_salmon(user2.salmon(original_message).xml_for(user.person))
user.raw_visible_posts.count.should be 1
lambda {
malicious_message = Factory.build( :status_message, :id => original_message.id, :message => 'BAD!!!', :person => user3.person) malicious_message = Factory.build( :status_message, :id => original_message.id, :message => 'BAD!!!', :person => user3.person)
proc{user.receive_salmon(user3.salmon(malicious_message).xml_for(user.person))}.should raise_error /Malicious Post/ user.receive_salmon(user3.salmon(malicious_message).xml_for(user.person))
}.should_not change{user.reload.raw_visible_posts.count}
user.raw_visible_posts.count.should be 1 original_message.reload.message.should == "store this!"
user.raw_visible_posts.first.message.should == "store this!" user.raw_visible_posts.first.message.should == "store this!"
end end
it 'overwrites messages which apear to be from the same user' do it 'does not save a message over an old message with the same author' do
original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id
user.receive_salmon(user2.salmon(original_message).xml_for(user.person)) user.receive_salmon(user2.salmon(original_message).xml_for(user.person))
user.raw_visible_posts.count.should be 1
lambda {
malicious_message = Factory.build( :status_message, :id => original_message.id, :message => 'BAD!!!', :person => user2.person) malicious_message = Factory.build( :status_message, :id => original_message.id, :message => 'BAD!!!', :person => user2.person)
proc{user.receive_salmon(user3.salmon(malicious_message).xml_for(user.person))}.should raise_error /Malicious Post/ user.receive_salmon(user3.salmon(malicious_message).xml_for(user.person))
}.should_not change{user.reload.raw_visible_posts.count}
original_message.reload.message.should == "store this!"
user.raw_visible_posts.count.should be 1
user.raw_visible_posts.first.message.should == "store this!" user.raw_visible_posts.first.message.should == "store this!"
end end
end
it 'should not overwrite another persons profile profile' do it 'should not overwrite another persons profile profile' do
profile = user2.profile.clone profile = user2.profile.clone
profile.first_name = "Not BOB" profile.first_name = "Not BOB"
@ -86,12 +85,12 @@ describe "attack vectors" do
user2.reload user2.reload
first_name = user2.profile.first_name first_name = user2.profile.first_name
proc{user.receive_salmon(user3.salmon(profile).xml_for(user.person))}.should raise_error /Malicious Post/ user.receive_salmon(user3.salmon(profile).xml_for(user.person))
user2.reload user2.reload
user2.profile.first_name.should == first_name user2.profile.first_name.should == first_name
end end
it 'should not receive retractions on post you do not own' do it "ignores retractions on a post not owned by the retraction's sender" do
original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id
user.receive_salmon(user2.salmon(original_message).xml_for(user.person)) user.receive_salmon(user2.salmon(original_message).xml_for(user.person))
user.raw_visible_posts.count.should be 1 user.raw_visible_posts.count.should be 1
@ -101,12 +100,12 @@ describe "attack vectors" do
ret.diaspora_handle = user3.person.diaspora_handle ret.diaspora_handle = user3.person.diaspora_handle
ret.type = original_message.class.to_s ret.type = original_message.class.to_s
proc{ user.receive_salmon(user3.salmon(ret).xml_for(user.person)) }.should raise_error /is trying to retract a post they do not own/ user.receive_salmon(user3.salmon(ret).xml_for(user.person))
StatusMessage.count.should be 1 StatusMessage.count.should be 1
user.reload.raw_visible_posts.count.should be 1 user.reload.raw_visible_posts.count.should be 1
end end
it 'should disregard retractions for a non-existant posts' do it "disregards retractions for non-existent posts that are from someone other than the post's author" do
original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id original_message = user2.post :status_message, :message => 'store this!', :to => aspect2.id
id = original_message.reload.id id = original_message.reload.id
@ -131,8 +130,9 @@ describe "attack vectors" do
ret.diaspora_handle = user2.person.diaspora_handle ret.diaspora_handle = user2.person.diaspora_handle
ret.type = original_message.class.to_s ret.type = original_message.class.to_s
proc{ user.receive_salmon(user3.salmon(ret).xml_for(user.person)) }.should raise_error /Malicious Post/ lambda {
StatusMessage.count.should be 1 user.receive_salmon(user3.salmon(ret).xml_for(user.person))
}.should_not change(StatusMessage, :count)
user.reload.raw_visible_posts.count.should be 1 user.reload.raw_visible_posts.count.should be 1
end end
@ -144,9 +144,7 @@ describe "attack vectors" do
proc{ proc{
user.receive_salmon(user3.salmon(ret).xml_for(user.person)) user.receive_salmon(user3.salmon(ret).xml_for(user.person))
}.should raise_error /#{user3.diaspora_handle} trying to disconnect #{user2.person.id} from #{user.id}/ }.should_not change{user.reload.contacts.count}
user.reload.contacts.count.should == 2
end end
it 'it should not allow you to send retractions with xml and salmon handle mismatch' do it 'it should not allow you to send retractions with xml and salmon handle mismatch' do
@ -157,9 +155,7 @@ describe "attack vectors" do
proc{ proc{
user.receive_salmon(user3.salmon(ret).xml_for(user.person)) user.receive_salmon(user3.salmon(ret).xml_for(user.person))
}.should raise_error /Malicious Post/ }.should_not change{user.reload.contacts.count}
user.reload.contacts.count.should == 2
end end
it 'does not let me update other persons post' do it 'does not let me update other persons post' do