Check Trial Period using Dropbox (first version, improved version in Post #2)
Hello,
I have tried to find a solution to solve the control of the trial period of an app using the Dropbox. The idea arose when using the solution of the member "gregchao" which realized it with FTP:
https://www.b4x.com/android/forum/threads/trial-period-using-ftp.95338/
The solution works perfectly. However, it requires web space. Everyone gets a Dropbox account for free. The limited space in the free version is no problem for this task.
I use the dropbox library of "DonManfred" for this task:
https://www.b4x.com/android/forum/threads/dropbox-sdk-v2-java.74019/#content
To disguise the access data of the Dropbox I use the library F5Steg from the Probundle Pack of Informatix:
https://www.b4x.com/android/forum/threads/probundle-chargeable.58754/#content
The dropbox must already be set up for the project example. In addition, an App must be set up in the Dropbox App Console:
https://www.dropbox.com/developers/
There you can also generate the required token. This will be integrated into the app.
I've written a small app (it's nothing more than an edited example from the author of the library). With this one can hide the Dropbox token in a picture. The source text must be supplemented with the token (variable "PASSWORD"). If you run them in debug mode, the location for the output file "tresor.jpg" will be displayed in the log window. This image file must be copied to the "Files" folder in the example project (overwrite existing invalid file).
Important !!! Both projects must be compiled with the same "private sign key". If you later change the signature of the app, a new image must be generated (with the same key). The app decrypts the image with the signature. Consequently, encryption and decryption must be done with the same signature.
I wrote a class file "daycheck". This is very easy to call in any app:
Class "daycheck"
The sample project also contains the libraries that have to be copied to the folder "Userlib" of B4A (if necessary).
In addition, the following file must be downloaded and copied to the "Userlib" folder:
http://central.maven.org/maven2/com/dropbox/core/dropbox-core-sdk/3.0.10/dropbox-core-sdk-3.0.10.jar
It will first try to find a file in File.DirInternal. If it is missing, it will be generated and stored additional in the Dropbox in the folder "... \ Apps \ ...". This works only if an internet connection is available. Otherwise the variable "proversion" is set to false. This file stores the date of installation. In order to complicate a manipulation in rooted devices, a checksum is additionally stored in addition to this time. If this file is deleted (for example, during uninstallation and new installation) it must be recreated. If the file already exists in the dropbox, the original time will be read out and set again.
I have still made it difficult to reset the date. That would force an immediate reinstallation. However, this would only restore the function until the end of the regular test time. The chosen method has the advantage that the app requires an online connection only in the absence of the internal file. This is the case in the normal only after the first installation.
For reviews and hints I am always very grateful.
31.3.2019 Edit: daycheck.bas - small error correction (line 153 added new)
Best regards,
Gunnar
Hello,
I have tried to find a solution to solve the control of the trial period of an app using the Dropbox. The idea arose when using the solution of the member "gregchao" which realized it with FTP:
https://www.b4x.com/android/forum/threads/trial-period-using-ftp.95338/
The solution works perfectly. However, it requires web space. Everyone gets a Dropbox account for free. The limited space in the free version is no problem for this task.
I use the dropbox library of "DonManfred" for this task:
https://www.b4x.com/android/forum/threads/dropbox-sdk-v2-java.74019/#content
To disguise the access data of the Dropbox I use the library F5Steg from the Probundle Pack of Informatix:
https://www.b4x.com/android/forum/threads/probundle-chargeable.58754/#content
The dropbox must already be set up for the project example. In addition, an App must be set up in the Dropbox App Console:
https://www.dropbox.com/developers/
There you can also generate the required token. This will be integrated into the app.
I've written a small app (it's nothing more than an edited example from the author of the library). With this one can hide the Dropbox token in a picture. The source text must be supplemented with the token (variable "PASSWORD"). If you run them in debug mode, the location for the output file "tresor.jpg" will be displayed in the log window. This image file must be copied to the "Files" folder in the example project (overwrite existing invalid file).
Important !!! Both projects must be compiled with the same "private sign key". If you later change the signature of the app, a new image must be generated (with the same key). The app decrypts the image with the signature. Consequently, encryption and decryption must be done with the same signature.
B4X:
#Region Project Attributes
#ApplicationLabel: Encrypt PW
#VersionCode: 1
#VersionName:
'SupportedOrientations possible values: unspecified, landscape or portrait.
#SupportedOrientations: unspecified
#CanInstallToExternalStorage: False
#End Region
#Region Activity Attributes
#FullScreen: False
#IncludeTitle: True
#End Region
Sub Process_Globals
Dim Const PASSWORD As String = "xxxxxxxxxxxxxxxxxxxxxx"
End Sub
Sub Globals
Dim F5S As F5Steg
End Sub
Sub Activity_Create(FirstTime As Boolean)
Starter.Rp.CheckAndRequest(Starter.Rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
Sub Activity_PermissionResult (Permission As String, Result As Boolean)
If Permission = Starter.rp.PERMISSION_WRITE_EXTERNAL_STORAGE Then
If Result Then
File.Copy(File.DirAssets, "tresor.png", File.DirInternalCache, "tresor.png")
EmbedInImages
Else
Activity.Finish
ExitApplication
End If
End If
End Sub
Sub EmbedInImages
File.Delete(File.DirRootExternal, "tresor.jpg")
F5S.EmbedArray(File.DirInternalCache & "/tresor.png", File.DirRootExternal & "/tresor.jpg", PASSWORD.GetBytes("UTF-8"), 80, "PW")
Log("Encrypted file: " & File.DirRootExternal & "/tresor.jpg")
End Sub
Sub PW_Embedded(OutFileName As String)
F5S.ExtractToArray(OutFileName, "PW")
End Sub
Sub PW_ArrayExtracted(SecretMessage() As Byte)
Dim PlainText As String = BytesToString(SecretMessage, 0, SecretMessage.Length, "UTF-8")
Log("SECRET = " & PlainText)
If PlainText = PASSWORD Then
LogColor("MATCH !", Colors.Green)
Else
LogColor("DIFFERENT !", Colors.Red)
End If
Sleep(6000)
Activity.Finish
End Sub
I wrote a class file "daycheck". This is very easy to call in any app:
B4X:
#Region Project Attributes
#ApplicationLabel: Trial Check
#VersionCode: 1
#VersionName:
'SupportedOrientations possible values: unspecified, landscape or portrait.
#SupportedOrientations: unspecified
#CanInstallToExternalStorage: False
#End Region
#Region Activity Attributes
#FullScreen: False
#IncludeTitle: True
#End Region
Sub Process_Globals
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Dim fullversion As daycheck
Dim trialperiod As Int = 14
Dim proversion As Boolean = False
End Sub
Sub Globals
End Sub
Sub Activity_Create(FirstTime As Boolean)
End Sub
Sub Activity_Resume
fullversion.Initialize(Activity, "main","fullversion")
End Sub
Sub Activity_Pause (UserClosed As Boolean)
File.WriteString(File.DirInternal, "lastuse.ini", DateTime.now)
End Sub
Public Sub fullversion_Result(days As Int)
ToastMessageShow("Proversion = " & proversion & ", Days left: " & days, True)
Activity.Finish
End Sub
Class "daycheck"
B4X:
Sub Class_Globals
Private mymodule As Object
Private myname As String
Dim daysleft As Int
Dim auth As DbxAuth
Dim Dropbox As DropboxV2
Dim token As String
Dim client As DbxClientV2
Dim config As DbxRequestConfig
Dim dbxFiles As DbxUserFilesRequests
Dim F5S As F5Steg
Dim uniqueid As String
Dim job As HttpJob
End Sub
Public Sub Initialize(Parent As Activity, Module As Object, Eventname As String)
mymodule = Module
myname = Eventname
trialcheck
End Sub
Sub trialcheck
File.Copy(File.DirAssets, "tresor.jpg", File.DirInternalCache, "tresor.jpg")
F5S.ExtractToArray(File.DirInternalCache & "/tresor.jpg", "dbopen")
End Sub
Sub dbopen_ArrayExtracted(SecretMessage() As Byte)
Dim PlainText As String = BytesToString(SecretMessage, 0, SecretMessage.Length, "UTF-8")
token = PlainText
uniqueid = GetDeviceId
If File.Exists(File.DirInternal, uniqueid) = False Then
ToastMessageShow("Please wait, check internet connection", False)
job.Initialize("Job1", Me)
job.Download("http://www.google.com")
Else
Dim ts As String
If File.Exists(File.DirInternal, "lastuse.ini") Then
ts = File.ReadString(File.DirInternal, "lastuse.ini")
If DateTime.Now < ts Then
' Date manipulation
File.writeString(File.DirInternal, uniqueid, encrypt("973897200000")) ' first install: 11/11/2000 (manipulation)
Main.proversion = False
CallSub2(mymodule, myname & "_Result", 0)
Return
End If
End If
ts = File.ReadString(File.DirInternal, uniqueid)
ts = decrypt(ts)
If ts = "973897200000" Then
' pro version expiried
Main.proversion = False
CallSub2(mymodule, myname & "_Result", 0)
Else If DateTime.Now > ts Then
Dim per As Period = DateUtils.PeriodBetweenindays(ts, DateTime.Now)
If per.days <= Main.trialperiod Then
Dim daysleft As Int = Main.trialperiod - per.days
Main.proversion = True
CallSub2(mymodule, myname & "_Result", daysleft)
Return
Else
File.writeString(File.DirInternal, uniqueid, encrypt("973897200000")) ' first install: 11/11/2000 (manipulation)
Main.proversion = False
CallSub2(mymodule, myname & "_Result", 0)
End If
Else
' Date manipulation
File.writeString(File.DirInternal, uniqueid, encrypt("973897200000")) ' first install: 11/11/2000 (manipulation)
Main.proversion = False
CallSub2(mymodule, myname & "_Result", 0)
End If
End If
End Sub
Sub JobDone(jobx As HttpJob)
If jobx.JobName="Job1" And job.Success=False Then
job.Release
Main.proversion = False
ToastMessageShow("Test time can only be activated when the internet connection is active", True)
CallSubDelayed2(mymodule, myname & "_Result", 0)
Else
job.Release
Sleep(2000)
check
End If
End Sub
Sub check
config.Initialize("",token,"","", 5)
Dim dbxhost As DbxHost
dbxhost.Initialize
client.Initialize("Dropbox", config, token, dbxhost)
dbxFiles = client.files
dbxFiles.setEventname("dbxFiles")
Dropbox.Initialize("")
auth.Initialize(token)
dbxFiles.search("",uniqueid,"FILENAME", 2, 0)
End Sub
Sub dbxFiles_Search(results As List)
Dim foundit As Int = 0
If results.Size > 0 Then
For i = 0 To results.Size - 1
Dim match As Map = results.Get(i)
Dim meta As Metadata = match.Get("Metadata")
If meta.Name = uniqueid Then
foundit = 1
End If
Next
End If
If foundit = 0 Then
' create a file and upload it
File.WriteString(File.DirInternal, uniqueid, encrypt(DateTime.now))
dbxFiles.upload(File.DirInternal, uniqueid, "/" & uniqueid, False, False)
Else
' download the file
dbxFiles.download("/" & uniqueid, File.DirInternal, uniqueid)
End If
End Sub
Sub dbxFiles_UploadFinished(success As Boolean, meta As FileMetadata, sessionId As String)
If success = False Then
ToastMessageShow("Upload error for trial check", True)
' Log(LastException.Message)
Main.proversion = False
daysleft = 0
Else
Main.proversion = True
daysleft = Main.trialperiod
End If
CallSub2(mymodule, myname & "_Result", daysleft)
End Sub
Sub dbxFiles_DownloadFinished(success As Boolean, meta As FileMetadata, error As String)
If success = False Then
ToastMessageShow("Download error for trial check", True)
' Log(LastException.Message)
Main.proversion = False
CallSub2(mymodule, myname & "_Result", 0)
Return
Else
Dim ts As String = File.ReadString(File.DirInternal, uniqueid)
ts = decrypt(ts)
If DateTime.Now > ts Then
Dim per As Period = DateUtils.PeriodBetweenindays(ts, DateTime.Now)
If per.days <= Main.trialperiod Then
daysleft = Main.trialperiod - per.days
Main.proversion = True
CallSub2(mymodule, myname & "_Result", daysleft)
Return
Else
File.writeString(File.DirInternal, uniqueid, encrypt("973897200000")) ' first install: 11/11/2000 (manipulation)
Main.proversion = False
CallSub2(mymodule, myname & "_Result", 0)
End If
Else
Main.proversion = False
CallSub2(mymodule, myname & "_Result", 0)
End If
End If
End Sub
Sub GetDeviceId As String
Dim p As Phone
Dim r As Reflector
Dim id As String
id = p.GetSettings("android_id") & r.GetStaticField("android.os.Build", "SERIAL")
Return id
End Sub
Sub encrypt(tstr As String) As String
Dim ztxt As String
Dim checksum As Int
ztxt = ""
checksum = 0
For i = tstr.Length - 1 To 0 Step - 1
ztxt = ztxt & tstr.SubString2(i, i + 1)
checksum = checksum + tstr.SubString2(i, i + 1)
Next
' Manipulate checksum
checksum = checksum + ztxt.SubString2(0, 3)
ztxt = ztxt & "." & checksum
Return ztxt
End Sub
Sub decrypt(tstr As String) As String
Dim ztxt As String
Dim digit, checksum, checksumorg As Int
Try
digit = tstr.IndexOf(".")
ztxt = tstr.SubString(digit + 1)
checksum = ztxt
' Remanipulate checksum
checksum = checksum - tstr.SubString2(0, 3)
ztxt = ""
checksumorg = 0
tstr = tstr.SubString2(0, digit)
For i = tstr.Length - 1 To 0 Step - 1
ztxt = ztxt & tstr.SubString2(i, i + 1)
checksumorg = checksumorg + tstr.SubString2(i, i + 1)
Next
If checksum = checksumorg Then
Return ztxt
Else
Return "973897200000" ' first install: 11/11/2000 (manipulation)
End If
Catch
Return "973897200000" ' first install: 11/11/2000 (manipulation)
End Try
End Sub
The sample project also contains the libraries that have to be copied to the folder "Userlib" of B4A (if necessary).
In addition, the following file must be downloaded and copied to the "Userlib" folder:
http://central.maven.org/maven2/com/dropbox/core/dropbox-core-sdk/3.0.10/dropbox-core-sdk-3.0.10.jar
It will first try to find a file in File.DirInternal. If it is missing, it will be generated and stored additional in the Dropbox in the folder "... \ Apps \ ...". This works only if an internet connection is available. Otherwise the variable "proversion" is set to false. This file stores the date of installation. In order to complicate a manipulation in rooted devices, a checksum is additionally stored in addition to this time. If this file is deleted (for example, during uninstallation and new installation) it must be recreated. If the file already exists in the dropbox, the original time will be read out and set again.
I have still made it difficult to reset the date. That would force an immediate reinstallation. However, this would only restore the function until the end of the regular test time. The chosen method has the advantage that the app requires an online connection only in the absence of the internal file. This is the case in the normal only after the first installation.
For reviews and hints I am always very grateful.
31.3.2019 Edit: daycheck.bas - small error correction (line 153 added new)
Best regards,
Gunnar
Attachments
Last edited: