How to add form-data to Laravel Echo request? - javascript

I'm trying to send some data with Laravel Echo request
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'somekey',
wsHost: '127.0.0.1',
wsPort: 6001,
encrypted: false,
disableStats: true,
forceTLS: false,
authEndpoint: 'http://127.0.0.1:8000/broadcasting/auth',
'form-data': { // I tried data, dataForm, dataform
someData: '123', // this doesn't seem to work
},
});
I've seen how to add custom headers to the request
auth: {
headers: {
token: '123'
}
}
Is there any way to add form-data in a similar way?
Edit
When I inspect the network requests in the DevTools, I can see that there are two formData properties sent by the Echo to the server. So I thought there must be a way to attach additional properties into the existing formData object

Is there any way to add form-data in a similar way?
The simple answer is - NO
Laravel Echo doesn't have the functionality to achieve that within the parameter set.
The reason we can see the Form Data object in the Dev Tools requests, is because pusher-js is adding them before making the request to the server. To achieve that, we would have to manipulate the pusher API before the request is executed, but this goes off the original topic of this thread.
So if you want to send the data to the server, the easiest would be adding custom headers as pointed in the original question.
...
auth: {
headers: {
token: '123'
}
}
...

Edit 1
I'm really not sure if this would actually work but can you try this when you can
class LaravelEcho extends Echo {
constructor(options) {
super(options);
this.setformData();
}
setformData(formData = this.options.formData) {
if (formData) {
let path =
"?" +
Object.entries(formData)
.map((ch) => ch.join("="))
.join("&");
this.options.authEndpoint += path;
this.connector.options = this.options;
// since you are using pusher
if (this.connector.pusher) {
this.connector.pusher.options = this.options;
}
// maybe also for socket.io too?
else if (this.connector.socket) {
this.connector.socket.options = this.options;
}
}
}
}
let myEcho = new LaravelEcho({
broadcaster: "pusher",
key: "somekey",
wsHost: "127.0.0.1",
wsPort: 6001,
encrypted: false,
disableStats: true,
forceTLS: false,
authEndpoint: "http://127.0.0.1:8000/broadcasting/auth",
formData: {
foo: "bar",
username: "username",
password: "password",
},
});
console.log(myEcho);
I know this is really not the way you want. I've tried to make it as #Islam said on the comment and I'm really wondering if this is gonna work like this if we just override options after creation :)
Old
I was looking into this. here I saw that there is a headers option as following:
private _defaultOptions: any = {
auth: {
headers: {},
},
authEndpoint: '/broadcasting/auth',
broadcaster: 'pusher',
csrfToken: null,
host: null,
key: null,
namespace: 'App.Events',
};
This is Connecter's default options and inside it's constructor it's also setting an auth header for csrfToken here
So I'm guessing while you are creating your Laravel/Echo you might do,
window.Echo = new Echo({
broadcaster: 'pusher',
key: 'somekey',
wsHost: '127.0.0.1',
wsPort: 6001,
encrypted: false,
disableStats: true,
forceTLS: false,
authEndpoint: 'http://127.0.0.1:8000/broadcasting/auth',
auth: {
headers: {
'X-CSRF-TOKEN': 'your-csrf-token'
'your-header': 'with-value'
}
}
});
Hope this would work for you. Please do let me know! :)
By the way I don't have a test environment so i never tested it..

Related

URL parse vs constructor: path missing

