File encryption using Crypto.js with AES cipher algorithm? - javascript

I have stacked so far with file uploading program on javascript. The code I have wrapped in if() and else statement.
if(filetype.name.match(/(.*?)\.(jpg|gif|doc|pdf|mp3|mp4|avi|txt|png|jpeg|tif)$/)) {
const formData = new FormData();
var encryptedfile;
const url = 'process.php';
const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
e.preventDefault();
const file = document.querySelector('[type=file]').files[0];
var reader = new FileReader();
And after that, I have written reader.onload function. The code out of that function doesn't see what inside, because of local variables. But the problem not about that
reader.onload = function() {
var encrypted = CryptoJS.AES.encrypt(reader.result, "ThisIsPasswordForTheFile" );
encryptedfile = new File([encrypted], "foo.txt", {
type: "text/plain"
});
formData.append('files',encryptedfile);
}
reader.readAsDataURL(file);
The problem is const formData = new FormData() doesn't add this encrypted file
after I send it to the server, and it is successful, but no file the upload folder
fetch(url, {
method: 'POST',
body: formData,
}).then((response) => {
console.log("ok");
// document.location.href = _url+"process.php";
});
});
}
And I am not really sure about CryptoJS.AES.encrypt code. is this code encrypt right file from document input? const file = document.querySelector('[type=file]').files[0];
Please take a look at my whole js code
document.querySelector("#inputGroupFile01").addEventListener("change", function(){
const reader = new FileReader();
var filetype =this.files[0]
if(filetype.name.match(/(.*?)\.(jpg|gif|doc|pdf|mp3|mp4|avi|txt|png|jpeg|tif)$/)) {
const formData = new FormData();
var encryptedfile;
const url = 'process.php';
const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
e.preventDefault();
const file = document.querySelector('[type=file]').files[0];
var reader = new FileReader();
reader.onload = function() {
var encrypted = CryptoJS.AES.encrypt(reader.result, "ThisIsPasswordForTheFile" );
encryptedfile = new File([encrypted], "foo.txt", {
type: "text/plain"
});
formData.append('files',encryptedfile);
}
reader.readAsDataURL(file);
fetch(url, {
method: 'POST',
body: formData,
}).then((response) => {
console.log("ok");
});
});
}
else{
alert("please choose another one!");
}
});

Related

Preventing duplicate files in an input file

I'm using loodash cloneDeep to upload files, however I need files to not be duplicated and only be able to upload a file once. How can I do this using cloneDeep?
I don't know how to do it, I googled, but the solution was only for jquery
const [files, setFiles] = useState([]);
const onSelectFile = (e) => {
try {
let fileArr = cloneDeep(files);
let promises = [];
for (let file of e.target.files) {
promises.push(
new Promise((resolve, reject) => {
const fileName = file.name
const type = file.type;
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (evt) {
const fileData = evt.target.result;
fileArr.push({
name: fileName,
type: type,
data: fileData,
comment: "",
id: `${new Date().getTime()}_${fileName}`,
canDelete: true
});
if (typeof props.onFileSelected == "function")
props.onFileSelected(fileArr);
resolve(true);
}
reader.onerror = function (evt) {
console.log("error reading file");
reject(false);
}
})
);
}
Promise.all(promises).then(r => {
setFiles(fileArr);
})
}
catch(e) {
console.log(e);
}
}
If relying on the filenames is enough, you can try to store them to check if it has been uploaded already :
const [files, setFiles] = useState([]);
//state to store uploaded file's name
const [fileNames, setFileNames] = useState([]);
const onSelectFile = (e) => {
try {
let fileArr = cloneDeep(files);
let promises = [];
for (let file of e.target.files) {
promises.push(
new Promise((resolve, reject) => {
const fileName = file.name
//if the file has not been already uploaded
if (!fileNames.includes(fileName)) {
//add the current fileName in state
setFileNames([fileName, ...fileNames]);
const type = file.type;
let reader = new FileReader();
reader.readAsArrayBuffer(file);
reader.onload = function (evt) {
const fileData = evt.target.result;
fileArr.push({
name: fileName,
type: type,
data: fileData,
comment: "",
id: `${new Date().getTime()}_${fileName}`,
canDelete: true
});
if (typeof props.onFileSelected == "function")
props.onFileSelected(fileArr);
resolve(true);
}
reader.onerror = function (evt) {
console.log("error reading file");
reject(false);
}
} else {
alert("File has already been uploaded");
reject(false);
}
})
);
}
Promise.all(promises).then(r => {
setFiles(fileArr);
})
}
catch(e) {
console.log(e);
}
}
Note: this will not prevent the case when the user upload a file, then refresh the website and upload the same file again
If you want to prevent that you have to ask your backend if the file has already been upload or not.

How can I read the data in the excel file with reactjs or javascript using the path to the file

