Upload Image to Amazon S3 Using Swift3 - swift

After looking around at different threads such as these (Swift - AWS S3 Upload Image from Photo Library and download it), and (Upload image AWS S3 bucket in swift), I got pretty close to getting an image upload to work but can't figure out what I'm doing wrong?
I get the following error below in my console.
Error: Error Domain=com.amazonaws.AWSS3TransferUtilityErrorDomain Code=1 "(null)" UserInfo={Server=AmazonS3, Transfer-Encoding=Identity, Connection=close, Content-Type=application/xml, Date=Tue, 13 Dec 2016 05:58:32 GMT, x-amz-request-id=2A76DF0FE33476C5, x-amz-id-2=QWZgOETbWQfddlqKmm0w3Z9HFGM2x1DWnrFjukiajTsIXfbSt9W0orTkoZeNXH/bI1xfc3mxI4Q=, x-amz-bucket-region=us-west-1}
My code is below:
let myIdentityPoolId = "us-west-2:dca2beb4-etcetcetc...."
let credentialsProvider:AWSCognitoCredentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.usWest2, identityPoolId: myIdentityPoolId)
let configuration = AWSServiceConfiguration(region: AWSRegionType.usWest2, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
I then call to upload my image with a function I made below
func uploadImage(filename:String){
print("AWS Upload Image Attempt...")
//defining bucket and upload file name
let S3BucketName: String = "distribution-tech-mobile"
let filepath = "\(AppDelegate.appDelegate.applicationDocumentsDirectory())/\(filename)"
let imageURL = URL(fileURLWithPath: filepath)
let S3UploadKeyName = filename //TODO: Change this later
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = S3BucketName
uploadRequest?.key = filename
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = imageURL
uploadRequest?.serverSideEncryption = AWSS3ServerSideEncryption.awsKms
uploadRequest?.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
self.amountUploaded = totalBytesSent // To show the updating data status in label.
self.fileSize = totalBytesExpectedToSend
print("\(totalBytesSent)/\(totalBytesExpectedToSend)")
})
}
self.uploadCompletionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)");
}
else{
print("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.default()
let expression = AWSS3TransferUtilityUploadExpression()
transferUtility.uploadFile(imageURL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continue({ (task) -> AnyObject! in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let exception = task.exception {
print("Exception: \(exception.description)")
}
if let _ = task.result {
print("Upload Starting!")
}
return nil;
})
}
I get the console message "Upload Starting" and then a message "Failed with error" (which comes from my completion handler), followed by the error I assume from Amazon.
Any thoughts on what I'm doing wrong?

Okay I found the answer, but I have a different problem now that I'll post in another question regarding showing upload progress.
The answer was my bucket was created in the incorrect region. I created my credentials in Oregon, which is Us-West-2, and I created the bucket in Northern California by accident the first time. This apparently created the error.

Related

Can not convert url to html using kanna in swift

using Kanna to parse html from url.tried swfitsoup but same problem.
func getContentFromHtml(urlString : String) -> String{
let url = URL(string: urlString)!
var result = ""
do {
let doc = try HTML(url: url, encoding: .utf8)
for description in doc.xpath("//meta[#property=\"og:description\"]") {
if let contentDescription = description["content"] {
result = contentDescription
}
}
} catch let error {
print(error.localizedDescription)
}
return result
}
I'm getting 34 urls from google rss(https://news.google.com/rss?hl=ko&gl=KR&ceid=KR:ko) through loop and pass to this method.
but with some urls , it doesn't convert url to html with error code
for example, https://news.google.com/__i/rss/rd/articles/CBMiMWh0dHBzOi8vd3d3Lnl0bi5jby5rci9fbG4vMDEwM18yMDIwMDMyNTIxNTk0Mzg0NzXSAUNodHRwczovL20ueXRuLmNvLmtyL25ld3Nfdmlldy5hbXAucGhwP3BhcmFtPTAxMDNfMjAyMDAzMjUyMTU5NDM4NDc1?oc=5
this url from rss is getting error.
The operation couldn’t be completed. (Kanna.ParseError error 1.)
or EncodingMismatch
but these urls are fine to access.
How can I fix it?

Upload file to S3 service 403 ERROR (com.amazonaws.AWSS3TransferUtilityErrorDomain error 2.) Swift iOS

I tried to upload my file to S3 service vie AWSS3 SDK swift.
My code:
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: Config.main.accessKey, secretKey: Config.main.secretKey)
let configuration = AWSServiceConfiguration(region: .USEast1, endpoint: AWSEndpoint(url: URL(string: Config.main.AWS_ENDPOINT)!), credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let image = UIImage(named: "photo")!
let data: Data = image.pngData()!
let remoteName = generateRandomStringWithLength(length: 12) + "." + data.format
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = documentsURL.appendingPathComponent(remoteName)
try! data.write(to: fileURL, options: .atomic)
upload(fileUrl: fileURL, fileData: data, fileName: remoteName, type: .image, completionHandler: {_ in})
func upload(fileUrl: URL, fileData: Data, fileName: String, type: FileTypes, completionHandler: #escaping (URL?) -> ()) {
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = { task, progress in
DispatchQueue.main.async {
print("Progress = \(progress.completedUnitCount)/\(progress.totalUnitCount)")
}
}
let util = AWSS3TransferUtility.default()
util.uploadData(
fileData,
bucket: self.getBucket(type: type),
key: "\(self.getDir(type: type))_\(fileName)",
contentType: "image/png",
expression: expression) { task, error in
print("ERROR: \(error?.localizedDescription)")
print("response: \(task.response)")
print("response: \(task.response)")
}.continueWith { task in
if let error = task.error {
print("ERROR1: \(error.localizedDescription)")
}
return nil
}
}
It returns me something like 5 times progress response and after that
ERROR: Optional("The operation couldn’t be completed.
(com.amazonaws.AWSS3TransferUtilityErrorDomain error 2.)")
response: Optional( { URL:
http://(bucket).(host)/image_L24i8RGCeAaj.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=59589007eea780cf27c5%2F20200131%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200131T125453Z&X-Amz-Expires=2999&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
} { Status Code: 403, Headers {
"Content-Length" = (
186
);
Date = (
"Fri, 31 Jan 2020 12:54:53 GMT"
);
Server = (
LeoFS
); } })
Android app with same setup works perfect.
What is the solution of the problem?
I was having same issue. Everything was working fine on android, While IOS was not working with same configuration.
Then I contacted AWS support, and they told me iPhones Date and time is wrong. I just adjusted date and time to correct date and time and then tried to upload and it worked.
hi if you are not using custom endpoints, change this line:
let configuration = AWSServiceConfiguration(region: .USEast1, endpoint: AWSEndpoint(url: URL(string: Config.main.AWS_ENDPOINT)!), credentialsProvider: credentialsProvider)
to:
let configuration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
and it will work just fine. The SDK can resolve the endpoint of the service by itself without providing an endpoint. You only need to provide an endpoint if you are using custom endpoints. It is also worth noting here that if you did want to pass the endpoint, you need to make sure you are passing the correct endpoint and us-east-1 for s3 has a special endpoint that does not include region as shown below:
let configuration = AWSServiceConfiguration(region: .USEast1,endpoint: AWSEndpoint(url: URL(string: "https://s3.amazonaws.com")) , credentialsProvider: credentialsProvider)
There is some useful info about this at https://medium.com/#lewisjkl/signing-aws4-31dcff1bf1f0, from Jeff Lewis.
It uses the CryptoSwift library; I'm working now to convert it to use the new CryptoKit.
Just check your device date and time. Because, AWS don't accept the wrong date or time.

Error validating CMS signature

For the past 2 weeks I've been banging my head against a wall trying to create and validate CMS signatures in Swift 4 using OpenSSL. My code is ultimately destined to be run on Linux, so I can't use the macOS Security framework. I believe I have finally gotten CMS signature creation working properly. My code for that looks like this:
let testBundle = Bundle(for: type(of: self))
guard let textUrl = testBundle.url(forResource: "test_message", withExtension: "txt"),
let signingKeyUrl = testBundle.url(forResource: "signing_key", withExtension: "pem"),
let signingCertUrl = testBundle.url(forResource: "signing_cert", withExtension: "pem") else {
exit(1)
}
let certFileObject = signingCertUrl.path.withCString { filePtr in
return fopen(filePtr, "rb")
}
defer {
fclose(certFileObject)
}
let keyFileObject = signingKeyUrl.path.withCString { filePtr in
return fopen(filePtr, "rb")
}
defer {
fclose(keyFileObject)
}
guard let key = PEM_read_PrivateKey(keyFileObject, nil, nil, nil),
let cert = PEM_read_X509(certFileObject, nil, nil, nil) else {
exit(1)
}
OpenSSL_add_all_ciphers()
OpenSSL_add_all_digests()
OPENSSL_add_all_algorithms_conf()
guard let textData = FileManager.default.contents(atPath: textUrl.path) else {
exit(1)
}
guard let textBIO = BIO_new(BIO_s_mem()) else {
print("Unable to create textBIO")
exit(1)
}
_ = textData.withUnsafeBytes({dataBytes in
BIO_write(textBIO, dataBytes, Int32(textData.count))
})
guard let cms = CMS_sign(cert, key, nil, textBIO, UInt32(CMS_BINARY)) else {
exit(1)
}
When I debug this code, I see that the cms object is being set after the CMS_sign call, so I believe that the signature was generated properly. Right after this, I'm trying to validate the signature I just created. That code looks like this:
let store = X509_STORE_new()
X509_STORE_add_cert(store, cert)
let outBIO = BIO_new(BIO_s_mem())
let result = CMS_verify(cms, nil, store, nil, outBIO, 0)
print("result : \(result)")
if result != 1 {
let errorCode: UInt = ERR_get_error()
print("ERROR : \(String(format: "%2X", errorCode))")
}
When I run this code, however, result == 0, indicating an error. The error code that OpenSSL is returning is 0x2E099064. I ran this command:
openssl errstr 0x2E099064
Which gave me this info about the error:
error:2E099064:CMS routines:func(153):reason(100)
After a bit more digging, I think that the error corresponds to PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH. I got that from the pkcs7.h file here. I'm not 100% that this is the correct error message, however.
My question is, why is my signature validation failing? I'm using the exact same certificate to validate the signature. All of this code is inline, so nothing is getting lost anywhere. Can any of you give me an idea where things are going wrong?

Downloading a JSON file as an Unauthenticated user AWS/S3/Cognito

I am trying to download a JSON file which is in my bucket in my S3 on my AWS account. I created an Unauthenticated cognito pool and copied this into my app delegate from the sample code:
let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.USWest2,
identityPoolId:"us-west-2:59a31a8f-ee6a-45fe-adaa-fa3eff871c80")
let configuration = AWSServiceConfiguration(region:.USWest2, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
In my view controller I have this code:
let transferManager = AWSS3TransferManager.default()
let downloadingFileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("db_storage/costdb_latest.json ")
if let downloadRequest = AWSS3TransferManagerDownloadRequest(){
downloadRequest.bucket = "coast-s3-bucket"
downloadRequest.key = "db_storage/costdb_latest.json "
downloadRequest.downloadingFileURL = downloadingFileURL
transferManager.download(downloadRequest).continueWith(executor: AWSExecutor.default(), block: { (task: AWSTask<AnyObject>) -> Any? in
if( task.error != nil){
print(task.error!.localizedDescription)
return nil
}
print(task.result!)
if let data = NSData(contentsOf: downloadingFileURL){
DispatchQueue.main.async(execute: { () -> Void in
print(data)
})
}
return nil
})
}
Both the bucket and the pool are in the same region. USWest2 (Oregon). My bucket is public, and I've added AmazonS3FullAccess and AmazonS3ReadOnlyAccess to my policies. And I'm getting this error:
The operation couldn’t be completed. (com.amazonaws.AWSS3ErrorDomain error 4.)
Its not an authentication/authorization error (I think). From the looks of it, there is some issue with the configuration (region,endpoint etc.). Generally, these errors contain a full description of what's wrong. Try logging the full error message.
Also, see this example app for S3 TransferManager. Use your S3 & Cognito details. If this works, there is some code issue and you can find out by comparing both of these. If this does not work, then this could be a service issue.

Downloading metadata from Firebase Storage

unable to get access to my metadata on the new Firebase. Able to get download of article and have them display.
storageRef.child(article).metadataWithCompletion { (metadata, error) in
if error != nil{
print("error getting metadata")
}else{
let metadata1 = FIRStorageMetadata()
let nameMeta = metadata1.downloadURLs
print("nameMeta is \(nameMeta)")
}
output display:
nameMeta is nil
You shouldn't create a new metatada instance, you should use the one already provided in the closure.
else {
let downloadUrl = metadata.downloadUrl()
print(downloadUrl)
}