Merging master into production

This commit is contained in:
Raphael 2010-08-24 11:18:42 -07:00
commit b5bb61a135
172 changed files with 2524 additions and 439 deletions

View file

@ -26,7 +26,7 @@ gem 'json'
#Standards #Standards
gem 'pubsubhubbub' gem 'pubsubhubbub'
gem 'redfinger' gem 'redfinger', :git => 'git://github.com/rsofaer/redfinger.git'
#EventMachine #EventMachine
gem 'em-http-request',:git => 'git://github.com/igrigorik/em-http-request.git', :require => 'em-http' gem 'em-http-request',:git => 'git://github.com/igrigorik/em-http-request.git', :require => 'em-http'

View file

@ -2,7 +2,8 @@ class ApplicationController < ActionController::Base
protect_from_forgery :except => :receive protect_from_forgery :except => :receive
before_filter :set_friends_and_status, :count_requests before_filter :set_friends_and_status
before_filter :count_requests
layout :layout_by_resource layout :layout_by_resource
@ -17,8 +18,6 @@ class ApplicationController < ActionController::Base
def set_friends_and_status def set_friends_and_status
if current_user if current_user
@groups = current_user.groups @groups = current_user.groups
@friends = current_user.friends
@group = params[:group] ? current_user.group_by_id(params[:group]) : current_user.groups.first
end end
end end

View file

@ -1,15 +0,0 @@
class GridfsController < ActionController::Metal
def serve
gridfs_path = env["PATH_INFO"].gsub("/images/", "")
begin
gridfs_file = Mongo::GridFileSystem.new(MongoMapper.database).open(gridfs_path, 'r')
self.response_body = gridfs_file.read
self.content_type = gridfs_file.content_type
rescue
self.status = :file_not_found
self.content_type = 'text/plain'
self.response_body = "File totally imaginary #{gridfs_path}"
end
end
end

View file

@ -2,7 +2,9 @@ class GroupsController < ApplicationController
before_filter :authenticate_user! before_filter :authenticate_user!
def index def index
@posts = current_user.raw_visible_posts.paginate :page => params[:page], :order => 'created_at DESC' @posts = current_user.visible_posts(:by_members_of => :all).paginate :page => params[:page], :order => 'created_at DESC'
@group = :all
@friends = current_user.friends
end end
def create def create
@ -28,12 +30,9 @@ class GroupsController < ApplicationController
end end
def show def show
@people_ids = @group.person_ids
@group = Group.first(:id => params[:id]) @group = Group.first(:id => params[:id])
@friends = @group.people
@posts = current_user.visible_posts( :by_members_of => @group ).paginate :order => 'created_at DESC' @posts = current_user.visible_posts( :by_members_of => @group ).paginate :order => 'created_at DESC'
#@posts = Post.paginate :person_id => @people_ids, :order => 'created_at DESC'
end end
def edit def edit

View file

@ -2,6 +2,7 @@ class PhotosController < ApplicationController
before_filter :authenticate_user! before_filter :authenticate_user!
def create def create
render :nothing => true
begin begin
@photo = current_user.post(:photo, params) @photo = current_user.post(:photo, params)
@ -21,6 +22,8 @@ class PhotosController < ApplicationController
def new def new
@photo = Photo.new @photo = Photo.new
@album = current_user.album_by_id(params[:album_id])
render :partial => "new_photo"
end end
def destroy def destroy

View file

@ -31,22 +31,31 @@ class RequestsController < ApplicationController
end end
def create def create
puts params.inspect begin
rel_hash = relationship_flow(params[:request][:destination_url]) rel_hash = relationship_flow(params[:request][:destination_url])
rescue Exception => e
flash[:error] = "no diaspora seed found with this email!"
redirect_to current_user.group_by_id(params[:request][:group_id])
return
end
Rails.logger.debug("Sending request: #{rel_hash}") Rails.logger.debug("Sending request: #{rel_hash}")
begin
@request = current_user.send_request(rel_hash, params[:request][:group_id]) @request = current_user.send_request(rel_hash, params[:request][:group_id])
rescue Exception => e
raise e unless e.message.include? "already friends"
flash[:notice] = "You are already friends with #{params[:request][:destination_url]}!"
redirect_to current_user.group_by_id(params[:request][:group_id])
return
end
if @request if @request
flash[:notice] = "a friend request was sent to #{@request.destination_url}" flash[:notice] = "a friend request was sent to #{@request.destination_url}"
redirect_to requests_url redirect_to current_user.group_by_id(params[:request][:group_id])
else else
if url.include? '@' flash[:error] = "Something went horribly wrong..."
flash[:error] = "no diaspora seed found with this email!" redirect_to current_user.group_by_id(params[:request][:group_id])
else
flash[:error] = "you have already friended this person"
end
@request = Request.new
render :action => 'new'
end end
end end

