uploading a file from chrome extension popup - google-chrome-extension

I want to let the user choose and upload a file from the chrome extension popup. But, as soon as the file-chooser dialog opens the popup loses focus and closes immediately. From this answer, the workaround seems to be that I can move the dialog opening logic to the background-page, which is not affected by loss of focus.
I have tried the answer, but the file-chooser does not appear at all. It is weird that fileChooser.click() event does actually occur (I was able to verify it by creating a click listener for fileChooser). Below is a simplified version just to focus on the problem.
popup.html
<button id="uploadCSV">Upload CSV</button>
popup.js
$('#uploadCSV').click(function() {
chrome.extension.sendMessage({ action: 'browseAndUpload' });
});
background.js
var fileChooser = document.createElement('input');
fileChooser.type = 'file';
chrome.extension.onMessage.addListener(function (msg) {
if (msg.action === 'browseAndUpload') {
fileChooser.click();
}
});

Popup.js
var file = document.getElementById('#file')[0].files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
chrome.runtime.sendMessage({
"uploadFile": true,
blob: reader.result,
file: { name: file.name }
}, x => { })
};
reader.onerror = function (error) {
console.log('Error: ', error);
};
Background.js
function dataURLtoFile(dataurl, filename) {
var arr = dataurl.split(','),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
function uploadFile(msg) {
var file = msg.file;
let nfile = dataURLtoFile(msg.blob, file.name)
var formData = new FormData();
formData.append('cvFile', nfile);
var settings = {
"async": true,
"crossDomain": true,
"url": "endpoint",
"method": "POST",
"headers": {
"accept": "application/json",
"cache-control": "no-cache",
},
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": formData
}
$.ajax(settings).done(function (response) {
console.log(response);
});
}
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) {
switch (!0) {
case 'uploadFile' in msg: uploadFile(msg); break;
}
})

Related

How to send PDF file object from Facebook messaging API

I have developed a facebook messenger app in Node.js.
I am using PDFKit to generate a PDF and send it to the user from the messenger bot. The problem I am facing is I am not able to send the generated file object.
generatePDF.js
require('dotenv').config("./env");
const getStream = require('get-stream')
const PDFDocument = require('pdfkit');
const fs = require('fs');
async function createPDF(name) {
const doc = new PDFDocument({
layout: 'landscape',
size: 'A4',
});
doc.rect(0, 0, doc.page.width, doc.page.height).fill('#fff');
``
doc.fontSize(10);
doc.image('src/airtable/assets/corners.png', -1, 0, { scale: 0.585 }, { fit: [doc.page.width, doc.page.height], align: 'center' })
doc
.font('src/airtable/fonts/Pinyon Script 400.ttf')
.fontSize(65)
.fill('#125951')
.text(`${name}`, 240, 240, {
// width: 500,
// align: 'center'
});
doc.end();
return await getStream.buffer(doc)
}
module.exports = { createPDF}
Invoking the above function after receiving specific postback
main.js
const pdf= require('./generatePDF')
name = "John"
const generated_pdf = await pdf.createPDF(name)
sendMedia(sender_psid, generated_pdf )
async function sendMedia(sender_psid, file) {
try {
let response = {
"attachment": {
"type": "file",
"payload": file
}
}
}
callSendAPI(sender_psid, response);
}
catch (e) {
console.log("Error cert ", e)
}
}
function callSendAPI(sender_psid, response) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
};
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v7.0/me/messages",
"qs": { "access_token": process.env.FB_PAGE_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!!!');
} else {
console.error("Unable to send message:" + err);
}
});
}
How can I send the file object without a URL and without fetching locally?
any help or advice is appreciated!
There is no such type ("application/pdf"), for sending attachments like a PDF you'd use the file type. Also, as stated in the docs, there is no "filedata" parameter, instead you'd use "payload".
Docs can be found here by the way:
https://developers.facebook.com/docs/messenger-platform/reference/send-api/

