GCP storage issue - javascript

Trying to wrap my head around what this error really means, but it's saying Anonymous caller does not have storage.objects.get access to... when I try to get fileData from a bucket file.
app.get('/api/videos', (req, res) => {
const storageBucket = storageClient.bucket(config.video_bucket);
storageBucket.getFiles(function(err, files) {
if (!err) {
let fileArray = [];
files.forEach(function(file) {
const videoAnnotationBucket = storageClient.bucket(config.video_json_bucket);
const videoAnnotationFilename = (file.metadata.name).replace('/', '').replace('.', '') + '.json';
const annotationFile = videoAnnotationBucket.file(videoAnnotationFilename);
// GET ANNONATIONS FOR EACH FILE
annotationFile.get(function(error, fileData) {
if (error) {
console.log('error getting file', error);
}
else {
const remoteJsonUrl = fileData.metadata.mediaLink;
// console.log(fileData.metadata);
request({
url: remoteJsonUrl,
json: true
},
function(jsonReadErr, jsonResp, body) {
console.log('logging body:');
console.log(body);
The error is occuring on the callback, and I'm reading the error via console.log(body) which gives me the error message I stated above.
What's weird is it's saying I'm anonymous when I did gcloud auth login as well as I'm providing creds when I declare storageBucket as such:
const storageClient = storage({
credentials: {
"client_email": "clientEmail",
"private_key": "privateKey",
},
projectId: "projectId"
});
So right off the bar, to avoid any "did you set this" questions, no I am not actually supplying those values I omitted the real values, and we use them elsewhere so I know they are correct.
My question is, what does Anonymous caller mean? And how can I fix it? How is it thinking I am anonymous when I did all the (seemingly) necessary things to use the API?

It's possible that you need to explicitly authenticate within request. This SO thread looks related.
Let us know how explicitly authenticating worked out!

Related

How to get a variable from front to a service worker?

Some context
I've created a service worker to send notifications to registered users.
It works well until I tried to implement a sort of id to each people who register to a service worker (to send notification).
I do that because I have to delete old registration from my database, so I took the choice to let each users three registration (one for mobile device and two others for different navigator on computer) and if there is more, I want to remove from the database the older.
Tools
I'm using nodejs, express and mySql for the database.
The issue
When I launch a subscription I got this error:
SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse (<anonymous>)
I saw in an other post that it's because they try to JSON.parse what's already an object.
But in my case, I can't find where I parse, see the part which are concerned:
// service.js (service worker file)
// saveSubscription saves the subscription to the backend
const saveSubscription = async (subscription, usrCode) => {
const SERVER_URL = 'https://mywebsite:4000/save-subscription'
subscription = JSON.stringify(subscription);
console.log(subscription); // I got here what I expect
console.log(usrCode); // <-------------------------------- HERE I GOT UNDEFIND
const response = await fetch(SERVER_URL, {
method: 'post',
headers: {
'Content-Type' : 'application/json',
},
body : {
subscription: subscription,
usrCode: usrCode
}
})
return response
}
But when I console.log(usrCode) in my inspector, I got the good value.
So how should I do to get the value in service.js
Maybe the problem is from:
const bodyParser = require('body-parser')
app.use(bodyParser.json())
At the beginning I thought that the issue is from the back (because I'm not really good with async function).
And here is the back, If maybe I got something wrong.
// index.js (backend)
// Insert into database
const saveToDatabase = async (subscription, usrCode) => {
// make to connection to the database.
pool.getConnection(function (err, connection) {
if (err) throw err; // not connected!
console.log(usrCode);
console.log(subscription);
connection.query(`INSERT INTO webpushsub (webpushsub_info, webpushsub_code) VALUES ('${subscription}', '${usrCode}')`, function (err, result, fields) {
// if any error while executing above query, throw error
if (err) throw err;
// if there is no error, you have the result
console.log(result);
connection.release();
});
});
}
// The new /save-subscription endpoint
app.post('/save-subscription', async (req, res) => {
const usrCode = req.body.usrCode; // <------------------ I'm not sure about this part
const subscription = req.body.subscription
await saveToDatabase(JSON.stringify(subscription, usrCode)) //Method to save the subscription to Database
res.json({ message: 'success' })
})
By searching on google, I've found this tutorial. So the reason why usrCode is undefined is because the service worker doesn't have access to a data stored in front.
First you have to pass it in the URL as following:
// swinstaller.js (front)
// SERVICE WORKER INITIALIZATION
const registerServiceWorker = async (usrCode) => {
const swRegistration = await navigator.serviceWorker.register('service.js?config=' + usrCode); //notice the file name
return swRegistration;
}
And then get it in the service worker:
// service.js (service worker file)
// get the usrCode
const usrCode = new URL(location).searchParams.get('config');

How do I catch aws-sdk errors that occur outside of my call stack?

The Situation
I'm using the aws-sdk to interact with an S3 bucket.
If I don't have the proper credentials set up, the sdk appropriately complains. However, its method of complaint is an error that is thrown outside of my call stack. I want to be able to catch that error and handle it gracefully.
The Problem
Here is a little script that causes the problem.
import { S3 } from 'aws-sdk';
try {
const s3 = new S3();
s3.createPresignedPost({}, (err, data) => {
console.log('sup dog');
});
} catch (err: Error) {
console.log('KABOOM!');
}
I would expect this to catch any errors thrown by s3.createPresignedPost and trigger the catch, but what actually happens is sup dog is posted, and then node crashes with a stack trace that points to the aws-sdk.
sup dog
./node_modules/aws-sdk/lib/services/s3.js:1241
throw new Error('Unable to create a POST object policy without a bucket,'
^
Error: Unable to create a POST object policy without a bucket, region, and credentials
at features.constructor.preparePostFields (./node_modules/aws-sdk/lib/services/s3.js:1241:13)
at finalizePost (./node_modules/aws-sdk/lib/services/s3.js:1204:22)
at ./node_modules/aws-sdk/lib/services/s3.js:1221:24
at finish (./node_modules/aws-sdk/lib/config.js:386:7)
at ./node_modules/aws-sdk/lib/config.js:428:9
at Object.<anonymous> (./node_modules/aws-sdk/lib/credentials/credential_provider_chain.js:111:13)
at Object.arrayEach (./node_modules/aws-sdk/lib/util.js:516:32)
at resolveNext (./node_modules/aws-sdk/lib/credentials/credential_provider_chain.js:110:20)
at ./node_modules/aws-sdk/lib/credentials/credential_provider_chain.js:126:13
at ./node_modules/aws-sdk/lib/credentials.js:124:23
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
The Question
The solution here of course is to properly configure the aws sdk with credentials, but I would like to gracefully handle cases where that hasn't happened by catching the error and preventing a hard crash.
How can I use the callback pattern of createPresignedPost without risking system crash?
I have created this lambda request :
const AWS = require('aws-sdk');
const s3 = new AWS.S3();
exports.handler = async (event, context) => {
//console.log('Received event:', JSON.stringify(event, null, 2));
let body;
let statusCode = '200';
const headers = {
'Content-Type': 'application/json',
};
var params = {
Bucket: 'bucketname',
Fields: {
key: 'example.pdf'
}
};
try {
s3.createPresignedPost(params, (err, data) => {
body = "successfully";
});
} catch (err) {
statusCode = '400';
body = err.message;
} finally {
body = JSON.stringify(body);
}
return {
statusCode,
body,
headers,
};
};
For testing success case run code as it is. For testing error comment params one of key either bucket or key. it will throw error and catch.
Response:
{
"statusCode": "400",
"body": "\"Unable to create a POST object policy without a bucket, region, and credentials\"",
"headers": {
"Content-Type": "application/json"
}
}
This turned out to be a full blown bug in AWS -- I issued a patch which was merged.
So, the answer to this question is that it wasn't possible to catch that error... but now you don't have to.

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client ASYNC AWAIT not Working

I am trying to verify if some data is in the session. If not the controller will redirect you to another route, to get that data.
The problem is that I am getting an error "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"
I search over StackOverflow and I find that everyone that had this problem fix it using it async/await, but i was already using async await.
Your help will be trully appreciated!
Thank you very much!
Jose
dashboardCtrl.init = async (req, res) => {
//
var frontdata = req.session;
if (!frontdata.user) {
frontdata.user = await userfacebook.findOne({ where: { 'email': frontdata.passport.user } });
};
if (!frontdata.store) {
tmpstoredata = await userstore.findOne({ where: { 'userfacebookId': frontdata.user.id } });
if (!tmpstoredata) {
res.redirect('/toURL');
};
};
};
Note: I am using EJS MATE.
If i do this
dashboardCtrl.init = async (req, res) => {
//
res.redirect('/toURL');
};
Redirect works, the problem is using await. So i dont know how to continue
That error says that you have already sent an answer to the cliente. In other words, you are trying to declare for the second time -> **res.*****.
Check the flow again in case you have twice declared any action on express's "res".
The solution below allows you to have a good structured and readable asynchronous code.
dashboardCtrl.init = (req, res) => {
// I think destructuring looks good
let { user, store } = req.session;
(async () => {
try {
if (!user) user = await userfacebook.findOne({ where: { 'email': frontdata.passport.user } });
let tmpstoredata;
if (!store) tmpstoredata = await userstore.findOne({ where: { 'userfacebookId': frontdata.user.id } });
if (!tmpstoredata) res.redirect('/toURL');
} catch (err) {
// don't forget ;)
}
})()
};
Hope this can help you.
Greetings.
The code was OK
The problem was the EJS MATE
I replace it with EJS

Append a query param to a GET request?

I'm trying to make a simple API that calls another API that will return some information. The thing is, in order to connect to the second API, I need to attach query parameters to it.
So what I've tried to do so far is to use an axios.get in order to fetch the API. If I didn't need to add queries on top of that, then this would be really simple but I'm having a really hard time trying to figure out how to attach queries on top of my request.
I've created an object that pulled the original query from my end and then I used JSON.stringify in order to turn the object I made into a JSON. Then, from my understanding of Axios, you can attach params my separating the URL with a comma.
On line 6, I wasn't sure if variables would carry over but I definitely can't have the tag var turned into the string "tag", so that's why I left it with the curly brackets and the back ticks. If that's wrong, then please correct me as to how to do it properly.
the var tag is the name of the query that I extracted from my end. That tag is what needs to be transferred over to the Axios GET request.
app.get('/api/posts', async (req, res) => {
try {
const url = 'https://myurl.com/blah/blah';
let tag = req.query.tag;
objParam = {
tag: `${tag}`
};
jsonParam = JSON.stringify(objParam);
let response = await axios.get(url, jsonParam);
res.json(response);
} catch (err) {
res.send(err);
}
});
response is SUPPOSED to equal a JSON file that I'm making the request to.
What I'm actually getting is a Error 400, which makes me think that somehow, the URL that Axios is getting along with the params aren't lining up. (Is there a way to check where the Axios request is going to? If I could see what the actual url that axios is firing off too, then it could help me fix my problem)
Ideally, this is the flow that I want to achieve. Something is wrong with it but I'm not quite sure where the error is.
-> I make a request to MY api, using the query "science" for example
-> Through my API, Axios makes a GET request to:
https://myurl.com/blah/blah?tag=science
-> I get a response with the JSON from the GET request
-> my API displays the JSON file
After looking at Axios' README, it looks like the second argument needs the key params. You can try:
app.get('/api/posts', async (req, res, next) => {
try {
const url = 'https://myurl.com/blah/blah';
const options = {
params: { tag: req.query.tag }
};
const response = await axios.get(url, options);
res.json(response.data);
} catch (err) {
// Be sure to call next() if you aren't handling the error.
next(err);
}
});
If the above method does not work, you can look into query-string.
const querystring = require('query-string');
app.get('/api/posts', async (req, res, next) => {
try {
const url = 'https://myurl.com/blah/blah?' +
querystring.stringify({ tag: req.params.tag });
const response = await axios.get(url);
res.json(response.data);
} catch (err) {
next(err);
}
});
Responding to your comment, yes, you can combine multiple Axios responses. For example, if I am expecting an object literal to be my response.data, I can do:
const response1 = await axios.get(url1)
const response2 = await axios.get(url2)
const response3 = await axios.get(url3)
const combined = [
{ ...response1.data },
{ ...response2.data },
{ ...response3.data }
]

Express req object is not defined inside async sequelilze js then call

I am new to express js. I am working on a project. where i have to send email when the user is updated. but the problem is that once the user is updated. Inside the update success I don't have access to req object or userUpdate. I know its a concept issue. Can you please let me know how to fix this.?
thanks
module.exports.update = function(req, res) {
var body = _.pick(req.body, 'email', 'first_name', 'last_name', 'role', 'clinic_id', 'profile_id');
if (!_.isString(body.email) || !_.isString(body.first_name) || body.email.length == 0 || body.first_name.length == 0) {
res.status(404).send();
} else {
var userUpdate = req.body;
var selector = {
email: userUpdate.email
};
userUpdate.updatedAt = new Date().getTime();
//*********req object and userUpdate have data till this point**************//
db.user.update(userUpdate, { where: selector })
.then(function(result) {
// ****req object and userUpdate are not defined here. WHY??
mailer.sendActivateEmail(result);
// sending response to front end
res.json(result);
}).catch(function(e) {
res.status(500).json(e);
console.log("error updating user:", e);
});
}
};
The problem was in my understanding. I am able to access req object anywhere in the function. The problem occurs in debugging. When i use debugger in my code. I usually don't have access to variables outside of function scope.
When i use console.log to print object before debugger, things work as expected.
Don't have time to actually run your code but I would suggest two things:
Try binding your function call so that the function definitely receives the req object.
db.user.update(userUpdate, { where: selector }).then(updateSuccess.bind(req)))
Define updateSuccess like this
const updateSuccess = (req, result) => { ... }
Try using anonymous functions instead of function, ie.
module.exports.update = (req, res) => {
Could be some weird scoping problem

Categories

Resources