I Always Got Cors Error When Send DELETE request to gcs Resumable Singed Url - gcs

I've tried to use "resumable signed url" when uploading a file.
This is the CORS config on the bucket:
[{“maxAgeSeconds”: 3600, “method”: [“GET”, “PATCH”, “DELETE”, “OPTIONS”, “POST”, “PUT”], “origin”: [“*”], “responseHeader”: [“*”]}]
BE
const options: GetSignedUrlConfig = {
version: 'v4',
action: 'resumable',
expires: Date.now() + 60 * 60 * 1000, // 60 minutes
contentType: 'text/plain',
};
FE
const res1 = await axios.post(
signedUrl.url,
{},
{
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'text/plain',
'x-goog-resumable': 'start',
},
}
);
const res2 = await axios.put(res.headers.location, file);
Uploading the file works successfully.
The problem is when I sent a 'DELETE' request via the url while uploading. The below code is what I used.
Google Docs Link
await axios.delete(resumable_signed_url_session_uri, {
headers: {
'Content-Length': '0'
}
});
What I expected to happen is that the file is being stop uploaded. but I got a CORS error. To be more specific, in the Console panel of Chrome, I saw an error like this:
'xhr.js?78a4:193 Refused to set unsafe header "content-length"'.
After this error, I got a CORS error:
Access to XMLHttpRequest at 'https://storage.googleapis.com/%5Bbucket%5D/test/test.mp3? ... &upload_id=ADPycdvPhSounQyXYnfOeyiXu-reeZf2j2ghdrXzHcUkSNzoFmmTa3k8Mutis_hhXJjEiMbP6TtzSbjuXzXSClvHUrqdNUlvCJiy' from origin 'http://localhost:3001' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Where is it wrong? Any help would be appreciated.

Related

CORS while uploading to S3 in React-Vite application

I am trying to upload a file to s3 using aws sdk on a react application. However I bumped into CORS error and even after configuring the CORS policy for my bucket the error still persist.
My CORS policy for the bucket is as follow:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"http://localhost:3000"
],
"ExposeHeaders": []
}
]
And this is my code to upload my blob:
import * as AWS from 'aws-sdk';
const s3 = new AWS.S3({
accessKeyId: "access key id",
secretAccessKey: "secret access key",
});
export const uploadToS3 = (fileContent: Blob, fileName: string, bucket: string) => {
console.log('attempting to upload to s3')
const params = {
Bucket: bucket,
Key: fileName,
Body: fileContent
}
s3.upload(params, function (err: any, data: any) {
if (err) {
console.log(err);
} if (data) {
console.log(data);
}
});
}
And this is the console output.
Access to XMLHttpRequest at 'https://.s3.amazonaws.com/testing.png' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I wasn't exactly sure what happened, but I deleted the bucket and created an identical one (as far as I am concerned) and I am getting a different error message, saying
The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'ap-southeast-2'
Hence I have to include region in my s3 instantiation.
const s3 = new AWS.S3({
accessKeyId: "access key id",
secretAccessKey: "secret access key",
region: "bucket region" // <-------------- was missing
});
Now I can put object on my bucket as intended, I will try to recreate the error and see what was the difference between my first and second bucket.

Jeresy CORS filter working but React rest GET failing still with header ‘access-control-allow-origin’ is not allowed

