junobuild / juno

Build Web3 at Lightning Speed
https://juno.build
Other
193 stars 13 forks source link

Unable to upload a document to a managed storage collection from a NodeJS context #666

Closed ByronBecker closed 4 months ago

ByronBecker commented 4 months ago

I'm currently unable to upload a document to a managed storage collection from a NodeJS context when making the call as an Ed25519 generated identity.

I'm receiving this error:

Error: Call was rejected:
  Request ID: 69dbeae68ea9385db4f60a1398118adcd532f59dd868e400bfc840abf9b52026
  Reject code: 5
  Reject text: Error from Canister njz5m-nyaaa-aaaal-ajola-cai: Canister called `ic0.trap` with message: Caller not allowed to upload data..
Consider gracefully handling failures from this canister or altering the canister to handle exceptions. See documentation: http://internetcomputer.org/docs/current/references/execution-errors#trapped-explicitly

My understanding according to the documentation is that both the owner of an asset (identity making the call) and the controllers of the satellite can make the call to the collection

Here are the settings on my Juno collection, I have read set to public, and write set to managed.

Screenshot 2024-07-20 at 16 37 24

And here's a reproduction of the issue as I currently see it (requires creating a collection on your own satellite first) https://github.com/ByronBecker/managed-upload-reproduction

Note that when I set the write permissions on the collection to public, this script works just fine.

peterpeterparker commented 4 months ago

Thanks for the detailed question and code snippet.

Anonymous identity are not allowed to upload data if the permission are not set to public.

Your collection's "Write permission" are set to "Managed".

If you wish to upload assets from a NodeJS context with such type of permission, you can create a controller with write (Read+Write) permission for example.

ByronBecker commented 4 months ago

Anonymous identity are not allowed to upload data if the permission are not set to public.

I'm creating an identity with Ed25519KeyIdentity.generate() and passing that in with my call to uploadBlob().

https://github.com/ByronBecker/managed-upload-reproduction/blob/60e688d6f8487dba73d1335fc1481f56f73d107e/index.mjs#L30C7-L30C47

This call should be made as the identity I created then, right (and not the anonymous identity)?

peterpeterparker commented 4 months ago

I'm creating an identity with Ed25519KeyIdentity.generate()

Right the identity is not anonymous but, its an unknown user - i.e. it's just an identity which hasn't been registered as a user in the authentication of the satellite. I should improve the documentation about the subject.

The most correct way, given that your a writing a batch that runs in a NodeJS script, is probably to create a controller with write permission as I said ealier.

Another option is to create a user entry in the authentication as it would have signed in. For example:

await setDocs({
   collection: "#user",
    doc: {
      key: identity.getPrincipal().toText(),
      data: {
        provider: 'internet_identity'
      },
    },
    satellite,
});
ByronBecker commented 4 months ago

Another option is to create a user entry in the authentication as it would have signed in.

I updated the example with a branch outlining this approach. Here's my new attempt. https://github.com/ByronBecker/managed-upload-reproduction/blob/with-mock-auth/index.mjs

I'm hitting a different error now during the call to uploadBlob()

Steps performed in the example are:

  1. Create an Ed25519KeyIdentity
  2. Use the created identity it in a call to set the user doc in the #user collection, pretending that it's an II created identity. ✅ this is successful, I can see the user in the list of users in my Authentication tab in the Juno console.
  3. Call the uploadBlob() endpoint with the same created identity. ❌ this fails with the following error:
Error: Call was rejected:
  Request ID: 160897e4f98e4b93b424c499b4266815f513d4aab01ae4bbde2af25edc2c7582
  Reject code: 5
  Reject text: Error from Canister <canister_id>: Canister called `ic0.trap` with message: Cannot commit batch..
Consider gracefully handling failures from this canister or altering the canister to handle exceptions. See documentation: http://internetcomputer.org/docs/current/references/execution-errors#trapped-explicitly
...
ByronBecker commented 4 months ago

I tried this example with both @junobuild/core and @junobuild/core-peer installed and got a different response from the user setDoc() call (more data returned with the response), but I received the same error message as above when calling uploadBlob().

ByronBecker commented 4 months ago

Ah, I found what the issue was.

I was trying to write to the same doc as was created by someone else. I think that it was returning an error since I wasn't the creator/last person to update the doc, right?

I modified the filename key string to be ${identity.getPrincipal().toText()}/asset.png and it works now.

Maybe a different error message would be helpful, but everything works now! Thanks for answering my questions.

peterpeterparker commented 4 months ago

Really glad to hear it worked out! 🥳

Error messages are purposely left relatively generic to avoid providing too many hints to potential attackers.

However, if you notice areas that can be better documented and integrated within the website, your input is certainly welcome!

peterpeterparker commented 4 months ago

Likewise, given that it required few iterations we should probably enhance the sample as well! Thanks a ton for iterating!