Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

Publish through JS #99

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions app/assets/javascripts/private_pub.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,22 @@ function buildPrivatePub(doc) {

fayeExtension: {
outgoing: function(message, callback) {
if (message.channel == "/meta/subscribe") {
// Attach the signature and timestamp to subscription messages
var subscription = self.subscriptions[message.subscription];
if (!message.channel.match(/^\/meta\/(?!subscribe).*/)) {
var channel = message.channel == '/meta/subscribe' ? message.subscription : message.channel;
var subscription = self.subscriptions[channel];
if (!message.ext) message.ext = {};
message.ext.private_pub_signature = subscription.signature;
// Attach the timestamp to messages
message.ext.private_pub_timestamp = subscription.timestamp;

if (message.channel == "/meta/subscribe") {
// Attach the signature to subscription messages
message.ext.private_pub_signature = subscription.sub_signature;
} else {
// Attach the signature to subscription messages
message.ext.private_pub_signature = subscription.pub_signature;
}
}

callback(message);
}
},
Expand Down Expand Up @@ -89,6 +98,12 @@ function buildPrivatePub(doc) {

subscribe: function(channel, callback) {
self.subscriptionCallbacks[channel] = callback;
},

publish: function(channel, message) {
self.faye(function(faye) {
faye.publish(channel, {channel: channel, data: message});
});
}
};
return self;
Expand Down
9 changes: 7 additions & 2 deletions lib/private_pub.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,16 @@ def message(channel, data)
# Returns a subscription hash to pass to the PrivatePub.sign call in JavaScript.
# Any options passed are merged to the hash.
def subscription(options = {})
sub = {:server => config[:server], :timestamp => (Time.now.to_f * 1000).round}.merge(options)
sub[:signature] = Digest::SHA1.hexdigest([config[:secret_token], sub[:channel], sub[:timestamp]].join)
sub = {:publish => false, :server => config[:server], :timestamp => (Time.now.to_f * 1000).round}.merge(options)
sub[:sub_signature] = generate_signature(sub, false)
sub[:pub_signature] = generate_signature(sub, true) if sub[:publish]
sub
end

def generate_signature(options, publish)
Digest::SHA1.hexdigest([publish ? "pub" : "sub", config[:secret_token], options[:channel], options[:timestamp]].join)
end

# Determine if the signature has expired given a timestamp.
def signature_expired?(timestamp)
timestamp < ((Time.now.to_f - config[:signature_expiration])*1000).round if config[:signature_expiration]
Expand Down
43 changes: 32 additions & 11 deletions lib/private_pub/faye_extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,55 @@ class FayeExtension
# Callback to handle incoming Faye messages. This authenticates both
# subscribe and publish calls.
def incoming(message, callback)
if message["channel"] == "/meta/subscribe"
authenticate_subscribe(message)
elsif message["channel"] !~ %r{^/meta/}
if is_subscription? message
check_signature(message)
elsif is_not_meta? message
authenticate_publish(message)
end

callback.call(message)
end

private

# Ensure the subscription signature is correct and that it has not expired.
def authenticate_subscribe(message)
subscription = PrivatePub.subscription(:channel => message["subscription"], :timestamp => message["ext"]["private_pub_timestamp"])
if message["ext"]["private_pub_signature"] != subscription[:signature]
def is_subscription?(message)
message["channel"] == "/meta/subscribe"
end

def is_not_meta?(message)
message["channel"] !~ %r{^/meta/}
end

def channel_of(message)
message[is_subscription?(message) ? "subscription" : "channel"]
end

# Ensure a signature is correct and that it has not expired.
def check_signature(message)
subscription = PrivatePub.subscription(:publish => true, :channel => channel_of(message), :timestamp => message["ext"]["private_pub_timestamp"])
expected_signature = is_subscription?(message) ? subscription[:sub_signature] : subscription[:pub_signature]

if message["ext"]["private_pub_signature"] != expected_signature
message["error"] = "Incorrect signature."
elsif PrivatePub.signature_expired? message["ext"]["private_pub_timestamp"].to_i
message["error"] = "Signature has expired."
end
end

# Ensures the secret token is correct before publishing.
# Ensures either the correct secret token or publish signature is set
def authenticate_publish(message)
if PrivatePub.config[:secret_token].nil?
raise Error, "No secret_token config set, ensure private_pub.yml is loaded properly."
elsif message["ext"]["private_pub_token"] != PrivatePub.config[:secret_token]
message["error"] = "Incorrect token."
end

if message["ext"]["private_pub_token"]
if message["ext"]["private_pub_token"] != PrivatePub.config[:secret_token]
message["error"] = "Incorrect token."
else
message["ext"]["private_pub_token"] = nil
end
else
message["ext"]["private_pub_token"] = nil
check_signature message
end
end
end
Expand Down
5 changes: 3 additions & 2 deletions lib/private_pub/view_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ def publish_to(channel, data = nil, &block)
# Subscribe the client to the given channel. This generates
# some JavaScript calling PrivatePub.sign with the subscription
# options.
def subscribe_to(channel)
subscription = PrivatePub.subscription(:channel => channel)
def subscribe_to(channel, options = {})
options = {publish: false}.merge! options
subscription = PrivatePub.subscription(channel: channel, publish: options[:publish])
content_tag "script", :type => "text/javascript" do
raw("PrivatePub.sign(#{subscription.to_json});")
end
Expand Down