I am total beginner in Node.js but I am trying to fix what I thought was a simple issue. I am using the following code example for an AWS Lambda function using Node.js 12 runtime:
function respond(event, context, responseStatus, responseData, physicalResourceId, noEcho) {
var responseBody = JSON.stringify({
Status: responseStatus,
Reason: "See the details in CloudWatch Log Stream: " + context.logStreamName,
PhysicalResourceId: physicalResourceId || context.logStreamName,
StackId: event.StackId,
RequestId: event.RequestId,
LogicalResourceId: event.LogicalResourceId,
NoEcho: noEcho || false,
Data: responseData
});
var https = require("https");
var url = require("url");
var parsedUrl = url.parse(event.ResponseURL);
var options = {
hostname: parsedUrl.hostname,
port: 443,
path: parsedUrl.path,
method: "PUT",
headers: {
"content-type": "",
"content-length": responseBody.length
}
};
var request = https.request(options, function(response) {
context.done();
});
request.on("error", function(error) {
console.log("send(..) failed executing https.request(..): " + error);
context.done();
});
request.write(responseBody);
request.end();
}
Full source code can be found here: https://github.com/aws-samples/amazon-cloudfront-secure-static-site/blob/7f96cdbcfbd7f94c3ab5a4c028b6bafd10744c83/source/witch/witch.js#L70
My IDE gives me a warning that the URL.parse() method is deprecated and so that I should use the URL constructor instead. So the only change I made is replacing:
var parsedUrl = url.parse(event.ResponseURL);
with
var parsedUrl = new url.URL(event.ResponseURL);
But when I do that, the options.path field ends up missing. What is even more confusing to me is that if I log the parsedUrl variable (passing it through JSON.stringify()), I can see that when I use url.parse(), I get a simple string in parsedUrl:
"https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-1%3A123456789012%3Astack/AcmCertificateStack-ABCDEFGHIJKL/00112233-4455-6677-8899-aabbccddeeff%7CCopyCustomResource%7C00112233-4455-6677-8899-aabbccddeeff?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20220101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7199&X-Amz-Credential=ABCDEFGHIJKLMNOPQRST%2F20220101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
But when using the constructor, I can see in the log an object structure with all the expected fields (protocol, hostname, port, even path):
{
"protocol": "https:",
"slashes": true,
"auth": null,
"host": "cloudformation-custom-resource-response-useast1.s3.amazonaws.com",
"port": null,
"hostname": "cloudformation-custom-resource-response-useast1.s3.amazonaws.com",
"hash": null,
"search": "?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20220101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7199&X-Amz-Credential=ABCDEFGHIJKLMNOPQRST%2F20220101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"query": "XX-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20220101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7199&X-Amz-Credential=ABCDEFGHIJKLMNOPQRST%2F20220101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"pathname": "/arn%3Aaws%3Acloudformation%3Aus-east-1%3A123456789012%3Astack/AcmCertificateStack-ABCDEFGHIJKL/00112233-4455-6677-8899-aabbccddeeff%7CCopyCustomResource%7C00112233-4455-6677-8899-aabbccddeeff",
"path": "/arn%3Aaws%3Acloudformation%3Aus-east-1%3A123456789012%3Astack/AcmCertificateStack-ABCDEFGHIJKL/00112233-4455-6677-8899-aabbccddeeff%7CCopyCustomResource%7C00112233-4455-6677-8899-aabbccddeeff?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20220101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7199&X-Amz-Credential=ABCDEFGHIJKLMNOPQRST%2F20220101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff",
"href": "https://cloudformation-custom-resource-response-useast1.s3.amazonaws.com/arn%3Aaws%3Acloudformation%3Aus-east-1%3A123456789012%3Astack/AcmCertificateStack-ABCDEFGHIJKL/00112233-4455-6677-8899-aabbccddeeff%7CCopyCustomResource%7C00112233-4455-6677-8899-aabbccddeeff?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20220101T000000Z&X-Amz-SignedHeaders=host&X-Amz-Expires=7199&X-Amz-Credential=ABCDEFGHIJKLMNOPQRST%2F20220101%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Signature=00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff"
}
So if anything the constructor seems to provide a better break down of the URL. I don't why, when I try to copy the parsedUrl.path field to options.path it works when parsedUrl comes from the parse() method but not when it comes from the constructor. The hostname field on the other hand works in both cases.
Any idea what's the issue here?
As indicated by the OP, the use of the url.parse method is discouraged in favor of the WATWG URL API. The legacy .path attribute returns the combined pathname and search components. Although the preferred WATWG URL API does not have the path attribute, the value required by options.path can be constructed by combining the .pathname and .search attributes.

How to set `You and moderator can reply` in bot when posting proactive message to channels?

