From c8e85d25822795df440143ab8743f720f7b7969c Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 25 Nov 2017 04:45:18 +0100 Subject: [PATCH] Add firewall access rules endpoint (#37) * Add firewall access rules endpoint * Configuration is an object Maybe this needs to be defined in a seperate namespace (e.g. Cloudflare\API\Configuration) because it's no longer an array. * Incorporate review --- src/Configurations/AccessRules.php | 28 ++++ src/Endpoints/AccessRules.php | 153 ++++++++++++++++++ tests/Endpoints/AccessRulesTest.php | 112 +++++++++++++ .../Fixtures/Endpoints/createAccessRule.json | 30 ++++ .../Fixtures/Endpoints/deleteAccessRule.json | 12 ++ tests/Fixtures/Endpoints/listAccessRules.json | 38 +++++ .../Fixtures/Endpoints/updateAccessRule.json | 30 ++++ 7 files changed, 403 insertions(+) create mode 100644 src/Configurations/AccessRules.php create mode 100644 src/Endpoints/AccessRules.php create mode 100644 tests/Endpoints/AccessRulesTest.php create mode 100644 tests/Fixtures/Endpoints/createAccessRule.json create mode 100644 tests/Fixtures/Endpoints/deleteAccessRule.json create mode 100644 tests/Fixtures/Endpoints/listAccessRules.json create mode 100644 tests/Fixtures/Endpoints/updateAccessRule.json diff --git a/src/Configurations/AccessRules.php b/src/Configurations/AccessRules.php new file mode 100644 index 0000000..17ea57f --- /dev/null +++ b/src/Configurations/AccessRules.php @@ -0,0 +1,28 @@ +config = ['target' => 'ip', 'value' => $value]; + } + + public function setIPRange(string $value) + { + $this->config = ['target' => 'ip_range', 'value' => $value]; + } + + public function setCountry(string $value) + { + $this->config = ['target' => 'country', 'value' => $value]; + } + + public function getArray(): array + { + return $this->config; + } +} diff --git a/src/Endpoints/AccessRules.php b/src/Endpoints/AccessRules.php new file mode 100644 index 0000000..b80d1b6 --- /dev/null +++ b/src/Endpoints/AccessRules.php @@ -0,0 +1,153 @@ +adapter = $adapter; + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * + * @param string $zoneID + * @param string $scopeType + * @param string $mode + * @param string $configurationTarget + * @param string $configurationValue + * @param int $page + * @param int $perPage + * @param string $order + * @param string $direction + * @param string $match + * @param string $notes + * @return \stdClass + */ + public function listRules( + string $zoneID, + string $scopeType = '', + string $mode = '', + string $configurationTarget = '', + string $configurationValue = '', + int $page = 1, + int $perPage = 50, + string $order = '', + string $direction = '', + string $match = 'all', + string $notes = '' + ): \stdClass { + $query = [ + 'page' => $page, + 'per_page' => $perPage, + 'match' => $match + ]; + + if (!empty($scopeType)) { + $query['scope_type'] = $scopeType; + } + + if (!empty($mode)) { + $query['mode'] = $mode; + } + + if (!empty($configurationTarget)) { + $query['configuration_target'] = $configurationTarget; + } + + if (!empty($configurationValue)) { + $query['configuration_value'] = $configurationValue; + } + + if (!empty($order)) { + $query['order'] = $order; + } + + if (!empty($direction)) { + $query['direction'] = $direction; + } + + if (!empty($notes)) { + $query['notes'] = $notes; + } + + $data = $this->adapter->get('zones/' . $zoneID . '/firewall/access_rules/rules', $query, []); + $body = json_decode($data->getBody()); + + return (object)['result' => $body->result, 'result_info' => $body->result_info]; + } + + public function createRule( + string $zoneID, + string $mode, + Configurations $configuration, + string $notes = null + ): bool { + $options = [ + 'mode' => $mode, + 'configuration' => (object) $configuration->getArray() + ]; + + if ($notes !== null) { + $options['notes'] = $notes; + } + + $query = $this->adapter->post('zones/' . $zoneID . '/firewall/access_rules/rules', [], $options); + + $body = json_decode($query->getBody()); + + if (isset($body->result->id)) { + return true; + } + + return false; + } + + public function updateRule( + string $zoneID, + string $ruleID, + string $mode, + string $notes = null + ): bool { + $options = [ + 'mode' => $mode + ]; + + if ($notes !== null) { + $options['notes'] = $notes; + } + + $query = $this->adapter->patch('zones/' . $zoneID . '/firewall/access_rules/rules/' . $ruleID, [], $options); + + $body = json_decode($query->getBody()); + + if (isset($body->result->id)) { + return true; + } + + return false; + } + + public function deleteRule(string $zoneID, string $ruleID, string $cascade = 'none'): bool + { + $options = [ + 'cascade' => $cascade + ]; + + $data = $this->adapter->delete('zones/' . $zoneID . '/firewall/access_rules/rules/' . $ruleID, [], $options); + + $body = json_decode($data->getBody()); + + if (isset($body->result->id)) { + return true; + } + + return false; + } +} diff --git a/tests/Endpoints/AccessRulesTest.php b/tests/Endpoints/AccessRulesTest.php new file mode 100644 index 0000000..cb36900 --- /dev/null +++ b/tests/Endpoints/AccessRulesTest.php @@ -0,0 +1,112 @@ +getPsr7JsonResponseForFixture('Endpoints/listAccessRules.json'); + + $mock = $this->getMockBuilder(\Cloudflare\API\Adapter\Adapter::class)->getMock(); + $mock->method('get')->willReturn($response); + + $mock->expects($this->once()) + ->method('get') + ->with( + $this->equalTo('zones/023e105f4ecef8ad9ca31a8372d0c353/firewall/access_rules/rules'), + $this->equalTo([ + 'page' => 1, + 'per_page' => 50, + 'match' => 'all' + ]), + $this->equalTo([]) + ); + + $zones = new \Cloudflare\API\Endpoints\AccessRules($mock); + $result = $zones->listRules('023e105f4ecef8ad9ca31a8372d0c353'); + + $this->assertObjectHasAttribute('result', $result); + $this->assertObjectHasAttribute('result_info', $result); + + $this->assertEquals('92f17202ed8bd63d69a66b86a49a8f6b', $result->result[0]->id); + $this->assertEquals(1, $result->result_info->page); + } + + public function testCreateRule() + { + $config = new \Cloudflare\API\Configurations\AccessRules(); + $config->setIP('1.2.3.4'); + + $response = $this->getPsr7JsonResponseForFixture('Endpoints/createAccessRule.json'); + + $mock = $this->getMockBuilder(\Cloudflare\API\Adapter\Adapter::class)->getMock(); + $mock->method('post')->willReturn($response); + + $mock->expects($this->once()) + ->method('post') + ->with( + $this->equalTo('zones/023e105f4ecef8ad9ca31a8372d0c353/firewall/access_rules/rules'), + $this->equalTo([]), + $this->equalTo([ + 'mode' => 'challenge', + 'configuration' => (object) $config->getArray(), + 'notes' => 'This rule is on because of an event that occured on date X', + ]) + ); + + $rules = new \Cloudflare\API\Endpoints\AccessRules($mock); + $rules->createRule( + '023e105f4ecef8ad9ca31a8372d0c353', + 'challenge', + $config, + 'This rule is on because of an event that occured on date X' + ); + } + + public function testUpdateRule() + { + $response = $this->getPsr7JsonResponseForFixture('Endpoints/updateAccessRule.json'); + + $mock = $this->getMockBuilder(\Cloudflare\API\Adapter\Adapter::class)->getMock(); + $mock->method('patch')->willReturn($response); + + $mock->expects($this->once()) + ->method('patch') + ->with( + $this->equalTo('zones/023e105f4ecef8ad9ca31a8372d0c353/firewall/access_rules/rules/92f17202ed8bd63d69a66b86a49a8f6b'), + $this->equalTo([]), + $this->equalTo([ + 'mode' => 'challenge', + 'notes' => 'This rule is on because of an event that occured on date X', + ]) + ); + + $rules = new \Cloudflare\API\Endpoints\AccessRules($mock); + $rules->updateRule( + '023e105f4ecef8ad9ca31a8372d0c353', + '92f17202ed8bd63d69a66b86a49a8f6b', + 'challenge', + 'This rule is on because of an event that occured on date X' + ); + } + + public function testDeleteRule() + { + $response = $this->getPsr7JsonResponseForFixture('Endpoints/deleteAccessRule.json'); + + $mock = $this->getMockBuilder(\Cloudflare\API\Adapter\Adapter::class)->getMock(); + $mock->method('delete')->willReturn($response); + + $mock->expects($this->once()) + ->method('delete') + ->with( + $this->equalTo('zones/023e105f4ecef8ad9ca31a8372d0c353/firewall/access_rules/rules/92f17202ed8bd63d69a66b86a49a8f6b'), + $this->equalTo([]), + $this->equalTo([ + 'cascade' => 'none' + ]) + ); + + $rules = new \Cloudflare\API\Endpoints\AccessRules($mock); + $rules->deleteRule('023e105f4ecef8ad9ca31a8372d0c353', '92f17202ed8bd63d69a66b86a49a8f6b'); + } +} diff --git a/tests/Fixtures/Endpoints/createAccessRule.json b/tests/Fixtures/Endpoints/createAccessRule.json new file mode 100644 index 0000000..3f34b6a --- /dev/null +++ b/tests/Fixtures/Endpoints/createAccessRule.json @@ -0,0 +1,30 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": { + "id": "92f17202ed8bd63d69a66b86a49a8f6b", + "notes": "This rule is on because of an event that occured on date X", + "allowed_modes": [ + "whitelist", + "block", + "challenge" + ], + "mode": "challenge", + "configuration": { + "target": "ip", + "value": "1.2.3.4" + }, + "scope": { + "id": "7c5dae5552338874e5053f2534d2767a", + "email": "user@example.com", + "type": "user" + }, + "created_on": "2014-01-01T05:20:00.12345Z", + "modified_on": "2014-01-01T05:20:00.12345Z" + } +} \ No newline at end of file diff --git a/tests/Fixtures/Endpoints/deleteAccessRule.json b/tests/Fixtures/Endpoints/deleteAccessRule.json new file mode 100644 index 0000000..2c1ae81 --- /dev/null +++ b/tests/Fixtures/Endpoints/deleteAccessRule.json @@ -0,0 +1,12 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": { + "id": "92f17202ed8bd63d69a66b86a49a8f6b" + } +} \ No newline at end of file diff --git a/tests/Fixtures/Endpoints/listAccessRules.json b/tests/Fixtures/Endpoints/listAccessRules.json new file mode 100644 index 0000000..a11d418 --- /dev/null +++ b/tests/Fixtures/Endpoints/listAccessRules.json @@ -0,0 +1,38 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": [ + { + "id": "92f17202ed8bd63d69a66b86a49a8f6b", + "notes": "This rule is on because of an event that occured on date X", + "allowed_modes": [ + "whitelist", + "block", + "challenge" + ], + "mode": "challenge", + "configuration": { + "target": "ip", + "value": "1.2.3.4" + }, + "scope": { + "id": "7c5dae5552338874e5053f2534d2767a", + "email": "user@example.com", + "type": "user" + }, + "created_on": "2014-01-01T05:20:00.12345Z", + "modified_on": "2014-01-01T05:20:00.12345Z" + } + ], + "result_info": { + "page": 1, + "per_page": 20, + "count": 1, + "total_count": 2000 + } +} \ No newline at end of file diff --git a/tests/Fixtures/Endpoints/updateAccessRule.json b/tests/Fixtures/Endpoints/updateAccessRule.json new file mode 100644 index 0000000..3f34b6a --- /dev/null +++ b/tests/Fixtures/Endpoints/updateAccessRule.json @@ -0,0 +1,30 @@ +{ + "success": true, + "errors": [ + {} + ], + "messages": [ + {} + ], + "result": { + "id": "92f17202ed8bd63d69a66b86a49a8f6b", + "notes": "This rule is on because of an event that occured on date X", + "allowed_modes": [ + "whitelist", + "block", + "challenge" + ], + "mode": "challenge", + "configuration": { + "target": "ip", + "value": "1.2.3.4" + }, + "scope": { + "id": "7c5dae5552338874e5053f2534d2767a", + "email": "user@example.com", + "type": "user" + }, + "created_on": "2014-01-01T05:20:00.12345Z", + "modified_on": "2014-01-01T05:20:00.12345Z" + } +} \ No newline at end of file