Compare commits
68 Commits
santiagofm
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2076b4849e | ||
|
|
80c35ae524 | ||
|
|
5534340fad | ||
|
|
863fbcaf1b | ||
|
|
6dcf954aab | ||
|
|
9746bf57a2 | ||
|
|
14f7846144 | ||
|
|
51e040873f | ||
|
|
8e8a850a78 | ||
|
|
2368c865c9 | ||
|
|
63ab38c9d3 | ||
|
|
4828fd1a67 | ||
|
|
c36726fd58 | ||
|
|
4bb26d8907 | ||
|
|
60fab025ff | ||
|
|
29ac5639cc | ||
|
|
a054f16807 | ||
|
|
133a1a93cf | ||
|
|
08285e25bc | ||
|
|
aedb1b95af | ||
|
|
e681d0a7e2 | ||
|
|
c331182f4a | ||
|
|
342a4876fd | ||
|
|
b18c68b37e | ||
|
|
30c26e5b27 | ||
|
|
daf8291540 | ||
|
|
2996abb4de | ||
|
|
9d9dc01487 | ||
|
|
6c5bcef97a | ||
|
|
2b66799a51 | ||
|
|
4ba25dedb3 | ||
|
|
97668bdf81 | ||
|
|
b885b2e375 | ||
|
|
03e8b4b47a | ||
|
|
67a44276cb | ||
|
|
1c3749d08f | ||
|
|
8ea8ac2cdb | ||
|
|
74cdbd2e0c | ||
|
|
586e1734ac | ||
|
|
caa59d0b43 | ||
|
|
53cbeb2255 | ||
|
|
3cc49cf7c1 | ||
|
|
dd8597dbaa | ||
|
|
680a027711 | ||
|
|
cd6b422545 | ||
|
|
3bc02010d9 | ||
|
|
7e89d793b6 | ||
|
|
cf7919a93e | ||
|
|
b82e280996 | ||
|
|
a259d4dbb1 | ||
|
|
d35569e928 | ||
|
|
1f2edcac6e | ||
|
|
ac5168a638 | ||
|
|
c3694a9c3e | ||
|
|
7e0d21f63f | ||
|
|
dcf5a581d4 | ||
|
|
bb4d5eb683 | ||
|
|
8507b91792 | ||
|
|
675d151be8 | ||
|
|
2726d6fe76 | ||
|
|
84d53a9fa6 | ||
|
|
e883a89fda | ||
|
|
4a879a2c63 | ||
|
|
e5618b9592 | ||
|
|
e01856d2e9 | ||
|
|
2bda4f8395 | ||
|
|
6af285a33a | ||
|
|
72cab06a05 |
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: [pradeep1991singh]
|
||||
patreon: live2code
|
||||
# open_collective: # Replace with a single Open Collective username
|
||||
# ko_fi: # Replace with a single Ko-fi username
|
||||
# tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
# community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
# liberapay: # Replace with a single Liberapay username
|
||||
# issuehunt: # Replace with a single IssueHunt username
|
||||
# otechie: # Replace with a single Otechie username
|
||||
# custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
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
|
||||
|
||||
|
||||
@ -118,3 +112,6 @@ Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
|
||||
|
||||
[](https://www.buymeacoffee.com/ps91)
|
||||
|
||||
21
SECURITY.md
Normal file
21
SECURITY.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Use this section to tell people about which versions of your project are
|
||||
currently being supported with security updates.
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 5.1.x | :white_check_mark: |
|
||||
| 5.0.x | :x: |
|
||||
| 4.0.x | :white_check_mark: |
|
||||
| < 4.0 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Use this section to tell people how to report a vulnerability.
|
||||
|
||||
Tell them where to go, how often they can expect to get an update on a
|
||||
reported vulnerability, what to expect if the vulnerability is accepted or
|
||||
declined, etc.
|
||||
@ -1,24 +1,37 @@
|
||||
|
||||
def safeExtGet(prop, fallback) {
|
||||
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
}
|
||||
// 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
|
||||
// module dependency in an application project.
|
||||
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()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||
dependencies {
|
||||
classpath("com.android.tools.build:gradle:3.5.2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
@ -29,10 +42,11 @@ android {
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.facebook.react:react-native:+'
|
||||
implementation 'com.facebook.react:react-native:+'
|
||||
implementation "androidx.security:security-crypto:1.0.0-rc03"
|
||||
}
|
||||
|
||||
@ -6,37 +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 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 android.support.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 {
|
||||
|
||||
@ -55,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();
|
||||
@ -64,86 +50,26 @@ public class RNSecureKeyStoreModule extends ReactContextBaseJavaModule {
|
||||
}
|
||||
}
|
||||
|
||||
private PublicKey getOrCreatePublicKey(String alias) throws GeneralSecurityException, IOException {
|
||||
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();
|
||||
|
||||
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);
|
||||
@ -154,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",
|
||||
|
||||
@ -684,9 +684,9 @@ acorn-walk@^6.0.1:
|
||||
integrity sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==
|
||||
|
||||
acorn@^5.5.3:
|
||||
version "5.7.3"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
|
||||
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
|
||||
version "5.7.4"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e"
|
||||
integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==
|
||||
|
||||
acorn@^6.0.1:
|
||||
version "6.0.5"
|
||||
@ -920,7 +920,7 @@ async-limiter@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
|
||||
integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
|
||||
|
||||
async@^2.4.0, async@^2.5.0, async@^2.6.1:
|
||||
async@^2.4.0, async@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
|
||||
integrity sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==
|
||||
@ -1341,10 +1341,10 @@ commander@~2.13.0:
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
|
||||
integrity sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==
|
||||
|
||||
commander@~2.17.1:
|
||||
version "2.17.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
|
||||
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
|
||||
commander@~2.20.3:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
||||
commondir@^1.0.1:
|
||||
version "1.0.1"
|
||||
@ -2234,11 +2234,11 @@ growly@^1.3.0:
|
||||
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
|
||||
|
||||
handlebars@^4.0.11:
|
||||
version "4.0.12"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5"
|
||||
integrity sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==
|
||||
version "4.5.3"
|
||||
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482"
|
||||
integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==
|
||||
dependencies:
|
||||
async "^2.5.0"
|
||||
neo-async "^2.6.0"
|
||||
optimist "^0.6.1"
|
||||
source-map "^0.6.1"
|
||||
optionalDependencies:
|
||||
@ -3144,9 +3144,9 @@ jest@24.0.0:
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
|
||||
js-yaml@^3.12.0, js-yaml@^3.9.0:
|
||||
version "3.12.1"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600"
|
||||
integrity sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==
|
||||
version "3.13.1"
|
||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
|
||||
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
esprima "^4.0.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.11"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
|
||||
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"
|
||||
@ -3822,9 +3822,9 @@ minizlib@^1.1.1:
|
||||
minipass "^2.2.1"
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
|
||||
integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
|
||||
integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
|
||||
dependencies:
|
||||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
@ -3903,6 +3903,11 @@ negotiator@0.6.1:
|
||||
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
|
||||
integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=
|
||||
|
||||
neo-async@^2.6.0:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
|
||||
integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
@ -5525,11 +5530,11 @@ uglify-es@^3.1.9:
|
||||
source-map "~0.6.1"
|
||||
|
||||
uglify-js@^3.1.4:
|
||||
version "3.4.9"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
|
||||
integrity sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==
|
||||
version "3.7.3"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.7.3.tgz#f918fce9182f466d5140f24bb0ff35c2d32dcc6a"
|
||||
integrity sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==
|
||||
dependencies:
|
||||
commander "~2.17.1"
|
||||
commander "~2.20.3"
|
||||
source-map "~0.6.1"
|
||||
|
||||
ultron@1.0.x:
|
||||
|
||||
23
index.d.ts
vendored
Normal file
23
index.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
declare module 'react-native-secure-key-store' {
|
||||
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 =
|
||||
'AccessibleWhenPasscodeSetThisDeviceOnly',
|
||||
WHEN_UNLOCKED = 'AccessibleWhenUnlocked',
|
||||
WHEN_UNLOCKED_THIS_DEVICE_ONLY = 'AccessibleWhenUnlockedThisDeviceOnly',
|
||||
}
|
||||
|
||||
interface RNSecureKeyStore {
|
||||
get: (key: string) => Promise<any>
|
||||
set: (key: string, value: string, options?: { accessible?: ACCESSIBLE }) => Promise<any>
|
||||
remove: (key: string) => Promise<any>
|
||||
setResetOnAppUninstallTo: (enabled: boolean) => boolean
|
||||
}
|
||||
const secureKeystore: RNSecureKeyStore
|
||||
|
||||
export default secureKeystore
|
||||
}
|
||||
@ -74,7 +74,7 @@ static NSString *serviceName = @"RNSecureKeyStoreKeyChain";
|
||||
}
|
||||
|
||||
- (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier options: (NSDictionary * __nullable)options {
|
||||
CFStringRef accessible = accessibleValue(options);
|
||||
CFStringRef accessible = accessibleVal(options);
|
||||
NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
|
||||
|
||||
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
|
||||
@ -91,7 +91,7 @@ static NSString *serviceName = @"RNSecureKeyStoreKeyChain";
|
||||
|
||||
- (BOOL)updateKeychainValue:(NSString *)password forIdentifier:(NSString *)identifier options:(NSDictionary * __nullable)options {
|
||||
|
||||
CFStringRef accessible = accessibleValue(options);
|
||||
CFStringRef accessible = accessibleVal(options);
|
||||
NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
|
||||
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
|
||||
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];
|
||||
@ -128,15 +128,6 @@ static NSString *serviceName = @"RNSecureKeyStoreKeyChain";
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleAppUninstallation
|
||||
{
|
||||
if ([self resetOnAppUninstall] && ![[NSUserDefaults standardUserDefaults] boolForKey:@"RnSksIsAppInstalled"]) {
|
||||
[self clearSecureKeyStore];
|
||||
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"RnSksIsAppInstalled"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
}
|
||||
}
|
||||
|
||||
NSError * secureKeyStoreError(NSString *errMsg)
|
||||
{
|
||||
NSError *error = [NSError errorWithDomain:serviceName code:200 userInfo:@{@"reason": errMsg}];
|
||||
@ -155,7 +146,6 @@ RCT_EXPORT_METHOD(set: (NSString *)key value:(NSString *)value
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
@try {
|
||||
[self handleAppUninstallation];
|
||||
BOOL status = [self createKeychainValue: value forIdentifier: key options: options];
|
||||
if (status) {
|
||||
resolve(@"key stored successfully");
|
||||
@ -180,7 +170,6 @@ RCT_EXPORT_METHOD(get:(NSString *)key
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
@try {
|
||||
[self handleAppUninstallation];
|
||||
NSString *value = [self searchKeychainCopyMatching:key];
|
||||
if (value == nil) {
|
||||
NSString* errorMessage = @"{\"message\":\"key does not present\"}";
|
||||
@ -214,7 +203,7 @@ RCT_EXPORT_METHOD(remove:(NSString *)key
|
||||
}
|
||||
}
|
||||
|
||||
CFStringRef accessibleValue(NSDictionary *options)
|
||||
CFStringRef accessibleVal(NSDictionary *options)
|
||||
{
|
||||
if (options && options[@"accessible"] != nil) {
|
||||
NSDictionary *keyMap = @{
|
||||
|
||||
@ -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,11 +1,15 @@
|
||||
{
|
||||
"name": "react-native-secure-key-store",
|
||||
"version": "2.0.4",
|
||||
"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": {
|
||||
"registry": "https://registry.npmjs.org"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"types": "index.d.ts",
|
||||
"keywords": [
|
||||
"react-native",
|
||||
"ios",
|
||||
|
||||
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