I am currently developing a bot that posts proactive message to channels. My client wants me to set No reply or You and moderator can reply on the message that posted from the bot proactively. 
What I tried so far:
// post message to channels
const credentials = new MicrosoftAppCredentials(process.env.MicrosoftAppId, process.env.MicrosoftAppPassword);
const client = new ConnectorClient(credentials, { baseUri: serviceUrl });
const message = MessageFactory.text(inMessage);
let approveResult = false;
let MessageActivityId = "";
const conversationParams = {
isGroup: true,
bot: {
id: process.env.MicrosoftAppId,
name: process.env.BotName
},
conversationType: 'channel',
channelData: {
channel: {
id: teamsChannelId
}
},
activity: message
};
const msRes = await client.conversations.createConversation(conversationParams).catch(e => console.log(e));
I tried to post the message first, and immediately update the activity and set the type as ActivityTypes.EndOfConversation. However, it doesn't work at all.
const tmpResult = await client.conversations.updateActivity(teamsChannelId, msRes.activityId, {type: ActivityTypes.EndOfConversation})
Error form above updateActivity code: 
RestError: Unknown activity type
at ...(skipped for paths)
{
code: 'BadArgument',
statusCode: 400,
request: WebResource {
streamResponseBody: false,
url: 'https://{service_url}/{channel_id}/activities/{messageActivityId}',
method: 'PUT',
headers: HttpHeaders {
_headersMap: [Object]
},
body: '{"type":"endOfConversation"}',
query: undefined,
formData: undefined,
withCredentials: false,
abortSignal: undefined,
timeout: 0,
onUploadProgress: undefined,
onDownloadProgress: undefined,
proxySettings: undefined,
keepAlive: undefined,
agentSettings: undefined,
operationSpec: {
httpMethod: 'PUT',
path: 'v3/conversations/{conversationId}/activities/{activityId}',
urlParameters: [Array],
requestBody: [Object],
responses: [Object],
serializer: [Serializer]
}
},
response: {
body: '{"error":{"code":"BadArgument","message":"Unknown activity type"}}',
headers: HttpHeaders {
_headersMap: [Object]
},
status: 400
},
body: {
error: {
code: 'BadArgument',
message: 'Unknown activity type'
}
}
}
Is there any method that allows me to do so? Thanks.
It would be better if I could only disable the reply function in Channels from bot programmatically.
Update on 2021-06-28:
Simulation of expected behavior on UI:
Simulation of actual behavior on UI:
I've not actually tested this property myself, but it seems like it should handle what you need: In the Teams app manifest, there is a "NotificationOnly" setting on the bot, which means it should not allow users to converse with it (i.e. "reply"). See more at https://learn.microsoft.com/en-us/microsoftteams/platform/resources/bot-v3/bots-notification-only

When using PUT method body is not passed using Koa

I am trying to make update function, where a user can put the new data and the data in the server would get updated, a simple task, however, when I try to PUT new data, the body is always undefined.
The data which gets sent:
request: {
method: 'PUT',
url: '/api/v1.0/articles/1',
header: {
'user-agent': 'PostmanRuntime/7.17.1',
accept: '*/*',
'cache-control': 'no-cache',
host: 'localhost:3000',
'accept-encoding': 'gzip, deflate',
'content-length': '98',
connection: 'keep-alive'
}
},
response: {
status: 404,
message: 'Not Found',
header: [Object: null prototype] {}
},
Now I tried passing it as keys using other methods and not RAW method, this is what is inside of the body I am trying to pass:
{
"title": "another article",
"fullText": "again here is some text hereto fill the body"
}
This is the function which should update the data, but it gets undefined from the put request.
router.put("/:id", updateArticle);
function updateArticle(cnx, next) {
let id = parseInt(cnx.params.id);
console.log(cnx);
if (articles[id - 1] != null) {
//articles[id - 1].title = cnx.request.body.title;
cnx.body = {
message:
"Updated Successfully: \n:" + JSON.stringify(updateArticle, null, 4)
};
} else {
cnx.body = {
message:
"Article does not exist: \n:" + JSON.stringify(updateArticle, null, 4)
};
}
}
I am using postman, Body -> Raw | JSON, I do have to mention all other methods work perfectly - delete, create, getAll, getById
With a PUT or POST, the data is in the body of the request. You have to have some code (in your request handler or some middleware) that actually reads the body from the stream and populates the body property for you. If you don't have that, then the data is still sitting in the request stream waiting to be read.
You can see an example of reading it yourself here: https://github.com/koajs/koa/issues/719 or there is pre-built middleware that will do that for you.
Here's are a couple modules that will do that middleware for you:
https://github.com/dlau/koa-body
https://www.npmjs.com/package/koa-body-parser

Why do mysql-event not working in node.js?

