Unable to Convert Data ( JPG Encoding ) to an Image - javascript

Hello Stackoverfllow,
The context,
> nodejs: v16.17.0
> NPM: 8.15.0
> OS: Ubuntu 20.04.5 LTS
> Axiom:0.27.2
I Developing an Application using Twitter API. I use Account Activity API to get a webhook event from it. Then I will have a media endpoint from which I can download an image.
The most important thing is that I'm trying to /GET da images from the Twitter Media API. The response ( from Twitter ) gives me the image encoded under res.data
data: '����\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00��\x00C\x00\x06\x04\x05\x06\x05\x04\x06\x06\x05\x06\x07\x07\x06\b\n' +
'\x10\n' +
'\n' +
'\t\t\n' +
"\x14\x0E\x0F\f\x10\x17\x14\x18\x18\x17\x14\x16\x16\x1A\x1D%\x1F\x1A\x1B#\x1C\x16\x16 , #&')*)\x19\x1F-0-(0%()(��\x00C\x01\x07\x07\x07\n" +
'\b\n' +
'\x13\n' +
'\n' +
'\x13(\x1A\x16\x1A((((((((((((((((((((((((((((((((((((((((((((((((((��\x00\x11\b\x06#\x03�\x03\x01"\x00\x02\x11\x01\x03\x11\x01��\x00\x1B\x00\x00\x02\x03\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07��\x00\x19\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05��\x00\f\x03\x01\x00\x02\x10\x03\x10\x00\x00\x01�x\x7Fe��\x00������P\x14\x00�\x00\x02�%\n' +
'Q�_K:�*�]�R�%!�(�I�%\x19\x12#�RI�/O\x06�l4#BMP\f\x06#\x0
(I dont know what type of encoding ( I received ) and their doc does not mention it ). its been days now, and I had try to encode with Binary, base64 and UTC-8, which failed in all these attempted
I visited a lot of tutorials, but I could not see any solution that worked for me. , will link a few 1 , 2 , 3
Moreover, I could see the image from the postman client, but I didn't find any way to download this image as a jpg in the local drive.
Below is my snippet for the request
const nconf = require('nconf')
nconf.file({ file: 'config.json' }).env()
const axios = require('axios');
const crypto = require('crypto');
const oauth1a = require('oauth-1.0a');
const CONSUMERKEY = nconf.get('TWITTER_CONSUMER_KEY');
const CONSUMERSECRET = nconf.get('TWITTER_CONSUMER_SECRET');
const TOKENKEY = nconf.get('TWITTER_ACCESS_TOKEN');
const TOKENSECRET = nconf.get('TWITTER_ACCESS_TOKEN_SECRET');
function getAuthHeaderForRequest(request) {
const oauth = oauth1a({
consumer: { key: CONSUMERKEY, secret: CONSUMERSECRET },
signature_method: 'HMAC-SHA1',
hash_function(base_string, key) {
return crypto
.createHmac('sha1', key)
.update(base_string)
.digest('base64')
},
})
const authorization = oauth.authorize(request, {
key: TOKENKEY,
secret: TOKENSECRET,
});
return oauth.toHeader(authorization);
}
const request = {
url: 'https://ton.twitter.com/1.1/ton/data/dm/1564581847908098052/1564581845014126592/56XDEw1t.jpg',
method: 'GET',
};
const authHeader = getAuthHeaderForRequest(request);
/**
* Media in direct messages must be retrieved via an authenticated app-user GET request.
* It is advised that applications store user's access tokens to use for direct message media retrieval.
*
* #param {string} url - the url for the media i wanna retrive
* #return {Promise}
*/
function retrieveMediaApi (url){
// message_request_options.url = 'https://ton.twitter.com/1.1/ton/data/dm/1564581847908098052/1564581845014126592/56XDEw1t.jpg' //url.toString(); //should be the media url
return axios.get(
request.url,
{ headers: authHeader,
AcceptEncoding: 'gzip, deflate, br' });
}
module.exports= retrieveMediaApi;
Here how I try to save the date to the local drive
retrieveMediaApi(x.message_create.message_data.attachment.media.media_url_https).then(async newUrl => {
//newevent.message.payload[0].url = newUrl;
//await decode(newUrl, { fname: 'example', ext: 'jpg' });
console.log(newUrl);
console.log('start')
require('fs').writeFile('outout.jpg',newUrl.data, // to use with writeFile
{ encoding: "binary" }, // to use with writeFile ***************WORKING
(err) => {
if (err) {
console.log("An error ocurred while writing the media file.");
return console.log(err);
}
}
);
console.log('!')
}).catch(x=>{
logger('🚀 ~ file: convert_formate.js ~ line 56 ~ retrieveMediaApi ~ x ', x);

Related

Translating Axios + crypto request to postman + cryptojs

I would like to make a request to an API using Postman. There is an example in the API documentation for Javascript using axios and crypto.
The documentation says the following
Signing a request
The value of the X-App-Access-Sig is generated by a sha256 HMAC algorithm using a secret key (provided upon App Token generation) on the bytes obtained by concatenating the following information:
A timestamp (value of the X-App-Access-Ts header) taken as a string
An HTTP method name in upper-case, e.g. GET or POST
URI of the request without a host name, starting with a slash and including all query parameters, e.g. /resources/applicants/123?fields=info
Request body, taken exactly as it will be sent. If there is no request body, e.g., for GET requests, don't include it.
Example:
const axios = require('axios');
const crypto = require('crypto');
var config = {};
config.baseURL= BASE_URL;
axios.interceptors.request.use(createSignature, function (error) {
return Promise.reject(error);
})
function createSignature(config) {
console.log('Creating a signature for the request...');
var ts = Math.floor(Date.now() / 1000);
const signature = crypto.createHmac('sha256', SECRET_KEY);
signature.update(ts + config.method.toUpperCase() + config.url);
if (config.data instanceof FormData) {
signature.update (config.data.getBuffer());
} else if (config.data) {
signature.update (config.data);
}
config.headers['X-App-Access-Ts'] = ts;
config.headers['X-App-Access-Sig'] = signature.digest('hex');
return config;
}
My attempt to implement this as a postman Pre-request Script:
var CryptoJs = require("crypto-js")
console.log('Creating a signature for the request...');
const endpoint = pm.request.url.toString().split("{{BASE_URL}}").pop()
var ts = Math.floor(Date.now() / 1000);
const signature = CryptoJs.HmacSHA256(ts + pm.request.method.toUpperCase() + endpoint + pm.request.body, "{{SECRET_KEY}}")
pm.request.headers.add({
key: 'X-App-Access-Ts',
value: ts
})
pm.request.headers.add({
key: 'X-App-Access-Sig',
value: signature.toString(CryptoJs.enc.Hex)
})
console.log(pm.request)
But I get the error:
{
"description": "Request signature mismatch",
"code": 401,
"correlationId": "req-53db2067-b0ec-4ce8-b333-387b0b20a955",
"errorCode": 4003,
"errorName": "app-token-signature mismatch"
}

MInio presigned url upload issue

I have an issue with the Minio presigned url , I've been able to get the url and to use the PUT method to insert my file into my Minio bucket but i could not open it especially when it is a jpg , a png or a pdf file because it's automatically modified by Minio who adds a header and a footer to the file what makes it unreadable as an image
exemple of header :
----------- 591397828093304071314847
Content-Disposition: form-data; name="file"; filename="y.png"
Content-Type: image/png
Here's what i got when i download it using the presignedGetObject
the problem is with the metadata added by minio.
enter image description here
I'm using Nodejs , here is my code :
service.js:
exports.presignedurl = async (filename) => {
return await minioClient.presignedPutObject(
process.env.MINIO_BUCKET,
filename
);
};
exports.getpresignedurl = async (filename) => {
return await minioClient.presignedGetObject(
process.env.MINIO_BUCKET,
filename,
24 * 60 * 60
);
};
controller.js
exports.presignedurl = async (req = null, res = null) => {
try {
let filename = req.query.filename;
let result = await StorageService.presignedurl(filename);
res.status(200).json(result);
} catch (err) {
res.status(405).send({ error: err.message, code: err.code });
}
};
exports.getpresignedurl = async (req = null, res = null) => {
try {
let filename = req.query.filename;
let result = await StorageService.getpresignedurl(filename);
res.status(200).json(result);
} catch (err) {
res.status(405).send({ error: err.message, code: err.code });
}
};
The key in this case is how the file is uploaded from the postman. While uploading the file, you need to use Body > Binary > Select File, rather than using the Body > Form-Data.
Source: https://stackoverflow.com/a/66413354/16587713

Bad Request when trying to get an access token

I'm trying to use the Nest Device API, however I am unable to get an Access Token as it throws
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
I've downloaded my credentials.json from GCP and I open a new tab with the AUTH_URL below:
const credentials = require('../../../credentials.json');
const PROJECT_ID = <NEST DEVICE API PROJECT ID>;
const REDIRECT_URL = 'http://localhost:3000/connect/callback';
const AUTH_URL =
`https://nestservices.google.com/partnerconnections/${PROJECT_ID}/auth?` +
`redirect_uri=${REDIRECT_URL}&access_type=offline&prompt=consent&client_id=${credentials.web.client_id}&` +
`response_type=code&scope=https://www.googleapis.com/auth/sdm.service`;
From that, I have my callback page that gets the authcode.
const credentials = require('../../../credentials.json');
const { code } = router.query; // Auth Code
try {
const url =
`https://www.googleapis.com/oauth2/v4/token?client_id=${credentials.web.client_id}` +
`&client_secret=${credentials.web.client_secret}&code=${code}&grant_type=authorization_code&` +
`redirect_uri=${REDIRECT_URL}`;
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
});
console.log(response);
} catch (e) {
console.error(e);
}
This is where the API returns the above error. I have also tried taking this URL and doing curl -L -X POST <url> however I get exactly the same results.
Any ideas?

