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

Method getObject returns the error 'NoSuchKey null: The specified key does not exist.' #404

Open
dthuesen opened this issue Jul 4, 2023 · 0 comments

Comments

@dthuesen
Copy link

dthuesen commented Jul 4, 2023

I've tried every possible combination of providing required params.

I'm trying to download a previous version of a pdf file, which exists on the server with getObject. I have checked if the version exists and its versionId in the S3 Console on s3.console.aws.amazon.com. I am also able to list the versions in the ui of the app with use of the method listObjectVersions.

In the app and on S3 I use a prefix called teamId (name is an uuid) to structure the files.

When trying to download a version of a file the code looks like this:

Future<Uint8List?> getConsentByFileIdAndVersionId({
    required String fileId,
    required String versionId,
    required String teamId,
  }) async {
    GetObjectOutput? getObjectOutput;

    /// Access to the S3 instance via the singleton
    final s3Singleton = S3Singleton();
    await s3Singleton.initializeS3Client();
    final accessLevel = s3Singleton.defaultAccessLevel;
    final identityId = s3Singleton.identityId;

    final bucket = s3Singleton.bucket;

    /// These are the different attempts to get the 'key' working
    final keyParam = "$fileId";
    // final keyParam = "$teamId/$fileId";
    // final keyParam = "$identityId/$accessLevel/$teamId/$fileId";
    // final keyParam = "$accessLevel/$teamId/$fileId";
    
    log("keyParam: $keyParam", name: "StorageClient");
    if (bucket != null) {
      try {
        getObjectOutput = await s3Singleton.s3?.getObject(
          bucket: bucket,
          key: keyParam,
          versionId: versionId,
        );
        return getObjectOutput?.body;
      } on Exception catch (e, s) {
        log("EXCEPTION in getConsentByFileIdAndVersionId",
            error: e, stackTrace: s, name: "StorageClient");
        return null;
      }
    }
    return null;
  }

Properties mentioned in the code above:

  • fileId is provided by the app, it separates files of different teams
  • identityId consists of the region and an id given by s3 separated by a colon.
  • accessLevel in the case of my app is 'private'
  • identityId is taken from the file's list of versions in the ui and have checked it's existence

Following the code for the s3Singleton:

class S3Singleton {
  static final S3Singleton _singleton = S3Singleton._internal();
  S3? s3;
  String? region;
  String? bucket;
  String? defaultAccessLevel;
  String? identityId;

  factory S3Singleton() {
    return _singleton;
  }

  S3Singleton._internal();

  Future<S3?> initializeS3Client() async {
    AWSCredentials? awsCredentials;

    if (s3 == null) {
      awsCredentials = await fetchCognitoAuthSession();

      final Map<String, dynamic> amplifyConfig =
          jsonDecode(amplifyCofiguration.amplifyconfig);

      region =
          amplifyConfig["storage"]?["plugins"]["awsS3StoragePlugin"]["region"];
      bucket =
          amplifyConfig["storage"]?["plugins"]["awsS3StoragePlugin"]["bucket"];

      /// TODO: figure out how to change the default access level on S3.
      ///
      /// Since currently the default access level is configured to 'guest'
      /// and I currently have no clue to change that, it will stay here
      /// as hard coded value.
      defaultAccessLevel = 'private';
      // defaultAccessLevel = amplifyConfig["storage"]?["plugins"]
      //     ["awsS3StoragePlugin"]["defaultAccessLevel"];

      log("region: $region");
      log("awsCredentials: $awsCredentials");

      if (awsCredentials != null && region != null) {
        log("identityId: $identityId");
        final accessKey = awsCredentials.accessKeyId;
        final secretKey = awsCredentials.secretAccessKey;
        final expiration = awsCredentials.expiration;
        final sessionToken = awsCredentials.sessionToken;

        final s3Credentials = AwsClientCredentials(
          accessKey: accessKey,
          secretKey: secretKey,
          expiration: expiration,
          sessionToken: sessionToken,
        );
        s3 = S3(region: region!, credentials: s3Credentials);
        return s3;
      }
    }
    return s3;
  }

  Future<AWSCredentials?> fetchCognitoAuthSession() async {
    try {
      final cognitoPlugin =
          Amplify.Auth.getPlugin(AmplifyAuthCognito.pluginKey);

      final result = await cognitoPlugin.fetchAuthSession();
      identityId = result.identityIdResult.value;

      final AWSCredentials awsCredentials = result.credentialsResult.value;

      return awsCredentials;
    } on SessionExpiredException catch (e, s) {
      log('''
        
        SessionExpiredException in initializeS3Client, 
        recovery:            ${e.recoverySuggestion} 
        
        underlyingException: ${e.underlyingException}
                
        message:             ${e.message}
        ''', error: e, stackTrace: s, name: "StorageClient", level: 400);
      return null;
    } on AuthException catch (e) {
      safePrint('Error retrieving awsCredentials: ${e.message}');
      return null;
    }
  }
}

Since I've spent some days to get it running, I now try it here. Maybe this is an issue of the library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant