Private channels with Pusherapp (using Rails) - ruby-on-rails

I just got through the hello world for Pusherapp. Now I want to create private channels so users only read messages that they are supposed to read.
The Pusher docs only give some details on how to do this, and I'm kind of lost.
From the docs:
...
The Pusher JS library is returned
a socket_id when it connects to
Pusher.
When it attempts to subscribe to a
private channel, it sends back an AJAX
request to your server with the
channel_name and socket_id as
parameters.
The default URL for this is
http://yourserver.com/pusher/auth.
...
class PusherController < ApplicationController
def auth
if current_user
response = Pusher[params[:channel_name]].authenticate(params[:socket_id])
render :json => response
else
render :text => "Not authorized", :status => '403'
end
end
end
Given a unique user id (current_user.id), how can I authenticate that user then have him/her subscribe to the corresponding channel?
Thanks

This blog post on the implementation seems to explain things a bit more: https://pusher.com/docs/client_api_guide/client_private_channels
The authorization scheme is based on
the idea that, rather than
implementing custom user
authentication, and adding complexity
and state to pusher, we should trust
the existing level of authentication
offered by your application. We also
wanted to ensure that someone reading
data sent from your application to the
browser would not be able to connect
to a channel as that user, and
therefore couldn't include any secrets
in the page HTML.
Sounds like your application's business logic should authenticate the user and decide that they should access the private channel.
Their diagram shows:
Once authenticated, the app requests to subscribe the user. Pusher replies with the socket_id. Then they are connected using that.
Here's how they describe it:
As shown in this diagram, a unique
socket id is generated and sent to the
browser by Pusher. This is sent to
your application (1) via an AJAX
request which authorizes the user to
access the channel against your
existing authentication system. If
successful your application returns an
authorization string to the browser
signed with you Pusher secret. This is
sent to Pusher over the WebSocket,
which completes the authorization (2)
if the authorization string matches.
The example at the bottom of the blog post further clarifies:
Suppose you have a channel called project-3, to which users A and B have access, but not C. You'd like to make this channel private so that user C cannot listen in on the private events. Simply send events to private-project-3 and subscribe to it in the browser. As long as you're using the latest javascript (version 1.3 or above), you'll see that a POST request is made to your application to /pusher/auth. This will currently fail, and therefore the subscribe request will not be made to the socket.
So, to me this sounds like:
1) Request to subscribe is sent to Pusher
2) Pusher POSTs to your /auth method to determine if the user can access the channel
3) If your business logic allows the user to access this channel, the auth method returns the "ok" response:
auth = Pusher[params[:channel_name]].socket_auth(params[:socket_id])
content_type 'application/json'
return JSON.generate({
:auth => auth
})
I haven't used Pusher itself, but its model seems to mirror the structure of other push-based models. Hope this helps!

Related

Using send API of gupshup to reply to a user within 24 hrs shows an User not opted-in error

I have my own bot running locally and have made it publicly accessible using ngrok
Trying to use the sandbox environment of gupshup to communicate with my bot.
Have hooked my bot using webhook (link your bot)
Have also created a BOT and configured the webhook as a callback POST to my ngrok server.
However when i try replying to a user supplied whats app message after say about 10 min using the Delayed response strategy i.e. by passing the contextobj and message via the send API (http://api.gupshup.io/sm/api/bot/{botname}/msg), I get an error stating "User Not Opted In".
Why isnt the user considered as an Active User since the messaging was initiated by the user and the send API is only replying to that message with 24 hrs ?
How do i simply give a delayed response to the user within 24hrs without forcing the user to opt-in ?
We do this all the time, however we are using the endpoint documented here:
https://www.gupshup.io/developer/docs/bot-platform/guide/whatsapp-api-documentation#OutboundMessage
You have to take the consent of user once before sending messages.
Also while using sandbox the user needs to opt in but for verified user it will be relaxed.
But still you will need to take consent of user at any place (your site, your terms and conditions or anywhere) before sending him anything for the record purposes so that they cannot claim that you are spamming them without consent.

handle sending sms between users over Twilio

I've read THIS Twilio post on how to enable text messaging between users. I am building using Ruby on Rails.
At the moment, this is what I have:
A messaging system in my app where users can inbox each other.
When a user X messages another user Y, the application also sends that message to user Y's email address. User Y can reply to the message on the app or by responding to the email received by user X. If user Y choses to respond to the email (inbound email) my application processes the email received - it knows that it is intended for user X so it will forward that the email to user X's email address.
This is great because I'm giving the user several means of communication between each other (in app or email).
Now i'd like a similar but instead using the Twilio API.
Particularly i'd like to enable this type of communication:
As per Twilio help center
I'm having trouble understanding the concept of having multiple numbers that can be used by different user but somehow you know who's the message for...( Wow, I'm even having trouble describing what i'm having trouble with!)
I'm using the Ruby wrapper for the Twilio API
To send a message to user it is fairly simple:
# set up a client to talk to the Twilio REST API
#client = Twilio::REST::Client.new account_sid, auth_token
# send sms
#client.messages.create(
from: 'twilio_number',
to: 'a user number',
body: 'Hey there!'
)
To receive a message:
First configure the your Twilio phone number request url to point to an endpoint in your application. In my case its 'yourappurl.com/twilio/create'.
class TwilioController < ApplicationController
include Webhookable
after_filter :set_header
skip_before_action :verify_authenticity_token
def create
# inbound messages arrive here. Need to do something with the message, identify who's it for
# the receiving user and where its coming from ( the user who sent the text message)
render_twiml response
end
end
However this is for my application sending a message to a user's phone number. How can I handle communication between two users where user X can communicate with user Y via text messages (all going through my application)
Twilio developer evangelist here.
The help centre article on sending messages between users has a great explanation of how to implement this in theory, however you probably want to see some code.
Your best bet is to work through this tutorial on Masked numbers with Twilio which shows you practically how you would purchase a number for a user and then connect two users through that number.
In brief, you need to get a number that represents a relationship between two users. When you receive a message at that number and you get the webhook from Twilio then you can look up the relationship based on the Twilio number the message was sent to and the number it was sent from. You can then connect and send the message on to the number on the other side of the relationship.
But, as I said, I recommend going through the tutorial to really learn this in depth.
Let me know if this helps at all.

Can BigCommerce Private Apps use OAuth

I am very confused by the BC documentation on their API, because they let you create "Draft Apps" (private apps) and now I see that in their documentation they say "We do not currently provide a means of keeping OAuth apps private.".
My concern here is that they made some changes recently that might have affected a few of my Private Apps that I had running just fine a month ago. If anyone can provide some insight, I would appreciate it greatly!
https://developer.bigcommerce.com/api/guides/oauth-transition
There is nothing wrong with creating oAuth credentials with a "Draft App" for the sole purpose of accessing the API of your store. You do not ever have to publish your app and your app will never be made "public" in that case. You also don't have to bother with the 'Load Callback URL' and filling out the details on your draft app, unless you want to provide yourself an interface in the store.
The "Draft App" function was specifically meant to allow Developers building apps for the BC App Marketplace to test their apps in a store before submission. However, you can use it to make a private application that is only intended for your store - I'm including the process here for others!
Making a Private App with oAuth (or How to Generate oAuth Credentials for a Store)
What you will need
Access to the account listed as the "store owner" of the store where you want to install your app or the ability to get a person with access to complete a couple steps
Ability to setup a local or public URL to receive the 'Auth Callback Request'
Getting started
The first thing you should do is sort out making available a local or public URL that can receive an "Auth Callback" request. This resource must be able to work over an HTTPS connection but the SSL can be self-signed. The 'Auth Callback' request from Bigcommerce is a GET request that will have 3 query parameters on the URL: code, scope, and context.
It is described in greater detail here:
https://developer.bigcommerce.com/api/callback#get-req
Additional info
When building a public app it is important that the service receiving the Auth Callback request be configured to catch the 3 query values and combine them with information you already have. You would then send all of this information in a POST to the BC oAuth Token service to generate your API token for the store. In addition to that you would want to respond to the Auth Callback request with a 200 status and an interface, or instructions, for the user.
In the context of building a private application you don't need to worry about any of that. All you need to do is capture the query values. If you have this already then go ahead and jump down to the section on generating an API token below.
Before Moving On
You should have a URL path that can receive a GET request and captures query parameters. Test it out and make sure it works. Here are a couple example URLs:
https://example.com/auth-callback
https://localhost:8000/auth-service
Registering an App
The key point here is that the registration of the app must be completed by the store owner account of the store where you want to install the app. If you have access to the store owner account credentials then follow the steps at the bottom of this page:
https://developer.bigcommerce.com/api/registration
If you are working with the store owner then you can direct them to complete the steps above. You will need to provide them the Auth Callback URL you created for completing Step 9. The Load Callback URL does have to be filled in but the default example provided can be left in place.
SCOPES
When registering an app you are able to choose the scopes for the app. It is simple to just leave them all open but it is best practice to only enable the scopes you need. Here is a list of the scopes:
https://developer.bigcommerce.com/api/scopes
If you are not sure whether or not you will need a certain scope then leave it enabled because you will have to re-generate your API Token (perform a re-install of the app) if you have to change the scopes on your app.
Before Moving On
You need to have the client_id and client_secret. If someone else registered the app then you will need to ask them for this. There is a View Client ID button that will provide it after registering an app.
Generate the Auth Callback Request
You will need the person with store owner access again for this step. They will need to login to their store and go to the Apps section on the left side column. After that click on Marketplace -> then My Apps (in the top-right) -> then My Draft Apps
You should now see a list containing any "apps" that the store owner has registered. Choose the one relating to the client_id you plan to use. Click to install the app.
The Auth Callback request has now been sent and you are done here. You should expect to see just a blank or grey page as a result unless you are responding to the Auth Callback request with content. Your app is now awaiting authentication.
If using a self-signed certificate
When your Auth Callback URL has a self-signed certificate then you will see a "untrusted cert" error in your browser when you attempt installation of the app. You should choose to trust the certificate and continue.
Before Moving On
You should now have received the code, scope, and context at your Auth Callback URL. If you did not it was likely due to not having SSL/TLS at your server. You can replay the Auth Callback request as many times as needed by Cancelling Installation of the app in the same place where you started it. You can even open up a Dev tool and watch the request happen to see what errors show up in the console. If this is continuing to fail then you should reach out to Bigcommerce support or ask a new question on here!
Generating an API Token to Complete Installation
Follow the steps here:
https://developer.bigcommerce.com/api/callback#post-req
You should have all of the details needed to send a POST request to the BC Auth Token Service at https://login.bigcommerce.com/oauth2/token
Make sure to URL encode your content and you should be good! Here is a site that can URL encode and decode for you: http://meyerweb.com/eric/tools/dencoder/
Just be careful of it encoding & and = signs when those are actually being used as separators between fields or between field/value (respectively).
Before Moving On
You should have received a successful response from the Auth service which will include your API Token. Once you have this you are all set to access the API of the store. You no longer need to have your Auth Callback URL up and available and can take that down.
Also take note of the context to use to create your API path.
Accessing the API
Now that you have your API Token and context you are all set to access the API of a store. Start off with a simple request to the /time endpoint.
Make a GET request and include the following headers (minus the curly braces):
X-Auth-Client: {CLIENT_ID}
X-Auth-Token: {API_TOKEN}
Accept: application/json
Content-Type: application/json
Send your request to a URL path of (minus curly braces):
https://api.bigcommerce.com/{context}/v2/time
If you get back a 200 response then you are all set!
Additional Notes - Ways to Break Credentials
Once you have successfully generated an API Token for a certain app, that app will display in the Control Panel as an icon in the Apps section. The fact the app is there shows it is installed and allowing access. If you uninstall that app then the previously generated API token will stop working.
Changing the scopes on an already installed app will require it to be re-installed to correct the token.
Changing the store owner email on the store will cause the token to stop working. The API Token is specifically tied to the store owner that registered the app.
if you have apps in "My draft apps" and you used basic oauth, you will have to change to Oauth Authentication, but if only have private apps using "legacy api account", you will not need to change.

