Licensing is difficult, which is one of the reasons there are third party products to enforce licensing for you. And in the context of this question we are simply talking about license enforcement. You do have to define what you mean by "airtight", and whether you support licensing enforcement on private networks.
By running a Python based application, you already are at a disadvantage because python byte code can be easily disassembled and the enforcement code can be disconnected. You'll find that an appropriate solution has to be implemented in layers:
- Step 1: automated obfuscation tools (change variable names to non-displayable characters, etc.) This can break your code.
- Step 2: define when the licensing starts and ends, this information needs to be local to the application
- Step 3: define how licensing is applied (per user, per machine, per user/per machine), this affects 1: where you can store this information and 2: how you identify the user or machine
- Step 4: Define the license token that contains the start/expiration dates and the identifiable information
- Step 5: Store that token in appropriate space (user roaming storage, user local storage, machine storage) and verify on program startup--erroring out if the license token does not exist or is no longer valid
Per User licensing only verifies the running user account against the licence grant.
Per Machine licensing only verifies the running machine--which can be difficult when PCs are so modular--against the license grant.
Per User/Per Machine needs to verify that the user and machine combination are correct against the license grant. Same user on another machine would require a new grant, just like a different user on the same machine would require a new grant.
For some scenarios (like Microsoft products) you simply need a token that encodes the product id and expiration. Simple existence of the token is sufficient to make the product usable.
Some application providers want to sign the license token (like RedGate) which creates an identifier token that gets sent to a central server, and that server sends a signed token back that has the expiration date. Because the exchange requires an active connection to their servers, they have to make special provision for users on a disconnected network. I.e. they need to allow users to copy the token as a file from the private network to the public one, upload it manually, and copy the signed token back to the private network.
The general concepts are the same. The robustness of the license enforcement (or DRM) depends on how that license token is generated and validated. Key factors for a secure token include:
- Detection if the token has been tampered with (digital signing ensures this)
- Method to identify the licensed party (i.e. user, machine)
- Method to identify licensing terms
- Method to determine if the clock has been tampered with (i.e. changing the date of the machine)
You have to think through the following:
- How much protection do I really need? The trade-off is the more you do to enforce the license the less your customers will want to use it--particularly if they have to deal with a private network
- How much business am I really losing? At some point, the effort someone needs to go through to defeat your licensing mechanisms is just not worth pursuing.
- Does my DRM defeat my ability to support the application? Obfuscation tools can do terrible things here.
I am positive you will find you need a solution that is less than "airtight". It might be worth looking at existing DRM tools, and see if they can be incorporated so you aren't spending a large engineering effort on this problem.