diff --git a/cache/timer.yaml b/cache/timer.yaml index b69662f..89a2f7f 100644 --- a/cache/timer.yaml +++ b/cache/timer.yaml @@ -1 +1 @@ -licenseupdate: 1740428318 +licenseupdate: 1743303388 diff --git a/system/typemill/Models/ApiCalls.php b/system/typemill/Models/ApiCalls.php index 815bc61..eb58354 100644 --- a/system/typemill/Models/ApiCalls.php +++ b/system/typemill/Models/ApiCalls.php @@ -45,7 +45,12 @@ class ApiCalls } $curl = curl_init($url); + if (defined('CURLSSLOPT_NATIVE_CA') && version_compare(curl_version()['version'], '7.71', '>=')) + { + curl_setopt($curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA); + } curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_TIMEOUT, 5); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); if ($method === 'POST' && $data) { @@ -58,17 +63,19 @@ class ApiCalls curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata); curl_setopt($curl, CURLOPT_POST, true); } - curl_setopt($curl, CURLOPT_FAILONERROR, true); +# curl_setopt($curl, CURLOPT_FAILONERROR, true); $response = curl_exec($curl); if ($response === false) { $this->error = curl_error($curl); + curl_close($curl); + return false; } - curl_close($curl); - return $response !== false ? $response : false; + curl_close($curl); + return $response; } private function makeFileGetContentsCall($url, $method, $data = null, $authHeader = '') @@ -108,9 +115,22 @@ class ApiCalls if ($response === false) { - $this->error = 'file_get_contents failed for ' . $method . ' request.'; + if (!empty($http_response_header) && isset($http_response_header[0])) + { + $parts = explode(' ', $http_response_header[0], 3); + $status_code = $parts[1] ?? 'Unknown'; + $msg = $parts[2] ?? 'No status message'; + + $this->error = Translations::translate('We got an error from file_get_contents: ') . $status_code . ' ' . $msg; + } + else + { + $this->error = Translations::translate('No HTTP response received or file_get_contents is blocked.'); + } + + return false; } - return $response !== false ? $response : false; + return $response; } } diff --git a/system/typemill/Models/License.php b/system/typemill/Models/License.php index 9d1c74f..213a917 100644 --- a/system/typemill/Models/License.php +++ b/system/typemill/Models/License.php @@ -3,6 +3,7 @@ namespace Typemill\Models; use Typemill\Models\StorageWrapper; +use Typemill\Models\ApiCalls; use Typemill\Static\Translations; class License @@ -108,7 +109,31 @@ class License if(!$subscriptionPaid) { $storage = new StorageWrapper('\Typemill\Models\Storage'); - if(!$forceUpdateCheck && !$storage->timeoutIsOver('licenseupdate', 3600)) + $timeoutIsOver = $storage->timeoutIsOver('licenseupdate', 3600); + $storageError = $storage->getError(); + + if($storageError) + { + $this->message = Translations::translate($storageError) . $this->message; + + return false; + } + + $backtrace = debug_backtrace(); + $callingMethod = isset($backtrace[1]['function']) ? $backtrace[1]['function'] : 'Unknown'; + +/* + echo '

