cedricziel / canva-extension-helper
Canva.com 扩展辅助工具
v0.0.9
2021-02-07 17:20 UTC
Requires
- php: ^7.4 || ^8.0
- ext-json: *
- psr/http-factory: ^1.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- psr/log: ^1.1
Requires (Dev)
- phpunit/phpunit: ^9.3
- symfony/property-access: ^5.1
- symfony/property-info: ^5.1
- symfony/serializer: ^5.1
Suggests
- symfony/serializer: For quick and easy de-/serialization
README
构建 Canva 扩展的一些实用工具。
使用方法
安装
通过 composer
composer require cedricziel/canva-extension-helper
与 Symfony
Symfony 项目通常附带完全配置的序列化器和配置的 http 服务器层。
以下 Symfony 控制器足以用于具有 basic
布局的 "发布" 扩展
<?php namespace App\Controller\Canva; use Canva\Error; use Canva\HttpHelper; use Canva\Publish\ErrorResponse; use Canva\Publish\UploadRequest; use Canva\Publish\UploadResponse; use Canva\Request as CanvaRequest; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\ControllerEvent; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\SerializerInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; /** * @Route(path="/canva/extensions/publish", name="canva_publish") */ class PublishExtensionController extends AbstractController implements EventSubscriberInterface { private string $canvaSecret; public function __construct(string $canvaSecret) { $this->canvaSecret = $canvaSecret; } public static function getSubscribedEvents() { return [ KernelEvents::CONTROLLER => 'onKernelController', ]; } /** * @Route("/configuration", name="_configuration", methods={"POST"}) */ public function configuration(): Response { return $this->json(new ErrorResponse(Error::CODE_INVALID_REQUEST)); } /** * @Route("/resources/find", name="_resources_find", methods={"POST"}) */ public function resourcesFind(): Response { return $this->json(new ErrorResponse(Error::CODE_INVALID_REQUEST)); } /** * @Route("/resources/get", name="_resources_get", methods={"POST"}) */ public function resourcesGet(): Response { return $this->json(new ErrorResponse(Error::CODE_INVALID_REQUEST)); } /** * @Route("/resources/upload", name="_resources_upload") */ public function resourcesUpload(Request $request, HttpClientInterface $httpClient, SerializerInterface $serializer): Response { try { /** @var UploadRequest $uploadRequest */ $uploadRequest = $serializer->deserialize($request->getContent(), UploadRequest::class, 'json'); foreach ($uploadRequest->getAssets() as $asset) { // do something with the result $httpClient->request('GET', $asset->getUrl()); } return $this->json(new UploadResponse()); } catch (InvalidArgumentException $exception) { return $this->json(new ErrorResponse(Error::CODE_INVALID_REQUEST)); } } public function onKernelController(ControllerEvent $event) { $controller = $event->getController(); $request = $event->getRequest(); // when a controller class defines multiple action methods, the controller // is returned as [$controllerInstance, 'methodName'] if (is_array($controller)) { $controller = $controller[0]; } /** * Every publish extension endpoint is invoked via POST and needs * signature AND timestamp checking. */ if ($controller instanceof self) { $timestampHeader = $request->headers->get(CanvaRequest::HEADER_TIMESTAMP); if ($timestampHeader === null || !HttpHelper::verifyTimestamp($timestampHeader, time())) { throw new HttpException(401, 'Timestamp skew is too large.'); } $path = parse_url($request->getUri(), PHP_URL_PATH); $operation = ''; switch (true) { case str_ends_with($path, '/configuration'): $operation = '/configuration'; break; case str_ends_with($path, '/publish/resources/find'): $operation = '/publish/resources/find'; break; case str_ends_with($path, '/publish/resources/get'): $operation = '/publish/resources/get'; break; case str_ends_with($path, '/publish/resources/upload'): $operation = '/publish/resources/upload'; break; default: throw new HttpException(401, 'Unknown operation'); } $signature = HttpHelper::calculatePostSignature( $timestampHeader, $operation, $request->getContent(), $this->canvaSecret ); $signatureHeader = $request->headers->get(CanvaRequest::HEADER_SIGNATURES); if ($signatureHeader === null || !in_array($signature, explode(',', $signatureHeader), true)) { throw new HttpException(401, 'Signatures do not match'); } } } }
然后您可以在 services.yaml
中将构造函数参数 $canvaSecret
"绑定" 到您的 Canva.com 密钥
services: _defaults: # .. other defaults bind: $canvaSecret: 'my-secret'
序列化
注意:此项目提供模型类。反/序列化必须通过您的应用程序进行。
示例使用 Symfony Serializer 组件
use Canva\Publish\GetResourceRequest; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\PropertyInfoExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; use Symfony\Component\Serializer\Serializer; // the json chunk extracted from the request body $request = '...'; $encoders = [new JsonEncoder()]; $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]); $normalizers = [new ArrayDenormalizer(), new ObjectNormalizer(null, null, null, $extractor), new PropertyNormalizer(), new GetSetMethodNormalizer()]; /** @var GetResourceRequest $getResourceRequest */ $getResourceRequest = $serializer->deserialize($request, GetResourceRequest::class, 'json');
检查传入请求
Canva 要求扩展检查传入请求的时间戳偏移和匹配的 HMAC 签名。此包提供辅助程序以轻松处理。
检查时间戳
// allow a skew of 300 seconds $leniency = 300; // the timestamp at which the request was received $localTimestamp = time(); // the timestamp at which the request was sent $sentTimestamp = $_SERVER['HTTP_X_CANVA_TIMESTAMP']; // returns a boolean whether the timestamps are close enough together $timestampIsOkay = \Canva\HttpHelper::verifyTimestamp($sentTimestamp, $localTimestamp, $leniency)
有关检查签名的示例,请参阅中间件部分。
中间件
Canva 要求您检查来自其端点的请求。您可以手动使用 Canva\HttpHelper
类验证时间戳标头,或者选择在 Canva 将通信的路径上安装中间件。
Canva\MiddlewareTimestampMiddleware
- 检查时间偏移 Canva\Middleware\PostHMACMiddleware
- 检查 POST 请求上的签名 Canva\Middleware\GetHMACMiddleware
- 检查 GET 请求上的签名
免责声明
本项目与 Canva.com 无关
许可证
MIT