How to block the url chrome://extension and new tab in my extension with manifest v3?

My google chrome extension has a background.js and content script that communicate with port.OnMessage but I have noticed that when I run my extension in Chrome://extension it throws an error because it is not a url and the same happens with a new google tab chrome which has no url. How could I block them?
On the internet I got information that said that they were blocked with
"exclude_matches": [
"chrome://extensions/"
]
however, this doesn't work for the version 3 manifest. Also how could it tell you not to run the extension in a new tab (no url)
this is my manifest v3
"name":"Certified Records Full Certificate",
"description":"Esta extensión permite grabar la pantalla o hacer capturas de pantalla",
"version": "1.0",
"manifest_version":3,
"background":{
"service_worker":"background.js"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"],
"exclude_matches": [
"chrome://extensions/"
]
}],
"permissions":["storage","activeTab","scripting","tabs","desktopCapture"],
"action":{
"default_popup":"popup.html",
"default_icon":{
"16":"/images/logo-16.png",
"32":"/images/logo-32.png",
"48": "/images/logo-48.png",
"128": "/images/logo-128.png"
}
},
"icons":{
"16":"/images/logo-16.png",
"32":"/images/logo-32.png",
"48": "/images/logo-48.png",
"128": "/images/logo-128.png"
} }
this is my background.js
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(function(msg){
if (msg.type === 'SS_UI_REQUEST') {
requestScreenSharing(port,msg);
}
});
});
function requestScreenSharing(port, msg) {
const sources = ['window'];
const tab = port.sender.tab;
desktopMediaRequestId = chrome.desktopCapture.chooseDesktopMedia(
sources,
port.sender.tab,
streamId => {
if (streamId) {
msg.type = 'SS_DIALOG_SUCCESS';
msg.streamId = streamId;
msg.text ="sharing";
} else {
msg.type = 'SS_DIALOG_CANCEL';
msg.text ="cancel";
}
var tab = getTabId();
tab.then((value) => {
const respuesta = chrome.tabs.connect(value.id, {
name: "respuesta",
});
respuesta.postMessage(msg);
});
}
);
}
async function getTabId() {
let queryOptions = { active: true, currentWindow: true };
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
}
this is my content-script.js
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(function(msg){
if (msg.type === 'SS_UI_REQUEST') {
console.log(msg);
var background = chrome.runtime.connect();
background.postMessage(msg);
}
if (msg.type === 'SS_DIALOG_SUCCESS') {
console.log(msg);
startScreenStreamFrom(msg.streamId);
}
if (msg.type === 'SS_DIALOG_CANCEL') {
console.log(msg);
}
if(msg.type === "SS_UI_TAKESCREENSHOT")
{
console.log("tomar screenshot");
TakeScreenShot();
}
});
});
function startScreenStreamFrom(streamId) {
console.log("compartiendo pantalla");
navigator.mediaDevices
.getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: streamId
}
}
})
.then(stream => {
window.stream = stream;
});
}
async function TakeScreenShot(){
setTimeout(async () => {
const screen = window.stream;
const track = screen.getVideoTracks()[0];
const imageCapture = new ImageCapture(track);
await imageCapture.grabFrame()
.then(function(bitmap) {
track.stop();
var canvas = document.createElement('canvas');
canvas.width = bitmap.width
canvas.height = bitmap.height
const context = canvas.getContext('2d')
context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height)
const image = canvas.toDataURL()
var link = document.createElement('a');
link.download = 'FullCertificateCaptureScreen.png';
link.href = image
link.click();
})
.catch(function(error) {
track.stop();
console.log('grabFrame() error: ', error);
});
}, 1000);
}
this is the popup script
document.getElementById("btn-share").addEventListener("click", function(){
var tab = getTabId();
tab.then((value) => {
chrome.storage.local.set({'pestaña': value.id});
const port = chrome.tabs.connect(value.id, {
name: "conexion",
});
port.postMessage({ type: 'SS_UI_REQUEST', text: 'start' }, '*');
}); //fin de tab.then()
})//fin de click addEventListener
document.getElementById("btn-capture").addEventListener("click", async function(){
chrome.storage.local.get('pestaña', function (result) {
const port = chrome.tabs.connect(result.pestaña, {
name: "tomarScreenShot",
});
port.postMessage({ type: 'SS_UI_TAKESCREENSHOT', text: 'takescreenshot' }, '*');
window.close();
});
});
async function getTabId() {
let queryOptions = { active: true, currentWindow: true };
let [tab] = await chrome.tabs.query(queryOptions);
return tab;
}

