Search Unity

Anti-Cheat Toolkit: stop cheaters easily!

Discussion in 'Assets and Asset Store' started by codestage, Aug 20, 2013.

  1. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Sure, it's safe to stay on 1.4.1.1 if it works fine for you and you don't need any new features.
     
  2. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Hi there - I'm getting an issue with the editor GUI drawing UI for Obscured floats/doubles:

    The properties triggering the issue are in classes that implement ISerializable so maybe that's related ... the issue started last night after working fine for weeks. Restarting Unity hasn't helped.
     
  3. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey,

    Thanks for your report!

    Are you using latest ACTk version?
    And could you please send me reproducible case within unitypackage?

    Thanks!
     
  4. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Hey, yes I'm using the latest version. So, I tried to create a reproduce project and ... didn't get the error. Then in my original project I tried deleting the gameobject that was having issues rendering from the scene hierarchy and re-adding it and ... error went away.

    At a guess this seems to be an issue with how Unity is saving/serializing hierarchy objects with obscured types in them.
     
    Last edited: Feb 3, 2016
  5. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Thanks for your efforts and additional info!
    Feel free to let me know if it will occur again.
     
  6. Cybertiger

    Cybertiger

    Joined:
    Dec 19, 2013
    Posts:
    35
    Hello,

    I am having troubles figuring out the following code:
    ObscuredFloat.Decrypt();

    I am confused why it wants a INT as parameter? Could you give an example please how to decrypt a ObscuredFloat type?
    Many thanks in advance
     
  7. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Cybertiger !

    That's because ObscuredFloats are encrypted into the integer value under the hood.
    Similar, ObscuredDouble is stored as long under the hood.

    I'm not sure what's your final target, but if you wish to decrypt some existing obscured float instance - just assign it to the usual float type variable, like:

    float cleanValue = someObscuredFloatInstance;

    Or, just cast to to the float:

    (float)someObscuredFloatInstance
     
  8. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Next question: I was hoping to use .Get/SetEncrypted() on an ObscuredString to store an encrypted version of my game save in a cookie (because of an unrelated issue with unity webplayer and playerprefs getting wiped because of the way itch.io versions game uploads ... it's a long story).

    It looks like GetEncrypted() is truncating heavily, this is logging the original JSON serialized game save vs. what GetEncrypted returns:

    {"CurrentSpeciesID":1,"OriginatingSite":"SITE_SCARYBEE_WEBSITE","EnergyLimit":100,"Energy":100.0,"Creatures":[{"Seed":1084294478,"XP":4608.3121097683907,"Level":16,"Role":1,"Sex":1,"Age":0.0,"Generation":1,"Stats":[{"CurrentStat":40,"BaseStat":10,"StatType":1},{"CurrentStat":40,"BaseStat":10,"StatType":3},{"CurrentStat":40,"BaseStat":10,"StatType":4},{"CurrentStat":40,"BaseStat":10,"StatType":2}],"Name":"Burt"},{"Seed":489965641,"XP":4608.3121097683907,"Level":16,"Role":1,"Sex":2,"Age":0.0,"Generation":1,"Stats":[{"CurrentStat":40,"BaseStat":10,"StatType":1},{"CurrentStat":40,"BaseStat":10,"StatType":3},{"CurrentStat":40,"BaseStat":10,"StatType":4},{"CurrentStat":40,"BaseStat":10,"StatType":2}],"Name":"Elba"},{"Seed":1735056510,"XP":4561.4873327706009,"Level":16,"Role":0,"Sex":1,"Age":0.0,"Generation":2,"Stats":[{"CurrentStat":40,"BaseStat":10,"StatType":1},{"CurrentStat":23,"BaseStat":8,"StatType":3},{"CurrentStat":41,"BaseStat":11,"StatType":4},{"CurrentStat":41,"BaseStat":11,"StatType":2}],"Name":"Gene"},{"Seed":1031216915,"XP":4517.6733277682215,"Level":16,"Role":0,"Sex":2,"Age":0.0,"Generation":2,"Stats":[{"CurrentStat":23,"BaseStat":8,"StatType":1},{"CurrentStat":41,"BaseStat":11,"StatType":3},{"CurrentStat":40,"BaseStat":10,"StatType":4},{"CurrentStat":23,"BaseStat":8,"StatType":2}],"Name":"Ling"},{"Seed":737947693,"XP":4487.65798576735,"Level":16,"Role":0,"Sex":1,"Age":0.0,"Generation":2,"Stats":[{"CurrentStat":23,"BaseStat":8,"StatType":1},{"CurrentStat":24,"BaseStat":9,"StatType":3},{"CurrentStat":41,"BaseStat":11,"StatType":4},{"CurrentStat":40,"BaseStat":10,"StatType":2}],"Name":"Tuan"}],"GameSaveVersion":"0.5.3.1","AwesomeBiscuits":1000.0,"DerpySlurps":0.0,"AwesomeProductionLimit":1,"PopulationLimit":5,"CheeseProductionLimit":1,"CandyProductionLimit":1,"CandyReserve":0.0,"CheeseReserve":0.0,"LastKnownServerTime":"\/Date(1454979656428)\/","ResearchPopulationLimit":1,"SoldierPopulationLimit":1}

    GetEncrypted():

    OwDFFQ_@gDTW]QB}p~F]SXZU@XZSgX@Qg}eqkgrufmsqqkfqvgx`qqZTFSM}]Y]EtZQFVM

    Am I just misusing this method or is there a bug here? This is using Unity 5.3.2 and ACT 1.5.0.6. Thanks!
     
  9. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Aurigan !

    Did you tried to check the length of the string returned from the GetEncrypted()?
    It returns "raw" encrypted string, which often has unprintable chars, line endings, etc.
    If you wish to get string valid for the WEB, you may apply Base64 to what you get from the GetEncrypted().

    Please, let me know if it helps or not.
     
  10. Aurigan

    Aurigan

    Joined:
    Jun 30, 2013
    Posts:
    291
    Hey :) Yes that helps! For posterity this works:

    Code (CSharp):
    1. //save
    2. ObscuredString savegame = "whatever";
    3. string encrypted = s.GetEncrypted();
    4. string base64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(encrypted));
    5.  
    6. //load
    7. string encrypted = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(base64));
    8. ObscuredString savegame = "";
    9. savegame.SetEncrypted(encrypted);
    Please let me know if that will break for some reason (curious about the encoding type!)
     
  11. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Yeah, it should work fine, and UTF8 should be fine too.
     
    Aurigan likes this.
  12. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    WIP update
    Just wish to let you guys know I've started work on the PrefsEditor with ObscuredPrefs support:



    Going to make it as simple as possible, just to let you deal with obscured prefs with some meaningful comfort, since there are lot of great prefs editors on the market already and I don't wish to spend a lot of time to reinvent a wheel.

    Maybe it will evolve into something neat and cool and maybe standalone in future, but for now I don't have such plans.
     
    pea, hopeful and mcmorry like this.
  13. mcmorry

    mcmorry

    Joined:
    Dec 2, 2012
    Posts:
    580
    Indeed would be useful to be able to see the obscured keys and values and to allow editing them. Other editors are pretty much useless when working with obscured player prefs.
    Looking forward for the update :)
     
  14. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Currently this editor allows to decrypt obscured prefs of standard types (string, int, float), edit them in decrypted state and encrypt them back.

    Trying to decide what to do with non-standard types in ObscuredPrefs (like byte[], Color, etc.) and how to expose them for editing...
     
  15. mcmorry

    mcmorry

    Joined:
    Dec 2, 2012
    Posts:
    580
    For colors a starting point could be to convert it to an hexadecimal string.
    For other formats is hard. It would require custom editors. For example a bin editor. Anyway would be not so easy to visually edit bin data. So is probably not needed. Maybe just to show the key and allow to delete it.
     
    codestage likes this.
  16. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Yeah, thought something similar, thanks for your feedback, @mcmorry !
     
    mcmorry likes this.
  17. zKici

    zKici

    Joined:
    Feb 12, 2014
    Posts:
    438
    Great news, I 2nd that ^
     
  18. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    With the famous and awesome ANTICHEAT TOOLKIT !

    Say I am only using one thing - the secure prefs.

    On the asset store reviews you mention "There are few possible ways to decrease binary size. I'd suggest to check the stripping options and remove any unused parts of plugin in first pass."

    Again say I am only using "secure prefs" from ACTK. what should I do exactly, can you explain step-by-step what you mean there Dmitriy! Thanks!

    Sorry if this has already been asked on here, it is a big forum.
     
  19. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey again, @Fattie!

    You may remove these items inside CodeStage/AntiCheatToolkit folder in such case:
    - whole Editor folder (note in future versions it will contain prefs editor window you might need)
    - whole Examples folder
    - whole Shaders folder
    - whole Scripts/Detectors folder
    - in Scripts/ObscuredVars everything except the ObscuredPrefs and ObscuredString classes
    - and in ObscuredString remove Detectors.ObscuredCheatingDetector* checks in 4 places and fakeValue field

    Please let me know if it works for you and leads to the build size decrease, I'm curious how much you'll save =)
     
  20. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    ObscuredPrefs editor WIP update:



    * edit both PlayerPrefs and Obscured prefs in Unity Editor
    * encrypt regular PlayerPrefs with configurable encryption key
    * decrypt ObscuredPrefs to the regular PlayerPrefs
    * search in prefs names
    * sort prefs by name, type, or encrypted state
    * smart prefs reading progress bar (won't show up if you're dealing with less than 1000 prefs)
    * shows 50 prefs per page allowing to work with huge collections
    * overwrite notice to prevent data loss
    * coloration of obscured prefs for easier navigation
    * copy prefs to clipboard
    * copy raw obscured prefs to clipboard

    Woot, stay tuned!
     
    mcmorry and elmar1028 like this.
  21. zKici

    zKici

    Joined:
    Feb 12, 2014
    Posts:
    438
    Amazing! Keep up the wonderful work.
     
  22. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Fantastic! Will report back in a couple days.
     
  23. appxplore-tech

    appxplore-tech

    Joined:
    Jul 4, 2012
    Posts:
    62
    Hi,

    Just a clarification on the Cryptography and U.S. Export Compliance when submitting games to Apple iOS.

    By using AntiCheatTool, do i need to apply the U.S. Export Compliance?

    Thank you.
     
  24. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @AppxploreF !

    Just use custom crypto keys with length of 7 chars/bytes or shorter to be able to claim an exemption. All default keys are 7 bytes or shorter.
     
    hopeful likes this.
  25. appxplore-tech

    appxplore-tech

    Joined:
    Jul 4, 2012
    Posts:
    62
  26. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Hi Dmitriy, so as above to use ONLY secure prefs....

    You may remove these items inside CodeStage/AntiCheatToolkit folder in such case:
    - whole Editor folder (note in future versions it will contain prefs editor window you might need)
    - whole Examples folder
    - whole Shaders folder
    - whole Scripts/Detectors folder
    - in Scripts/ObscuredVars
    [actually "ObscuredTypes" ] everything except the ObscuredPrefs and ObscuredString classes
    No problem, done

    - and in ObscuredString remove Detectors.ObscuredCheatingDetector* checks in 4 places and fakeValue field

    Right, as you say that brings up four missing `Detectors.ObscuredCheatingDetector`, I have removed them.

    FTR this brings up a warning on a trivial unused variable, I removed that variable.

    Q) Is it correct that the way to set preservePlayerPrefs true is exactly

    Code (CSharp):
    1. ObscuredPrefs.preservePlayerPrefs = true;
    To be clear, IT IS ABSOLUTELY ESSENTIAL THAT THE "ORDINARY" PlayerPrefs ARE TOTALLY UNTOUCHED AND THAT ANY EXISTING PlayerPrefs ARE COMPLETELY UNTOUCHED AND UNMODIFIED IN ANYWAY.

    It's great you include this facility. To be clear I should set that to

    TRUE

    correct?

    Q) Should I do that before or after calling ObscuredPrefs.SetNewCryptoKey("abc");

    Q) If I happen to call ObscuredPrefs.SetNewCryptoKey("abc"); more than once will it cause problems? Might it blank the preservePlayerPrefs setting?

    Which is more reliable - the goal is to absolutely NOT touch existing PlayerPrefs in anyway whatsoever.

    Thanks!
     
  27. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    BTW everything about ACTK looks fantastic!

    I was also wondering, when working on a Mac (for iOS/Android targets) where is the ObscuredPrefs data kept? I was trying to erase it all during testing. (If you are at liberty to tell us!) I believe it's not in the usual PlayerPrefs location, ~usr/Library/ApplicationSupport/CompanyName
     
  28. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Fattie !

    preservePlayerPrefs option allows you to save usual PlayerPrefs untouched in cases when you're trying to read them using ObscuredPrefs. Otherwise they will be automatically converted to the ObscuredPrefs (this is called automatic migration).

    Example:
    - you save some pref with PlayerPrefs.SetString("SomeKey", "SomeValue");
    - then you read it with ObscuredPrefs.GetString("SomeKey");
    - if you have preservePlayerPrefs set to false (default setting), ObscuredPrefs.GetString() will read your pref, return "SomeValue" as expected and automatically convert your original pref to the obscured one (so it becomes secure, but not anymore accessible via regular PlayerPrefs)
    - if you set preservePlayerPrefs to true, ObscuredPrefs.GetString("SomeKey") will read your pref too and will return "SomeValue", but it will not convert it to the ObscuredPrefs so it will remain unsecure and readable with PlayerPrefs

    The order is not important in this case.

    Just make sure you pass the same key every time you call it and you don't read\write obscured prefs before changing the key.
    Usually it's a good idea to call it once as your game starts, somewhere at the Awake phase.

    Nope

    preservePlayerPrefs = true; should do the trick for you in such case

    Please note though, calling ObscuredPrefs.DeleteAll() will delete both obscured and regular prefs.
     
  29. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Sorry forgot to answer your latest question:

    ObscuredPrefs are based on the PlayerPrefs, so location is the same, quote from the docs:
    "On Mac OS X PlayerPrefs are stored in ~/Library/Preferences folder, in a file named unity.[company name].[product name].plist, where company and product names are the names set up in Project Settings. The same .plist file is used for both Projects run in the Editor and standalone players."
     
  30. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    @Dmitriy Yukhanov , thanks for all the great info!

    "Please note though, calling ObscuredPrefs.DeleteAll() will delete BOTH obscured and regular prefs."

    That is critical information! Thanks.

    You know, regarding preservePlayerPrefs. I would have done it the other way: I would not delete anything unless the developer calls for it explicitly, if you see what I mean. Consider the case of a popular app already with many users, changing from no-prefs-security to ACTK security. The developers in that case would want to proceed with extreme caution, perhaps over a few versions. Anyway, "if it works it works" and there's no problem. You're probably right in that for 95% of developers it's best to "just do it". I think that in terms of DeleteAll deleting both prefs, would it be worth particularly emphasizing that in the doco. In some cases that could be a surprise: I'm glad I found it out here. I think there are some use cases where people would want to keep and use BOTH prefs.

    Anyway, ACTK is amazing - I love it!
     
  31. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Fattie

    Yeah, in most cases people wish to just switch from PlayerPrefs to ObscuredPrefs and don't bother with rest, but in some cases it's nice to have an option to keep PlayerPrefs for debugging reasons, etc. that's why preservePlayerPrefs exists.

    Regarding DeleteAll - it's clearly stated in docs it removes all prefs:
    http://codestage.ru/unity/anti-chea..._prefs.html#a679a567703ae81702f5c7be446dd2600

    Thanks for all your kind words and feedback!
     
  32. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Suggestion box: say Dmitriy, Unity now have their own IAP which is fantastic. Never again use any plugins for IAP for iOS or Android.

    When you do IAP you use receipt validation for security. Indeed, Unity have included some receipt validation (which is great).

    (There is a lot to know about this, such as obfuscation and payload passing.)

    You could possibly offer something in this field (maybe even as a second different product). So, it would help with receipt validation when using Unity's (excellent) new IAP.

    For example, this guy .. http://receigen.etiemble.com .. is the leader in the field in iOS receipt validation. It is a big and difficult field of enquiry. If you get a chance try out Unity's new IAP (which, again, is great - one of the best things they have done) and notice the "Tangle" feature for making a start on secure receipt validation. However plenty more needs to be done for each developer & app.

    Anyway just a thought, something to consider for the future! Cheers!
     
    codestage likes this.
  33. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Yeah, few customers already asked for this.
    IAP protection \ validation is a great, interesting and important topic, I definitely have interest on it, but can't say anything yet.
    There are more popular requests on the top of the todo now, but I'll check the IAP field in future, will see what may be done here.
    Thanks for all the related info!
     
  34. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Right on, we all look for the next step from ACTK - the best!

    Like I say Dmitriy .. be sure to investigate .. http://receigen.etiemble.com .. M. Etiemble is the leader! Great stuff.
     
  35. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Say @Dmitriy Yukhanov !

    I have an interesting use case where I save certain ID strings, as an ObscuredPrefs.

    In short, later it would be handy to know when the ObscuredPref was saved, the datestamp, or how old it is.

    Just curious if you ever came across this, maybe you've already had this come up! Cheers

    It's very useful for example with verifying transaction receipts in IAP. So, from time to time transaction IDs arrive.

    What you do is, simply, you want to check if that one has ever arrived before. (It's very easy for IAP cheaters to just "resend" a receipt package - the most common trick). If the id has already been seen you just ignore it as a cheat. If the id has never been seen, you pay out, and you make a note of it.

    To make a note of it, one can simply write it to ObscuredPref (value irrelevant say "1") ... and then simply use "HasKey" later to check if it has already arrived.

    {Note - of course this only applies strictly to consumable category IAP. Which you only ever pay out once no matter what. Regarding nonconsumables, it's perfectly normal that they are all restored every time you restart the app, say, or for example if the user happens to buy it again for a second time (the app store says "You already own it, no need to pay" and sends the receipt again).}

    That's all fantastic and works perfectly. You simply use ObscuredPrefs to save all the IDs as you go over the life of the app. The only slight downside is that they pile up .. what you want to do is delete old ones periodically. Or you want to keep only say "ten" in a stack and delete the old ones. You can see that perhaps knowing which ones are old would be handy. (Of course, you'd still have to know the overall list to know which ones to check.)

    Of course, there are other approaches. Certainly, one can just keep a text file (encrypted) with ten lines of text being the ten most recent consumable IDs.

    You can see that ultimately this would be a perfect new job for ACTK.

    You could have a pair of functions:

    Code (CSharp):
    1. SecureNoteStack( "someID", 8 );
    2. SecureNoteStackContains( "someID" );
    putting one on the stack would be putting it on a LIFO stack. The "8" would limit the count of the stack .. any on the end are discarded. So, pile-up attacks are eliminated.

    To check if a Note already exists, just the contains call. That would be terrific!

    Anything like this come to mind?

    (I'll probably just do it for now by adding them together to make a long string, and saving that as a securepref.)

    FOOTNOTE:

    Actually I did realize, Dmitriy, regarding this

    Code (CSharp):
    1. SecureNoteStack( "someID", 8 );
    2. SecureNoteStackContains( "someID" );
    it is indeed better if the developer, say me, simply writes their own class for that (after all it's like 3 lines of code), using ACTK to store the data string with ObscuredPrefs.

    Since ACTK is so important and generally security packages should be simple, it would be a bad idea for you to bother adding in such a feature. I should not have suggested it - sorry.

    But yes .. in course of time ACTK needs IAP stuff! Look for a post on it soon in the IAP thread, I already mention ACTK there. (It's absolutely impossible to have secure IAP unless you have secure prefs: you can't have IAP without ACTK.)
     
    Last edited: Mar 23, 2016
    codestage likes this.
  36. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Fattie

    I didn't reach IAP stuff yet, so I didn't thought about such stuff. And now I'll add link to your post to my TODO's section about IAP to read it as I'll reach it, thanks for the detailed ideas!

    P.S. it's definitively easy to add a timestamp to the ObscuredPrefs, increasing overall prefs size for few bytes, added this to the TODO as well, thanks!
     
  37. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Hi ! You know as I say above (pls read footnote I added), it was a bad idea of mine to add a function like a stack to ACTK (it is easily written in a few lines of code: developers would do that themselves for their custom needs, using ACTK underneath) - security systems need to stay simple and pure.

    Regarding the timestamp ... yes, I can see many security uses where that would be incredibly handy. But again there's a danger of making ACTK unnecessarily complicated. Security systems should be simple.

    Regarding IAP in general ... right, in time ACTK should be the king of IAP !!!!!!!!!!!! It is a very tricky field. I am just writing some receipt verification now and will post it.
     
  38. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Yeah, I always try to keep ACTk as simple as possible, yet flexible and powerful for the advanced developers who needs some extra stuff.

    Anyway, all your feedback may be handy in future, when I'll reach IAP stuff, so

    thanks again! =)
     
  39. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    IAP corner ... @Dmitriy Yukhanov , if you get a second I encourage you to look at this post of mine,

    http://forum.unity3d.com/threads/un...tore-windows-store.372647/page-3#post-2566639

    (and indeed the previous posts with the classes IapBase and Iap.)

    Looking at PurchaseSUCCESSFUL , it does the job of then verifying the receipt. Unity's new IAP does the first part of this job (checking the crypto) which is great.

    With Apple IAP, you then have to basically do this on your own:

    -- look through all the receipts (confusingly Apple always sends back "a big pile of" receipts instead of just the one, just one of those strange things)

    -- check if you're dealing with a consumable

    -- if so, basically check this is the first and only time you have checked this receipt.

    That's actually the fundamental mechanism for "spending something" (a consumable IAP) - the "fundamental idea" of programming IAP for apple is you get a receipt and you have to somehow cryptographically, using your own servers, using obfuscation -- whatever -- check that this is the first time you have seen it, and if so pay it out ("add gems" or whatever) if it is the first time.

    (Of course, you have to be cautious for the usual racetrack conditions, if you are anal what happens if the device crashes at that moment, etc etc.)

    Note that, indeed, the solution I use is to save the receipt ID using the ever-handy Anti-Cheat Toolkit.

    Hence, note the code ...

    Code (CSharp):
    1.         string supposedTID = productReceipt.transactionID;
    2.         Debug.Log("IAP    Here's the ID to check if fresh... " +supposedTID);
    3.  
    4.         // you must use anti-cheat toolkit or some similar security
    5.         // to locally save transactionID which have been "used up" already
    6.  
    7.         if ( CodeStage.AntiCheat.ObscuredTypes.ObscuredPrefs.HasKey(supposedTID) )
    8.           {
    9.           Debug.Log("IAP    Some joker tried to RE-USE a consumable receipt. Ignore it.");
    10.           // make a note in your analytics
    11.           continue; // keep checking all the receipts Apple sent in a batch
    12.           }
    13.         // be sure to save the TID since this is the first time we have seen it...
    14.         CodeStage.AntiCheat.ObscuredTypes.ObscuredPrefs.SetInt(supposedTID,1);
    15.         CodeStage.AntiCheat.ObscuredTypes.ObscuredPrefs.Save();
    16.  
    17.         // since this was NOT a re-use, go ahead and payout or whatever.....
    18.  
    Note that there are some conceptual problems with this, for example prefs could eventually fill up after some user buys many many receipts. There are no good solutions to some of these problems.

    Anyway you can see this is fertile ground for ACTK!! Cheers!
     
    codestage likes this.
  40. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hehe you're going to do all the job instead of me looks like! =D
    Thanks once again, your and that linked post go to the TODO's IAP section too, will make a deeper read as soon as I'll reach that phase!
     
  41. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey all!

    I'm glad to let you know new 1.5.1.0 version just went live in Asset Store!

    Most important part of this update - brand new ObscuredPrefs and PlayerPrefs editor!
    Tiny, simple and easy-to-use tool. Now you may easily debug all your prefs while working on your game in Unity Editor:



    Here is a full changelog for this update:

    1.5.1.0
    - added ObscuredPrefs Editor!
    * edit both PlayerPrefs and Obscured prefs in Unity Editor
    * encrypt regular PlayerPrefs with configurable encryption key
    * decrypt ObscuredPrefs to the regular PlayerPrefs
    * search in prefs names
    * sort prefs by name, type, or encrypted state
    * smart prefs reading progress bar
    * shows 50 prefs per page allowing to work with huge collections
    * overwrite notice to prevent data loss
    * coloration of obscured prefs for easier navigation
    * copy prefs to clipboard
    * copy raw obscured prefs to clipboard
    * works on Win, Mac, Linux​
    - ObscuredFloat/Double now may be assigned to ObscuredInt
    - changed the randomize crypto key logic for all obscured types
    - added support for the Unity 5.4 SceneManager.sceneLoaded delegate
    - more editor actions are undoable now
    - minor ObscuredPrefs API changes

    Stay tuned, lots of great stuff ahead!
     
    hopeful and mcmorry like this.
  42. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Hi Dmitriy, looks awesome!

    "changed the randomize crypto key logic for all obscured types"

    Can you confirm that when I do this ...

    there is NO change from 1.5.0 to 1.5.1. My "SetNewCryptoKey" in 1.5.1 will still work perfectly to read preferences set in 1.5.0 ? Thanks!
     
  43. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Fattie

    That change was made for the obscured types, not obscured prefs, so yeah, you're totally safe =)
     
  44. DshFox

    DshFox

    Joined:
    Oct 10, 2013
    Posts:
    15
    Hi Dmitriy
    the obscuredTypes is to be used in private class variables or it's only for the public ones? What about the local variables(garbage)? Thanks bro, love you s2
     
  45. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @DshFox

    ObscuredVars can be used in any context and scenario, but it's recommended to use them for the sensitive (for cheating) variables which stay in memory for a long period (many frames).

    So if you make some calculations in some function which runs and ends during 1 frame, there is no sense to use obscured vars inside.
     
    DshFox likes this.
  46. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    hi @Dmitriy Yukhanov !

    I have some simple text files (like 200 lines of text) which are called abc.txt.

    They are simply loaded as TextAsset

    In other words, in a monobehaviour I have public TextAsset info1 and I just drag that text asset to the Inspector slot.

    I then get the text simply using string theText = info1.text; and I use the text from there.

    Of course, any kid could look at those text files. It would be better if they were obscured.

    Is there a way I could I use ACTK in this case?
     
  47. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey, @Fattie !

    You may encrypt your text in editor code using ObscuredString.EncryptDecrypt, and decrypt it back after loading in runtime with same crypto key.
    Also I'd suggest to apply base64 over encrypted string or use it as a binary file.
     
  48. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    hi @Dmitriy Yukhanov that makes sense, thanks!

    Perhaps one day you could include a very simple addition to your code so that this happens in Editor:

    say I have a file parts.txt

    I can click on it and on the menu I get "ACTK -> encrypt". I click that

    it brings up "Enter key" and I type in say "1234Secret"

    ACTK then creates a new sibling file parts.etxt

    then on my own I can use the ".etxt" file as a text asset .. or indeed any way I want.

    it would be up to me to simply refresh that encrypted version if/when I wanted, use it as I want, etc.

    So, no big amount of automation is required on the part of ACTK to achieve this. plus it is very flexible; there could be other ways one would use this.

    Of course I would do this myself with 2 lines of editor script .. if I was any good at editor script :)
     
  49. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey again, @Fattie !

    Sure, this is a good suggestion, added it to my TODO, thanks!
     
  50. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    476
    Having many users is like having a big family, but they don't cook for you! :)
     
    codestage likes this.