Licensing bug where free trial does not expire


#1

I explained to Chris Fulmer long ago, that I’m uncomfortable with the licensing implementation: I can’t test it because an extension developer doesn’t ever get a license to his own extension. I just insert license calls and hope I didn’t make any typos. Then I have to comment out all the license calls to continue using my own extension and work on the next release.

Over time I’ve noticed on my “Store” that many customers who buy, never bothered with the free trial. And that many trial users never buy. Maybe trials aren’t properly expiring when they should?

So I did a test using another developer’s extension: CADMAN’s “Snap Connector”. I downloaded its free 5 day trial. It worked. Then I waited 6 days: it still worked. No sign that it was going to expire.

Looked at detail info in the extension manager and saw that it said “license missing”. But it still works! Here’s a screen grab.

I’m running SketchUp Pro 2017 on Windows 7. I have no idea what factors lead to this kind of problem, or how extensive it might be. I’ve reported this to Chris Fulmer by email, but he is AWOL. Meanwhile I’m turning OFF free trials for my extensions until this is resolved.


#2

Jim Foltz has replied to me as follows:
“Barry - nothing is broken. SnapConector licensing is working exactly how Mark wanted it. He decided to be lax in the enforcement of the license. We allow it to run, license or not, only prompting unlicensed users upon exiting the tool.”

I guess I just picked the wrong extension to test.
However I’m still not clear on how this works:
Obviously you can test for a licence in your code and then still allow it to run.
But as a developer we can’t distinguish between trial and full licenses, nor can we tell when a trial is concluded. All we can do is “if ext_lic.licensed?”. For that call to understand when a trial has expired, there has to be a trial license with dates in the ew.lic file on the user machine.
Yet Snap Connector shows “license missing”.

What am I missing here?


#3

:question:

I clearly see in the Sketchup::Licensing module documentation, that the following constants are defined:

Sketchup::Licensing::LICENSED
Sketchup::Licensing::EXPIRED
Sketchup::Licensing::TRIAL
Sketchup::Licensing::TRIAL_EXPIRED
Sketchup::Licensing::NOT_LICENSED

Further more, I see (plain as mud,) in the Sketchup::Licensing::ExtensionLicense class the following instance methods:

#days_remaining ⇒ Object
The days_remaining method is used to get the number of days
 remaining until license expiration.

#error_description ⇒ Object
The error_description method is used to obtain error information
 in case of failure to acquire a license.

#licensed? ⇒ Object
The licensed? method is used to decide whether the extension
 is licensed to run or not.

#state ⇒ Object
The state method returns a constant indicating the specific
 licensing state.

The last, ie #state() method, returns an integer corresponding to the constants listed above.

I’m guessing most of what I reference above ?
I cannot explain why you cannot see this in the documentation.

… or are you implying all this functionality is bugged or not working ?


#4

You are correct. But since we’re doing this coding in the dark (without being able to test against an actual license), I just followed the example in the licensing tutorial which mentions only the “if ext_lic.licensed?” test.
A link to this tutorial still exists but is dead at “http://ruby.sketchup.com/Sketchup/Licensing.html”.
It showed an example where it recommended that you load your extension to SU but then do a “if ext_lic.licensed?” to decide whether to add your toolbars. I pointed out to Chris Fulmer at the time that any knowlegeable rubyist could use the console to discover your module name and method and load the toolbars himself, and bypass the need for a license! Which is why you MUST use the test elsewhere in your code.

So this leaves the following questions:
If a trial license exists (expired or unexpired) why does the extension manager show “license missing”?
Does “if ext_lic.licensed?” return TRUE for an expired trial license"; for an unexpired trial license?
Do I need to make any of these distinctions in my code? Or can I rely on SketchUp handling all this at load time? And if SketchUp can handles all licensing at load time, why have any licensing calls in the API?


Licensing errors passing undetected
#5

So I DISABLED free trials on the EW pages of my extensions yesterday.
Their pages now DO NOT show the length of the trial period as they did before.
BUT they still show a link below the “Purchase” button which says “Install Trial from SketchUp”.
AND I’m still getting new trial downloads by users.


#6

It is expected for developers using API classes and their methods, to read the API documentation.

It is unexpected for a developer to not read the available resources, and then publicly declare the API to be deficient with respect to a certain feature.

It is expected for a developer to use their own good sense, experience and programming acumen to code their extensions in a way that works properly. (Ie, Trimble sells many kinds of products, but is not generally in the programming education business. They will however from time to time hold some developer “camps” to promote their APIs and their good use. But it is not Trimble’s responsibility to hold a developer’s hand and make sure their code works. This is the developer’s responsibility.)

It is most unexpected to have a developer believe that any certain tutorial would be the limit of knowledge surrounding the use of any API class, model or feature.

An example, is an example only. It shows something that can be done, but you as the programmer do not give up your own good sense of what must be done (in addition to what any example shows.)

Ruby is a dynamic language, therefor code objects can be changed unless you freeze your modules and classes.

You also need to protect your command methods (with licensing checks) which are fired from the toolbar buttons. The documentation mentions that a developer needs to put checks elsewhere in their code.

It is also possible to protect every single method (except public callbacks) in your code to only allow it to be called from within your code. (See: global method Kernel#caller and other methods in that module.)

Also, your extension sub-module belongs to you. There is no reason why you must leave introspective and reflective features active within your modules. Undefine or remove these kinds of methods before freezing your sub-modules. (Do not freeze your top-level namespace module, as it needs to be modified as sub-modules are added as extensions load.)

I know, I logged the issue, and I attempted to fix it but we’re having some issues with the YARD doc repo.
And then it seemed like, in the midst of us testing the new Licensing class page, that some one at Trimble redirected the new good link (to the aforementioned tutorial,) to the Developer landing page. (@tt_su was going to check on that.)

The latest API doc changes (including the updates to the Licensing class page,) have not yet been pushed to the public docs. (There were a bunch of other changes as well. But Thomas has been swamped with work of late.)

Well this is an issue for the Extension Manager interface. It is not a Ruby API bug. It’s an implementation issue for an application side interface. (So I would log it as an application bug against SketchUp itself. But I do agree, the"message" is ambiguous.)

However, the API docs for #error_description() say:

This is meant to aid in debugging only. Extensions should not rely on any exact error description.

So, they have not yet enumerated what the descriptions can be, nor what they mean.
This is all relatively new, with respect to the total age of the SketchUp Ruby API.
In other words they wish to “have license” (pun intended) to massage these, and perhaps also to localize these for the various languages builds. So do not test against them for conditional code branching. (Ie, think messagebox display only.)

Firstly, the documentation pages still need better information.

I believe that this is the probable “way of things”:

#state() when ext_lic.licensed? == true :

Sketchup::Licensing::LICENSED
Sketchup::Licensing::TRIAL

#state() when ext_lic.licensed? == false :

Sketchup::Licensing::EXPIRED
Sketchup::Licensing::TRIAL_EXPIRED
Sketchup::Licensing::NOT_LICENSED

At least, this (above) is what would be the most obvious scenario (IMO.)

You decide how your code reacts to licensing state changes.

NO, plain and simple, … code defensively. (See the previous comments above.)

It cannot., which is WHY there is licensing interfaces in the API, for your code to use.

These are issues for the Extension Warehouse. Best to re-post in that category with a relation link back to this thread.