Been at this for a week: every, single, day. Nothing is working.
How hard is it for a minimal authentication? I bet so many people are looking for this answer too.
Here is rough-draft of what we've got so far:
import cbpro, hmac, hashlib, time,
api_key = "[YOUR_API_KEY]"
secret_key = "[YOUR_B64SECRET]"
passphrase = "[YOUR_PASSPHRASE]"
message = message.encode('ascii')
hmac_key = base64.b64decode(secret_key)
signature = hmac.new(hmac_key, message, hashlib.sha256)
signature_b64 = base64.b64encode(signature.digest()).decode('utf-8')
auth_client = cbpro.AuthenticatedClient(api_key, signature_b64, passphrase)
auth_client.get_accounts()
or while subscribing with websockets, something with this:
{
"type": "subscribe",
"product_ids": [
"BTC-USD"
],
"channels": ["full"],
"signature": "...",
"key": "...",
"passphrase": "...",
"timestamp": "..."
}
using:
socket = "wss://ws-feed.pro.coinbase.com"
ws = websocket.WebSocketApp(socket, on_open=on_open, on_message=on_message)
ws.run_forever()
I dont understand why a simply few lines of code to authenticate and view open orders/account is so hard, while subscribing to the websocket ticker and receiving price changes is so easy. Encoding the secret key shouldnt be too hard? Please help us with a super short and simple example (without all the "init"s and imports and different functions with passing). Sheesh
"I dont understand why a simply few lines of code to authenticate and view open orders/account is so hard, while subscribing to the websocket ticker and receiving price changes is so easy."
This is because your code will not produce an authenticated websockets session. The session is secured using 'wss' aka TLS, but inside of this session, you are not authenticated to their server and therefore you do not receive enhanced data elements for trade messages in which your account is involved. Receiving price data does not require being authenticated.
This is just like you are visiting a website at its "https" address, but are not logged in. "Public" data is being sent to you across a secure connection.
The cbpro module creates an AuthenticatedClient instance by passing to it the unaltered api key, base64-encoded secret, and passphrase. You should really review any module's code base before trusting it with your authentication data, or even installing it on your machine, but to each their own.
import cbpro #, hmac, hashlib, time,
api_key = YOUR_API_KEY
secret_key = YOUR_B64SECRET
passphrase = YOUR_PASSPHRASE
# message = message.encode('ascii')
# hmac_key = base64.b64decode(secret_key)
# signature = hmac.new(hmac_key, message, hashlib.sha256)
# signature_b64 = base64.b64encode(signature.digest()).decode('utf-8')
auth_client = cbpro.AuthenticatedClient(api_key, secret_key, passphrase)
auth_client.get_accounts()
You can test out what I am saying about how your websocket code is not properly authenticating either by running your wss client and subscribing to only the "user" channel for a product before placing a trade in for that product. With no other channels subscribed, you will receive a message indicating that the server received your new order. You can then cancel the order after testing. If your code does somehow allow you to receive messages in the "user" channel, then CoinbasePro is doing something different from what is published in its documentation.
Related
I'm building a web app that has a chat feature. I'm using Laravel 5.4 for the backend and Angular 4 for the front-end.
Everything is working (meaning I can broadcast and recieve) but I'm not at all sure how to secure it. The chat will always be 1 to 1 so its private and has to be secure. Each chat room will have a unique id but somebody could still listen in.
Currently I'm using JWTs for authentication when I make requests from my frontend to my API, but I'm not sure if its possible to implement something similar for this. I know I can pass the token from the frontend using the query option but than I'm unsure how to parse it and I'm also unsure how to verify that it indeed belongs to the user that is trying to access the chat (should I make a request to the API to verify in server.js? That doesn't seem efficient. Is it good enough to compare the user id of the token to the user id that will be passed in the data?)
If anybody has any advice or knows a better way to do it, it would be greatly apperciated
Event that is fired off from Laravel when a new message is posted
class NewMessage implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $data;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct()
{
$this->data = array(
'message'=> 'hi'
);
}
/**
* Get the channels the event should broadcast on.
*
* #return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('chat');
}
}
server.js (node.js)
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
redis.psubscribe('private-chat', function(err, count) {
console.log('psubscribe');
});
redis.on('pmessage', function(subscribed, channel, message) {
console.log('pmessage', subscribed, channel, message);
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
http.listen(3000, function(){
console.log('Listening on Port 3000');
});
Frontend component
socket: io.Socket;
this.socket = io.connect("http://webapp.test:3000", { query: this.token });
this.socket.on("private-chat:App\\Events\\NewMessage", (data) =>
{
console.log("Data", data);
});
Try to use SSL (confidentiality)
SSL as we know ensures that the server you're communicating with is actually the webservice you want.
Authentication (To avoid certificate pinning)
You need authentication in your case you are using JWT with HS256, I would strongly recommend you to use RS256 algorythm JWT in this case with private and public keys.
It doesn't matter that nobody else can listen to the conversation between the two of you if you don't know for sure who's on the other end (authentication).
Since I would build the app in the way that if session authentication between two channels its not set then never unfold the content of the data that is being send.
Unique session
As slong as your sevice is authenticated using JWT you send them back an authentication token. This is as simple as a random number or a GUID. This identifier will be required as part of any request to send or receive data on this channel during this session, it will only be accepted on this particular channel, and only as long as this unique session is open.
One more security check: link reply attack
I gave you the tips that I use everyday to seccurely send data back and forth with central banks (so following those tips I think your app should be pretty secure)
UPDATE
How to handle JWT
Create a new middleware Verify JWT token since the middleware in laravel its outter layer of core vendor that means if authentication fails it fails in outter layer not in core.
Group the routes under Verify JWT token middleware!
Create a RedisRepository this could be under App\RedisRepository. This class should be responsible for fetching data from redis.
On middleware decrypt user JWT get the decrypted payload(this might be user UUID or ID).
Fetch user ID from RedisRepository compare with the decrypted payload if positive authentication passes otherwise abort 403 unauthenticated!
I'm trying to implement oauth2 authentication on my nodejs Google Assistant app developed using (DialogFlow or API.ai and google actions).
So I followed this answer. But I'm always getting "It looks like your test oauth account is not linked yet. " error. When I tried to open the url shown on the debug tab, it shows 500 broken url error.
Dialogflow fullfillment
index.js
'use strict';
const functions = require('firebase-functions'); // Cloud Functions for Firebase library
const DialogflowApp = require('actions-on-google').DialogflowApp; // Google Assistant helper library
const googleAssistantRequest = 'google'; // Constant to identify Google Assistant requests
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
console.log('Request headers: ' + JSON.stringify(request.headers));
console.log('Request body: ' + JSON.stringify(request.body));
// An action is a string used to identify what needs to be done in fulfillment
let action = request.body.result.action; // https://dialogflow.com/docs/actions-and-parameters
// Parameters are any entites that Dialogflow has extracted from the request.
const parameters = request.body.result.parameters; // https://dialogflow.com/docs/actions-and-parameters
// Contexts are objects used to track and store conversation state
const inputContexts = request.body.result.contexts; // https://dialogflow.com/docs/contexts
// Get the request source (Google Assistant, Slack, API, etc) and initialize DialogflowApp
const requestSource = (request.body.originalRequest) ? request.body.originalRequest.source : undefined;
const app = new DialogflowApp({request: request, response: response});
// Create handlers for Dialogflow actions as well as a 'default' handler
const actionHandlers = {
// The default welcome intent has been matched, welcome the user (https://dialogflow.com/docs/events#default_welcome_intent)
'input.welcome': () => {
// Use the Actions on Google lib to respond to Google requests; for other requests use JSON
//+app.getUser().authToken
if (requestSource === googleAssistantRequest) {
sendGoogleResponse('Hello, Welcome to my Dialogflow agent!'); // Send simple response to user
} else {
sendResponse('Hello, Welcome to my Dialogflow agent!'); // Send simple response to user
}
},
// The default fallback intent has been matched, try to recover (https://dialogflow.com/docs/intents#fallback_intents)
'input.unknown': () => {
// Use the Actions on Google lib to respond to Google requests; for other requests use JSON
if (requestSource === googleAssistantRequest) {
sendGoogleResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
} else {
sendResponse('I\'m having trouble, can you try that again?'); // Send simple response to user
}
},
// Default handler for unknown or undefined actions
'default': () => {
// Use the Actions on Google lib to respond to Google requests; for other requests use JSON
if (requestSource === googleAssistantRequest) {
let responseToUser = {
//googleRichResponse: googleRichResponse, // Optional, uncomment to enable
//googleOutputContexts: ['weather', 2, { ['city']: 'rome' }], // Optional, uncomment to enable
speech: 'This message is from Dialogflow\'s Cloud Functions for Firebase editor!', // spoken response
displayText: 'This is from Dialogflow\'s Cloud Functions for Firebase editor! :-)' // displayed response
};
sendGoogleResponse(responseToUser);
} else {
let responseToUser = {
//richResponses: richResponses, // Optional, uncomment to enable
//outputContexts: [{'name': 'weather', 'lifespan': 2, 'parameters': {'city': 'Rome'}}], // Optional, uncomment to enable
speech: 'This message is from Dialogflow\'s Cloud Functions for Firebase editor!', // spoken response
displayText: 'This is from Dialogflow\'s Cloud Functions for Firebase editor! :-)' // displayed response
};
sendResponse(responseToUser);
}
}
};
// If undefined or unknown action use the default handler
if (!actionHandlers[action]) {
action = 'default';
}
// Run the proper handler function to handle the request from Dialogflow
actionHandlers[action]();
// Function to send correctly formatted Google Assistant responses to Dialogflow which are then sent to the user
function sendGoogleResponse (responseToUser) {
if (typeof responseToUser === 'string') {
app.ask(responseToUser); // Google Assistant response
} else {
// If speech or displayText is defined use it to respond
let googleResponse = app.buildRichResponse().addSimpleResponse({
speech: responseToUser.speech || responseToUser.displayText,
displayText: responseToUser.displayText || responseToUser.speech
});
// Optional: Overwrite previous response with rich response
if (responseToUser.googleRichResponse) {
googleResponse = responseToUser.googleRichResponse;
}
// Optional: add contexts (https://dialogflow.com/docs/contexts)
if (responseToUser.googleOutputContexts) {
app.setContext(...responseToUser.googleOutputContexts);
}
app.ask(googleResponse); // Send response to Dialogflow and Google Assistant
}
}
// Function to send correctly formatted responses to Dialogflow which are then sent to the user
function sendResponse (responseToUser) {
// if the response is a string send it as a response to the user
if (typeof responseToUser === 'string') {
let responseJson = {};
responseJson.speech = responseToUser; // spoken response
responseJson.displayText = responseToUser; // displayed response
response.json(responseJson); // Send response to Dialogflow
} else {
// If the response to the user includes rich responses or contexts send them to Dialogflow
let responseJson = {};
// If speech or displayText is defined, use it to respond (if one isn't defined use the other's value)
responseJson.speech = responseToUser.speech || responseToUser.displayText;
responseJson.displayText = responseToUser.displayText || responseToUser.speech;
// Optional: add rich messages for integrations (https://dialogflow.com/docs/rich-messages)
responseJson.data = responseToUser.richResponses;
// Optional: add contexts (https://dialogflow.com/docs/contexts)
responseJson.contextOut = responseToUser.outputContexts;
response.json(responseJson); // Send response to Dialogflow
}
}
});
// Construct rich response for Google Assistant
const app = new DialogflowApp();
const googleRichResponse = app.buildRichResponse()
.addSimpleResponse('This is the first simple response for Google Assistant')
.addSuggestions(
['Suggestion Chip', 'Another Suggestion Chip'])
// Create a basic card and add it to the rich response
.addBasicCard(app.buildBasicCard(`This is a basic card. Text in a
basic card can include "quotes" and most other unicode characters
including emoji 📱. Basic cards also support some markdown
formatting like *emphasis* or _italics_, **strong** or __bold__,
and ***bold itallic*** or ___strong emphasis___ as well as other things
like line \nbreaks`) // Note the two spaces before '\n' required for a
// line break to be rendered in the card
.setSubtitle('This is a subtitle')
.setTitle('Title: this is a title')
.addButton('This is a button', 'https://assistant.google.com/')
.setImage('https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
'Image alternate text'))
.addSimpleResponse({ speech: 'This is another simple response',
displayText: 'This is the another simple response 💁' });
// Rich responses for both Slack and Facebook
const richResponses = {
'slack': {
'text': 'This is a text response for Slack.',
'attachments': [
{
'title': 'Title: this is a title',
'title_link': 'https://assistant.google.com/',
'text': 'This is an attachment. Text in attachments can include \'quotes\' and most other unicode characters including emoji 📱. Attachments also upport line\nbreaks.',
'image_url': 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
'fallback': 'This is a fallback.'
}
]
},
'facebook': {
'attachment': {
'type': 'template',
'payload': {
'template_type': 'generic',
'elements': [
{
'title': 'Title: this is a title',
'image_url': 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png',
'subtitle': 'This is a subtitle',
'default_action': {
'type': 'web_url',
'url': 'https://assistant.google.com/'
},
'buttons': [
{
'type': 'web_url',
'url': 'https://assistant.google.com/',
'title': 'This is a button'
}
]
}
]
}
}
}
};
Actually I deployed the code exists in the dialog flow inline editor. But don't know how to implement an oauth endpoint, whether it should be a separate cloud function or it has to be included within the existsing one. And also I am so confused with how oauth authorization code flow will actually work.. Let's assume we are on the Assistant app, once the user say "talk to foo app", does it automatically opens a web browser for oauth code exchange process?
The answer you referenced had an update posted on October 25th indicating they had taken action to prevent you from entering in a google.com endpoint as your auth provider for Account Linking. It seems possible that they may have taken other actions to prevent using Google's auth servers in this way.
If you're using your own auth server, the error 500 would indicate an error on your oauth server, and you should check your oauth server for errors.
Update to answer some of your other questions.
But don't know how to implement an oauth endpoint
Google provides guidance (but not code) on what you need to do for a minimal OAuth service, either using the Implicit Flow or the Authorization Code Flow, and how to test it.
whether it should be a separate cloud function or it has to be included within the existing one
It should be separate - it is even arguable that it must be separate. In both the Implicit Flow and the Authorization Code Flow, you need to provide a URL endpoint where users will be redirected to log into your service. For the Authorization Code Flow, you'll also need an additional webhook that the Assistant will use to exchange tokens.
The function behind these needs to be very very different than what you're doing for the Dialogflow webhook. While someone could probably make a single function that handles all of the different tasks - there is no need to. You'll be providing the OAuth URLs separately.
However, your Dialogflow webhook does have some relationship with your OAuth server. In particular, the tokens that the OAuth server hands to the Assistant will be handed back to the Dialogflow webhook, so Dialogflow needs some way to get the user's information based on that token. There are many ways to do this, but to list just a few:
The token could be a JWT and contain the user information as claims in the body. The Dialogflow webhook should use the public key to verify the token is valid and needs to know the format of the claims.
The OAuth server and the Dialogflow webhook could use a shared account database, and the OAuth server store the token as a key to the user account and delete expired keys. The Dialogflow webhook could then use the token it gets as a key to look up the user.
The OAuth server might have a(nother) webhook where Dialogflow could request user information, passing the key as an Authorization header and getting a reply. (This is what Google does, for example.)
The exact solutions depends on your needs and what resources you have available to you.
And also I am so confused with how oauth authorization code flow will actually work.. Let's assume we are on the Assistant app, once the user say "talk to foo app", does it automatically opens a web browser for oauth code exchange process?
Broadly speaking - yes. The details vary (and can change), but don't get too fixated on the details.
If you're using the Assistant on a speaker, you'll be prompted to open the Home app which should be showing a card saying what Action wants permission. Clicking on the card will open a browser or webview to the Actions website to begin the flow.
If you're using the Assistant on a mobile device, it prompts you directly and then opens a browser or webview to the Actions website to begin the flow.
The auth flow basically involves:
Having the user authenticate themselves, if necessary.
Having the user authorize the Assistant to access your resources on the user's behalf.
It then redirects to Google's servers with a one-time code.
Google's servers then take the code... and close the window. That's the extent of what the user's see.
Behind the scenes, Google takes this code and, since you're using the Authorization Code Flow, exchanges it for an auth token and a refresh token at the token exchange URL.
Then, whenever the user uses your Action, it will send an auth token along with the rest of the request to your server.
Plz suggest the necessary package for OAuth2 configuration
That I can't do. For starters - it completely depends on your other resources and requirements. (And this is why StackOverflow doesn't like people asking for suggestions like this.)
There are packages out there (you can search for them) that let you setup an OAuth2 server. I'm sure someone out there provides OAuth-as-a-service, although I don't know any offhand. Finally, as noted above, you can write a minimal OAuth2 server using the guidance from Google.
Trying to create a proxy for Google's OAuth is... probably possible... not as easy as it first seems... likely not as secure as anyone would be happy with... and possibly (but not necessarily, IANAL) a violation of Google's Terms of Service.
can't we store the user's email address by this approach?
Well, you can store whatever you want in the user's account. But this is the user's account for your Action.
You can, for example, access Google APIs on behalf of your user to get their email address or whatever else they have authorized you to do with Google. The user account that you have will likely store the OAuth tokens that you use to access Google's server. But you should logically think of that as separate from the code that the Assistant uses to access your server.
My implementation of a minimal oauth2 server(works for the implicit flow but doesn't store the user session).
taken from https://developers.google.com/identity/protocols/OAuth2UserAgent.
function oauth2SignIn() {
// Google's OAuth 2.0 endpoint for requesting an access token
var oauth2Endpoint = 'https://accounts.google.com/o/oauth2/v2/auth';
// Create element to open OAuth 2.0 endpoint in new window.
var form = document.createElement('form');
form.setAttribute('method', 'GET'); // Send as a GET request.
form.setAttribute('action', oauth2Endpoint);
//Get the state and redirect_uri parameters from the request
var searchParams = new URLSearchParams(window.location.search);
var state = searchParams.get("state");
var redirect_uri = searchParams.get("redirect_uri");
//var client_id = searchParams.get("client_id");
// Parameters to pass to OAuth 2.0 endpoint.
var params = {
'client_id': YOUR_CLIENT_ID,
'redirect_uri': redirect_uri,
'scope': 'email',
'state': state,
'response_type': 'token',
'include_granted_scopes': 'true'
};
// Add form parameters as hidden input values.
for (var p in params) {
var input = document.createElement('input');
input.setAttribute('type', 'hidden');
input.setAttribute('name', p);
input.setAttribute('value', params[p]);
form.appendChild(input);
}
// Add form to page and submit it to open the OAuth 2.0 endpoint.
document.body.appendChild(form);
form.submit();
}
This implementation isn't very secure but it's the only code I've gotten to work as OAuth server for the Assistant.
I am able to make it work after a long time. We have to enable the webhook first and we can see how to enable the webhook in the dialog flow fulfillment docs If we are going to use Google Assistant, then we have to enable the Google Assistant Integration in the integrations first. Then follow the steps mentioned below for the Account Linking in actions on google:-
Go to google cloud console -> APIsand Services -> Credentials -> OAuth 2.0 client IDs -> Web client -> Note the client ID, client secret from there -> Download JSON - from json note down the project id, auth_uri, token_uri -> Authorised Redirect URIs -> White list our app's URL -> in this URL fixed part is https://oauth-redirect.googleusercontent.com/r/ and append the project id in the URL -> Save the changes
Actions on Google -> Account linking setup 1. Grant type = Authorisation code 2. Client info 1. Fill up client id,client secrtet, auth_uri, token_uri 2. Enter the auth uri as https://www.googleapis.com/auth and token_uri as https://www.googleapis.com/token 3. Save and run 4. It will show an error while running on the google assistant, but dont worry 5. Come back to the account linking section in the assistant settings and enter auth_uri as https://accounts.google.com/o/oauth2/auth and token_uri as https://accounts.google.com/o/oauth2/token 6. Put the scopes as https://www.googleapis.com/auth/userinfo.profile and https://www.googleapis.com/auth/userinfo.email and weare good to go. 7. Save the changes.
In the hosting server(heroku)logs, we can see the access token value and through access token, we can get the details regarding the email address.
Append the access token to this link "https://www.googleapis.com/oauth2/v1/userinfo?access_token=" and we can get the required details in the resulting json page.
`accessToken = req.get("originalRequest").get("data").get("user").get("accessToken")
r = requests.get(link)
print("Email Id= " + r.json()["email"])
print("Name= " + r.json()["name"])`
If my bot asks different questions and if the user answers each of them, how do I find out which answer relates to which question. There is a field called metadata that you can attach to the sendTextMessage API but when the user responds, this metadata comes in as undefined. Do you guys use any node-cache for tracking state or an FSM such as machina.js? How can I best figure out at what of the conversation we are currently stuck in?
When your app receives a message, there's no payload or metadata associated with it. This is as opposed to a quick-reply or post-back which can have a payload. The only way to associate a response with a question this is to manually track the conversation state in your app as suggested by #anshuman-dhamoon
To do this, it's best to maintain a state for each user, as well as the next state for each state.
// optionally store this in a database
const users = {}
// an object of state constants
const states = {
question1: 'question1',
question2: 'question2',
closing: 'closing',
}
// mapping of each to state to the message associated with each state
const messages = {
[states.question1]: 'How are you today?',
[states.question2]: 'Where are you from?',
[states.closing]: 'That\'s cool. It\'s nice to meet you!',
}
// mapping of each state to the next state
const nextStates = {
[states.question1]: states.question2,
[states.question2]: states.closing,
}
const receivedMessage = (event) => {
// keep track of each user by their senderId
const senderId = event.sender.id
if (!users[senderId].currentState){
// set the initial state
users[senderId].currentState = states.question1
} else {
// store the answer and update the state
users[senderId][users[senderId].currentState] = event.message.text
users[senderId].currentState = nextStates[users[senderId.currentState]]
}
// send a message to the user via the Messenger API
sendTextMessage(senderId, messages[users[senderId].currentState])
}
Note If you wanted, you can even make the values of nextStates into callable functions that take the answer of the current state and branch off into different conversation flows by passing the user to a different state depending on his/her response.
As per my knowledge,in Facebook chatbot you can send data from user to chatbot just by setting payload from postback buttons as they have given in API reference.
And chatbot won't store your session or any states/flags.you can set status or flags or arrays but all will be lost when you update your application or restart your server.
so,if you really want to set status you should use database for that.and senderID will remain same everytime so you can handle data from database by that particular id for particular user.
For more details checkout technical referance here.
I hope this will help you.if so,kindly mark it as an answer.
You can have a status code in your code, to keep track of where the user conversation with the bot is.
For eg. if you have 10 questions, keep statuscode = 0 initially, and ask the first question. When you receive a message to your webhook, check if statuscode==0, and store that user message as a response to your first question. Then increment statusCode=1 and ask the next question.
You can have multiple flags and statusCodes to deal with different conversation flows.
I'm running into this issue myself. Though it hasn't been mentioned at all in their documentation, I don't think attaching an in-memory database is out of the question. It seems that the user_id is the same regardless of when the conversation is initiated.
Making an API call every time the user rejoins the session would probably slow down the performance of the bot. Also, I noticed that you can't really construct a "pseudo-distributed database" by using the metadata key in the API if that is what you were suggesting. The metadata tag can be sent from Server -> Client (Messenger) but not from Client -> Server from what the documentation says.
I've spent some time working with this. The best solution is to use a database to track the user's conversation flow. The POST object contains the senders ID. You can use this ID to make a row in the database in which you'd definitely need to store this ID, any answers to the questions, and a field to keep track of of which step in the conversation.
Then you can use if statements in your code to return the proper responses. Some example code below:
if( $currentStep == '1' ){
// Ask Next Question
$message_to_reply = "Thank you! What's your name?";
$message_to_reply = '"text":"'.$message_to_reply.'"';
} elseif( $currentStep == '2' ){
// Ask Next Question
$message_to_reply = "Thank you! What's your email address?";
$message_to_reply = '"text":"'.$message_to_reply.'"';
} elseif( $currentStep == '3' ){
// Ask Next Question
$message_to_reply = "Thank you! What's your address?";
$message_to_reply = '"text":"'.$message_to_reply.'"';
}
I am trying to make a chat system where only two users are able to talk to each other at a time ( much like facebook's chat )
I've tried multiplexing, using mongoDB's _id as the name so every channel is unique.
The problem I'm facing is that I cannot direct a message to a single client connection.
this is the client side code that first sends the message
$scope.sendMessage = function() {
specificChannel.send(message)
$scope.messageText = '';
};
this is the server side receiving the message
specificChannel.on('connection', function (conn) {
conn.on('data', function(message){
conn.write('message')
}
}
When I send a message, to any channel, every channel still receives the message.
How can I make it so that each client only listens to the messages sent to a specific channel?
It appeared that SockJS doesn't support "private" channels. I used the following solution for a similar issue:
var channel_id = 'my-very-private-channel'
var connection = new SockJS('/pubsub', '')
connection.onopen = function(){
connection.send({'method': 'set-channel', 'data': {'channel': channel_id}})
}
Backend solution is specific for every technology stack so I can't give a universal solution here. General idea is the following:
1) Parse the message in "on_message" function to find the requested "method name"
2) If the method is "set-channel" -> set the "self.channel" to this value
3) Broadcast further messages to subscribers with the same channel (I'm using Redis for that, but it also depends on your platform)
Hope it helps!
I am creating a J2ME real time streaming audio player with RTP and through SIP connection. Also I am new for these things. I want to take look deeply those things. If any one know a good working sample code demonstrating an audio player streaming with RTP (That means how to send a REGISTER message to the server through SIP to get registered and send an INVITE message and get the response & play). Please let me know, highly appreciated.
Also I looked here
if
My server port is 6060
ip 111.111.111.1
id is myid password 123
Have I used the code correctly? If I am wrong, please make me correct.
public void doRegister(String username, String password, String realm) {
SipClientConnection scc = null;
SipConnectionNotifier scn = null;
String contact = null;
try {
scn = (SipConnectionNotifier) Connector.open("sip:5080");
contact = new String("sip:myid:123#"+scn.getLocalAddress()+":"+scn.getLocalPort());
scc = (SipClientConnection) Connector.open("sip:111.111.111.1+"transport=tcp") ;
scc.initRequest("REGISTER", scn);
scc.setHeader("From", "sip:myid:123#"+scn.getLocalAddress()+":5080");
scc.setHeader("To", "sip:myid:123#111.111.111.1");
scc.setHeader("Contact", contact);
scc.send();
boolean handled = false;
int scode = 0;
while(!handled) {
SipHeader sh;
scc.receive(30000);
scode = scc.getStatusCode();
switch(scode){
case 401:
sh = new SipHeader("WWW-Authenticate",
scc.getHeader("WWW-Authenticate"));
realm = sh.getParameter("realm");
scc.setCredentials(username, password, realm);
break;
case 407:
sh = new SipHeader("Proxy-Authenticate",
scc.getHeader("Proxy-Authenticate"));
realm = sh.getParameter("realm");
scc.setCredentials(username, password, realm);
break;
case 200:
handled = true;
break;
default:
handled = true;
}
}
scc.close();
} catch(Exception ex) {
// handle Exceptions
}
}
I got a respond with 180 Rigging message. Also let me know what is realm here. scc.setCredentials(username, password, realm);
As you see here in example 1 - you realize that when you make a fresh Reqeust to server, where as server expects authentication it first sends 401. By seeing this the client can then either search for a password or ask the user. When server sends the 401 response code, it specifies which security domain is applicable for the given requests. This is already what you have got in your code :
realm = sh.getParameter("realm");
Once, failed, you need to send() the request again with credentials here. I guess the setCredentials() function is only setting these parameters inside the scc object and they will be applied when send() is called again.
Some references that might be of interest: http://www.developer.nokia.com/Community/Discussion/showthread.php?126760-SIP-registration-401-Unauthorized-..
(here people had issues related port number, which i am not sure if this is bothering you)
Many functions and more things are available and wide answer can be found here Also Nokia JSR180 API has sample codes as well