View file

@ -1,15 +1,8 @@
class StatusMessagesController < ApplicationController class StatusMessagesController < ApplicationController
before_filter :authenticate_user! before_filter :authenticate_user!
def index
@status_messages = StatusMessage.paginate :page => params[:page], :order => 'created_at DESC'
respond_to do |format|
format.html
end
end
def create def create
puts params.inspect params[:status_message][:group_ids] = params[:group_ids]
@status_message = current_user.post(:status_message, params[:status_message]) @status_message = current_user.post(:status_message, params[:status_message])
if @status_message.created_at if @status_message.created_at

View file

@ -1,7 +1,7 @@
module ApplicationHelper module ApplicationHelper
def current_group?(group) def current_group?(group)
@group.id == group.id @group == :all || @group.id == group.id
end end
def object_path(object) def object_path(object)

View file

@ -4,11 +4,11 @@ module PhotosHelper
link_to (image_tag photo.url(:scaled_full)), photo_path(album.next_photo(photo)), :rel => "prefetch" link_to (image_tag photo.url(:scaled_full)), photo_path(album.next_photo(photo)), :rel => "prefetch"
end end
def link_to_prev(photo, album) def url_to_prev(photo, album)
link_to "<< prev", photo_path(album.prev_photo(photo)), :rel => "prefetch" photo_path(album.prev_photo(photo))
end end
def link_to_next(photo, album) def url_to_next(photo, album)
link_to "next >>", photo_path(album.next_photo(photo)), :rel => "prefetch" photo_path(album.next_photo(photo))
end end
end end

View file

@ -29,7 +29,6 @@ module RequestsHelper
action = :none action = :none
url = nil url = nil
local_person = Person.by_webfinger identifier local_person = Person.by_webfinger identifier
puts local_person.inspect
if local_person if local_person
action = (local_person == current_user.person ? :none : :friend) action = (local_person == current_user.person ? :none : :friend)
url = local_person.receive_url url = local_person.receive_url

View file

@ -51,6 +51,10 @@ class Person
serialized_key = new_key.export serialized_key = new_key.export
end end
def public_key_hash
Base64.encode64 OpenSSL::Digest::SHA256.new(self.export_key).to_s
end
def export_key def export_key
encryption_key.public_key.export encryption_key.public_key.export
end end

View file

@ -29,11 +29,6 @@ class Post
self.create params self.create params
end end
#Querying
def self.newest_for(person)
self.where(:person_id => person.id, :order => '_id desc')
end
#ENCRYPTION #ENCRYPTION
xml_accessor :creator_signature xml_accessor :creator_signature
key :creator_signature, String key :creator_signature, String

View file

