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 }