Ren'Py Ren'py's Ver 7.6.x / 8.1.x - Frustrating Sync and Tokens Security - Save Features - Are driving me buggy!

Twistty

The Happy Beaver
Respected User
Donor
Former Staff
Sep 9, 2016
4,138
37,766
Not really enjoying the new "features".

I noticed Ren'py ver 8.+.+ added a "sync" folder.
For example - C:\Users\Twistty\AppData\Roaming\RenPy\MidnightParadise_Sandbox\sync

I still have all my regular saves in C:\Users\Twistty\AppData\Roaming\RenPy\MidnightParadise_Sandbox root folder - but the bloody "sync" folder DOUBLES them - so our save AppData\Roaming\RenPy folder will become friggin huge over time!
Un1titled.jpg Untitled.jpg
How do I stop it from creating that?

Also....
That applies to the C:\Users\Twistty\AppData\Roaming\RenPy\tokens - which is a nice security feature - but totally killed my enjoyment of many games - as "save" editing is necessary sometimes.

Tried the security_keys.txt hack where you delete the 2 security keys and save it as read only - but that broke the persistent data of my games.
Only editing the savetoken.py within each individual game seems to work.
By changing this:
Python:
def verify_data(data, signatures, check_verifying=True):
    """
    Verifies that `data` has been signed by the keys in `signatures`.
    """

    for i in signatures.splitlines():
        kind, key, sig = decode_line(i)

        if kind == "signature":

            if key is None:
                continue

            if check_verifying and key not in verifying_keys:
                continue

            try:
                vk = ecdsa.VerifyingKey.from_der(key)
                if vk.verify(sig, data):
                    return True
            except Exception:
                continue

    return False
To this:
Python:
def verify_data(data, signatures, check_verifying=True):
    """
    Verifies that `data` has been signed by the keys in `signatures`.
    """

    for i in signatures.splitlines():
        kind, key, sig = decode_line(i)

        if kind == "signature":

            if key is None:
                continue

            if check_verifying and key not in verifying_keys:
                continue

            try:
                vk = ecdsa.VerifyingKey.from_der(key)
                if vk.verify(sig, data):
                    return True
            except Exception:
                continue

    return True
Any help, info or insights - would be appreciated.
 
  • Like
Reactions: rKnight

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
4,940
7,261
$config.has_sync = False should disable it, but I couldn't find much documentation about it for some reason.
Whereas for tokens, the changelog specifies that it was purposely made so that it cannot be disabled.
 
  • Yay, new update!
Reactions: Twistty

Twistty

The Happy Beaver
Respected User
Donor
Former Staff
Sep 9, 2016
4,138
37,766
Thanks Winterfire (y)

"config.has_sync"
Yes I found that using dnGrep in - ....\renpy\common\00sync
Thanks

" Whereas for tokens, the changelog specifies that it was purposely made so that it cannot be disabled."
Crap :poop:

Maybe someone really smart and helpful can create a .bat similar to unren to fix the new features.

Going to be a pain is the ass remembering to change for the new games and updates going forward.

Edit - ....\renpy\common\00sync
Changing
You don't have permission to view the spoiler content. Log in or register now.
To
You don't have permission to view the spoiler content. Log in or register now.
Doesn't seem to work???
 
Last edited:
  • Hey there
Reactions: rKnight

Winterfire

Forum Fanatic
Respected User
Game Developer
Sep 27, 2018
4,940
7,261
Do that within your game like the other config settings, it should work then
 
  • Yay, new update!
Reactions: Twistty

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,132
14,815
[...] but totally killed my enjoyment of many games - as "save" editing is necessary sometimes.
Hmm, why not using the console ?

Of course, you need to know the name of the variable(s) to change, and the embedded variable viewer is relatively limited and austere. But I heard that someone ( :whistle: ) made a better version, way more beautiful and that permit to track the values when they are changing, what make it easier to know what variable is for what, even when their name are cryptic.
 
  • Red Heart
Reactions: Twistty

Twistty

The Happy Beaver
Respected User
Donor
Former Staff
Sep 9, 2016
4,138
37,766
anne O'nymous
Yes 0x52's Universal Ren'Py Mod and your Extended Variable Viewer are absolutely wonderful tools!!!
I have promoted them in the past and continue to do do so... (If that is the mods you eluded to?).
And you are also correct - that console commands are the golden standard - when it comes to modifying variables.

But I was looking for a simple and true method, (or methods) - to reverse the specific changes in the newer versions of Ren'py that they consider features - that I do not want. Regardless of the security and sync-ability that they may provide.
 
Last edited:
  • Yay, new update!
Reactions: rKnight

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,132
14,815
But I was looking for a simple and true method, (or methods) - to reverse the specific changes in the newer versions of Ren'py that they consider features - that I do not want. Regardless of the security and sync-ability that they may provide.
Like Winterfire said, the save check can't be reverted.