facebook puts access code in web page

Trying to write a facebook app and am attempting authentication. This is a rails 3.1 application
The First redirect where I give facebook my api and it returns a code seems to run well. But when I try to take that code and 'exchange it' from a access_token I run into problems.
The access token appears where the iframe aws.
Here is my code.
def index
#Load facebook.yml info
config = YAML::load(File.open("#{Rails.root}/config/facebook.yml"));
# setup client
redirect_to "https://graph.facebook.com/oauth/authorize?client_id=#{config['development']['app_id']}&redirect_uri=#{CALLBACK_URI}"
end
def callback
logger.debug("c")
config = YAML::load(File.open("#{Rails.root}/config/facebook.yml"));
if (!params.key?('access_token'))
logger.debug("A")
redirect_to "https://graph.facebook.com/oauth/access_token?client_id=# {config['development']['app_id']}&redirect_uri=#{CALLBACK_URI}&client_secret=#{config['development']['client_secret']}&code=#{params['code']}"
return
end
logger.debug("B")
access_token = params['access_token']
#me = FbGraph::User.me(ACCESS_TOKEN)
#name=#me.name
end
end
You are not supposed to redirect the user’s browser to the second endpoint (think for a moment, you are putting your app secret into that URL, so it would be easy for everyone to spot it there) – you are supposed to make a server-side call to that endpoint.
The docs clearly say so, https://developers.facebook.com/docs/authentication/server-side/:
“Once the user has authorized your app, you should make a server side request to exchange the code returned above for a user access token.”

Provide my users with a realtime API using Pusher

I'm using Pusher to add realtime functionality to my app. Is there a way to provide my users with realtime functionality through an API? I'm using private and presence channels, so connections to these need to be authenticated. Has anyone worked with Pusher and provided some sort of API to their users?
I'm doing this using Rails 3.1.
The solution here is to give the users you want to be able to access your data your app_key (not app_secret). They can then connect to Pusher and try to subscribe to your channels. They'll need to use JSONP authentication which makes a call to your server where you can authenticate the request to the private or presence channels.
Pusher.channel_auth_endpoint = 'http://yourserver.com/pusher_jsonp_auth';
Pusher.channel_auth_transport = 'jsonp';
var pusher = new Pusher('YOUR_APP_KEY');
var channel = pusher.subscribe('private-your-channel');
channel.bind('your_event', function(data) {
// do something here with data
});
In your authentication you'll need to check the referrer (domain) to see if you've given them access to your data along with what they are subscribing to.
You could also wrap this JavaScript up in your own library so that a subscription_error (authentication error) disconnects the client from Pusher.
Hope this helps. You can always drop an email to support#pusher.com too.

Resources