diff --git a/src/app/Http/Controllers/Controller.php b/src/app/Http/Controllers/Controller.php index 68aebaf..6a20f3c 100644 --- a/src/app/Http/Controllers/Controller.php +++ b/src/app/Http/Controllers/Controller.php @@ -1,255 +1,253 @@ generateCert("test", "test", Carbon::now()->addDays(1)); } catch (\Exception $e) { - print("Caught an error\n"); + \Log::warning("Caught an error: " . $e->getMessage()); return response()->json(["status" => 'FAILURE', "message" => "Certificate signing failed."], 500); } return response()->json(["status" => 'OK']); } private function generateCert(string $comment, string $systemUuid, Carbon $expirationDate) { //Reset errors while (openssl_error_string() != null); // We use 2048 bits because the Plesk Key Administrator does not support license // key bodies larger than 4000 bytes. $dn = [ "countryName" => "CH", "stateOrProvinceName" => "Zurich", "organizationName" => "Apheleia IT AG", "organizationalUnitName" => "Product Sales", "commonName" => $systemUuid, "emailAddress" => "contact@apheleia-it.ch", ]; // $privkey = openssl_pkey_new([ "private_key_bits" => 2048, "private_key_type" => OPENSSL_KEYTYPE_RSA ]); $csr = openssl_csr_new($dn, $privkey, ['digest_alg' => 'sha256']); $contents = file_get_contents('/etc/ssl/openssl.cnf'); $contents = $contents . " [custom] basicConstraints=CA:FALSE subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer nsComment = \"$comment\" "; $tmpFile = \tempnam("/tmp", "OPENSSLCNF"); file_put_contents($tmpFile, $contents); $validForDays = Carbon::now()->diffInDays($expirationDate, false); if ($validForDays <= 0) { throw new \Exception("Expiration date is in the past"); } $caCert = \config("app.ca_cert"); $caPrivateKey = \config("app.ca_private_key"); - print("\n"); - var_export($caCert); - print("\n"); + \Log::info(var_export($caCert)); $x509 = openssl_csr_sign($csr, $caCert, $caPrivateKey, $validForDays, [ 'digest_alg' => 'sha256', 'x509_extensions' => 'custom', 'config' => $tmpFile ] ); if (!$x509) { - print("Failed to sign\n"); + \Log::warning("Failed to sign\n"); throw new \Exception("Failed to sign"); } // Save your private key, CSR and self-signed cert for later use // openssl_csr_export($csr, $csrout) and var_dump($csrout); if (!openssl_x509_export($x509, $certout)) { throw new \Exception("Failed to export the certificate"); } if (!openssl_pkey_export($privkey, $pkeyout)) { throw new \Exception("Failed to export the key"); } $errors = ""; while ($msg = openssl_error_string()) { $errors .= $msg; } if (!empty($errors)) { - print($errors); + \Log::warning($errors); throw new \Exception("Errors while signing: $errors"); } return $certout . $pkeyout; } const PRODUCT_PREFIXES = ['PLESK', 'NFR', 'COLLABORA']; private function validateProductId(string $productId) { foreach (self::PRODUCT_PREFIXES as $prefix) { if ((bool)preg_match("/^$prefix-[0-9]*$/", $productId)) { return true; } } return false; } private function numUsersFromProduct(string $productId) { $numUsers = $productId; foreach (self::PRODUCT_PREFIXES as $prefix) { $numUsers = str_replace("$prefix-", '', $numUsers); } if (!is_numeric($numUsers)) { throw new \Exception("Failed to extract number of users from product: $productId"); } return intval($numUsers); } private function updateLicense(\App\Models\License $license, $object, string $idempotencyKey) { if (\App\Models\License::where('idempotency_key', $idempotencyKey)->exists()) { throw new \Exception("Idempotency key already exists: $idempotencyKey"); } $productId = $object['productId']; if (empty($productId)) { throw new \Exception("No product id."); } if (!$this->validateProductId($productId)) { throw new \Exception("Invalid product id."); } $numUsers = $this->numUsersFromProduct($productId); $comment = base64_encode( json_encode(['users' => $numUsers, 'nfr' => $object['nfr']]) ); $license->key_id = $object['keyId']; $license->num_licenses = $numUsers; $license->product_id = $object['productId']; $license->status = $object['status']; $license->creation_date = Carbon::parse($object['creationDate']); $license->expiration_date = Carbon::parse($object['expirationDate']); $license->idempotency_key = $idempotencyKey; $license->owner_id = $object['owner']['id']; $license->nfr = $object['nfr']; $license->body = $this->generateCert($comment, 'PLESK' . $license->shortId(), $license->expiration_date); } public function createKey(Request $request) { $testMode = $request->testMode == 'true'; $idempotencyKey = $request->idempotencyKey; $object = $request->except(['testMode', 'idempotencyKey']); $license = new \App\Models\License(); $this->updateLicense($license, $object, $idempotencyKey); if (!$testMode) { $license->save(); } $object['body'] = $license->body; return response()->json($object); } private function serializeLicense(\App\Models\License $license) { return [ "keyId" => $license->key_id, "productId" => $license->product_id, "status" => $license->status, "body" => $license->body, "creationDate" => $license->creation_date->format('Y-m-d\TH:i:s.vp'), "operationDate" => Carbon::now()->format('Y-m-d\TH:i:s.vp'), "expirationDate" => $license->expiration_date->format('Y-m-d\TH:i:s.vp'), "owner" => [ "id" => $license->owner_id ], "nfr" => (bool)$license->nfr ]; } public function getKey(Request $request, string $keyId) { if (!is_numeric($keyId)) { return abort(404); } $keyId = (int)$keyId; $license = \App\Models\License::where('key_id', $keyId)->first(); if (!$license) { return abort(404); } return response()->json($this->serializeLicense($license)); } public function updateKey(Request $request, string $keyId) { if (!is_numeric($keyId)) { return abort(404); } $keyId = (int)$keyId; $license = \App\Models\License::withTrashed()->where('key_id', $keyId)->first(); if (!$license) { return abort(404); } $testMode = $request->testMode == 'true'; $idempotencyKey = $request->idempotencyKey; $object = $request->except(['testMode', 'idempotencyKey']); if ($license->trashed() && $object['status'] != \App\Models\License::STATUS_TERMINATED) { $license->restore(); } $this->updateLicense($license, $object, $idempotencyKey); if (!$testMode) { $license->save(); } $object['body'] = $license->body; return response()->json($object); } public function deleteKey(Request $request, string $keyId) { if (!is_numeric($keyId)) { return abort(404); } $keyId = (int)$keyId; $license = \App\Models\License::where('key_id', $keyId)->first(); if (!$license) { return abort(404); } $license->status = \App\Models\License::STATUS_TERMINATED; $license->save(); $license->delete(); } }