'Eperm: operation not permitted' when using multer - reactjs

I'm attempting to pass a video file from my front end (using React and Axios) and upload it to youtube from my backend using express (using this tutorial https://youtu.be/xhiWEpU-h-A). The file gets submitted in the form of a 'formdata' object from my front end.
Here's my backend
const oAuth = youtube.authenticate({type: 'oauth',client_id: credentials.web.client_id,client_secret: credentials.web.client_secret,//Redirect uris has not been set up, may cause errors
redirect_url: credentials.web.redirect_uris[0]
})
const storage = multer.diskStorage({destination: '/',filename(req, file, cb) {const newFileName = ${uuid()}-${file.originalname}cb(null,newFileName);}})
const uploadVideoFile = multer({storage: storage}).single("videoFile");
app.post('/api/uploadVideo', uploadVideoFile, (req, res)=>{
console.log("upload video endpoint established")console.log(file was set to: ${req.file})if(req.file)console.log('we found a file')
else
console.log('no file?')console.log(title: ${title} description: ${description})return;
//ignore the stuff below here
Here's the function that submits the formdata on the front end, as well as the state variables
const uploadVideo = ()=>{
//uploadVideo(Credentials, [{}])
const videoData = new FormData()
videoData.append("videoFile", videoFile)
videoData.append("title", videoTitle)
videoData.append("description", videoDescription)
console.log(videoData)
Axios.post("http://localhost:3001/api/uploadVideo", videoData).then((response) =>{
console.log(response.data)
})
}
const [videoTitle, setVideoTitle] = useState('')
const [videoMode, setVideoMode] = useState(true)
const [videoFile, setVideoFile] = useState(null)`
And here's the form object that accepts the video file
<Form.Control type="file" accept="video/mp4" disabled={!videoMode} onChange={(e)=>{setVideoFile(e.target.files[0])}}>
</Form.Control>`
When I attempt to run the function I get the following error message on my server
Error: EPERM: operation not permitted, open 'C:\fb434fe2-e46c-4d8c-8f41-7b807f1b92a7-Column test - Google Chrome 2022-01-12 17-27-21.mp4'
the error occurs before the post request can be resolved
I was hoping multer would be able to locate the file I passed to it but I simply get a permission error.

I managed to solve the error by setting up Multer again and using the default settings from the documentation
const upload = multer({dest: "uploads/"});//uploads to "uploads" folder on my server
//post request
app.post('/api/uploadVideo', upload.single("videoFile"), (req, res)=>{
const {title, description} = req.body;
console.log("upload video endpoint established")
console.log(`file destination was set to: ${req.file.destination}`)
//return

Related

Firebase Storage not displaying image properly (shows a small box)

EDIT: I've updated the CORS config but its still showing the same error.
I have a Tinymce RTE on my page, and when u drop an image into the editor, I have some functions that upload it to firebase storage, then swaps out the src of the text editor with the url fetched from firebase. It works kinda ok, but its being displayed as a broken link image icon.
When I check the link, its because originally it downloads the image when the link is clicked. I added a metadata property when it uploads it, but now its just showing a tiny box.
Here is the code where the image dropped into the editor is uploaded into firebase storage
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: 'image/jpeg',
};
await uploadBytes(storageRef, file, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message
console.log(error.message);
}
};
Originally, i didnt include the contentType metadata, and it was just uploading as application/octet-stream, which i assume is why it prompts you to save the image.
Image link: https://firebasestorage.googleapis.com/v0/b/cloudnoise-news.appspot.com/o/ref.jpg?alt=media&token=1edc90e7-1668-4a06-92a3-965ce275798b
Currently its displaying this
Somethings i checked through
firebase storage rules is in test mode, so should be able to read and write by anyone.
i tried sticking in different MIME types but it either shows the tiny box, or it shows "undefined"
the files upload successfully and the "swap" in Tinymce editor is also all good.
Any idea why this is happening?
you need to set the metadata tag
const metadata = {
contentType: file.type,
};
This should ensure that the correct content type is set when the image is uploaded to Firebase Storage.
If this does not resolve the issue, you may need to check that the URL returned from getDownloadURL is valid and points to the correct image. You can try opening the URL in a new browser tab to verify that the image is accessible.
I fixed it by adding a blob, I created a blob object with the file data, then i just made it upload the blob object instead of the single file.
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: file.type,
};
// Create a new Blob object with the file data
const blob2 = await new Blob([file], { type: file.type });
// Upload the Blob to Firebase Storage
await uploadBytes(storageRef, blob2, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message;;
console.log(error.message)
}
};

React JS and Firebase : Cannot upload image