method: '; + echo $callingMethod; + echo '
force: '; + var_dump($forceUpdateCheck); + echo '
timer: '; + var_dump($timeoutIsOver); + + $forceUpdateCheck = false; +*/ + + if(!$forceUpdateCheck && $timeoutIsOver === false) { $this->message = Translations::translate('The subscription period has not been paid yet. We will check it every 60 minutes.') . $this->message; @@ -246,7 +271,7 @@ class License # make remote check on the license server $url = 'https://service.typemill.net/api/v1/licensecheck'; - $remoteCheck = $this->callLicenseServer($licensedata, $url); + $remoteCheck = $this->callLicenseServer($licensedata, $url, 'remoteCheck'); if(isset($remoteCheck['status']) && $remoteCheck['status']) { @@ -287,7 +312,7 @@ class License ksort($licensedata); # test manipulate data - # $licensedata['plan'] = 'wrong'; +# $licensedata['plan'] = 'wrong'; # Check signature $public_key_pem = $this->getPublicKeyPem(); @@ -331,7 +356,7 @@ class License { # make the call to the license server $url = 'https://service.typemill.net/api/v1/testcall'; - $testcall = $this->callLicenseServer(['test' => 'test'], $url); + $testcall = $this->callLicenseServer(['test' => 'test'], $url, 'testLicensecall'); if(!$testcall) { @@ -354,7 +379,7 @@ class License # make the call to the license server $url = 'https://service.typemill.net/api/v1/activate'; - $signedLicense = $this->callLicenseServer($licensedata, $url); + $signedLicense = $this->callLicenseServer($licensedata, $url, 'activateLicense'); if(!$signedLicense) { @@ -391,7 +416,7 @@ class License # make the call to the license server $url = 'https://service.typemill.net/api/v1/update'; - $signedLicense = $this->callLicenseServer($licensedata, $url); + $signedLicense = $this->callLicenseServer($licensedata, $url, 'updateLicense'); if(!$signedLicense) { @@ -461,7 +486,7 @@ class License $url = 'https://service.typemill.net/api/v1/gettoken'; - $tokenresponse = $this->callLicenseServer($licensedata, $url); + $tokenresponse = $this->callLicenseServer($licensedata, $url, 'getToken'); if($tokenresponse && isset($tokenresponse['token']) && $tokenresponse['token']) { @@ -473,14 +498,53 @@ class License return false; } - private function callLicenseServer( $licensedata, $url ) + private function callLicenseServer( $licensedata, $url, $from ) + { + $authstring = $this->getPublicKeyPem(); + +# echo '
license server call from: ' . $from; + + if(!$authstring) + { + $this->message = Translations::translate('Please check if there is a readable file public_key.pem in your settings folder.'); + + return false; + } + + $authstring = hash('sha256', substr($authstring, 0, 50)); + $authHeader = "Authorization: " . $authstring; + + $apiservice = new ApiCalls(); + $apiResponse = $apiservice->makePostCall($url, $licensedata, $authHeader); + + if (!$apiResponse) + { + $error = $apiservice->getError(); + $this->message = 'ApiCallError: ' . Translations::translate($error); + + return false; + } + + $responseJson = json_decode($apiResponse, true); + + if(isset($responseJson['code'])) + { + $this->message = 'LicenseServerError: ' . $responseJson['code']; + + return false; + } + + return $responseJson; + } + + private function callLicenseServerOld( $licensedata, $url ) { $authstring = $this->getPublicKeyPem(); if(!$authstring) { $this->message = Translations::translate('Please check if there is a readable file public_key.pem in your settings folder.'); - + return false; } @@ -499,7 +563,8 @@ class License curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata); curl_setopt($curl, CURLOPT_HTTPHEADER, array( - "Content-Type: application/x-www-form-urlencoded", +# "Content-Type: application/x-www-form-urlencoded", + "Content-Type: application/json", "Accept: application/json", "Authorization: $authstring", "Connection: close" diff --git a/system/typemill/Models/Storage.php b/system/typemill/Models/Storage.php index 63bcb26..54cf2e1 100644 --- a/system/typemill/Models/Storage.php +++ b/system/typemill/Models/Storage.php @@ -496,11 +496,15 @@ class Storage $folder = ''; $filename = 'timer.yaml'; - // Get current timers from the YAML file, if it exists - $timers = $this->getYaml($location, $folder, $filename) ?: []; + if(!$this->checkFolder('cacheFolder')) + { + return false; + } - $currentTime = time(); - $timeThreshold = $currentTime - $timespan; + // Get current timers from the YAML file, if it exists + $currentTime = time(); + $timeThreshold = $currentTime - $timespan; + $timers = $this->getYaml($location, $folder, $filename) ?: []; # Check if the name exists and if the timestamp is older than the current time minus the timespan if (!isset($timers[$name]) || !is_numeric($timers[$name]) || $timers[$name] <= $timeThreshold) @@ -511,6 +515,11 @@ class Storage # Update the YAML file with the new or updated timer $this->updateYaml($location, $folder, $filename, $timers); + if($this->error) + { + return false; + } + return true; } diff --git a/system/typemill/author/js/vue-license.js b/system/typemill/author/js/vue-license.js index 9294924..af4eb9e 100644 --- a/system/typemill/author/js/vue-license.js +++ b/system/typemill/author/js/vue-license.js @@ -111,7 +111,7 @@ const app = Vue.createApp({ self.disabled = false; self.message = handleErrorMessage(error); self.messageClass = 'bg-rose-500'; - self.licensemessage = error.response.data.message; + self.licensemessage = self.licensemessage + ' ' + error.response.data.message; if(error.response.data.errors !== undefined) { self.errors = error.response.data.errors;