Getting the pdf blob from url and insert to drive directly using puppeteer library and fetch

I´m trying to use puppeteer to log in a website and "download" a pdf directly to my drive. I've managed to reach the pdf page with puppeteer and I tried (between other tries) to get the blob using fetch with the cookies to send to drive. I can´t post the login information here, but if you could help me looking for an error (or more) in the code it would be great! For now, it goes to the page before pdf, gets the link, fetch with cookies and insert a pdf in drive, but the pdf is corrupted with 0 kb.
I tried setRequestInterception, getPdf (from puppeteer) and using buffer with some stuff I found on my research.
//Page before pdfPage. Here I got the link: urlPdf
//await page.goto(urlPdf);
//await page.waitForNavigation();
//const htmlPdf = await page.content();
const cookies = await page.cookies()
const opts = {
headers: {
cookie: cookies
}
};
let blob = await fetch(urlPdf,opts).then(r => r.blob());
console.log("pegou o blob")
// upload file in specific folder
var file ;
console.log("driveApi upload reached")
function blobToFile(req){
file = req.body.blob
//A Blob() is almost a File() - it's just missing the two properties below which we will add
file.lastModifiedDate = new Date();
file.name = teste.pdf;//req.body.word;
return file;
}
var folderId = myFolderId;
var fileMetadata = {
'name': 'teste.pdf',
parents: [folderId]
};
var media = {
mimeType: 'application/pdf',
body: file
};
drive.files.create({
auth: jwToken,
resource: fileMetadata,
media: media,
fields: 'id'
}, function(err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file.data.id);
}
});
I tried many things, but the final solution I came with is posted here:
Puppeteer - How can I get the current page (application/pdf) as a buffer or file?
await page.setRequestInterception(true);
page.on('request', async request => {
if (request.url().indexOf('exibirFat.do')>0) { //This condition is true only in pdf page (in my case of course)
const options = {
encoding: null,
method: request._method,
uri: request._url,
body: request._postData,
headers: request._headers
}
/* add the cookies */
const cookies = await page.cookies();
options.headers.Cookie = cookies.map(ck => ck.name + '=' + ck.value).join(';');
/* resend the request */
const response = await request_client(options);
//console.log(response); // PDF Buffer
buffer = response;
let filename = 'file.pdf';
fs.writeFileSync(filename, buffer); //Save file
} else {
request.continue();
}
});
This solution needs: const request_client = require('request-promise-native');

