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

The example useage code under managing security tokens contains an error #983

Closed
yoursweater opened this issue Oct 24, 2019 · 4 comments
Closed
Assignees
Labels
amplify/js Issues tied to JS

Comments

@yoursweater
Copy link

Describe the bug
The example useage code listed under Managing Security Tokens does not work because it references a nonexistent variable "MemoryStorage".

This is the code:


    /**
     * Will sync the MemoryStorage data from AsyncStorage to storageWindow MemoryStorage
    */
    static sync() {
        if (!MemoryStorage.syncPromise) {
            MemoryStorage.syncPromise =  new Promise((res, rej) => {
                AsyncStorage.getAllKeys((errKeys, keys) => {
                    if (errKeys) rej(errKeys);
                    const memoryKeys = keys.filter((key) => key.startsWith(MEMORY_KEY_PREFIX));
                    AsyncStorage.multiGet(memoryKeys, (err, stores) => {
                        if (err) rej(err);
                        stores.map((result, index, store) => {
                            const key = store[index][0];
                            const value = store[index][1];
                            const memoryKey = key.replace(MEMORY_KEY_PREFIX, '');
                            dataMemory[memoryKey] = value;
                        });
                        res();
                    });
                });
            });
        }
        return MemoryStorage.syncPromise;
    }
}

Auth.configure({
    storage: MyStorage
});

MemoryStorage should in fact be this. It's possible that calling it "MemoryStorage" in this code is an attempt to specify and/or make clear what type the variable is expected to be, but it makes the question of how to use this code more confusing to end users, not less. If you want to keep things abstract and define the "type", do that in the concept code that precedes it, not in the "example useage" code which is supposed to show how it works in practice. Moreover, it differs from other examples because that particular variable will always be this, as it is a reference to itself, and not some variable that could be passed as an argument, such as code in the example useage of Auth.signUp().

@sofyan-ahmad
Copy link

sofyan-ahmad commented Apr 30, 2020

Hey, why this issue hasn't been resolved yet?
It's really miss leading, especially for beginners

Here is my implementation on custom auth storage in typescript

import AsyncStorage from '@react-native-community/async-storage';
import {ICognitoStorage} from 'amazon-cognito-identity-js';

const MEMORY_KEY_PREFIX = '@fcAuth:';
let dataMemory = {};
const syncPromise: Promise<any> = null;

/**
 * This is used to set a specific item in storage
 */
function setItem(key: string, value: any) {
  AsyncStorage.setItem(MEMORY_KEY_PREFIX + key, value);
  dataMemory[key] = value;
  return dataMemory[key];
}

/**
 * This is used to get a specific key from storage
 */
function getItem(key: string) {
  return Object.prototype.hasOwnProperty.call(dataMemory, key)
    ? dataMemory[key]
    : undefined;
}

/**
 * This is used to remove an item from storage
 */
function removeItem(key: string) {
  AsyncStorage.removeItem(MEMORY_KEY_PREFIX + key);
  return delete dataMemory[key];
}

/**
 * This is used to clear the storage
 */
function clear() {
  dataMemory = {};
  return dataMemory;
}

/**
 * Will sync the MemoryStorage data from AsyncStorage to storageWindow MemoryStorage
 */
async function sync() {
  if (!syncPromise) {
    try {
      // syncPromise = new Promise((res, rej) => {
      const keys = await AsyncStorage.getAllKeys();

      const memoryKeys = keys.filter((key: string) =>
        key.startsWith(MEMORY_KEY_PREFIX),
      );

      const stores: string[][] = await AsyncStorage.multiGet(memoryKeys);

      stores.map((store: string[]) => {
        const key = store[0];
        const value = store[1];
        const memoryKey = key.replace(MEMORY_KEY_PREFIX, '');

        dataMemory[memoryKey] = value;
      });
    } catch (err) {
      console.error(err);
    }
  }

  return syncPromise;
}

export const AuthStorage: ICognitoStorage & {sync: () => Promise<any>} = {
  setItem,
  getItem,
  removeItem,
  clear,
  sync,
};

Please AWS Amplify team you can do better than this

@janndriessen
Copy link

