.htaccess
1 year ago
License.php
1 year ago
LicenseLocalKey.php
1 year ago
index.html
1 year ago
web.config
1 year ago
License.php
229 lines
| 1 | <?php |
| 2 | |
| 3 | namespace JetBackup\License; |
| 4 | |
| 5 | |
| 6 | use Exception; |
| 7 | use JetBackup\Alert\Alert; |
| 8 | use JetBackup\Exception\HttpRequestException; |
| 9 | use JetBackup\Exception\IOException; |
| 10 | use JetBackup\Exception\LicenseException; |
| 11 | use JetBackup\Factory; |
| 12 | use JetBackup\Web\JetHttp; |
| 13 | use JetBackup\Wordpress\Wordpress; |
| 14 | |
| 15 | if (!defined( '__JETBACKUP__')) die('Direct access is not allowed'); |
| 16 | |
| 17 | class License { |
| 18 | |
| 19 | const LICENSE_CHECK_URL = "https://check-v3.jetlicense.com/v2/"; |
| 20 | const LOCALKEY_DAYS = 259200; // 3 days |
| 21 | const LOCALKEY_CHECK_INTERVAL = 172800; // 2 days |
| 22 | const LOCALKEY_FAIL_INTERVAL = 3540; // 59 minutes |
| 23 | const NOTIFY_ERROR_INTERVAL = 21600; // 6 hours |
| 24 | const LICENSE_PRODUCT_ID = "67bc74749a80571ed902c792"; |
| 25 | const LIST_PRODUCT_ID = [ |
| 26 | self::LICENSE_PRODUCT_ID, // Production |
| 27 | '63cd2f8bba4b3903835787dc', // Solo |
| 28 | '63cd2fd30c422d43a55ea0da', // Admin |
| 29 | '63cd30220c422d43a55ea0db', // Pro |
| 30 | '64e60930438e804c0a6c1603', // Pro 100 |
| 31 | ]; |
| 32 | const PUBLIC_KEY = "-----BEGIN PUBLIC KEY----- |
| 33 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxseSQBDHnTGbSKaS3A2h |
| 34 | CTbvyQpxMw+t/IXfLRZx+xdwFO7iFx/8nYVxgxbv/Typkq7uomJ/cqxnCrWT6Arz |
| 35 | 5OoMgwsiLq0qMb4fXErsBrNt7v4F5AyGzLizVQXnQw06TpXdqYzud/MsfPQFTQKM |
| 36 | p7LDbYO0zSxj9b12Q2cj4Bq5cwvAHDmSasDcLSI7FVqrohTCEKU4/AegFSzGbma3 |
| 37 | 2mHcENyaFkT4m7fhQ0EbaFTrBw2/vW63TqJy6B71P+6q68dh5s2stwxcogN0Nx62 |
| 38 | BPdaHxatGIXJYvxCHDHnFaPuCyZCXWHmOb1j84cuJU28DMiTDSG6g04lp/WRLuq9 |
| 39 | EwIDAQAB |
| 40 | -----END PUBLIC KEY-----"; |
| 41 | |
| 42 | const STATUS_ACTIVE = "Active"; |
| 43 | const STATUS_INVALID = "Invalid"; |
| 44 | |
| 45 | /** |
| 46 | * @param string $error |
| 47 | * |
| 48 | * @return void |
| 49 | * @throws IOException |
| 50 | */ |
| 51 | private static function _addAlert(string $error):void { |
| 52 | $settings = Factory::getConfig(); |
| 53 | |
| 54 | if($settings->getLicenseNotifyDate()) { |
| 55 | if($settings->getLicenseNotifyDate() > (time()-self::NOTIFY_ERROR_INTERVAL)) return; |
| 56 | Alert::add("License check failed", "There was a failed license check. Error: $error. Please visit the following link for more information https://docs.jetbackup.com/licensing_issue_notification.html", Alert::LEVEL_CRITICAL); |
| 57 | } |
| 58 | |
| 59 | $settings->setLicenseNotifyDate(time()); |
| 60 | $settings->save(); |
| 61 | } |
| 62 | |
| 63 | private static function _fetchLicense($product_id, $licenseKey, $domain) { |
| 64 | |
| 65 | $public_key = openssl_get_publickey(static::PUBLIC_KEY); |
| 66 | |
| 67 | if(!openssl_public_encrypt($licenseKey, $key_encrypted, $public_key)) |
| 68 | throw new LicenseException("Unable to prepare license key for validation"); |
| 69 | |
| 70 | try { |
| 71 | $response = JetHttp::request() |
| 72 | ->setMethod(JetHttp::METHOD_POST) |
| 73 | ->setTimeout(30) |
| 74 | ->setReturnTransfer() |
| 75 | ->setBody(http_build_query([ |
| 76 | 'output' => 'json', |
| 77 | 'license_key' => base64_encode($key_encrypted), |
| 78 | 'product_id' => $product_id, |
| 79 | 'domain' => $domain, |
| 80 | ])) |
| 81 | ->exec(self::LICENSE_CHECK_URL); |
| 82 | } catch(HttpRequestException $e) { |
| 83 | throw new LicenseException( "Failed checking license (" . self::LICENSE_CHECK_URL . "). Error: " . $e->getMessage()); |
| 84 | } |
| 85 | |
| 86 | if($response->getHeaders()->getCode() !== 200 || !($data = $response->getBody())) |
| 87 | throw new LicenseException( "Could not resolve host (" . self::LICENSE_CHECK_URL . ")"); |
| 88 | |
| 89 | $result = json_decode($data, true); |
| 90 | |
| 91 | if($result === false) |
| 92 | throw new LicenseException("No valid response received from the license server"); |
| 93 | |
| 94 | if(!$result['success'] || !$result['data']['localkey']) |
| 95 | throw new LicenseException("Invalid response from licensing server: {$result['message']}"); |
| 96 | |
| 97 | $localKey = $result['data']['localkey']; |
| 98 | |
| 99 | $newLocalKeyDetails = new LicenseLocalKey($localKey); |
| 100 | |
| 101 | $signed = $newLocalKeyDetails->getSigned() ? base64_decode($newLocalKeyDetails->getSigned()) : ''; |
| 102 | $signed_key = sha1(intval(time() / self::LOCALKEY_DAYS), true); |
| 103 | |
| 104 | if(!openssl_verify($signed_key, $signed, $public_key, OPENSSL_ALGO_SHA256)) |
| 105 | throw new LicenseException( "Failed validating license. " . ($newLocalKeyDetails->getDescription() ? " The error returned from our licensing server: \"" . $newLocalKeyDetails->getDescription() . "\"" : '') . "<br />Please contact your JetApps license provider if you need to reissue your license"); |
| 106 | |
| 107 | return $localKey; |
| 108 | } |
| 109 | |
| 110 | /** |
| 111 | * @param string|null $licenseKey |
| 112 | * |
| 113 | * @return void |
| 114 | * @throws IOException |
| 115 | * @throws LicenseException |
| 116 | */ |
| 117 | public static function retrieveLocalKey(?string $licenseKey=null) { |
| 118 | $config = Factory::getConfig(); |
| 119 | |
| 120 | $localKeyDetails = new LicenseLocalKey(); |
| 121 | |
| 122 | if(!$licenseKey) $licenseKey = $config->getLicenseKey(); |
| 123 | |
| 124 | if (!$licenseKey) { |
| 125 | $config->setLicenseLocalKey(''); |
| 126 | $config->setLicenseLastCheck(time()); |
| 127 | $config->setLicenseNextCheck(time() + self::LOCALKEY_CHECK_INTERVAL); |
| 128 | $config->save(); |
| 129 | return; |
| 130 | } |
| 131 | |
| 132 | try { |
| 133 | |
| 134 | $domain = Wordpress::getSiteDomain(); |
| 135 | if (!$domain) throw new LicenseException('Cannot find domain'); |
| 136 | $domain = preg_replace('/^www\./', '', $domain); |
| 137 | |
| 138 | $exception = null; |
| 139 | |
| 140 | foreach(self::LIST_PRODUCT_ID as $product_id) { |
| 141 | |
| 142 | try { |
| 143 | $localKey = self::_fetchLicense($product_id, $licenseKey, $domain); |
| 144 | $exception = null; |
| 145 | break; |
| 146 | } catch(LicenseException $e) { |
| 147 | $exception = $e; |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | if($exception) throw $exception; |
| 152 | |
| 153 | $config->setLicenseNotifyDate(); |
| 154 | $config->setLicenseLocalKey($localKey); |
| 155 | $config->setLicenseLastCheck(time()); |
| 156 | $config->setLicenseNextCheck(time() + self::LOCALKEY_CHECK_INTERVAL); |
| 157 | $config->save(); |
| 158 | |
| 159 | } catch(LicenseException $e) { |
| 160 | self::_addAlert($e->getMessage()); |
| 161 | $config->setLocalKeyInvalid($e->getMessage(), $localKeyDetails); |
| 162 | $config->save(); |
| 163 | throw $e; |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * @throws LicenseException |
| 169 | * @throws Exception |
| 170 | */ |
| 171 | public static function checkLocalKey() { |
| 172 | |
| 173 | $settings = Factory::getConfig(); |
| 174 | |
| 175 | if(!$settings->getLicenseKey()) |
| 176 | throw new LicenseException("No license key found"); |
| 177 | |
| 178 | $localKey = new LicenseLocalKey(); |
| 179 | |
| 180 | if(!$localKey->getLocalKey()) |
| 181 | throw new LicenseException("LocalKey is empty"); |
| 182 | |
| 183 | $status = $localKey->getStatus() ?: self::STATUS_INVALID; |
| 184 | $description = $localKey->getDescription() ?? ''; |
| 185 | $public_key = openssl_get_publickey(static::PUBLIC_KEY); |
| 186 | |
| 187 | $modulo = $settings->getLicenseLastCheck() % self::LOCALKEY_DAYS; |
| 188 | $signed = $localKey->getSignedStatus() ? base64_decode($localKey->getSignedStatus()) : ''; |
| 189 | $signed_key = sha1(intval((time() - $modulo) / self::LOCALKEY_DAYS) . self::STATUS_ACTIVE, true); |
| 190 | |
| 191 | if(!openssl_verify($signed_key, $signed, $public_key, OPENSSL_ALGO_SHA256)) { |
| 192 | if($status == self::STATUS_ACTIVE || ($status == self::STATUS_INVALID && !$description)) { |
| 193 | $description = "Cannot find valid license. " . ($description ? " Error: $description." : '') . " Please visit the following link for more information https://docs.jetbackup.com/licensing_issue_notification.html"; |
| 194 | $settings->setLocalKeyInvalid($description, $localKey); |
| 195 | $settings->setLicenseNextCheck(); |
| 196 | $settings->save(); |
| 197 | } |
| 198 | throw new LicenseException($description, $status); |
| 199 | } |
| 200 | } |
| 201 | |
| 202 | /** |
| 203 | * @return string |
| 204 | * @throws Exception |
| 205 | */ |
| 206 | public static function getLicenseStatus():string { |
| 207 | try { |
| 208 | self::checkLocalKey(); |
| 209 | } catch(LicenseException $e) { |
| 210 | return $e->getStatus(); |
| 211 | } |
| 212 | |
| 213 | return self::STATUS_ACTIVE; |
| 214 | } |
| 215 | |
| 216 | /** |
| 217 | * @return bool |
| 218 | */ |
| 219 | public static function isValid():bool { |
| 220 | |
| 221 | try { |
| 222 | self::checkLocalKey(); |
| 223 | } catch(Exception $e) { |
| 224 | return false; |
| 225 | } |
| 226 | |
| 227 | return true; |
| 228 | } |
| 229 | } |