| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | declare(strict_types = 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Plugin\Pinboard\Entity; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use App\Core\Cache; | 
					
						
							|  |  |  | use App\Core\DB; | 
					
						
							|  |  |  | use App\Core\Entity; | 
					
						
							|  |  |  | use App\Entity\LocalUser; | 
					
						
							|  |  |  | use App\Util\Common; | 
					
						
							|  |  |  | use DateTimeInterface; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Token extends Entity | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     // {{{ Autocode
 | 
					
						
							|  |  |  |     // @codeCoverageIgnoreStart
 | 
					
						
							|  |  |  |     private int $actor_id; | 
					
						
							|  |  |  |     private string $token; | 
					
						
							|  |  |  |     private bool $enabled = false; | 
					
						
							|  |  |  |     private DateTimeInterface $created; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setActorId(int $actor_id): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->actor_id = $actor_id; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getActorId(): int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->actor_id; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setToken(string $token): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->token = mb_substr($token, 0, 64); | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getToken(): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->token; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setEnabled(bool $enabled): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->enabled = $enabled; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getEnabled(): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->enabled; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setCreated(DateTimeInterface $created): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->created = $created; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getCreated(): DateTimeInterface | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->created; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // @codeCoverageIgnoreEnd
 | 
					
						
							|  |  |  |     // }}} Autocode
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |     public static function cacheKeys(int $id): array | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         return [ | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |             'user-token' => "pinboard-token-{$id}", | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |         ]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getUser(): LocalUser | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return LocalUser::getById($this->getActorId()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |      * Get a token for a $id and $token pair, unless given a $user, in which case the token field is not validated | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |      * | 
					
						
							|  |  |  |      * XXX: may need to verify it's timing safe | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |     public static function get(?int $id, ?string $token, ?LocalUser $user = null): ?self | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         if (!\is_null($user)) { | 
					
						
							|  |  |  |             return Cache::get( | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |                 self::cacheKeys($user->getId())['user-token'], | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |                 fn () => DB::dql( | 
					
						
							|  |  |  |                     'select t from \Plugin\Pinboard\Entity\Token t where t.actor_id = :id', | 
					
						
							|  |  |  |                     ['id' => $user->getId()], | 
					
						
							|  |  |  |                     options: ['limit' => 1], | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |             ); | 
					
						
							| 
									
										
										
										
											2022-04-01 00:16:04 +01:00
										 |  |  |         } elseif (!\is_null($id) && !\is_null($token)) { | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |             return Cache::get( | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |                 self::cacheKeys($id)['user-token'], | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |                 fn () => DB::dql( | 
					
						
							|  |  |  |                     <<<'EOF' | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |                         select t from \Plugin\Pinboard\Entity\Token t | 
					
						
							|  |  |  |                         where t.actor_id = :id and t.token = :token and t.enabled = true | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |                         EOF, | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |                     ['id' => $id, 'token' => $token], | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |                     options: ['limit' => 1], | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |             ); | 
					
						
							| 
									
										
										
										
											2022-10-19 22:38:49 +01:00
										 |  |  |         } else { | 
					
						
							|  |  |  |             return null; | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getUserTokenString() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-03-31 22:06:37 +01:00
										 |  |  |         return $this->getActorId() . ':' . $this->getToken(); | 
					
						
							| 
									
										
										
										
											2022-03-31 03:28:26 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static function generateTokenString(): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return bin2hex(random_bytes(Common::config('plugin_pinboard', 'token_length') / 2)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public static function schemaDef(): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return [ | 
					
						
							|  |  |  |             'name'   => 'pinboard_token', | 
					
						
							|  |  |  |             'fields' => [ | 
					
						
							|  |  |  |                 'actor_id' => ['type' => 'int', 'not null' => true, 'description' => 'Actor who created this note'], | 
					
						
							|  |  |  |                 'token'    => ['type' => 'varchar', 'length' => 64, 'not null' => true, 'description' => 'The token this user has enabled'], | 
					
						
							|  |  |  |                 'enabled'  => ['type' => 'bool', 'not null' => true, 'default' => false, 'description whether this user enabled the pinboard API'], | 
					
						
							|  |  |  |                 'created'  => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |             'primary key' => ['actor_id'], | 
					
						
							|  |  |  |         ]; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |