/ app / Http / Services / KeyService.php
KeyService.php
  1  <?php
  2  
  3  namespace App\Http\Services;
  4  
  5  use App\Models\Entity;
  6  use App\Models\GpgKey;
  7  use App\Models\User;
  8  use Carbon\Carbon;
  9  use Crypt_GPG;
 10  use Crypt_GPG_SubKey;
 11  use Crypt_GPG_UserId;
 12  use Exception;
 13  use Illuminate\Support\Facades\DB;
 14  
 15  class KeyService
 16  {
 17  
 18      /**
 19       * Display all keys for a specific user.
 20       *
 21       * @param int $entityId
 22       * @param string $entityType
 23       * @return GpgKey[]|\Illuminate\Database\Eloquent\Collection
 24       */
 25      public static function getKeys(int $entityId, string $entityType)
 26      {
 27          return GpgKey::where('entity_id', $entityId)
 28              ->where('entity_type', $entityType == 'entity' ? Entity::class : User::class)
 29              ->get();
 30      }
 31  
 32      /**
 33       * Create a resource
 34       *
 35       * @param int $entityId
 36       * @param string $entityType
 37       * @param string $public_gpg_key
 38       * @return bool|Exception
 39       * @throws \Throwable
 40       */
 41      public static function create(int $entityId, string $entityType, string $ascii_key, string $passphrase = null): bool|Exception
 42      {
 43          try {
 44              DB::beginTransaction();
 45              if (isset($_ENV['argv'])) {
 46                  unset($_ENV['argv']);
 47              }
 48  
 49              // Import the key to keystore and get key data
 50              $importKey = self::importGpgKey($ascii_key, $passphrase);
 51  
 52              $class = $entityType == 'entity' ? Entity::class : User::class;
 53              $class::find($entityId)->activeKey()->delete();
 54  
 55              // Add key info to database and relate with user
 56              GpgKey::create([
 57                  'entity_id' => $entityId,
 58                  'entity_type' => $class,
 59                  'key_id' => $importKey['key_id'],
 60                  'key_fingerprint' => $importKey['key_fingerprint'],
 61                  'key_created_at' => Carbon::createFromTimestamp($importKey['key_created_at'])->toDateTimeString(),
 62                  'key_expiration_at' => $importKey['key_expiration_at'] ? Carbon::createFromTimestamp($importKey['key_expiration_at'])->toDateTimeString() : null,
 63                  'key_algorithm' => GpgKey::getAlgorithmName($importKey['key_algorithm']),
 64                  'key_length' => $importKey['key_length'],
 65                  'key_name' => $importKey['key_name'],
 66                  'key_email' => $importKey['key_email'],
 67                  'key_comment' => $importKey['key_comment'],
 68                  'key_passphrase' => $passphrase,
 69              ]);
 70  
 71              DB::commit();
 72  
 73              return true;
 74          } catch (Exception $e) {
 75              DB::rollBack();
 76              throw $e;
 77          }
 78      }
 79  
 80      protected static function importGpgKey(string $public_gpg_key, string $passphrase = null): array|null
 81      {
 82          if (isset($_ENV['argv'])) {
 83              unset($_ENV['argv']);
 84          }
 85  
 86          $gpg = new Crypt_GPG(['homedir' => config('gpg.homedir')]);
 87  
 88          $importKey = $gpg->importKey($public_gpg_key);
 89          if ($passphrase) {
 90              $gpg->addPassphrase($importKey['fingerprint'], $passphrase);
 91              $gpg->exportPrivateKey($importKey['fingerprint']);
 92          }
 93  
 94          if ($importKey['public_unchanged']) {
 95              GpgKey::where('key_fingerprint', $importKey['fingerprint'])->delete();
 96          }
 97  
 98          $importedKey = $gpg->getKeys($importKey['fingerprint']);
 99          $user = new Crypt_GPG_UserId($importedKey[0]->getUserIds()[0]);
100          $key = new Crypt_GPG_SubKey($importedKey[0]->getPrimaryKey());
101  
102          return [
103              'key_id' => $key->getId(),
104              'key_created_at' => $key->getCreationDate(),
105              'key_expiration_at' => $key->getExpirationDate(),
106              'key_fingerprint' => $key->getFingerprint(),
107              'key_algorithm' => $key->getAlgorithm(),
108              'key_length' => $key->getLength(),
109              'key_name' => $user->getName(),
110              'key_email' => $user->getEmail(),
111              'key_comment' => $user->getComment(),
112          ];
113      }
114  
115      /**
116       * @param int $keyId
117       * @return void
118       * @throws \Throwable
119       */
120      public static function remove(int $keyId): void
121      {
122          try {
123              DB::beginTransaction();
124  
125              if (isset($_ENV['argv'])) {
126                  unset($_ENV['argv']);
127              }
128  
129              // Create object
130              $gpg = new Crypt_GPG(['homedir' => config('gpg.homedir')]);
131  
132              // Find from database
133              $dbKey = GpgKey::findOrFail($keyId);
134  
135              // Delete GPG key from keystore
136              if ($keys = $gpg->getKeys($dbKey->key_id)) {
137                  try {
138                      $gpg->deletePrivateKey($dbKey->key_id);
139                  } catch (Exception $e) {
140                      logger()->info("Clave privada GPG ID {$dbKey->key_id} no encontrada en el keyring.");
141                  }
142  
143                  try {
144                      $gpg->deletePublicKey($dbKey->key_id);
145                  } catch (Exception $e) {
146                      logger()->info("Clave pública GPG ID {$dbKey->key_id} no encontrada en el keyring.");
147                  }
148              }
149  
150              // Delete from database
151              GpgKey::destroy($keyId);
152  
153              DB::commit();
154          } catch (Exception $e) {
155              DB::rollBack();
156              throw new Exception($e->getMessage());
157          }
158      }
159  }