I am trying to download an object from existing s3 bucket to IOS app using amplify-swift.
I've followed the tutorial to init amplify, and import storage.
I am trying to do a call for an unauthenticated user->
In Cognito console I defined a role for unauth user, (and allowed access to unauth users), gave him permissions to my bucket and verified with simulator that getObject works.
When calling this code:
let key = "images/some_file.txt"
do {
try Amplify.add(plugin: AWSCognitoAuthPlugin())
try Amplify.add(plugin: AWSS3StoragePlugin())
try Amplify.configure()
print("Amplify configured with storage plugin")
} catch {
print("Failed to initialize Amplify with \(error)")
}
Amplify.Storage.downloadData(
key: key,
progressListener: { progress in
print("Progress: \(progress)")
}, resultListener: { (event) in
switch event {
case let .success(data):
print("Completed: \(data)")
case let .failure(storageError):
print("Failed: \(storageError.errorDescription). \(storageError.recoverySuggestion)")
}
})
I get this error:
Amplify configured with storage plugin 2021-03-31 18:09:09.988304+0300
ota[30840:728969] [] nw_protocol_get_quic_image_block_invoke dlopen
libquic failed Progress: <NSProgress: 0x6000001d50e0> : Parent: 0x0
(portion: 0) / Fraction completed: 0.0000 / Completed: 243 of -1
Failed: The HTTP response status code is [403].. TODO some status code
to recovery message mapper. For more information on HTTP status codes,
take a look at https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
I checked that the pool id, bucket name are all defined correctly in the json files.
What am I missing?
EDIT:
this seems to work, so i know the actual problem is not with the permissions, but rather with the amplify default download:
let expression = AWSS3TransferUtilityDownloadExpression()
expression.progressBlock = {(task, progress) in DispatchQueue.main.async(execute: {
print("Downloading...")
})
}
let credentialProvider = AWSCognitoCredentialsProvider(regionType: .EUWest1, identityPoolId: "eu-west-1:xxxxxx")
let configuration = AWSServiceConfiguration(region: .EUWest1, credentialsProvider: credentialProvider)
AWSS3TransferUtility.register(with: configuration!, forKey: "customTU")
let tu = AWSS3TransferUtility.s3TransferUtility(forKey: "customTU")
tu?.downloadData(fromBucket: bucket, key: _key, expression: expression) { (task, URL, data, error) in
if error != nil {
print(error!)
}
DispatchQueue.main.async(execute: {
print("Got here")
let rawJSON = (String(data: data!, encoding: .utf8))!
print(rawJSON)
})
}
Related
We are trying to upload audio to AWS S3 bucket using method(AWSS3TransferUtility). Pod - AWSS3. We are getting below error.
Error description:
Error Domain=com.amazonaws.AWSS3TransferUtilityErrorDomain Code=2 "(null)" UserInfo={Server=AmazonS3, Transfer-Encoding=Identity, Connection=close, Content-Type=application/xml, Date=Fri, 06 Sep 2021 04:43:50 GMT, x-amz-request-id=VH53PCCWA529FDRC, x-amz-id-2=4uZoqJj+TJ93WUBSnrC889CAj3gkGGw/V6iJjhrVjB2+ZygTflGcPAV+amfxmeBGeGHHVXv3nHk=}
func uploadFile(withImage image: UIImage) {
let credentialsProvider = AWSCognitoCredentialsProvider(regionType:AWSRegionType.USEast2,
identityPoolId:"us-east-2:fe41c293-df49-49a4-886d-094f2cd8d0fd")
let configuration = AWSServiceConfiguration(region:.USEast2, credentialsProvider:credentialsProvider)
let tuConf = AWSS3TransferUtilityConfiguration()
AWSS3TransferUtility.register(
with: configuration!,
transferUtilityConfiguration: tuConf,
forKey: "transfer-utility-with-advanced-options"
)
let transferUtility = AWSS3TransferUtility.s3TransferUtility(forKey: "transfer-utility-with-advanced-options")
AWSServiceManager.default().defaultServiceConfiguration = configuration
let s3BucketName = "testingimageupload"
let data: Data = image.pngData()!
let remoteName = generateRandomStringWithLength(length: 12)+"."+"png"
print("REMOTE NAME : ",remoteName)
let expression = AWSS3TransferUtilityUploadExpression()
expression.setValue("public-read", forRequestHeader: "x-amz-acl")
expression.progressBlock = { (task, progress) in
DispatchQueue.main.async(execute: {
// Update a progress bar
})
}
var completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
completionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
})
}
transferUtility!.uploadData(data, bucket: s3BucketName, key: "private/Abhay/" + remoteName, contentType: "image/"+"png", expression: expression, completionHandler: completionHandler).continueWith { (task) -> Any? in
if let error = task.error {
print("Error : \(error.localizedDescription)")
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent(s3BucketName).appendingPathComponent(remoteName)
if let absoluteString = publicURL?.absoluteString {
// Set image with URL
print("Image URL : ",absoluteString)
}
}
return nil
}
Prerequisite : Setup AWS Amplify CLI.
1. Project initialisation.
amplify init: Setup AWS Amplify locally & remote.
Note: amplify init command not found
1)`npm install -g #aws-amplify/cli` - ### install the Amplify CLI ###
2)`curl -sL https://aws-amplify.github.io/amplify-cli/install | bash && $SHELL` ### configured $Path correctly ###
3)`amplify init` ###Try Amplify init###
Amplify Demo project or click enter for the default name : Enter a name for the project
Dev or click enter for the default name : Enter a name for the Environment
Choose Visual Studio Code : Choose your default Editor
iOS : Choose the type of app that you’re building
yes : Do you want to use an AWS Profile?
2. Project Storage setup
amplify add storage : Add storage
Content(Images, audio, video, etc.) : Select the below mentioned services
yes : (Amazon Cognito) Do you want to add auth now?
No: Do you want to configure advanced settings?
bucket name or click enter for the default name : Please provide bucket name
Auth users only or Auth and guest users : Who should have access
create/update , read , delete. : What kind of access do you want for Authenticated users?
create/update , read , delete.: What kind of access do you want for guest users?
No : Do you want add a lama trigger for your S3 Bucket?
3. Push - Amplify configuration to backend
amplify push : Amplify Push
Yes: are you sure you want to continue ?
Pod install
target ‘ProjectName do
use_frameworks!
pod 'Amplify'
pod 'AmplifyPlugins/AWSS3StoragePlugin'
pod 'AmplifyPlugins/AWSCognitoAuthPlugin'
end
Code: ViewController.swift
import Amplify
import AmplifyPlugins
func configureAmplify() {
do {
try Amplify.add(plugin: AWSCognitoAuthPlugin())
try Amplify.add(plugin: AWSS3StoragePlugin())
try Amplify.configure()
print("Successfully configured Amplify")
} catch {
print("Could not configure Amplify", error)
}
}
func uploadFile() {
let audioUrl = URL(string: "/Users/appaiah/Downloads/RealAudio.mp3")!
Amplify.Storage.uploadFile(key: fileKey, local: audioUrl){ // let fileKey = "SampleAudio.mp3"
result in
switch result {
case .success(let key):
print("file with key uploaded \(key)")
case .failure(let error):
print("failed \(error)")
}
}
}
func downloadFile(){
let downloadToFileName = getTermsOfUseURL()
Amplify.Storage.downloadFile(
key: fileKey,
local: downloadToFileName,
progressListener: { progress in
print("Progress: \(progress)")
}, resultListener: { event in
switch event {
case .success:
print("Completed")
DispatchQueue.main.async { }
case .failure(let storageError):
print("Failed: \(storageError.errorDescription). \(storageError.recoverySuggestion)")
}
})
}
func getTermsOfUseURL() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
print(paths[0].appendingPathComponent(fileKey))
return paths[0].appendingPathComponent(fileKey)
}
I'm not able to do a S3 Upload despite AWS Cognito indicating that the device is signedIn and the IdentityID being obtained.
The storage error description is "Session expired could not fetch identity id". This is despite the identityID that was returned and passed into the s3 upload file function.
Logs into AWS Cognito using the ASAuthorizationAppleIDCredential.identityToken
Also obtains the IdentityID
func SignIn() {
awsmobileclient.federatedSignIn(providerName: IdentityProvider.apple.rawValue,
token: identityToken) { (userState, error) in
if let error = error {
print("Error in federatedSignIn: \(error)")
return
}
guard let userState = userState else {
print("userState unexpectedly nil")
return
}
print("federatedSignIn successful: \(userState.rawValue)")
sleep(5)
// Retrieve your Amazon Cognito ID
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .CACentral1, identityPoolId: "ca-central-1:3e8d12d5-9739-4934-8eb0-df6bec232d77")
let configuration = AWSServiceConfiguration(region: .CACentral1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
credentialsProvider.getIdentityId().continueWith(block: { (task) -> AnyObject? in
if (task.error != nil) {
print("Error: " + task.error!.localizedDescription)
}
else {
// the task result will contain the identity id
let cognitoId = task.result!
print("Cognito id: \(cognitoId)")
UserDefaults.standard.set(cognitoId, forKey: "cognitoId")
}
return task;
})
}
Uploads Data to S3
func uploadData(key: String, data: Data) {
var progressSink: AnyCancellable?
var resultSink: AnyCancellable?
let options = StorageUploadDataRequest.Options(accessLevel: .private, targetIdentityId: UserDefaults.standard.string(forKey: "cognitoId"), contentType: "image/jpeg")
let storageOperation = Amplify.Storage.uploadData(key: key, data: data, options: options)
progressSink = storageOperation.progressPublisher.sink { progress in print("Progress: \(progress)") }
resultSink = storageOperation.resultPublisher.sink {
if case let .failure(storageError) = $0 {
print("Failed: \(storageError.errorDescription). \(storageError.recoverySuggestion)")
}
}
receiveValue: { data in
print("Completed: \(data)")
}
}
Turns out it was likely due to AWS Cognito settings. AWS Cognito configured as, "enable access to unauthenticated users" unchecked, Allow Basic (Classic) Flow checked, Apple Services ID should be Bundle ID, Role Selection Default, Attributes Disabled.
This was done using the AWS Amplify Escape Hatch to AWS Mobile Client SDK with the AWSMobileClient.federatedSignIn
In my iOS app, I try to download a file from an AWS S3 bucket. Here is what I tried:
I initialize AWSMobileClient:
import AWSMobileClient
import AWSS3
let configuration = AWSServiceConfiguration(
region: AWSRegionType.EUCentral1,
credentialsProvider: AWSMobileClient.default())
AWSServiceManager.default().defaultServiceConfiguration = configuration
AWSMobileClient.default().initialize { (userState: UserState?, error: Error?) in
if (userState != nil)
{
print("Initialize OK : \(userState.debugDescription)")
}
if (error != nil)
{
print("Initialize error: \(String(describing: error))")
}
}
I got:
"initialize OK : Optional(AWSMobileClient.UserState.guest)"
Now I try to download a file:
let expression = AWSS3TransferUtilityDownloadExpression()
expression.progressBlock = {(task, progress) in DispatchQueue.main.async(execute: {
print("Progress : \(progress)")
})
}
let completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock = {
(task: AWSS3TransferUtilityDownloadTask, url: URL?, data: Data?, error: Error?) -> Void in
DispatchQueue.main.async(execute: {
print("End download 1")
})
}
let fileManager = FileManager.default
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("100.ogg")
let transferUtility: AWSS3TransferUtility = AWSS3TransferUtility.default()
transferUtility.download(
to: fileURL,
bucket: "my-s3-bucket",
key: "100.ogg",
expression: expression,
completionHandler: completionHandler).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("Error download : \(error)")
}
if let result = task.result {
print("Result : \(result.debugDescription)")
}
print("End download 2 : \(fileManager.fileExists(atPath: fileURL.absoluteString))")
return nil
}
I got:
"Result : <AWSS3TransferUtilityDownloadTask: 0x6000020bd4d0>
"End download 2 : false"
I don't get any progress, and I also don't get the "End download 1"
So basically, I dont get any error, but it does look like nothing has been downloaded. Also, on a side note, it works well with the Android version of my app, so it's very likely that there is an error in my code.
So what should I change to make it work?
Thanks.
My bad, the example above is actually working, But I had to:
change fileManager.fileExists(atPath: fileURL.absoluteString)) by fileManager.fileExists(atPath: fileURL.path))
check if file exists in the first completionHandler (where I wrote print("End download 1"))
I am trying to integrate S3 upload to upload a video file and tried Developer authenticated Identity method. Everything is configured as per the aws docs says.
DeveloperAuthenticatedIdentityProvider Class :
class DeveloperAuthenticatedIdentityProvider : AWSCognitoCredentialsProviderHelper {
override func token() -> AWSTask<NSString> {
//return AWSTask //with token and will set identityId
}
and then
let devAuth = DeveloperAuthenticatedIdentityProvider(regionType: COGNITO_REGION, identityPoolId: COGNITO_POOL_ID, useEnhancedFlow: true, identityProviderManager:nil)
let credentialsProvider =
AWSCognitoCredentialsProvider(regionType: COGNITO_REGION, identityProvider:devAuth)
let configuration =
AWSServiceConfiguration(region: S3_REGION, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
after configuring these things tried to upload using AWSS3TransferManager
let transferManager = AWSS3TransferManager.default()
let uploadingFileURL = URL(fileURLWithPath: "your/file/path/myTestFile.txt")
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.bucket = "myBucket"
uploadRequest.key = "myTestFile.txt"
uploadRequest.body = uploadingFileURL
transferManager.upload(uploadRequest).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if let error = task.error as? NSError {
if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
switch code {
case .cancelled, .paused:
break
default:
print("Error uploading: \(uploadRequest.key) Error: \(error)")
}
} else {
print("Error uploading: \(uploadRequest.key) Error: \(error)")
}
return nil
}
let uploadOutput = task.result
print("Upload complete for: \(uploadRequest.key)")
return nil
})
Whenever I call Upload method it shows
[Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8
"(null)" UserInfo={__type=NotAuthorizedException,
message=Unauthenticated access is not supported for this identity
pool.}]
also DeveloperAuthenticatedIdentityProvider not getting fired
kindly please help.
When you using Developer authenticated identity for cognito identity provider you need not use
AWSS3TransferManager.default()
You need to register the AWSServiceConfiguration to the AWSS3TransferManager with a key.
AWSS3TransferManager.register(with: configuration!, forKey:
"KEY")
Try this way:
let devAuth = DeveloperAuthenticatedIdentityProvider(regionType: COGNITO_REGION, identityPoolId: COGNITO_POOL_ID, useEnhancedFlow: true, identityProviderManager:nil)
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: COGNITO_REGION, identityProvider:devAuth)
let configuration = AWSServiceConfiguration(region: S3_REGION, credentialsProvider:credentialsProvider)
AWSS3TransferManager.register(with: configuration!, forKey: "YOUR_KEY")
//Start Upload
let uploadRequest = AWSS3TransferManagerUploadRequest()
//Set all properties to uploadRequest
AWSS3TransferManager.s3TransferManager(forKey: "YOUR_KEY").upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
// Do something with the response
if task.isCancelled {
print("Cancelled Upload")
}
else if (task.error != nil) {
print("Upload error --> \(task.error)")
}else{
print("Upload success!!! Be happy :)")
}
return task
})
Just try, I think it may work.
Im trying to upload image to Aws S3 bucket. I tried to follow a tutorial and I'm getting a error saying "Returning ENOTCONN because protocol has not yet been set up." I'm new to swift and I'm not able to understand why the error is occurring also.My code for S3 upload is as follows:
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.body = url!
uploadRequest?.key = remoteFileName
uploadRequest?.bucket = S3BucketName
uploadRequest?.contentType = "image/" + ext
let transferManager = AWSS3TransferManager.default()
// Perform Upload
transferManager.upload(uploadRequest!).continueWith(block: { (task:AWSTask<AnyObject>) -> AnyObject! in
if let error = task.error{
print("error \(error.localizedDescription)")
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent((uploadRequest?.bucket!)!).appendingPathComponent((uploadRequest?.key!)!)
print("Uploaded to:\(publicURL)")
}
return nil
})
My S3 is in ap-south-1 and cognito pool id in us-west-2. I guess thats creating the problem.Is there a way to fix the issue without creating another bucket in us-west-2.
I get the following error:
You want the bucket policy to be somewhat like this if the cognito pool is not set up for authentication: Notice Principal and Action values
Also, is there any particular reason you're using AWSS3TransferManagerUploadRequest? If the policy doesn't resolve your issue, you can use the following code for AWSS3TransferUtilityUploadExpression which sends your data in chunks asynchronously.
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = progressBlock
transferUtility.uploadData(UIImagePNGRepresentation(imageNew!)!,
bucket: "bucket-name",
key: (imgName.removeWhitespace()),
contentType: "image/png",
expression: expression,
completionHandler: completionHandler).continueWith { (task) -> AnyObject! in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let _ = task.result {
print("Upload Starting!")
// Do something with uploadTask.
}
return nil;
}