janndriessen commented Jun 4, 2020

Not sure if this is the right place but @sofyan-ahmad's response helped me a lot (thank you!) to solve my issues. Found my way here through different issues (as aws-amplify/amplify-js#4272) and solutions (like aws-amplify/amplify-js#3422 (comment)).

For me, most solutions with the community version of AsyncStorage did not work as I was already using the RC of v2 - which was necessary for other important parts of the app.

"@react-native-community/async-storage": "2.0.0-rc.3",
"@react-native-community/async-storage-backend-legacy": "2.0.0-rc.3",
"amazon-cognito-identity-js": "4.2.1",
"aws-amplify": "2.3.0",
"react": "16.9.0",
"react-native": "0.61.2",

So for anyone using @react-native-community/async-storage@2.0.0-rc.3, this is how it worked for me.

import {ICognitoStorage} from "amazon-cognito-identity-js";
import AsyncStorageFactory from "@react-native-community/async-storage";
import LegacyStorage from "@react-native-community/async-storage-backend-legacy";

const legacyStorage = new LegacyStorage();
const storage = AsyncStorageFactory.create(legacyStorage, {});

const MEMORY_KEY_PREFIX = "@MemoryStorage:";
let dataMemory: any = {};

let syncPromise: Promise<any>;

const clear = () => {
  dataMemory = {};
  return dataMemory;
};

const getItem = (key: string) => {
  return Object.prototype.hasOwnProperty.call(dataMemory, key)
    ? dataMemory[key]
    : undefined;
};

const removeItem = (key: string) => {
  storage.remove(MEMORY_KEY_PREFIX + key);
  return delete dataMemory[key];
};

const setItem = (key: string, value: any) => {
  storage.set(MEMORY_KEY_PREFIX + key, value);
  dataMemory[key] = value;
  return dataMemory[key];
};

const sync = async () => {
  if (!syncPromise) {
    try {
      const keys = await storage.getKeys();

      const memoryKeys = keys.filter((key: string | number | symbol) => {
        if (typeof key === "string") {
          return key.startsWith(MEMORY_KEY_PREFIX);
        }
      });

      const stores: {
        [x: string]: any;
        [x: number]: any;
      } = await storage.getMultiple(memoryKeys);

      for (let key in stores) {
        const value = stores[key];
        const memoryKey = key.replace(MEMORY_KEY_PREFIX, "");
        dataMemory[memoryKey] = value;
      }
    } catch (err) {
      console.log(err);
    }
  }

  return syncPromise;
};

export const AmplifyAuthStorage: ICognitoStorage & {
  sync: () => Promise<any>;
} = {
  setItem,
  getItem,
  removeItem,
  clear,
  sync,
};

And when configuring Amplify:

Amplify.configure({
  Auth: {
    storage: AmplifyAuthStorage,
  },
});

@ashika01
Copy link
Contributor

Thank you all for the content provided. We have updated the docs to reflect the right usage.

@gHashTag
Copy link

gHashTag commented Jul 7, 2020

Async-storage is not secure storage. How to do the same with react-native-keychain?
I have a solution, but I do not know if it is right.

const MEMORY_KEY_PREFIX = '@MyStorage:'

let dataMemory: any = {}

class MyStorage {
  // the promise returned from sync function
  static syncPromise = null

  // set item with the key
  static setItem(key: string, value: string): string {
    Keychain.setGenericPassword(MEMORY_KEY_PREFIX + key, value)
    dataMemory[key] = value
    return dataMemory[key]
  }

  // get item with the key
  static getItem(key: string): string {
    return Object.prototype.hasOwnProperty.call(dataMemory, key) ? dataMemory[key] : undefined
  }

  // remove item with the key
  static removeItem(key: string): boolean {
    Keychain.resetGenericPassword()
    return delete dataMemory[key]
  }

  // clear out the storage
  static clear(): object {
    dataMemory = {}
    return dataMemory
  }
}

Amplify.configure({
  ...awsconfig,
  Analytics: {
    disabled: false
  },
  storage: MyStorage
})

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
amplify/js Issues tied to JS
Projects
None yet
Development

No branches or pull requests

6 participants