Merge branch 'pradeep1991singh:master' into master
This commit is contained in:
commit
2076b4849e
72
.github/workflows/codeql-analysis.yml
vendored
Normal file
72
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '40 9 * * 5'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java', 'javascript', 'ruby' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
@ -14,12 +14,6 @@ or
|
||||
$ yarn add react-native-secure-key-store
|
||||
```
|
||||
|
||||
### Mostly automatic installation
|
||||
|
||||
```sh
|
||||
$ react-native link react-native-secure-key-store
|
||||
```
|
||||
|
||||
### Manual installation
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
@ -6,6 +10,10 @@ buildscript {
|
||||
if (project == rootProject) {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
// JCenter is going read-only repository indefinitely
|
||||
// Gradle is discouraging jcenter to avoid to avoid build issues - pipeline
|
||||
// ref: https://blog.gradle.org/jcenter-shutdown
|
||||
jcenter()
|
||||
}
|
||||
|
||||
@ -18,12 +26,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', 23)
|
||||
targetSdkVersion safeExtGet('targetSdkVersion', 28)
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
@ -34,10 +42,11 @@ android {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.facebook.react:react-native:+'
|
||||
implementation "androidx.security:security-crypto:1.0.0-rc03"
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
private 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() + "}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
143
example/App.js
143
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<Props> {
|
||||
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 (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.welcome}>Welcome to React Native!</Text>
|
||||
<Text style={styles.instructions}>To get started, edit App.js</Text>
|
||||
<Text style={styles.instructions}>{instructions}</Text>
|
||||
<View style={styles.row}>
|
||||
<Text>Alias:</Text>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
onChangeText={alias => this.setState({alias})}
|
||||
value={this.state.alias}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.row}>
|
||||
<Text>Value:</Text>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
onChangeText={value => this.setState({value})}
|
||||
value={this.state.value}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.row}>
|
||||
<View style={styles.button}>
|
||||
<Button
|
||||
onPress={() => this.getValue()}
|
||||
title='Get'
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.button}>
|
||||
<Button
|
||||
onPress={() => this.setValue()}
|
||||
title='Set'
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.button}>
|
||||
<Button
|
||||
onPress={() => this.removeValue()}
|
||||
title='Remove'
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -82,14 +95,20 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
welcome: {
|
||||
fontSize: 20,
|
||||
textAlign: 'center',
|
||||
margin: 10,
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginTop: 20
|
||||
},
|
||||
instructions: {
|
||||
textAlign: 'center',
|
||||
color: '#333333',
|
||||
marginBottom: 5,
|
||||
textInput: {
|
||||
height: 40,
|
||||
width: 200,
|
||||
borderColor: 'gray',
|
||||
borderWidth: 1,
|
||||
marginLeft: 10
|
||||
},
|
||||
button: {
|
||||
marginLeft: 10
|
||||
}
|
||||
});
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
buildscript {
|
||||
ext {
|
||||
buildToolsVersion = "28.0.2"
|
||||
minSdkVersion = 16
|
||||
minSdkVersion = 23
|
||||
compileSdkVersion = 28
|
||||
targetSdkVersion = 27
|
||||
supportLibVersion = "28.0.0"
|
||||
|
||||
@ -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
|
||||
12
example/metro.config.js
Normal file
12
example/metro.config.js
Normal file
@ -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],
|
||||
};
|
||||
@ -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",
|
||||
|
||||
@ -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"
|
||||
|
||||
18
index.d.ts
vendored
18
index.d.ts
vendored
@ -1,19 +1,19 @@
|
||||
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 {
|
||||
get: (key: string) => Promise<any>
|
||||
set: (key: string, value: string, accessible?: ACCESSIBLE) => Promise<any>
|
||||
set: (key: string, value: string, options?: { accessible?: ACCESSIBLE }) => Promise<any>
|
||||
remove: (key: string) => Promise<any>
|
||||
setResetOnAppUninstallTo: (enabled: boolean) => boolean
|
||||
}
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "RNSecureKeyStore"
|
||||
s.version = "1.0.0"
|
||||
s.summary = "A package for secure storage on android and ios"
|
||||
s.description = "A package for secure storage on android and ios. Stores using the keystore on Android devices, and the keychain on iOS devices."
|
||||
s.homepage = "https://github.com/pradeep1991singh/react-native-secure-key-store#readme"
|
||||
s.license = "MIT"
|
||||
# s.license = { :type => "MIT", :file => "FILE_LICENSE" }
|
||||
s.author = { "author" => "pradeep1991singh" }
|
||||
s.platform = :ios, "7.0"
|
||||
s.source = { :git => "https://github.com/pradeep1991singh/react-native-secure-key-store", :tag => "master" }
|
||||
s.source_files = "**/*.{h,m}"
|
||||
s.requires_arc = true
|
||||
|
||||
|
||||
s.dependency "React"
|
||||
#s.dependency "others"
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-secure-key-store",
|
||||
"version": "2.0.7",
|
||||
"version": "2.0.10",
|
||||
"description": "React Native Library for securely storing keys to iOS and Android devices in KeyChain and KeyStore respectively.",
|
||||
"main": "index.js",
|
||||
"publishConfig": {
|
||||
|
||||
24
react-native-secure-key-store.podspec
Normal file
24
react-native-secure-key-store.podspec
Normal file
@ -0,0 +1,24 @@
|
||||
require "json"
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = package['name']
|
||||
s.version = package['version']
|
||||
s.summary = package['description']
|
||||
s.description = package['description']
|
||||
s.homepage = package['homepage']
|
||||
s.license = package['license']
|
||||
s.authors = package['author']
|
||||
s.platform = :ios, "7.0"
|
||||
s.source = { :git => "https://github.com/pradeep1991singh/react-native-secure-key-store", :tag => "master" }
|
||||
s.source_files = "ios/**/*.{h,m}"
|
||||
s.requires_arc = true
|
||||
|
||||
|
||||
s.dependency "React-Core"
|
||||
#s.dependency "others"
|
||||
|
||||
end
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user