The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. /**
  18. A base class for online unlocking systems.
  19. This class stores information about whether your app has been unlocked for the
  20. current machine, and handles communication with a web-store to perform the
  21. unlock procedure.
  22. You probably won't ever use this base class directly, but rather a store-specific
  23. subclass such as TracktionMarketplaceStatus, which knows how to talk to the particular
  24. online store that you're using.
  25. To use it, you create a subclass which implements all the pure virtual methods
  26. (see their comments to find out what you'll need to make them do).
  27. Then you can create an instance of your subclass which will hold the registration
  28. state. Typically, you'll want to just keep a single instance of the class around for
  29. the duration of your app. You can then call its methods to handle the various
  30. registration tasks.
  31. Areas of your code that need to know whether the user is registered (e.g. to decide
  32. whether a particular feature is available) should call isUnlocked() to find out.
  33. If you want to create a GUI that allows your users to enter their details and
  34. register, see the OnlineUnlockForm class.
  35. @see OnlineUnlockForm, KeyGeneration
  36. */
  37. class JUCE_API OnlineUnlockStatus
  38. {
  39. public:
  40. OnlineUnlockStatus();
  41. /** Destructor. */
  42. virtual ~OnlineUnlockStatus();
  43. //==============================================================================
  44. /** This must return your product's ID, as allocated by the store. */
  45. virtual String getProductID() = 0;
  46. /** This must check whether a product ID string that the server returned is OK for
  47. unlocking the current app.
  48. */
  49. virtual bool doesProductIDMatch (const String& returnedIDFromServer) = 0;
  50. /** This must return the RSA public key for authenticating responses from
  51. the server for this app. You can get this key from your marketplace
  52. account page.
  53. */
  54. virtual RSAKey getPublicKey() = 0;
  55. /** This method must store the given string somewhere in your app's
  56. persistent properties, so it can be retrieved later by getState().
  57. */
  58. virtual void saveState (const String&) = 0;
  59. /** This method must retrieve the last state that was provided by the
  60. saveState method.
  61. On first-run, it should just return an empty string.
  62. */
  63. virtual String getState() = 0;
  64. /** Returns the name of the web-store website, not for communication, but for
  65. presenting to the user.
  66. */
  67. virtual String getWebsiteName() = 0;
  68. /** Returns the URL of the authentication API. */
  69. virtual URL getServerAuthenticationURL() = 0;
  70. /** Subclasses that talk to a particular web-store will implement this method
  71. to contact their webserver and attempt to unlock the current machine for
  72. the given username and password. The return value is the XML text from the
  73. server which contains error information and/or the encrypted keyfile.
  74. */
  75. virtual String readReplyFromWebserver (const String& email, const String& password) = 0;
  76. /** Returns a list of strings, any of which should be unique to this
  77. physical computer.
  78. When testing whether the user is allowed to use the product on this
  79. machine, this list of tokens is compared to the ones that were stored
  80. on the webserver.
  81. The default implementation of this method will simply call
  82. MachineIDUtilities::getLocalMachineIDs(), which provides a default
  83. version of this functionality.
  84. */
  85. virtual StringArray getLocalMachineIDs();
  86. //==============================================================================
  87. // The following methods can be called by your app:
  88. /** Returns true if the product has been successfully authorised for this machine.
  89. The reason it returns a variant rather than a bool is just to make it marginally
  90. more tedious for crackers to work around. Hopefully if this method gets inlined
  91. they'll need to hack all the places where you call it, rather than just the
  92. function itself.
  93. Bear in mind that each place where you check this return value will need to be
  94. changed by a cracker in order to unlock your app, so the more places you call this
  95. method, the more hassle it will be for them to find and crack them all.
  96. */
  97. inline var isUnlocked() const { return status[unlockedProp]; }
  98. /** Returns the Time when the keyfile expires.
  99. If a the key file obtained has an expiry time, isUnlocked will return false and this
  100. will return a non-zero time. The interpretation of this is up to your app but could
  101. be used for subscription based models or trial periods.
  102. */
  103. inline Time getExpiryTime() const { return Time (static_cast<int64> (status[expiryTimeProp])); }
  104. /** Optionally allows the app to provide the user's email address if
  105. it is known.
  106. You don't need to call this, but if you do it may save the user
  107. typing it in.
  108. */
  109. void setUserEmail (const String& usernameOrEmail);
  110. /** Returns the user's email address if known. */
  111. String getUserEmail() const;
  112. /** Attempts to perform an unlock using a block of key-file data provided.
  113. You may wish to use this as a way of allowing a user to unlock your app
  114. by drag-and-dropping a file containing the key data, or by letting them
  115. select such a file. This is often needed for allowing registration on
  116. machines without internet access.
  117. */
  118. bool applyKeyFile (String keyFileContent);
  119. /** This provides some details about the reply that the server gave in a call
  120. to attemptWebserverUnlock().
  121. */
  122. struct UnlockResult
  123. {
  124. /** If an unlock operation fails, this is the error message that the webserver
  125. supplied (or a message saying that the server couldn't be contacted)
  126. */
  127. String errorMessage;
  128. /** This is a message that the webserver returned, and which the user should
  129. be shown.
  130. It's not necessarily an error message, e.g. it might say that there's a
  131. new version of the app available or some other status update.
  132. */
  133. String informativeMessage;
  134. /** If the webserver wants the user to be directed to a web-page for further
  135. information, this is the URL that it would like them to go to.
  136. */
  137. String urlToLaunch;
  138. /** If the unlock operation succeeded, this will be set to true. */
  139. bool succeeded;
  140. };
  141. /** Contacts the webserver and attempts to perform a registration with the
  142. given user details.
  143. The return value will either be a success, or a failure with an error message
  144. from the server, so you should show this message to your user.
  145. Because this method blocks while it contacts the server, you must run it on
  146. a background thread, not on the message thread. For an easier way to create
  147. a GUI to do the unlocking, see OnlineUnlockForm.
  148. */
  149. UnlockResult attemptWebserverUnlock (const String& email, const String& password);
  150. /** Attempts to load the status from the state retrieved by getState().
  151. Call this somewhere in your app's startup code.
  152. */
  153. void load();
  154. /** Triggers a call to saveState which you can use to store the current unlock status
  155. in your app's settings.
  156. */
  157. void save();
  158. /** This class contains some utility functions that might help with machine ID generation. */
  159. struct MachineIDUtilities
  160. {
  161. /** Returns a character that represents the current OS.
  162. E.g. 'M' for Mac, 'W' for windows, etc
  163. */
  164. static char getPlatformPrefix();
  165. /** Returns an encoded hash string from the given input string, prefixing it with
  166. a letter to represent the current OS type.
  167. */
  168. static String getEncodedIDString (const String& inputString);
  169. /** Utility function that you may want to use in your machine-ID generation code.
  170. This adds an ID string to the given array which is a hash of the filesystem ID of the
  171. given file.
  172. */
  173. static bool addFileIDToList (StringArray& result, const File& file);
  174. /** Utility function that you may want to use in your machine-ID generation code.
  175. This adds some ID strings to the given array which represent each MAC address of the machine.
  176. */
  177. static void addMACAddressesToList (StringArray& result);
  178. /** This method calculates some machine IDs based on things like network
  179. MAC addresses, hard-disk IDs, etc, but if you want, you can overload
  180. it to generate your own list of IDs.
  181. The IDs that are returned should be short alphanumeric strings
  182. without any punctuation characters. Since users may need to type
  183. them, case is ignored when comparing them.
  184. Note that the first item in the list is considered to be the
  185. "main" ID, and this will be the one that is displayed to the user
  186. and registered with the marketplace webserver. Subsequent IDs are
  187. just used as fallback to avoid false negatives when checking for
  188. registration on machines which have had hardware added/removed
  189. since the product was first registered.
  190. */
  191. static StringArray getLocalMachineIDs();
  192. };
  193. private:
  194. ValueTree status;
  195. UnlockResult handleXmlReply (XmlElement);
  196. UnlockResult handleFailedConnection();
  197. static const char* unlockedProp;
  198. static const char* expiryTimeProp;
  199. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OnlineUnlockStatus)
  200. };