I'm currently working on hooking into the Gmail API using NodeJS. I have a working connection and can access my messages and such, but I'm having difficulty actually sending email with the API. Here is what I have below:
/**
* Send Message.
*
* #param {String} userId User's email address. The special value 'me'
* can be used to indicate the authenticated user.
* #param {String} email RFC 5322 formatted String.
* #param {Function} callback Function to call when the request is complete.
*/
function sendMessage(userId, email, callback, auth) {
// Using the js-base64 library for encoding:
// https://www.npmjs.com/package/js-base64
//var base64EncodedEmail = Base64.encodeURI(email);
var base64EncodedEmail = Buffer.from(email).toString('base64');
var request = gapi.client.gmail.users.messages.send({
'userId': userId,
'resource': {
'raw': base64EncodedEmail
}
});
request.execute(callback);
}
This is from the official documentation (here), for the most part. I'm calling the function as such:
authorize(JSON.parse(content), sendMessage('me', btoa('This is a test')));
The error I'm getting is this:
var request = gapi.client.gmail.users.messages.send({
^
ReferenceError: gapi is not defined
at sendMessage (D:\Documents\Web Programming\React\neis-guy-painting\src\Server\Node\gmail.js:148:17)
at fs.readFile (D:\Documents\Web Programming\React\neis-guy-painting\src\Server\Node\gmail.js:23:34)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:511:3)
I realize that this is because I don't have gapi defined, but I can't seem to figure out what that actually should be.
What am I missing here?
Related
I'm facing an issue with the Binance API
Whenever I try to make a request for withdrawal, it returns "Signature for this request is not valid." error message, even though if with the same function I make a request for the account info, Funding balance, getAll balances or whatever, it works.
I already tried several solutions, but nothing seemed to work. This are some of my tries reading similar issues
Works with endpoints like "api/v3/account" or "sapi/v1/capital/config/getall"
Sending the signature and the params in the body (it returns "You are not authorized to execute this request" error message, I think is because is not reading the body, only query params)
Activate all permissions for the API, and check the API
Send in the query the param "name"
Using Node packages like node-binance-api (It's not up to date with the request for withdrawals)
Changing scripts in librery node-binance-api to the actual api for withdrawals (same error as doing it myself)
I'm using NodeJs, axios to make the requests. This is my function:
/**
* Send Request to withdraw USDT funds from the selected wallet to a specified address
* #param wallet
* #param amount
* #param address
* #returns
* #link https://binance-docs.github.io/apidocs/spot/en/#withdraw-user_data
*/
makeWithdrawal(
wallet: WalletType = 'SPOT',
amount: number,
address: string
) {
const walletIndex = WalletEnum[wallet];
return this.makeRequest<{ id: string }>(
'sapi/v1/capital/withdraw/apply',
'POST',
{
coin: 'USDT',
amount,
wallet: walletIndex,
address,
network: 'TRX',
name: '_'
}
);
}
/**
* Makes Request to Binance Pay API
* #param endpoint
* #param method
* #param params
* #returns
* #link https://binance-docs.github.io/apidocs/spot/en
*/
private makeRequest<T>(
endpoint: string,
method: Method = 'GET',
params: {[key: string]: string | number} = {}
): Promise<T> {
const timestamp = Number(new Date().getTime()).toFixed(0);
let query = `timestamp=${timestamp}`;
for (const key in params) {
if (Object.prototype.hasOwnProperty.call(params, key)) {
const value = params[key];
query += `&${key}=${value}`
}
}
const signature = this.sign(query);
const headers: AxiosRequestHeaders = {
'X-MBX-APIKEY': process.env.BINANCE_API_KEY,
};
const requestObservable = this.httpService.request<T>({
method,
url: `${process.env.BINANCE_API_URL}/${endpoint}`,
params: {...params, timestamp, signature},
headers
}).pipe(
map(res => res.data)
);
return lastValueFrom(requestObservable);
}
/**
* Signs payload with private key
* #param payload
* #returns
*/
private sign(query: string) {
return createHmac('sha256', process.env.BINANCE_API_SECRET)
.update(query)
.digest('hex');
}
I really can't understand what is going, if someone could please help me to solve this, as I'm reading this is a common issue, but I really tried solutions and no hope.
Thank you
For anyone having this problem, the issue was that I was sending the request inside the "params" instead of the url, weirdly enough, it didn't proccess it correctly, so make this small change:
const requestObservable = this.httpService.request<T>({
method,
url: `${process.env.BINANCE_API_URL}/${endpoint}?${query}&signature=${signature}`,
headers
}).pipe(
map(res => res.data)
);
And you are good to go
I am using the Xero Api with Nodejs and the xero-node library.
I have completed the oAuth flow and saved the token to the database. The issue i am now having is continually getting a 403 forbidden error when attempting to get anything from Xero be that Contacts, Accounts or Users. Sample code is below
I can get tenants ok without an issue however anything else doesn't work. I have checked the scopes to make sure when I am setting up the client they are correct which they are.
var getStuff = async(tokenSet) => {
await xero.setTokenSet(tokenSet);
const tenants = await xero.updateTenants();
const xeroTenantId = tenants[0].id // {String} Xero identifier for Tenant
const ifModifiedSince = new Date("2020-02-06T12:17:43.202-08:00");
const where = 'IsSubscriber==true'; // {String} Filter by an any element
const order = 'LastName ASC'; // {String} Order by an any element
console.log(tenants);
try {
const response = await xero.accountingApi.getUsers(xeroTenantId, ifModifiedSince, where, order);
console.log(response.body || response.response.statusCode)
}
catch (err) {
/// console.log(err);
console.log(`There was an ERROR! \n Status Code: ${err.response.statusCode}.`);
console.log(`ERROR: \n ${JSON.stringify(err.response.body, null, 2)}`);
}
}
Which scopes have been added to the access token you are passing through? You can decode your token here https://jwt.io/
Also - you need to pass the ‘tenant.tenantId’ to the function. I believe the tenant.id actually relates to the connection id which is coming back from the /connections endpoint.
My hunch is that is the issue. Also curious how that’s working, as updateTenants() should have the empty function call on the end. Is that working for you?
I've sign up to start using Twilio and I'm trying to setup the quickstart (https://www.twilio.com/docs/voice/client/javascript/quickstart) and it's almost working but incoming calls are not being received by:
Client code (used on browser after getTokenCapabilities):
Twilio.Device.incoming(function (conn) {
log('Incoming connection from ' + conn.parameters.From);
var archEnemyPhoneNumber = '+12093373517';
if (conn.parameters.From === archEnemyPhoneNumber) {
conn.reject();
log('It\'s your nemesis. Rejected call.');
} else {
// accept the incoming connection and start two-way audio
conn.accept();
}
});
Code on Twilio Function for voice calls (consoles are always printed and else condition is never called:
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
console.log('entrou aqui');
if(event.To) {
console.log('entrou ali');
// Wrap the phone number or client name in the appropriate TwiML verb
// if is a valid phone number
const attr = isAValidPhoneNumber(event.To) ? 'number' : 'client';
const dial = twiml.dial({
callerId: context.CALLER_ID,
});
dial[attr]({}, event.To);
} else {
twiml.say('Thanks for calling!');
}
console.log('callback');
callback(null, twiml);
};
/**
* Checks if the given value is valid as phone number
* #param {Number|String} number
* #return {Boolean}
*/
function isAValidPhoneNumber(number) {
return /^[\d\+\-\(\) ]+$/.test(number);
}
I've include my phone number as Verified Caller ID, got a number from Twilio and create the functions using template Twilio Client Quickstart.
On Twilio Client Quickstart, i've paste TwiML SID as TWIML_APP_SID and tried to use my phone number and the number from Twilio as CALLER_ID.
Also I've changed VOICE URL on TwiML configuration and changed the VOICE URL on phone number from twilio configuration.
Any ideas on what is missing or what is wrong? When I open on browser http://127.0.0.1:8080/, It's possible to make calls but I don't receive any call on browser when I call to twilio number.
In order to answer call, you need to have your token name identity in a tag in your VoiceResponse, here is an example.
exports.incomingVoiceResponse = function voiceResponse( to ) {
// Create a TwiML voice response
const twiml = new VoiceResponse();
// Wrap the phone number or client name in the appropriate TwiML verb
// if is a valid phone number
const attr = isAValidPhoneNumber(to) ? 'client' : 'number';
const dial = twiml.dial({
callerId: to,
});
dial[attr]({}, 'jesus');
console.log(twiml.toString())
return twiml.toString();
};
See the 'jesus' client tag I have put ? Here is the token generator side :
exports.tokenGenerator = function tokenGenerator() {
const identity = 'jesus';
const capability = new ClientCapability({
accountSid: config.accountSid,
authToken: config.authToken,
});
capability.addScope(new ClientCapability.IncomingClientScope(identity));
capability.addScope(new ClientCapability.OutgoingClientScope({
applicationSid: config.twimlAppSid,
clientName: identity,
}));
// Include identity and token in a JSON response
return {
identity: identity,
token: capability.toJwt(),
};
};
This works for me using the node quickstart as is and changing both of these functions.
However, don't forger to change the from 'number' to 'client' in function voiceResponse because it's an incoming call and not an outgoing.
const attr = isAValidPhoneNumber(to) ? 'client' : 'number';
instead of
const attr = isAValidPhoneNumber(to) ? 'number' : 'client';
Since the default nameGenerator from the client-quickstart-node from Twilio generates a random name, it isn't properly set when receiving incoming call.
I need to use the revokeRefreshTokens method of the Auth class that is described in the Node.js API document here: https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth#revokeRefreshTokens
It is contained in the firebase-admin package which I have installed using the npm command as per the documentation at https://www.npmjs.com/package/firebase-admin#installation :
npm install --save firebase-admin
On doing this, and going into the installed directory and checking auth.js file, I see that the method is missing. Where exactly can I find this revokeRefreshTokens method to use in Firebase Cloud Functions?
Initially, I had also tried calling the method in my Cloud Function using:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
//Some additional code here to fetch the userRecord...
admin.auth().revokeRefreshTokens(userRecord.uid)
.then(function() {
console.log("Successfully revoked token");
})
.catch(function(error) {
console.log("Error revoking token:", error);
});
which gave an error saying
TypeError: admin.auth(...).revokeRefreshTokens is not a function.
Let me know if any further information is required.
Make sure you're installing the latest version (5.7.0). If you did that you will find the following in node_modules/firebase-admin/lib/auth/auth.js (around line 295):
/**
* Revokes all refresh tokens for the specified user identified by the provided UID.
* In addition to revoking all refresh tokens for a user, all ID tokens issued before
* revocation will also be revoked on the Auth backend. Any request with an ID token
* generated before revocation will be rejected with a token expired error.
*
* #param {string} uid The user whose tokens are to be revoked.
* #return {Promise<void>} A promise that resolves when the operation completes
* successfully.
*/
Auth.prototype.revokeRefreshTokens = function (uid) {
return this.authRequestHandler.revokeRefreshTokens(uid)
.then(function (existingUid) {
// Return nothing on success.
});
};
I am trying to send text to all my peers and I found this function "sendDirectlyToAll".
For your convenience, I put the function information here:
sendDirectlyToAll(channelLabel, messageType, payload) - broadcasts a
message to all peers in the room via a dataChannel.
string channelLabel - the label for the dataChannel to send on.
string messageType - the key for the type of message being sent.
object payload - an arbitrary value or object to send to peers.
I do not understand the meaning of 2nd and 3rd parameters. Could you kindly show me an example how to use this function?
Thanks
Derek
Here is my example showing how i managed to get it working:
/**
* send directly to all other peers
*/
oSimpleWebRTC.sendDirectlyToAll(
'meta', // sLabel
'info', // sType - will become oData.sType
{"foo": "bar"} // oData - will become oData.payload
);
/**
* Handle incoming dataChannel messages sent by "sendDirectlyToAll"
* #param {object} oPeer The Remote sending Peer Object
* #param {string} sLabel A Label, e.g.: 'meta'
* #param {object} oData Object containing the relevant Data
*/
oSimpleWebRTC.on('channelMessage', function (oPeer, sLabel, oData) {
// e.g. we want label "hark" to be ignored, as it fires continiously.
if ('hark' === sLabel) {
return true;
}
if ('meta' === sLabel) {
if ('info' === oData.type)
{
// do your stuff
console.log(oData.payload.foo);
}
}
}
Also, There are Answers to this question at the official SimpleWebRTC issues Tracker: https://github.com/andyet/SimpleWebRTC/issues/450
See my blog post to this example: https://blog.ueffing.net/post/2017/02/22/simplewebrtc-usage-example-of-senddirectlytoall/