There's an external tool somewhere, but even I find it really dirty, so I'll not promote it even if I was remembering where it is.

I'm in fact really conflicted about this. I know a way, less dirty and easier to use, but I'm not sure that I want to share it, and even less make it public.
Ren'Py's saves can really be dangerous and seriously compromise your computer. It need advanced knowledge, and it's a small target, but also an easy target and finding it isn't difficult. Come here, share a save in whatever popular game thread (WVM by example), and you'll infect the computers of the few thousands who are too lazy to play the game, and never noticed that they already have a copy of their own save in their computer even if they deleted the game. Therefore an ideal target that will surely not notice it if something goes wrong. And in top of that your anti-virus would see nothing.
Plus, if it can, in one year or two, remove the "save please" from at least Ren'Py game threads, it would be a good side effect. And unlike the games themselves, that would be checked by few members if something feel wrong, no one would be able to check those saves, and therefore to warn about the threat.

If it was the only way to "cheat", I would probably hesitate less, but there's better way, and they are safer, so...
 
  • Like
Reactions: Twistty

Twistty

The Happy Beaver
Respected User
Donor
Former Staff
Sep 9, 2016
4,138
37,766
Thanks for the full explanation anne O'nymous (y)
on GitHub did a good job explaining the issue last December here:
And the linked video - is scary.
DKCQXBKAk5-10.jpg
Killer Python Pickles are dangerous!

But I will keep looking - as I do not use "others" saves (or share mine).
That said - I do often - USB transfer my personal save files from one of my own computers to another - and enjoy the functionality of .

