How to update corsRules for Backblaze b2 Cloud Storage using CLI or how to bypass blocking by CORS policy?

177 Views Asked by At

I am making a website that users can upload and download pictures (posts and profile pictures), The cloud storage I use is Backblaze b2 cloud storage, REACT for frontend, NODE & Express for backend.

Backblaze

This simple explanation of what I coded: React client send get request to express server, then get the B2 authorizationToken & uploadUrl back, then start uploading the picture or pictures from the frontend (look at the code below)

const url = res.dt.uploadUrl;
const authToken = res.dt.authorizationToken ;
const hash = CryptoJS.SHA1(CryptoJS.enc.Latin1.parse(myPicture));

const body = {
  myPicture
};

const headers = {
  Authorization: authToken,
  "X-Bz-File-Name": res.dt.picName,
  "Content-Length": optimisedImage.size,
  "X-Bz-Content-Sha1": hash,
  "X-Bz-Info-Author": "unknown",
  'Access-Control-Allow-Credentials': true
};

const uploadPicRes = await axios.post(url, body, headers);

so when I run the code from a github pages website it gives me this error:

Access to XMLHttpRequest at '<backblaze uploadUrl>' from origin '<my github-pages origin>' 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 have been trying to solve this issue for days now, I downloaded b2 CLI and authorize my account then tried to update the corsRules but it gives me this error: b2 update-bucket: error: argument --corsRules: invalid validated_loads value: "'[{corsRuleName:"

I also changed my b2 bucket CORS Rules.

I am really stuck and have no way to change to another Cloud Storage right now.

1

There are 1 best solutions below

0
On

You can't use the web UI to set a CORS rule to allow POSTs to upload files - you need to set a custom rule using the CLI or API. It looks like you had an error in your JSON when you tried to set one.

I followed https://www.backblaze.com/docs/cloud-storage-enable-cors-with-the-cli to create a file with a custom CORS rule, changing the rule to contain the headers you want to use. You don't need to include Content-Length as the browser doesn't include it in the preflight CORS request.

[
  {
    "corsRuleName": "uploadFromAnyOrigin",
    "allowedOrigins": [
      "https"
    ],
    "allowedHeaders": [
      "Authorization",
      "X-Bz-File-Name",
      "X-Bz-Content-Sha1",
      "X-Bz-Info-Author"
    ],
    "allowedOperations": [
      "b2_upload_file"
    ],
    "exposeHeaders": [
      "x-bz-content-sha1"
    ],
    "maxAgeSeconds": 3600
  }
]

I then used the B2 CLI to update my bucket with the rule:

b2 update-bucket --corsRules "$(<./rules.json)" Metadaddy-Tester allPrivate

I used curl to simulate the OPTIONS preflight request from the browser to check that it worked:

% curl -H "Origin: https://example.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Authorization, X-Bz-File-Name, X-Bz-Content-Sha1, X-Bz-Info-Author" \
  -X OPTIONS --verbose \
  https://pod-040-2000-00.backblaze.com/b2api/v2/b2_upload_file/71d55f5943b52c7f74ed0c1b/c004_v0402000_t0055
*   Trying 149.137.129.57:443...
* Connected to pod-040-2000-00.backblaze.com (149.137.129.57) port 443
* ALPN: curl offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES128-GCM-SHA256
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: CN=backblaze.com
*  start date: Feb  8 21:14:41 2024 GMT
*  expire date: May  8 21:14:40 2024 GMT
*  subjectAltName: host "pod-040-2000-00.backblaze.com" matched cert's "*.backblaze.com"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* using HTTP/1.x
> OPTIONS /b2api/v2/b2_upload_file/71d55f5943b52c7f74ed0c1b/c004_v0402000_t0055 HTTP/1.1
> Host: pod-040-2000-00.backblaze.com
> User-Agent: curl/8.4.0
> Accept: */*
> Origin: https://example.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: Authorization, X-Bz-File-Name, X-Bz-Content-Sha1, X-Bz-Info-Author
> 
< HTTP/1.1 200 
< Cache-Control: max-age=0, no-cache, no-store
< access-control-allow-origin: https://example.com
< access-control-allow-credentials: true
< vary: origin, access-control-request-method, access-control-request-headers
< access-control-max-age: 3600
< access-control-allow-methods: POST
< access-control-allow-headers: Authorization, X-Bz-File-Name, X-Bz-Content-Sha1, X-Bz-Info-Author
< Content-Type: application/json;charset=UTF-8
< Content-Length: 3
< Date: Thu, 15 Feb 2024 00:34:21 GMT
< 
{}
* Connection #0 to host pod-040-2000-00.backblaze.com left intact

Success!

To allow downloads as well as uploads, you can add another rule to rules.json. For example,

[
  {
    "corsRuleName": "uploadFromAnyOrigin",
    "allowedOrigins": [
      "https"
    ],
    "allowedHeaders": [
      "Authorization",
      "X-Bz-File-Name",
      "X-Bz-Content-Sha1",
      "X-Bz-Info-Author"
    ],
    "allowedOperations": [
      "b2_upload_file"
    ],
    "exposeHeaders": [
      "x-bz-content-sha1"
    ],
    "maxAgeSeconds": 3600
  },{
    "corsRuleName": "downloadFromAnyOrigin",
    "allowedOrigins": [
      "https"
    ],
    "allowedHeaders": [
      "range"
    ],
    "allowedOperations": [
      "b2_download_file_by_id",
      "b2_download_file_by_name"
    ],
    "exposeHeaders": [
      "x-bz-content-sha1"
    ],
    "maxAgeSeconds": 3600
  }
]