Jump to content
lido

About licensing AutoLISP program

Recommended Posts

lido

Please advise me about the step by step procedure, algorithm, etc., to license an AutoLISP program (VLX file) to the end user with a trial period of 30 days, during which the user can test the demo version of the program.

Thank you

Share this post


Link to post
Share on other sites
BIGAL

There are various ways of testing a date via lisp, lee-mac has a check date via internet this removes the PC clock which can be wound back. you just IF date > expire date then a exit defun use (Exit) last. This question has been posted here before.

Share this post


Link to post
Share on other sites
Lee Mac
11 hours ago, BIGAL said:

lee-mac has a check date via internet this removes the PC clock which can be wound back.

 

Internet Time

 

Thanks for the recommendation @BIGAL :thumbsup:

  • Thanks 1

Share this post


Link to post
Share on other sites
Grrr
Posted (edited)

BTW one could do this aswell, by putting a fixed (expiration) date :

(cond 
  ( (>= (read (substr (rtos (getvar 'cdate) 2 5) 1 8)) 20181226) (prompt "\nProgram Expired !") (princ) ) ; expiration
  (
    ; .. Define functions for our program
    (defun C:MyHandsomeProgram nil
      ; ...
    ); defun 
    (defun C:AnotherHandsomeProgram nil
      ; ...
    ); defun 
    (defun SomeFancySubFun ( args )
      ;...
    ); defun
    ; ...
  )
); cond

Although one thing I couldn't figure out yet, was how to alert when the program expires in X days, when the year or the month is changed -

(
  (lambda ( cdate expdate / )
    (cond 
      ( (and (= 3 (- expdate cdate)) (alert "\nProgram will exipre in 3 days.")) )
      ( (and (= 2 (- expdate cdate)) (alert "\nProgram will exipre in 2 days.")) )
      ( (and (= 1 (- expdate cdate)) (alert "\nProgram will exipre in 1 day.")) )
      ( (>= cdate expdate) (alert "\nProgram Expired !") (princ) ) ; expiration
      (t
        
        (defun C:test ( / )
          (alert "Hello World")
          (princ)
        ); defun C:test
        
        ; .. Define functions for our program
      ); t
    ); cond
  ); lambda
  (read (substr (rtos (getvar 'cdate) 2 5) 1 8))
  20190131
)

Say the expiration date is on 2019.02.01 and the current date is 2019.01.30, so we'd like to alert that there are 2 days remaining. 😕

 

Edited by Grrr

Share this post


Link to post
Share on other sites
Lee Mac
Posted (edited)
58 minutes ago, Grrr said:

Say the expiration date is on 2019.02.01 and the current date is 2019.01.30, so we'd like to alert that there are 2 days remaining. 😕

 

The easiest way is to use the contiguous Julian date system, e.g.:

(
    (lambda ( date expdate / dif )
        (if
            (cond
                (   (not (or dtoj (and (load "julian.lsp" nil) dtoj))))
                (   (<= (setq dif (- (fix (dtoj expdate)) date)) 0)
                    (alert "Program has expired.")
                )
                (   (progn (alert (strcat "Program will expire in " (itoa dif) " day" (if (= 1 dif) "." "s."))) t))
            )
            (progn
                (defun c:test ( )
                    (alert "Hello World!")
                    (princ)
                )
            )
        )
    )
    (fix (getvar 'date))
    20190131
)

Here, the Express Tools' dtoj function is only used to make it easier to specify the expiration date in the code - you can easily remove this reliance by specifying the expiration date as a Julian date directly in the code.

 

Note that this approach is still susceptible to the user changing the system clock - hence the suggestion to use my Internet Time function above.

Edited by Lee Mac
  • Like 1

Share this post


Link to post
Share on other sites
ssdd
Posted (edited)

Can I add a MacAddress?

 

(
    (lambda ( date expdate / dif )
        (if
            (cond
                (   (not (or dtoj (and (load "julian.lsp" nil) dtoj))))
                (   (<= (setq dif (- (fix (dtoj expdate)) date)) 0)
                    (alert "Program has expired.")
                )
            ( (not get_macaddress) (princ "\nFunction get_macaddress is not loaded.") )
                    ( (not (eq MyMacAddress (get_macaddress))) (princ "\nYou have no permission to run this routine.") )
                (   (progn (alert (strcat "Program will expire in " (itoa dif) " day" (if (= 1 dif) "." "s."))) t))
        
            )
            (progn
                (defun c:test ( )
                    (alert "Hello World!")
                    (princ)
                )
            )
        )
    )
    (fix (getvar 'date))
    20190131
)

Edited by ssdd
  • Thanks 1

Share this post


Link to post
Share on other sites
Grrr
25 minutes ago, Lee Mac said:

The easiest way is to use the contiguous Julian date system, e.g.:

 

Wow nice one, Lee!

 

33 minutes ago, Lee Mac said:

Here, the Express Tools' dtoj function is only used to make it easier to specify the expiration date in the code - you can easily remove this reliance by specifying the expiration date as a Julian date directly in the code.

 

Well I could also violate a bit Autodesk's terms of use, by appending the dtoj function definition into the expiration date wrapper.  :playing:

Ofcourse this doesn't sound like the right thing to do, but on the other hand the algorithm could be replicated (if its not already somewhere on the internet) and overall doesn't do any harm.

 

41 minutes ago, Lee Mac said:

Note that this approach is still susceptible to the user changing the system clock - hence the suggestion to use my Internet Time function above.

 

I remember we were doing such clock-adjusting back in the 90's in order to run some expired programs :D

I find your LM:InternetTime great, but theres one thing to keep in mind, since when defined the subfunction remains "public" -

It must be defined while running the expiration wrapper...else one could simple redefine your sub in order to bypass the checks like so:

(defun LM:InternetTime ( format )
  "01.01.99" ; "MO.DD.YY"
)

Assuming the "bad" guy nailed the date format.

Thats why I try to keep some stuff localised/private within a scope.

 

Thanks Lee!

 

  • Thanks 1

Share this post


Link to post
Share on other sites
Lee Mac
4 minutes ago, Grrr said:

I find your LM:InternetTime great, but theres one thing to keep in mind, since when defined the subfunction remains "public" -

It must be defined while running the expiration wrapper...else one could simple redefine your sub in order to bypass the checks like so:


(defun LM:InternetTime ( format )
  "01.01.99" ; "MO.DD.YY"
)

Assuming the "bad" guy nailed the date format.

Thats why I try to keep some stuff localised/private within a scope.

 

If you were going to the trouble of implementing an trial license, you would of course compile the entire application to a separate-namespace vlx, meaning that the definition of the LM:InternetTime function could not be modified (or, rather, any definition would not affect the definition within the vlx namespace) as it resides outside of the document namespace.

  • Like 1

Share this post


Link to post
Share on other sites
Grrr
9 minutes ago, Lee Mac said:

you would of course compile the entire application to a separate-namespace vlx, meaning that the definition of the LM:InternetTime function could not be modified

 

Oh wow seems like you already thought about this problem! 👍

..and I've forgot to like your posts, so doing it right now!

Share this post


Link to post
Share on other sites
Lee Mac
Posted (edited)
40 minutes ago, ssdd said:

Can I add a MacAddress?

 

Indeed you can - consider a function such as the following:

;; MAC Addresses  -  Lee Mac
;; Returns a list of MAC Addresses for all installed network adaptors

(defun LM:macaddresses ( / err qry srv wmi )
    (if (setq wmi (vlax-create-object "wbemscripting.swbemlocator"))
        (progn
            (setq err
                (vl-catch-all-apply
                    (function
                        (lambda ( / rtn )
                            (setq srv (vlax-invoke wmi 'connectserver)
                                  qry (vlax-invoke srv 'execquery "select macaddress from win32_networkadapter where macaddress is not null")
                            )
                            (vlax-for itm qry (setq rtn (cons (vlax-get itm 'macaddress) rtn)))
                        )
                    )
                )
            )
            (foreach obj (list qry srv wmi)
                (if (= 'vla-object (type obj))
                    (vlax-release-object obj)
                )
            )
            (if (vl-catch-all-error-p err)
                (prompt (vl-catch-all-error-message err))
                err
            )
        )
    )
)

 

Edited by Lee Mac
  • Thanks 1

Share this post


Link to post
Share on other sites
Lee Mac
13 minutes ago, Grrr said:

 

Oh wow seems like you already thought about this problem! 👍

..and I've forgot to like your posts, so doing it right now!

 

Thanks! 🍺

Share this post


Link to post
Share on other sites
BIGAL

Mac address

PC Date

Internet date

Hard disk ID

Regapp entry

Autocad serial number

Ping a web server

 

Lots of methods available 

 

Oh yeah the phone call "the software is not working how do I fix ?" bottom line the end user tried to install on another computer without paying.

  • Thanks 1

Share this post


Link to post
Share on other sites
joemcanciller
On 08/01/2019 at 02:16, Lee Mac said:

 

Internet Time

 

Thanks for the recommendation @BIGAL :thumbsup:

This is great sir @Lee Mac. Im also looking for this. Will it work even if the user has no internet connection?

Share this post


Link to post
Share on other sites
lido

Thank all of you guys for your answers.

Bellow, I will try to analyze the options. Please correct me if I'm wrong.

 

If we were talking about the date, finding the current date is not enough. It is important to check the difference between the date of installing the program and the current one (<=30, in days).  So the installing date must be saved. Options:

1. Use the registry key from the installation kit (NSIS, for example).

2. Create a file as hidden as possible, containing the date of the first launch of the program (with AutoLISP).

In my opinion, both variants are weak and do not provide an effective protection system.

Another approach is to not check the 30 days trial period. In this case the program can be used as usual, with some limitations until the user decides to purchase it.

 

Now, with regard to how licensing can be done, at least at this time, the licensing option is offline. What data should be provided by the user?

Let's see the vendor's options for licensing:

1. Identify hardware components: HDD serial number, BIOS data, MAC address, etc.: 

     PROS: strong level of protection.

     CONS: replacing a hardware component will result in the license being canceled.

2. Using (Auto)CAD system variables:

   a) _PKSER:

        PROS: level of protection under (Auto)CAD.

        CONS: if (Auto)CAD is cracked, there is no control over the program.

  b) LOGINNAME:

        PROS: same as 2a above.

        CONS: same as 2 above; only the licensed user can use the program (case of multiple users for the same PC).

3. Any combination between option 1 and option 2 above.

 

Concluding, let's say that I chose option 2a. Considering this option, in my opinion, the type of (Auto)CAD license should be checked: Standalone or Network (multi-users); the number of licenses of the program should be equal to the number of subscription seats, if the (Auto)CAD license type is Network.

Under AutoCAD, the system variable _LINFO (undocumented) provide same information, as follow:

 - AutoCAD 2005 Network license: (getvar "_LINFO") return "ADLM Network License Granted. Connects: 1"

 - AutoCAD 2015 Standalone license:  (getvar "_LINFO") return  nil.

I do not know if the system variable _LINFO exists and how it behaves under other CAD platforms.

 

 

 

Questions:

1. The (Auto)CAD license type (Standalone or Network) can be found out otherwise than by using system variable _LINFO?

2. How to find the number of subscription seats using AutoLISP in case of (Auto)CAD Network license?

Share this post


Link to post
Share on other sites
Lee Mac
2 hours ago, joemcanciller said:

This is great sir @Lee Mac. Im also looking for this. Will it work even if the user has no internet connection?

 

No, as the function retrieves the UTC time from the NIST time server (http://time.nist.gov).

  • Like 1

Share this post


Link to post
Share on other sites
maratovich

lido

If you need good protection, you need to use a ready-made solution.
Write a request to this company: http://www.star-force.com/
They make protection on programs, and they make protection on Lisp.
All your protection requirements they can do is not a problem.
I have been using this protection for a long time.

  • Thanks 1

Share this post


Link to post
Share on other sites
lido

@maratovich

Thank you for guidance. I'll give it a try.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×