Send multiple files from express server to rest api

I am trying to send multiple files from react to express server and then to microservice. The problem is that my express server is getting crashed whenever I try to upload multiple files.
Here is my express.js side code:
router.post("/upload-files", upload.array("file[]"), async function (req, res) {
let check = new FormData();
// check = req.files;
const file = req.files;
// console.log("DATA------------------------>", file);
// check.append("file", file.buffer, file.originalname);
await axios.post(
constants.URL2 +":9095/upload-files", check,
{
headers: {
...check.getHeaders(),
},
})
.then((res) => {
return res;
})
.then((result) => {
res.send(result.data);
});
});
Here is my React.js side code:
update = () => {
if (this.isValidForm()) {
$(".loader").css({ display: "block" });
$(".overlay").css({ display: "block" });
// const obj = {
// fullName: this.state.fullName,
// };
var formData = new FormData();
const size = this.state.fileData;
for (let i = 0; i < size.length; i++) {
console.log(this.state.fileData[i]);
formData.append("file[]", this.state.fileData[i]);
}
// formData.append("files", this.state.fileData);
const updateRequest = {
method: "POST",
headers: {
// "Content-Type": "application/json",
Authorization:
},
// body: JSON.stringify(obj),
body: formData
};
fetch(URL.BASE_URL + "upload-file", updateRequest)
.then((res) => {
if (res.status == 401) {
this.props.GETLOGGEDINUSER(null);
this.props.history.push("/");
} else {
return res.json();
}
})
.then((res) => {
if (res.statusCode == 0) {
this.props.history.push({
pathname: "/newScreen",
state: { notification: "File uploaded Successfully" },
});
toast.success("File uploaded Successfully");
$(".loader").css({ display: "none" });
$(".overlay").css({ display: "none" });
} else {
toast.error(res.message);
$(".loader").css({ display: "none" });
$(".overlay").css({ display: "none" });
}
});
} else {
}
};
I tried many ways to solve this but none of them works.

Uploading blob/file in react-native, contents is empty

I am able to succesfully upload a blob with proper contents from my web browser, but when I do it from react-native, the upload file is empty. Here is the code:
async function doit() {
const data = new FormData();
data.append('str', 'strvalue');
data.append(
'f',
new File(['foo'], 'foo.txt', {type: 'text/plain'}),
);
await fetch('http://localhost:3002/upload', {
method: 'POST',
body: data
});
}
However doing this same code from react-native, it uploads, but the file is empty.
Here is the node.js server I am using to test this. Loading http://localhost:3002 gives you a button called "upload it". Clicking it does the upload from the web. Screenshots of results are below.
var multiparty = require('multiparty');
var http = require('http');
http
.createServer(function (req, res) {
if (req.url === '/upload' && req.method === 'POST') {
console.log('multipart here');
var form = new multiparty.Form();
form.parse(req, function (err, fields, files) {
console.log(require('util').inspect({ fields, files }, false, null, true));
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ bar: true }));
});
return;
}
console.log('here');
// show a file upload form
res.writeHead(200, { 'content-type': 'text/html' });
res.end(
`
<script>
async function doit() {
const data = new FormData();
data.append('str', 'strvalue');
data.append(
'f',
// new File([new Blob(['asdf'], {type : 'text/plain'})], 'filename.txt'),
new File(['foo', 'what', 'the', 'hell'], 'foo.txt', {type: 'text/plain'}),
);
const res = await fetch('http://localhost:3002/upload', {
method: 'POST',
body: data
});
console.log(JSON.stringify(res, null, 4));
}
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('b').addEventListener('click', doit, false)
}, false);
</script>
<button type="button" id="b">upload it</button>
`
);
})
.listen(3002);
From web browser we see the node server logs this, notice file size is 14.
However from react-native we see file size is 0:
I faced the same problem recently while posting an image from a react-native app to a server. However, I was able to make it work by appending the name and type of the file to the formData instance.
Here, the uri argument to uploadImageAsync is passed as a route parameter from the previous screen.
const postShoutHandler = async () => {
setShoutUploadStatus("Started Upload");
const response = await uploadImageAsync(route.params.captures);
const uploadResult = await response.json();
if (uploadResult === "Upload successful") {
setShoutUploadStatus("Success");
navigation.navigate("Home");
} else {
setShoutUploadStatus("Failed");
}
};
/* <--Upload image function --> */
const uploadImageAsync = (uri: string) => {
const apiUrl = "https://www.yourserver.com/image";
let uriParts = uri.split(".");
let fileType = uriParts[uriParts.length - 1];
let formData = new FormData();
formData.append("img", {
uri,
name: `photo.${fileType}`,
type: `image/${fileType}`,
});
formData.append("description", "HEY");
let options = {
method: "POST",
body: formData,
headers: {
Accept: "application/json",
"Content-Type": "multipart/form-data",
Authorization: "Bearer " + accessToken,
},
};
return fetch(apiUrl, options);
};
/* <--Upload image function --> */
Here is the Image configuration.
const photoData = await camera.takePictureAsync({
base64: true,
exif: false,
});

Contentful Management API upload image

I'm using the CMA directly (no SDK). I am trying to upload a file to Contenful. From what I've read the flow is this:
Upload the file
Create an asset(associating it to the recently uploaded file)
Process the asset
I am uploading the file like this:
const xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 201) {
let data: any = JSON.parse(xhr.response);
resolve(JSON.parse(xhr.response));
} else {
reject(xhr.response);
}
}
};
const url = "https://upload.contentful.com/spaces/" + space_id + "/uploads";
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.setRequestHeader("Authorization", "Bearer " + token);
const formData = new FormData();
formData.append("file", file, file.name);
xhr.send(formData);
Then I create the asset like this:
const request = {
fields: {
file: {
"en-US": {
contentType: file.type,
fileName: file.name,
uploadFrom: {
sys: {
type: "Link",
linkType: "Upload",
id: uploadId
}
}
}
}
}
};
return axios
.post(
"https://api.contentful.com/spaces/" + space_id + "/assets",
JSON.stringify(request),
config
)....
and then process it like this:
const request = {
fields: {
file: {
"en-US": {
contentType: "image/png",
fileName: "Sample_45.png",
uploadFrom: {
sys: {
linkType: "Upload",
type: "Link",
id:uploadId
}
}
}
}
}
};
return axios
.put(
"https://api.contentful.com/spaces/" +
space_id +
"/assets/" +
assetId +
"/files/en-US/process",
asset.data.fields,
config
)
After that I can see an asset in Contentful Media, but the image never really loads, nor the image size is displayed. It seems like some how Contenful does not recognize the file, or has been incorrectly associated with the asset; I have no clue. Help please.
Looks like you are using React.
Create an upload form :
<input type="file" onChange={this.fileChangedHandler}>
<button onClick={this.uploadHandler}>Upload!</button>
and set your state, fileChangedHandler, and uploadHandler:
state = {selectedFile: null}
fileChangedHandler = (event) => {
this.setState({selectedFile: event.target.files[0]})
}
uploadHandler = () => {
axios.post(
'https://upload.contentful.com/spaces/{space_id}/uploads,
this.state.selectedFile,
config
)
}
And once the upload is finished, you can create, process, and publish the asset.

Resources