I am using xero as my accounting software. I have one requirement that part of my application need to be integrated with xero to perform automation. Using the nodejs sdk seems so easy, but the fact is i cannot connect to xero even using the simplest example. Here is the code:
const xero = require('xero-node');
const config = {
"userAgent": "Firefox",
"consumerKey": "<MY_CONSUMER_KEY>",
"consumerSecret": "<MY_CONSUMER_SECRET>",
"privateKeyPath": "./privatekey.pem"
};
const xeroClient = new xero.PrivateApplication(config);
xeroClient.core.contacts.getContacts()
.then(contacts => {
console.log(contacts);
}).catch(err => {
console.log(err);
});
The code does nothing and prints no error. Anyone ever deal with this problem?
The most likely reason is that your privatekey is invalid. If you put these lines(https://github.com/XeroAPI/xero-node/pull/169/files) into your module then it will check it first.
You could also copy a few of those lines and validate your privateKey.
At the moment the SDK swallows the exception when the key is invalid.
Also, please make sure you are running server side - not browser side.
Solved. I need to add following code:
if (config.privateKeyPath && !config.privateKey)
config.privateKey = fs.readFileSync(config.privateKeyPath);
Related
I'm currently using firebase for the backend of a project I'm working on. In this project, the client authenticates using the firebase-twitter sign in method. For the purpose of security, I'm trying to minimise the amount of communication between the client and backend when it comes to auth data. In jest of this, I'm wondering if there is a way to access the auth data i.e. the user's twitter key/secret (as well as things like the user's twitter handle) from the server-side after the user authenticates ? I figured there might be a way as the authentication happens through twitter + firebase, but I'm struggling to find the exact solution I need in the documentation (been stuck on this for a week now) so was hoping someone else already knows if this is possible and how :) cheers
Maybe not the best way, but you can try: on client side use RealTime database and add a new entry every time the user log in. They call this 'realtime triggers'.
You don't mention what front are you using, but on ionic is something like:
firebase.auth().onAuthStateChanged(function(user) {
if (user)
this.db.addLogin(user.uid)
});
On database class function:
addLogin(uid){
let path = "/logins/"
let ref = this.db.list(path)
let body = {uid: uid}
return ref.push(body)
}
On the server side, listen the path using child_added
var ref = db.ref("logins");
ref.on("child_added", function(snapshot, prevChildKey) {
var newPost = snapshot.val();
console.log("Uid: " + newPost.uid);
console.log("Previous Post ID: " + prevChildKey);
});
More information about triggers
I am having trouble implementing the isRequestFromAssistant method to verify requests to my fulfillment webhook. Using Node.js, I instantiate the following variables at the start of my index.js file:
const App = require('actions-on-google').ApiAiApp;
const app = new App({ request, response });
I then use "app" with the .ask and .tell and other methods throughout my functions.
The code I see in the docs for implementing isRequestFromAssistant is:
const app = new ActionsSdkApp({request, response});
app.isRequestFromAssistant('my-project-id')
.then(() => {
app.ask('Hey there, thanks for stopping by!');
})
.catch(err => {
response.status(400).send();
});
If I leave out the first line and use my existing app variable, created with the .ApiAi method instead of the .ActionsSdkApp method, it doesn't work. If I create a new variable App1 and app1 using the .ActionsSdkApp method and change the above code to be app1.isRequestFromAssistant, it also doesn't work. I have tried other variations with no luck.
When I say it doesn't work, I mean I receive a 500 Internal Server Error when I call it. I am hosting it with NGROK currently. I am still a beginner with Node.js, although I have managed to get the other 700 lines of code working just fine, learning mostly from Google searches and reading these forums.
You have a few things going on here which, individually or separately, may be causing the problem.
First - make sure you have the most recent version of the actions-on-google library. The isRequestFromAssistant() function was added in version 1.6.0, I believe.
Second - Make sure you're creating the right kind of App instance. If you're using Dialogflow (formerly API.AI), you should be creating it with something like
const App = require('actions-on-google').DialogflowApp;
const app = new App( {request, response} );
or
const { DialogflowApp } = require('actions-on-google');
const app = new DialogflowApp( {request, response} );
(They both do the same thing, but you'll see both forms in documentation.) You should switch to DialogflowApp from ApiAiApp (which your example uses) to reflect the new name, but the old form has been retained.
If you're using the Actions SDK directly (not using Dialogflow / API.AI), then you should be using the ActionsSdkApp object, something like
const { ActionsSdkApp } = require('actions-on-google');
const app = new ActionsSdkApp({request: request, response: response});
(Again, you'll see variants on this, but they're all fundamentally the same.)
Third - Make sure you're using the right function that matches the object you're using. The isRequestFromAssistant() function is only if you are using the Actions SDK.
If you are using Dialogflow, the corresponding function is isRequestFromDialogflow(). The parameters are different, however, since it requires you to set confirmation information as part of your Dialogflow configuration.
Finally - If you're getting a 500 error, then check your logs (or the output from stderr) for the node.js server that is running. Typically there will be an error message there that points you in the right direction. If not - posting that error message as part of your StackOverflow question is always helpful.
Set the secure (randomly generated) auth header & key values in the dialogflow Fulfillment page, then in nodejs:
if (app.isRequestFromDialogflow("replace_with_key", "replace_with_value")) {
console.log("Request came from dialogflow!");
// rest of bot
} else {
console.log("Request did not come from dialogflow!");
response.status(400).send();
}
Also see: https://developers.google.com/actions/reference/nodejs/DialogflowApp#isRequestFromDialogflow
I am using the sample Video application pulled from GitHub. I am using a node.js server to supply the sample application with the access token. When I use the Twilio Console to generate a video access token and put it in my Node.js server as a literal and return it I am able to run the example application and connect to a room. If I use the sample token generation code in my Node.js server I get 'Invalid Access Token' back in an exception in the onDisconnected method in the Room.Listener.
The following code is what is running in the server to create the access token, I also found a different sample which I tried as well. I have gone back and verified that my data values for the account SID and the API keys are correct. I have a similar method running returning the VoiceGrant access token and that is working, but something about this VideoGrant one is off, I just do not see it.
// ***********************************************************************************
// ***********************************************************************************
// Video Access Token
// ***********************************************************************************
// ***********************************************************************************
var videoCallAccessToken = function(request, response) {
console.log('/twilio/video/accessToken');
var accessToken = makeVideoAccessToken();
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end(accessToken);
console.log(accessToken);
};
app.get('/twilio/video/accessToken', videoCallAccessToken);
var makeVideoAccessToken = function() {
const AccessToken = twilio.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
const grant = new VideoGrant({configurationProfileSid: accountData.videoConfigurationProfileSid});
const accessToken = new AccessToken(accountData.sid, accountData.videoApiSid, accountData.videoApiSecret);
accessToken.identity = 'ABC123';
accessToken.addGrant(grant);
return accessToken.toJwt();
};
FYI...I plan to alter the identity generation, but have not got there yet.
Thanks,
Adding this from my comment as an answer to close this question out, the issue was that the example code was flawed...
Ok, thought I had waited long enough prior to actually sending this, but apparently not. The issue is the example does not work in that the value passed into the VideoGrant constructor needed to have the attribute name quoted, so {configurationProfileSid: accountData.videoConfigurationProfileSid}); needed to be {'configurationProfileSid': accountData.videoConfigurationProfileSid}); Glad I finally found that, wasted a ton of time on it, but at least it is working properly now.
I want to create a google docs sheet within my alexa skill, that is written in Node.js. I have the enabled the google API, I set the required scope in amazon dev portal, I actually can log into the google account (so the first few lines of the posted code seem to work), and I do not get any error messages. But the sheet is never created.
Now the main question would be whether anyone can see the problem in my code.
But I would also have an additional question I would be very interested in: since I use account linking, I can not try that code in the Alexa test simulator, but have to upload it to Alexa before running it, where I can not get any debug messages. How does one best debug in that way?
if (this.event!== undefined)
{
if (this.event.session.user.accessToken === undefined)
{
this.emit(':tellWithLinkAccountCard','to start using this skill, please use the companion app to authenticate on Google');
return;
}
}
else
{
this.emit(':tellWithLinkAccountCard','to start using this skill, please use the companion app to authenticate on Google');
return;
}
var oauth2Client = new google.auth.OAuth2('***.apps.googleusercontent.com', '***', '***');
oauth2Client.setCredentials({
access_token: this.event.session.user.accessToken,
refresh_token: this.event.session.user.refreshToken
});
var services = google.sheets('v4');
services.spreadsheets.create({
resource : {properties:{title:"MySheet"}},
auth : oauth2Client
}, function(err,response) {
if( err ) {
console.log('Error : unable to create file, ' + err);
return;
} else {
console.dir(response);
}
});
Edit: I tried just the lower part manually, and could create a spreadsheet. So the problem seems indeed to be retrieving the access token with "this.event.session.user.accessToken" .
I find it is much easier to debug issues like this using unit tests. This allows rerunning code locally. I use NPM and Mocha and it makes it easier to debug both custom and smart home skills. There is quite a bit of information available online about how to use NPM and Mocha to test Nodejs code, so I won't repeat that here. For example, refer to the Big Nerd Ranch article. It makes it a bit more complex to setup your project initially, but you'll be glad you did every time you hit a bug.
In this example, I would divide the code in half:
The first half would handle the request coming from Alexa and extract the token.
The second half would use the token to create the Google doc. I would also pass the name of the doc to create.
I would test the 2nd part first, passing in a valid token (for testing only) and a test doc name. When that is working, at least you'd know that the doc creation code was working, and any issues would have to be with the token or how you're getting it.
Once that was working, I would then create a test for the first part.
I would us a hardcoded JSON object to pass in as the 'event', with event.session.user.accesToken set to a the working test token used in the first test:
'use strict';
var token = '<valid token obtained from google account>';
let testEvent = {
'session': {
'user': {
'accessToken': token
}
}
}
I have a pretty simple NodeJS server that I'm using to monitor our Firebase Database. My code is basically identical to the sample on the Firebase documentation:
var firebase = require("firebase");
firebase.initializeApp({
databaseURL: 'https://myurl.firebaseio.com/',
serviceAccount: 'path/to/json.json'
})
Now the issue I'm having is when I run this code from within our network, it doens't seem to be connection as a have a block of code right after to read some data and it never gets ran:
var nodeRef = this.db.ref("node");
nodeRef.on("child_added", function (snapshot, prevChildKey) {
// ...
}, function (error) {
console.log(error);
})
If I give everyone write access to the database, I can take out the serviceAccount setting on the initializeApp call, and everything works perfectly. I've tried running Fiddler to see what it might be making a request to that is failing, but I'm not seeing any requests pop up in Fiddler at all. Any ideas what this might be calling that our proxy would need to allow?
Our IT team found what the problem was, I had asked them to open accounts.google.com in our proxy server. It got set to "allow" instead of "tunnel".
According to them, the HSTS headers were causing the SSL decryption on the proxy unless it was set to tunnel, which was causing the "self signed certificate" error I mentioned above in the comments.
For me, disabling Kaspersky got it to work. You can try that.