Demo Period

I’m looking for a simple way to make a 30 day trial period for my software. I would like a few things to happen.

  1. During the demo period I would like a pop up that says how many days are left in the trial period.
  2. I would like a pop up after the trial period is done saying the trial is over.

My understanding is that the easiest way to do the trial period is by saving the date in the user preferences. I’m not familiar with how to do this so any help would be appreciated.

Also I have searched previous topics and the only ones I’ve found seem to be discussions on how to make a more complex trial period. I want to start out fairly basic.

While you certainly CAN save such info in the User Defaults (same as Preferences), those plist files are fairly easy to read, and if someone can figure out what information you’re storing, then they can defeat the trial period by monkeying with the date.

A better approach would be to save that information in your application bundle or in a non-standard place.

If you want help using the user defaults, check out the article in our archives on Polishing Your Application.

This topic is the discussion of many, many forum threads and email list discussions. Not necessarily here at macscripter, but certainly elsewhere. Ultimately, this is a “roll your own” subject, meaning that you have to tailor the methods you use to exactly what your own unique needs are. You need to clearly define what your trial period means. Do you want the app to irrevocably stop working after the period ends, or do you just want to pop up reminders? Do features get enabled/disabled based on registration? How far do you want to go to make sure you can’t just reinstall to reset the trial period? How do users register… via email, internet, other? There are many concerns, and once you start looking into it you may find yourself changing your approach to either your registration scheme, or to your entire app itself.

It’s not necessarily bad to store your reg info in user defaults, but what you need to accommodate is the likelihood that most users will try to scrap their prefs first to try to get around your registration. As Kevin said, another approach is to use a plist or file within the bundle to record user registrations. This, too, can be circumvented by simply uninstalling and reinstalling. The third method is to use an arbitrary location for recording a registration. Using this approach gets complicated, though. While your instinct would be to bury the file really deep in a filesystem hole somewhere, you need to be careful with trying to hide it too far away. Remember that some users don’t have the broad read/write authority you probably do. Consider using invisible files to store your data, and pick a home that all users will have installed on their machine and that each user will have write access to. A good approach will likely have a combination of multiple methods of authentication, all working together to give you whatever level of security you’re after.

Another very important matter is obfuscation… both in your code and in your files. Obviously, if you have a key like “RegistrationNumber” in your plist file, it’s a beacon for user tampering… and ultimately fraudulent use of your software. In fact, do put a “RegistrationNumber” key in your plist, but NEVER use it for anything related to your registration scheme. Write arbitrarily to it parallel to your actual registration tasks as a dummy key so people get frustrated trying to figure it out. :wink: If you’re going to write things to disk that the user can readily get at (which you should assume is EVERYTHING) then try to name things and store information in a way that the user is less likely to understand without significant investment of time. Name the key that stores your registration number something like “WindowFrame” or “lastOpenPanelFilePath”. Don’t store unaltered, plain text in your plist values. At least save them as data objects, or add encryption methods to your code so you can encrypt the text before writing it to file. The same rules generally should apply to any data you write to your other bundle/hidden files. In your bundle file, keep a list of all users that have launched the app, what their registration status is, and an encrypted record of their registration key if they have one. If you keep a hidden file somewhere else, just make a copy of the bundle file. That way you can compare the two files as another validation method, and you can compare their contents with the reg data that the user is trying to validate when they’re using your software. It’s wise, too, to always write SOMETHING to file. Even if the user hasn’t registered, still write a placeholder to file where their key would be stored. This makes it more difficult to simply look at a before/after version of your files to find where the reg info is stored. If used with good, creative encryption, you can make it extremely difficult for someone to crack your scheme.

As far as hiding things in your code goes, pretty much the same rules apply here too. Don’t make routines in your code named “DecryptPassword” or “validateRegistration”. Anyone who happens to get a hold of your code could easily find and possibly exploit your reg scheme. Use dummy names for this to make it much harder for people to pry into your code. Also, make sure that your code is being compiled before you distribute it. In applescript studio apps, when you build them as ‘release’ versions, they should be compiled as read-only. There are certain cases where they are not though, so go into the bundle and try to open your scripts in script builder to make sure that they’re not plain text versions of your code. OUCH! Bye-bye registration scheme! :stuck_out_tongue: If you find a case where your code is not being compiled (such as when building bundles like applescript-based plugins) you can add a build phase that executes a script to do that for you while your app is being built.