I want to read the contents of the file directly by using the file path. I can do this by having the file selected. But I don't know how to do it using the direct file path. I could not find any examples or sources for this. Below is how I read the file by selecting it from the input.
import * as XLSX from 'xlsx';
var items = [];
readExcel = (file) => {
const promise = new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsArrayBuffer(file);
fileReader.onload = (e) => {
const bufferArray = e.target.result;
const wb = XLSX.read(bufferArray, { type: "buffer" });
const wsname = wb.SheetNames[0];
const ws = wb.Sheets[wsname];
const data = XLSX.utils.sheet_to_json(ws);
resolve(data);
};
fileReader.onerror = (error) => {
reject(error);
};
});
promise.then((d) => {
this.items = d;
console.log(this.items)
// fill dictionary
this.dictionary = Object.assign({}, ...this.items.map((x) => ({ [x.PartNumber]: x.Cost })));
console.log(this.dictionary)
});
};
<input
type="file"
onChange={(e) => {
const file = e.target.files[0];
this.readExcel(file);
}}
/>
I beleive it should work:
const req = new XMLHttpRequest();
req.responseType = "arraybuffer";
req.open("GET", "https://.../MyExcelFile.xlsx", true);
req.onload = () => {
const bufferArray = req.response;
const wb = XLSX.read(bufferArray, { type: "buffer" });
...
I couldn't find a direct read operation. I converted the excel file to json format and got my job done.

Create File object using file path

With the given file path, create a file object. new File(file_path) doesn't work. (WIN/MAC)
When tried creating a new file object using File constructor. There occurs an error.
new File(decodeURI(file_path))
when the above approach is followed File constructor err comes up.
File API needs a Blob here is work-arround
var GetFileBlobUsingURL = function (url, convertBlob) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
convertBlob(xhr.response);
});
xhr.send();
};
var blobToFile = function (blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var GetFileObjectFromURL = function(filePathOrUrl, convertBlob) {
GetFileBlobUsingURL(filePathOrUrl, function (blob) {
convertBlob(blobToFile(blob, 'testFile.jpg'));
});
};
var FileURL="test/test.jpg"
GetFileObjectFromURL(FileURL, function (fileObject) {
console.log(fileObject);
});
Had the exact same issue today, so I'll provide an answer in TypeScript(3.7.5) based on what worked out for me.
Tips:
FileAPI needs a Blob to work with (as others have also stated), it won't work with a file path.
The function:
static async createFile(path: string, name: string, type: string): Promise<File> {
let response = await fetch(path);
let data = await response.blob();
let metadata = {
type: type
};
return new File([data], name, metadata);
}
The call:
await createFile('../assets/images/someInterestingPNGImage.png', 'iAmAFile.png', 'image/png')
.then((file) => {
//do something with ur file.
console.log(file);
});
Here is a simple alternative solution using axios:
const srcToFile = async (src, fileName) => {
const response = await axios.get(src, {
responseType: "blob",
});
const mimeType = response.headers["content-type"];
return new File([response.data], fileName, { type: mimeType });
};

How to upload files with Vue.js2 and Laravel 5.4?

I'm trying to upload an image using Laravel as a backend and Vue.js2 as a frontend.
Here's my code
addUser() {
let formData = new FormData();
formData.append('fullname', this.newUser.fullname);
formData.append('email', this.newUser.email);
formData.append('phone', this.newUser.phone);
formData.append('photo', this.newUser.photo);
formData.append('roles', this.newUser.roles);
formData.append('permissions', this.newUser.permissions);
axios.post('users', formData)
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
},
onFileChange(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage(file) {
let reader = new FileReader();
let vm = this;
reader.onload = (e) => {
vm.newUser.photo = e.target.result;
};
reader.readAsDataURL(file);
},
And Laravel code on a backend:
if($request->hasFile('photo')) {
return response()->json([
'success' => true,
'message' => 'Файл есть.',
'data' => $request->all()
]);
}
return response()->json([
'success' => true
]);
Finally, the html code:
<input type="file" class="filestyle" data-text="Загрузите фото" #change="onFileChange">
Unfortunately, it doesn't seem to work. File has not been found. What's the workaround?
I doubt that the image gets attached to the request sent because the line formData.append('photo', this.newUser.photo); only appends the file's temporary url to the formData due to the fact that the property photo of the newUser object was set to the temporary url of the file inside your FileReader onload method: vm.newUser.photo = e.target.result;.
You should attach the file to the formData and not the temporary url
To do that, you might want to change your createImage(file) function to:
createImage(file) {
let reader = new FileReader();
this.newUser.photo = file;
let vm = this;
reader.onload = (e) => {
vm.newUser.photo_preview = e.target.result;
};
reader.readAsDataURL(file);
},
and you can use this.newUser.photo_preview for showing the photo preview wherever you like in your view.
Hope that helps :)
Solved
I simply deleted createImage(file) method and changed onFileChange(e) method like this:
onFileChange(e) {
let files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.newUser.photo = files[0];
}
And everything worked perfecly. Thanks for everyone for spending time and help...)

What is the correct fetch body in React with FileReader

I have a React app which gets data from an upload. I want to send the data (mostly CSV's) row by row to my API. The problem is that I cannot get the correct value.
const uploadLocalFile = (file) => (dispatch) => {
const reader = new FileReader()
reader.onload = evt => {
fetch("some/api/here",
{
credentials: "same-origin",
method: "POST",
body: //file, evt.target.result ?? <---
})
}
reader.readAsText(file)
alert("done.")
}
file is the whole file, evt.target.result is not allowed in react? Is evt.currentTarget forbidden by fetch?
What do you mean by "not allowed in react"? Passing this function as the handler for your file input should work:
handleSelectFile = (event) => {
const file = event.currentTarget.files[0]
const reader = new FileReader()
reader.onload = (event) => {
const content = event.target.result
// do whatever you want do do with `content`
}
reader.readAsText(file)
}

Categories

Resources