Im trying to create a signup form for my website. Im storing the user information on MongoDB and their images on Firebase. When Signup button is pressed i get "POST https://firebasestorage.googleapis.com/v0/b/app/o?name=image.jpg 403" in the browser's console
I have seen several tutorials on how to upload files to firebase storage using React.js and this is what i tried:
const [file , setfile] = useState(null);
const handleClick = (e)=>{
e.preventDefault();
const fileName = new Date().getTime() + file?.name;
const storage = getStorage(app);
const StorageRef = ref(storage , fileName);
const uploadTask = uploadBytesResumable(StorageRef, file);
uploadTask.on('state_changed',
() => {
// Handle successful uploads on complete
// For instance, get the download URL: https://firebasestorage.googleapis.com/...
getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => {
//signup() is the node js signup endpoint
signup(dispatch ,{email , password , username , phonenumber , profile:downloadURL});
})
});
}
Image field:
<input type="file" name="file" id="file" onChange={(e)=>setfile(e.target.files[0])} />
If is needed to upload any other part of the code please let me know
Based on the comments under your question you get a 403 error because your Security Rules prevent any user to upload a file (allow read, write: if false;). This is also a point listed by #eugenemusebe in his answer.
You need to adapt your Security Rules in such a way the desired users have the correct access right for writing:
For example a user needs to be authenticated to upload an image:
service firebase.storage {
// The {bucket} wildcard indicates we match files in all Cloud Storage buckets
match /b/{bucket}/o {
// Match filename
match /filename {
allow read: if <condition>;
allow write: if request.auth != null;
}
}
}
More details in the Security Rules documentation.
Note that for testing (and confirming that this is the problem) you can (temporarily) open the write access with:
service firebase.storage {
// The {bucket} wildcard indicates we match files in all Cloud Storage buckets
match /b/{bucket}/o {
// Match filename
match /filename {
allow read: if <condition>;
allow write: if true;
}
}
}

Trying to upload files to firebase storage but its not working. Error object is empty, how do I figure out what's wrong?

So i'm trying to send image files uploaded by my users to firebase storage using the file type input element. Like this:
<input
className={inputStyle}
{...register("donorPhotoFile")}
type="file"
accept=".png, .jpg,.jpeg"
></input>
So when I try to console.log the value returned of that input, im getting an object with the following properties:
name: "file_name.jpg",
size: ,
type: "image/png"
webkitRelativePath: ""
The /api/firebase is my api endpoint in next.js to upload my form data to firestore. From the firebase documentation, the 'file' should come from File API which I've did but its always unsuccessful and im not sure what im doing wrong.
const submitForm = async (data) => {
const imageFile = data.donorPhotoFile[0] //this is the file
const imageUpload = await fetch("/api/firestorage", {
method: "POST",
body: imageFile
});
const res = await imageUpload.json()
console.log(res)
}
//in my firestorage endpoint i've done this:
const storage = getStrorage(app) //app here is an instance of my firebase initialized
const handler = async (req, res) => {
const storageRef= ref(storage)
const imageFile = req.body
try {
uploadBytes(storageRef, imageFile);
res.status(200).json({statusRes: "success"})
} catch(error) {
res.status(400).json({statusRes: "failed", errorMessage: error})
}
}
Doing that returns a storage/invalid-root-operation error code with a message of:
"Firebase Storage: The operation 'uploadBytes' cannot be performed on a root reference, create a non-root reference using child, such as .child('file.png')
So tried to make a reference to a specific file and inserted the file name as a second parameter to storageRef like this:
const storageRef = ref(storage).child(`images/${req.body.name}`)
but its still not working but now i'm getting an empty error object so I can't figure out what's wrong now. So i actually tried checking what req.body is and it's returning this:
file object in my api endpoint
I don't understand why is it like that? And what im actually looking at? What i've sent in my post request is a File object. Like this:
File object i attached to my post request
You can create a reference to a path using Modular SDK as shown below:
const storageRef= ref(storage, `images/${req.body.name}`)
The .child() method is used in older name-spaced syntax.

SAS key permissions getting change when using blobserviceclient

