From 97e7b309347526e04e8f8f2ee01f78344be1230f Mon Sep 17 00:00:00 2001 From: Shigeki Tanaka Date: Fri, 26 Jan 2024 14:49:22 +0900 Subject: [PATCH] =?UTF-8?q?[update]=20=E5=AE=9F=E8=A3=85=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20for=20v3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + README.md | 1 + composer.lock | 204 +++++++++--------- src/Action/AbstractAction.php | 12 +- src/Action/Cmd.php | 13 -- src/Action/CmdCode.php | 12 ++ src/Action/History.php | 8 - src/Action/Lock.php | 10 +- src/Action/Status.php | 11 - src/Action/Toggle.php | 10 +- src/Action/Unlock.php | 10 +- src/Client.php | 28 +-- src/Device.php | 17 +- src/Enum/Status.php | 36 ++++ src/Extend/AesCmac.php | 6 + src/Http/GuzzleHttp.php | 2 + src/Http/GuzzleHttpFactory.php | 9 +- src/Http/Response.php | 1 + src/{Interface => Http}/ResponseFactory.php | 7 +- src/Interface/ClientInterface.php | 13 +- src/Interface/DeviceInterface.php | 2 +- src/Interface/HttpInterface.php | 2 - .../ResponseFactoryInterface.php | 2 +- src/{Http => Interface}/ResponseInterface.php | 2 +- tests/Action/ActionTest.php | 18 +- tests/SesameStatusTest.php | 2 +- 26 files changed, 225 insertions(+), 214 deletions(-) delete mode 100644 src/Action/Cmd.php create mode 100644 src/Action/CmdCode.php create mode 100644 src/Enum/Status.php rename src/{Interface => Http}/ResponseFactory.php (57%) rename src/{Http => Interface}/ResponseFactoryInterface.php (81%) rename src/{Http => Interface}/ResponseInterface.php (87%) diff --git a/.gitignore b/.gitignore index 7238d0f..a511045 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea/ .phpcs.xml .phpcs-cache +.phpunit.cache build/ docker/ vendor/ diff --git a/README.md b/README.md index db81047..89a4af0 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ $ composer require chanshige/sesame Usage -- + ```injectablephp =8.1", "phpunit/php-file-iterator": "^4.0", "phpunit/php-text-template": "^3.0", @@ -2499,7 +2499,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.10" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.11" }, "funding": [ { @@ -2507,7 +2507,7 @@ "type": "github" } ], - "time": "2023-12-11T06:28:43+00:00" + "time": "2023-12-21T15:38:30+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2754,16 +2754,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.3", + "version": "10.5.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19" + "reference": "0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6fce887c71076a73f32fd3e0774a6833fc5c7f19", - "reference": "6fce887c71076a73f32fd3e0774a6833fc5c7f19", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe", + "reference": "0bd663704f0165c9e76fe4f06ffa6a1ca727fdbe", "shasum": "" }, "require": { @@ -2835,7 +2835,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.3" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.9" }, "funding": [ { @@ -2851,7 +2851,7 @@ "type": "tidelift" } ], - "time": "2023-12-13T07:25:23+00:00" + "time": "2024-01-22T14:35:40+00:00" }, { "name": "psalm/plugin-mockery", @@ -3319,20 +3319,20 @@ }, { "name": "sebastian/complexity", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "68cfb347a44871f01e33ab0ef8215966432f6957" + "reference": "68ff824baeae169ec9f2137158ee529584553799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957", - "reference": "68cfb347a44871f01e33ab0ef8215966432f6957", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799", + "reference": "68ff824baeae169ec9f2137158ee529584553799", "shasum": "" }, "require": { - "nikic/php-parser": "^4.10", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1" }, "require-dev": { @@ -3341,7 +3341,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.1-dev" + "dev-main": "3.2-dev" } }, "autoload": { @@ -3365,7 +3365,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0" }, "funding": [ { @@ -3373,20 +3373,20 @@ "type": "github" } ], - "time": "2023-09-28T11:50:59+00:00" + "time": "2023-12-21T08:37:17+00:00" }, { "name": "sebastian/diff", - "version": "5.0.3", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b" + "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/912dc2fbe3e3c1e7873313cc801b100b6c68c87b", - "reference": "912dc2fbe3e3c1e7873313cc801b100b6c68c87b", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/fbf413a49e54f6b9b17e12d900ac7f6101591b7f", + "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f", "shasum": "" }, "require": { @@ -3399,7 +3399,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "5.0-dev" + "dev-main": "5.1-dev" } }, "autoload": { @@ -3432,7 +3432,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/diff/tree/5.1.0" }, "funding": [ { @@ -3440,7 +3440,7 @@ "type": "github" } ], - "time": "2023-05-01T07:48:21+00:00" + "time": "2023-12-22T10:55:06+00:00" }, { "name": "sebastian/environment", @@ -3648,20 +3648,20 @@ }, { "name": "sebastian/lines-of-code", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d" + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/649e40d279e243d985aa8fb6e74dd5bb28dc185d", - "reference": "649e40d279e243d985aa8fb6e74dd5bb28dc185d", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0", + "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0", "shasum": "" }, "require": { - "nikic/php-parser": "^4.10", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=8.1" }, "require-dev": { @@ -3694,7 +3694,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.1" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2" }, "funding": [ { @@ -3702,7 +3702,7 @@ "type": "github" } ], - "time": "2023-08-31T09:25:50+00:00" + "time": "2023-12-21T08:38:20+00:00" }, { "name": "sebastian/object-enumerator", @@ -4118,16 +4118,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.8.0", + "version": "3.8.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7" + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5805f7a4e4958dbb5e944ef1e6edae0a303765e7", - "reference": "5805f7a4e4958dbb5e944ef1e6edae0a303765e7", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/14f5fff1e64118595db5408e946f3a22c75807f7", + "reference": "14f5fff1e64118595db5408e946f3a22c75807f7", "shasum": "" }, "require": { @@ -4137,11 +4137,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -4194,7 +4194,7 @@ "type": "open_collective" } ], - "time": "2023-12-08T12:32:31+00:00" + "time": "2024-01-11T20:47:48+00:00" }, { "name": "symfony/config", @@ -4273,16 +4273,16 @@ }, { "name": "symfony/console", - "version": "v7.0.1", + "version": "v7.0.2", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cdce5c684b2f920bb1343deecdfba356ffad83d5" + "reference": "f8587c4cdc5acad67af71c37db34ef03af91e59c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cdce5c684b2f920bb1343deecdfba356ffad83d5", - "reference": "cdce5c684b2f920bb1343deecdfba356ffad83d5", + "url": "https://api.github.com/repos/symfony/console/zipball/f8587c4cdc5acad67af71c37db34ef03af91e59c", + "reference": "f8587c4cdc5acad67af71c37db34ef03af91e59c", "shasum": "" }, "require": { @@ -4346,7 +4346,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.0.1" + "source": "https://github.com/symfony/console/tree/v7.0.2" }, "funding": [ { @@ -4362,20 +4362,20 @@ "type": "tidelift" } ], - "time": "2023-12-01T15:10:06+00:00" + "time": "2023-12-10T16:54:46+00:00" }, { "name": "symfony/dependency-injection", - "version": "v7.0.1", + "version": "v7.0.2", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "f6667642954bce638733f254c39e5b5700b47ba4" + "reference": "bd25ef7c937b9da12510bdc4f1c66728f19620e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/f6667642954bce638733f254c39e5b5700b47ba4", - "reference": "f6667642954bce638733f254c39e5b5700b47ba4", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/bd25ef7c937b9da12510bdc4f1c66728f19620e3", + "reference": "bd25ef7c937b9da12510bdc4f1c66728f19620e3", "shasum": "" }, "require": { @@ -4426,7 +4426,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v7.0.1" + "source": "https://github.com/symfony/dependency-injection/tree/v7.0.2" }, "funding": [ { @@ -4442,7 +4442,7 @@ "type": "tidelift" } ], - "time": "2023-12-01T15:10:06+00:00" + "time": "2023-12-28T19:18:20+00:00" }, { "name": "symfony/filesystem", @@ -4839,21 +4839,21 @@ }, { "name": "symfony/service-contracts", - "version": "v3.4.0", + "version": "v3.4.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838" + "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/b3313c2dbffaf71c8de2934e2ea56ed2291a3838", - "reference": "b3313c2dbffaf71c8de2934e2ea56ed2291a3838", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", + "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^2.0" + "psr/container": "^1.1|^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -4901,7 +4901,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" }, "funding": [ { @@ -4917,20 +4917,20 @@ "type": "tidelift" } ], - "time": "2023-07-30T20:28:31+00:00" + "time": "2023-12-26T14:02:43+00:00" }, { "name": "symfony/string", - "version": "v7.0.0", + "version": "v7.0.2", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "92bd2bfbba476d4a1838e5e12168bef2fd1e6620" + "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/92bd2bfbba476d4a1838e5e12168bef2fd1e6620", - "reference": "92bd2bfbba476d4a1838e5e12168bef2fd1e6620", + "url": "https://api.github.com/repos/symfony/string/zipball/cc78f14f91f5e53b42044d0620961c48028ff9f5", + "reference": "cc78f14f91f5e53b42044d0620961c48028ff9f5", "shasum": "" }, "require": { @@ -4987,7 +4987,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.0" + "source": "https://github.com/symfony/string/tree/v7.0.2" }, "funding": [ { @@ -5003,20 +5003,20 @@ "type": "tidelift" } ], - "time": "2023-11-29T08:40:23+00:00" + "time": "2023-12-10T16:54:46+00:00" }, { "name": "symfony/var-exporter", - "version": "v7.0.1", + "version": "v7.0.2", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "a3d7c877414fcd59ab7075ecdc3b8f9c00f7bcc3" + "reference": "345c62fefe92243c3a06fc0cc65f2ec1a47e0764" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/a3d7c877414fcd59ab7075ecdc3b8f9c00f7bcc3", - "reference": "a3d7c877414fcd59ab7075ecdc3b8f9c00f7bcc3", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/345c62fefe92243c3a06fc0cc65f2ec1a47e0764", + "reference": "345c62fefe92243c3a06fc0cc65f2ec1a47e0764", "shasum": "" }, "require": { @@ -5061,7 +5061,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.0.1" + "source": "https://github.com/symfony/var-exporter/tree/v7.0.2" }, "funding": [ { @@ -5077,7 +5077,7 @@ "type": "tidelift" } ], - "time": "2023-11-30T11:38:21+00:00" + "time": "2023-12-27T08:42:13+00:00" }, { "name": "theseer/tokenizer", @@ -5131,16 +5131,16 @@ }, { "name": "vimeo/psalm", - "version": "5.18.0", + "version": "5.20.0", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "b113f3ed0259fd6e212d87c3df80eec95a6abf19" + "reference": "3f284e96c9d9be6fe6b15c79416e1d1903dcfef4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/b113f3ed0259fd6e212d87c3df80eec95a6abf19", - "reference": "b113f3ed0259fd6e212d87c3df80eec95a6abf19", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/3f284e96c9d9be6fe6b15c79416e1d1903dcfef4", + "reference": "3f284e96c9d9be6fe6b15c79416e1d1903dcfef4", "shasum": "" }, "require": { @@ -5237,7 +5237,7 @@ "issues": "https://github.com/vimeo/psalm/issues", "source": "https://github.com/vimeo/psalm" }, - "time": "2023-12-16T09:37:35+00:00" + "time": "2024-01-18T12:15:06+00:00" }, { "name": "webmozart/assert", diff --git a/src/Action/AbstractAction.php b/src/Action/AbstractAction.php index 116b0c2..b52e312 100644 --- a/src/Action/AbstractAction.php +++ b/src/Action/AbstractAction.php @@ -4,8 +4,10 @@ namespace Chanshige\SmartLock\Sesame\Action; +use Chanshige\SmartLock\Sesame\Extend\Signature; use Chanshige\SmartLock\Sesame\Interface\ActionInterface; use Chanshige\SmartLock\Sesame\Interface\DeviceInterface; +use Chanshige\SmartLock\Sesame\Interface\NowInterface; use Koriym\HttpConstants\Method; abstract class AbstractAction implements ActionInterface @@ -23,9 +25,9 @@ public function uuid(): string return $this->device->uuid(); } - public function sign(callable|null $generate = null): string + public function secretKey(): string { - return $this->device->sign($generate); + return $this->device->secretKey(); } abstract public function method(): string; @@ -34,4 +36,10 @@ abstract public function path(): string; /** @return array|array{} */ abstract public function payload(): array; + + /** @SuppressWarnings(PHPMD.StaticAccess) */ + protected function sign(NowInterface $now): string + { + return Signature::generate($this->secretKey(), $now); + } } diff --git a/src/Action/Cmd.php b/src/Action/Cmd.php deleted file mode 100644 index 1750532..0000000 --- a/src/Action/Cmd.php +++ /dev/null @@ -1,13 +0,0 @@ -device instanceof DeviceInterface); + parent::__construct($device); } @@ -31,9 +37,9 @@ public function path(): string public function payload(): array { return [ - 'cmd' => Cmd::LOCK->value, + 'cmd' => CmdCode::LOCK, 'history' => base64_encode($this->comment), - 'sign' => $this->device->sign(), + 'sign' => $this->sign($this->now), ]; } } diff --git a/src/Action/Status.php b/src/Action/Status.php index 59273da..fca3b57 100644 --- a/src/Action/Status.php +++ b/src/Action/Status.php @@ -4,10 +4,6 @@ namespace Chanshige\SmartLock\Sesame\Action; -use BadFunctionCallException; - -use function assert; - final class Status extends AbstractAction { public function method(): string @@ -20,13 +16,6 @@ public function path(): string return ''; } - public function sign(callable|null $generate = null): string - { - assert($generate === null); - - throw new BadFunctionCallException('This method is not supported.'); - } - /** @return array{} */ public function payload(): array { diff --git a/src/Action/Toggle.php b/src/Action/Toggle.php index a3942e5..ed5ec75 100644 --- a/src/Action/Toggle.php +++ b/src/Action/Toggle.php @@ -4,8 +4,11 @@ namespace Chanshige\SmartLock\Sesame\Action; +use Chanshige\SmartLock\Sesame\Extend\Now; use Chanshige\SmartLock\Sesame\Interface\DeviceInterface; +use Chanshige\SmartLock\Sesame\Interface\NowInterface; +use function assert; use function base64_encode; final class Toggle extends AbstractAction @@ -13,7 +16,10 @@ final class Toggle extends AbstractAction public function __construct( private readonly DeviceInterface $device, private readonly string $comment = 'WebAPI', + private readonly NowInterface $now = new Now(), ) { + assert($this->device instanceof DeviceInterface); + parent::__construct($device); } @@ -31,9 +37,9 @@ public function path(): string public function payload(): array { return [ - 'cmd' => Cmd::TOGGLE->value, + 'cmd' => CmdCode::TOGGLE, 'history' => base64_encode($this->comment), - 'sign' => $this->device->sign(), + 'sign' => $this->sign($this->now), ]; } } diff --git a/src/Action/Unlock.php b/src/Action/Unlock.php index eb83b64..84a5951 100644 --- a/src/Action/Unlock.php +++ b/src/Action/Unlock.php @@ -4,8 +4,11 @@ namespace Chanshige\SmartLock\Sesame\Action; +use Chanshige\SmartLock\Sesame\Extend\Now; use Chanshige\SmartLock\Sesame\Interface\DeviceInterface; +use Chanshige\SmartLock\Sesame\Interface\NowInterface; +use function assert; use function base64_encode; final class Unlock extends AbstractAction @@ -13,7 +16,10 @@ final class Unlock extends AbstractAction public function __construct( private readonly DeviceInterface $device, private readonly string $comment = 'WebAPI', + private readonly NowInterface $now = new Now(), ) { + assert($this->device instanceof DeviceInterface); + parent::__construct($device); } @@ -31,9 +37,9 @@ public function path(): string public function payload(): array { return [ - 'cmd' => Cmd::UNLOCK->value, + 'cmd' => CmdCode::UNLOCK, 'history' => base64_encode($this->comment), - 'sign' => $this->device->sign(), + 'sign' => $this->sign($this->now), ]; } } diff --git a/src/Client.php b/src/Client.php index 1485106..fd0e846 100644 --- a/src/Client.php +++ b/src/Client.php @@ -7,11 +7,10 @@ use Chanshige\SmartLock\Sesame\Exception\ClientException; use Chanshige\SmartLock\Sesame\Exception\SesameException; use Chanshige\SmartLock\Sesame\Http\GuzzleHttpFactory; -use Chanshige\SmartLock\Sesame\Http\ResponseInterface; use Chanshige\SmartLock\Sesame\Interface\ActionInterface; use Chanshige\SmartLock\Sesame\Interface\ClientInterface; -use Chanshige\SmartLock\Sesame\Interface\DeviceInterface; use Chanshige\SmartLock\Sesame\Interface\HttpInterface; +use Chanshige\SmartLock\Sesame\Interface\ResponseInterface; use function sprintf; @@ -35,31 +34,6 @@ public function __invoke(ActionInterface $action): ResponseInterface } } - public function status(DeviceInterface $device): ResponseInterface - { - return $this(new Action\Status($device)); - } - - public function history(DeviceInterface $device, int $page = 0, int $lg = 50): ResponseInterface - { - return $this(new Action\History($device, $page, $lg)); - } - - public function lock(DeviceInterface $device, string $note = 'WebAPI'): ResponseInterface - { - return $this(new Action\Lock($device, $note)); - } - - public function unLock(DeviceInterface $device, string $note = 'WebAPI'): ResponseInterface - { - return $this(new Action\Unlock($device, $note)); - } - - public function toggle(DeviceInterface $device, string $note = 'WebAPI'): ResponseInterface - { - return $this(new Action\Toggle($device, $note)); - } - /** * @param array $options * diff --git a/src/Device.php b/src/Device.php index b4e4127..467370a 100644 --- a/src/Device.php +++ b/src/Device.php @@ -4,19 +4,13 @@ namespace Chanshige\SmartLock\Sesame; -use Chanshige\SmartLock\Sesame\Extend\Now; -use Chanshige\SmartLock\Sesame\Extend\Signature; use Chanshige\SmartLock\Sesame\Interface\DeviceInterface; -use Chanshige\SmartLock\Sesame\Interface\NowInterface; -use function is_callable; - -final readonly class Device implements DeviceInterface +readonly class Device implements DeviceInterface { public function __construct( private string $uuid, private string $secretKey, - private NowInterface|null $now = new Now(), ) { } @@ -25,13 +19,8 @@ public function uuid(): string return $this->uuid; } - /** @SuppressWarnings(PHPMD.StaticAccess) */ - public function sign(callable|null $generate = null): string + public function secretKey(): string { - if (! is_callable($generate)) { - return $this->sign(Signature::generate(...)); - } - - return $generate($this->secretKey, $this->now); + return $this->secretKey; } } diff --git a/src/Enum/Status.php b/src/Enum/Status.php new file mode 100644 index 0000000..8ecd512 --- /dev/null +++ b/src/Enum/Status.php @@ -0,0 +1,36 @@ + '施錠', + self::UNLOCKED => '解錠', + self::MOVED => 'サムターン位置確認', + }; + } + + public function equals(Status $status): bool + { + return $this === $status; + } + + public function next(): self + { + return match ($this) { + self::LOCKED => self::UNLOCKED, + self::UNLOCKED, self::MOVED => self::LOCKED, + }; + } +} diff --git a/src/Extend/AesCmac.php b/src/Extend/AesCmac.php index 0ecad11..7dafb2a 100644 --- a/src/Extend/AesCmac.php +++ b/src/Extend/AesCmac.php @@ -7,9 +7,15 @@ use Crypto\CMAC; use Crypto\MACException; use InvalidArgumentException; +use LogicException; +use function extension_loaded; use function hex2bin; +if (! extension_loaded('crypto')) { + throw new LogicException('You cannot use the "Chanshige\SmartLock\Sesame\Extend\AesCmac" as the "crypto" extension is not installed.'); +} + final class AesCmac { /** diff --git a/src/Http/GuzzleHttp.php b/src/Http/GuzzleHttp.php index 7767e20..3c633a2 100644 --- a/src/Http/GuzzleHttp.php +++ b/src/Http/GuzzleHttp.php @@ -6,6 +6,8 @@ use Chanshige\SmartLock\Sesame\Exception\ClientException; use Chanshige\SmartLock\Sesame\Interface\HttpInterface; +use Chanshige\SmartLock\Sesame\Interface\ResponseFactoryInterface; +use Chanshige\SmartLock\Sesame\Interface\ResponseInterface; use GuzzleHttp\ClientInterface as GuzzleClientInterface; use GuzzleHttp\Exception\GuzzleException; use GuzzleHttp\RequestOptions; diff --git a/src/Http/GuzzleHttpFactory.php b/src/Http/GuzzleHttpFactory.php index 606df8f..f6d4fcd 100644 --- a/src/Http/GuzzleHttpFactory.php +++ b/src/Http/GuzzleHttpFactory.php @@ -4,8 +4,8 @@ namespace Chanshige\SmartLock\Sesame\Http; +use Chanshige\SmartLock\Sesame\Interface\ClientInterface; use Chanshige\SmartLock\Sesame\Interface\HttpInterface; -use Chanshige\SmartLock\Sesame\Interface\ResponseFactory; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use GuzzleHttp\Middleware; @@ -13,6 +13,7 @@ use Psr\Http\Message\RequestInterface; use function array_merge; +use function sprintf; final class GuzzleHttpFactory { @@ -28,7 +29,11 @@ public static function newInstance(string $apiKey, array $config = []): HttpInte $stack->push(Middleware::prepareBody(), 'prepare_body'); $stack->push(Middleware::mapRequest(static function (RequestInterface $request) use ($apiKey) { return $request->withHeader('x-api-key', $apiKey); - }), 'add_api_key'); + }), 'sesame_api_key'); + + if (! isset($config['headers'])) { + $config['headers']['User-Agent'] = sprintf('SesameWebAPI/%s', ClientInterface::MAJOR_VERSION); + } return new GuzzleHttp(new Client(array_merge(['handler' => $stack], $config)), new ResponseFactory()); } diff --git a/src/Http/Response.php b/src/Http/Response.php index a020199..5bce934 100644 --- a/src/Http/Response.php +++ b/src/Http/Response.php @@ -5,6 +5,7 @@ namespace Chanshige\SmartLock\Sesame\Http; use Chanshige\SmartLock\Sesame\Extend\Json; +use Chanshige\SmartLock\Sesame\Interface\ResponseInterface; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; final readonly class Response implements ResponseInterface diff --git a/src/Interface/ResponseFactory.php b/src/Http/ResponseFactory.php similarity index 57% rename from src/Interface/ResponseFactory.php rename to src/Http/ResponseFactory.php index d8836e2..dc6c408 100644 --- a/src/Interface/ResponseFactory.php +++ b/src/Http/ResponseFactory.php @@ -2,11 +2,10 @@ declare(strict_types=1); -namespace Chanshige\SmartLock\Sesame\Interface; +namespace Chanshige\SmartLock\Sesame\Http; -use Chanshige\SmartLock\Sesame\Http\Response; -use Chanshige\SmartLock\Sesame\Http\ResponseFactoryInterface; -use Chanshige\SmartLock\Sesame\Http\ResponseInterface; +use Chanshige\SmartLock\Sesame\Interface\ResponseFactoryInterface; +use Chanshige\SmartLock\Sesame\Interface\ResponseInterface; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; class ResponseFactory implements ResponseFactoryInterface diff --git a/src/Interface/ClientInterface.php b/src/Interface/ClientInterface.php index 65fc966..46325ec 100644 --- a/src/Interface/ClientInterface.php +++ b/src/Interface/ClientInterface.php @@ -5,20 +5,11 @@ namespace Chanshige\SmartLock\Sesame\Interface; use Chanshige\SmartLock\Sesame\Exception\SesameException; -use Chanshige\SmartLock\Sesame\Http\ResponseInterface; interface ClientInterface { + public const MAJOR_VERSION = '2.0'; + /** @throws SesameException */ public function __invoke(ActionInterface $action): ResponseInterface; - - public function status(DeviceInterface $device): ResponseInterface; - - public function history(DeviceInterface $device, int $page = 0, int $lg = 50): ResponseInterface; - - public function lock(DeviceInterface $device, string $note = 'WebAPI'): ResponseInterface; - - public function unLock(DeviceInterface $device, string $note = 'WebAPI'): ResponseInterface; - - public function toggle(DeviceInterface $device, string $note = 'WebAPI'): ResponseInterface; } diff --git a/src/Interface/DeviceInterface.php b/src/Interface/DeviceInterface.php index 23b987e..7950829 100644 --- a/src/Interface/DeviceInterface.php +++ b/src/Interface/DeviceInterface.php @@ -8,5 +8,5 @@ interface DeviceInterface { public function uuid(): string; - public function sign(callable|null $generate = null): string; + public function secretKey(): string; } diff --git a/src/Interface/HttpInterface.php b/src/Interface/HttpInterface.php index 7d71bb3..aef368d 100644 --- a/src/Interface/HttpInterface.php +++ b/src/Interface/HttpInterface.php @@ -4,8 +4,6 @@ namespace Chanshige\SmartLock\Sesame\Interface; -use Chanshige\SmartLock\Sesame\Http\ResponseInterface; - interface HttpInterface { /** @param array $params */ diff --git a/src/Http/ResponseFactoryInterface.php b/src/Interface/ResponseFactoryInterface.php similarity index 81% rename from src/Http/ResponseFactoryInterface.php rename to src/Interface/ResponseFactoryInterface.php index 6dda02e..8059f7f 100644 --- a/src/Http/ResponseFactoryInterface.php +++ b/src/Interface/ResponseFactoryInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Chanshige\SmartLock\Sesame\Http; +namespace Chanshige\SmartLock\Sesame\Interface; use Psr\Http\Message\ResponseInterface as PsrResponseInterface; diff --git a/src/Http/ResponseInterface.php b/src/Interface/ResponseInterface.php similarity index 87% rename from src/Http/ResponseInterface.php rename to src/Interface/ResponseInterface.php index 196fb61..e229dd0 100644 --- a/src/Http/ResponseInterface.php +++ b/src/Interface/ResponseInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Chanshige\SmartLock\Sesame\Http; +namespace Chanshige\SmartLock\Sesame\Interface; interface ResponseInterface { diff --git a/tests/Action/ActionTest.php b/tests/Action/ActionTest.php index 619ca5a..0b9578c 100644 --- a/tests/Action/ActionTest.php +++ b/tests/Action/ActionTest.php @@ -4,7 +4,7 @@ namespace Chanshige\SmartLock\Sesame\Action; -use Chanshige\SmartLock\Sesame\Device; +use Chanshige\SmartLock\Sesame\Enum; use Chanshige\SmartLock\Sesame\Extend\Signature; use Chanshige\SmartLock\Sesame\Fake\FakeNow; use Chanshige\SmartLock\Sesame\Interface\ActionInterface; @@ -13,6 +13,7 @@ use Koriym\HttpConstants\Method; use PHPUnit\Framework\TestCase; +/** @SuppressWarnings(PHPMD.StaticAccess) */ class ActionTest extends TestCase { private DeviceInterface $device; @@ -22,10 +23,11 @@ class ActionTest extends TestCase protected function setUp(): void { + $this->now = new FakeNow(); + $this->device = new Device( $this->uuid, $this->secretKey, - $this->now = new FakeNow(), ); } @@ -56,7 +58,7 @@ public function testStatus(): void public function testLockCommand(): void { - $action = new Lock($this->device, 'test_lock'); + $action = new Lock($this->device, 'test_lock', $this->now); $this->assertInstanceOf(ActionInterface::class, $action); $this->assertSame('/cmd', $action->path()); $this->assertArrayHasKey('history', $payload = $action->payload()); @@ -64,12 +66,12 @@ public function testLockCommand(): void $this->assertArrayHasKey('cmd', $payload); $this->assertSame('dGVzdF9sb2Nr', $payload['history']); $this->assertSame(Signature::generate($this->secretKey, $this->now), $payload['sign']); - $this->assertSame(82, $payload['cmd']); + $this->assertSame(CmdCode::LOCK, $payload['cmd']); } public function testUnlockCommand(): void { - $action = new Unlock($this->device, 'test_unlock'); + $action = new Unlock($this->device, 'test_unlock', $this->now); $this->assertInstanceOf(ActionInterface::class, $action); $this->assertSame('/cmd', $action->path()); $this->assertArrayHasKey('history', $payload = $action->payload()); @@ -77,12 +79,12 @@ public function testUnlockCommand(): void $this->assertArrayHasKey('cmd', $payload); $this->assertSame('dGVzdF91bmxvY2s=', $payload['history']); $this->assertSame(Signature::generate($this->secretKey, $this->now), $payload['sign']); - $this->assertSame(83, $payload['cmd']); + $this->assertSame(CmdCode::UNLOCK, $payload['cmd']); } public function testToggleCommand(): void { - $action = new Toggle($this->device, 'test_toggle'); + $action = new Toggle($this->device, 'test_toggle', $this->now); $this->assertInstanceOf(ActionInterface::class, $action); $this->assertSame('/cmd', $action->path()); $this->assertArrayHasKey('history', $payload = $action->payload()); @@ -90,6 +92,6 @@ public function testToggleCommand(): void $this->assertArrayHasKey('cmd', $payload); $this->assertSame('dGVzdF90b2dnbGU=', $payload['history']); $this->assertSame(Signature::generate($this->secretKey, $this->now), $payload['sign']); - $this->assertSame(88, $payload['cmd']); + $this->assertSame(CmdCode::TOGGLE, $payload['cmd']); } } diff --git a/tests/SesameStatusTest.php b/tests/SesameStatusTest.php index 6873093..ab77d65 100644 --- a/tests/SesameStatusTest.php +++ b/tests/SesameStatusTest.php @@ -8,8 +8,8 @@ use Chanshige\SmartLock\Sesame\Exception\ClientException; use Chanshige\SmartLock\Sesame\Exception\SesameException; use Chanshige\SmartLock\Sesame\Http\Response; -use Chanshige\SmartLock\Sesame\Http\ResponseInterface; use Chanshige\SmartLock\Sesame\Interface\HttpInterface; +use Chanshige\SmartLock\Sesame\Interface\ResponseInterface; use Koriym\HttpConstants\StatusCode; use Mockery; use PHPUnit\Framework\TestCase;