Skip to content

Commit 3212fbc

Browse files
committed
Merge pull request #2 from aws/develop
Standalone SNS validator
2 parents 4729589 + cf4c08c commit 3212fbc

12 files changed

+869
-2
lines changed

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
phpunit.xml
2+
Makefile
3+
/.idea/
4+
/*.iml
5+
atlassian-ide-plugin.xml
6+
.DS_Store
7+
.swp
8+
.build
9+
composer.lock
10+
vendor/

.travis.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
language: php
2+
3+
php:
4+
- 5.4
5+
- 5.5
6+
- 5.6
7+
- 7.0
8+
- hhvm
9+
10+
sudo: false
11+
12+
install:
13+
- travis_retry composer update --no-interaction --prefer-dist
14+
15+
script: vendor/bin/phpunit

LICENSE.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Apache License
2+
Version 2.0, January 2004
3+
4+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5+
6+
## 1. Definitions.
7+
8+
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1
9+
through 9 of this document.
10+
11+
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the
12+
License.
13+
14+
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled
15+
by, or are under common control with that entity. For the purposes of this definition, "control" means
16+
(i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract
17+
or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
18+
ownership of such entity.
19+
20+
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
21+
22+
"Source" form shall mean the preferred form for making modifications, including but not limited to software
23+
source code, documentation source, and configuration files.
24+
25+
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form,
26+
including but not limited to compiled object code, generated documentation, and conversions to other media
27+
types.
28+
29+
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License,
30+
as indicated by a copyright notice that is included in or attached to the work (an example is provided in the
31+
Appendix below).
32+
33+
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from)
34+
the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent,
35+
as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not
36+
include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work
37+
and Derivative Works thereof.
38+
39+
"Contribution" shall mean any work of authorship, including the original version of the Work and any
40+
modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to
41+
Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to
42+
submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of
43+
electronic, verbal, or written communication sent to the Licensor or its representatives, including but not
44+
limited to communication on electronic mailing lists, source code control systems, and issue tracking systems
45+
that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but
46+
excluding communication that is conspicuously marked or otherwise designated in writing by the copyright
47+
owner as "Not a Contribution."
48+
49+
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been
50+
received by Licensor and subsequently incorporated within the Work.
51+
52+
## 2. Grant of Copyright License.
53+
54+
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
55+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
56+
Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such
57+
Derivative Works in Source or Object form.
58+
59+
## 3. Grant of Patent License.
60+
61+
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
62+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent
63+
license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such
64+
license applies only to those patent claims licensable by such Contributor that are necessarily infringed by
65+
their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such
66+
Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim
67+
or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work
68+
constitutes direct or contributory patent infringement, then any patent licenses granted to You under this
69+
License for that Work shall terminate as of the date such litigation is filed.
70+
71+
## 4. Redistribution.
72+
73+
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without
74+
modifications, and in Source or Object form, provided that You meet the following conditions:
75+
76+
1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
77+
78+
2. You must cause any modified files to carry prominent notices stating that You changed the files; and
79+
80+
3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent,
81+
trademark, and attribution notices from the Source form of the Work, excluding those notices that do
82+
not pertain to any part of the Derivative Works; and
83+
84+
4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that
85+
You distribute must include a readable copy of the attribution notices contained within such NOTICE
86+
file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one
87+
of the following places: within a NOTICE text file distributed as part of the Derivative Works; within
88+
the Source form or documentation, if provided along with the Derivative Works; or, within a display
89+
generated by the Derivative Works, if and wherever such third-party notices normally appear. The
90+
contents of the NOTICE file are for informational purposes only and do not modify the License. You may
91+
add Your own attribution notices within Derivative Works that You distribute, alongside or as an
92+
addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be
93+
construed as modifying the License.
94+
95+
You may add Your own copyright statement to Your modifications and may provide additional or different license
96+
terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative
97+
Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the
98+
conditions stated in this License.
99+
100+
## 5. Submission of Contributions.
101+
102+
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by
103+
You to the Licensor shall be under the terms and conditions of this License, without any additional terms or
104+
conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate
105+
license agreement you may have executed with Licensor regarding such Contributions.
106+
107+
## 6. Trademarks.
108+
109+
This License does not grant permission to use the trade names, trademarks, service marks, or product names of
110+
the Licensor, except as required for reasonable and customary use in describing the origin of the Work and
111+
reproducing the content of the NOTICE file.
112+
113+
## 7. Disclaimer of Warranty.
114+
115+
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor
116+
provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
117+
or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
118+
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the
119+
appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of
120+
permissions under this License.
121+
122+
## 8. Limitation of Liability.
123+
124+
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless
125+
required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any
126+
Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential
127+
damages of any character arising as a result of this License or out of the use or inability to use the Work
128+
(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or
129+
any and all other commercial damages or losses), even if such Contributor has been advised of the possibility
130+
of such damages.
131+
132+
## 9. Accepting Warranty or Additional Liability.
133+
134+
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for,
135+
acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this
136+
License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole
137+
responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold
138+
each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason
139+
of your accepting any such warranty or additional liability.
140+
141+
END OF TERMS AND CONDITIONS

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
# aws-php-sns-message-validator
2-
Amazon SNS message validation for PHP
1+
# Amazon SNS message Validator for PHP
2+

composer.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "aws/aws-sns-message-validator",
3+
"homepage": "http://aws.amazon.com/sdkforphp",
4+
"description": "Amazon SNS message validation for PHP",
5+
"keywords": ["aws","amazon","sdk","sns","message","webhooks","cloud"],
6+
"type": "library",
7+
"license": "Apache-2.0",
8+
"authors": [
9+
{
10+
"name": "Amazon Web Services",
11+
"homepage": "http://aws.amazon.com"
12+
}
13+
],
14+
"support": {
15+
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
16+
"issues": "https://github.com/aws/aws-sns-message-validator/issues"
17+
},
18+
"require": {
19+
"php": ">=5.4",
20+
"ext-openssl": "*"
21+
},
22+
"require-dev": {
23+
"phpunit/phpunit": "^4.0",
24+
"squizlabs/php_codesniffer": "^2.3"
25+
},
26+
"autoload": {
27+
"psr-4": { "Aws\\Sns\\": "src/" }
28+
},
29+
"autoload-dev": {
30+
"psr-4": { "Aws\\Sns\\": "tests/" }
31+
}
32+
}

phpunit.xml.dist

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit bootstrap="./vendor/autoload.php">
4+
<testsuites>
5+
<testsuite name="AWS SNS Message Validator Test Suite">
6+
<directory>./tests</directory>
7+
</testsuite>
8+
</testsuites>
9+
</phpunit>

src/Message.php

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
<?php
2+
3+
namespace Aws\Sns;
4+
5+
class Message
6+
{
7+
private static $requiredKeys = [
8+
'__default' => [
9+
'Message',
10+
'MessageId',
11+
'Timestamp',
12+
'TopicArn',
13+
'Type',
14+
'Signature',
15+
'SigningCertURL',
16+
],
17+
'SubscriptionConfirmation' => [
18+
'SubscribeURL',
19+
'Token',
20+
],
21+
'UnsubscribeConfirmation' => [
22+
'SubscribeURL',
23+
'Token',
24+
],
25+
];
26+
27+
private static $signableKeys = [
28+
'Message',
29+
'MessageId',
30+
'Subject',
31+
'SubscribeURL',
32+
'Timestamp',
33+
'Token',
34+
'TopicArn',
35+
'Type',
36+
];
37+
38+
/** @var array The message data */
39+
private $data;
40+
41+
/**
42+
* Creates a message object from the raw POST data
43+
*
44+
* @return Message
45+
* @throws \RuntimeException If the POST data is absent, or not a valid JSON document
46+
*/
47+
public static function fromRawPostData()
48+
{
49+
if (!isset($_SERVER['HTTP_X_AMZ_SNS_MESSAGE_TYPE'])) {
50+
throw new \RuntimeException('SNS message type header not provided.');
51+
}
52+
53+
$data = json_decode(file_get_contents('php://input'), true);
54+
if (JSON_ERROR_NONE !== json_last_error()) {
55+
throw new \InvalidArgumentException('Unable to parse JSON.');
56+
} elseif (!is_array($data)) {
57+
throw new \RuntimeException('Invalid POST data.');
58+
}
59+
60+
return self::fromArray($data);
61+
}
62+
63+
/**
64+
* Creates a Message object from an array of raw message data
65+
*
66+
* @param array $data The message data.
67+
*
68+
* @return Message
69+
* @throws \InvalidArgumentException If a valid type is not provided or
70+
* there are other required keys missing.
71+
*/
72+
public static function fromArray(array $data)
73+
{
74+
// Make sure the type key is set
75+
if (!isset($data['Type'])) {
76+
throw new \InvalidArgumentException('The "Type" key must be '
77+
. 'provided to instantiate a Message object.');
78+
}
79+
80+
// Determine required keys and create a collection from the message data
81+
$requiredKeys = array_merge(
82+
self::$requiredKeys['__default'],
83+
isset(self::$requiredKeys[$data['Type']]) ?
84+
self::$requiredKeys[$data['Type']]
85+
: []
86+
);
87+
88+
foreach ($requiredKeys as $key) {
89+
if (!isset($data[$key])) {
90+
throw new \InvalidArgumentException(
91+
"Missing key {$key} in the provided data."
92+
);
93+
}
94+
}
95+
96+
return new self($data);
97+
}
98+
99+
/**
100+
* @param array $data Message data with all required keys.
101+
*/
102+
public function __construct(array $data)
103+
{
104+
$this->data = $data;
105+
}
106+
107+
/**
108+
* Get the entire message data as an array.
109+
*
110+
* @return array
111+
*/
112+
public function getData()
113+
{
114+
return $this->data;
115+
}
116+
117+
/**
118+
* Gets a single key from the message data.
119+
*
120+
* @param string $key Key to retrieve
121+
*
122+
* @return string
123+
*/
124+
public function get($key)
125+
{
126+
return isset($this->data[$key]) ? $this->data[$key] : null;
127+
}
128+
129+
/**
130+
* Builds a newline delimited string-to-sign according to the specs.
131+
*
132+
* @return string
133+
* @link http://docs.aws.amazon.com/sns/latest/gsg/SendMessageToHttp.verify.signature.html
134+
*/
135+
public function getStringToSign()
136+
{
137+
$stringToSign = '';
138+
foreach (self::$signableKeys as $key) {
139+
if ($value = $this->get($key)) {
140+
$stringToSign .= "{$key}\n{$value}\n";
141+
}
142+
}
143+
144+
return $stringToSign;
145+
}
146+
}

0 commit comments

Comments
 (0)