Office 365 'Create Event' Rest API is giving error - node.js

I am new user on stackoverflow as well as in office 365 development using node.js.
I am successfully getting User(my own office 365 account) mails,calendar events using this tutorial (https://dev.outlook.com/RestGettingStarted/Tutorial/node)
but when i am trying to Create an Event in my calender it gives me below error
"{"error":{"code":"ErrorAccessDenied","message":"Access is denied. Check credentials and try again."}}"
Please provide me suggestions on the same.
Below is the code for creating event which i copied from [https://msdn.microsoft.com/office/office365/APi/calendar-rest-operations#CreateEvents] here
function createEvent(response, request) {
var cookieName = 'node-tutorial-token';
var cookie = request.headers.cookie;
// if (cookie && cookie.indexOf(cookieName) !== -1) {
console.log("Cookie: ", cookie);
// Found our token, extract it from the cookie value
var start = cookie.indexOf(cookieName) + cookieName.length + 1;
var end = cookie.indexOf(';', start);
end = end === -1 ? cookie.length : end;
var token = cookie.substring(start, end);
console.log("Token found in cookie: " + token);
var event = new outlook.Microsoft.OutlookServices.Event();
event.subject = 'Your Subject';
event.start = new Date("October 30, 2014 11:13:00").toISOString();
event.end = new Date("October 30, 2014 12:13:00").toISOString();
// Body
event.body = new outlook.Microsoft.OutlookServices.ItemBody();
event.body.content = 'Body Content';
event.body.contentType = outlook.Microsoft.OutlookServices.BodyType.Text;
// Location
event.location = new outlook.Microsoft.OutlookServices.Location();
event.location.displayName = 'Location';
// Attendee
var attendee1 = new outlook.Microsoft.OutlookServices.Attendee();
var emailAddress1 = new outlook.Microsoft.OutlookServices.EmailAddress();
emailAddress1.name = "abc";
emailAddress1.address = "abc#abcdt.onmicrosoft.com";
attendee1.emailAddress = emailAddress1;
event.attendees.push(attendee1);
var outlookClient = new outlook.Microsoft.OutlookServices.Client('https://outlook.office365.com/api/v1.0',
authHelper.getAccessTokenFn(token));
outlookClient.me.calendar.events.addEvent(event)
.then(function (response) {
console.log(response._Id);
}, function (error) {
console.log(error);
});
}

Make sure your app has requested for calendar.readwrite permission and you need this to create new events. In the example you followed, your app registered for only Calendar.Read permissions (see below).
You should instead go to https://dev.outlook.com/AppRegistration to register an app with Calendar.ReadWrite permission which is required to create new events.

Related

How to configure the user_token of Damn Vulnerable Web Application within CSRF field while Script based authentication using ZAP?

I had been following the documentation of Script Based Authentication for Damn Vulnerable Web Application using ZAP. I have navigated to http://localhost/dvwa/login.php through Manual Explore which opens up the DVWA application on my localhost as follows:
and adds the URL to the Default Context.
I've also created the dvwa script with the following configuration:
and modified the dvwa script:
Now when I try Configure Context Authentication, dvwa script does gets loaded but the CSRF field doesn't shows up.
Additionally, POST Data doesn't even shows up but Extra POST Data is shown.
Am I missing something in the steps? Can someone help me out?
The modified script within the documentation of Script Based Authentication section for Damn Vulnerable Web Application using ZAP
seems incomplete.
The complete script is available at Setting up ZAP to Test Damn Vulnerable Web App (DVWA) which is as follows:
function authenticate(helper, paramsValues, credentials) {
var loginUrl = paramsValues.get("Login URL");
var csrfTokenName = paramsValues.get("CSRF Field");
var csrfTokenValue = extractInputFieldValue(getPageContent(helper, loginUrl), csrfTokenName);
var postData = paramsValues.get("POST Data");
postData = postData.replace('{%username%}', encodeURIComponent(credentials.getParam("Username")));
postData = postData.replace('{%password%}', encodeURIComponent(credentials.getParam("Password")));
postData = postData.replace('{%' + csrfTokenName + '%}', encodeURIComponent(csrfTokenValue));
var msg = sendAndReceive(helper, loginUrl, postData);
return msg;
}
function getRequiredParamsNames() {
return [ "Login URL", "CSRF Field", "POST Data" ];
}
function getOptionalParamsNames() {
return [];
}
function getCredentialsParamsNames() {
return [ "Username", "Password" ];
}
function getPageContent(helper, url) {
var msg = sendAndReceive(helper, url);
return msg.getResponseBody().toString();
}
function sendAndReceive(helper, url, postData) {
var msg = helper.prepareMessage();
var method = "GET";
if (postData) {
method = "POST";
msg.setRequestBody(postData);
}
var requestUri = new org.apache.commons.httpclient.URI(url, true);
var requestHeader = new org.parosproxy.paros.network.HttpRequestHeader(method, requestUri, "HTTP/1.0");
msg.setRequestHeader(requestHeader);
helper.sendAndReceive(msg);
return msg;
}
function extractInputFieldValue(page, fieldName) {
// Rhino:
var src = new net.htmlparser.jericho.Source(page);
// Nashorn:
// var Source = Java.type("net.htmlparser.jericho.Source");
// var src = new Source(page);
var it = src.getAllElements('input').iterator();
while (it.hasNext()) {
var element = it.next();
if (element.getAttributeValue('name') == fieldName) {
return element.getAttributeValue('value');
}
}
return '';
}
Using this script, CSRF Field and POST Data field shows up just perfect.

Azure function to send telemetry data to iotDevice

I am trying to develop a azure function that receives messages from one the built-in eventhub process it and send the result to another IoT Device configured in the Azure IoT Hub.
Below is the code:
module.exports = function (context, IoTHubMessages) {
var Mqtt = require('azure-iot-device-mqtt').Mqtt;
var DeviceClient = require('azure-iot-device').Client
var Message = require('azure-iot-device').Message
var connectionString = '{connectionstring of the target device}';
var acRoom1 = DeviceClient.fromConnectionString(connectionString, Mqtt);
var totalPerson = 0;
var events = IoTHubMessages.length;
context.log(JSON.stringify(IoTHubMessages));
context.log(Array.isArray(IoTHubMessages));
context.log(`Number of entries: ${IoTHubMessages.length}`);
IoTHubMessages.forEach(message => {
context.log(`Processed message: ${JSON.stringify(message)}`);
totalPerson = totalPerson + message.personCount;
context.log(`Total count: ${totalPerson}`);
});
var avgPersonCount = Math.round( totalPerson / events );
context.log(`Average person count: ${avgPersonCount}`);
var temp = 24;
if ( avgPersonCount > 5){
temp = 20;
}
else if ((avgPersonCount>2) && (avgPersonCount <= 5)){
temp = 22;
}
else {
temp = 24;
}
var msg = new Message(`Setting temperature to ${temp} C`);
context.log('Sending message: ' + msg.getData());
context.log(`Temeperature set to ${temp} C`);
acRoom1.sendEvent(msg);
context.done();
};
The issue I have is that the event that I am sending to device is coming back to this azure functions again. I believe, i need to do something in the Message Routing, but not sure what needs to be done.
The flow of the entire solution ( that I want to achieve ) is as below
Camera -- > Azure IOT Hub --> Azure Function --> AC
So please follow as below example shows on Message routing.
Routing on Message Body If you are routing on $body.property
You have to add the property in the body payload which is being sent by the device (device code is not shown here, only portal query is shown here).
and you can test it out by...
Routing on system property
The Iot Hub will assign this property on every message , so simply do setting on Portal side.(just give device name in the query, for quick you can test by using it on portal side)
App Property as said by Matthijs in his response, below snap shows on device C# sample code. And then you have to write the query which matches the app property.
Verify on Destination side In my example the destination is Blob container.
You could filter events by device ID, but a more scalable way would be to add an appProperty. If you want to send all the AC events to a different endpoint, you can add an appProperty to the message the AC is sending. Example:
var msg = new Message(`Setting temperature to ${temp} C`);
msg .properties.add('eventType', 'AC');
context.log('Sending message: ' + msg.getData());
context.log(`Temeperature set to ${temp} C`);
acRoom1.sendEvent(msg);
After that, you can go to your IoT Hub and add a new route. You can route these events to a different endpoint like so:
Because your camera doesn't send this appProperty, it will rely on the fallback route and your Azure Function will still handle those events. Another, perhaps more reliant option is to send only the camera messages to a specific route. But either will work!
I figured out the answer. Thanks to #Matthijs van der Veer for the hint.
1. Firstly disable the fall back rule. Now I have a 2 route
Instead of azure-iot-device package, i shifted to azure-iothub package.
module.exports = function (context, IoTHubMessages) {
var Client = require('azure-iothub').Client;
var Message = require('azure-iot-common').Message;
var connectionString = '{connection-string-policy-service}';
var targetDevice = '{destination-deviceid}';
var serviceClient = Client.fromConnectionString(connectionString);
serviceClient.open(function (err) {
if (err) {
context.log('Could not connect: ' + err.message);
}
});
var totalPerson = 0;
var events = IoTHubMessages.length;
context.log(JSON.stringify(IoTHubMessages));
context.log(`Number of entries: ${IoTHubMessages.length}`);
IoTHubMessages.forEach(message => {
context.log(`Processed message: ${JSON.stringify(message)}`);
totalPerson = totalPerson + message.personCount;
context.log(`Total count: ${totalPerson}`);
});
var avgPersonCount = Math.round( totalPerson / events );
context.log(`Average person count: ${avgPersonCount}`);
var temp = 24;
if ( avgPersonCount > 5){
temp = 20;
}
else if ((avgPersonCount>2) && (avgPersonCount <= 5)){
temp = 22;
}
else {
temp = 24;
}
var msg = new Message(`Setting temperature to ${temp} C`);
msg .properties.add('eventType', 'AC');
context.log('Sending message: ' + msg.getData());
context.log(`Temeperature set to ${temp} C`);
serviceClient.send(targetDevice, msg);
context.done();
};

Values seems changing straight after Initial Save in Dynamics CRM Opportunity

I'm doing a Service Call to retrieve the Account details (currency, discount associated with the account) on the Selection of the Account lookup on the Opportunity form (form type == 1 // Create) using Web API in CRM 2016 On-Premise. Everything is working fine but when the opportunity is saved initially it's straight away coming up with unsaved changes next to the Save button after the initial save which is forcing me to do another save(abnormal behaviour).I'm not so sure what value is changing straightaway after initial save.
The Service Call is Synchronous and is being triggered on the change of the Account Lookup, well before the initial save. Any Help Appreciated!.
function SetOpportunityCurrencyAndDiscount(){
var accountId = (GetValue("vm_accountid"))[0].id;
var result = RetrieveRecord("account", null, accountId.slice(1,-1));
var accountDiscount = result["vm_accountdiscount"];
var transactionCurrencyId = result["_transactioncurrencyid_value"];
var currencyName = result["_transactioncurrencyid_value#OData.Community.Display.V1.FormattedValue"];
SetValue("vm_discount", accountDiscount);
Xrm.Page.getAttribute("transactioncurrencyid").setValue([{ id: transactionCurrencyId, name: currencyName, entityType: "transactioncurrency"}]); }
function RetrieveRecord(recordType, alternateKey, accountId){
var result = null;
var entityType = recordType;
var query = null;
if(alternateKey != null && agencyId == null)
query = "/api/data/v8.0/accounts(emailaddress1='"+alternateKey+"')?$select=name,accountid,_transactioncurrencyid_value,vm_agencydiscount";
else
query = "/api/data/v8.0/accounts("+agencyId+")?$select=name,accountid,_transactioncurrencyid_value,vm_agencydiscount";
var req = new XMLHttpRequest();
req.open("GET", Xrm.Page.context.getClientUrl() + query, false);
req.setRequestHeader("OData-MaxVersion", "4.0");
req.setRequestHeader("OData-Version", "4.0");
req.setRequestHeader("Accept", "application/json");
req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
req.setRequestHeader("Prefer", "odata.include-annotations=\"OData.Community.Display.V1.FormattedValue\"");
req.onreadystatechange = function () {
if (this.readyState === 4) {
req.onreadystatechange = null;
if (this.status === 200) {
result = JSON.parse(this.response);
}
else {
alert(this.statusText);
}
}
};
req.send();
return result;
}
After you save your record and the form is dirty again, open dev tools and paste this into the console. It will show you which fields are dirty.
function showDirtyFields() {
var Xrm = Array.prototype.slice.call(document.querySelectorAll('iframe')).filter(function(d) {
return d.style.visibility !== 'hidden';
})[0].contentWindow.Xrm;
var message='The following fields are dirty: \n';
Xrm.Page.data.entity.attributes.forEach(function(attribute,index){
if(attribute.getIsDirty()==true){message+="\u2219 "+attribute.getName()+"\n";}
});
Xrm.Utility.alertDialog(message);
}
showDirtyFields();
Another way of accomplishing the same thing is to turn on auditing for the entity. The audit log will show you which fields were submitted.

I'm trying to send emails using sendgrid in nodejs.But am getting "TypeError: object is not a function" error

Here is my code snippet
var sendgrid = require('sendgrid')('xxxxxx', 'xxxxxx');
var email = new sendgrid.Email();
email.addTo('xyz#gmail.com');
email.setFrom('xyz#gmail.com');
email.setSubject('welcome to send grid');
email.setHtml('<html><body>HELLO evryone ...,</body></html>');
sendgrid.send(email, function(err, json) {
if(!err)
{
console.log("mail sent successssss");
res.send({"status":0,"msg":"failure","result":"Mail sent successfully"});
}
else
{
console.log("error while sending mail")
res.send({"status":1,"msg":"failure","result":"Error while sending mail."});
}
});
Installed sendgrid throgh npm also.am getting "TypeError: object is not a function" error.MAy i know why.??
Version:--
sendgrid#3.0.8 node_modules\sendgrid
└── sendgrid-rest#2.2.1
It looks like you're using sendgrid#3.0.8 but trying to call on the sendgrid#2.* api.
v2 implementation: https://sendgrid.com/docs/Integrate/Code_Examples/v2_Mail/nodejs.html
v3 implementation:
https://sendgrid.com/docs/Integrate/Code_Examples/v3_Mail/nodejs.html
Give the v3 a go.
As for the type error:
v2
var sendgrid = require("sendgrid")("SENDGRID_APIKEY");
you're invoking a function
however you have v3 installed
require('sendgrid').SendGrid(process.env.SENDGRID_API_KEY)
and it's now an object
REQUESTED UPDATE:
I don't know too much about the keys given, but since they have tons of different supported libraries, it's completely possible that some of them use both while others use only one. If you really only have a USER_API_KEY nad PASSWORD_API_KEY, just use the user_api_key
Here is their source for the nodejs implementation module SendGrid:
function SendGrid (apiKey, host, globalHeaders) {
var Client = require('sendgrid-rest').Client
var globalRequest = JSON.parse(JSON.stringify(require('sendgrid-rest').emptyRequest));
globalRequest.host = host || "api.sendgrid.com";
globalRequest.headers['Authorization'] = 'Bearer '.concat(apiKey)
globalRequest.headers['User-Agent'] = 'sendgrid/' + package_json.version + ';nodejs'
globalRequest.headers['Accept'] = 'application/json'
if (globalHeaders) {
for (var obj in globalHeaders) {
for (var key in globalHeaders[obj] ) {
globalRequest.headers[key] = globalHeaders[obj][key]
}
}
}
The apiKey is attached to the header as an auth, and it looks like that's all you need.
Try following their install steps, without your own implementation,
1) (OPTIONAL) Update the development environment with your SENDGRID_API_KEY, for example:
echo "export SENDGRID_API_KEY='YOUR_API_KEY'" > sendgrid.env
echo "sendgrid.env" >> .gitignore
source ./sendgrid.env
========
2) Make this class and if you did the above use process.env.SENDGRID_API_KEY else put your USER_API_KEY
var helper = require('sendgrid').mail
from_email = new helper.Email("test#example.com")
to_email = new helper.Email("test#example.com")
subject = "Hello World from the SendGrid Node.js Library!"
content = new helper.Content("text/plain", "Hello, Email!")
mail = new helper.Mail(from_email, subject, to_email, content)
//process.env.SENDGRID_API_KEY if above is done
//else just use USER_API_KEY as is
var sg = require('sendgrid').SendGrid(process.env.SENDGRID_API_KEY)
var requestBody = mail.toJSON()
var request = sg.emptyRequest()
request.method = 'POST'
request.path = '/v3/mail/send'
request.body = requestBody
sg.API(request, function (response) {
console.log(response.statusCode)
console.log(response.body)
console.log(response.headers)
})

Azure API App authentication

So I have an Azure API-App with protection working.
I want to use microsoftaccount and google as tokenname for GetRawTokenAsync.
How can I know before which token name to use? Can I obtain that from the current user info?
So something like:
var runtime = Runtime.FromAppSettings(Request);
var user = runtime.CurrentUser;
if (user == "google account") { // google account
var token = await user.GetRawTokenAsync("google");
}
else if (user == "microsoft account") { // microsoftaccount
var token = await user.GetRawTokenAsync("microsoftaccount");
}
Try adding .Result to the GetRawTokenAsync call
var runtime = Runtime.FromAppSettings(Request);
var user = runtime.CurrentUser;
TokenResult token = await user.GetRawTokenAsync("google").Result;
var name = (string)token.Claims["name"];

Resources