Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Support for Custom Hosts/Regions #13

Merged
merged 9 commits into from
Sep 7, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,8 @@
"repositoryURL": "https://github.com/vapor/url-encoded-form.git",
"state": {
"branch": null,
"revision": "57cf7fb9c1a1014c50bc05123684a9139ad44127",
"version": "1.0.3"
"revision": "cbfe7ef6301557d3f2d0807a98165232ae06e1c6",
"version": "1.0.4"
}
},
{
Expand All @@ -149,9 +149,9 @@
"package": "VaporTestTools",
"repositoryURL": "https://github.com/LiveUI/VaporTestTools.git",
"state": {
"branch": "master",
"branch": null,
"revision": "e07ce263257463f2f2af9e640f81eb95a72760e4",
"version": null
"version": "0.1.5"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Sources/S3/Extensions/S3+Bucket.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public extension S3 {

let content = """
<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<LocationConstraint>\(region.rawValue)</LocationConstraint>
<LocationConstraint>\(region.name.rawValue)</LocationConstraint>
</CreateBucketConfiguration>
"""

Expand Down
2 changes: 1 addition & 1 deletion Sources/S3/Extensions/S3+List.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ extension S3 {
/// Get list of objects
public func list(bucket: String, region: Region? = nil, headers: [String: String], on container: Container) throws -> Future<BucketResults> {
let region = region ?? signer.config.region
guard let baseUrl = URL(string: "https://\(bucket).s3.\(region.rawValue).amazonaws.com/"), let host = baseUrl.host,
guard let baseUrl = URL(string: region.hostUrlString(bucket: bucket)), let host = baseUrl.host,
var components = URLComponents(string: baseUrl.absoluteString) else {
throw S3.Error.invalidUrl
}
Expand Down
13 changes: 11 additions & 2 deletions Sources/S3/URLBuilder/URLBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,22 @@ extension Region {

/// Host URL including scheme
public func hostUrlString(bucket: String? = nil) -> String {
if hostName != nil {
return urlProtocol + host.finished(with: "/") + (bucket ?? "")
}

var bucket = bucket
if let b = bucket {
if let b = bucket, !b.isEmpty {
bucket = b + "."
}
return "https://" + (bucket ?? "") + host.finished(with: "/")

return urlProtocol + (bucket ?? "") + host.finished(with: "/")
}

private var urlProtocol: String {
return useTLS ? "https://" : "http://"
}

}


Expand Down
164 changes: 113 additions & 51 deletions Sources/S3Signer/Region.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,126 @@ import Foundation


/// AWS Region
public enum Region: String, Codable {

/// US East (N. Virginia)
case usEast1 = "us-east-1"

/// US East (Ohio)
case usEast2 = "us-east-2"

/// US West (N. California)
case usWest1 = "us-west-1"

/// US West (Oregon)
case usWest2 = "us-west-2"

/// Canada (Central)
case caCentral1 = "ca-central-1"

/// EU (Frankfurt)
case euCentral1 = "eu-central-1"

/// EU (Ireland)
case euWest1 = "eu-west-1"

/// EU (London)
case euWest2 = "eu-west-2"

/// EU (Paris)
case euWest3 = "eu-west-3"

/// Asia Pacific (Tokyo)
case apNortheast1 = "ap-northeast-1"

/// Asia Pacific (Seoul)
case apNortheast2 = "ap-northeast-2"

/// Asia Pacific (Osaka-Local)
case apNortheast3 = "ap-northeast-3"

/// Asia Pacific (Singapore)
case apSoutheast1 = "ap-southeast-1"

/// Asia Pacific (Sydney)
case apSoutheast2 = "ap-southeast-2"

/// Asia Pacific (Mumbai)
case apSouth1 = "ap-south-1"

/// South America (São Paulo)
case saEast1 = "sa-east-1"

public struct Region {

public let name: RegionName
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add helper comments to these

public let hostName: String?
public let useTLS: Bool

public enum RegionName : String, Codable {
/// US East (N. Virginia)
case usEast1 = "us-east-1"

/// US East (Ohio)
case usEast2 = "us-east-2"

/// US West (N. California)
case usWest1 = "us-west-1"

/// US West (Oregon)
case usWest2 = "us-west-2"

/// Canada (Central)
case caCentral1 = "ca-central-1"

/// EU (Frankfurt)
case euCentral1 = "eu-central-1"

/// EU (Ireland)
case euWest1 = "eu-west-1"

/// EU (London)
case euWest2 = "eu-west-2"

/// EU (Paris)
case euWest3 = "eu-west-3"

/// Asia Pacific (Tokyo)
case apNortheast1 = "ap-northeast-1"

/// Asia Pacific (Seoul)
case apNortheast2 = "ap-northeast-2"

/// Asia Pacific (Osaka-Local)
case apNortheast3 = "ap-northeast-3"

/// Asia Pacific (Singapore)
case apSoutheast1 = "ap-southeast-1"

/// Asia Pacific (Sydney)
case apSoutheast2 = "ap-southeast-2"

/// Asia Pacific (Mumbai)
case apSouth1 = "ap-south-1"

/// South America (São Paulo)
case saEast1 = "sa-east-1"
}

public init(name: RegionName, hostName: String? = nil, useTLS: Bool = true) {
self.name = name
self.hostName = hostName
self.useTLS = useTLS
}
}


extension Region {

/// Base URL / Host
public var host: String {
return "s3.\(rawValue).amazonaws.com"
if let host = hostName {
return host
}
return "s3.\(name.rawValue).amazonaws.com"
}
}

public extension Region {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think the extension needs to have public, only methods within do

init?(rawValue: String) {
guard let name = RegionName(rawValue: rawValue) else {
return nil
}

self.init(name: name)
}

static var usEast1: Region { return Region(name: RegionName.usEast1) }
static var usEast2: Region { return Region(name: RegionName.usEast2) }
static var usWest1: Region { return Region(name: RegionName.usWest1) }
static var usWest2: Region { return Region(name: RegionName.usWest2) }
static var caCentral1: Region { return Region(name: RegionName.caCentral1) }
static var euCentral1: Region { return Region(name: RegionName.euCentral1) }
static var euWest1: Region { return Region(name: RegionName.euWest1) }
static var euWest2: Region { return Region(name: RegionName.euWest2) }
static var euWest3: Region { return Region(name: RegionName.euWest3) }
static var apNortheast1: Region { return Region(name: RegionName.apNortheast1) }
static var apNortheast2: Region { return Region(name: RegionName.apNortheast2) }
static var apNortheast3: Region { return Region(name: RegionName.apNortheast3) }
static var apSoutheast1: Region { return Region(name: RegionName.apSoutheast1) }
static var apSoutheast2: Region { return Region(name: RegionName.apSoutheast2) }
static var apSouth1: Region { return Region(name: RegionName.apSouth1) }
static var saEast1: Region { return Region(name: RegionName.saEast1) }
}

extension Region: Codable {
public init(from decoder: Decoder) throws {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space and comment please

let container = try decoder.singleValueContainer()

let name = try container.decode(String.self)

guard let regionName = RegionName(rawValue: name) else {
throw DecodingError.typeMismatch(String.self, DecodingError.Context(codingPath: [],
debugDescription: "Could not find region for \(name)"))
}

self.name = regionName
self.hostName = nil
self.useTLS = true
}

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(self.name.rawValue)
}
}
6 changes: 3 additions & 3 deletions Sources/S3Signer/S3Signer+Private.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ extension S3Signer {

func createSignature(_ stringToSign: String, timeStampShort: String, region: Region) throws -> String {
let dateKey = try HMAC.SHA256.authenticate(timeStampShort.convertToData(), key: "AWS4\(config.secretKey)".convertToData())
let dateRegionKey = try HMAC.SHA256.authenticate(region.rawValue.convertToData(), key: dateKey)
let dateRegionKey = try HMAC.SHA256.authenticate(region.name.rawValue.convertToData(), key: dateKey)
let dateRegionServiceKey = try HMAC.SHA256.authenticate(config.service.convertToData(), key: dateRegionKey)
let signingKey = try HMAC.SHA256.authenticate("aws4_request".convertToData(), key: dateRegionServiceKey)
let signature = try HMAC.SHA256.authenticate(stringToSign.convertToData(), key: signingKey)
Expand All @@ -44,8 +44,8 @@ extension S3Signer {
}

func credentialScope(_ timeStampShort: String, region: Region) -> String {
var arr = [timeStampShort, region.rawValue, config.service, "aws4_request"]
if region == .none {
var arr = [timeStampShort, region.name.rawValue, config.service, "aws4_request"]
if region.name == .none {
arr.remove(at: 1)
}
return arr.joined(separator: "/")
Expand Down