How to retrieve callback token for sending emails for API set v1.3 - outlook-addin

Scenario:
Permission on the Manifest: ReadWriteMailbox
We have a outlook add-in that has a button that sends email from the compose mode of OWA/Outlook Desktop add-in. We are doing that by
Get the callback token.
Get item rest id.
Get rest url (which turns out to be https://outlook.office365.com/api).
Making a POST call to https://resturl/v2.0/me/messages/restId/send
dataType: 'json',
Headers
'Authorization': 'Bearer callbackToken'
Problem:
The email sends successfully in OWA (Outlook Web) but on Outlook 2016 Desktop we get an 403 Forbidden response with
code: ErrorAccessDenied
message: The api you are trying to access does not support item scoped OAuth.
Our Analysis
As far as we have investigated, Outlook 2016 MSI install does not support v1.5 of API requirement set
see this:
API requirement set
Since, there are two getCallbackTokenAsync methods as per
https://dev.office.com/reference/add-ins/outlook/1.5/Office.context.mailbox?product=outlook&version=v1.5
we are using the one with the isRest option set to true, i.e. the v1.5 one
Our code to get the callback token:
Office.context.mailbox.getCallbackTokenAsync({
isRest: true
},
function(asyncResult) {
if (asyncResult.status === "succeeded") {
deferred.resolve(asyncResult.value);
} else {
deferred.reject("Could not retrieve token");
}
});
Code to get rest id
function _getItemRestId() {
// Currently the only Outlook Mobile version that supports add-ins
// is Outlook for iOS.
if (Office.context.mailbox.diagnostics.hostName === 'OutlookIOS') {
// itemId is already REST-formatted
return Office.context.mailbox.item.itemId || pvt.currentMailId;
} else {
// Convert to an item ID for API v2.0
return Office.context.mailbox.convertToRestId(Office.context.mailbox.item.itemId || pvt.currentMailId, Office.MailboxEnums.RestVersion.v2_0);
}
}
Code to get the rest url
function _getRestUrl() {
$timeout(function() {
notificationService.showInfo('This is the rest URL==> ' + Office.context.mailbox.restUrl);
});
console.log('Office REST URL =>', Office.context.mailbox.restUrl);
return Office.context.mailbox.restUrl || 'https://outlook.office.com/api'; // This is because this requires v1.5 api set requirements which is not yet supported in Outlook for Windows.
}
Most Probably,
the getCallbackTokenAsync that executes on Outlook Desktop is that of v1.3 API set and gets us some different token (for getting attachments for an item i guess.) although I am not 100% sure that this is exactly what is wrong with our app.
Will be grateful if I can get a fix to send emails using API v1.4 requirement set.
There is nothing on other forums regarding this and also on the official documentation for that matter.

Related

Chrome Extension - Migration to Manifest v3 - chrome.permissions user gesture issue

I have built a chrome extension in manifest version 2 and am now looking at migrating to version 3. As part of this migration I have come across an issue when trying to toggle an optional permission to use the chrome notifications api.
Since you can't request a new permission from a content script as the api is not accessible from a content script, you have to send a message to the background script to perform the request and return the response to the content script. This worked as expected with version 2, now I am receiving this error:
Unchecked runtime.lastError: This function must be called during a user gesture
This means that the extension wants the permission request to be initiated on the back of an event initiated by a user action, such as a click. This indicates that the extension wishes the permission request to be completed from the content script but as stated above this is impossible.
Could anyone illuminate me if I'm missing something?
Content Script:
chrome.runtime.sendMessage(
{message: 'requestPermissions', permissions: ['notifications']},
(res) => console.log(res)
);
Background Script:
export function requestPermissions(request, sender, sendResponse) {
const {permissions} = request;
new Promise((resolve) => {
chrome.permissions.request(
{
permissions
},
(granted) => resolve(granted)
);
}).then((res) => sendResponse(res));
return true;
}

Trying to log in to gmail while using TestCafe

I am learning TestCafe and am trying to create an account on a website and then logging in to Gmail to find the activation link. When I try to do this I just get a browser isn't secure message when I get to the part to enter a password. How do I get Gmail to trust TestCafe?
While you might succeed in doing so, this is not a good approach because:
it's slow doing this via GUI
it's britle because selectors will likely change, and you have no control over Google email selectors, so you won't even know if they change them
A better approach wuld be to use a service like Mailosaur where you can create an account and receive emails that you can later query via an API. Instead of doing a whole e2e flow over GUI, you request an email on Mailosaur's API, and if such an email exists, you'll receive a response you can parse and check for various things.
I've done this in the past, you can see my post here: https://sqa.stackexchange.com/questions/40427/automating-verification-of-sent-email-sms-messages/45721#45721 It's exactly Mailosaur and Testcafe (plus it requires axios as a package), so it seems to be what you're looking for.
To add the same code here:
import config from '../config';
import { customAlphabet } from 'nanoid';
import axios from 'axios';
import Newsletter from '../Objects/newsletter';
async function request (reqObject) {
try {
return await axios(reqObject);
} catch (error) {
console.error(error);
}
}
function serverId () {
return process.env.MAILOSAUR_SERVER_ID;
}
function mailosaurFullEmail (id) {
return (id ? id : nanoid()) + '.' + serverId()
+ '#' + config.mailosaurDomain;
}
fixture `Newsletter`
.page(baseUrl);
test
('Sign Up For Newsletter', async t => {
const id = (customAlphabet('1234567890', 10))();
await t
.typeText(Newsletter.newsEmailInput, mailosaurFullEmail(id))
.click(Newsletter.consent)
.click(Newsletter.sendButton);
let res = await request({
method: 'POST',
url: config.mailosaurUrlEmail + serverId(),
headers: {
'Authorization': 'Basic '
+ Buffer.from(process.env.MAILOSAUR_API_KEY)
.toString('base64'),
'Content-Type': 'application/json'
},
data: {
sentTo: mailosaurFullEmail(id)
}
});
await t
.expect(res.status).eql(200);
});
and it requires some config values:
{
"mailosaurUrlEmail": "https://mailosaur.com/api/messages/await?server=",
"mailosaurDomain": "mailosaur.io"
}
This is definitely much better, but it still has some limitations:
Mailosaur's API can still change, so it won't be exactly without any maintenance
it assumes that an email is sent immediately after a user action (newsletter in my case), but that might be far from reality in many situations such as when emails are sent to a queue where it can easily take several minutes to send an email
If you absolutely have to do it via Gmail, you will still be better off looking at their API that should allow you to search and query email messages as well.
There is an issue related to the Google login. You can try turning on the "Allow less secure apps" Google account setting to workaround this issue. Please note that this setting is available for the disabled 2-Step Verification.

Cloud Recoding RESTful API Error of Agora.io

I would like to implement your Cloud Recoding of Live Broadcasting via RESTful API. I implemented it with NodeJs. Could you please help me why I get an error and how I can fix it?
On the manual,
"Status Code 400: The input is in the wrong format."
But I do not know what is wrong.
error: null
body: { resourceId: '', code: 400 }
var plainCredentials = new Buffer.from(agoraCustomerId+":"+agoraCustomerCertificate);
var base64Credentials = plainCredentials.toString("base64");
var options = {
url: "https://api.agora.io/v1/apps/AGORA_APP_ID/cloud_recording/acquire",
method: "POST",
headers: {
"Authorization": "Basic " + base64Credentials,
"Content-type": "application/json;charset=utf-8"
},
body:{
"cname": "190724060650293",
"uid": "060716332",
"clientRequest": {}
}
};
request.post(options, function (error, response, body) {
console.log("error: " + error);
console.log("body: ", body);
});
Agora's Cloud Recording is an add-on feature so it's not enabled by default, it needs to be enabled on your account for a specific AppID. The error you may be receiving is because the feature is not enabled on your account.
UPDATE:
Enabling Agora.io's Cloud Recording on your project is now available through the Agora.io Dashboard.
To enable Cloud Recording on your project, you’ll need to click into the Products & Usage section of the Agora.io Dashboard and select the Project name from the drop-down in the upper left-hand corner, click the Duration link below Cloud Recording.
After you click Enable Cloud Recording, you will be prompted to confirm the concurrent channels settings which defaults to 50, but you can contact sales#agora.io if you need more.
Theres a getting started tutorial that leverages a POSTMAN collection for quick testing.
QuickStart Tutorial: https://medium.com/#hermes_11327/agora-cloud-recording-quickstart-guide-with-postman-demo-c4a6b824e708
Postman Collection: https://documenter.getpostman.com/view/6319646/SVSLr9AM?version=latest
In my case it was mistake in Region settings . I used AP_NORTHEAST_1 but 10 need be used
1 - Make sure you have enable agora recording
2- Check the link and send all parameters.
https://docs-preprod.agora.io/en/cloud-recording/cloud_recording_webpage_mode?platform=RESTful
EX: {
"cname": "httpClient463224",
"uid": "527841",
"clientRequest":{
"resourceExpiredHour": 24,
"scene": 1
}
}
You forgot to put "resourceExpiredHour": 24,"scene": 1
More info:
PHP: you need to put strval function
$body = ["cname"=>strval($cname),"uid" =>strval($uid),"clientRequest" => ["resourceExpiredHour" => 24,"scene" => 1]];
I hope you solve your issue

Access to Calendar API return 401 Unauthorized

I'm new to office 365 and having problem with accessing rest api.
I'm trying to test the rest api of Calendar and Mail API, so I decided to use Postman. However, to test those APIs, I need an access token in Authorization header. To figure out how to get a token, I decided to get the sample project here , configure, run and sign in on this local site to get the token cached in local storage and use that token for further requests in Postman. However, all requests I tested returned '401 unauthorized request'.
What I did:
Register a new app on Azure ADD associated with O365 account
Add full app permissions and delegated permissions.
Update 'oauth2AllowImplicitFlow' to true in manifest file.
Clone sample project
In app.js, I change the alter the content of config function as following
function config($routeProvider, $httpProvider, adalAuthenticationServiceProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html',
controller: 'HomeController',
controllerAs: 'home',
requireADLogin: true
})
.otherwise({
redirectTo: '/'
});
// The endpoints here are resources for ADAL to get tokens for.
var endpoints = {
'https://outlook.office365.com': 'https://outlook.office365.com'
};
// Initialize the ADAL provider with your tenant name and clientID (found in the Azure Management Portal).
adalAuthenticationServiceProvider.init(
{
tenant: 'mytenantname.onmicrosoft.com',
clientId: '<my cliend Id>',
endpoints: endpoints,
cacheLocation: 'localStorage'
},
$httpProvider
);
};
Then I ran the app, it sign me in just fine and I can also get the token, but that token is also unauthorized to request.
I decoded the token and saw the value of 'aud', it didn't return "https://outlook.office365.com/". In this url, the author said that "This should be "https://outlook.office365.com/" for the Mail, Calendar, or Contacts APIs"
So what did I miss ?
How you call the Office 365 API in AngularJS?
When signing the user in, you will only get the id_token to authenticate the user.
The aud of id_token is the tenant id (GUID).
To call the Office 365 API, you need to use AugularJS http request.
Here is a sample of sending email using Microsoft Graph API in AngularJS:
// Build the HTTP request to send an email.
var request = {
method: 'POST',
url: 'https://graph.microsoft.com/v1.0/me/microsoft.graph.sendmail',
data: email
};
// Execute the HTTP request.
$http(request)
.then(function (response) {
$log.debug('HTTP request to Microsoft Graph API returned successfully.', response);
response.status === 202 ? vm.requestSuccess = true : vm.requestSuccess = false;
vm.requestFinished = true;
}, function (error) {
$log.error('HTTP request to Microsoft Graph API failed.');
vm.requestSuccess= false;
vm.requestFinished = true;
});
Before calling the API, ADAL.js will acquire another token - access token which you can used to send the email.
UPDATE#1
I also downloaded the sample you mentioned. To run this sample, please ensure you have the Exchange Online > Read and writer user mail Permission assigned in your application.

