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

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
proggeramlug authored Mar 16, 2018
2 parents 76fd421 + 35516e1 commit 22aea30
Show file tree
Hide file tree
Showing 23 changed files with 391 additions and 129 deletions.
65 changes: 65 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
version: 2
jobs:
MacOS:
macos:
xcode: "9.0"
steps:
- checkout
- restore_cache:
keys:
- v1-spm-deps-{{ checksum "Package.swift" }}
- run:
name: Install CMySQL and CTLS
command: |
brew tap vapor/homebrew-tap
brew install cmysql
brew install ctls
- run:
name: Build and Run Tests
no_output_timeout: 1800
command: |
swift package generate-xcodeproj --enable-code-coverage
xcodebuild -scheme AWS-Package -enableCodeCoverage YES test | xcpretty
- run:
name: Report coverage to Codecov
command: |
bash <(curl -s https://codecov.io/bash)
- save_cache:
key: v1-spm-deps-{{ checksum "Package.swift" }}
paths:
- .build
Linux:
docker:
- image: brettrtoomey/vapor-ci:0.0.1
steps:
- checkout
- restore_cache:
keys:
- v2-spm-deps-{{ checksum "Package.swift" }}
- run:
name: Copy Package file
command: cp Package.swift res
- run:
name: Build and Run Tests
no_output_timeout: 1800
command: |
swift test -Xswiftc -DNOJSON
- run:
name: Restoring Package file
command: mv res Package.swift
- save_cache:
key: v2-spm-deps-{{ checksum "Package.swift" }}
paths:
- .build
workflows:
version: 2
build-and-test:
jobs:
- MacOS
- Linux
experimental:
notify:
branches:
only:
- master
- develop
2 changes: 2 additions & 0 deletions .codebeatignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Public/**
Resources/Assets/**
12 changes: 12 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
included:
- Sources
function_body_length:
warning: 60
variable_name:
min_length:
warning: 2
line_length: 80
disabled_rules:
- opening_brace
colon:
flexible_right_spacing: true
20 changes: 0 additions & 20 deletions .travis.yml

This file was deleted.

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2016 Nodes Agency - Operations
Copyright (c) 2016-2018 Nodes

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 3 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import PackageDescription
let package = Package(
name: "AWS",
targets: [
Target(name: "AWS", dependencies: ["EC2", "S3", "AWSSignatureV4"]),
Target(name: "AWS", dependencies: ["AutoScaling", "EC2", "S3"]),
Target(name: "AutoScaling", dependencies: ["AWSSignatureV4"]),
Target(name: "EC2", dependencies: ["AWSSignatureV4"]),
Target(name: "S3", dependencies: ["AWSSignatureV4"]),
Target(name: "VaporS3", dependencies: ["S3"]),
],
dependencies: [
.Package(url: "https://github.com/vapor/vapor.git", majorVersion: 2),
.Package(url: "https://github.com/drmohundro/SWXMLHash", majorVersion: 3),
]
)
24 changes: 24 additions & 0 deletions [email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// swift-tools-version:4.0

import PackageDescription

let package = Package(
name: "AWS",
products: [
.library(name: "AWS", targets: ["AWS"]),
.library(name: "VaporS3", targets: ["VaporS3"]),
],
dependencies: [
.package(url: "https://github.com/vapor/vapor.git", from: "2.2.0"),
.package(url: "https://github.com/drmohundro/SWXMLHash", from: "4.1.1"),
],
targets: [
.target(name: "AWS", dependencies: ["AutoScaling", "EC2", "S3"]),
.target(name: "AutoScaling", dependencies: ["AWSSignatureV4", "SWXMLHash"]),
.target(name: "AWSSignatureV4", dependencies: ["Vapor"]),
.target(name: "EC2", dependencies: ["AWSSignatureV4"]),
.target(name: "S3", dependencies: ["AWSSignatureV4"]),
.target(name: "VaporS3", dependencies: ["S3"]),
.testTarget(name: "AWSTests", dependencies: ["AWS"]),
]
)
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# AWS
[![Swift Version](https://img.shields.io/badge/Swift-3.1-brightgreen.svg)](http://swift.org)
[![Swift Version](https://img.shields.io/badge/Swift-3-brightgreen.svg)](http://swift.org)
[![Vapor Version](https://img.shields.io/badge/Vapor-2-F6CBCA.svg)](http://vapor.codes)
[![Linux Build Status](https://img.shields.io/circleci/project/github/nodes-vapor/aws.svg?label=Linux)](https://circleci.com/gh/nodes-vapor/aws)
[![macOS Build Status](https://img.shields.io/travis/nodes-vapor/aws.svg?label=macOS)](https://travis-ci.org/nodes-vapor/aws)
[![codebeat badge](https://codebeat.co/badges/52c2f960-625c-4a63-ae63-52a24d747da1)](https://codebeat.co/projects/github-com-nodes-vapor-aws)
[![Circle CI](https://circleci.com/gh/nodes-vapor/aws/tree/master.svg?style=shield)](https://circleci.com/gh/nodes-vapor/aws)
[![codebeat badge](https://codebeat.co/badges/255e7772-28ec-4695-bdd5-770cfd676d9c)](https://codebeat.co/projects/github-com-nodes-vapor-aws-master)
[![codecov](https://codecov.io/gh/nodes-vapor/aws/branch/master/graph/badge.svg)](https://codecov.io/gh/nodes-vapor/aws)
[![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)
[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nodes-vapor/aws/master/LICENSE)
Expand Down Expand Up @@ -83,6 +82,13 @@ do {
}
```

## 📃 Development

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:

```
swift package -Xswiftc -I/usr/local/Cellar/openssl/1.0.2j/include -Xlinker -L/usr/local/Cellar/openssl/1.0.2j/lib/ generate-xcodeproj
```

## 🏆 Credits

Expand Down
69 changes: 45 additions & 24 deletions Sources/AWSSignatureV4/AWSSignatureV4.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ public struct AWSSignatureV4 {
case post = "POST"
case put = "PUT"
}

let service: String
let host: String
let region: String
let accessKey: String
let secretKey: String

var unitTestDate: Date?

let contentType = "application/x-www-form-urlencoded; charset=utf-8"

internal var unitTestDate: Date?

var amzDate: String {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
Expand Down Expand Up @@ -63,7 +64,7 @@ public struct AWSSignatureV4 {
canonicalHash
].joined(separator: "\n")
}

func getSignature(_ stringToSign: String) throws -> String {
let dateHMAC = try HMAC(.sha256, dateStamp()).authenticate(key: "AWS4\(secretKey)")
let regionHMAC = try HMAC(.sha256, region).authenticate(key: dateHMAC)
Expand All @@ -82,7 +83,7 @@ public struct AWSSignatureV4 {
"aws4_request"
].joined(separator: "/")
}

func getCanonicalRequest(
payloadHash: String,
method: Method,
Expand All @@ -93,7 +94,7 @@ public struct AWSSignatureV4 {
) throws -> String {
let path = try path.percentEncode(allowing: Byte.awsPathAllowed)
let query = try query.percentEncode(allowing: Byte.awsQueryAllowed)

return [
method.rawValue,
path,
Expand All @@ -108,6 +109,7 @@ public struct AWSSignatureV4 {
func dateStamp() -> String {
let date = unitTestDate ?? Date()
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatter.dateFormat = "YYYYMMdd"
return dateFormatter.string(from: date)
}
Expand All @@ -119,24 +121,24 @@ extension AWSSignatureV4 {
host: String,
hash: String
) {
headers["host"] = host
headers["Host"] = host
headers["X-Amz-Date"] = amzDate
if hash != "UNSIGNED-PAYLOAD" {

if hash != "UNSIGNED-PAYLOAD" {
headers["x-amz-content-sha256"] = hash
}
}

func alphabetize(_ dict: [String : String]) -> [(key: String, value: String)] {
return dict.sorted(by: { $0.0.lowercased() < $1.0.lowercased() })
}

func createCanonicalHeaders(_ headers: [(key: String, value: String)]) -> String {
return headers.map {
"\($0.key.lowercased()):\($0.value)"
}.joined(separator: "\n")
}

func createAuthorizationHeader(
algorithm: String,
credentialScope: String,
Expand All @@ -148,6 +150,19 @@ extension AWSSignatureV4 {
}

extension AWSSignatureV4 {
/**
Sign a request to be sent to an AWS API.

- returns:
A dictionary with headers to attach to a request

- parameters:
- payload: A hash of this data will be included in the headers
- method: Type of HTTP request
- path: API call being referenced
- query: Additional querystring in key-value format ("?key=value&key2=value2")
- headers: HTTP headers added to the request
*/
public func sign(
payload: Payload = .none,
method: Method = .get,
Expand All @@ -158,14 +173,16 @@ extension AWSSignatureV4 {
let algorithm = "AWS4-HMAC-SHA256"
let credentialScope = getCredentialScope()
let payloadHash = try payload.hashed()

var headers = headers

generateHeadersToSign(headers: &headers, host: host, hash: payloadHash)

let sortedHeaders = alphabetize(headers)
let signedHeaders = sortedHeaders.map { $0.key.lowercased() }.joined(separator: ";")
let canonicalHeaders = createCanonicalHeaders(sortedHeaders)


// Task 1 is the Canonical Request
let canonicalRequest = try getCanonicalRequest(
payloadHash: payloadHash,
method: method,
Expand All @@ -176,35 +193,39 @@ extension AWSSignatureV4 {
)

let canonicalHash = try Hash.make(.sha256, canonicalRequest).hexString


// Task 2 is the String to Sign
let stringToSign = getStringToSign(
algorithm: algorithm,
date: amzDate,
scope: credentialScope,
canonicalHash: canonicalHash
)


// Task 3 calculates Signature
let signature = try getSignature(stringToSign)


//Task 4 Add signing information to the request
let authorizationHeader = createAuthorizationHeader(
algorithm: algorithm,
credentialScope: credentialScope,
signature: signature,
signedHeaders: signedHeaders
)



var requestHeaders: [HeaderKey: String] = [
"X-Amz-Date": amzDate,
"Content-Type": contentType,
"x-amz-content-sha256": payloadHash,
"Authorization": authorizationHeader
"Authorization": authorizationHeader,
"Host": self.host
]

headers.forEach { key, value in
let headerKey = HeaderKey(stringLiteral: key)
requestHeaders[headerKey] = value
}

return requestHeaders
}
}
6 changes: 3 additions & 3 deletions Sources/AWSSignatureV4/ErrorParser/ErrorParser+Grammar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Core
extension ErrorParser {
static let awsGrammar: Trie<AWSError> = {
let trie = Trie<AWSError>()

insert(into: trie, .accessDenied)
insert(into: trie, .accountProblem)
insert(into: trie, .ambiguousGrantByEmailAddress)
Expand Down Expand Up @@ -82,10 +82,10 @@ extension ErrorParser {
insert(into: trie, .unexpectedContent)
insert(into: trie, .unresolvableGrantByEmailAddress)
insert(into: trie, .userKeyMustBeSpecified)

return trie
}()

static func insert(into trie: Trie<AWSError>, _ error: AWSError) {
trie.insert(error, for: error.rawValue.makeBytes())
}
Expand Down
Loading

0 comments on commit 22aea30

Please sign in to comment.