How should I license Excel Add-ons for sale in Envato?

Hello and good day,
Refering the code below, I am trying to sell an excel add-in here but before that I need to integrate licensing into the add-in to prevent people from buying it once and using in on multiple PC’s without paying.
Luckily Envanto does handle licensing for the codes we sell here. Now I need to adapt the blow code to use the envato licensing system. Can anyone give me some advice or instructions on how to go about doing this and also how to test it once its implemented?
Any help is much appreciated. Below is the (draft) code for license checking:

Option Explicit

’ Global variables to store the activation status and license key
Dim IsActivated As Boolean

Sub SetupAddIn()
’ This function sets up the initial configuration. You can customize it if needed.
’ For example, it could be used to set the product ID and API key.
’ For now, it’s assumed that the product ID and API key are constants.

' Uncomment and modify the lines below if you need to set up additional parameters.
' ProductID = "YOUR_PRODUCT_ID"
' APIKey = "YOUR_API_KEY"
' SaveToConfigFile "ProductID", ProductID
' SaveToConfigFile "APIKey", APIKey

' This function may also be used to prompt the user for the license key initially,
' but in the modified CheckLicenseKeyActivation function, the user will be prompted
' only when there's no stored license key.

End Sub

Function CheckLicenseKeyActivation() As Boolean
’ Load the license key from the secure storage
Dim licenseKey As String
licenseKey = LoadFromConfigFile(“LicenseKey”)

' Check if a license key is present
If licenseKey = "" Then
    ' If no license key is found, prompt the user to enter it
    licenseKey = InputBox("Enter your license key:")
   
    ' Validate the entered license key
    If IsValidLicenseKey(licenseKey) Then
        IsActivated = True
        SaveActivationStatus IsActivated
        SaveToConfigFile "LicenseKey", licenseKey  ' Save the entered license key
        MsgBox "License activation successful. You can now use the add-in."
    Else
        MsgBox "Invalid or missing license key. Please activate the license first.", vbExclamation
    End If
Else
    ' A license key is found, check its validity
    If IsValidLicenseKey(licenseKey) Then
        IsActivated = True
    Else
        MsgBox "Invalid or expired license key. Please enter a valid license key.", vbExclamation
    End If
End If

' Return the activation status
CheckLicenseKeyActivation = IsActivated

End Function

Function IsValidLicenseKey(key As String) As Boolean
’ Implement the logic to validate the license key
’ Use the stored ProductID and APIKey, or any other necessary information
’ Modify the validation logic based on your specific requirements
’ …

' For now, this function returns True if the key is not empty
' You should replace this with your actual validation logic
IsValidLicenseKey = (key <> "")

End Function

’ Include other functions such as GetHTTPResponse, SaveActivationStatus, etc.

’ …

’ Include the functions for saving and loading from a secure storage mechanism
’ For example, SaveToConfigFile, LoadFromConfigFile, or any other secure method

’ …

1 Like

It’s something that you need to figure it out by checking the API but where exactly are you planning to upload it for Excel on CodeCanyon? ( Which category )

I will most likely upload it under plugins

Plugins category may not be the good idea but I’m not sure Envato ( CodeCanyon ) accepting Excel Add-ons.


This has me woried, does it mean even after userspurchase the add-in that users has to keep requesting for tokens to use the add in , not a one time token, or am I mistaken?

:sweat:The below is as far as I’ve gotten, now I need to know how to associate any license given to the specific PC to ensure that the same license key cannot be used on multiple PCs. Does anyone know how to do this and in Envato has this feature?
Any help is much appreciated :pray:

Option Explicit

’ Global variables to store the activation status, product ID, and API key
Dim IsActivated As Boolean
Dim ProductID As String
Dim machineID As String
Dim Json As Object ’ Declare Json object

’ Set the product ID constant ’ Change XXXX_PRODUCT_ID to name of site
Const XXXX_PRODUCT_ID As String = “xxxxxxxxxxxxxxxxx==”
Const LICENSE_STORAGE_LOCATION As String = “LicenseStorage” 'use suitable name

Sub SetupAddIn()
’ Set the product ID directly in the code
ProductID = XXXX_PRODUCT_ID

' Save the entered product ID securely
SaveToConfigFile LICENSE_STORAGE_LOCATION, "ProductID", ProductID

