How do i encrypt a file before uploading to a server? - javascript

I am sending a file like this to the server:
const fd = new FormData()
const targetFile = document.getElementById('default_file').files[0]
fd.append('file', targetFile )
fetch('url', {
method: 'POST',
body: fd,
})
I want to be able to encrypt the file with a password before uploading (client-side)
i have tried this so far but i'm not sure where to go next:
const targetFile = document.getElementById('default_file').files[0]
const reader = new FileReader()
reader.readAsArrayBuffer(targetFile)
reader.onload = () => {
console.log(reader.result)
const encrypted = CryptoJs.AES.encrypt(reader.result, "password123") <-- is this correct?
//should i convert the encrypted part to something specific?
}
reader.result returns the arraybuffer of the file, is it this part that i have to encrypt, and will the file stay in the same format so i can upload it to the server without changing code there?

Related

Messy Chinese filenames in FormData

I used the following js code to load a file with a Chinese filename into FormData and then upload it and found the filename garbled on the server side.
export async function uploadFile(file, url) {
let formData = new FormData()
formData.append('file', file.file)
file.status = 'loading'
let response = await fetch(url, { method: 'POST', body: formData})
file.status = response.ok
return response
}
How can I solve the filename garbling problem because the filenames in formdata seem to be ASCII encoded?
This question is used to share my solution. The code is below. I encoded the file name with encodeURIComponent and created a new File Object from it.
export async function uploadFile(file, url) {
let formData = new FormData()
const file_ = new File([file.file], encodeURIComponent(file.filename), {type: file.file.type});
formData.append('file', file_)
file.status = 'loading'
let response = await fetch(url, { method: 'POST', body: formData})
file.status = response.ok
return response
}
Afterwards I decode the filename with decodeURIComponent on the server side.

Turn base64 string into png for upload to s3 in frontend

I feel like I'm going crazy, I really hope this is not a duplication although I did find multiple similar issues but none of the solutions worked for me.
I'm using react-signature-canvas to let people sign on the website. That library offers a toDataURL() method, which turns the canvas into a base64 string. I then remove the "data:image/png;base64," from that string and turn it into a Blop using the fetch function. Getting a presigned URL I use axios.put() to send the image to an S3 bucket. However when I download that image from that bucket I can't open it because it's corrupted. When I put the dataURL into a base64 to image converter online the string works.
Here is my code so far:
const fileUpload = async signatureImageSrc => {
const signatureImage = await (await fetch(signatureImageSrc)).blob();
const fileBody = new FormData();
fileBody.append("signature", signatureImage);
const config = {
headers: {
"Content-Type": "application/json"
}
};
const fileName = id + "-" + "signature.png";
axios
.post("/upload_url", {fileName: fileName, fileType: "image/png"}, config)
.then(res => {
axios.put(res.data, fileBody, config).then(res => console.log(res));
});
};
I have tried changing the type of the blop (because it currently set to text/html) as well as sending it appended to a Form data object, as well as changing the Content-Type in the config object. I tried creating it as a file ( new File([blop], fileName)) and sending it through and more.
It always gets corrupted or sometimes it's a .json or .html file.
I finally got it to work.
I used a function to create a blob from the base64 string and then turned that blob into a file by adding the lastModifiedDate and name property to it.
Additionally I did not use a form data element anymore but instead uploaded that created file directly to the S3 bucket.
The code looks like this now:
const fileUpload = signatureImageSrc => {
const config = {
headers: {
"Content-Type": "application/json"
}
};
const configBlop = {
headers: {
"Content-Type": "multipart/form-data"
}
};
const blob = b64toBlob(signatureImageSrc, "image/png");
const fileName = id + "-" + "beauftragung-unterschrift.png";
const file = blobToFile(blob, fileName);
axios
.post("/upload_url", {fileName: fileName, fileType: "image/png"}, config)
.then(res => {
axios.put(res.data, file, configBlop).then(res => console.log(res));
});
};
The function to create the Blob is taken from here and the blobToFile function looks like this:
const blobToFile = (theBlob, fileName) => {
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
};

How create json file by object for send request in Angular

I need to send a multipart request to server with a file (document_example.pdf) and a json file that contains the data object (data_object_example.json) in Angular 7.
data_object_example.json -> {
"attribute1": "name",
"attribute2": "second_name"
}
I know how create a multipart request, but I don't know how create json file by a object.
Thanks. ;)
Answer: Thanks to HaiTH
const docJson = {
fileDocType: file.name.split('?')[0].split('.').pop(),
fileName: file.name
}
const fileJson = new File([JSON.stringify(docJson)], "file.json", {type: "application/json'"});
const formData = new FormData();
formData.append('json', fileJson);
In the case you can't change backend and must create a file from client-side.
You can try this way:
const data = {someKey: 'value'};
const blob = new Blob([JSON.stringify(data)], {type: 'text/plain'});
const tmpFile = new File([blob], 'data_object_example.json');
// now you can pass this tmp file to a form with your pdf
const form = new FormData();
form.append('file', tmpFile);

How to convert Blob URL to Base64 string and retrieve an Image URL using Cloudinary Client-Side?

I am using React-Dropzone npm to use a nicely styled drag and drop out of the box file uploader. I got stuck on the fact that React-Dropzone as of version 8.2.0 didn't include the paths to the file, e.g. shortened it with just the image name. They do however, provide a Blob Url. I can't figure out how to convert a Blob-URL to a Base64 string and then send that to Cloudinary.
Another way can be:
const url = 'blob:http://uri';
const blobToBase64 = (url) => {
return new Promise((resolve, _) => {
// do a request to the blob uri
const response = await fetch(url);
// response has a method called .blob() to get the blob file
const blob = await response.blob();
// instantiate a file reader
const fileReader = new FileReader();
// read the file
fileReader.readAsDataURL(blob);
fileReader.onloadend = function(){
resolve(fileReader.result); // Here is the base64 string
}
});
};
// now you can get the
blobToBase64(url)
.then(base64String => {
console.log(base64String) // i.e: data:image/jpeg;base64,/9j/4AAQSkZJ..
});
// or with await/async
const file = await blobToBase64(url);
console.log(file) // i.e: data:image/jpeg;base64,/9j/4AAQSkZJ..
I've figured it out:
After a few hours, and some nice people posting on StackOverflow I have pieced it together.
const getBlobData = (file) => {
axios({
method: "get",
url: file, // blob url eg. blob:http://127.0.0.1:8000/e89c5d87-a634-4540-974c-30dc476825cc
responseType: "blob",
}).then(function (response) {
var reader = new FileReader();
reader.readAsDataURL(response.data);
reader.onloadend = function () {
var base64data = reader.result;
const formData = new FormData();
formData.append("file", base64data);
formData.append("api_key", YOUR_API_KEY);
// replace this with your upload preset name
formData.append("upload_preset", YOUR_PRESET_NAME);//via cloudinary
axios({
method: "POST",
url: "https://api.cloudinary.com/v1_1/YOUR_CLOUD_NAME/upload",
data: formData,
})
.then((res) => {
const imageURL = res.data.url;
//YOU CAN SET_STATE HOWEVER YOU WOULD LIKE HERE.
})
.catch((err) => {
console.log(err);
});
};
});
};

Mock image upload to Cloudinary

A form I use to upload a book cover to Cloudinary has an input type='file' on it. However I'd like to allow no image upload too that is when the form submits there is no file provided to input type='file'. Cloudinary responds with Request failed with status code 400.
This is how I try to mock a file to upload it to Cloudinary inside an action.
export const addBook = (bookData, history) => (dispatch) => {
const cloudinaryUrl = 'https://api.cloudinary.com/v1_1/*****/upload';
const cloudinaryUploadPreset = '*****';
const formData = new FormData();
bookData.cover[0] && formData.append('file', bookData.cover[0]);
if (!bookData.cover[0]) {
const blob = new Blob([''], { type: 'image/png' });
blob['lastModifiedDate'] = '';
blob['name'] = 'mockImageFile';
blob['webkitRelativePath'] = '';
blob['size'] = 7654;
formData.append('file', blob);
/* const f = new File([''], 'filename', { type: 'image/jpeg' });
formData.append('file', f); */
}
formData.append('upload_preset', cloudinaryUploadPreset);
axios({
url: cloudinaryUrl,
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
data: formData
})
... ...
Still Cloudinary responds with Request failed with status code 400. How do I convince it to take a programmatically created 'file'?
The goal is to handle an upload with no file.
You need to convert blob data to a data URI which will be accepted by the file parameter to Cloudinary's upload method.
Please try below codebase to convert blob data to data URI. which you can append it to formdata.
const blob = new Blob([""],{ type: "image/png" });
blob["lastModifiedDate"] = "";
blob["name"] = "mockImageFile";
blob["webkitRelativePath"] = "";
blob["size"]=7654;
var reader = new FileReader();
var blob_base64data;
reader.readAsDataURL(blob);
reader.onloadend = function() { blob_base64data = reader.result;
};
formData.append("file", blob_base64data);
You can either perform a check for an empty file before uploading to Cloudinary and not upload to Cloudinary if there is no file or you can use a default image everytime there is no file uploaded instead of creating a blob.

Categories