I create a rest react front end to talk to a Jersey servlet on tomcat on the back end for RH 8.6. When react tried to do on REST GET or POST commands I got the "‘access-control-allow-origin’ is not allowed according to header" error. So I then added the CORS filter which was suppose to fix the origin problem, but the react client is still failing. I have tried different filters but there is no change. I assume the problem is in the react GET fetch but it looks ok with me and gets a header back when mode: 'no-cors' is set. In the debugger the CORSFilter class gets the GET, but it does not reach the resource class endpoint so its getting rejected.
Using postman I have verified the CORSFilter is inserting the values in the response as you can see here.
POST http://localhost:8080/rtc-servlet/mcd/location
Headers from postman tool:
Status Code: 200
access-control-allow-credentials: true
access-control-allow-headers: X-Requested-With, CSRF-Token, X-Requested-By, Authorization, Content-Type
access-control-allow-methods: API, GET, POST, PUT, DELETE, OPTIONS, HEAD
access-control-allow-origin: *
access-control-max-age: 151200
connection: keep-alive
content-length: 701
content-type: application/json
date: Sat, 10 Dec 2022 02:52:19 GMT
keep-alive: timeout=20
servlet code:
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
// *(allow from all servers) OR https://crunchify.com/
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
// As part of the response to a request, which HTTP headers can be used during the actual request.
responseContext.getHeaders().add("Access-Control-Allow-Headers",
"X-Requested-With, CSRF-Token, X-Requested-By, Authorization, Content-Type");
Also tried these options:
"Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
responseContext.getHeaders().add("Access-Control-Allow-Methods",
"API, GET, POST, PUT, DELETE, OPTIONS, HEAD");
// How long the results of a request can be cached in a result cache.
responseContext.getHeaders().add("Access-Control-Max-Age", "151200");
}
}
#GET // read in updated/original files
#Produces(MediaType.APPLICATION_JSON) // what format we send back
public JsonObject getLocationValues() {
System.out.println("Called location getLocationValues ");
return locationRepository.readConfigFile(false);
}
React Rest GET fetch:
const urll1 = "http://localhost:8080/rtc-servlet/mcd/location";
useEffect(() => {
const fetchPost = async () => {
await fetch(urll1, {
// mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
"Accept": "application/json",
"Access-Control-Allow-Origin": "*",
},
})
.then((response) => {
if (response.ok) {
response.json().then(data => {
console.log("response fetchPost :" + JSON.stringify(data));
setPosts1(data);
});
} else {
console.log("response was not ok");
}
})
.catch((err) => {
console.log(err.message);
});
};
fetchPost();
}, []);
The console error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rtc-servlet/mcd/location. (Reason: header ‘access-control-allow-origin’ is not allowed according to header ‘Access-Control-Allow-Headers’ from CORS preflight response).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rtc-servlet/mcd/location. (Reason: CORS request did not succeed). Status code: (null).
NetworkError when attempting to fetch resource.
So does anyone see that I am doing wrong?
After read the CORS not working posts in stackoverflow again I came across a commit about getting the origin from the header and then setting Access-Control-Allow-Origin to it vs. "*" and react on port localhost:3000 started to get responses back from the localhost:8080 servlet (origin is being set to "localhost:3000"). This was the forum string if you want to read up on it:
How to enable Cross domain requests on JAX-RS web services?.
So the change in the filter class is as follows:
String origin = requestContext.getHeaderString("origin");
if ((origin != null) && (!origin.isEmpty())) {
headers.add("Access-Control-Allow-Origin", origin);
} else {
// *(allow from all servers) OR https://crunchify.com/
headers.add("Access-Control-Allow-Origin", "*");
}
headers.add("Access-Control-Allow-Credentials", "true");
and in the js script "Access-Control-Allow-Origin": "*" was deleted:
await fetch(urll1, {
headers: {
'Content-Type': 'application/json',
"Accept": "application/json"
},
})
I am not sure if I now need the else since "*" didn't work for me, but I left it in. If its not needed or I am just doing something that sort of works because I am using firefox please let me know.

403 when upload file to S3 bucket using axios