However; I figure that there must be a "better" way than what (or the way) it was implemented in the newer versions of Ren'py.
What? I do not know?
A Bloated - AppData\Roaming\RenPy save folder is not ideal (as most if not all Dev's seem to have sync enabled by default)?
That, and my issues posted above - plus the knowledge of what the dangers are (and mainly how they are spread) - keep me pressing onwards.

It is (like I said) - driving me buggy - lol

Would be happy to have any info shared via PM (if you so choose)!?

Thanks again!!!
 
Last edited:
  • Hey there
Reactions: rKnight

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,132
14,815
However; I figure that there must be a "better" way than what (or the way) it was implemented in the newer versions of Ren'py.
Alas there isn't really one.

Look at it that way:
An anti-virus do not give you a 100% protection. It can only protect you against what it know about. Of course, nowadays anti-virus, coupled to nowadays CPU, permit to look at the behavior of the code, and detect unknown malwares. But it stay limited to the known behavior, and to the known files.
When the first JEPG virus (a virus using a photo to exploit a vulnerability in the code displaying it), all anti-virus were taken by surprise, because none ever thought that images should be scanned.

And the same would apply for Ren'Py save control.
Of course, PyTom and the community can test each field of the save file, and check if it's safe content or not. But it would protect you only against the currently known attacks, and only to the limits of their coding capability.
And like Ren'Py isn't an anti-virus, you can't update it remotely, if there's a hole in the, let's say version 8.2.7, all games using this version will be vulnerable, without possibility to fix the hole.

So, the way it's done is radical, I agree with this, but it's the only possible way.
"You thought it was safe, and then told me to still load the save file, but I detect something really weird, I prefer to protect you".


A Bloated - AppData\Roaming\RenPy save folder is not ideal (as most if not all Dev's seem to have sync enabled by default)?
This is stupidity, and it's more PyTom wanting to boost his ego by seeing big numbers, than anything else.
Use the config value that Winterfire gave, add it in your "console enabler" file or something like this, to disable the sync by default.


Would be happy to have any info shared via PM (if you so choose)!?
It would mean that I validate my idea, because I know how it should be done, but never really tried. And I'm not sure that I trust myself enough to effectively know without doubt how to do it ;)
 
  • Hey there
Reactions: Twistty

FaceCrap

Active Member
Oct 1, 2020
855
596
Was wondering the same thing as Twistty, and I tried the variable given by Winterfire, but without much success. In fact without any success.

I also read all the objections raised by anne O'nymous, and although the warning for potential malicious save files is a valid one, I fail to see what it has to do with a bloat forming feature, nor what it has to do with an added sync folder.
It's not like that sync folder is going to protect dimwits from downloading and using a malicious save file. From what I saw in the code that handles loading saves, it will compare file times across the various locations and just load the newest one. If that happens to be the malicious one, the user is still hosed.
Plus, in all my time here in the forum, I've not yet read anyone posting they got bitten this way.

Took me a fair bit to find but here's the skinny.

Despite it being a variable that has a connection with this feature, putting renpy.config.has_sync = False in whatever file you use to override config variables is not going to do shit.
Whatever it gets set to is a result of Ren'Py's ability to find a savedir to begin with. So when changing it to something else you're already too late.

Second, you need to use an init value higher than what RenPy uses to make sure your override is the one that sticks but I'll come to that later.

Third, there's another variable that actually is responsible for the folder to be created which is renpy.config.extra_savedirs

renpy/config.py contains the initial definition extra_savedirs = []
renpy/common/00sync.py is where this one gets assigned the location to the sync subfolder based on a test if there is a config.savedir (which there obviously is unless you somehow managed to prevent saving all together)
so, if that location exists this results in
Code:
   if config.savedir is not None:
       config.extra_savedirs.append(config.savedir + "/sync")
   else:
       config.has_sync = None
And as you can see, instead of False it has to be None.
which then allows renpy/savelocation.py to do
Code:
for i in renpy.config.extra_savedirs:
       location.add(FileLocation(i))
The final straw is that the test on the existence of config.savedir is done in an init 1100 python: block
so to override it, you need to use a value higher than 1100, and instead of setting config.has_sync to None, you need to prevent extra_savedirs getting appended with the sync folder location.

Now, this is where I am not 100% sure but only 99.99% (at least on a Windows platform), but just adding this
Code:
init 9999 python:
    renpy.config.extra_savedirs = []
    renpy.config.has_sync = None
In some file you always copy into the game folder, will at least on a Windows system, prevent the sync folder.
Despite what I said about changing has_sync being too late, I still added the last line for good measure, just in case.

I am not sure if the same works on *Nix, Mac and/or Android, and I'm also not in a position to test this since I don't have or use any of those platforms.
 
Last edited:
  • Hey there
Reactions: Twistty

Twistty

The Happy Beaver
Respected User
Donor
Former Staff
Sep 9, 2016
4,138
37,766
Was wondering the same thing as Twistty, and I tried the variable given by Winterfire, but without much success. In fact without any success.
I tried it many ways also - none ever seemed to work?
Gave up - and just deleted the folder manually!
Now, this is where I am not 100% sure but only 99.99% (at least on a Windows platform), but just adding this
Code:
init 9999 python:
    renpy.config.extra_savedirs = []
    renpy.config.has_sync = None
In some file you always copy into the game folder, will at least on a Windows system, prevent the sync folder.
Despite what I said about changing has_sync being too late, I still added the last line for good measure, just in case.

I am not sure if the same works on *Nix, Mac and/or Android, and I'm also not in a position to test this since I don't have or use any of those platforms.
Where do you add that code - config.rpy for example?

Thanks
 

FaceCrap

Active Member
Oct 1, 2020
855
596
Where do you add that code - config.rpy for example?
I have a separate rpy file in which I override some config variables.
Like enable developer mode, console, force enable skip_unseen, force enable rollback and assigning quickSave/quickLoad to F5/F9 function keys.
And now this bit.

I just always copy that file into the ./game folder so I never actually change any file included with the game
 
Last edited:
  • Like
Reactions: Twistty

FaceCrap

Active Member
Oct 1, 2020
855
596
This is what it currently has as content.
Code:
init 9999 python:
    renpy.config.developer = True
    renpy.config.console = True
    renpy.config.has_sync = None
    renpy.config.extra_savedirs = []

    _preferences.skip_unseen = True
    renpy.game.preferences.skip_unseen = True
    renpy.config.allow_skipping = True
    renpy.config.fast_skipping = True

    #  Divide_By_Zero 
    renpy.config.rollback_enabled = True
    renpy.config.hard_rollback_limit = 256
    renpy.config.rollback_length = 256

    def unren_noblock( *args, **kwargs ):
        return

    renpy.block_rollback = unren_noblock

    try:
        config.keymap['rollback'] = [ 'K_PAGEUP', 'repeat_K_PAGEUP', 'K_AC_BACK', 'mousedown_4' ]
        # Allows interruption of Hard Pause... USE '*' key on KEYPAD (NUMPAD)... (NOT 'SHIFT' + '8')
        config.keymap['dismiss_hard_pause'].append('K_KP_MULTIPLY')
    except:
        pass

    try:
        config.underlay[0].keymap['quickSave'] = QuickSave()
        config.keymap['quickSave'] = 'K_F5'
        config.underlay[0].keymap['quickLoad'] = QuickLoad()
        config.keymap['quickLoad'] = 'K_F9'
    except:
        pass
 
  • Red Heart
Reactions: gold and Twistty

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,132
14,815
I also read all the objections raised by anne O'nymous, and although the warning for potential malicious save files is a valid one, I fail to see what it has to do with a bloat forming feature, nor what it has to do with an added sync folder.
Could it be because the thread is about two different issues, and I'm addressing the other one ?


From what I saw in the code that handles loading saves, it will compare file times across the various locations and just load the newest one. If that happens to be the malicious one, the user is still hosed.
Well, take a better look, and do it with the 7.6.x/8.1.x branches, where the security token have been added.


Plus, in all my time here in the forum, I've not yet read anyone posting they got bitten this way.
In all my life, I'm 52yo, I only have been in one car crash, when I was 7 months old ; lucky me, my parents were ahead of their time. It never prevented me to buckle my safety belt, just in case it will happen again.
 

FaceCrap

Active Member
Oct 1, 2020
855
596
Could it be because the thread is about two different issues, and I'm addressing the other one ?
You are right of course, I seem to have overlooked that, as I was concentrating on the .has_sync option

Well, take a better look, and do it with the 7.6.x/8.1.x branches, where the security token have been added.
I will for sure, but since your main objection was against mocking with the security key, I feel more confident that my solution won't interfere.


In all my life, I'm 52yo, I only have been in one car crash, when I was 7 months old ; lucky me, my parents were ahead of their time. It never prevented me to buckle my safety belt, just in case it will happen again.
I don't know if I can say "lucky me" but I've had my fill of accidents in my life (66yo nearing 67). A few of them I was lucky to escape fatality, so I get your point.

Also, I should add this as a heads-up. I noticed that if you re-enable the creation of the sync folder, existing saves don't get duplicated again. Only the persistent file and saves made after re-enabling the creation of the sync folder.
I haven't come across a game yet that supports Upload Sync and Download Sync, but if a game suddenly starts to support this in a future update, you will likely need to manually copy any already existing saves into the sync folder yourself.
 
Last edited:
  • Like
Reactions: Twistty

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,132
14,815
I don't know if I can say "lucky me" but I've had my fill of accidents in my life (66yo nearing 67). A few of them I was lucky to escape fatality, so I get your point.
In my case it was really luck. At this time a baby was just put in a cradle, itself placed on the back seat. Everyone mocked my parents who brought a baby seat and was strapping me inside. Since the car rolled over three times... Do I really need to say what would have happened to me without this ?


I haven't come across a game yet that supports Upload Sync and Download Sync, but if a game suddenly starts to support this in a future update, you will likely need to manually copy any already existing saves into the sync folder yourself.
No need for this. Or, more precisely, it's the opposite that should be done.

I finally had both the time to look closely at the sync process and the idea to do it, thanks to this thread, and things are way more messed than it looks.

config.has_sync effectively works, but it regard the online synchronization, not the local "sync" folder. Reason why setting it at True do not prevent it to be used. The upload is performed in the same way that when you load a save file from the game ; it don't care where the file is located, it will use the most recent one. Therefore, the files do not need to be in the "sync" folder to be saved online.

What lead to an obvious question: What the fuck is this "sync" folder for in this case ?
Well, it's used to save the files downloaded from the online synchronization server. What is relatively ridiculous since this could perfectly be done directly in the %APPDATA% or equivalent folder.
And like the folder need to be parts of the save location for the save files to be loadable, it become also used every time a save is done.
Therefore, strictly speaking, it's after having synchronized back your save files that you would have to copy the files, from the "sync" folder to its father.

There's a whole logic flaw in the whole process:
renpy/common/00sync.rpy
Python:
    def download():
        [...]
                data = zf.read(fn)

                fn = config.savedir + "/sync/" + fn
                nfn = fn + ".new"

                if os.path.exists(nfn):
                    os.unlink(nfn)

                with open(nfn, "wb") as f:
                    f.write(data)

                os.utime(nfn, (timestamp, timestamp))

                if os.path.exists(fn):
                    os.unlink(fn)

                os.rename(nfn, fn)
Would the download be transparent, I would understand the need for a secondary folder ; "oh fuck, I downloaded my online saves, I lost all my current progress".
But before you can download those files, you are asked for the sync ID used for the upload. I don't see someone searching for that ID (because who will remember it ?) then writing it in Ren'Py, without realizing that it's absolutely not what he wanted to do.
 

FaceCrap

Active Member
Oct 1, 2020
855
596
But before you can download those files, you are asked for the sync ID used for the upload. I don't see someone searching for that ID (because who will remember it ?) then writing it in Ren'Py, without realizing that it's absolutely not what he wanted to do.
Well, the files only stay available for 1day, so if a player wants to transfer saves from one device to another, they better make damn sure they made a note of the ID at upload.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,132
14,815
Well, the files only stay available for 1day, [...]
On the official server operated by PyTom. But the address of the host is stored in config.sync_server therefore, despite the path being hardcoded, it's perfectly possible to operate your own server, either as player or as creator.
 

ArunPrime

Member
Nov 5, 2022
214
217
Hi Guys
Is there any way or options to disable the signature and security keys permanently from creating.