@ -27,10 +27,7 @@ class User
def allowed_email? def allowed_email?
allowed_emails = ["@pivotallabs.com", "@joindiaspora.com", "@sofaer.net", allowed_emails = ["@pivotallabs.com", "@joindiaspora.com", "@sofaer.net"]
"wchulley@gmail.com", "kimfuh@yahoo.com", "CJichi@yahoo.com",
"madkisso@mit.edu", "bribak@msn.com", "asykley@verizon.net",
"paulhaeberli@gmail.com","bondovatic@gmail.com", "dixon1e@yahoo.com"]
allowed_emails.each{|allowed| allowed_emails.each{|allowed|
if email.include?(allowed) if email.include?(allowed)
return true return true
@ -59,23 +56,25 @@ class User
def post(class_name, options = {}) def post(class_name, options = {})
options[:person] = self.person options[:person] = self.person
group_id = options[:group_id] group_ids = options[:group_ids]
options.delete(:group_id) options.delete(:group_ids)
model_class = class_name.to_s.camelize.constantize model_class = class_name.to_s.camelize.constantize
post = model_class.instantiate(options) post = model_class.instantiate(options)
post.creator_signature = post.sign_with_key(encryption_key) post.creator_signature = post.sign_with_key(encryption_key)
post.save post.save
if group_id groups = self.groups.find_all_by_id(group_ids)
group = self.groups.find_by_id(group_id) target_people = []
groups.each{ |group|
group.posts << post group.posts << post
group.save group.save
post.push_to( group.people.all ) target_people = target_people | group.people
else }
post.push_to( self.friends.all ) post.push_to( target_people )
end
post.socket_to_uid(id) if post.respond_to?(:socket_to_uid) post.socket_to_uid(id) if post.respond_to?(:socket_to_uid)
@ -86,6 +85,7 @@ class User
def visible_posts( opts = {} ) def visible_posts( opts = {} )
if opts[:by_members_of] if opts[:by_members_of]
return raw_visible_posts if opts[:by_members_of] == :all
group = self.groups.find_by_id( opts[:by_members_of].id ) group = self.groups.find_by_id( opts[:by_members_of].id )
group.posts group.posts
end end
@ -139,7 +139,7 @@ class User
######### Friend Requesting ########### ######### Friend Requesting ###########
def send_friend_request_to(friend_url, group_id) def send_friend_request_to(friend_url, group_id)
unless self.friends.detect{ |x| x.receive_url == friend_url} raise "You are already friends with that person!" if self.friends.detect{ |x| x.receive_url == friend_url}
request = Request.instantiate(:to => friend_url, :from => self.person, :into => group_id) request = Request.instantiate(:to => friend_url, :from => self.person, :into => group_id)
if request.save if request.save
self.pending_requests << request self.pending_requests << request
@ -154,7 +154,7 @@ class User
end end
request request
end end
end
def accept_friend_request(friend_request_id, group_id) def accept_friend_request(friend_request_id, group_id)
request = Request.find_by_id(friend_request_id) request = Request.find_by_id(friend_request_id)
@ -358,7 +358,12 @@ class User
group(:name => "Acquaintances") group(:name => "Acquaintances")
group(:name => "Family") group(:name => "Family")
group(:name => "Nemeses") group(:name => "Nemeses")
group(:name => "Work") group(:name => "Pivots")
end
def album_by_id( id )
id = ensure_bson id
albums.detect{|x| x.id == id }
end end
def groups_with_person person def groups_with_person person
@ -369,8 +374,8 @@ class User
protected protected
def setup_person def setup_person
self.person.serialized_key = generate_key.export self.person.serialized_key ||= generate_key.export
self.person.email = email self.person.email ||= email
self.person.save! self.person.save!
end end

View file

@ -11,9 +11,9 @@ class ImageUploader < CarrierWave::Uploader::Base
%w(jpg jpeg gif png) %w(jpg jpeg gif png)
end end
# def filename def filename
# model.id.to_s + File.extname(@filename) model.id.to_s + File.extname(@filename) if @filename
# end end
version :thumb_small do version :thumb_small do
process :resize_to_fill => [30,30] process :resize_to_fill => [30,30]

View file

@ -1,3 +1,9 @@
:javascript
$(document).ready(function(){
reset_photo_fancybox();
});
.album_id{:id => @album.id, :style => "display:hidden;"}
.back= link_to '⇧ albums', albums_path .back= link_to '⇧ albums', albums_path
%h1.big_text %h1.big_text
@ -11,7 +17,6 @@
.yo{:style => "display:none;"} .yo{:style => "display:none;"}
#new_photo_pane #new_photo_pane
= render "photos/new_photo", :photo => @photo, :album => @album
.sub_header .sub_header
="updated #{how_long_ago(@album)}" ="updated #{how_long_ago(@album)}"

View file

@ -2,9 +2,7 @@
welcome, welcome,
= current_user.profile.first_name = current_user.profile.first_name
- @group.nil? ? group_id = nil : group_id = @group.id = render "shared/publisher", :group_ids => :all
= render "shared/publisher", :group_id => group_id
%ul#stream %ul#stream
- for post in @posts - for post in @posts

View file

@ -1,8 +1,6 @@
- if user_signed_in? = javascript_include_tag 'FABridge', 'swfobject', 'web_socket'
= javascript_include_tag 'FABridge', 'swfobject', 'web_socket' :javascript
:javascript
WebSocket.__swfLocation = "/javascripts/WebSocketMain.swf"; WebSocket.__swfLocation = "/javascripts/WebSocketMain.swf";
:javascript
$(document).ready(function(){ $(document).ready(function(){
function debug(str){ $("#debug").append("<p>" + str); }; function debug(str){ $("#debug").append("<p>" + str); };

View file

@ -13,7 +13,6 @@
/= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" /= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"
= javascript_include_tag 'jquery142', 'rails', 'google' = javascript_include_tag 'jquery142', 'rails', 'google'
= javascript_include_tag 'tiny_mce/tiny_mce'
= javascript_include_tag 'jquery.infieldlabel', 'jquery.cycle/jquery.cycle.min.js' = javascript_include_tag 'jquery.infieldlabel', 'jquery.cycle/jquery.cycle.min.js'
= javascript_include_tag 'fancybox/jquery.fancybox-1.3.1.pack' = javascript_include_tag 'fancybox/jquery.fancybox-1.3.1.pack'
@ -33,26 +32,35 @@
%header %header
.container .container
#session_action #session_action
- if user_signed_in?
%ul#user_menu %ul#user_menu
%li.name= link_to current_user.real_name, current_user.person %li#global_search
%li= link_to "requests (#{@request_count})", requests_path, :class => new_request(@request_count) = form_tag(users_path, :method => 'get') do
%li= link_to "settings", edit_user_path(current_user) %label{:for => 'q'} Search
%li= link_to "search", users_path = text_field_tag 'q'
%li= link_to "logout", destroy_user_session_path
- else %li
= link_to "login", new_user_session_path %ul#other_user_menu
%li
= owner_image_tag
= link_to current_user.real_name, current_user.person
%li.requests= link_to "requests (#{@request_count})", requests_path, :class => new_request(@request_count)
%li.settings= link_to "settings", edit_user_path(current_user)
%li.logout= link_to "logout", destroy_user_session_path
#diaspora_text{:href => root_path} #diaspora_text{:href => root_path}
= link_to "DIASPORA*", root_path = link_to "DIASPORA*", root_path
%span.sub_text %span.sub_text
PREVIEW PREVIEW
= render "shared/group_nav"
%span{:style => "padding-left:30px;"}
= link_to "photos", albums_path = link_to "photos", albums_path
.container .container
.span-24.last .span-4.append-1.last
= render "shared/group_nav"
.span-19.last
= yield = yield
.span-24.last
= render "posts/debug" = render "posts/debug"

View file

@ -1,11 +0,0 @@
%ul#friend_stream.nav
%h3 friends
- for friend in @friends
= person_image_link(friend)
%li= link_to "view all", people_path
%br
%br
= link_to "add a new person", requests_path

View file

@ -2,7 +2,7 @@
$(function() { $(function() {
$("#photo_image").html5_upload({ $("#photo_image").html5_upload({
// WE INSERT ALBUM_ID PARAM HERE // WE INSERT ALBUM_ID PARAM HERE
url: "/photos?album_id=#{album.id}", url: "/photos?album_id=#{@album.id}",
sendBoundary: window.FormData || $.browser.mozilla, sendBoundary: window.FormData || $.browser.mozilla,
setName: function(text) { setName: function(text) {
$("#progress_report_name").text(text); $("#progress_report_name").text(text);
@ -12,7 +12,9 @@
$("#add_photo_loader").fadeOut(400); $("#add_photo_loader").fadeOut(400);
$("#photo_title_status").text("Done!"); $("#photo_title_status").text("Done!");
$("#progress_report").html("Great job!"); $("#progress_report").html("Good job me!");
$("#add_photo_button").addClass("uploading_complete");
}, },
onStart: function(event, total){ onStart: function(event, total){
$("#add_photo_button").html( "Uploading Photos" ); $("#add_photo_button").html( "Uploading Photos" );
@ -29,10 +31,10 @@
%h1 %h1
%span{:id=>"photo_title_status"} %span{:id=>"photo_title_status"}
Add photos to Add photos to
%i= album.name %i= @album.name
= form_for photo, :html => {:multipart => true} do |f| = form_for @photo, :html => {:multipart => true} do |f|
= f.error_messages = f.error_messages
= f.hidden_field :album_id, :value => album.id = f.hidden_field :album_id, :value => @album.id
= f.file_field :image, :multiple => 'multiple' = f.file_field :image, :multiple => 'multiple'
#progress_report{ :style => "display:none;text-align:center;" } #progress_report{ :style => "display:none;text-align:center;" }

View file

@ -1,3 +1,16 @@
:javascript
$(document).keydown(function(e){
switch(e.keyCode) {
case 37:
window.location.replace( "#{url_to_prev(@photo,@album)}" );
break;
case 39:
window.location.replace( "#{url_to_next(@photo,@album)}" );
break;
}
});
.back= link_to "⇧ #{@album.name}", album_path(@album) .back= link_to "⇧ #{@album.name}", album_path(@album)
%h1.big_text %h1.big_text
= @photo.image = @photo.image
@ -6,11 +19,11 @@
= link_to 'Edit Photo', edit_photo_path(@photo), :class => "button" = link_to 'Edit Photo', edit_photo_path(@photo), :class => "button"
.sub_header .sub_header
= link_to_prev @photo, @album = link_to "<< prev", url_to_prev(@photo, @album)
| |
= link_to "full size", @photo.url = link_to "full size", @photo.url
| |
= link_to_next @photo, @album = link_to "next >>", url_to_next(@photo, @album)
%div{:id => @photo.id} %div{:id => @photo.id}
#show_photo #show_photo

View file

@ -1,6 +0,0 @@
= form_for @request do |f|
= f.error_messages
.field_with_submit
= f.text_field :destination_url
= f.submit

View file

@ -1,5 +0,0 @@
%h1 requests
= render 'form'
%p= link_to "Back to List", requests_path

View file

@ -1,7 +1,15 @@
#group #group
%ul %ul
- if @group == :all
= link_to "All Groups", root_url, :class => "selected"
- elsif @group
= link_to @group.name, @group, :class => "selected"
= link_to "edit", edit_group_path(@group)
- for group in @groups - for group in @groups
%li{:class => ("selected" if group.id.to_s == params[:id])} - unless (group.id.to_s == params[:id])
%li
= link_to group.name, group = link_to group.name, group
%li.new_group= link_to("NEW GROUP", "#add_group_pane", :id => "add_group_button") %li.new_group= link_to("NEW GROUP", "#add_group_pane", :id => "add_group_button")
@ -12,15 +20,11 @@
- if @group - if @group
#friend_pictures #friend_pictures
- for friend in @group.people - for friend in @friends
= person_image_link(friend) = person_image_link(friend)
= link_to (image_tag 'add_friend_button.png'), "#add_request_pane", :id => 'add_request_button' = link_to (image_tag 'add_friend_button.png'), "#add_request_pane", :id => 'add_request_button'
- if @group.people.count == 0 - unless @group == :all
%span.add_new_description
<< click the plus to add friends to this group
.yo{:style => 'display:none'} .yo{:style => 'display:none'}
#add_request_pane #add_request_pane
= render "requests/new_request" = render "requests/new_request"

View file

@ -1,18 +1,24 @@
#publisher #publisher
#publisher_form .span-19.last
= form_for StatusMessage.new, :remote => true do |f| = form_for StatusMessage.new, :remote => true do |f|
= f.error_messages = f.error_messages
-if group_id .span-15.last
= f.hidden_field :group_id, :value => group_id .span-2.last
.user_image
= owner_image_tag
.span-13.last
%p
%label{:for => "status_message_message"} Message %label{:for => "status_message_message"} Message
= f.text_area :message, :rows => 2 = f.text_area :message, :rows => 2
%ul
.span-3.last
%ul.group_selector
going to...
- for group in current_user.groups - for group in current_user.groups
%li %li
= check_box_tag("group_ids[]", group.id, current_group?(group) )
= group.name = group.name
= check_box_tag("groups_id[]", group.id, current_group?(group)) .span-1.last
.right
= f.submit "Post" = f.submit "Post"

View file

@ -1,14 +1,17 @@
development: development:
debug: false debug: false
socket_debug : false
socket_port: 8080 socket_port: 8080
pubsub_server: 'https://pubsubhubbub.appspot.com/' pubsub_server: 'https://pubsubhubbub.appspot.com/'
test: test:
debug: false debug: false
socket_debug : false
socket_port: 8081 socket_port: 8081
pubsub_server: 'https://pubsubhubbub.appspot.com/' pubsub_server: 'https://pubsubhubbub.appspot.com/'
production: production:
debug: false debug: false
socket_debug : false
socket_port: 8080 socket_port: 8080
pubsub_server: 'https://pubsubhubbub.appspot.com/' pubsub_server: 'https://pubsubhubbub.appspot.com/'

View file

@ -1,3 +1,4 @@
require 'lib/mongo_mapper/clear_dev_memory'
Diaspora::Application.configure do Diaspora::Application.configure do
# Settings specified here will take precedence over those in config/environment.rb # Settings specified here will take precedence over those in config/environment.rb
@ -17,6 +18,7 @@ Diaspora::Application.configure do
# Don't care if the mailer can't send # Don't care if the mailer can't send
config.action_mailer.raise_delivery_errors = true config.action_mailer.raise_delivery_errors = true
config.active_support.deprecation = :log config.active_support.deprecation = :log
config.middleware.use MongoMapper::ClearDevMemory
#config.threadsafe! #config.threadsafe!
config.action_mailer.delivery_method = :smtp config.action_mailer.delivery_method = :smtp
config.action_mailer.default_url_options = {:host => 'localhost:3000'} config.action_mailer.default_url_options = {:host => 'localhost:3000'}

View file

@ -7,7 +7,7 @@ require "lib/diaspora/websocket"
EventMachine::WebSocket.start( EventMachine::WebSocket.start(
:host => "0.0.0.0", :host => "0.0.0.0",
:port => APP_CONFIG[:socket_port], :port => APP_CONFIG[:socket_port],
:debug =>APP_CONFIG[:debug]) do |ws| :debug =>APP_CONFIG[:socket_debug]) do |ws|
ws.onopen { ws.onopen {
sid = Diaspora::WebSocket.subscribe(ws.request['Path'].gsub('/',''), ws) sid = Diaspora::WebSocket.subscribe(ws.request['Path'].gsub('/',''), ws)

View file

@ -1,10 +1,10 @@
Diaspora::Application.routes.draw do Diaspora::Application.routes.draw do
resources :people resources :people, :only => [:index, :show, :destroy]
resources :users, :except => [:create, :new] resources :users, :except => [:create, :new]
resources :status_messages resources :status_messages, :except => [:index]
resources :comments resources :comments, :except => [:index]
resources :requests resources :requests, :except => [:edit, :update]
resources :photos resources :photos, :except => [:index]
resources :albums resources :albums
resources :groups resources :groups

View file

@ -0,0 +1,19 @@
module MongoMapper
class ClearDevMemory
def initialize(app)
@app = app
end
def call(env)
if Rails.configuration.cache_classes
else
MongoMapper::Document.descendants.each do |m|
m.descendants.clear if m.respond_to? :descendants
end
MongoMapper::Document.descendants.clear
MongoMapper::EmbeddedDocument.descendants.clear
end
@app.call(env)
end
end
end

220
lib/salmon/salmon.rb Normal file
View file

@ -0,0 +1,220 @@
# Add URL safe Base64 support
module Base64
module_function
# Returns the Base64-encoded version of +bin+.
# This method complies with RFC 4648.
# No line feeds are added.
def strict_encode64(bin)
[bin].pack("m0")
end
# Returns the Base64-decoded version of +str+.
# This method complies with RFC 4648.
# ArgumentError is raised if +str+ is incorrectly padded or contains
# non-alphabet characters. Note that CR or LF are also rejected.
def strict_decode64(str)
str.unpack("m0").first
end
# Returns the Base64-encoded version of +bin+.
# This method complies with ``Base 64 Encoding with URL and Filename Safe
# Alphabet'' in RFC 4648.
# The alphabet uses '-' instead of '+' and '_' instead of '/'.
def urlsafe_encode64(bin)
strict_encode64(bin).tr("+/", "-_")
end
# Returns the Base64-decoded version of +str+.
# This method complies with ``Base 64 Encoding with URL and Filename Safe
# Alphabet'' in RFC 4648.
# The alphabet uses '-' instead of '+' and '_' instead of '/'.
def urlsafe_decode64(str)
strict_decode64(str.tr("-_", "+/"))
end
end
# Verify documents secured with Magic Signatures
module Salmon
class SalmonSlap
attr_accessor :magic_sig, :user, :data, :data_type, :sig
def self.parse(xml)
slap = self.new
doc = Nokogiri::XML(xml)
sig_doc = doc.search('entry')
slap.magic_sig = MagicSigEnvelope.parse sig_doc
if 'base64url' == slap.magic_sig.encoding
slap.data = decode64url(slap.magic_sig.data)
slap.sig = slap.magic_sig.sig
else
raise ArgumentError, "Magic Signature data must be encoded with base64url, was #{slap.magic_sig.encoding}"
end
slap.data_type = slap.magic_sig.data_type
raise ArgumentError, "Magic Signature data must be signed with RSA-SHA256, was #{slap.magic_sig.alg}" unless 'RSA-SHA256' == slap.magic_sig.alg
slap
end
def self.create(user, activity)
salmon = self.new
salmon.user = user
salmon.magic_sig = MagicSigEnvelope.create(user, activity)
salmon
end
def to_xml
xml =<<ENTRY
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom'>
<author>
<name>#{@user.real_name}</name>
<uri>acct:#{@user.email}</uri>
</author>
#{@magic_sig.to_xml}
</entry>
ENTRY
end
# Decode URL-safe-Base64. This implements
def self.decode64url(str)
# remove whitespace
sans_whitespace = str.gsub(/\s/, '')
# pad to a multiple of 4
string = sans_whitespace + '=' * ((4 - sans_whitespace.size) % 4)
# convert to standard Base64
# string = padded.tr('-','+').tr('_','/')
# Base64.decode64(string)
Base64.urlsafe_decode64 string
end
# def verified?
#
# end
# Check whether this envelope's signature can be verified with the
# provided OpenSSL::PKey::RSA public_key.
# Example:
#
# env.verified_for_key? OpenSSL::PKey::RSA.new(File.open('public_key.pem'))
# # -> true
def verified_for_key?(public_key)
signature = Base64.urlsafe_decode64(self.magic_sig.sig)
signed_data = self.magic_sig.signable_string# Base64.urlsafe_decode64(self.magic_sig.signable_string)
public_key.verify(OpenSSL::Digest::SHA256.new, signature, signed_data )
end
# Decode a string containing URL safe Base64 into an integer
# Example:
#
# MagicSig.b64_to_n('AQAB')
# # -> 645537
def self.b64_to_n(str)
packed = decode64url(str)
packed.unpack('B*')[0].to_i(2)
end
# Parse a string containing a magic-public-key into an OpenSSL::PKey::RSA key.
# Example:
#
# key = MagicSig.parse_key('RSA.mVgY8RN6URBTstndvmUUPb4UZTdwvwmddSKE5z_jvKUEK6yk1u3rrC9yN8k6FilGj9K0eeUPe2hf4Pj-5CmHww.AQAB')
# key.n
# # -> 8031283789075196565022891546563591368344944062154100509645398892293433370859891943306439907454883747534493461257620351548796452092307094036643522661681091
# key.e
# # -> 65537
def self.parse_key(str)
n,e = str.match(/^RSA.([^.]*).([^.]*)$/)[1..2]
build_key(b64_to_n(n),b64_to_n(e))
end
# Take two integers e, n and create a new OpenSSL::PKey::RSA key with them
# Example:
#
# n = 9487834027867356975347184933768917275269369900665861930617802608089634337052392076689226301419587057117740995382286148368168197915234368486155306558161867
# e = 65537
# key = MagicSig.build_key(n,e)
# key.public_encrypt(...) # for sending to strangers
# key.public_decrypt(...) # very rarely used
# key.verify(...) # for verifying signatures
def self.build_key(n,e)
key = OpenSSL::PKey::RSA.new
key.n = n
key.e = e
key
end
end
class MagicSigEnvelope
attr_accessor :data, :data_type, :encoding, :alg, :sig, :user
def self.parse(doc)
env = self.new
ns = {'me'=>'http://salmon-protocol.org/ns/magic-env'}
env.encoding = doc.search('//me:env/me:encoding', ns).text.strip
env.data = doc.search('//me:env/me:data', ns).text
env.alg = doc.search('//me:env/me:alg', ns).text.strip
env.sig = doc.search('//me:env/me:sig', ns).text
env.data_type = doc.search('//me:env/me:data', ns).first['type'].strip
env
end
def self.create(user, activity)
env = MagicSigEnvelope.new
env.user = user
env.data = Base64.urlsafe_encode64(activity)
env.data_type = env.get_data_type
env.encoding = env.get_encoding
env.alg = env.get_alg
env.sig = Base64.urlsafe_encode64(
user.encryption_key.sign OpenSSL::Digest::SHA256.new, env.signable_string )
env
end
def signable_string
[@data, Base64.urlsafe_encode64(@data_type),Base64.urlsafe_encode64(@encoding), Base64.urlsafe_encode64(@alg)].join(".")
end
def to_xml
xml= <<ENTRY
<me:env xmlns:me="http://salmon-protocol.org/ns/magic-env">
<me:data type='#{@data_type}'>#{@data}</me:data>
<me:encoding>#{@encoding}</me:encoding>
<me:alg>#{@alg}</me:alg>
<me:sig>#{@sig}</me:sig>
</me:env>
ENTRY
xml
end
def get_encoding
'base64url'
end
def get_data_type
'application/atom+xml'
end
def get_alg
'RSA-SHA256'
end
end
end

View file

@ -29,7 +29,7 @@ namespace :db do
MongoMapper::connection.drop_database(MongoMapper::database.name) MongoMapper::connection.drop_database(MongoMapper::database.name)
puts 'Deleting tmp folder...' puts 'Deleting tmp folder...'
`rm -rf #{File.dirname(__FILE__)}/../../public/uploads/tmp` `rm -rf #{File.dirname(__FILE__)}/../../public/uploads/*`
end end
desc 'Purge and seed the current RAILS_ENV database using information from db/seeds.rb' desc 'Purge and seed the current RAILS_ENV database using information from db/seeds.rb'

View file

@ -0,0 +1,13 @@
Created by Joseph Wain (see http://penandthink.com) at and probably downloaded from http://glyphish.com
This work is licensed under the Creative Commons Attribution 3.0 United States License. To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/ or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
You are free to share it and to remix it remix under the following conditions:
* You must attribute the work in the manner specified by the author (SEE BELOW).
* For any reuse or distribution, you must make clear to others the license terms of this work.
* The above conditions can be waived if you get permission from the copyright holder (send me an email!).
ATTRIBUTION -- a note reading "icons by Joseph Wain / glyphish.com" or similar, plus a link back to glyphish.com from your app's website, is the preferred form of attribution. Also acceptable would be, like, a link from within your iPhone application, or from the iTunes store page, but those aren't as useful to other people. If none of these work for you, please contact hello@glyphish.com and we can work something out.
USE WITHOUT ATTRIBUTION -- If attribution is not possible, workable or desirable for your application, contact hello@glyphish.com for commercial non-attributed licensing terms.

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 263 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 743 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Some files were not shown because too many files have changed in this diff Show more