From 2b66799a514e91a7636e2f71ef57b197a542a4fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2020 18:05:23 +0000 Subject: [PATCH 01/16] Bump lodash from 4.17.15 to 4.17.19 in /example Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19) Signed-off-by: dependabot[bot] --- example/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/yarn.lock b/example/yarn.lock index 3021d0a..c306b2c 100644 --- a/example/yarn.lock +++ b/example/yarn.lock @@ -3389,9 +3389,9 @@ lodash.throttle@^4.1.1: integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.6.1: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + version "4.17.19" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" + integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: version "1.4.0" From 6c5bcef97adb75acc739d41a00c19c3fb20132f6 Mon Sep 17 00:00:00 2001 From: David Govea Date: Mon, 27 Jul 2020 20:59:36 -0700 Subject: [PATCH 02/16] fix(types): update const initializer to enum in typedef --- index.d.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/index.d.ts b/index.d.ts index d508de0..a68b2f3 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,14 +1,14 @@ declare module 'react-native-secure-key-store' { - export const ACCESSIBLE = { - AFTER_FIRST_UNLOCK: 'AccessibleAfterFirstUnlock', - AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY: + export enum ACCESSIBLE { + AFTER_FIRST_UNLOCK = 'AccessibleAfterFirstUnlock', + AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY = 'AccessibleAfterFirstUnlockThisDeviceOnly', - ALWAYS: 'AccessibleAlways', - ALWAYS_THIS_DEVICE_ONLY: 'AccessibleAlwaysThisDeviceOnly', - WHEN_PASSCODE_SET_THIS_DEVICE_ONLY: + ALWAYS = 'AccessibleAlways', + ALWAYS_THIS_DEVICE_ONLY = 'AccessibleAlwaysThisDeviceOnly', + WHEN_PASSCODE_SET_THIS_DEVICE_ONLY = 'AccessibleWhenPasscodeSetThisDeviceOnly', - WHEN_UNLOCKED: 'AccessibleWhenUnlocked', - WHEN_UNLOCKED_THIS_DEVICE_ONLY: 'AccessibleWhenUnlockedThisDeviceOnly', + WHEN_UNLOCKED = 'AccessibleWhenUnlocked', + WHEN_UNLOCKED_THIS_DEVICE_ONLY = 'AccessibleWhenUnlockedThisDeviceOnly', } interface RNSecureKeyStore { From 9d9dc0148716e22a8630a52b88b4f2f8bb2fde63 Mon Sep 17 00:00:00 2001 From: David Govea Date: Mon, 27 Jul 2020 22:07:47 -0700 Subject: [PATCH 03/16] chore: use `safeExtGet` approach to prioritize project-level android build settings --- android/build.gradle | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 28daa45..2d6de7e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,4 +1,8 @@ +def safeExtGet(prop, fallback) { + rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback +} + buildscript { // The Android Gradle plugin is only required when opening the android folder stand-alone. // This avoids unnecessary downloads and potential conflicts when the library is included as a @@ -18,12 +22,12 @@ buildscript { apply plugin: 'com.android.library' android { - compileSdkVersion 28 - buildToolsVersion "28.0.3" + compileSdkVersion safeExtGet('compileSdkVersion', 28) + buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3') defaultConfig { - minSdkVersion 16 - targetSdkVersion 28 + minSdkVersion safeExtGet('minSdkVersion', 16) + targetSdkVersion safeExtGet('targetSdkVersion', 28) versionCode 1 versionName "1.0" } From 2996abb4de16fd92e240f1921a7d4f7dbf5767dd Mon Sep 17 00:00:00 2001 From: David Govea Date: Tue, 28 Jul 2020 10:27:01 -0700 Subject: [PATCH 04/16] fix(example): enable AndroidX Technically, `androidx.annotation:annotation` should be included in the library's build.gradle, since it is used in java sourcecode. --- example/android/gradle.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 89e0d99..59d5aab 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -16,3 +16,5 @@ # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true +android.useAndroidX=true +android.enableJetifier=true \ No newline at end of file From daf829154064a0cf6a8aae3262fe1ad1505d52ce Mon Sep 17 00:00:00 2001 From: David Govea Date: Tue, 28 Jul 2020 10:27:26 -0700 Subject: [PATCH 05/16] fix(example): fix metro bundling issues with metro.config.js in example app --- example/metro.config.js | 12 ++++++++++++ example/package.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 example/metro.config.js diff --git a/example/metro.config.js b/example/metro.config.js new file mode 100644 index 0000000..3f6e714 --- /dev/null +++ b/example/metro.config.js @@ -0,0 +1,12 @@ +const path = require("path"); + +const packagePath = path.resolve(__dirname, "../"); + +module.exports = { + resolver: { + extraNodeModules: { + "react-native-secure-key-store": packagePath, + }, + }, + watchFolders: [packagePath], +}; diff --git a/example/package.json b/example/package.json index b534326..87420c2 100644 --- a/example/package.json +++ b/example/package.json @@ -9,7 +9,7 @@ "dependencies": { "react": "16.6.3", "react-native": "0.58.1", - "react-native-secure-key-store": "../../react-native-secure-key-store" + "react-native-secure-key-store": "file:.." }, "devDependencies": { "babel-core": "^7.0.0-bridge.0", From c331182f4a10b24859bdafbdec8cc5c160919cbc Mon Sep 17 00:00:00 2001 From: pradeep singh Date: Wed, 5 Aug 2020 23:12:46 +0530 Subject: [PATCH 06/16] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b9d4262..789896d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-secure-key-store", - "version": "2.0.7", + "version": "2.0.8", "description": "React Native Library for securely storing keys to iOS and Android devices in KeyChain and KeyStore respectively.", "main": "index.js", "publishConfig": { From e681d0a7e2363f0b3347cc50ea75d0ed8da29366 Mon Sep 17 00:00:00 2001 From: David Govea Date: Thu, 6 Aug 2020 15:06:59 -0700 Subject: [PATCH 07/16] fix: update type signature of set() - third argument is an options object --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index a68b2f3..d6f0459 100644 --- a/index.d.ts +++ b/index.d.ts @@ -13,7 +13,7 @@ declare module 'react-native-secure-key-store' { interface RNSecureKeyStore { get: (key: string) => Promise - set: (key: string, value: string, accessible?: ACCESSIBLE) => Promise + set: (key: string, value: string, options?: { accessible?: ACCESSIBLE }) => Promise remove: (key: string) => Promise setResetOnAppUninstallTo: (enabled: boolean) => boolean } From 08285e25bcaadbd53daeb8f006a7f1bbb90ce6ea Mon Sep 17 00:00:00 2001 From: Corbin Crutchley Date: Sat, 8 Aug 2020 14:12:27 -0700 Subject: [PATCH 08/16] Made "getPlainText" a public method for use in native code --- .../com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java b/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java index b9daade..9cc77c1 100644 --- a/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java +++ b/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java @@ -194,7 +194,7 @@ public class RNSecureKeyStoreModule extends ReactContextBaseJavaModule { return new SecretKeySpec(decryptRsaCipherText(getPrivateKey(alias), cipherTextBytes), Constants.AES_ALGORITHM); } - private String getPlainText(String alias) throws GeneralSecurityException, IOException { + public String getPlainText(String alias) throws GeneralSecurityException, IOException { SecretKey secretKey = getSymmetricKey(alias); byte[] cipherTextBytes = Storage.readValues(getContext(), Constants.SKS_DATA_FILENAME + alias); return new String(decryptAesCipherText(secretKey, cipherTextBytes), "UTF-8"); From a054f16807e6ac72654b24c4211f67371d326918 Mon Sep 17 00:00:00 2001 From: pradeep singh Date: Sun, 9 Aug 2020 13:22:26 +0530 Subject: [PATCH 09/16] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 789896d..5003fd0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-secure-key-store", - "version": "2.0.8", + "version": "2.0.9", "description": "React Native Library for securely storing keys to iOS and Android devices in KeyChain and KeyStore respectively.", "main": "index.js", "publishConfig": { From 29ac5639cca1d7efb3f13cb1c4db1cba1d26114c Mon Sep 17 00:00:00 2001 From: Tom Bailey Date: Sat, 3 Oct 2020 14:45:37 +0900 Subject: [PATCH 10/16] Use encrypted shared preferences from androidx.security --- android/build.gradle | 3 +- .../RNSecureKeyStoreModule.java | 196 +++--------------- .../reactlibrary/securekeystore/Storage.java | 38 ---- example/android/build.gradle | 2 +- 4 files changed, 33 insertions(+), 206 deletions(-) delete mode 100644 android/src/main/java/com/reactlibrary/securekeystore/Storage.java diff --git a/android/build.gradle b/android/build.gradle index 2d6de7e..555c82e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -26,7 +26,7 @@ android { buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3') defaultConfig { - minSdkVersion safeExtGet('minSdkVersion', 16) + minSdkVersion safeExtGet('minSdkVersion', 23) targetSdkVersion safeExtGet('targetSdkVersion', 28) versionCode 1 versionName "1.0" @@ -44,4 +44,5 @@ repositories { dependencies { implementation 'com.facebook.react:react-native:+' + implementation "androidx.security:security-crypto:1.0.0-rc03" } diff --git a/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java b/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java index 9cc77c1..e20d488 100644 --- a/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java +++ b/android/src/main/java/com/reactlibrary/securekeystore/RNSecureKeyStoreModule.java @@ -6,38 +6,23 @@ package com.reactlibrary.securekeystore; -import android.content.Context; +import android.content.SharedPreferences; import android.os.Build; -import android.security.KeyPairGeneratorSpec; import android.util.Log; -import java.util.Locale; + +import androidx.annotation.Nullable; +import androidx.security.crypto.EncryptedSharedPreferences; +import androidx.security.crypto.MasterKeys; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.KeyPairGenerator; -import java.security.KeyStore; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.util.Calendar; -import androidx.annotation.Nullable; import com.facebook.react.bridge.ReadableMap; -import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import javax.security.auth.x500.X500Principal; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.GeneralSecurityException; public class RNSecureKeyStoreModule extends ReactContextBaseJavaModule { @@ -56,7 +41,7 @@ public class RNSecureKeyStoreModule extends ReactContextBaseJavaModule { @ReactMethod public void set(String alias, String input, @Nullable ReadableMap options, Promise promise) { try { - setCipherText(alias, input); + getSecureSharedPreferences().edit().putString(alias, input).commit(); promise.resolve("stored ciphertext in app storage"); } catch (Exception e) { e.printStackTrace(); @@ -65,89 +50,26 @@ public class RNSecureKeyStoreModule extends ReactContextBaseJavaModule { } } - private PublicKey getOrCreatePublicKey(String alias) throws GeneralSecurityException, IOException { - Locale currentLocale = Locale.getDefault(); - Locale.setDefault(Locale.ENGLISH); - KeyStore keyStore = KeyStore.getInstance(getKeyStore()); - keyStore.load(null); - - if (!keyStore.containsAlias(alias) || keyStore.getCertificate(alias) == null) { - Log.i(Constants.TAG, "no existing asymmetric keys for alias"); - - Calendar start = Calendar.getInstance(); - Calendar end = Calendar.getInstance(); - end.add(Calendar.YEAR, 50); - KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(getContext()) - .setAlias(alias) - .setSubject(new X500Principal("CN=" + alias)) - .setSerialNumber(BigInteger.ONE) - .setStartDate(start.getTime()) - .setEndDate(end.getTime()) - .build(); - - KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", getKeyStore()); - generator.initialize(spec); - generator.generateKeyPair(); - - Locale.setDefault(currentLocale); - Log.i(Constants.TAG, "created new asymmetric keys for alias"); - } - - return keyStore.getCertificate(alias).getPublicKey(); - } - - private byte[] encryptRsaPlainText(PublicKey publicKey, byte[] plainTextBytes) throws GeneralSecurityException, IOException { - Cipher cipher = Cipher.getInstance(Constants.RSA_ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - return encryptCipherText(cipher, plainTextBytes); - } - - private byte[] encryptAesPlainText(SecretKey secretKey, String plainText) throws GeneralSecurityException, IOException { - Cipher cipher = Cipher.getInstance(Constants.AES_ALGORITHM); - cipher.init(Cipher.ENCRYPT_MODE, secretKey); - return encryptCipherText(cipher, plainText); - } - - private byte[] encryptCipherText(Cipher cipher, String plainText) throws GeneralSecurityException, IOException { - return encryptCipherText(cipher, plainText.getBytes("UTF-8")); - } - - private byte[] encryptCipherText(Cipher cipher, byte[] plainTextBytes) throws GeneralSecurityException, IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher); - cipherOutputStream.write(plainTextBytes); - cipherOutputStream.close(); - return outputStream.toByteArray(); - } - - private SecretKey getOrCreateSecretKey(String alias) throws GeneralSecurityException, IOException { - try { - return getSymmetricKey(alias); - } catch (FileNotFoundException fnfe) { - Log.i(Constants.TAG, "no existing symmetric key for alias"); - - KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); - //32bytes / 256bits AES key - keyGenerator.init(256); - SecretKey secretKey = keyGenerator.generateKey(); - PublicKey publicKey = getOrCreatePublicKey(alias); - Storage.writeValues(getContext(), Constants.SKS_KEY_FILENAME + alias, - encryptRsaPlainText(publicKey, secretKey.getEncoded())); - - Log.i(Constants.TAG, "created new symmetric keys for alias"); - return secretKey; - } - } - - private void setCipherText(String alias, String input) throws GeneralSecurityException, IOException { - Storage.writeValues(getContext(), Constants.SKS_DATA_FILENAME + alias, - encryptAesPlainText(getOrCreateSecretKey(alias), input)); + private SharedPreferences getSecureSharedPreferences() throws GeneralSecurityException, IOException { + return EncryptedSharedPreferences.create( + "secret_shared_prefs", + MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC), + reactContext, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ); } @ReactMethod public void get(String alias, Promise promise) { try { - promise.resolve(getPlainText(alias)); + String value = getSecureSharedPreferences().getString(alias, null); + if (value == null) { + //throw FileNotFoundException to keep match old behaviour when a value is missing + throw new FileNotFoundException(alias + " has not been set"); + } else { + promise.resolve(value); + } } catch (FileNotFoundException fnfe) { fnfe.printStackTrace(); promise.reject("404", "{\"code\":404,\"api-level\":" + Build.VERSION.SDK_INT + ",\"message\":" + fnfe.getMessage() + "}", fnfe); @@ -158,73 +80,15 @@ public class RNSecureKeyStoreModule extends ReactContextBaseJavaModule { } } - private PrivateKey getPrivateKey(String alias) throws GeneralSecurityException, IOException { - KeyStore keyStore = KeyStore.getInstance(getKeyStore()); - keyStore.load(null); - return (PrivateKey) keyStore.getKey(alias, null); - } - - private byte[] decryptRsaCipherText(PrivateKey privateKey, byte[] cipherTextBytes) throws GeneralSecurityException, IOException { - Cipher cipher = Cipher.getInstance(Constants.RSA_ALGORITHM); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - return decryptCipherText(cipher, cipherTextBytes); - } - - private byte[] decryptAesCipherText(SecretKey secretKey, byte[] cipherTextBytes) throws GeneralSecurityException, IOException { - Cipher cipher = Cipher.getInstance(Constants.AES_ALGORITHM); - cipher.init(Cipher.DECRYPT_MODE, secretKey); - return decryptCipherText(cipher, cipherTextBytes); - } - - private byte[] decryptCipherText(Cipher cipher, byte[] cipherTextBytes) throws IOException { - ByteArrayInputStream bais = new ByteArrayInputStream(cipherTextBytes); - CipherInputStream cipherInputStream = new CipherInputStream(bais, cipher); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - byte[] buffer = new byte[256]; - int bytesRead = cipherInputStream.read(buffer); - while (bytesRead != -1) { - baos.write(buffer, 0, bytesRead); - bytesRead = cipherInputStream.read(buffer); - } - return baos.toByteArray(); - } - - private SecretKey getSymmetricKey(String alias) throws GeneralSecurityException, IOException { - byte[] cipherTextBytes = Storage.readValues(getContext(), Constants.SKS_KEY_FILENAME + alias); - return new SecretKeySpec(decryptRsaCipherText(getPrivateKey(alias), cipherTextBytes), Constants.AES_ALGORITHM); - } - - public String getPlainText(String alias) throws GeneralSecurityException, IOException { - SecretKey secretKey = getSymmetricKey(alias); - byte[] cipherTextBytes = Storage.readValues(getContext(), Constants.SKS_DATA_FILENAME + alias); - return new String(decryptAesCipherText(secretKey, cipherTextBytes), "UTF-8"); - } - @ReactMethod public void remove(String alias, Promise promise) { - Storage.resetValues(getContext(), new String[] { - Constants.SKS_DATA_FILENAME + alias, - Constants.SKS_KEY_FILENAME + alias, - }); - promise.resolve("cleared alias"); - } - - private Context getContext() { - return getReactApplicationContext(); - } - - private String getKeyStore() { try { - KeyStore.getInstance(Constants.KEYSTORE_PROVIDER_1); - return Constants.KEYSTORE_PROVIDER_1; - } catch (Exception err) { - try { - KeyStore.getInstance(Constants.KEYSTORE_PROVIDER_2); - return Constants.KEYSTORE_PROVIDER_2; - } catch (Exception e) { - return Constants.KEYSTORE_PROVIDER_3; - } + getSecureSharedPreferences().edit().remove(alias).commit(); + promise.resolve("cleared alias"); + } catch (Exception e) { + e.printStackTrace(); + Log.e(Constants.TAG, "Exception: " + e.getMessage()); + promise.reject("{\"code\":6,\"api-level\":" + Build.VERSION.SDK_INT + ",\"message\":" + e.getMessage() + "}"); } } - } diff --git a/android/src/main/java/com/reactlibrary/securekeystore/Storage.java b/android/src/main/java/com/reactlibrary/securekeystore/Storage.java deleted file mode 100644 index 62184fe..0000000 --- a/android/src/main/java/com/reactlibrary/securekeystore/Storage.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.reactlibrary.securekeystore; - -// Helper function for storing keys to internal storage. - -import android.content.Context; - -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - -public final class Storage { - - public static void writeValues(Context context, String filename, byte[] bytes) throws IOException { - FileOutputStream fos = context.openFileOutput(filename, Context.MODE_PRIVATE); - fos.write(bytes); - fos.close(); - } - - public static byte[] readValues(Context context, String filename) throws IOException { - FileInputStream fis = context.openFileInput(filename); - ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); - byte[] buffer = new byte[1024]; - int bytesRead = fis.read(buffer); - while(bytesRead != -1) { - baos.write(buffer, 0, bytesRead); - bytesRead = fis.read(buffer); - } - return baos.toByteArray(); - } - - public static void resetValues(Context context, String[] filenames) { - for(String filename : filenames) { - context.deleteFile(filename); - } - } - -} \ No newline at end of file diff --git a/example/android/build.gradle b/example/android/build.gradle index 3231b29..edb5d39 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -3,7 +3,7 @@ buildscript { ext { buildToolsVersion = "28.0.2" - minSdkVersion = 16 + minSdkVersion = 23 compileSdkVersion = 28 targetSdkVersion = 27 supportLibVersion = "28.0.0" From 60fab025ff240b2b5098f900da1fd84024cdd534 Mon Sep 17 00:00:00 2001 From: Tom Bailey Date: Sat, 3 Oct 2020 15:29:35 +0900 Subject: [PATCH 11/16] Improve example app --- example/App.js | 143 ++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 62 deletions(-) diff --git a/example/App.js b/example/App.js index 92ae662..5821706 100644 --- a/example/App.js +++ b/example/App.js @@ -8,68 +8,81 @@ */ import React, {Component} from 'react'; -import {Platform, StyleSheet, Text, View} from 'react-native'; +import {Platform, StyleSheet, Button, Text, TextInput, View} from 'react-native'; import RNSecureKeyStore, {ACCESSIBLE} from "react-native-secure-key-store"; -const instructions = Platform.select({ - ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu', - android: - 'Double tap R on your keyboard to reload,\n' + - 'Shake or press menu button for dev menu', -}); - type Props = {}; export default class App extends Component { + state = { + alias: 'hello', + value: 'world' + }; + + getValue() { + RNSecureKeyStore.get(this.state.alias) + .then((value) => { + this.setState({ + value, + }); + }) + .catch(console.error); + } + + setValue() { + RNSecureKeyStore.set(this.state.alias, this.state.value, {}) + .then(() => this.getValue()) + .catch(console.error); + } + + removeValue() { + RNSecureKeyStore.remove(this.state.alias) + .then(() => this.getValue()) + .catch(console.error); + } + render() { - - RNSecureKeyStore.set("key1", "value1", {accessible: ACCESSIBLE.ALWAYS_THIS_DEVICE_ONLY}) - .then((res) => { - console.log(res); - }, (err) => { - console.log(err); - }); - - RNSecureKeyStore.set("key2", "value2", {accessible: ACCESSIBLE.ALWAYS_THIS_DEVICE_ONLY}) - .then((res) => { - console.log(res); - }, (err) => { - console.log(err); - }); - - RNSecureKeyStore.get("key1") - .then((res) => { - console.log(res); - }, (err) => { - console.log(err); - }); - - RNSecureKeyStore.get("key2") - .then((res) => { - console.log(res); - }, (err) => { - console.log(err); - }); - - RNSecureKeyStore.remove("key1") - .then((res) => { - console.log(res); - }, (err) => { - console.log(err); - }); - - RNSecureKeyStore.remove("key2") - .then((res) => { - console.log(res); - }, (err) => { - console.log(err); - }); - return ( - Welcome to React Native! - To get started, edit App.js - {instructions} + + Alias: + this.setState({alias})} + value={this.state.alias} + /> + + + + Value: + this.setState({value})} + value={this.state.value} + /> + + + + +