' Generate and save machine-specific ID
machineID = GetMachineID()
SaveToConfigFile LICENSE_STORAGE_LOCATION, "MachineID", machineID

End Sub

Function CheckLicenseKeyActivation() As Boolean
’ Load the license key and machine ID from the secure storage
Dim licenseKey As String

Debug.Print "Attempting to load: LicenseKey from LicenseStorage"
' Load the license key only once
licenseKey = LoadFromConfigFile(LICENSE_STORAGE_LOCATION, "LicenseKey")

' Check if a license key is present
Debug.Print "Loaded: LicenseKey = " & licenseKey
If licenseKey = "" Then
    ' If no license key is found, prompt the user to enter it
    Debug.Print "No license key found. Prompting for user input."
    licenseKey = InputBox("Enter your license key:")
    Debug.Print "Entered license key: " & licenseKey
    
    ' Validate the entered license key
    If IsValidLicenseKey(licenseKey) Then
        ' Check if the license is associated with this machine
        If ValidateMachineID(licenseKey) Then
            ' Save the entered license key and activation status
            Debug.Print "Saving: LicenseKey = " & licenseKey & " to LicenseStorage"
            SaveToConfigFile LICENSE_STORAGE_LOCATION, "LicenseKey", licenseKey
            SaveActivationStatus True
            MsgBox "License activation successful. You can now use the add-in."
            CheckLicenseKeyActivation = True
        Else
            MsgBox "The license key is not valid for this machine. Please enter a valid license key.", vbExclamation
        End If
    Else
        MsgBox "Invalid or missing license key. Please activate the license first.", vbExclamation
    End If
Else
    ' A license key is found, check its validity
    Debug.Print "Checking validity of license key: " & licenseKey
    If IsValidLicenseKey(licenseKey) And ValidateMachineID(licenseKey) Then
        CheckLicenseKeyActivation = True
    Else
        MsgBox "Invalid or expired license key. Please enter a valid license key.", vbExclamation
    End If
End If

End Function

Function IsValidLicenseKey(key As String) As Boolean
’ Use the stored ProductID
Dim url As String
Dim response As String

' Use the constant for the product ID
url = https://api.XXXXXXX ‘Use URL given from site

' Modify the request to use POST and include product_id and license_key in the body
Dim postData As String
postData = "product_id=" & XXXX_PRODUCT_ID & "&license_key=" & key

response = PostHTTPResponse(url, postData)

On Error Resume Next
' Create and configure the JSON object
Set Json = CreateObject("ScriptControl")
Json.Language = "JScript"

' Execute the JSON parsing statement
Json.ExecuteStatement "var result = " & response
On Error GoTo 0

' Check if the "success" property exists and is true
On Error Resume Next
Dim successValue As Variant
successValue = Json.Eval("result.success")
On Error GoTo 0

If VarType(successValue) = vbBoolean Then
    ' "success" property exists and is a boolean
    IsValidLicenseKey = successValue
Else
    ' "success" property does not exist or is not a boolean
    IsValidLicenseKey = False
End If

End Function

Function PostHTTPResponse(url As String, postData As String) As String
Dim http As Object

Set http = CreateObject("MSXML2.XMLHTTP")

http.Open "POST", url, False
http.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
http.send postData

PostHTTPResponse = http.responseText

End Function

Sub SaveActivationStatus(activated As Boolean)
’ Save activation status to the same storage location as the license key
SaveToConfigFile LICENSE_STORAGE_LOCATION, “ActivationStatus”, CStr(activated)
End Sub

Function LoadActivationStatus() As Boolean
’ Load activation status from the same storage location as the license key
LoadActivationStatus = CBool(LoadFromConfigFile(LICENSE_STORAGE_LOCATION, “ActivationStatus”))
End Function

Sub SaveToConfigFile(storageLocation As String, key As String, value As String)
’ Save the key and value to the storage location
Dim saveSuccessful As Boolean
On Error Resume Next

Do
    Err.Clear
    saveSuccessful = True ' Assume success
    
    VBA.Interaction.SaveSetting "YourCompanyName", storageLocation, key, value
    If Err.Number <> 0 Then
        saveSuccessful = False
        Debug.Print "Error saving " & key & " to " & storageLocation & ". Error: " & Err.Description
    End If