How to find access_token expired or not in Onedrive?

In Onedrive I am able to use their Live SDK API and get the Access_token and the filepicker for my users is also working properly.
But, every time a user tries to attach a file I am calling the API to get the Access_token.
Is this a problem, when more number of users try to call this API every time they try to attach the files( did Microsoft has a limit for number of API call).
Also, If i try to use Refresh_token for Access_token using WL.offline_access scope how would my app know the Access_token is expired?
You'll need to add logic to your code to see if the user is already has a session occurring. You can do this this by adding WL.Event.subscribe and checking for "auth.statusChange". If the users status has changed at any point, it will call the function to check the users current status (i.e. connect, notConnected, and unknown) by calling WL.getLoginStatus. WL.getLoginStatus will also return the users session object (access_token, expires_in, etc) if you want to use any values there.
Your code will look something like this.
< script type = "text/javascript" >
WL.Event.subscribe("auth.statusChange", chkStatus);
function chkStatus() {
WL.getLoginStatus(
function(response) {
if (response.status == "connected") {
document.getElementById("info").innerText = "You're signed in";
} else {
WL.login({
"scope": "wl.skydrive_update"
});
}
More info on WL.getLoginStatus can be found at https://msdn.microsoft.com/EN-US/library/hh550842.aspx. I hope that helps.