Am I using Cloud wrong?

Discussion and help for Easy Save 3
Post Reply
krolldk
Posts: 25
Joined: Sun Jun 02, 2019 11:15 am

Am I using Cloud wrong?

Post by krolldk »

Hi

My usecase: I want to upload a string to cloud, and download it again. My app is crossplatform web as well as PC, so I do NOT want to sync a local file, since on webGL, I have no local file access.

My code:

Code: Select all


    public IEnumerator doTest()
    {

        cloud = new ES3Cloud(url, apiKey);
        var myFile = new ES3File("MyFile.es3");
        myFile.Save<string>("teststring", "testcontent");
        yield return StartCoroutine(cloud.UploadFile(myFile));
        if (cloud.isError)
        {
            Debug.LogError(cloud.error);
        }

        myFile.Save<string>("teststring", "testcontent2");
        print("uploaded ");
        yield return StartCoroutine(cloud.DownloadFile(myFile));
        if (cloud.isError)
        {
            Debug.LogError(cloud.error);
        }

        string contentafterCloud = myFile.Load<string>("teststring");
        print("after download " + contentafterCloud);
    }
This fails with an error:
NullReferenceException: Object reference not set to an instance of an object
ES3.LoadRawBytes (.ES3Settings settings) (at Assets/Plugins/Easy Save 3/Scripts/ES3.cs:389)
ES3Cloud.UploadFile (System.Byte[] bytes, .ES3Settings settings, System.String user, System.String password) (at Assets/Plugins/Easy Save 3/Scripts/Web/ES3Cloud.cs:252)
ES3Cloud.UploadFile (.ES3File es3File) (at Assets/Plugins/Easy Save 3/Scripts/Web/ES3Cloud.cs:221)
CloudTest+<doTest>c__Iterator0.MoveNext () (at Assets/_Scripts/Cloud/CloudTest.cs:43)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at C:/buildslave/unity/build/Runtime/Export/Scripting/Coroutines.cs:17)
UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
CloudTest:Test() (at Assets/_Scripts/Cloud/CloudTest.cs:34)
UnityEngine.EventSystems.EventSystem:Update()

I suspect I'm doing something wrong. Am I trying to create a local filesystem file ?
krolldk
Posts: 25
Joined: Sun Jun 02, 2019 11:15 am

Re: Am I using Cloud wrong?

Post by krolldk »

On a related note

Could you please make just a simple code example solving the following:

I have a string in memory.
I put that string in a named value in a named cloudfile.
I upload the file to cloud, creating it if the files doesn't exist already on cloud.
I download the file from cloud
I retreive the string to memory.

During the process, I NEVER access local filesystem (because I want it to run on WebGL)
krolldk
Posts: 25
Joined: Sun Jun 02, 2019 11:15 am

Re: Am I using Cloud wrong?

Post by krolldk »

Followup

I added a myFile.Sync() line to the above. This created a local file (as expected) and now the upload/download works fine.

However: I want myFile to just exist in memory and on the cloud. How do I do that ?
krolldk
Posts: 25
Joined: Sun Jun 02, 2019 11:15 am

Re: Am I using Cloud wrong?

Post by krolldk »

OK .. this is getting problematic

As far as I can see, when I upload a file, the username field on the server is filled with garbage, if a username is supplied, and different garbage if a username AND password is supplied.

yield return StartCoroutine(cloud.UploadFile(myFile,"user1"));
yield return StartCoroutine(cloud.UploadFile(myFile,"user1","pass1"));
Both of the above lines create a file in the cloud DB, with two different garbled strings for username.

I'm hazarding a guess here, that the garbled string is a hash of username and password, where the password is set to empty string or something in the first line of code. This is a problem:
If it IS a hash, as I suspect, and you store the hash next to all files owned by user X, then what happens when user X changes password ? He will loose access to all his files, because they will have the hash of his username and old password next to them

Suggestion:
Do NOT store hash of username and pass next to each file. Store only the username. Ignore security completely, and just focus on loading and saving.
krolldk
Posts: 25
Joined: Sun Jun 02, 2019 11:15 am

Re: Am I using Cloud wrong?

Post by krolldk »

Further followup:

In order to try and make the memory only file solution work, I changed settings to "Memory".
Now, even with the myFile.Sync() call, the Upload fails with a nullref.

At this stage, I am sorely tempted to cut my losses, and go with another solution for cloud save. I am dissapointed at the poor API documentation, the lack of code examples and the general buggyness of esp. the cloud solution.
User avatar
Joel
Moodkie Staff
Posts: 4826
Joined: Wed Nov 07, 2012 10:32 pm

Re: Am I using Cloud wrong?

Post by Joel »

Hi there,

Sorry to hear you're encountering difficulties. Your original way of working should work, and I've not seen this error occur here before. Would it be possible for you to PM a project which replicates this?

