Solved Update category picture (via image upload) API not working

  • Global Moderator Plugin & Theme Dev

    I'm pretty sure this same API is used when you upload an image through the UI.

    @julian can you take a look?

  • NodeBB

    Did you try logging the value of req.files here.

  • @baris Not yet, but I'm going to now.

  • @baris adding log output produces zero additional data, I just see the error:

    2021-10-22T22:58:44.720Z [4567/19620] - error: /api/admin/category/uploadpicture
    Error: [[error:invalid-files]]
        at validateFiles (/opt/nodebb/src/middleware/index.js:112:15)
        at Layer.handle [as handle_request] (/opt/nodebb/node_modules/express/lib/router/layer.js:95:5)
        at next (/opt/nodebb/node_modules/express/lib/router/route.js:137:13)
        at Form.<anonymous> (/opt/nodebb/node_modules/connect-multiparty/index.js:114:7)
        at Form.emit (events.js:326:22)
        at /opt/nodebb/node_modules/multiparty/index.js:610:12
        at processTicksAndRejections (internal/process/task_queues.js:79:11)

    I work with API's of all flavors for my job. This sincerely looks like "files" does not exist in the API. Is it possible that this function was just not enabled, or otherwise overlooked? Server error 500's usually means bad code. I'm just not familiar enough with NodeBB to debug this myself.

  • NodeBB

    This seems to work for me on windows.

    $ curl -H "Authorization: Bearer ...." -XPOST -F cid=2 -F "files[][email protected]:\ideas.png"

    I got a forbidden error due to missing csrf token but the file was visible on the server logs.

      files: [
          fieldName: 'files[]',
          originalFilename: 'ideas.png',
          path: 'C:\\Users\\Baris\\AppData\\Local\\Temp\\BnugKrdsfzdSP4rlETtcLt9t.png',
          headers: [Object],
          size: 59289,
          name: 'ideas.png',
          type: 'image/png'

    Did you try using "files[][email protected]:\ideas.png" ?

  • @baris We did not try that way, we tried files[0]=

    Now I'm getting 403 Forbidden, with invalid csrf token in the logs.

    2021-10-22T23:54:52.993Z [4567/19620] - error: /api/admin/category/uploadpicture
    invalid csrf token

    How do I get around the invalid token?

  • Here is the verbose output from my macbook:

    Note: Unnecessary use of -X or --request, POST is already inferred.
    *   Trying
    * TCP_NODELAY set
    * Connected to ( port 4567 (#0)
    > POST /api/admin/category/uploadpicture HTTP/1.1
    > Host:
    > User-Agent: curl/7.64.1
    > Accept: */*
    > Authorization: Bearer e3642513-175a-4650-ae39-622505ce32ba
    > Content-Length: 7450
    > Content-Type: multipart/form-data; boundary=------------------------23a77408539631fe
    > Expect: 100-continue
    < HTTP/1.1 100 Continue
    * We are completely uploaded and fine
    < HTTP/1.1 403 Forbidden
    < X-DNS-Prefetch-Control: off
    < Expect-CT: max-age=0
    < X-Frame-Options: SAMEORIGIN
    < X-Download-Options: noopen
    < X-Content-Type-Options: nosniff
    < X-Permitted-Cross-Domain-Policies: none
    < X-XSS-Protection: 0
    < Referrer-Policy: strict-origin-when-cross-origin
    < X-Powered-By: NodeBB
    < Content-Security-Policy: frame-ancestors 'self'
    < Set-Cookie: _csrf=KEEYRk8-aMRzJbUywg3dSE5C; Path=/
    < Set-Cookie: express.sid=s%3AAZCyzQs6kMVtHBfIxhfjHyTNarERnXAx.IXyYI8wP1w3cJjJkcreNjgGJTVJGP6UoI0FXRTJQZso; Path=/; Expires=Sat, 06 Nov 2021 00:09:16 GMT; HttpOnly; SameSite=Lax
    < Content-Type: text/plain; charset=utf-8
    < Content-Length: 9
    < ETag: W/"9-PatfYBLj4Um1qTm5zrukoLhNyPU"
    < Date: Sat, 23 Oct 2021 00:09:16 GMT
    < Connection: keep-alive
    < Keep-Alive: timeout=5
    * Connection #0 to host left intact
    Forbidden* Closing connection 0

    I see the message "We are completely uploaded and fine" in the above. But ultimately am getting the invalid token error over and over.

  • NodeBB

    I think you have to first load a regular route and get a csrf token and then use that in your POST call. I am not sure how to do that in curl. Our tests do it using request and then storing the cookies then we use it to make POST requests.

  • NodeBB

    This worked for me give it a try

    # get csrf token and save cookies
    curl -c cookies.txt -s | grep csrf
    #this will print something like
    "csrf_token": "bHqyDEde-Y_zLYuitkD4uc5Cd7-0mYF1m5GU",

    Copy the value of the csrf_token and make the upload also use cookies.txt with -b cookies.txt

    curl -H "Authorization: Bearer da21bf5f-6924-4e5d-9a82-92191e6f2240" -XPOST \
      -F params="{\"cid\":\"2\"}" \
      -F "files[][email protected]:\ideas.png" \
      -F "_csrf=bHqyDEde-Y_zLYuitkD4uc5Cd7-0mYF1m5GU"  \
      -b cookies.txt \

    Should get this output

            "name": "ideas.png",
            "url": "/assets/uploads/category/category-2.png"

  • @baris we are definitely close. That process works, I do get the success output, but the image doesn't appear as the category image. It just stays the default background color.

  • NodeBB

    That could be due to cache, did you try clearing the object cache at /admin/advanced/cache?

  • @baris thanks, just tried that and it didn't work. Is there a 3rd step to actually placing the image?

  • NodeBB

    Ahh yes you need to set the backgroundImage property of category:2 to the value of "url": "/assets/uploads/category/category-2.png"

  • @baris Thank-you, found it, it is a PUT on the write API. First go, I got the syntax mostly correct, I got a 200 OK message, but the Response:backgroundImage key was empty.

    I will poke at this more after dinner, but I think we can call this one solved, since it is just a matter of figuring out the right syntax at this point.

  • @baris Using the below site, reminding me of just how powerful Chrome Developers tools are, I was able to Copy As Curl the specific PUT command.

    Curl Convert

    Then using the same command and just changing the CID, I confirmed the same command works for all of them.

    This is what ended up working, it includes all the recorded headers, of which some will be removed as not necessary:

    curl '' \
      -X 'PUT' \
      -H 'Connection: keep-alive' \
      -H 'Accept: */*' \
      -H 'DNT: 1' \
      -H 'x-csrf-token: H5FMJEaY-CthHWM_2Unzf7DtoPeryGq_JejE' \
      -H 'X-Requested-With: XMLHttpRequest' \
      -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' \
      -H 'Content-Type: application/json; charset=UTF-8' \
      -H 'Origin:' \
      -H 'Referer:' \
      -H 'Accept-Language: en-US,en;q=0.9,zh;q=0.8,zh-CN;q=0.7,zh-TW;q=0.6,ja;q=0.5,ko;q=0.4,th;q=0.3' \
      -H 'Cookie: _csrf=27ygKMdG0c0EyiVsJKAkKpId; express.sid=s%3AdODaXfUpLz7NTFsijWLq0d2rPUhH1Ki4.qkyxWOaxlBy%2BLDRpTYbhWS9QkD9IJE%2FRTN1vIhp7yV4' \
      -H 'sec-gpc: 1' \
      --data '{"backgroundImage":"/assets/uploads/category/category-84.jpg"}' \
      --compressed \

    Then using the cURL convert site, was able to save as javascript and modify to our needs so that we could loop through all categories.


  • Topic has been marked as solved  J jpop71 

Suggested Topics

| |