Skip to content
This repository was archived by the owner on Apr 20, 2024. It is now read-only.

Commit 22aea30

Browse files
authored
Merge branch 'master' into master
2 parents 76fd421 + 35516e1 commit 22aea30

23 files changed

+391
-129
lines changed

.circleci/config.yml

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
version: 2
2+
jobs:
3+
MacOS:
4+
macos:
5+
xcode: "9.0"
6+
steps:
7+
- checkout
8+
- restore_cache:
9+
keys:
10+
- v1-spm-deps-{{ checksum "Package.swift" }}
11+
- run:
12+
name: Install CMySQL and CTLS
13+
command: |
14+
brew tap vapor/homebrew-tap
15+
brew install cmysql
16+
brew install ctls
17+
- run:
18+
name: Build and Run Tests
19+
no_output_timeout: 1800
20+
command: |
21+
swift package generate-xcodeproj --enable-code-coverage
22+
xcodebuild -scheme AWS-Package -enableCodeCoverage YES test | xcpretty
23+
- run:
24+
name: Report coverage to Codecov
25+
command: |
26+
bash <(curl -s https://codecov.io/bash)
27+
- save_cache:
28+
key: v1-spm-deps-{{ checksum "Package.swift" }}
29+
paths:
30+
- .build
31+
Linux:
32+
docker:
33+
- image: brettrtoomey/vapor-ci:0.0.1
34+
steps:
35+
- checkout
36+
- restore_cache:
37+
keys:
38+
- v2-spm-deps-{{ checksum "Package.swift" }}
39+
- run:
40+
name: Copy Package file
41+
command: cp Package.swift res
42+
- run:
43+
name: Build and Run Tests
44+
no_output_timeout: 1800
45+
command: |
46+
swift test -Xswiftc -DNOJSON
47+
- run:
48+
name: Restoring Package file
49+
command: mv res Package.swift
50+
- save_cache:
51+
key: v2-spm-deps-{{ checksum "Package.swift" }}
52+
paths:
53+
- .build
54+
workflows:
55+
version: 2
56+
build-and-test:
57+
jobs:
58+
- MacOS
59+
- Linux
60+
experimental:
61+
notify:
62+
branches:
63+
only:
64+
- master
65+
- develop

.codebeatignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Public/**
2+
Resources/Assets/**

.swiftlint.yml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
included:
2+
- Sources
3+
function_body_length:
4+
warning: 60
5+
variable_name:
6+
min_length:
7+
warning: 2
8+
line_length: 80
9+
disabled_rules:
10+
- opening_brace
11+
colon:
12+
flexible_right_spacing: true

.travis.yml

-20
This file was deleted.

LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2016 Nodes Agency - Operations
3+
Copyright (c) 2016-2018 Nodes
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

Package.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import PackageDescription
33
let package = Package(
44
name: "AWS",
55
targets: [
6-
Target(name: "AWS", dependencies: ["EC2", "S3", "AWSSignatureV4"]),
6+
Target(name: "AWS", dependencies: ["AutoScaling", "EC2", "S3"]),
7+
Target(name: "AutoScaling", dependencies: ["AWSSignatureV4"]),
78
Target(name: "EC2", dependencies: ["AWSSignatureV4"]),
89
Target(name: "S3", dependencies: ["AWSSignatureV4"]),
910
Target(name: "VaporS3", dependencies: ["S3"]),
1011
],
1112
dependencies: [
1213
.Package(url: "https://github.com/vapor/vapor.git", majorVersion: 2),
14+
.Package(url: "https://github.com/drmohundro/SWXMLHash", majorVersion: 3),
1315
]
1416
)

[email protected]

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// swift-tools-version:4.0
2+
3+
import PackageDescription
4+
5+
let package = Package(
6+
name: "AWS",
7+
products: [
8+
.library(name: "AWS", targets: ["AWS"]),
9+
.library(name: "VaporS3", targets: ["VaporS3"]),
10+
],
11+
dependencies: [
12+
.package(url: "https://github.com/vapor/vapor.git", from: "2.2.0"),
13+
.package(url: "https://github.com/drmohundro/SWXMLHash", from: "4.1.1"),
14+
],
15+
targets: [
16+
.target(name: "AWS", dependencies: ["AutoScaling", "EC2", "S3"]),
17+
.target(name: "AutoScaling", dependencies: ["AWSSignatureV4", "SWXMLHash"]),
18+
.target(name: "AWSSignatureV4", dependencies: ["Vapor"]),
19+
.target(name: "EC2", dependencies: ["AWSSignatureV4"]),
20+
.target(name: "S3", dependencies: ["AWSSignatureV4"]),
21+
.target(name: "VaporS3", dependencies: ["S3"]),
22+
.testTarget(name: "AWSTests", dependencies: ["AWS"]),
23+
]
24+
)

README.md

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
# AWS
2-
[![Swift Version](https://img.shields.io/badge/Swift-3.1-brightgreen.svg)](http://swift.org)
2+
[![Swift Version](https://img.shields.io/badge/Swift-3-brightgreen.svg)](http://swift.org)
33
[![Vapor Version](https://img.shields.io/badge/Vapor-2-F6CBCA.svg)](http://vapor.codes)
4-
[![Linux Build Status](https://img.shields.io/circleci/project/github/nodes-vapor/aws.svg?label=Linux)](https://circleci.com/gh/nodes-vapor/aws)
5-
[![macOS Build Status](https://img.shields.io/travis/nodes-vapor/aws.svg?label=macOS)](https://travis-ci.org/nodes-vapor/aws)
6-
[![codebeat badge](https://codebeat.co/badges/52c2f960-625c-4a63-ae63-52a24d747da1)](https://codebeat.co/projects/github-com-nodes-vapor-aws)
4+
[![Circle CI](https://circleci.com/gh/nodes-vapor/aws/tree/master.svg?style=shield)](https://circleci.com/gh/nodes-vapor/aws)
5+
[![codebeat badge](https://codebeat.co/badges/255e7772-28ec-4695-bdd5-770cfd676d9c)](https://codebeat.co/projects/github-com-nodes-vapor-aws-master)
76
[![codecov](https://codecov.io/gh/nodes-vapor/aws/branch/master/graph/badge.svg)](https://codecov.io/gh/nodes-vapor/aws)
87
[![Readme Score](http://readme-score-api.herokuapp.com/score.svg?url=https://github.com/nodes-vapor/aws)](http://clayallsopp.github.io/readme-score?url=https://github.com/nodes-vapor/aws)
98
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nodes-vapor/aws/master/LICENSE)
@@ -83,6 +82,13 @@ do {
8382
}
8483
```
8584

85+
## 📃 Development
86+
87+
If you want to improve this, you'll need to make sure you're making a copy of OpenSSL available to `swift build` and the toolchain. If you use Xcode, something like the following after `brew install openssl` will work:
88+
89+
```
90+
swift package -Xswiftc -I/usr/local/Cellar/openssl/1.0.2j/include -Xlinker -L/usr/local/Cellar/openssl/1.0.2j/lib/ generate-xcodeproj
91+
```
8692

8793
## 🏆 Credits
8894

Sources/AWSSignatureV4/AWSSignatureV4.swift

+45-24
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ public struct AWSSignatureV4 {
2020
case post = "POST"
2121
case put = "PUT"
2222
}
23-
23+
2424
let service: String
2525
let host: String
2626
let region: String
2727
let accessKey: String
2828
let secretKey: String
29-
30-
var unitTestDate: Date?
31-
29+
let contentType = "application/x-www-form-urlencoded; charset=utf-8"
30+
31+
internal var unitTestDate: Date?
32+
3233
var amzDate: String {
3334
let dateFormatter = DateFormatter()
3435
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
@@ -63,7 +64,7 @@ public struct AWSSignatureV4 {
6364
canonicalHash
6465
].joined(separator: "\n")
6566
}
66-
67+
6768
func getSignature(_ stringToSign: String) throws -> String {
6869
let dateHMAC = try HMAC(.sha256, dateStamp()).authenticate(key: "AWS4\(secretKey)")
6970
let regionHMAC = try HMAC(.sha256, region).authenticate(key: dateHMAC)
@@ -82,7 +83,7 @@ public struct AWSSignatureV4 {
8283
"aws4_request"
8384
].joined(separator: "/")
8485
}
85-
86+
8687
func getCanonicalRequest(
8788
payloadHash: String,
8889
method: Method,
@@ -93,7 +94,7 @@ public struct AWSSignatureV4 {
9394
) throws -> String {
9495
let path = try path.percentEncode(allowing: Byte.awsPathAllowed)
9596
let query = try query.percentEncode(allowing: Byte.awsQueryAllowed)
96-
97+
9798
return [
9899
method.rawValue,
99100
path,
@@ -108,6 +109,7 @@ public struct AWSSignatureV4 {
108109
func dateStamp() -> String {
109110
let date = unitTestDate ?? Date()
110111
let dateFormatter = DateFormatter()
112+
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
111113
dateFormatter.dateFormat = "YYYYMMdd"
112114
return dateFormatter.string(from: date)
113115
}
@@ -119,24 +121,24 @@ extension AWSSignatureV4 {
119121
host: String,
120122
hash: String
121123
) {
122-
headers["host"] = host
124+
headers["Host"] = host
123125
headers["X-Amz-Date"] = amzDate
124-
125-
if hash != "UNSIGNED-PAYLOAD" {
126+
127+
if hash != "UNSIGNED-PAYLOAD" {
126128
headers["x-amz-content-sha256"] = hash
127129
}
128130
}
129-
131+
130132
func alphabetize(_ dict: [String : String]) -> [(key: String, value: String)] {
131133
return dict.sorted(by: { $0.0.lowercased() < $1.0.lowercased() })
132134
}
133-
135+
134136
func createCanonicalHeaders(_ headers: [(key: String, value: String)]) -> String {
135137
return headers.map {
136138
"\($0.key.lowercased()):\($0.value)"
137139
}.joined(separator: "\n")
138140
}
139-
141+
140142
func createAuthorizationHeader(
141143
algorithm: String,
142144
credentialScope: String,
@@ -148,6 +150,19 @@ extension AWSSignatureV4 {
148150
}
149151

150152
extension AWSSignatureV4 {
153+
/**
154+
Sign a request to be sent to an AWS API.
155+
156+
- returns:
157+
A dictionary with headers to attach to a request
158+
159+
- parameters:
160+
- payload: A hash of this data will be included in the headers
161+
- method: Type of HTTP request
162+
- path: API call being referenced
163+
- query: Additional querystring in key-value format ("?key=value&key2=value2")
164+
- headers: HTTP headers added to the request
165+
*/
151166
public func sign(
152167
payload: Payload = .none,
153168
method: Method = .get,
@@ -158,14 +173,16 @@ extension AWSSignatureV4 {
158173
let algorithm = "AWS4-HMAC-SHA256"
159174
let credentialScope = getCredentialScope()
160175
let payloadHash = try payload.hashed()
161-
176+
162177
var headers = headers
178+
163179
generateHeadersToSign(headers: &headers, host: host, hash: payloadHash)
164-
180+
165181
let sortedHeaders = alphabetize(headers)
166182
let signedHeaders = sortedHeaders.map { $0.key.lowercased() }.joined(separator: ";")
167183
let canonicalHeaders = createCanonicalHeaders(sortedHeaders)
168-
184+
185+
// Task 1 is the Canonical Request
169186
let canonicalRequest = try getCanonicalRequest(
170187
payloadHash: payloadHash,
171188
method: method,
@@ -176,35 +193,39 @@ extension AWSSignatureV4 {
176193
)
177194

178195
let canonicalHash = try Hash.make(.sha256, canonicalRequest).hexString
179-
196+
197+
// Task 2 is the String to Sign
180198
let stringToSign = getStringToSign(
181199
algorithm: algorithm,
182200
date: amzDate,
183201
scope: credentialScope,
184202
canonicalHash: canonicalHash
185203
)
186-
204+
205+
// Task 3 calculates Signature
187206
let signature = try getSignature(stringToSign)
188-
207+
208+
//Task 4 Add signing information to the request
189209
let authorizationHeader = createAuthorizationHeader(
190210
algorithm: algorithm,
191211
credentialScope: credentialScope,
192212
signature: signature,
193213
signedHeaders: signedHeaders
194214
)
195-
196-
215+
197216
var requestHeaders: [HeaderKey: String] = [
198217
"X-Amz-Date": amzDate,
218+
"Content-Type": contentType,
199219
"x-amz-content-sha256": payloadHash,
200-
"Authorization": authorizationHeader
220+
"Authorization": authorizationHeader,
221+
"Host": self.host
201222
]
202-
223+
203224
headers.forEach { key, value in
204225
let headerKey = HeaderKey(stringLiteral: key)
205226
requestHeaders[headerKey] = value
206227
}
207-
228+
208229
return requestHeaders
209230
}
210231
}

Sources/AWSSignatureV4/ErrorParser/ErrorParser+Grammar.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import Core
33
extension ErrorParser {
44
static let awsGrammar: Trie<AWSError> = {
55
let trie = Trie<AWSError>()
6-
6+
77
insert(into: trie, .accessDenied)
88
insert(into: trie, .accountProblem)
99
insert(into: trie, .ambiguousGrantByEmailAddress)
@@ -82,10 +82,10 @@ extension ErrorParser {
8282
insert(into: trie, .unexpectedContent)
8383
insert(into: trie, .unresolvableGrantByEmailAddress)
8484
insert(into: trie, .userKeyMustBeSpecified)
85-
85+
8686
return trie
8787
}()
88-
88+
8989
static func insert(into trie: Trie<AWSError>, _ error: AWSError) {
9090
trie.insert(error, for: error.rawValue.makeBytes())
9191
}

0 commit comments

Comments
 (0)