var MySQLEvents = require('mysql-events');
var dsn = {
host: 'localhost',
user: 'root',
password: '' // no password set that's why keep blank
};
var mysqlEventWatcher = MySQLEvents(dsn);
console.log(mysqlEventWatcher);
var watcher =mysqlEventWatcher.add(
'myDB.myTable',
function (oldRow, newRow, event) {
//row inserted
if (oldRow === null) {
//insert code goes here
}
//row deleted
if (newRow === null) {
//delete code goes here
}
//row updated
if (oldRow !== null && newRow !== null) {
//update code goes here
}
//detailed event information
console.log(event); // don't matter, it updates, delete or insert
},
'Active'
);
Take code from https://www.npmjs.com/package/mysql-events
When I try to print console.log(mysqlEventWatcher); ,
it prints something like that
{ started: false,
zongji: {},
databases: [],
tables: {},
columns: {},
events: [ 'tablemap', 'writerows', 'updaterows', 'deleterows' ],
triggers: [],
dsn: { host: 'localhost', user: 'root', password: '' },
settings: {},
connect: [Function: connect],
add: [Function: add],
remove: [Function: remove],
stop: [Function: stop],
reload: [Function: reload],
includeSchema: [Function: includeSchema] }
After writing this code, I update specific table('myTable') in which I implement in mysqlEventWatcher, then It won't go to that method as inside that I am printing event.
I don't know which thing I am missing
I'm adding this answer because this appears first on Google. Hopefully this will help someone.
I'm using XAMPP as my server and in order to get it to work, I edited the my.cnf file, which can be found here: xampp\mysql\bin, with the following:
I enabled every instance of log-bin=mysql-bin (by removing the #) and I wrote-in binlog_format=row.
EDIT :
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = row
Make sure you enabled binlog on your mysql server and the binlog format is ROW
https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html
Try to remove 'Active' and make sure you set the correct database and table name to run the first test
var watcher =mysqlEventWatcher.add(
'your_database_name.your_table_name',
function (oldRow, newRow, event) {}
);
As well as checking #nguyendn answer, please try and run ZongJi standalone to check it's functioning
var ZongJi = require('zongji');
var zongji = new ZongJi({
host : 'localhost',
user : 'user',
password : 'password',
debug: true
});
zongji.on('binlog', function(evt) {
evt.dump();
});
If ZongJi is not working, mysql-event will not work either. For me ZongJi was only working on localhost, not remote IP

angular2 xhrfields withcredentials true

I am trying to login to a system. In angular 1, there was ways to set
withCredentials:true
But I could not find a working solution in angular2
export class LoginComponent {
constructor(public _router: Router, public http: Http, ) {
}
onSubmit(event,username,password) {
this.creds = {'Email': 'harikrishna#gmail.com','Password': '01010','RememberMe': true}
this.headers = new Headers();
this.headers.append('Content-Type', 'application/json');
this.http.post('http://xyz/api/Users/Login', {}, this.creds)
.subscribe(res => {
console.log(res.json().results);
});
}
}
In Angular > 2.0.0 (and actually from RC2 on), just
http.get('http://my.domain.com/request', { withCredentials: true })
AFAIK, right now (beta.1) the option is not available.
You have to work around it with something like this:
let _build = http._backend._browserXHR.build;
http._backend._browserXHR.build = () => {
let _xhr = _build();
_xhr.withCredentials = true;
return _xhr;
};
This issue has been noted by the angular2 team.
You can find some other workarounds (one especially written as an #Injectable) following the issue link.
If anyone is using plain JS, based on cexbrayat's answer:
app.Service = ng.core
.Class({
constructor: [ng.http.Http, function(Http) {
this.http = Http;
var _build = this.http._backend._browserXHR.build;
this.http._backend._browserXHR.build = function() {
var _xhr = _build();
_xhr.withCredentials = true;
return _xhr;
};
}],
I think you don't use the post metrhod the right way. You could try something like that:
onSubmit(event,username,password) {
this.creds = {
'Email': 'harikrishna#gmail.com',
'Password': '01010','RememberMe': true
}
this.headers = new Headers();
this.headers.append('Content-Type', 'application/json');
this.http.post('http://xyz/api/Users/Login',
JSON.stringify(this.creds),
{ headers: headers });
}
You invert parameters. The second parameter corresponds to the content to send into the POST and should be defined as string. Objects aren't supported yet at this level. See this issue: https://github.com/angular/angular/issues/6538.
If you want to set specific headers, you need to add the Headers object within the third parameter of the post method.
Otherwise, I think the withCredentials property is related to CORS if you want to send cookies within cross domain requests. You can have a look at this link for more details:
http://restlet.com/blog/2015/12/15/understanding-and-using-cors/
http://restlet.com/blog/2016/09/27/how-to-fix-cors-problems/
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
Hope it helps you,
Thierry
getHeaders(): RequestOptions {
let optionsArgs: RequestOptionsArgs = { withCredentials: true }
let options = new RequestOptions(optionsArgs)
return options;
}
getAPIData(apiName): Observable<any> {`enter code here`
console.log(Constants.API_URL + apiName);
let headers = this.getHeaders();
return this.http
.get(Constants.API_URL + apiName, headers)
.map((res: Response) => res.json())
}
Enabled cors in the webapi
Same code works fine in the chrome(normal),Internet explorer
But it is asking windows login prompt in the incognito chrome,firefox,edge.
Share the suggestions how to fix the issue
for CORS issue with withCredentials : yes, I send the auth token as parameter
req = req.clone({
//withCredentials: true,
setHeaders: { token: _token },
setParams: {
token: _token,
}
});

Categories

Resources