Loop While Not saveSuccessful

Debug.Print "Saving: " & key & " = " & value & " to " & storageLocation
Debug.Print "Storage location: " & storageLocation
On Error GoTo 0

End Sub

Sub SaveToFile(filePath As String, content As String)
’ Save content to the specified file
On Error Resume Next
Open filePath For Output As #1
If Err.Number = 0 Then
Print #1, content
Close #1
Debug.Print "License key saved successfully to: " & filePath
Debug.Print "License storage path: " & filePath ’ Print the file path
Else
Debug.Print “Error saving license key. Please try again.”
End If
On Error GoTo 0
End Sub

Function LoadFromConfigFile(storageLocation As String, key As String) As String
’ Load the value from a secure storage mechanism
’ For simplicity, you can use the Windows Registry or a more secure approach
’ …

Dim fileContent As String ' Add this line
Dim filePath As String
filePath = storageLocation & "\config.txt" ' Specify the file name

Debug.Print "Attempting to load: " & key & " from " & filePath

If Dir(filePath) <> "" Then
    Open filePath For Input As #1
    fileContent = Input$(LOF(1), 1)
    Close #1

    Debug.Print "File Content: " & fileContent ' Add this line

    Dim keyValuePairs() As String
    keyValuePairs = Split(fileContent, vbCrLf)

    Dim pair As Variant
    For Each pair In keyValuePairs
        Dim pairParts() As String
        pairParts = Split(pair, "=")
        If UBound(pairParts) = 1 Then
            Debug.Print "Found Pair: " & Trim(pairParts(0)) & " = " & Trim(pairParts(1))
            If Trim(pairParts(0)) = key Then
                Debug.Print "Loaded: " & key & " = " & Trim(pairParts(1))
                LoadFromConfigFile = Trim(pairParts(1))
                Exit Function
            End If
        End If
    Next pair
Else
    Debug.Print "No value found. Storage location: " & filePath
End If

End Function

Function GetMachineID() As String
’ Implement logic to generate a unique machine ID
’ This could include hardware-specific information
’ For simplicity, you can use the Windows username in this example
GetMachineID = Environ(“USERNAME”)
End Function

Function ValidateMachineID(key As String) As Boolean
’ Validate that the machine ID in the license matches the current machine
Dim storedMachineID As String
storedMachineID = DecryptText(LoadFromConfigFile(LICENSE_STORAGE_LOCATION, “MachineID”))
ValidateMachineID = (storedMachineID = machineID)
End Function

Function EncryptText(plainText As String) As String
’ Implement your encryption logic here
’ Placeholder implementation using Base64 encoding
Dim encoder As Object
Set encoder = CreateObject(“MSXML2.DOMDocument.6.0”)

' Create a base64 encoder
Dim base64 As Object
Set base64 = encoder.createElement("b64")

' Load the input string and get bytes
base64.DataType = "bin.base64"
base64.Text = plainText

' Return the base64 encoded string
EncryptText = base64.Text

End Function

Function DecryptText(cipherText As String) As String
’ Implement your decryption logic here
’ Placeholder implementation using Base64 decoding

Dim bytes() As Byte
Dim xmlDoc As Object

' Create a DOM document
Set xmlDoc = CreateObject("MSXML2.DOMDocument.6.0")

' Load the base64 encoded string
xmlDoc.LoadXML "<base64>" & cipherText & "</base64>"

' Convert the base64 string to bytes
bytes = xmlDoc.DocumentElement.nodeTypedValue

' Decode the bytes
DecryptText = BytesToString(bytes)

End Function

Private Function BytesToString(bytes() As Byte) As String
’ Convert an array of bytes to a string
Dim i As Long
For i = LBound(bytes) To UBound(bytes)
BytesToString = BytesToString & Chr(bytes(i))
Next i
End Function

Ok my last message was flaged, so I will only say that I have created a working version of the code, you can find the code in Gumroad if anyone would like to use it. I have yet to adapt it to envanto, will let you know once it’s done.
Again if anyone would like to use a working version of the code which can license excel add-ins , you can find it on Gumroad
Happy coding

Just for reference the example you have created may well be useful for people but it wouldn’t be allowed for envato items.

That’s not how the licensing and validating purchases etc works