With regards to the username and password, these are used for integration with login systems and are both entirely optional. The password field is often used to store a unique token from the login system which is persistent and independent of the login system's password, so it is unaffected by the login system's password being changed. Some login systems would also leave this blank.

Also if you have any suggestions on where I could improve the documentation and make things clearer, I'd really appreciate your feedback.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
krolldk
Posts: 25
Joined: Sun Jun 02, 2019 11:15 am

Re: Am I using Cloud wrong?

Post by krolldk »

Sorry to hear you're encountering difficulties. Your original way of working should work, and I've not seen this error occur here before. Would it be possible for you to PM a project which replicates this?
I'll see about making a minimal repro project for you.
With regards to the username and password, these are used for integration with login systems and are both entirely optional. The password field is often used to store a unique token from the login system which is persistent and independent of the login system's password, so it is unaffected by the login system's password being changed. Some login systems would also leave this blank.
I will have several users on my system. I need the functionality of looking up a users files, based on user name. as I said, I suggest that when I save a file using e.g. :
yield return StartCoroutine(cloud.UploadFile(myFile,"user1"));
this should save the string "user1" in the "username" field of the database.
as it is now,
yield return StartCoroutine(cloud.UploadFile(myFile,"user1"));
saves a garbled string in the username field, and
yield return StartCoroutine(cloud.UploadFile(myFile,"user1","pass1"));
saves a *different* garbled string in the username field.

Thus, I suspect that the string saved in the username field of the database is maybe a hash of username and password in both cases, but in case 1 (with no password supplied) it is a hash of user1 and empty string ?

I can work around it, by consistently using
yield return StartCoroutine(cloud.UploadFile(myFile,"user1")); (so, without supplying a password) but my DB will contain unreadable usernames, which isn't desired for me.
Also if you have any suggestions on where I could improve the documentation and make things clearer, I'd really appreciate your feedback.
Like I wrote a couple of messages above, I'd like a walkthrough as follows:

I have a string in memory.
I put that string in a named value in a named cloudfile.
I upload the file to cloud, creating it if the files doesn't exist already on cloud.
I download the file from cloud
I retreive the string to memory.
During the process, I NEVER access local filesystem (because I want it to run on WebGL)
User avatar
Joel
Moodkie Staff
Posts: 4826
Joined: Wed Nov 07, 2012 10:32 pm

Re: Am I using Cloud wrong?

Post by Joel »

Hi there,

I've created an example for you here: https://moodkie.com/forum/viewtopic.php ... 5989#p5989

Also this is currently undocumented as this is the first time anyone has requested this, but you can stop the username from being hashed by going to your projects Player setting, scroll down to the Scripting Define Symbols field and add DISABLE_HASHING to the end.

Note that if there's already scripting define symbols in there, you will need to separate them with semi-colons. I.e.

Code: Select all

OTHER_DEFINE_SYMBOL;ANOTHER_SYMBOL;DISABLE_HASHING
With regards to the error you were encountering, there doesn't appear to be anything in the PM you sent me. I've sent you a response with my email address.

All the best,
Joel
Joel @ Moodkie Interactive
Purchase Easy Save | Contact | Guides | Docs | Getting started
krolldk
Posts: 25
Joined: Sun Jun 02, 2019 11:15 am

Re: Am I using Cloud wrong?

Post by krolldk »

Great with the define statement. That adds a nice option.

If I were you, I'd also warn the developers about the hashing thing. I mean, I think I know why you're doing it: hashing username and password makes sense, so you don't send cleartext usernames and esp. passwords over the internet, BUT:

If devs aren't careful, they will run into the situation where they do stuff like:
yield return StartCoroutine(cloud.UploadFile(myFile,username,password));
and
yield return StartCoroutine(cloud.DownloadFilenames(username, password));
as per your code example here: https://docs.moodkie.com/easy-save-3/es ... filenames/

this will save the file on cloud with a hash of username/password on the server. This works fine, until someone changes their password. When that happens, all the files of the user are still stored with the hash of the OLD password, meaning that downloadfilenames will return NO files owned by the user, and NO WAY for the developer to fix it.

This would be catastrophic for many usecases, and many devs will not realise this, until it is too late to fix.

The fix for developers is to use UploadFile with no password or a constant password for all users. Then, ofcourse, user password changes won't matter, but on the other hand, the hashed value will be significantly easier to hack. Another fix is, when the user changes password, to go through all the users files and change the "username" field in DB to the new hash, which seems... idk... not great.

My thinking is, that your current technical design provides a huge shotgun pointed at the developers feet, if they upload with password, and allow players to change passwords, OR you provide security through obscurity if the developer doesn't use password on file uploads. Either situation is not desirable.

Personally, I'll be fine: I'll use fileupload with username provided and a constant password. Maybe I'll hash, maybe not, but probably not, since I prefer to be able to see the usernames in the DB, and then must provide security some other way.
Post Reply