the browser-facing portion of osu!
at master 2.5 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6declare(strict_types=1); 7 8namespace App\Models; 9 10use App\Traits\Validatable; 11use Cache; 12use Illuminate\Database\Eloquent\Builder; 13use Illuminate\Database\Eloquent\Relations\BelongsTo; 14 15/** 16 * @property string $api_key 17 * @property string $app_name 18 * @property string $app_url 19 * @property int $enabled 20 * @property int $hit_count 21 * @property int $key 22 * @property int $miss_count 23 * @property int $revoked 24 * @property-read User|null $user 25 * @property int $user_id 26 */ 27class ApiKey extends Model 28{ 29 use Validatable; 30 31 const MAX_FIELD_LENGTHS = [ 32 'app_name' => 100, 33 'app_url' => 512, 34 ]; 35 36 public $casts = [ 37 'revoked' => 'boolean', 38 ]; 39 public $timestamps = false; 40 41 protected $table = 'osu_apikeys'; 42 protected $primaryKey = 'key'; 43 44 public function user(): BelongsTo 45 { 46 return $this->belongsTo(User::class, 'user_id'); 47 } 48 49 public function scopeAvailable(Builder $query): Builder 50 { 51 return $query->where('revoked', false); 52 } 53 54 public function isValid(): bool 55 { 56 $this->validationErrors()->reset(); 57 58 $this->validateDbFieldLengths(); 59 60 foreach (['app_name', 'api_key'] as $field) { 61 if (!present($this->$field)) { 62 $this->validationErrors()->add($field, 'required'); 63 } 64 } 65 66 if (!filter_var($this->app_url ?? '', FILTER_VALIDATE_URL)) { 67 $this->validationErrors()->add('app_url', 'url'); 68 } 69 70 if (!$this->exists && static::where(['user_id' => $this->user_id])->available()->exists()) { 71 $this->validationErrors()->add('base', '.exists'); 72 } 73 74 return $this->validationErrors()->isEmpty(); 75 } 76 77 public function save(array $options = []) 78 { 79 // Prevent multiple isValid check from running simultaneously 80 // as it checks for some sort of uniqueness without database 81 // constraint. 82 $lock = Cache::lock("legacy_api_key_store:{$this->user_id}", 600); 83 84 try { 85 $lock->block(5); 86 87 return $this->isValid() && parent::save($options); 88 } finally { 89 $lock->release(); 90 } 91 } 92 93 public function validationErrorsTranslationPrefix(): string 94 { 95 return 'legacy_api_key'; 96 } 97}