How can I access Google Fit data without logging in - reactjs

I have a web page I am working on, I am wanting to use gapi to access my steps for the day. I do not want to log in every time, I want the page to log in automatically in the background, oAuth2 is required I believe but I can not get any further.
Based on code I've found online and using React with Hooks, I added ts ignore because it could not resolve gapi.
The issue I am having is that I get Login Required error
I've tried using Axios and doing it by API_KEY only. My knowledge on API's is growing but I thought just to access the data an API key would be enough providing I had registered the key in the API tools.
React.useEffect(() => {
const start = () => {
// 2. Initialize the JavaScript client library.
// #ts-ignore
gapi.client.init({
'apiKey': '<API_KEY>',
// clientId and scope are optional if auth is not required.
'clientId': '<CLIENT_ID>.apps.googleusercontent.com',
}).then(function() {
// 3. Initialize and make the API request.
// #ts-ignore
return gapi.client.request({
'path': 'https://www.googleapis.com/fitness/v1/users/<MY_GMAIL_ADDRESS>/dataset:aggregate',
'method': 'POST',
'body': {
"aggregateBy": [{
"dataTypeName": "com.google.step_count.delta",
"dataSourceId": "derived:com.google.step_count.delta:com.google.android.gms:estimated_steps"
}],
"bucketByTime": { "durationMillis": 86400000 },
"startTimeMillis": 1567983600000,
"endTimeMillis": 1568057160150
},
})
}).then(function(response) {
console.log(response.result);
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
};
// #ts-ignore
gapi.load('client', start);
}, []);
I just want to be able to return my steps in a JSON object preferably with Axios, if not using the gapi JS library using my React Application. Nothing fancy.
I appreciate this may not be possible but the docs and other questions on stack overflow just are not working for me and no one can answer me.

Related

React Autodesk Forge Create Buckets

I'm trying to create a bucket from the front end of a react app, once I work this out I will make the requests through the backend. I am passing in an options object inside of the useEffect hook and logging the result to the console. The headers are returning undefined on the environment variables I have passed in from a .env.I would like to know how do I pass in the headers from the .env or hard code for now? I aslo need to pass in scope into the headers bucket:create, bucket: read
Buckets.js
import React, { useEffect } from 'react'
import axios from 'axios'
const Buckets = () => {
useEffect(() => {
const options = {
method: 'POST',
url: 'https://developer.api.autodesk.com/authentication/v1/authenticate',
headers: {
ContentType: 'application/json',
Authorization: process.env.REACT_APP_FORGE_ACCESS_TOKEN,
client_id: process.env.REACT_APP_FORGE_CLIENT_ID,
client_secret: process.env.REACT_APP_FORGE_CLIENT_SECRET,
},
}
console.log(options)
}, [])
return <div>Buckets</div>
}
export default Buckets
There are a couple of problems with the code snippet:
first of all, you should never expose the client secret to the browser; implementing bucket creation on the server side is pretty straightforward
second, the process.env construct you use in your code is a Node.js feature, not something that's available in browser; that's most likely why the headers end up being empty
So with that, I would just suggest that you implement any of the Forge requests on the server side (for example, by following https://learnforge.autodesk.io), and then expose that functionality to your React frontend via a couple of endpoints.
EDIT: as mentioned in the comments, I'm working on "unofficial Forge SDK for Node.js", and that library does have an experimental support for browsers. Try something like this:
<script src="https://cdn.jsdelivr.net/npm/forge-server-utils/dist/browser/forge-server-utils.js"></script>
<script>
const client = new forge.DataManagementClient({ client_id: '...', client_secret: '...' });
client.listBuckets()
.then(buckets => { console.log('Buckets', buckets); })
.catch(err => { console.error('Could not get buckets', err); });
</script>

When attempting to stub a request in Cypress IO (JS) against a React app using fetch, the requests still call through to the server

I'm using Cypress to create some specs against my React app. My react app uses fetch to fetch data from an external api (isomorphic-fetch)
The fetch requests in my app are like so
import fetch from 'fetch'
...
fetch('http://www.external-server.com/ideas.json')
.then((response) => {
if (response.status >= 400) {
}
return response.json().then((result) => {
this._data = result
this._data((ele) => ele.key = ele.id)
});
})
In my Cypress specs, I want my regular specs to hit my lcoahost:3000 to get the initial page (which houses my React app). My react app in turn would normally make an external request (http://www.external-server.com/ideas.json) but in my specs I want to stub out that request and have that endpoint return fake data in my specs only.
The Cypress docs for cy.route() here, describe that I should be able to do something like
cy.server()
cy.route('http://www.external-server.com/ideas.json', [
{
id: 1,
name: 'john'
}
])
I attempted to put this into a beforeEach that runs in the context of my spec (thus running before every spec).
You will note that when I run the specs in the Cypress test running, it appears in the console output that the endpoint SHOULD be stubbed.
However, by examination, I can see that my app is in fact making the request to the real server, and calling the real endpoint (not stubbing it).
I tested several times and I am certain this is the behavior.
I found a solution online I will post below to answer my question
the solution is add to cypress/support/commands.js
this small hack will turn the window fetch into a no-op (disabling it) and will allow the native stubbing in Cypress to work without any alterations.
Cypress.Commands.overwrite('visit', (originalFn, url, options) => {
const opts = Object.assign({}, options = {}, {
onBeforeLoad: (window, ...args) => {
window.fetch = null;
if (options.onBeforeLoad) {
return options.onBeforeLoad(window, ...args);
}
},
});
return originalFn(url, opts);
});

Worldpay 3D Secure in React web app

I am attempting to integrate worldpay with out React web app.
Incorporating the credit card functionality via Worldpay.useTemplateForm() is working fine but the next step is causing a problem.
To use 3DS we have to redirect away from our site to a bank controlled site and supply them with a URL to be redirected back to afterwards.
This is annoying in itself because we have a lot of saved state in our app and on returning all of this would be lost, however its not the biggest issue.
After the 3DS they POST the form data back to us and React cannot accept post requests and the webpage simply displays 'CANNOT POST /'
Has anyone successfully implemented Worldpay 3DS into a React app??
You can send request with cart data dirrectly to payment system:
const formData = {
reusable: true,
paymentMethod: {
name: 'name',
expiryMonth: 10,
expiryYear: 2021,
issueNumber: 1,
startMonth: 2,
startYear: 2013,
cardNumber: '5454 5454 5454 5454',
type: 'Card',
cvc: '123'
},
clientKey: 'your key'
}
fetch('https://api.worldpay.com/v1/tokens', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
body: JSON.stringify(formData)
})
.then(data => {
if (data.ok) {
data.json().then(result => {
// if data is valid you will get token
console.log('result', result) // <-
})
}
})
.catch(err => console.log('err', err))
If cart data is correct you will get 'token' inside 'result' variable. Then you should send this token to your backend, then backend should make request with this token as mentioned in official documentation - 3D secure backend integration
Other steps described in this link.

How to call a function upon http get or post?

I'm sure this is a stupid question but I am very new to the backend so please forgive me.
I am building an angularjs app with express/node also and am trying to integrate PayPal (as a Node.js SDK), what I want is to call the pay method on the SDK from an angular controller and I am doing as follows:
On button click:
// controller
$scope.pay = function(amount) {
PaymentFactory.doPayment(amount);
}
Payment Factory:
// PaymentFactory
return {
doPayment: function(amount) {
$http.get("../../../server/payments/paypal.js")
.then(function(response) {
console.log( response );
})
}
}
Then the server-side file is as below:
require('paypal-adaptive');
var app = require('../../server.js');
var PayPal = require('paypal-adaptive');
var paypalSdk = new PayPal({
userId: 'userid',
password: 'password',
signature: 'signature',
sandbox: true //defaults to false
});
var payload = {
requestEnvelope: {
errorLanguage: 'en_US'
},
actionType: 'PAY_PRIMARY',
currencyCode: 'GBP',
feesPayer: 'EACHRECEIVER',
memo: 'Chained payment example',
cancelUrl: 'returnUrl,
returnUrl: 'cancelUrl',
receiverList: {
receiver: [
{
email: 'email1',
amount: '3.40',
primary:'true'
},
{
email: 'email2',
amount: '1.20',
primary:'false'
}
]
}
};
paypalSdk.pay(payload, function (err, response) {
if (err) {
console.log(err);
} else {
// Response will have the original Paypal API response
// But also a paymentApprovalUrl, so you can redirect the sender to checkout easily
console.log('Redirect to %s', response.paymentApprovalUrl);
return response;
}
});
Of course the get request just returns a string of the server-side file contents, I understand why the above doesn't work but not sure how one would make it work. My aim is to call the PayPal SDK from the angular factory and get back the response so that I can redirect a user to a URL. A direct solution would be helpful but even more so I need pointers to the principles that I am not understanding here as far as how one should call functions upon user actions to get this data from the server side. I have tried searching but I don't really the language to use in my search.
All you need to do is use curl (node-curl npm module). Using curl will help you post data to your paypal url and get back the response. Now you need to handle this response from paypal and accordingly generate your own response to be received by the angular http method.

Cordova app using angular & ADAL

I'm building my first mobile app using Cordova. The back-end services live on Azure so I'm trying to get authentication working by using the ADAL plugin for Cordova.
First of all I found out that the library does not do intercepts as the ADAL library for Angular does. I'm using Angular within my Cordova app, paired with material design directives for the look-and-feel. Would have been nice to have interception, but as I understood it's just not there at the moment (should find out how hard it is to implement).
So instead I now wrote a service which will take care of sending REST api requests to Azure, including the correct authentication token. It's based on the sample found here.
This is what I came up with:
var request = function(url)
{
createContext()
.then(function () {
getAuthToken().then(
function(token) {
sendRequest(token, url);
})
},
function (err) {
$log.error("Failed to create a context.");
});
};
First it will create the authentication context:
function createContext () {
return $q(function (resolve, reject) {
var authenticationContext = Microsoft.ADAL.AuthenticationContext;
authenticationContext.createAsync(authority)
.then(function (context) {
authContext = context;
$log.log("Created authentication context for authority URL: " + context.authority);
resolve();
}, function (err) {
$log.error("Failed to create authentication context: " + pre(err))
reject();
});
});
};
The using the context it should get the authentication token:
function getAuthToken()
{
if (authContext == null) {
$log.error('Authentication context isn\'t created yet. Create context first');
return;
}
return $q(function (resolve, reject) {
authContext.acquireTokenAsync(resourceUrl, appId, redirectUrl)
.then(function (authResult) {
resolve(authResult.accessToken);
}, function (err) {
$log.error("Failed to acquire token: " + pre(err));
reject();
});
});
}
And afterwards it should send the request but I'll leave that part out since it never gets there anyway. I feel the need to re-emphasize that I'm a complete n00b at this stuff, so please be easy on me and especially on the code. There's probably a lot of room for improvement, I get that.
When I actually run this, it pops up a window where I need to login using my Microsoft account, cool. I even got two factor authentication first time I tried this, very nice! So I log in and I get returned to the code. But now the authresult variable has a status of "Failed" and there's no access token in the result. Unfortunately there's also no indication of what went wrong. So first part of the question is; what could have gone wrong here?
Now we get to the second part of the question; how do you properly debug these kinds of things? On my desktop I'd run Fiddler to check out the communication, but I don't know how to do that for Android. I'm debugging on my device btw, cause for some reason all of the emulators available to me are extremely slow (VS and Google) even though my hardware specs should support them just fine.
Thanks for any pointers!
Update 03-02-2016
Fiddling around with the code a bit, I decided to pack things in a login function which gives a somewhat shorter sample:
var createContext = function () {
if (authContext == null) {
authContext = new Microsoft.ADAL.AuthenticationContext(authority);
}
};
var getAuthToken = function () {
if (authContext == null) {
$log.error('Authentication context isn\'t created yet. Create context first');
return;
}
return $q(function (resolve, reject) {
authContext.acquireTokenAsync(endpointUrl, appId, redirectUrl)
.then(function (authResult) {
resolve(authResult.accessToken);
}, function (err) {
$log.error("Failed to acquire token: " + pre(err));
reject();
});
});
}
var login = function () {
createContext();
getAuthToken();
}
This code runs on the following input vars:
var authority = 'https://login.windows.net/[tenantid]';
var resourceUrl = 'https://graph.windows.net/';
var appId = '1ef41b17-0943-4359-bc12-014f4fd2d841';
var redirectUrl = 'http://MyApp';
I now used chrome://inspect to see what is going over the wire. And to my big surprise, I see a valid SAML token returned from Azure. It has got my name in it and everything, which I'd recon they wouldn't send after a failed authentication. So it seems that even though the response is ok, the ADAL library doesn't give me a proper response (Status = Failed). Again no clue on how to proceed :S
I just solved it. And like one would expect, the remedy is as simple as they get. Configuring the application in Azure AD, I chose the "web application" type application, since this is a web application with Angular and all. Now I guess since Cordova translates things to native code, that's not the correct option to chose. As soon as I created a new application as "native application" instead and used the client ID of that one, everything started working.... Sincerely hope this will help someone else in the future...!
I had a very similar issue where I was trying to access a web api from a Cordova app. I was using the App ID Uri for the web api I wanted to access as the resouceURL when calling acquireTokenAsync. When I changed this to the client Id of the Web Api instead it worked.

Resources