I would start by determining what level of security you want your registration scheme to have. If you just want to steer the user towards registration of your app, then you can usually get away with simply nagging them for registration. Writing nagging into an app is really easy and fairly bulletproof. Just set an encrypted key in your plist that determines whether the user is registered or not and pop up a nag window until they do. Beyond this, the level of complication grows. If you want a relatively bombproof, all-inclusive demo period that results in near complete inability to continue use or reinstall, you’ll have to go to great lengths to make this happen. Big development companies that do this successfully have whole teams of people who handle only registration management. Thinking that you’re going to do the same, while possible, is probably not reasonable. Just try to come up with something that protects your asset in a reasonable way, knowing as you go into it that you WILL NOT keep someone from pirating your software if they want to badly enough.

While the user is entitled to do whatever they want with their computer, unless you’re writing free/opensource software, your software still belongs to you. The terms of your license should reflect that you require registration and that trying to get around the registration will terminate their license to use it. Remember, too, though, that they don’t care. People will definitely try to get around paying you for your work, so you must try to make it very difficult for them to do that… to the point that simply paying for it is easier than hacking it. Just don’t make it easy for someone to get around your scheme, and you will knock off most of the users who wouldn’t have payed for it anyways. Try to test out your scheme really well before throwing it at users, though, because you also want to make sure that honest, registered users have no obstacles to their use of your product.

Good luck,

Jobu, that’s the best discussion on this subject that I’ve seen on this forum! :cool:

The only thing I would add is this: If your application creates any kind of document, an effective form of protection is putting a “Please register YourApplicationName” message in the background of the document or some other prominent place. This prevents users from using the documents created until they register. With this method, you can generally dispense with “nag” dialogs entirely, since the documents themselves contain the reminder.

So how hard would it be if say I wanted the trial to be the exact same app as the real version, but just to make it so the app completely stops working after 15 days.

Well, the conceptis pretty simple:

On first launch you write down the date of the day somewhere on the user’s HD.

Then when the app launches you read the valueas a date and save it into a variable (here: firstUsed)
Then you just use something like this in “on launched”:

if ((current date - 15) > firstUsed) then
--do some action here (like showing a expiration warning)

They were saying above, though, that if the user found that file they could easily just change it so that it never expires. Would I just have to save the file as like .Example.txt so that it is hidden?

Everyone has a ~/Library folder that is accessible no matter what their permissions. Choose a folder in there, and hide your doc in that folder.

This is what I came up with it stores the first run date in the sqlite3 database that my program uses.

	script demoPeriod
		set databaseLocation to space & "~/documents/Database.db" & space
		set head to "sqlite3" & databaseLocation & quote
		set tail to quote
		set runDate to (current date)
		set theQuery to "select date from user;" & space
		set firstRun to do shell script head & theQuery & tail
		if firstRun is equal to "" then
			set enterDate to "insert into user (date) values ('" & runDate & "');" & space
			do shell script head & enterDate & tail
		end if
		if runDate - 15 is greater than date firstRun then
--The number 15 is seconds so if you wanted it to be a 1 day trial you would have to use 86400
			display dialog "Your trial period has expired. Would you like to purchase?" buttons {"Yes"} default button {"Yes"}
			set buttonResult to button returned of result
			if buttonResult is "Yes" then
				open location ""
			end if
			display dialog "Demo Version" & return & return & "Would you like to purchase?" buttons {"No", "Yes"} default button {"Yes"}
			set buttonResult to button returned of result
			if buttonResult is "Yes" then
				open location ""
			end if
		end if
	end script

I’m still working on it but it seems to work fine. Just needs a little tweaking here and there.

There is hardly any chance to build a bullet-proof trial period mechanism.

Check out this nifty observation tool:
Just have it running while your app’s initial start and it will find any file you try to create and hide on your disk.

Every app is crackable. It is just a matter of time.