MisterWil / abodepy

A thin Python wrapper for the Abode alarm API
MIT License
49 stars 17 forks source link

Cache Corruption #43

Closed MisterWil closed 4 years ago

MisterWil commented 5 years ago

Seems that there exists an edge case where if the cache exists but is corrupted in some way (failure to write due to disk full or incorrect permissions), logins will fail to work.

Possible solutions are perhaps to verify the integrity of the data. If the username and password are given then confirm that these values match the cached values?

See this stack overflow for how to append a checksum to the end of a pickle file to verify integrity: https://stackoverflow.com/questions/1653897/if-pickling-was-interrupted-will-unpickling-necessarily-always-fail-python

shred86 commented 4 years ago

This seems like it would be easy to implement but one issue I'm seeing is the fact the cache template also contains a UUID in addition to the ID and PASSWORD. So if I'm understanding this right, you would have to confirm the hash of ID, PASSWORD and UUID match, but since UUID is uniquely generated, I don't think that would work?

Perhaps another solution: https://stackoverflow.com/questions/33938173/verifying-file-integrity-with-python

MisterWil commented 4 years ago

Good point, however I do wonder if instead of appending a checksum to the pickle file if we just verify the username/password match what is in the cache and if not delete and regenerate the cache file. This might solve the issue too, since I think the issue was just the cache file being unreadable or only partially written.

shred86 commented 4 years ago

Noticed this post in the stack overflow link you posted:

Contra the other answers offered, I believe that we can make a strong argument about the recoverability of a pickle. That answer is: "Yes, an incomplete pickle always leads to an exception."

Why are we able to do this? Because the "pickle" format is in fact a small stack-based language. In a stack-based language you write code that pushes item after item on a stack, then invoke an operator that does something with the data you've accumulated. And it just so happens that a pickle has to end with the command ".", which says: "take the item now at the bottom of the stack and return it as the value of this pickle." If your pickle is chopped off early, it will not end with this command, and you will get an EOF error.

If that's true, then it seems like we should just be able to call pickle.load within a try: statement then catch the exceptions UnpicklingErrorand EOFError.