diff --git a/.gitignore b/.gitignore index 91e987e1c..40116a515 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ tmp/**/* Gemfile.lock gpg/diaspora-development/*.gpg gpg/diaspora-production/*.gpg +gpg/*/random_seed diff --git a/Gemfile b/Gemfile index e65b8d357..d40e7b65f 100644 --- a/Gemfile +++ b/Gemfile @@ -2,12 +2,12 @@ source 'http://rubygems.org' source 'http://gemcutter.org' gem 'rails', '3.0.0.beta4' -gem 'bundler' +gem 'bundler', '0.9.26' gem 'mongo_mapper', :git => "http://github.com/BadMinus/mongomapper.git" gem 'devise', :git => "http://github.com/BadMinus/devise.git" gem 'jnunemaker-validatable', :git => "http://github.com/BadMinus/validatable.git" gem 'mongo_ext' -gem "bson_ext", "1.0.1" +gem 'bson_ext' gem "haml" gem 'roxml', :git => "git://github.com/Empact/roxml.git" @@ -25,9 +25,9 @@ gem 'will_paginate', '3.0.pre' group :test do - gem 'rspec', '>= 2.0.0.beta.12' - gem 'rspec-rails', ">= 2.0.0.beta.8" - gem "mocha" + gem 'rspec', '>= 2.0.0.beta.17' + gem 'rspec-rails', '2.0.0.beta.17' + gem "mocha" gem 'webrat' gem 'redgreen' gem 'autotest' diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb index 10d0b8fd0..aa0780f87 100644 --- a/app/controllers/dashboards_controller.rb +++ b/app/controllers/dashboards_controller.rb @@ -16,7 +16,7 @@ class DashboardsController < ApplicationController def warzombie render :nothing => true - if User.owner.email == "tom@joindiaspora.com" && StatusMessage.where(:message => "There's a bomb in the lasagna!?").first == nil + if User.owner.email == "tom@tom.joindiaspora.com" && StatusMessage.where(:message => "There's a bomb in the lasagna!?").first == nil StatusMessage.create(:message => "There's a bomb in the lasagna!?", :person => User.owner) Bookmark.create(:title => "xkcd", :link => "http://xkcd.com/743/", :person => User.owner ) StatusMessage.create(:message => "I switched to Motoroi today, a Motorola Android-based phone, in Korea. Now, I am using Android phones in both the U.S. and Korea", :person => User.owner, :created_at => Time.now-930) @@ -33,4 +33,30 @@ class DashboardsController < ApplicationController StatusMessage.create(:message => "A cool, cool morning for once.", :person => User.owner, :created_at => Time.now-150000) end end + + def zombiefriends + render :nothing => true + backer_info = ["http://washington.joindiaspora.com/", + "http://adams.joindiaspora.com/", + "http://jefferson.joindiaspora.com/", + "http://madison.joindiaspora.com/", + "http://monroe.joindiaspora.com/", + "http://quincyadams.joindiaspora.com/", + "http://jackson.joindiaspora.com/", + "http://buren.joindiaspora.com/", + "http://harrison.joindiaspora.com/", + "http://tyler.joindiaspora.com/", + "http://polk.joindiaspora.com/", + #"http://taylor.joindiaspora.com/", + #"http://fillmore.joindiaspora.com/", + #"http://pierce.joindiaspora.com/", + ] + + if User.owner.email == "tom@tom.joindiaspora.com" && Person.friends.first.nil? + backer_info.each do |backer| + logger.info "Zombefriending #{backer}" + User.owner.send_friend_request_to(backer) + end + end + end end diff --git a/app/models/comment.rb b/app/models/comment.rb index b1cdc493b..8fbd9dd0c 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -2,12 +2,13 @@ class Comment include MongoMapper::Document include ROXML include Diaspora::Webhooks - + include Encryptable xml_accessor :text xml_accessor :person, :as => Person xml_accessor :post_id + key :text, String timestamps! @@ -25,10 +26,47 @@ class Comment (self.message == other.message) && (self.person.email == other.person.email) end + #ENCRYPTION + + before_validation :sign_if_mine, :sign_if_my_post + #validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature} + validates_true_for :post_creator_signature, :logic => lambda {self.verify_post_creator_signature} + + xml_accessor :creator_signature + key :creator_signature, String + key :post_creator_signature, String + + def signable_accessors + accessors = self.class.roxml_attrs.collect{|definition| + definition.accessor} + accessors.delete 'person' + accessors.delete 'creator_signature' + accessors.delete 'post_creator_signature' + accessors + end + + def signable_string + signable_accessors.collect{|accessor| + (self.send accessor.to_sym).to_s}.join ';' + end + + def verify_post_creator_signature + unless person == User.owner + verify_signature(post_creator_signature, post.person) + else + true + end + end + protected - - def send_people_comments_on_my_posts + def sign_if_my_post + if self.post.person == User.owner + self.post_creator_signature = sign + end + end + + def send_people_comments_on_my_posts if User.owner.mine?(self.post) && !(self.person.is_a? User) self.push_to(self.post.people_with_permissions) end diff --git a/app/models/person.rb b/app/models/person.rb index c60f74968..968ba5dd7 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -5,6 +5,7 @@ class Person xml_accessor :_id xml_accessor :email xml_accessor :url + xml_accessor :key_fingerprint xml_accessor :profile, :as => Profile @@ -13,19 +14,19 @@ class Person key :active, Boolean, :default => false key :key_fingerprint, String - one :profile, :class_name => 'Profile', :foreign_key => :person_id + one :profile, :class_name => 'Profile' many :posts, :class_name => 'Post', :foreign_key => :person_id timestamps! before_validation :clean_url - validates_presence_of :email, :url + validates_presence_of :email, :url, :key_fingerprint validates_format_of :url, :with => /^(https?):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(\.[a-z]{2,5})?(:[0-9]{1,5})?(\/.*)?$/ix validates_true_for :url, :logic => lambda { self.url_unique?} - after_destroy :remove_all_traces + after_destroy :remove_all_traces, :remove_key scope :friends, where(:_type => "Person", :active => true) @@ -38,7 +39,10 @@ class Person def key GPGME::Ctx.new.get_key key_fingerprint end - + + def export_key + GPGME::export(key_fingerprint, :armor => true) + end protected @@ -59,9 +63,11 @@ class Person def remove_all_traces self.posts.delete_all - Comment.delete_all(:person_id => self.id) end - + def remove_key + ctx = GPGME::Ctx.new + ctx.delete_key(key) + end end diff --git a/app/models/post.rb b/app/models/post.rb index fec801a71..9b711d6ce 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -4,12 +4,13 @@ class Post include MongoMapper::Document include ROXML include Diaspora::Webhooks + include Encryptable xml_accessor :_id xml_accessor :person, :as => Person key :person_id, ObjectId - + many :comments, :class_name => 'Comment', :foreign_key => :post_id belongs_to :person, :class_name => 'Person' @@ -42,9 +43,28 @@ class Post self.newest(Person.first(:email => email)) end +#ENCRYPTION + before_validation :sign_if_mine + validates_true_for :creator_signature, :logic => lambda {self.verify_creator_signature} + + xml_accessor :creator_signature + key :creator_signature, String + + def signable_accessors + accessors = self.class.roxml_attrs.collect{|definition| + definition.accessor} + accessors.delete 'person' + accessors.delete 'creator_signature' + accessors + end - protected - def destroy_comments + def signable_string + signable_accessors.collect{|accessor| + (self.send accessor.to_sym).to_s}.join ';' + end + +protected + def destroy_comments comments.each{|c| c.destroy} end diff --git a/app/models/profile.rb b/app/models/profile.rb index 13febaaf3..165d6a18f 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -1,5 +1,5 @@ class Profile - include MongoMapper::Document + include MongoMapper::EmbeddedDocument include ROXML xml_accessor :first_name @@ -8,10 +8,6 @@ class Profile key :first_name, String key :last_name, String - key :person_id, ObjectId - - belongs_to :person - - validates_presence_of :first_name, :last_name, :person_id + validates_presence_of :first_name, :last_name end diff --git a/app/models/request.rb b/app/models/request.rb index f59c57d37..c3962a0f5 100644 --- a/app/models/request.rb +++ b/app/models/request.rb @@ -8,10 +8,12 @@ class Request xml_accessor :person, :as => Person xml_accessor :destination_url xml_accessor :callback_url + xml_accessor :exported_key, :cdata => true key :destination_url, String key :callback_url, String key :person_id, ObjectId + key :exported_key, String belongs_to :person @@ -27,7 +29,7 @@ class Request def self.instantiate(options ={}) person = options[:from] - self.new(:destination_url => options[:to], :callback_url => person.url, :person => person) + self.new(:destination_url => options[:to], :callback_url => person.url, :person => person, :exported_key => person.export_key) end def activate_friend diff --git a/app/models/user.rb b/app/models/user.rb index 9b9a456a4..a9cdf0cd8 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,7 +4,7 @@ class User < Person :recoverable, :rememberable, :trackable, :validatable - #before_create :assign_key + before_validation :assign_key validates_presence_of :profile before_validation :do_bad_things @@ -31,7 +31,6 @@ class User < Person def send_friend_request_to(friend_url) unless Person.where(:url => friend_url).first p = Request.instantiate(:to => friend_url, :from => self) - puts p.inspect if p.save p.push_to_url friend_url end @@ -43,6 +42,7 @@ class User < Person request = Request.where(:id => friend_request_id).first request.activate_friend request.person = self + request.exported_key = self.export_key request.destination_url = request.callback_url request.push_to_url(request.callback_url) request.destroy @@ -56,10 +56,12 @@ class User < Person end def receive_friend_request(friend_request) + GPGME.import(friend_request.exported_key) if Request.where(:callback_url => friend_request.callback_url).first friend_request.activate_friend friend_request.destroy else + friend_request.person.save friend_request.save end end @@ -89,17 +91,23 @@ class User < Person protected def assign_key - keys = GPGME.list_keys(nil, true) + keys = GPGME.list_keys(real_name, true) if keys.empty? - #generate_key + generate_key end - self.key_fingerprint = GPGME.list_keys(nil, true).first.subkeys.first.fingerprint + self.key_fingerprint = GPGME.list_keys(real_name, true).first.subkeys.first.fingerprint end def generate_key puts "Generating key" + puts paramstring ctx = GPGME::Ctx.new - paramstring = " + ctx.genkey(paramstring, nil, nil) + + end + + def paramstring +" Key-Type: DSA Key-Length: 512 Subkey-Type: ELG-E @@ -108,9 +116,7 @@ Name-Real: #{self.real_name} Name-Comment: #{self.url} Name-Email: #{self.email} Expire-Date: 0 -Passphrase: #{self.password} " - ctx.genkey(paramstring, nil, nil) - + end end diff --git a/app/views/people/show.html.haml b/app/views/people/show.html.haml index 50050d2eb..ee0892315 100644 --- a/app/views/people/show.html.haml +++ b/app/views/people/show.html.haml @@ -1,6 +1,10 @@ .span-20.last %h1= "#{@person.real_name}" = link_to 'remove friend', @person, :confirm => 'Are you sure?', :method => :delete +%p + %b Active? +%p + = @person.active - if @person_profile %p %b First Name diff --git a/config/environments/test.rb b/config/environments/test.rb index 7f40c884b..2611a12fa 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -26,7 +26,8 @@ Diaspora::Application.configure do config.action_mailer.delivery_method = :test config.threadsafe! - + ENV['GNUPGHOME'] = File.expand_path("../../gpg/diaspora-#{Rails.env}/", __FILE__) + GPGME::check_version({}) # Use SQL instead of Active Record's schema dumper when creating the test database. # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types diff --git a/config/routes.rb b/config/routes.rb index 06f7cbe0d..47f98ed93 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,7 +6,8 @@ Diaspora::Application.routes.draw do |map| resources :comments resources :requests - match 'warzombie', :to => "dashboard#warzombie" + match 'warzombie', :to => "dashboards#warzombie" + match 'zombiefriends', :to => "dashboards#zombiefriends" #routes for devise, not really sure you will need to mess with this in the future, lets put default, #non mutable stuff in anohter file diff --git a/db/seeds.rb b/db/seeds.rb index 654131687..499f3a30a 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -9,7 +9,7 @@ require 'config/environment' # Create seed user -user = User.create( :email => "tom@joindiaspora.com", :password => "aaaaaa", :profile => Profile.create( :first_name => "Diaspora", :last_name => "Tom" )) +user = User.create( :email => "tom@joindiaspora.com", :password => "aaaaaa", :profile => Profile.new( :first_name => "Diaspora", :last_name => "Tom" )) names = [ ["George", "Washington"], ["John", "Adams"], @@ -31,7 +31,7 @@ names = [ ["George", "Washington"], # Make people (1..10).each { |n| - People.create( :email => "b#{n}@joindiaspora.com", :url => "http://b#{n}.joindiaspora.com/", :profile => Profile.create(:first_name => names[n-1][0], :last_name => names[n-1][1])) + People.create( :email => "b#{n}@joindiaspora.com", :url => "http://b#{n}.joindiaspora.com/", :profile => Profile.new(:first_name => names[n-1][0], :last_name => names[n-1][1])) } # Populate feed diff --git a/db/seeds/backer.rb b/db/seeds/backer.rb index 13be3e6be..d06379762 100644 --- a/db/seeds/backer.rb +++ b/db/seeds/backer.rb @@ -10,7 +10,7 @@ require 'config/environment' -def create(backer_number, password) +def create(backer_number) backer_info = [ [5072,"George", "Washington"], [3742,"John", "Adams"], [7782,"Thomas", "Jefferson"], @@ -51,22 +51,21 @@ def create(backer_number, password) # Create seed user - email = backer_info[backer_number][2].gsub(/ /,'').downcase - user = User.create( :email => "#{email}@joindiaspora.com", - :password => "#{email+backer_info[backer_number][0].to_s}", - :profile => Profile.create( :first_name => backer_info[backer_number][1], :last_name => backer_info[backer_number][2] ), - :url=> "#{email}.joindiaspora.com") + username = backer_info[backer_number][2].gsub(/ /,'').downcase + user = User.create( :email => "#{username}@#{username}joindiaspora.com", + :password => "#{username+backer_info[backer_number][0].to_s}", + :profile => Profile.new( :first_name => backer_info[backer_number][1], :last_name => backer_info[backer_number][2] ), + :url=> "#{username}.joindiaspora.com") # Make connection with Diaspora Tom - Person.create( :email => "tom@joindiaspora.com", :url => "http://tom.joindiaspora.com/", :active => true, :profile => Profile.create(:first_name => "Alexander", :last_name => "Hamiltom")) + User.owner.send_friend_request_to('http://tom.joindiaspora.com/') + #Person.create( :email => "tom@joindiaspora.com", :url => "http://tom.joindiaspora.com/", :active => true, :profile => Profile.new(:first_name => "Alexander", :last_name => "Hamiltom")) # Make people - (0..10).each { |n| - email = backer_info[n][2].gsub(/ /,'').downcase - Person.create( :email => "#{email}@joindiaspora.com", - :url => "http://#{email}.joindiaspora.com/", - :active => true, - :profile => Profile.create(:first_name => backer_info[n][1], :last_name => backer_info[n][2])) unless n == backer_number - } +# (0..10).each { |n| + #domain_name = backer_info[n][2].gsub(/ /,'').downcase + #url = "http://#{domain_name}.joindiaspora.com/" + #User.owner.send_friend_request_to(url) + #} end diff --git a/db/seeds/dev.rb b/db/seeds/dev.rb index d5a71b3c7..1c285c59b 100644 --- a/db/seeds/dev.rb +++ b/db/seeds/dev.rb @@ -9,7 +9,7 @@ require 'config/environment' # Create seed user -user = User.create( :email => "robert@joindiaspora.com", :password => "monkey", :profile => Profile.create( :first_name => "bobert", :last_name => "brin" )) +user = User.create( :email => "robert@joindiaspora.com", :password => "monkey", :profile => Profile.new( :first_name => "bobert", :last_name => "brin" )) names = [ ["George", "Washington"], ["John", "Adams"], @@ -51,8 +51,8 @@ names = [ ["George", "Washington"], # Make people (0..10).each { |n| - email = names[n][1].gsub(/ /,'').downcase - Person.create( :email => "#{email}@joindiaspora.com", :url => "http://#{email}.joindiaspora.com/", :active => true, :profile => Profile.create(:first_name => names[n][0], :last_name => names[n][1])) + username = names[n][1].gsub(/ /,'').downcase + Person.create( :email => "#{username}@#{username}joindiaspora.com", :url => "http://#{username}.joindiaspora.com/", :active => true, :profile => Profile.new(:first_name => names[n][0], :last_name => names[n][1])) } diff --git a/db/seeds/request.rb b/db/seeds/request.rb new file mode 100644 index 000000000..b0c652ca8 --- /dev/null +++ b/db/seeds/request.rb @@ -0,0 +1,6 @@ + +require 'config/environment' + +Request.all.each{|r| + User.owner.accept_friend_request(r.id) +} diff --git a/db/seeds/tom.rb b/db/seeds/tom.rb index 85170c013..364580fed 100644 --- a/db/seeds/tom.rb +++ b/db/seeds/tom.rb @@ -1,4 +1,4 @@ -# This file should contain all the record creation needed to seed the database with its default values. +#This file should contain all the record creation needed to seed the database with its default values. # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). # # Examples: @@ -9,7 +9,7 @@ require 'config/environment' # Create seed user -user = User.create( :email => "tom@joindiaspora.com", :password => "evankorth", :url => "http://tom.joindiaspora.com/", :profile => Profile.create( :first_name => "Alexander", :last_name => "Hamiltom" )) +user = User.create( :email => "tom@tom.joindiaspora.com", :password => "evankorth", :url => "http://tom.joindiaspora.com/", :profile => Profile.new( :first_name => "Alexander", :last_name => "Hamiltom" )) names = [ ["George", "Washington"], ["John", "Adams"], @@ -50,9 +50,9 @@ names = [ ["George", "Washington"], ] # Make people -(0..10).each { |n| - email = names[n][1].gsub(/ /,'').downcase - Person.create( :email => "#{email}@joindiaspora.com", :url => "http://#{email}.joindiaspora.com/", :active => true, :profile => Profile.create(:first_name => names[n][0], :last_name => names[n][1])) -} +#(0..10).each { |n| + #email = names[n][1].gsub(/ /,'').downcase + #Person.create( :email => "#{email}@joindiaspora.com", :url => "http://#{email}.joindiaspora.com/", :active => true, :profile => Profile.new(:first_name => names[n][0], :last_name => names[n][1])) +#} diff --git a/gpg/diaspora-test/pubring.gpg b/gpg/diaspora-test/pubring.gpg index 33ce2b7d9..413a37f87 100644 Binary files a/gpg/diaspora-test/pubring.gpg and b/gpg/diaspora-test/pubring.gpg differ diff --git a/gpg/diaspora-test/random_seed b/gpg/diaspora-test/random_seed deleted file mode 100644 index 303e6b5ce..000000000 Binary files a/gpg/diaspora-test/random_seed and /dev/null differ diff --git a/gpg/diaspora-test/secring.gpg b/gpg/diaspora-test/secring.gpg index 53286a621..9f945d3f1 100644 Binary files a/gpg/diaspora-test/secring.gpg and b/gpg/diaspora-test/secring.gpg differ diff --git a/gpg/diaspora-test/trustdb.gpg b/gpg/diaspora-test/trustdb.gpg index 5a8d5b325..1fec81fc8 100644 Binary files a/gpg/diaspora-test/trustdb.gpg and b/gpg/diaspora-test/trustdb.gpg differ diff --git a/lib/encryptable.rb b/lib/encryptable.rb new file mode 100644 index 000000000..c35ba70c3 --- /dev/null +++ b/lib/encryptable.rb @@ -0,0 +1,32 @@ + module Encryptable + def signable_string + "" + end + def verify_creator_signature + verify_signature(creator_signature, person) + end + + def verify_signature(signature, person) + return false unless signature && person.key_fingerprint + validity = nil + GPGME::verify(creator_signature, signable_string, + {:armor => true, :always_trust => true}){ |signature| + validity = signature.status == GPGME::GPG_ERR_NO_ERROR && + signature.fpr == person.key_fingerprint + } + return validity + end + + protected + def sign_if_mine + if self.person == User.owner + self.creator_signature = sign + end + end + + def sign + GPGME::sign(signable_string,nil, + {:armor=> true, :mode => GPGME::SIG_MODE_DETACH, :signers => [User.owner.key]}) + end + end + diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 6d61abd4a..dbcd29617 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -11,13 +11,18 @@ namespace :db do require 'db/seeds/dev' end - task :backer, :num, :password do |t, args| + task :backer, :num do |t, args| puts "Seeding the database for #{Rails.env}..." require 'db/seeds/backer' - create( Integer(args.num), args.password ) + create( Integer(args.num)) end end + task :accept_requests do + puts "Accepting all friend requests for #{Rails.env}" + require 'db/seeds/request' + end + desc 'Delete the collections in the current RAILS_ENV database' task :purge do require 'config/environment' @@ -28,7 +33,6 @@ namespace :db do Post.delete_all Person.delete_all User.delete_all - Profile.delete_all Request.delete_all end diff --git a/spec/controllers/dashboards_controller_spec.rb b/spec/controllers/dashboards_controller_spec.rb index 7b9a2857b..d8749727e 100644 --- a/spec/controllers/dashboards_controller_spec.rb +++ b/spec/controllers/dashboards_controller_spec.rb @@ -4,7 +4,7 @@ describe DashboardsController do render_views before do - @user = Factory.create(:user, :profile => Profile.create( :first_name => "bob", :last_name => "smith")) + @user = Factory.create(:user, :profile => Profile.new( :first_name => "bob", :last_name => "smith")) request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user) end diff --git a/spec/controllers/publics_controller_spec.rb b/spec/controllers/publics_controller_spec.rb index e9539b464..be297a64f 100644 --- a/spec/controllers/publics_controller_spec.rb +++ b/spec/controllers/publics_controller_spec.rb @@ -4,7 +4,7 @@ describe PublicsController do render_views before do - @user = Factory.create(:user, :profile => Profile.create( :first_name => "bob", :last_name => "smith")) + @user = Factory.create(:user, :profile => Profile.new( :first_name => "bob", :last_name => "smith")) request.env['warden'] = mock_model(Warden, :authenticate? => @user, :authenticate! => @user, :authenticate => @user) end diff --git a/spec/factories.rb b/spec/factories.rb index 46e09e3dd..1fdd262bf 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1,18 +1,20 @@ #For Guidance #http://github.com/thoughtbot/factory_girl # http://railscasts.com/episodes/158-factories-not-fixtures - +#This inclsion, because gpg-agent(not needed) is never run and hence never sets any env. variables on a MAC +ENV['GNUPGHOME'] = File.expand_path("../../gpg/diaspora-#{Rails.env}/", __FILE__) +GPGME::check_version({}) Factory.define :profile do |p| p.first_name "Robert" p.last_name "Grimm" - p.person Person.new( :email => "bob@aol.com" ) end Factory.define :person do |p| - p.email "bob@aol.com" + p.email "bob-person@aol.com" p.active true p.sequence(:url) {|n|"http://google-#{n}.com/"} + p.key_fingerprint GPGME::list_keys("Aditi").first.subkeys.first.fingerprint p.profile Profile.new( :first_name => "Robert", :last_name => "Grimm" ) end @@ -21,6 +23,7 @@ Factory.define :user do |u| u.password "bluepin7" u.password_confirmation "bluepin7" u.url "www.example.com/" + u.key_fingerprint GPGME.list_keys("Smith", true).first.subkeys.first.fingerprint u.profile Profile.new( :first_name => "Bob", :last_name => "Smith" ) end diff --git a/spec/fixtures/msg.xml b/spec/fixtures/msg.xml new file mode 100644 index 000000000..aa1fbf054 --- /dev/null +++ b/spec/fixtures/msg.xml @@ -0,0 +1,14 @@ + + jimmy's 1 whales + <_id>4c3b7cf9312f91367f000004 + + bob1@aol.com + http://www.example.com/ + <_id>4c3b7c64312f913664000005 + 0264242496D4B585297BF236BEEFE6DEBE3407AA + + Bob + Smith + + + \ No newline at end of file diff --git a/spec/fixtures/msg.xml.clear.asc b/spec/fixtures/msg.xml.clear.asc new file mode 100644 index 000000000..e80a6a26f --- /dev/null +++ b/spec/fixtures/msg.xml.clear.asc @@ -0,0 +1,24 @@ +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + + + jimmy's 1 whales + <_id>4c3b7cf9312f91367f000004 + + bob1@aol.com + http://www.example.com/ + <_id>4c3b7c64312f913664000005 + 0264242496D4B585297BF236BEEFE6DEBE3407AA + + Bob + Smith + + + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.10 (GNU/Linux) + +iEYEARECAAYFAkw7qBYACgkQ5hWCpTN+yRI3uwCgj4RhakQQP9K3Lu7fkHYydcEB +J30AnjQZjwY7e1VBkYp6NmL3z2039s5R +=ifDI +-----END PGP SIGNATURE----- diff --git a/spec/fixtures/msg.xml.detached.asc b/spec/fixtures/msg.xml.detached.asc new file mode 100644 index 000000000..66012caef --- /dev/null +++ b/spec/fixtures/msg.xml.detached.asc @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.10 (GNU/Linux) + +iEYEABECAAYFAkw72oUACgkQ5hWCpTN+yRLSuwCgwphc3LWMM0LOZ5wreKjNeaja +BCsAoIzYO9AG3fgV0KbtIFAtuwlNiFxt +=W2K4 +-----END PGP SIGNATURE----- diff --git a/spec/fixtures/msg.xml.normal.asc b/spec/fixtures/msg.xml.normal.asc new file mode 100644 index 000000000..90949d2ff --- /dev/null +++ b/spec/fixtures/msg.xml.normal.asc @@ -0,0 +1,13 @@ +-----BEGIN PGP MESSAGE----- +Version: GnuPG v1.4.10 (GNU/Linux) + +owGbwMvMwCT4TLRpqXHdSSHGtYxbkthzi9P1KnJzfKyXH7cpLkksKS2Oz00tLk5M +T7XjUlCwgbGzMnNzK9WLFQwVyjMSc1KLbfSRVcVnptiZJBsnmSenWRobGqVZGhqb +macZgICJjT5IFqSqILWoOD8PxARyUnMTM3PskvKTDB0S83P0kvNzbfQhYhD50qIc +u4ySkgIrff3y8nK91IrE3IKcVJA6fRt9kCREGcJmMxOYzWYmYJtN4TYD1WWnVsan +ZealpxYVFGXmldgZGJmZGAGhpZmLiZOphamRpbmTm5GxmZOrq5urmYurk6uxiYG5 +o6ONPrpOiHkFRflpmTmpEB6Qn5ZZVFwSn5eYm2rnlJ9ko4/EhynJSYSJBOdmlmTY +6CMEIGbqIxkK5EBDy0YfLVo63FgYBJkY2FiZQJHGwMUpAIvRzhkMC04tX8j8bv3T +QpXm+waPDzQ0HT38p45hntLiCTerfep5uNpMLHWWW75e9vqqAwA= +=k+0d +-----END PGP MESSAGE----- diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 20261308f..f47856265 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -4,7 +4,7 @@ include ApplicationHelper describe ApplicationHelper do before do - @user = Factory.create(:user, :email => "robert@grimm.com") + @user = Factory.create(:user) @person = Factory.create(:person) end diff --git a/spec/lib/parser_spec.rb b/spec/lib/parser_spec.rb index c6650fb75..4b4c7cc2d 100644 --- a/spec/lib/parser_spec.rb +++ b/spec/lib/parser_spec.rb @@ -132,13 +132,14 @@ describe "parser in application helper" do request_remote.destination_url = @user.url request_remote.callback_url = @user.url request_remote.person = @person + request_remote.exported_key = @person.export_key xml = Request.build_xml_for [request_remote] @person.destroy request_remote.destroy store_objects_from_xml(xml) - Person.where(:url => @person.url).first.active.should be true + Person.first(:url => @person.url).active.should be true end diff --git a/spec/lib/xml_spec.rb b/spec/lib/xml_spec.rb index 5c1714d73..42b26d01c 100644 --- a/spec/lib/xml_spec.rb +++ b/spec/lib/xml_spec.rb @@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/../spec_helper' describe Diaspora::XML do before do - @user = Factory.create(:user, :profile => { :first_name => "robert", :last_name => "grimm" } ) + @user = Factory.create(:user) Diaspora::XML::OWNER = @user end diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index a882b9849..8d6e75f51 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -34,7 +34,7 @@ describe Person do end - it 'should delete all of user upon user deletion' do + it 'should delete all of user except comments upon user deletion' do Factory.create(:user) f = Factory.create(:person) @@ -53,8 +53,8 @@ describe Person do f.destroy Post.count.should == 1 - Comment.all.count.should == 1 - s.comments.count.should == 1 + Comment.all.count.should == 4 + s.comments.count.should == 4 end it 'should let a user unfriend another user' do @@ -65,6 +65,7 @@ describe Person do Person.friends.all.count.should == 1 u.unfriend(f.id) Person.friends.all.count.should == 0 + Person.all.count.should == 1 end end diff --git a/spec/models/profile_spec.rb b/spec/models/profile_spec.rb index 5cb57b270..6099793b0 100644 --- a/spec/models/profile_spec.rb +++ b/spec/models/profile_spec.rb @@ -7,25 +7,19 @@ describe Profile do describe 'requirements' do it "should include a first name" do - @person.profile = Factory.build(:profile, :person => @person, :first_name => nil) + @person.profile = Factory.build(:profile,:first_name => nil) @person.profile.valid?.should be false @person.profile.first_name = "Bob" @person.profile.valid?.should be true end it "should include a last name" do - @person.profile = Factory.build(:profile, :person => @person, :last_name => nil) + @person.profile = Factory.build(:profile, :last_name => nil) @person.profile.valid?.should be false @person.profile.last_name = "Smith" @person.profile.valid?.should be true end - it "should include a person" do - profile = Factory.build(:profile, :person => nil) - profile.valid?.should be false - profile.person = @person - profile.valid?.should be true - end end end diff --git a/spec/models/request_spec.rb b/spec/models/request_spec.rb index f3357fc73..00fac8580 100644 --- a/spec/models/request_spec.rb +++ b/spec/models/request_spec.rb @@ -11,11 +11,8 @@ describe Request do end it 'should generate xml for the User as a Person' do - user = User.create(:email => "rob@bob.com") + user = Factory.create(:user) - user.profile = Factory.create(:profile) - - user.save(:validate => false) user.profile.save request = Request.instantiate(:to => "http://www.google.com/", :from => user) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index cf8bb59d7..f0156464d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,7 +12,7 @@ include Devise::TestHelpers Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} RSpec.configure do |config| - + config.mock_with :mocha config.mock_with :rspec DatabaseCleaner.strategy = :truncation @@ -20,11 +20,12 @@ RSpec.configure do |config| config.before(:suite) do DatabaseCleaner.clean_with(:truncation) + stub_signature_verification end config.before(:each) do DatabaseCleaner.start - stub_sockets_controller + stub_sockets_controller end config.after(:each) do @@ -39,3 +40,19 @@ end mock_sockets_controller.stub!(:delete_subscriber).and_return(true) SocketsController.stub!(:new).and_return(mock_sockets_controller) end + + def stub_signature_verification + Post.any_instance.stubs(:verify_creator_signature).returns(true) + StatusMessage.any_instance.stubs(:verify_creator_signature).returns(true) + Blog.any_instance.stubs(:verify_creator_signature).returns(true) + Bookmark.any_instance.stubs(:verify_creator_signature).returns(true) + Comment.any_instance.stubs(:verify_creator_signature).returns(true) + Comment.any_instance.stubs(:verify_post_creator_signature).returns(true) + Person.any_instance.stubs(:remove_key).returns(true) + User.any_instance.stubs(:remove_key).returns(true) + end + + def unstub_mocha_stubs + Mocha::Mockery.instance.stubba.unstub_all + + end diff --git a/spec/user_encryption_spec.rb b/spec/user_encryption_spec.rb index ad144f487..b0083f0ec 100644 --- a/spec/user_encryption_spec.rb +++ b/spec/user_encryption_spec.rb @@ -1,35 +1,189 @@ require File.dirname(__FILE__) + '/spec_helper' +include ApplicationHelper describe 'user encryption' do before :all do #ctx = GPGME::Ctx.new #keys = ctx.keys #keys.each{|k| ctx.delete_key(k, true)} - @u = User.new - @u.email = "george@aol.com" - @u.password = "bluepin7" - @u.password_confirmation = "bluepin7" - @u.url = "www.example.com" - @u.profile = Profile.new( :first_name => "Bob", :last_name => "Smith" ) - @u.profile.save - @u.send(:assign_key) - @u.save + + end + before do + unstub_mocha_stubs + @user = Factory.create(:user) + @user.send(:assign_key) + @user.save + @person = Factory.create(:person, + :key_fingerprint => GPGME.list_keys("Remote Friend").first.subkeys.first.fpr, + :profile => Profile.new(:first_name => 'Remote', + :last_name => 'Friend'), + :email => 'somewhere@else.com', + :url => 'http://distant-example.com/') + @person2 = Factory.create(:person, + :key_fingerprint => GPGME.list_keys("Second Friend").first.subkeys.first.fpr, + :profile => Profile.new(:first_name => 'Second', + :last_name => 'Friend'), + :email => 'elsewhere@else.com', + :url => 'http://distanter-example.com/') end -# after :all do + after do + stub_signature_verification #gpgdir = File.expand_path("../../db/gpg-#{Rails.env}", __FILE__) #ctx = GPGME::Ctx.new #keys = ctx.keys #keys.each{|k| ctx.delete_key(k, true)} - #end + end + it 'should remove the key from the keyring on person destroy' do + person = Factory.create :person + keyid = person.key_fingerprint + original_key = person.export_key + GPGME.list_keys(keyid).count.should be 1 + person.destroy + GPGME.list_keys(keyid).count.should be 0 + GPGME.import(original_key) + GPGME.list_keys(keyid).count.should be 1 + end + it 'should have a key fingerprint' do - @u.key_fingerprint.should_not be nil + @user.key_fingerprint.should_not be nil end it 'should retrieve a user key' do - @u.key.subkeys[0].fpr.should == @u.key_fingerprint + @user.key.subkeys[0].fpr.should == @user.key_fingerprint end + describe 'key exchange on friending' do + it 'should send over a public key' do + Comment.send(:class_variable_get, :@@queue).stub!(:add_post_request) + request = @user.send_friend_request_to("http://example.com/") + Request.build_xml_for([request]).include?( @user.export_key).should be true + end + it 'should receive and marshal a public key from a request' do + person = Factory.build(:person, :url => "http://test.url/" ) + person.key_fingerprint.nil?.should== false + #should move this to friend request, but i found it here + f = person.key_fingerprint + id = person.id + original_key = person.export_key + + request = Request.instantiate(:to =>"http://www.google.com/", :from => person) + + xml = Request.build_xml_for [request] + person.destroy + personcount = Person.all.count + store_objects_from_xml(xml) + Person.all.count.should == personcount + 1 + new_person = Person.first(:url => "http://test.url/") + new_person.key_fingerprint.nil?.should == false + new_person.id.should == id + new_person.key_fingerprint.should == f + new_person.export_key.should == original_key + end + end + + describe 'signing and verifying' do + + it 'should sign a message on create' do + message = Factory.create(:status_message, :person => @user) + message.verify_creator_signature.should be true + end + + it 'should not be able to verify a message from a person without a key' do + person = Factory.create(:person, :key_fingerprint => "123") + message = Factory.build(:status_message, :person => person) + message.save(:validate => false) + message.verify_creator_signature.should be false + end + + it 'should verify a remote signature' do + message = Factory.build(:status_message, :person => @person) + message.creator_signature = GPGME.sign(message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) + message.save(:validate => false) + message.verify_creator_signature.should be true + end + + it 'should know if the signature is from the wrong person' do + message = Factory.build(:status_message, :person => @person) + message.save(:validate => false) + message.creator_signature = GPGME.sign(message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) + message.person = @user + message.verify_creator_signature.should be false + end + + it 'should know if the signature is for the wrong text' do + message = Factory.build(:status_message, :person => @person) + message.creator_signature = GPGME.sign(message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) + message.message = 'I love VENISON' + message.save(:validate => false) + message.verify_creator_signature.should be false + end + end + + describe 'sending and recieving signatures' do + it 'should contain the signature in the xml' do + message = Factory.create(:status_message, :person => @user) + xml = message.to_xml.to_s + xml.include?(message.creator_signature).should be true + end + it 'A message with an invalid signature should be rejected' do + message = Factory.build(:status_message, :person => @person) + message.creator_signature = GPGME.sign(message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@user.key]}) + message.save + xml = Post.build_xml_for([message]) + message.destroy + Post.count.should be 0 + store_objects_from_xml(xml) + Post.count.should be 0 + end + + end + describe 'comments' do + before do + @remote_message = Factory.build(:status_message, :person => @person) + @remote_message.creator_signature = GPGME.sign(@remote_message.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person.key]}) + @remote_message.save + + end + it 'should attach the creator signature if the user is commenting' do + @user.comment "Yeah, it was great", :on => @remote_message + @remote_message.comments.first.verify_creator_signature.should be true + end + + it 'should sign the comment if the user is the post creator' do + message = Factory.create(:status_message, :person => @user) + @user.comment "Yeah, it was great", :on => message + StatusMessage.first.comments.first.verify_creator_signature.should be true + StatusMessage.first.comments.first.verify_post_creator_signature.should be true + end + + it 'should verify a comment made on a remote post by a different friend' do + comment = Comment.new(:person => @person2, :text => "balls", :post => @remote_message) + comment.creator_signature = GPGME.sign(comment.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person2.key]}) + comment.verify_creator_signature.should be true + + end + + it 'should reject comments on a remote post with only a creator sig' do + comment = Comment.new(:person => @person2, :text => "balls", :post => @remote_message) + comment.creator_signature = GPGME.sign(comment.signable_string, nil, + {:mode => GPGME::SIG_MODE_DETACH, :armor => true, :signers => [@person2.key]}) + comment.verify_creator_signature.should be true + comment.verify_post_creator_signature.should be false + comment.save.should be false + end + + it 'should receive remote comments on a user post with a creator sig' do + + end + + end end