I am trying to upload files to blob storage in azure from a react webapp but am having issues with the signature in the authorization header.
This is how the sasToken looks in my code
const sasToken = `sv=2020-08-04&ss=bfqt&srt=sco&sp=rwdlacupx&se=2021-09-22T00:41:33Z&st=2021-09-20T16:41:33Z&spr=https&sig=svP%2FecNOoteE%2**************%3D`;
const containerName = `containername`;
const storageAccountName = "acountname";
This is what it looks like the the GET and PUT requests of getBlobsInContainer and createBlobinContainer run.
sv=2020-08-04&ss=bfqt&srt=sco&sp=ghostery&se=2021-09-22T00:41:33Z&st=2021-09-20T16:41:33Z&spr=https&sig=svP/FecNOoteE/**************=
It's somehow overwriting the permission parameter in the token.
https://accountname.blob.core.windows.net/containername?SAS&comp=list&restype=container&_=1632199288178
The 3 functions I have to deal with it.
// return list of blobs in container to display
const getBlobsInContainer = async (containerClient) => {
const returnedBlobUrls = [];
// get list of blobs in container
// eslint-disable-next-line
for await (const blob of containerClient.listBlobsFlat()) {
// if image is public, just construct URL
returnedBlobUrls.push(
`https://${storageAccountName}.blob.core.windows.net/${containerName}/${blob.name}`
);
}
return returnedBlobUrls;
};
const createBlobInContainer = async (containerClient, file) => {
console.log(`initialising blobclient for ${file.name}`);
// create blobClient for container
const blobClient = containerClient.getBlockBlobClient(file.name);
console.log("blobclient generated");
// set mimetype as determined from browser with file upload control
const options = { blobHTTPHeaders: { blobContentType: file.type } };
// upload file
await blobClient.uploadBrowserData(file, options);
console.log("Adding Metadata");
await blobClient.setMetadata({UserName : 'Reynolds'});
};
const uploadFileToBlob = async (file) => {
if (!file) return [];
// get BlobService = notice `?` is pulled out of sasToken - if created in Azure portal
const blobService = new BlobServiceClient(
`https://${storageAccountName}.blob.core.windows.net?${sasToken}`
);
console.log(`blobservice: https://${storageAccountName}.blob.core.windows.net/?${sasToken}`);
// get Container - full public read access
const containerClient = blobService.getContainerClient(containerName);
// upload file
await createBlobInContainer(containerClient, file);
// // get list of blobs in container
return getBlobsInContainer(containerClient);
};
I'm basically trying to figure out why this is happening and how to prevent/avoid it. The code runs till the console.log(`blobservice: https://${storageAccountName}.blob.core.windows.net/?${sasToken}`); before breaking due to Error 403 from invalid signature.

upload image to S3 presigned url using react-native-image-picker and axios

I am trying to get an presigned url image upload working correctly. Currently the upload succeeds when selecting an image from the IOS simulator, however when I actually try to view the file it seems the file is corrupted and will not open as an image. I suspect it has something to do with my FormData but not sure.
export async function receiptUpload(file) {
const date = new Date();
const headers = await getAWSHeaders();
const presignUrl = await request.post(
urls.fileUpload.presignUpload,
{file_name: `${date.getTime()}.jpg`},
{headers}
)
.then(res => res.data);
const formData = new FormData();
formData.append('file', {
name: `${date.getTime()}.jpg`,
uri: file.uri,
type: file.type
});
const fileUpload = presignUrl.presignUrl && await request.put(
presignUrl.presignUrl,
formData
)
.then(res => res.status === 200);
}
I have tried from other fixes to change the file uri like so...
Platform.OS === 'android' ? file.uri : file.uri.replace('file://', '');
however this does not seem to work either.
I did this just recently in my current project and the following code is a working example for my use case. I didn't need to convert to a blob either though I am uploading to AWS S3 so if you are uploading elsewhere that may be the issue.
export const uploadMedia = async (fileData, s3Data, setUploadProgress = () => {}) => {
let sendData = { ...fileData };
sendData.data.type = sendData.type;
let formData = new FormData();
formData.append('key', s3Data.s3Key);
formData.append('Content-Type', fileData.type);
formData.append('AWSAccessKeyId', s3Data.awsAccessKey);
formData.append('acl', 'public-read');
formData.append('policy', s3Data.s3Policy);
formData.append('signature', s3Data.s3Signature);
formData.append('file', sendData.data);
return axios({
method: 'POST',
url: `https://${s3Data.s3Bucket}.s3.amazonaws.com/`,
data: formData,
onUploadProgress: progressEvent => {
let percentCompleted = Math.floor((progressEvent.loaded * 100) / progressEvent.total)
setUploadProgress(percentCompleted);
}
})
}
I would first check to see where the issue is occurring. After uploading can you view it on whatever storage service you are trying to upload it to. If so it's something on React Native side. If it doesn't ever get uploaded to the location you know its an error in your upload process. Might help you track the exact location of the error.
I had to do this recently for a project. I believe the data is a base64 string when coming directly from the file input. So the issue is your are uploading a base64 string not the image by simply passing the data field. I had to process it before uploading to the signed URL with the following method.
private dataUriToBlob(dataUri) {
const binary = atob(dataUri.split(',')[1]);
const array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], { type: 'image/jpeg' });
}
This answer fixed it for me: How can I upload image directly on Amazon S3 in React Native?
I had tried uploading with axios and fetch with FormData. The download went through but the image file was not readable, even when downloaded to my Mac from the S3 console:
The file "yourfile.jpg" could not be opened. It may be damaged or use a file format that Preview doesn’t recognize.
Only after trying to upload with XHR with the correct Content-Type header did it work. Your signedUrl should be correct as well, which seems to be the case if the download goes through.

Resources