Download file from Amazon S3 using REST API

I have my own REST API to call in order to download a file. (At the end, the file could be store in different kind of server... Amazon s3, locally etc...)
To get a file from s3, I should use this method:
var url = s3.getSignedUrl('getObject', params);
This will give me a downloadable link to call.
Now, my question is, how can I use my own rest API to download a file when it comes from that link? Is there a way to redirect the call?
I'm using Hapi for my REST server.
{
method: "GET", path: "/downloadFile",
config: {auth: false},
handler: function (request, reply) {
// TODO
reply({})
}
},
Instead of using a redirect to download the desired file, just return back an unbufferedStream instead from S3. An unbufferedStream can be returned from the HttpResponse within the AWS-SDK. This means there is no need to download the file from S3, then read it in, and then have the requester download the file.
FYI I use this getObject() approach with Express and have never used Hapi, however I think that I'm pretty close with the route definition but hopefully it will capture the essence of what I'm trying to achieve.
Hapi.js route
const getObject = require('./getObject');
{
method: "GET", path: "/downloadFile",
config: {auth: false},
handler: function (request, reply) {
let key = ''; // get key from request
let bucket = ''; // get bucket from request
return getObject(bucket, key)
.then((response) => {
reply.statusCode(response.statusCode);
response.headers.forEach((header) => {
reply.header(header, response.headers[header]);
});
return reply(response.readStream);
})
.catch((err) => {
// handle err
reply.statusCode(500);
return reply('error');
});
}
},
getObject.js
const AWS = require('aws-sdk');
const S3 = new AWS.S3(<your-S3-config>);
module.exports = function getObject(bucket, key) {
return new Promise((resolve, reject) => {
// Get the file from the bucket
S3.getObject({
Bucket: bucket,
Key: key
})
.on('error', (err) => {
return reject(err);
})
.on('httpHeaders', (statusCode, headers, response) => {
// If the Key was found inside Bucket, prepare a response object
if (statusCode === 200) {
let responseObject = {
statusCode: statusCode,
headers: {
'Content-Disposition': 'attachment; filename=' + key
}
};
if (headers['content-type'])
responseObject.headers['Content-Type'] = headers['content-type'];
if (headers['content-length'])
responseObject.headers['Content-Length'] = headers['content-length'];
responseObject.readStream = response.httpResponse.createUnbufferedStream();
return resolve(responseObject);
}
})
.send();
});
}
Return a HTTP 303 Redirect with the Location header set to the blob's public URL in the S3 bucket.
If your bucket is private then you need to proxy the request instead of performing a redirect, unless your clients also have access to the bucket.

Categories

Resources