I'm using axios to upload an audio file to AWS s3 bucket.
The workflow is: React => AWS API Gateway => Lambda.
Here is the backend Lambda code where generates the S3 presigned URL:
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(AUDIO_S3_BUCKET)
.key(objectKey)
.contentType("audio/mpeg")
.build();
PutObjectPresignRequest putObjectPresignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(10))
.putObjectRequest(putObjectRequest)
.build();
PresignedPutObjectRequest presignedPutObjectRequest = s3Presigner.presignPutObject(putObjectPresignRequest);
AwsProxyResponse awsProxyResponse = new AwsProxyResponse();
awsProxyResponse.setStatusCode(HttpStatus.SC_OK);
awsProxyResponse.setBody(
GetS3PresignedUrlResponse.builder()
.s3PresignedUrl(presignedPutObjectRequest.url().toString())
.build().toString());
return awsProxyResponse;
Here is the java code to create the bucket:
private void setBucketCorsSettings(#NonNull final String bucketName) {
s3Client.putBucketCors(PutBucketCorsRequest.builder()
.bucket(bucketName)
.corsConfiguration(CORSConfiguration.builder()
.corsRules(CORSRule.builder()
.allowedHeaders("*")
.allowedMethods("GET", "PUT", "POST")
.allowedOrigins("*") // TODO: Replace with domain name
.exposeHeaders("ETag")
.maxAgeSeconds(3600)
.build())
.build())
.build());
log.info("Set bucket CORS settings successfully for bucketName={}.", bucketName);
}
In my frontend, here is the part that try to upload file:
const uploadFile = (s3PresignedUrl: string, file: File) => {
let formData = new FormData();
formData.append("file", file);
formData.append('Content-Type', file.type);
const config = {
headers: {
"Content-Type": 'multipart/form-data; boundary=---daba-boundary---'
//"Content-Type": file.type,
},
onUploadProgress: (progressEvent: { loaded: any; total: any; }) => {
const { loaded, total } = progressEvent;
let percent = Math.floor((loaded * 100) / total);
if (percent < 100) {
setUploadPercentage(percent);
}
},
cancelToken: new axios.CancelToken(
cancel => (cancelFileUpload.current = cancel)
)
};
axios(
{
method: 'post',
url: s3PresignedUrl,
data: formData,
headers: {
"Content-Type": 'multipart/form-data; boundary=---daba-boundary---'
}
}
)
.then(res => {
console.log(res);
setUploadPercentage(100);
setTimeout(() => {
setUploadPercentage(0);
}, 1000);
})
.catch(err => {
console.log(err);
if (axios.isCancel(err)) {
alert(err.message);
}
setUploadPercentage(0);
});
};
However, when try to upload the file, it return 403 error.
And if I use fetch instead of axios instead and it works, like this:
export async function putToS3(presignedUrl: string, fileObject: any) {
const requestOptions = {
method: "PUT",
headers: {
"Content-Type": fileObject.type,
},
body: fileObject,
};
//console.log(presignedUrl);
const response = await fetch(presignedUrl, requestOptions);
//console.log(response);
return await response;
}
putToS3(getPresignedUrlResponse['s3PresignedUrl'], values.selectdFile).then(
(putToS3Response) => {
console.log(putToS3Response);
Toast("Success!!", "File has been uploaded.", "success");
}
);
It seems to me that the only difference between these two is that: when using fetch the request's Content-Type header is Content-Type: audio/mpeg, but when using axios it is Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryClLJS3r5Xetv3rN7 .
How can I make it work with axios? I'm switching to axios for its ability to monitor request progress as I want to show an upload progress bar.
I followed this blog and not sure what I missed: https://bobbyhadz.com/blog/aws-s3-presigned-url-react
You are using POST in your axios. Should be PUT instead.
Also I think the content type has to match the one specified during requesting the pre-signed URL, which is audio/mpeg as you rightly pointed out.
Correspondingly, your data should be just file, instead of formData.
axios(
{
method: 'put',
url: s3PresignedUrl,
data: file,
headers: {
"Content-Type": 'audio/mpeg'
}
}
...
You didn't mark any answers as accepted so I guess you didn't solve it.
For any future viewers out there. The reason why you are getting 403 forbidden error is because your Content-Type in your server and client side are not matching. I'm assuming you set up the AWS policies correctly.
Your code in the backend should look like this:
const presignedPUTURL = s3.getSignedUrl("putObject", {
Bucket: "bucket-name",
Key: String(Date.now()),
Expires: 100,
ContentType: "image/png", // important
});
and in the front-end (assuming you are using axios):
const file = e.target.files[0]
const result = await axios.put(url, file, {
withCredentials: true,
headers: { "Content-Type": "image/png" },
});
In practical, you would normally have to send the file type to generate the pre-signed url in the POST body or whatever and then in axios you do file.type to get the file type of the uploaded file.
Check your Lambda execution role. It may be the culprit. Perhaps it does not grant enough permissions to allow PUTting files into your bucket.
URL signing is a delegation of power on behalf of the signer, which is restricted to a specified object, action... Signing does not magically grants full read/write permissions on S3, even on the specific object related to the presigned URL.
The "user" who generates the signature requires sufficient permissions to allow the actions you want to delegate through that presigned URL. In this case, this is the execution role of your Lambda function.
You can add the AmazonS3FullAccess managed policy to the execution role and see if it solves your situation. This change took me out of a blocked situation me after days of struggle. Afterwards, before going to production, restrict that rule to the specific bucket you want to allow uploads into (least privilege principle).
If you develop using SAM local emulation, those execution roles seem not to be taken into account as long as you run your functions locally; the signed links work in that context even without S3 permissions.

firebase auth rest api not returning the full body response in arduino ide

i've been stuck in a problem with firebase auth rest api in arduino ide, the following code returns code 200
String url = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + String(apiKey);
http.setTimeout(5000);
http.begin(url);
http.addHeader("Content-Type", "application/json");
String dataSent = "{\"email\":\"" + String(email) + "\",\"password\":\"" + String(pswd) + "\",\"returSecureToken\":\"true\"}";
int status = http.POST(dataSent);
Serial.println(status);
if (status <= 0)
{
Serial.printf("HTTP error: %s\n",
http.errorToString(status).c_str());
return false;
}
// Read the response.
String payload = http.getString();
Serial.println(payload);
but when i look in my serial monitor the response looks like this:
{
kind: "the kind of response",
localId: "someId",
email: "myEmail",
displayName: "myDisplayName",
idToken: "someIdToken",
registered: "someBoolean",
}
witch aparently is ok but when i try the same http request in postman the response includes also refreshToken and expiresIn
with even more investigation i found that localId from postman is about 980 characters while the localId from my arduino code is only about 680
im trying (and failing) to use the localId to authenticate a request with the firestore api and i think this difference in lenght is what's been buggingme.
could that really be the problem ?
method: "POST",
body: JSON.stringify({
email: enteredEmail,
password: enteredPassword,
returnSecureToken: true,
}),
headers: {
"Content-Type": "application/json",
},
})
NB: Make sure {returnSecureToken: true} is part of your request body

CORS policy: Request header field tron-pro-api-key is not allowed by Access-Control-Allow-Headers in preflight response

I have a problem with trongrid. I dont know what to do. On trongrid i create API and put it in index.js
What config should i have on api settings on trongrid?
Console
Access to XMLHttpRequest at 'https://api.shasta.trongrid.io/wallet/getnodeinfo' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field tron-pro-api-key is not allowed by Access-Control-Allow-Headers in preflight response.
Here is my index.js
const TRONGRID_SHASTA_API = 'https://api.shasta.trongrid.io';
const HttpProvider = TronWeb.providers.HttpProvider;
const fullNode = new HttpProvider(TRONGRID_SHASTA_API);
const solidityNode = new HttpProvider(TRONGRID_SHASTA_API);
const eventServer = new HttpProvider(TRONGRID_SHASTA_API);
const privateKey = "c4f27f7b0523507**********************ecddfb21c891";
const tronWeb = new TronWeb(fullNode, solidityNode, eventServer, privateKey);
tronWeb.setHeader({'Content-Type': 'application/json',
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Origin': '*',
'TRON-PRO-API-KEY': '6ad9cb75-****-4f4c-a9cf-2156aa5e8453'});
async function triggercontract(){
console.log("trx:", tronWeb.trx);
console.log(tronWeb.transactionBuilder);
console.log(tronWeb.utils);
let instance = await tronWeb.contract().at("TNS*******tST9zAqXXssho5hgZ");
let res = await instance.f().call();
let res1 = await instance.g().call();
console.log("res", res);
console.log("res1", res1);
}
UPD 1:
I understand that: I have simple react-app, when i start it it up on localhost:3000 and it makes requests to api.shasta.trongrid.io/..... making post requests but api.shasta.trongrid.io dont give access to this localhost cause i dont have cors but how to set it cors correctly to work it project?
UPD 2:
Why my browser simply get info from this link, but react-app not? What should i do?

Resources