@@ -0,0 +1,3 @@ | |||||
{ | |||||
"presets": ["react-native"] | |||||
} |
@@ -0,0 +1,6 @@ | |||||
[android] | |||||
target = Google Inc.:Google APIs:23 | |||||
[maven_repositories] | |||||
central = https://repo1.maven.org/maven2 |
@@ -0,0 +1,67 @@ | |||||
[ignore] | |||||
; We fork some components by platform | |||||
.*/*[.]android.js | |||||
; Ignore "BUCK" generated dirs | |||||
<PROJECT_ROOT>/\.buckd/ | |||||
; Ignore unexpected extra "@providesModule" | |||||
.*/node_modules/.*/node_modules/fbjs/.* | |||||
; Ignore duplicate module providers | |||||
; For RN Apps installed via npm, "Libraries" folder is inside | |||||
; "node_modules/react-native" but in the source repo it is in the root | |||||
.*/Libraries/react-native/React.js | |||||
; Ignore polyfills | |||||
.*/Libraries/polyfills/.* | |||||
; Ignore metro | |||||
.*/node_modules/metro/.* | |||||
[include] | |||||
[libs] | |||||
node_modules/react-native/Libraries/react-native/react-native-interface.js | |||||
node_modules/react-native/flow/ | |||||
node_modules/react-native/flow-github/ | |||||
[options] | |||||
emoji=true | |||||
module.system=haste | |||||
module.system.haste.use_name_reducers=true | |||||
# get basename | |||||
module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' | |||||
# strip .js or .js.flow suffix | |||||
module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' | |||||
# strip .ios suffix | |||||
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' | |||||
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' | |||||
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' | |||||
module.system.haste.paths.blacklist=.*/__tests__/.* | |||||
module.system.haste.paths.blacklist=.*/__mocks__/.* | |||||
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.* | |||||
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.* | |||||
munge_underscores=true | |||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' | |||||
module.file_ext=.js | |||||
module.file_ext=.jsx | |||||
module.file_ext=.json | |||||
module.file_ext=.native.js | |||||
suppress_type=$FlowIssue | |||||
suppress_type=$FlowFixMe | |||||
suppress_type=$FlowFixMeProps | |||||
suppress_type=$FlowFixMeState | |||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) | |||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ | |||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy | |||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError | |||||
[version] | |||||
^0.75.0 |
@@ -0,0 +1 @@ | |||||
*.pbxproj -text |
@@ -0,0 +1,56 @@ | |||||
# OSX | |||||
# | |||||
.DS_Store | |||||
# Xcode | |||||
# | |||||
build/ | |||||
*.pbxuser | |||||
!default.pbxuser | |||||
*.mode1v3 | |||||
!default.mode1v3 | |||||
*.mode2v3 | |||||
!default.mode2v3 | |||||
*.perspectivev3 | |||||
!default.perspectivev3 | |||||
xcuserdata | |||||
*.xccheckout | |||||
*.moved-aside | |||||
DerivedData | |||||
*.hmap | |||||
*.ipa | |||||
*.xcuserstate | |||||
project.xcworkspace | |||||
# Android/IntelliJ | |||||
# | |||||
build/ | |||||
.idea | |||||
.gradle | |||||
local.properties | |||||
*.iml | |||||
# node.js | |||||
# | |||||
node_modules/ | |||||
npm-debug.log | |||||
yarn-error.log | |||||
# BUCK | |||||
buck-out/ | |||||
\.buckd/ | |||||
*.keystore | |||||
# fastlane | |||||
# | |||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the | |||||
# screenshots whenever they are needed. | |||||
# For more information about the recommended setup visit: | |||||
# https://docs.fastlane.tools/best-practices/source-control/ | |||||
*/fastlane/report.xml | |||||
*/fastlane/Preview.html | |||||
*/fastlane/screenshots | |||||
# Bundle artifact | |||||
*.jsbundle |
@@ -0,0 +1 @@ | |||||
{} |
@@ -0,0 +1,92 @@ | |||||
import React, { Component } from "react"; | |||||
import { Provider } from "react-redux"; | |||||
import { createStackNavigator } from "react-navigation"; | |||||
import { Provider as PaperProvider } from "react-native-paper"; | |||||
import { createMaterialBottomTabNavigator } from "react-navigation-material-bottom-tabs"; | |||||
import Icon from "react-native-vector-icons/FontAwesome"; | |||||
import { PersistGate } from "redux-persist/lib/integration/react"; | |||||
import { persistor, store } from "./src/store"; | |||||
import ForgotPasswordScreen from "./src/ForgotPasswordScreen"; | |||||
import HelpScreen from "./src/HelpScreen"; | |||||
import PasswordGeneratorScreen from "./src/PasswordGeneratorScreen"; | |||||
import SettingsScreen from "./src/SettingsScreen"; | |||||
import SignInScreen from "./src/SignInScreen"; | |||||
import SignUpScreen from "./src/SignUpScreen"; | |||||
import Theme from "./src/Theme"; | |||||
const AuthStack = createStackNavigator( | |||||
{ | |||||
ForgotPassword: ForgotPasswordScreen, | |||||
SignIn: SignInScreen, | |||||
SignUp: SignUpScreen | |||||
}, | |||||
{ | |||||
initialRouteName: "SignIn", | |||||
headerMode: "none" | |||||
} | |||||
); | |||||
const AppNavigator = createMaterialBottomTabNavigator( | |||||
{ | |||||
PasswordGenerator: { | |||||
screen: PasswordGeneratorScreen, | |||||
navigationOptions: { | |||||
title: "LessPass", | |||||
tabBarIcon: ({ tintColor, focused }) => ( | |||||
<Icon size={20} name="user-secret" style={{ color: tintColor }} /> | |||||
) | |||||
} | |||||
}, | |||||
Settings: { | |||||
screen: SettingsScreen, | |||||
navigationOptions: { | |||||
title: "Settings", | |||||
tabBarIcon: ({ tintColor, focused }) => ( | |||||
<Icon size={20} name="cogs" style={{ color: tintColor }} /> | |||||
) | |||||
} | |||||
}, | |||||
Help: { | |||||
screen: HelpScreen, | |||||
navigationOptions: { | |||||
title: "Help", | |||||
tabBarIcon: ({ tintColor, focused }) => ( | |||||
<Icon size={20} name="question" style={{ color: tintColor }} /> | |||||
) | |||||
} | |||||
} | |||||
/* | |||||
SignIn: { | |||||
screen: AuthStack, | |||||
navigationOptions: { | |||||
title: "Log In", | |||||
tabBarIcon: ({ tintColor, focused }) => ( | |||||
<Icon size={25} name="account-circle" style={{ color: tintColor }} /> | |||||
) | |||||
} | |||||
} | |||||
*/ | |||||
}, | |||||
{ | |||||
initialRouteName: "PasswordGenerator", | |||||
activeTintColor: Theme.colors.white, | |||||
inactiveTintColor: Theme.colors.lightBlue, | |||||
barStyle: { backgroundColor: Theme.colors.primary } | |||||
} | |||||
); | |||||
class App extends Component { | |||||
render() { | |||||
return ( | |||||
<Provider store={store}> | |||||
<PersistGate persistor={persistor}> | |||||
<PaperProvider theme={Theme}> | |||||
<AppNavigator /> | |||||
</PaperProvider> | |||||
</PersistGate> | |||||
</Provider> | |||||
); | |||||
} | |||||
} | |||||
export default App; |
@@ -0,0 +1,65 @@ | |||||
# To learn about Buck see [Docs](https://buckbuild.com/). | |||||
# To run your application with Buck: | |||||
# - install Buck | |||||
# - `npm start` - to start the packager | |||||
# - `cd android` | |||||
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` | |||||
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck | |||||
# - `buck install -r android/app` - compile, install and run application | |||||
# | |||||
lib_deps = [] | |||||
for jarfile in glob(['libs/*.jar']): | |||||
name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] | |||||
lib_deps.append(':' + name) | |||||
prebuilt_jar( | |||||
name = name, | |||||
binary_jar = jarfile, | |||||
) | |||||
for aarfile in glob(['libs/*.aar']): | |||||
name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] | |||||
lib_deps.append(':' + name) | |||||
android_prebuilt_aar( | |||||
name = name, | |||||
aar = aarfile, | |||||
) | |||||
android_library( | |||||
name = "all-libs", | |||||
exported_deps = lib_deps, | |||||
) | |||||
android_library( | |||||
name = "app-code", | |||||
srcs = glob([ | |||||
"src/main/java/**/*.java", | |||||
]), | |||||
deps = [ | |||||
":all-libs", | |||||
":build_config", | |||||
":res", | |||||
], | |||||
) | |||||
android_build_config( | |||||
name = "build_config", | |||||
package = "com.lesspass", | |||||
) | |||||
android_resource( | |||||
name = "res", | |||||
package = "com.lesspass", | |||||
res = "src/main/res", | |||||
) | |||||
android_binary( | |||||
name = "app", | |||||
keystore = "//android/keystores:debug", | |||||
manifest = "src/main/AndroidManifest.xml", | |||||
package_type = "debug", | |||||
deps = [ | |||||
":app-code", | |||||
], | |||||
) |
@@ -0,0 +1,175 @@ | |||||
apply plugin: "com.android.application" | |||||
import com.android.build.OutputFile | |||||
/** | |||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets | |||||
* and bundleReleaseJsAndAssets). | |||||
* These basically call `react-native bundle` with the correct arguments during the Android build | |||||
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the | |||||
* bundle directly from the development server. Below you can see all the possible configurations | |||||
* and their defaults. If you decide to add a configuration block, make sure to add it before the | |||||
* `apply from: "../../node_modules/react-native/react.gradle"` line. | |||||
* | |||||
* project.ext.react = [ | |||||
* // the name of the generated asset file containing your JS bundle | |||||
* bundleAssetName: "index.android.bundle", | |||||
* | |||||
* // the entry file for bundle generation | |||||
* entryFile: "index.android.js", | |||||
* | |||||
* // whether to bundle JS and assets in debug mode | |||||
* bundleInDebug: false, | |||||
* | |||||
* // whether to bundle JS and assets in release mode | |||||
* bundleInRelease: true, | |||||
* | |||||
* // whether to bundle JS and assets in another build variant (if configured). | |||||
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants | |||||
* // The configuration property can be in the following formats | |||||
* // 'bundleIn${productFlavor}${buildType}' | |||||
* // 'bundleIn${buildType}' | |||||
* // bundleInFreeDebug: true, | |||||
* // bundleInPaidRelease: true, | |||||
* // bundleInBeta: true, | |||||
* | |||||
* // whether to disable dev mode in custom build variants (by default only disabled in release) | |||||
* // for example: to disable dev mode in the staging build type (if configured) | |||||
* devDisabledInStaging: true, | |||||
* // The configuration property can be in the following formats | |||||
* // 'devDisabledIn${productFlavor}${buildType}' | |||||
* // 'devDisabledIn${buildType}' | |||||
* | |||||
* // the root of your project, i.e. where "package.json" lives | |||||
* root: "../../", | |||||
* | |||||
* // where to put the JS bundle asset in debug mode | |||||
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug", | |||||
* | |||||
* // where to put the JS bundle asset in release mode | |||||
* jsBundleDirRelease: "$buildDir/intermediates/assets/release", | |||||
* | |||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via | |||||
* // require('./image.png')), in debug mode | |||||
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug", | |||||
* | |||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via | |||||
* // require('./image.png')), in release mode | |||||
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release", | |||||
* | |||||
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means | |||||
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to | |||||
* // date; if you have any other folders that you want to ignore for performance reasons (gradle | |||||
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/ | |||||
* // for example, you might want to remove it from here. | |||||
* inputExcludes: ["android/**", "ios/**"], | |||||
* | |||||
* // override which node gets called and with what additional arguments | |||||
* nodeExecutableAndArgs: ["node"], | |||||
* | |||||
* // supply additional arguments to the packager | |||||
* extraPackagerArgs: [] | |||||
* ] | |||||
*/ | |||||
project.ext.react = [ | |||||
entryFile: "index.js" | |||||
] | |||||
apply from: "../../node_modules/react-native/react.gradle" | |||||
/** | |||||
* Set this to true to create two separate APKs instead of one: | |||||
* - An APK that only works on ARM devices | |||||
* - An APK that only works on x86 devices | |||||
* The advantage is the size of the APK is reduced by about 4MB. | |||||
* Upload all the APKs to the Play Store and people will download | |||||
* the correct one based on the CPU architecture of their device. | |||||
*/ | |||||
def enableSeparateBuildPerCPUArchitecture = false | |||||
/** | |||||
* Run Proguard to shrink the Java bytecode in release builds. | |||||
*/ | |||||
def enableProguardInReleaseBuilds = false | |||||
android { | |||||
compileSdkVersion rootProject.ext.compileSdkVersion | |||||
buildToolsVersion rootProject.ext.buildToolsVersion | |||||
defaultConfig { | |||||
applicationId "com.lesspass" | |||||
minSdkVersion rootProject.ext.minSdkVersion | |||||
targetSdkVersion rootProject.ext.targetSdkVersion | |||||
versionCode 1 | |||||
versionName "1.0" | |||||
ndk { | |||||
abiFilters "armeabi-v7a", "x86" | |||||
} | |||||
} | |||||
signingConfigs { | |||||
release { | |||||
storeFile file(LESSPASS_RELEASE_STORE_FILE) | |||||
storePassword LESSPASS_RELEASE_STORE_PASSWORD | |||||
keyAlias LESSPASS_RELEASE_KEY_ALIAS | |||||
keyPassword LESSPASS_RELEASE_KEY_PASSWORD | |||||
} | |||||
} | |||||
splits { | |||||
abi { | |||||
reset() | |||||
enable enableSeparateBuildPerCPUArchitecture | |||||
universalApk false // If true, also generate a universal APK | |||||
include "armeabi-v7a", "x86" | |||||
} | |||||
} | |||||
buildTypes { | |||||
release { | |||||
minifyEnabled enableProguardInReleaseBuilds | |||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" | |||||
signingConfig signingConfigs.release | |||||
} | |||||
} | |||||
dexOptions { | |||||
jumboMode true | |||||
} | |||||
// applicationVariants are e.g. debug, release | |||||
applicationVariants.all { variant -> | |||||
variant.outputs.each { output -> | |||||
// For each separate APK per architecture, set a unique version code as described here: | |||||
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits | |||||
def versionCodes = ["armeabi-v7a":1, "x86":2] | |||||
def abi = output.getFilter(OutputFile.ABI) | |||||
if (abi != null) { // null for the universal-debug, universal-release variants | |||||
output.versionCodeOverride = | |||||
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode | |||||
} | |||||
} | |||||
} | |||||
} | |||||
dependencies { | |||||
compile project(':react-native-keychain') | |||||
compile project(':react-native-vector-icons') | |||||
compile project(':react-native-touch-id') | |||||
compile fileTree(dir: "libs", include: ["*.jar"]) | |||||
compile "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}" | |||||
compile "com.facebook.react:react-native:+" // From node_modules | |||||
compile "com.madgag.spongycastle:prov:1.58.0.0" | |||||
testCompile "junit:junit:4.12" | |||||
} | |||||
sourceSets { | |||||
test { | |||||
java { | |||||
srcDirs = ["test"] | |||||
} | |||||
} | |||||
} | |||||
// Run this once to be able to run the application with BUCK | |||||
// puts all compile dependencies into folder libs for BUCK to use | |||||
task copyDownloadableDepsToLibs(type: Copy) { | |||||
from configurations.compile | |||||
into 'libs' | |||||
} |
@@ -0,0 +1,17 @@ | |||||
# Add project specific ProGuard rules here. | |||||
# By default, the flags in this file are appended to flags specified | |||||
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt | |||||
# You can edit the include path and order by changing the proguardFiles | |||||
# directive in build.gradle. | |||||
# | |||||
# For more details, see | |||||
# http://developer.android.com/guide/developing/tools/proguard.html | |||||
# Add any project specific keep options here: | |||||
# If your project uses WebView with JS, uncomment the following | |||||
# and specify the fully qualified class name to the JavaScript interface | |||||
# class: | |||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |||||
# public *; | |||||
#} |
@@ -0,0 +1,28 @@ | |||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |||||
package="com.lesspass"> | |||||
<uses-permission android:name="android.permission.INTERNET" /> | |||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> | |||||
<uses-permission android:name="android.permission.USE_FINGERPRINT" /> | |||||
<application | |||||
android:name=".MainApplication" | |||||
android:label="@string/app_name" | |||||
android:icon="@mipmap/ic_launcher" | |||||
android:roundIcon="@mipmap/ic_launcher_round" | |||||
android:allowBackup="false" | |||||
android:theme="@style/AppTheme"> | |||||
<activity | |||||
android:name=".MainActivity" | |||||
android:label="@string/app_name" | |||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize" | |||||
android:windowSoftInputMode="adjustResize"> | |||||
<intent-filter> | |||||
<action android:name="android.intent.action.MAIN" /> | |||||
<category android:name="android.intent.category.LAUNCHER" /> | |||||
</intent-filter> | |||||
</activity> | |||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" /> | |||||
</application> | |||||
</manifest> |
@@ -0,0 +1,55 @@ | |||||
package com.lesspass; | |||||
import java.util.Map; | |||||
import java.math.BigInteger; | |||||
import java.security.Security; | |||||
import java.security.MessageDigest; | |||||
import java.nio.charset.StandardCharsets; | |||||
import java.security.NoSuchAlgorithmException; | |||||
import javax.crypto.SecretKey; | |||||
import javax.crypto.SecretKeyFactory; | |||||
import javax.crypto.Mac; | |||||
import javax.crypto.spec.PBEKeySpec; | |||||
import javax.crypto.spec.SecretKeySpec; | |||||
import org.spongycastle.jce.provider.BouncyCastleProvider; | |||||
import org.spongycastle.crypto.PBEParametersGenerator; | |||||
import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; | |||||
import org.spongycastle.crypto.digests.SHA256Digest; | |||||
import org.spongycastle.crypto.params.KeyParameter; | |||||
public class Crypto { | |||||
public String pbkdf2(String secret, String salt, int iterations, int keyLength) { | |||||
try | |||||
{ | |||||
char[] secretData = secret.toCharArray(); | |||||
byte[] saltData = salt.getBytes(StandardCharsets.UTF_8); | |||||
PBEKeySpec keySpec = new PBEKeySpec(secretData, saltData, iterations, keyLength * 8); | |||||
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); | |||||
return toHex(secretKeyFactory.generateSecret(keySpec).getEncoded()); | |||||
} | |||||
catch (Exception e){ | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
public String hmac(String key) { | |||||
try | |||||
{ | |||||
Mac sha256_HMAC = Mac.getInstance("HmacSHA256"); | |||||
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); | |||||
sha256_HMAC.init(secret_key); | |||||
return toHex(sha256_HMAC.doFinal("".getBytes(StandardCharsets.UTF_8))); | |||||
} | |||||
catch (Exception e){ | |||||
throw new RuntimeException(e); | |||||
} | |||||
} | |||||
private static String toHex(byte[] bytes) { | |||||
BigInteger bi = new BigInteger(1, bytes); | |||||
return String.format("%0" + (bytes.length << 1) + "x", bi); | |||||
} | |||||
} | |||||
@@ -0,0 +1,40 @@ | |||||
package com.lesspass; | |||||
import com.facebook.react.bridge.NativeModule; | |||||
import com.facebook.react.bridge.ReactApplicationContext; | |||||
import com.facebook.react.bridge.ReactContext; | |||||
import com.facebook.react.bridge.ReactContextBaseJavaModule; | |||||
import com.facebook.react.bridge.ReactMethod; | |||||
import com.facebook.react.bridge.Promise; | |||||
import org.spongycastle.crypto.PBEParametersGenerator; | |||||
import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; | |||||
import org.spongycastle.crypto.digests.SHA256Digest; | |||||
import org.spongycastle.crypto.params.KeyParameter; | |||||
import java.math.BigInteger; | |||||
import java.nio.charset.StandardCharsets; | |||||
public class LessPassModule extends ReactContextBaseJavaModule { | |||||
public LessPassModule(ReactApplicationContext reactContext) { | |||||
super(reactContext); | |||||
} | |||||
@Override | |||||
public String getName() { | |||||
return "LessPass"; | |||||
} | |||||
@ReactMethod | |||||
public void calcEntropy(String site, String login, String masterPassword, String counter, Promise promise) { | |||||
String salt = site + login + counter; | |||||
String result = new Crypto().pbkdf2(masterPassword, salt, 100000, 32); | |||||
promise.resolve(result); | |||||
} | |||||
@ReactMethod | |||||
public void createFingerprint(String masterPassword, Promise promise) { | |||||
String result = new Crypto().hmac(masterPassword); | |||||
promise.resolve(result); | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
package com.lesspass; | |||||
import com.facebook.react.ReactPackage; | |||||
import com.facebook.react.bridge.NativeModule; | |||||
import com.facebook.react.bridge.ReactApplicationContext; | |||||
import com.facebook.react.uimanager.ViewManager; | |||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.List; | |||||
public class LessPassReactPackage implements ReactPackage { | |||||
@Override | |||||
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) { | |||||
return Collections.emptyList(); | |||||
} | |||||
@Override | |||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) { | |||||
List<NativeModule> modules = new ArrayList<>(); | |||||
modules.add(new LessPassModule(reactContext)); | |||||
return modules; | |||||
} | |||||
} |
@@ -0,0 +1,15 @@ | |||||
package com.lesspass; | |||||
import com.facebook.react.ReactActivity; | |||||
public class MainActivity extends ReactActivity { | |||||
/** | |||||
* Returns the name of the main component registered from JavaScript. | |||||
* This is used to schedule rendering of the component. | |||||
*/ | |||||
@Override | |||||
protected String getMainComponentName() { | |||||
return "LessPass"; | |||||
} | |||||
} |
@@ -0,0 +1,51 @@ | |||||
package com.lesspass; | |||||
import android.app.Application; | |||||
import com.facebook.react.ReactApplication; | |||||
import com.oblador.keychain.KeychainPackage; | |||||
import com.oblador.vectoricons.VectorIconsPackage; | |||||
import com.rnfingerprint.FingerprintAuthPackage; | |||||
import com.facebook.react.ReactNativeHost; | |||||
import com.facebook.react.ReactPackage; | |||||
import com.facebook.react.shell.MainReactPackage; | |||||
import com.facebook.soloader.SoLoader; | |||||
import java.util.Arrays; | |||||
import java.util.List; | |||||
public class MainApplication extends Application implements ReactApplication { | |||||
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { | |||||
@Override | |||||
public boolean getUseDeveloperSupport() { | |||||
return BuildConfig.DEBUG; | |||||
} | |||||
@Override | |||||
protected List<ReactPackage> getPackages() { | |||||
return Arrays.<ReactPackage>asList( | |||||
new MainReactPackage(), | |||||
new KeychainPackage(), | |||||
new VectorIconsPackage(), | |||||
new FingerprintAuthPackage(), | |||||
new LessPassReactPackage() | |||||
); | |||||
} | |||||
@Override | |||||
protected String getJSMainModuleName() { | |||||
return "index"; | |||||
} | |||||
}; | |||||
@Override | |||||
public ReactNativeHost getReactNativeHost() { | |||||
return mReactNativeHost; | |||||
} | |||||
@Override | |||||
public void onCreate() { | |||||
super.onCreate(); | |||||
SoLoader.init(this, /* native exopackage */ false); | |||||
} | |||||
} |
@@ -0,0 +1,5 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<resources> | |||||
<color name="colorPrimary">#333333</color> | |||||
<color name="textColorPrimary">#b3c7f9</color> | |||||
</resources> |
@@ -0,0 +1,3 @@ | |||||
<resources> | |||||
<string name="app_name">LessPass</string> | |||||
</resources> |
@@ -0,0 +1,13 @@ | |||||
<resources> | |||||
<!-- Base application theme. --> | |||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> | |||||
<!-- Customize your theme here. --> | |||||
<item name="android:colorPrimary">@color/colorPrimary</item> | |||||
<item name="android:colorPrimaryDark">@color/colorPrimary</item> | |||||
<item name="android:textColorPrimary">@color/textColorPrimary</item> | |||||
<item name="android:statusBarColor">@color/colorPrimary</item> | |||||
<item name="android:windowBackground">@color/colorPrimary</item> | |||||
<!-- <item name="android:navigationBarColor">@color/colorPrimary</item> --> | |||||
</style> | |||||
</resources> |
@@ -0,0 +1,31 @@ | |||||
import static org.junit.Assert.*; | |||||
import org.junit.Test; | |||||
import java.util.Map; | |||||
import java.util.HashMap; | |||||
import com.lesspass.Crypto; | |||||
public class CryptoTest { | |||||
@Test | |||||
public void testPbkdf2() { | |||||
String password = "password"; | |||||
String salt = "example.orgcontact@example.org1"; | |||||
String result = new Crypto().pbkdf2(password, salt, 100000, 32); | |||||
assertEquals("dc33d431bce2b01182c613382483ccdb0e2f66482cbba5e9d07dab34acc7eb1e", result); | |||||
} | |||||
@Test | |||||
public void testPbkdf2WithUnicodeChar() { | |||||
String password = "I ❤ LessPass"; | |||||
String salt = "example.org❤1"; | |||||
String result = new Crypto().pbkdf2(password, salt, 100000, 32); | |||||
assertEquals("4e66cab40690c01af55efd595f5963cc953d7e10273c01827881ebf8990c627f", result); | |||||
} | |||||
@Test | |||||
public void testHMAC() { | |||||
String result = new Crypto().hmac("password"); | |||||
assertEquals("e56a207acd1e6714735487c199c6f095844b7cc8e5971d86c003a7b6f36ef51e", result); | |||||
} | |||||
} |
@@ -0,0 +1,51 @@ | |||||
// Top-level build file where you can add configuration options common to all sub-projects/modules. | |||||
buildscript { | |||||
repositories { | |||||
jcenter() | |||||
maven { | |||||
url 'https://maven.google.com/' | |||||
name 'Google' | |||||
} | |||||
} | |||||
dependencies { | |||||
classpath 'com.android.tools.build:gradle:2.3.3' | |||||
// NOTE: Do not place your application dependencies here; they belong | |||||
// in the individual module build.gradle files | |||||
} | |||||
} | |||||
allprojects { | |||||
repositories { | |||||
mavenLocal() | |||||
jcenter() | |||||
maven { | |||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm | |||||
url "$rootDir/../node_modules/react-native/android" | |||||
} | |||||
maven { | |||||
url 'https://maven.google.com/' | |||||
name 'Google' | |||||
} | |||||
} | |||||
} | |||||
ext { | |||||
buildToolsVersion = "26.0.3" | |||||
minSdkVersion = 26 | |||||
compileSdkVersion = 26 | |||||
targetSdkVersion = 26 | |||||
supportLibVersion = "26.1.0" | |||||
} | |||||
subprojects { subproject -> | |||||
afterEvaluate{ | |||||
if((subproject.name == 'react-native-touch-id')) { | |||||
android { | |||||
compileSdkVersion rootProject.ext.compileSdkVersion | |||||
buildToolsVersion rootProject.ext.buildToolsVersion | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,20 @@ | |||||
# Project-wide Gradle settings. | |||||
# IDE (e.g. Android Studio) users: | |||||
# Gradle settings configured through the IDE *will override* | |||||
# any settings specified in this file. | |||||
# For more details on how to configure your build environment visit | |||||
# http://www.gradle.org/docs/current/userguide/build_environment.html | |||||
# Specifies the JVM arguments used for the daemon process. | |||||
# The setting is particularly useful for tweaking memory settings. | |||||
# Default value: -Xmx10248m -XX:MaxPermSize=256m | |||||
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 | |||||
# When configured, Gradle will run in incubating parallel mode. | |||||
# 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.useDeprecatedNdk=true |
@@ -0,0 +1,5 @@ | |||||
distributionBase=GRADLE_USER_HOME | |||||
distributionPath=wrapper/dists | |||||
zipStoreBase=GRADLE_USER_HOME | |||||
zipStorePath=wrapper/dists | |||||
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip |
@@ -0,0 +1,164 @@ | |||||
#!/usr/bin/env bash | |||||
############################################################################## | |||||
## | |||||
## Gradle start up script for UN*X | |||||
## | |||||
############################################################################## | |||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||||
DEFAULT_JVM_OPTS="" | |||||
APP_NAME="Gradle" | |||||
APP_BASE_NAME=`basename "$0"` | |||||
# Use the maximum available, or set MAX_FD != -1 to use that value. | |||||
MAX_FD="maximum" | |||||
warn ( ) { | |||||
echo "$*" | |||||
} | |||||
die ( ) { | |||||
echo | |||||
echo "$*" | |||||
echo | |||||
exit 1 | |||||
} | |||||
# OS specific support (must be 'true' or 'false'). | |||||
cygwin=false | |||||
msys=false | |||||
darwin=false | |||||
case "`uname`" in | |||||
CYGWIN* ) | |||||
cygwin=true | |||||
;; | |||||
Darwin* ) | |||||
darwin=true | |||||
;; | |||||
MINGW* ) | |||||
msys=true | |||||
;; | |||||
esac | |||||
# For Cygwin, ensure paths are in UNIX format before anything is touched. | |||||
if $cygwin ; then | |||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` | |||||
fi | |||||
# Attempt to set APP_HOME | |||||
# Resolve links: $0 may be a link | |||||
PRG="$0" | |||||
# Need this for relative symlinks. | |||||
while [ -h "$PRG" ] ; do | |||||
ls=`ls -ld "$PRG"` | |||||
link=`expr "$ls" : '.*-> \(.*\)$'` | |||||
if expr "$link" : '/.*' > /dev/null; then | |||||
PRG="$link" | |||||
else | |||||
PRG=`dirname "$PRG"`"/$link" | |||||
fi | |||||
done | |||||
SAVED="`pwd`" | |||||
cd "`dirname \"$PRG\"`/" >&- | |||||
APP_HOME="`pwd -P`" | |||||
cd "$SAVED" >&- | |||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |||||
# Determine the Java command to use to start the JVM. | |||||
if [ -n "$JAVA_HOME" ] ; then | |||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |||||
# IBM's JDK on AIX uses strange locations for the executables | |||||
JAVACMD="$JAVA_HOME/jre/sh/java" | |||||
else | |||||
JAVACMD="$JAVA_HOME/bin/java" | |||||
fi | |||||
if [ ! -x "$JAVACMD" ] ; then | |||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |||||
Please set the JAVA_HOME variable in your environment to match the | |||||
location of your Java installation." | |||||
fi | |||||
else | |||||
JAVACMD="java" | |||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||||
Please set the JAVA_HOME variable in your environment to match the | |||||
location of your Java installation." | |||||
fi | |||||
# Increase the maximum file descriptors if we can. | |||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then | |||||
MAX_FD_LIMIT=`ulimit -H -n` | |||||
if [ $? -eq 0 ] ; then | |||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |||||
MAX_FD="$MAX_FD_LIMIT" | |||||
fi | |||||
ulimit -n $MAX_FD | |||||
if [ $? -ne 0 ] ; then | |||||
warn "Could not set maximum file descriptor limit: $MAX_FD" | |||||
fi | |||||
else | |||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |||||
fi | |||||
fi | |||||
# For Darwin, add options to specify how the application appears in the dock | |||||
if $darwin; then | |||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |||||
fi | |||||
# For Cygwin, switch paths to Windows format before running java | |||||
if $cygwin ; then | |||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |||||
# We build the pattern for arguments to be converted via cygpath | |||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |||||
SEP="" | |||||
for dir in $ROOTDIRSRAW ; do | |||||
ROOTDIRS="$ROOTDIRS$SEP$dir" | |||||
SEP="|" | |||||
done | |||||
OURCYGPATTERN="(^($ROOTDIRS))" | |||||
# Add a user-defined pattern to the cygpath arguments | |||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |||||
fi | |||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh | |||||
i=0 | |||||
for arg in "$@" ; do | |||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |||||
else | |||||
eval `echo args$i`="\"$arg\"" | |||||
fi | |||||
i=$((i+1)) | |||||
done | |||||
case $i in | |||||
(0) set -- ;; | |||||
(1) set -- "$args0" ;; | |||||
(2) set -- "$args0" "$args1" ;; | |||||
(3) set -- "$args0" "$args1" "$args2" ;; | |||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |||||
esac | |||||
fi | |||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | |||||
function splitJvmOpts() { | |||||
JVM_OPTS=("$@") | |||||
} | |||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | |||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | |||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
@@ -0,0 +1,90 @@ | |||||
@if "%DEBUG%" == "" @echo off | |||||
@rem ########################################################################## | |||||
@rem | |||||
@rem Gradle startup script for Windows | |||||
@rem | |||||
@rem ########################################################################## | |||||
@rem Set local scope for the variables with windows NT shell | |||||
if "%OS%"=="Windows_NT" setlocal | |||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |||||
set DEFAULT_JVM_OPTS= | |||||
set DIRNAME=%~dp0 | |||||
if "%DIRNAME%" == "" set DIRNAME=. | |||||
set APP_BASE_NAME=%~n0 | |||||
set APP_HOME=%DIRNAME% | |||||
@rem Find java.exe | |||||
if defined JAVA_HOME goto findJavaFromJavaHome | |||||
set JAVA_EXE=java.exe | |||||
%JAVA_EXE% -version >NUL 2>&1 | |||||
if "%ERRORLEVEL%" == "0" goto init | |||||
echo. | |||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |||||
echo. | |||||
echo Please set the JAVA_HOME variable in your environment to match the | |||||
echo location of your Java installation. | |||||
goto fail | |||||
:findJavaFromJavaHome | |||||
set JAVA_HOME=%JAVA_HOME:"=% | |||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |||||
if exist "%JAVA_EXE%" goto init | |||||
echo. | |||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |||||
echo. | |||||
echo Please set the JAVA_HOME variable in your environment to match the | |||||
echo location of your Java installation. | |||||
goto fail | |||||
:init | |||||
@rem Get command-line arguments, handling Windowz variants | |||||
if not "%OS%" == "Windows_NT" goto win9xME_args | |||||
if "%@eval[2+2]" == "4" goto 4NT_args | |||||
:win9xME_args | |||||
@rem Slurp the command line arguments. | |||||
set CMD_LINE_ARGS= | |||||
set _SKIP=2 | |||||
:win9xME_args_slurp | |||||
if "x%~1" == "x" goto execute | |||||
set CMD_LINE_ARGS=%* | |||||
goto execute | |||||
:4NT_args | |||||
@rem Get arguments from the 4NT Shell from JP Software | |||||
set CMD_LINE_ARGS=%$ | |||||
:execute | |||||
@rem Setup the command line | |||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |||||
@rem Execute Gradle | |||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | |||||
:end | |||||
@rem End local scope for the variables with windows NT shell | |||||
if "%ERRORLEVEL%"=="0" goto mainEnd | |||||
:fail | |||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |||||
rem the _cmd.exe /c_ return code! | |||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |||||
exit /b 1 | |||||
:mainEnd | |||||
if "%OS%"=="Windows_NT" endlocal | |||||
:omega |
@@ -0,0 +1,8 @@ | |||||
keystore( | |||||
name = "debug", | |||||
properties = "debug.keystore.properties", | |||||
store = "debug.keystore", | |||||
visibility = [ | |||||
"PUBLIC", | |||||
], | |||||
) |
@@ -0,0 +1,4 @@ | |||||
key.store=debug.keystore | |||||
key.alias=androiddebugkey | |||||
key.store.password=android | |||||
key.alias.password=android |
@@ -0,0 +1,9 @@ | |||||
rootProject.name = 'LessPass' | |||||
include ':react-native-keychain' | |||||
project(':react-native-keychain').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-keychain/android') | |||||
include ':react-native-vector-icons' | |||||
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') | |||||
include ':react-native-touch-id' | |||||
project(':react-native-touch-id').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-touch-id/android') | |||||
include ':app' |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
"name": "LessPass", | |||||
"displayName": "LessPass" | |||||
} |
@@ -0,0 +1,5 @@ | |||||
import {AppRegistry} from 'react-native'; | |||||
import App from './App'; | |||||
import {name as appName} from './app.json'; | |||||
AppRegistry.registerComponent(appName, () => App); |
@@ -0,0 +1,54 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
<plist version="1.0"> | |||||
<dict> | |||||
<key>CFBundleDevelopmentRegion</key> | |||||
<string>en</string> | |||||
<key>CFBundleExecutable</key> | |||||
<string>$(EXECUTABLE_NAME)</string> | |||||
<key>CFBundleIdentifier</key> | |||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string> | |||||
<key>CFBundleInfoDictionaryVersion</key> | |||||
<string>6.0</string> | |||||
<key>CFBundleName</key> | |||||
<string>$(PRODUCT_NAME)</string> | |||||
<key>CFBundlePackageType</key> | |||||
<string>APPL</string> | |||||
<key>CFBundleShortVersionString</key> | |||||
<string>1.0</string> | |||||
<key>CFBundleSignature</key> | |||||
<string>????</string> | |||||
<key>CFBundleVersion</key> | |||||
<string>1</string> | |||||
<key>LSRequiresIPhoneOS</key> | |||||
<true/> | |||||
<key>UILaunchStoryboardName</key> | |||||
<string>LaunchScreen</string> | |||||
<key>UIRequiredDeviceCapabilities</key> | |||||
<array> | |||||
<string>armv7</string> | |||||
</array> | |||||
<key>UISupportedInterfaceOrientations</key> | |||||
<array> | |||||
<string>UIInterfaceOrientationPortrait</string> | |||||
<string>UIInterfaceOrientationLandscapeLeft</string> | |||||
<string>UIInterfaceOrientationLandscapeRight</string> | |||||
</array> | |||||
<key>UIViewControllerBasedStatusBarAppearance</key> | |||||
<false/> | |||||
<key>NSLocationWhenInUseUsageDescription</key> | |||||
<string></string> | |||||
<key>NSAppTransportSecurity</key> | |||||
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ --> | |||||
<dict> | |||||
<key>NSExceptionDomains</key> | |||||
<dict> | |||||
<key>localhost</key> | |||||
<dict> | |||||
<key>NSExceptionAllowsInsecureHTTPLoads</key> | |||||
<true/> | |||||
</dict> | |||||
</dict> | |||||
</dict> | |||||
</dict> | |||||
</plist> |
@@ -0,0 +1,24 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
<plist version="1.0"> | |||||
<dict> | |||||
<key>CFBundleDevelopmentRegion</key> | |||||
<string>en</string> | |||||
<key>CFBundleExecutable</key> | |||||
<string>$(EXECUTABLE_NAME)</string> | |||||
<key>CFBundleIdentifier</key> | |||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string> | |||||
<key>CFBundleInfoDictionaryVersion</key> | |||||
<string>6.0</string> | |||||
<key>CFBundleName</key> | |||||
<string>$(PRODUCT_NAME)</string> | |||||
<key>CFBundlePackageType</key> | |||||
<string>BNDL</string> | |||||
<key>CFBundleShortVersionString</key> | |||||
<string>1.0</string> | |||||
<key>CFBundleSignature</key> | |||||
<string>????</string> | |||||
<key>CFBundleVersion</key> | |||||
<string>1</string> | |||||
</dict> | |||||
</plist> |
@@ -0,0 +1,129 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<Scheme | |||||
LastUpgradeVersion = "0820" | |||||
version = "1.3"> | |||||
<BuildAction | |||||
parallelizeBuildables = "NO" | |||||
buildImplicitDependencies = "YES"> | |||||
<BuildActionEntries> | |||||
<BuildActionEntry | |||||
buildForTesting = "YES" | |||||
buildForRunning = "YES" | |||||
buildForProfiling = "YES" | |||||
buildForArchiving = "YES" | |||||
buildForAnalyzing = "YES"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "2D2A28121D9B038B00D4039D" | |||||
BuildableName = "libReact.a" | |||||
BlueprintName = "React-tvOS" | |||||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildActionEntry> | |||||
<BuildActionEntry | |||||
buildForTesting = "YES" | |||||
buildForRunning = "YES" | |||||
buildForProfiling = "YES" | |||||
buildForArchiving = "YES" | |||||
buildForAnalyzing = "YES"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7" | |||||
BuildableName = "LessPass-tvOS.app" | |||||
BlueprintName = "LessPass-tvOS" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildActionEntry> | |||||
<BuildActionEntry | |||||
buildForTesting = "YES" | |||||
buildForRunning = "YES" | |||||
buildForProfiling = "NO" | |||||
buildForArchiving = "NO" | |||||
buildForAnalyzing = "YES"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7" | |||||
BuildableName = "LessPass-tvOSTests.xctest" | |||||
BlueprintName = "LessPass-tvOSTests" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildActionEntry> | |||||
</BuildActionEntries> | |||||
</BuildAction> | |||||
<TestAction | |||||
buildConfiguration = "Debug" | |||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |||||
shouldUseLaunchSchemeArgsEnv = "YES"> | |||||
<Testables> | |||||
<TestableReference | |||||
skipped = "NO"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7" | |||||
BuildableName = "LessPass-tvOSTests.xctest" | |||||
BlueprintName = "LessPass-tvOSTests" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</TestableReference> | |||||
</Testables> | |||||
<MacroExpansion> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7" | |||||
BuildableName = "LessPass-tvOS.app" | |||||
BlueprintName = "LessPass-tvOS" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</MacroExpansion> | |||||
<AdditionalOptions> | |||||
</AdditionalOptions> | |||||
</TestAction> | |||||
<LaunchAction | |||||
buildConfiguration = "Debug" | |||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |||||
launchStyle = "0" | |||||
useCustomWorkingDirectory = "NO" | |||||
ignoresPersistentStateOnLaunch = "NO" | |||||
debugDocumentVersioning = "YES" | |||||
debugServiceExtension = "internal" | |||||
allowLocationSimulation = "YES"> | |||||
<BuildableProductRunnable | |||||
runnableDebuggingMode = "0"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7" | |||||
BuildableName = "LessPass-tvOS.app" | |||||
BlueprintName = "LessPass-tvOS" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildableProductRunnable> | |||||
<AdditionalOptions> | |||||
</AdditionalOptions> | |||||
</LaunchAction> | |||||
<ProfileAction | |||||
buildConfiguration = "Release" | |||||
shouldUseLaunchSchemeArgsEnv = "YES" | |||||
savedToolIdentifier = "" | |||||
useCustomWorkingDirectory = "NO" | |||||
debugDocumentVersioning = "YES"> | |||||
<BuildableProductRunnable | |||||
runnableDebuggingMode = "0"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7" | |||||
BuildableName = "LessPass-tvOS.app" | |||||
BlueprintName = "LessPass-tvOS" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildableProductRunnable> | |||||
</ProfileAction> | |||||
<AnalyzeAction | |||||
buildConfiguration = "Debug"> | |||||
</AnalyzeAction> | |||||
<ArchiveAction | |||||
buildConfiguration = "Release" | |||||
revealArchiveInOrganizer = "YES"> | |||||
</ArchiveAction> | |||||
</Scheme> |
@@ -0,0 +1,129 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<Scheme | |||||
LastUpgradeVersion = "0620" | |||||
version = "1.3"> | |||||
<BuildAction | |||||
parallelizeBuildables = "NO" | |||||
buildImplicitDependencies = "YES"> | |||||
<BuildActionEntries> | |||||
<BuildActionEntry | |||||
buildForTesting = "YES" | |||||
buildForRunning = "YES" | |||||
buildForProfiling = "YES" | |||||
buildForArchiving = "YES" | |||||
buildForAnalyzing = "YES"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "83CBBA2D1A601D0E00E9B192" | |||||
BuildableName = "libReact.a" | |||||
BlueprintName = "React" | |||||
ReferencedContainer = "container:../node_modules/react-native/React/React.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildActionEntry> | |||||
<BuildActionEntry | |||||
buildForTesting = "YES" | |||||
buildForRunning = "YES" | |||||
buildForProfiling = "YES" | |||||
buildForArchiving = "YES" | |||||
buildForAnalyzing = "YES"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" | |||||
BuildableName = "LessPass.app" | |||||
BlueprintName = "LessPass" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildActionEntry> | |||||
<BuildActionEntry | |||||
buildForTesting = "YES" | |||||
buildForRunning = "YES" | |||||
buildForProfiling = "NO" | |||||
buildForArchiving = "NO" | |||||
buildForAnalyzing = "YES"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E" | |||||
BuildableName = "LessPassTests.xctest" | |||||
BlueprintName = "LessPassTests" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildActionEntry> | |||||
</BuildActionEntries> | |||||
</BuildAction> | |||||
<TestAction | |||||
buildConfiguration = "Debug" | |||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |||||
shouldUseLaunchSchemeArgsEnv = "YES"> | |||||
<Testables> | |||||
<TestableReference | |||||
skipped = "NO"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "00E356ED1AD99517003FC87E" | |||||
BuildableName = "LessPassTests.xctest" | |||||
BlueprintName = "LessPassTests" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</TestableReference> | |||||
</Testables> | |||||
<MacroExpansion> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" | |||||
BuildableName = "LessPass.app" | |||||
BlueprintName = "LessPass" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</MacroExpansion> | |||||
<AdditionalOptions> | |||||
</AdditionalOptions> | |||||
</TestAction> | |||||
<LaunchAction | |||||
buildConfiguration = "Debug" | |||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | |||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | |||||
launchStyle = "0" | |||||
useCustomWorkingDirectory = "NO" | |||||
ignoresPersistentStateOnLaunch = "NO" | |||||
debugDocumentVersioning = "YES" | |||||
debugServiceExtension = "internal" | |||||
allowLocationSimulation = "YES"> | |||||
<BuildableProductRunnable | |||||
runnableDebuggingMode = "0"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" | |||||
BuildableName = "LessPass.app" | |||||
BlueprintName = "LessPass" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildableProductRunnable> | |||||
<AdditionalOptions> | |||||
</AdditionalOptions> | |||||
</LaunchAction> | |||||
<ProfileAction | |||||
buildConfiguration = "Release" | |||||
shouldUseLaunchSchemeArgsEnv = "YES" | |||||
savedToolIdentifier = "" | |||||
useCustomWorkingDirectory = "NO" | |||||
debugDocumentVersioning = "YES"> | |||||
<BuildableProductRunnable | |||||
runnableDebuggingMode = "0"> | |||||
<BuildableReference | |||||
BuildableIdentifier = "primary" | |||||
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" | |||||
BuildableName = "LessPass.app" | |||||
BlueprintName = "LessPass" | |||||
ReferencedContainer = "container:LessPass.xcodeproj"> | |||||
</BuildableReference> | |||||
</BuildableProductRunnable> | |||||
</ProfileAction> | |||||
<AnalyzeAction | |||||
buildConfiguration = "Debug"> | |||||
</AnalyzeAction> | |||||
<ArchiveAction | |||||
buildConfiguration = "Release" | |||||
revealArchiveInOrganizer = "YES"> | |||||
</ArchiveAction> | |||||
</Scheme> |
@@ -0,0 +1,14 @@ | |||||
/** | |||||
* Copyright (c) 2015-present, Facebook, Inc. | |||||
* | |||||
* This source code is licensed under the MIT license found in the | |||||
* LICENSE file in the root directory of this source tree. | |||||
*/ | |||||
#import <UIKit/UIKit.h> | |||||
@interface AppDelegate : UIResponder <UIApplicationDelegate> | |||||
@property (nonatomic, strong) UIWindow *window; | |||||
@end |
@@ -0,0 +1,35 @@ | |||||
/** | |||||
* Copyright (c) 2015-present, Facebook, Inc. | |||||
* | |||||
* This source code is licensed under the MIT license found in the | |||||
* LICENSE file in the root directory of this source tree. | |||||
*/ | |||||
#import "AppDelegate.h" | |||||
#import <React/RCTBundleURLProvider.h> | |||||
#import <React/RCTRootView.h> | |||||
@implementation AppDelegate | |||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions | |||||
{ | |||||
NSURL *jsCodeLocation; | |||||
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; | |||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation | |||||
moduleName:@"LessPass" | |||||
initialProperties:nil | |||||
launchOptions:launchOptions]; | |||||
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; | |||||
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; | |||||
UIViewController *rootViewController = [UIViewController new]; | |||||
rootViewController.view = rootView; | |||||
self.window.rootViewController = rootViewController; | |||||
[self.window makeKeyAndVisible]; | |||||
return YES; | |||||
} | |||||
@end |
@@ -0,0 +1,42 @@ | |||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> | |||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES"> | |||||
<dependencies> | |||||
<deployment identifier="iOS"/> | |||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/> | |||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/> | |||||
</dependencies> | |||||
<objects> | |||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/> | |||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> | |||||
<view contentMode="scaleToFill" id="iN0-l3-epB"> | |||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/> | |||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |||||
<subviews> | |||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye"> | |||||
<rect key="frame" x="20" y="439" width="441" height="21"/> | |||||
<fontDescription key="fontDescription" type="system" pointSize="17"/> | |||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/> | |||||
<nil key="highlightedColor"/> | |||||
</label> | |||||
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LessPass" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX"> | |||||
<rect key="frame" x="20" y="140" width="441" height="43"/> | |||||
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/> | |||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/> | |||||
<nil key="highlightedColor"/> | |||||
</label> | |||||
</subviews> | |||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> | |||||
<constraints> | |||||
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/> | |||||
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/> | |||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/> | |||||
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/> | |||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/> | |||||
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/> | |||||
</constraints> | |||||
<nil key="simulatedStatusBarMetrics"/> | |||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> | |||||
<point key="canvasLocation" x="548" y="455"/> | |||||
</view> | |||||
</objects> | |||||
</document> |
@@ -0,0 +1,38 @@ | |||||
{ | |||||
"images" : [ | |||||
{ | |||||
"idiom" : "iphone", | |||||
"size" : "29x29", | |||||
"scale" : "2x" | |||||
}, | |||||
{ | |||||
"idiom" : "iphone", | |||||
"size" : "29x29", | |||||
"scale" : "3x" | |||||
}, | |||||
{ | |||||
"idiom" : "iphone", | |||||
"size" : "40x40", | |||||
"scale" : "2x" | |||||
}, | |||||
{ | |||||
"idiom" : "iphone", | |||||
"size" : "40x40", | |||||
"scale" : "3x" | |||||
}, | |||||
{ | |||||
"idiom" : "iphone", | |||||
"size" : "60x60", | |||||
"scale" : "2x" | |||||
}, | |||||
{ | |||||
"idiom" : "iphone", | |||||
"size" : "60x60", | |||||
"scale" : "3x" | |||||
} | |||||
], | |||||
"info" : { | |||||
"version" : 1, | |||||
"author" : "xcode" | |||||
} | |||||
} |
@@ -0,0 +1,6 @@ | |||||
{ | |||||
"info" : { | |||||
"version" : 1, | |||||
"author" : "xcode" | |||||
} | |||||
} |
@@ -0,0 +1,75 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
<plist version="1.0"> | |||||
<dict> | |||||
<key>CFBundleDevelopmentRegion</key> | |||||
<string>en</string> | |||||
<key>CFBundleDisplayName</key> | |||||
<string>LessPass</string> | |||||
<key>CFBundleExecutable</key> | |||||
<string>$(EXECUTABLE_NAME)</string> | |||||
<key>CFBundleIdentifier</key> | |||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string> | |||||
<key>CFBundleInfoDictionaryVersion</key> | |||||
<string>6.0</string> | |||||
<key>CFBundleName</key> | |||||
<string>$(PRODUCT_NAME)</string> | |||||
<key>CFBundlePackageType</key> | |||||
<string>APPL</string> | |||||
<key>CFBundleShortVersionString</key> | |||||
<string>1.0</string> | |||||
<key>CFBundleSignature</key> | |||||
<string>????</string> | |||||
<key>CFBundleVersion</key> | |||||
<string>1</string> | |||||
<key>LSRequiresIPhoneOS</key> | |||||
<true/> | |||||
<key>UILaunchStoryboardName</key> | |||||
<string>LaunchScreen</string> | |||||
<key>UIRequiredDeviceCapabilities</key> | |||||
<array> | |||||
<string>armv7</string> | |||||
</array> | |||||
<key>UISupportedInterfaceOrientations</key> | |||||
<array> | |||||
<string>UIInterfaceOrientationPortrait</string> | |||||
<string>UIInterfaceOrientationLandscapeLeft</string> | |||||
<string>UIInterfaceOrientationLandscapeRight</string> | |||||
</array> | |||||
<key>UIViewControllerBasedStatusBarAppearance</key> | |||||
<false/> | |||||
<key>NSLocationWhenInUseUsageDescription</key> | |||||
<string/> | |||||
<key>NSAppTransportSecurity</key> | |||||
<dict> | |||||
<key>NSExceptionDomains</key> | |||||
<dict> | |||||
<key>localhost</key> | |||||
<dict> | |||||
<key>NSExceptionAllowsInsecureHTTPLoads</key> | |||||
<true/> | |||||
</dict> | |||||
</dict> | |||||
</dict> | |||||
<key>UIAppFonts</key> | |||||
<array> | |||||
<string>Entypo.ttf</string> | |||||
<string>EvilIcons.ttf</string> | |||||
<string>Feather.ttf</string> | |||||
<string>FontAwesome.ttf</string> | |||||
<string>Foundation.ttf</string> | |||||
<string>Ionicons.ttf</string> | |||||
<string>MaterialCommunityIcons.ttf</string> | |||||
<string>MaterialIcons.ttf</string> | |||||
<string>Octicons.ttf</string> | |||||
<string>Roboto_medium.ttf</string> | |||||
<string>Roboto.ttf</string> | |||||
<string>rubicon-icon-font.ttf</string> | |||||
<string>SimpleLineIcons.ttf</string> | |||||
<string>Zocial.ttf</string> | |||||
<string>FontAwesome5_Brands.ttf</string> | |||||
<string>FontAwesome5_Regular.ttf</string> | |||||
<string>FontAwesome5_Solid.ttf</string> | |||||
</array> | |||||
</dict> | |||||
</plist> |
@@ -0,0 +1,16 @@ | |||||
/** | |||||
* Copyright (c) 2015-present, Facebook, Inc. | |||||
* | |||||
* This source code is licensed under the MIT license found in the | |||||
* LICENSE file in the root directory of this source tree. | |||||
*/ | |||||
#import <UIKit/UIKit.h> | |||||
#import "AppDelegate.h" | |||||
int main(int argc, char * argv[]) { | |||||
@autoreleasepool { | |||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
<?xml version="1.0" encoding="UTF-8"?> | |||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
<plist version="1.0"> | |||||
<dict> | |||||
<key>CFBundleDevelopmentRegion</key> | |||||
<string>en</string> | |||||
<key>CFBundleExecutable</key> | |||||
<string>$(EXECUTABLE_NAME)</string> | |||||
<key>CFBundleIdentifier</key> | |||||
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string> | |||||
<key>CFBundleInfoDictionaryVersion</key> | |||||
<string>6.0</string> | |||||
<key>CFBundleName</key> | |||||
<string>$(PRODUCT_NAME)</string> | |||||
<key>CFBundlePackageType</key> | |||||
<string>BNDL</string> | |||||
<key>CFBundleShortVersionString</key> | |||||
<string>1.0</string> | |||||
<key>CFBundleSignature</key> | |||||
<string>????</string> | |||||
<key>CFBundleVersion</key> | |||||
<string>1</string> | |||||
</dict> | |||||
</plist> |
@@ -0,0 +1,68 @@ | |||||
/** | |||||
* Copyright (c) 2015-present, Facebook, Inc. | |||||
* | |||||
* This source code is licensed under the MIT license found in the | |||||
* LICENSE file in the root directory of this source tree. | |||||
*/ | |||||
#import <UIKit/UIKit.h> | |||||
#import <XCTest/XCTest.h> | |||||
#import <React/RCTLog.h> | |||||
#import <React/RCTRootView.h> | |||||
#define TIMEOUT_SECONDS 600 | |||||
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!" | |||||
@interface LessPassTests : XCTestCase | |||||
@end | |||||
@implementation LessPassTests | |||||
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test | |||||
{ | |||||
if (test(view)) { | |||||
return YES; | |||||
} | |||||
for (UIView *subview in [view subviews]) { | |||||
if ([self findSubviewInView:subview matching:test]) { | |||||
return YES; | |||||
} | |||||
} | |||||
return NO; | |||||
} | |||||
- (void)testRendersWelcomeScreen | |||||
{ | |||||
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; | |||||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; | |||||
BOOL foundElement = NO; | |||||
__block NSString *redboxError = nil; | |||||
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { | |||||
if (level >= RCTLogLevelError) { | |||||
redboxError = message; | |||||
} | |||||
}); | |||||
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { | |||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; | |||||
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; | |||||
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { | |||||
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { | |||||
return YES; | |||||
} | |||||
return NO; | |||||
}]; | |||||
} | |||||
RCTSetLogFunction(RCTDefaultLogFunction); | |||||
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); | |||||
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); | |||||
} | |||||
@end |
@@ -0,0 +1,37 @@ | |||||
{ | |||||
"name": "lesspass-mobile", | |||||
"version": "0.1.0", | |||||
"private": true, | |||||
"scripts": { | |||||
"start": "node node_modules/react-native/local-cli/cli.js start", | |||||
"test": "jest" | |||||
}, | |||||
"dependencies": { | |||||
"debounce": "^1.2.0", | |||||
"lesspass-master-password": "^0.1.0", | |||||
"lesspass-render-password": "^0.1.0", | |||||
"native-base": "^2.8.0", | |||||
"react": "16.4.1", | |||||
"react-native": "0.56.0", | |||||
"react-native-keychain": "^3.0.0", | |||||
"react-native-paper": "^2.0.1", | |||||
"react-native-slider": "^0.11.0", | |||||
"react-native-touch-id": "^4.0.4", | |||||
"react-native-vector-icons": "^5.0.0", | |||||
"react-navigation": "^2.12.1", | |||||
"react-navigation-material-bottom-tabs": "^0.4.0", | |||||
"react-redux": "^5.0.7", | |||||
"redux": "^4.0.0", | |||||
"redux-persist": "^5.10.0", | |||||
"redux-thunk": "^2.3.0" | |||||
}, | |||||
"devDependencies": { | |||||
"babel-jest": "23.4.2", | |||||
"babel-preset-react-native": "^5", | |||||
"jest": "23.5.0", | |||||
"react-test-renderer": "16.4.1" | |||||
}, | |||||
"jest": { | |||||
"preset": "react-native" | |||||
} | |||||
} |
@@ -0,0 +1,6 @@ | |||||
export function setConfig(config) { | |||||
return { | |||||
type: "SET_CONFIG", | |||||
config | |||||
}; | |||||
} |
@@ -0,0 +1,12 @@ | |||||
const initialState = { | |||||
keepMasterPasswordLocally: false | |||||
}; | |||||
export default function(state = initialState, action) { | |||||
switch (action.type) { | |||||
case "SET_CONFIG": | |||||
return { ...state, ...action.config }; | |||||
default: | |||||
return state; | |||||
} | |||||
} |
@@ -0,0 +1,45 @@ | |||||
import reducer from "./ConfigReducer"; | |||||
describe("config reducer", () => { | |||||
it("should return the initial state", () => { | |||||
expect(reducer(undefined, { | |||||
keepMasterPasswordLocally: false | |||||
})).toEqual({}); | |||||
}); | |||||
it("SET_CONFIG", () => { | |||||
expect( | |||||
reducer( | |||||
{ | |||||
keepMasterPasswordLocally: false | |||||
}, | |||||
{ | |||||
type: "SET_CONFIG", | |||||
config: { | |||||
keepMasterPasswordLocally: true | |||||
} | |||||
} | |||||
) | |||||
).toEqual({ | |||||
keepMasterPasswordLocally: true | |||||
}); | |||||
}); | |||||
it("SET_CONFIG keep existing config", () => { | |||||
expect( | |||||
reducer( | |||||
{ | |||||
config1: false, | |||||
config2: false | |||||
}, | |||||
{ | |||||
type: "SET_CONFIG", | |||||
config: { | |||||
config1: true | |||||
} | |||||
} | |||||
) | |||||
).toEqual({ | |||||
config1: false, | |||||
config2: false | |||||
}); | |||||
}); | |||||
}); |
@@ -0,0 +1,71 @@ | |||||
import React, { Component } from "react"; | |||||
import { View, NativeModules } from "react-native"; | |||||
import Icon from "react-native-vector-icons/FontAwesome"; | |||||
import LessPassMasterPassword from "lesspass-master-password"; | |||||
import _ from "lodash"; | |||||
export default class Fingerprint extends Component { | |||||
state = {}; | |||||
componentDidMount() { | |||||
this._calcFingerprint(); | |||||
} | |||||
componentDidUpdate() { | |||||
if (!this.state.loaded) { | |||||
this._calcFingerprint(); | |||||
} | |||||
} | |||||
static getDerivedStateFromProps(nextProps, prevState) { | |||||
if (nextProps.masterPassword === prevState.masterPassword) return null; | |||||
return { | |||||
masterPassword: nextProps.masterPassword, | |||||
loaded: false | |||||
}; | |||||
} | |||||
_calcFingerprint = () => { | |||||
const { masterPassword } = this.props; | |||||
NativeModules.LessPass.createFingerprint(masterPassword).then( | |||||
hmacSha256 => { | |||||
const fingerprint = LessPassMasterPassword.getLessPassFingerprint( | |||||
hmacSha256 | |||||
); | |||||
this.setState({ masterPassword, fingerprint, loaded: true }); | |||||
} | |||||
); | |||||
}; | |||||
render() { | |||||
const { fingerprint, loaded } = this.state; | |||||
if (!loaded) return null; | |||||
return ( | |||||
<View | |||||
style={{ | |||||
position: "absolute", | |||||
right: 10, | |||||
top: 24, | |||||
bottom: 0, | |||||
flexDirection: "row" | |||||
}} | |||||
> | |||||
<Icon | |||||
size={20} | |||||
name={fingerprint[0]["icon"].replace("fa-", "")} | |||||
style={{ color: fingerprint[0]["color"], marginRight: 5 }} | |||||
/> | |||||
<Icon | |||||
size={20} | |||||
name={fingerprint[1]["icon"].replace("fa-", "")} | |||||
style={{ color: fingerprint[1]["color"], marginRight: 5 }} | |||||
/> | |||||
<Icon | |||||
size={20} | |||||
name={fingerprint[2]["icon"].replace("fa-", "")} | |||||
style={{ color: fingerprint[2]["color"], marginRight: 5 }} | |||||
/> | |||||
</View> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
import React, { Component } from "react"; | |||||
import {View,Text} from "react-native"; | |||||
export default class ForgotPasswordScreen extends Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = {}; | |||||
} | |||||
render() { | |||||
return ( | |||||
<View> | |||||
<Text>ForgotPasswordScreen</Text> | |||||
</View> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,24 @@ | |||||
import React, { Component } from "react"; | |||||
import { View, Image } from "react-native"; | |||||
import Theme from "./Theme"; | |||||
export default class Header extends Component { | |||||
render() { | |||||
return ( | |||||
<View | |||||
style={{ backgroundColor: Theme.colors.primary, paddingVertical: 16 }} | |||||
> | |||||
<Image | |||||
resizeMode="cover" | |||||
style={{ | |||||
width: 180, | |||||
height: 39, | |||||
resizeMode: "contain", | |||||
alignSelf: "center" | |||||
}} | |||||
source={require("./logo.png")} | |||||
/> | |||||
</View> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
import React, { Component } from "react"; | |||||
import {View,Text} from "react-native"; | |||||
export default class HelpScreen extends Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = {}; | |||||
} | |||||
render() { | |||||
return ( | |||||
<View> | |||||
<Text>HelpScreen</Text> | |||||
</View> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
import React, { Component } from "react"; | |||||
import { TextInput } from "react-native-paper"; | |||||
import styles from "./styles"; | |||||
export default class Input extends Component { | |||||
render() { | |||||
return ( | |||||
<TextInput | |||||
autoCapitalize="none" | |||||
autoCorrect={false} | |||||
style={styles.input} | |||||
mode="outlined" | |||||
{...this.props} | |||||
/> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,67 @@ | |||||
import * as React from "react"; | |||||
import { ScrollView, Text } from "react-native"; | |||||
import TouchID from "react-native-touch-id"; | |||||
import { Button, Portal, Dialog, TextInput } from "react-native-paper"; | |||||
import { setGenericPassword } from "react-native-keychain"; | |||||
import styles from "./styles"; | |||||
export default class extends React.Component { | |||||
state = { | |||||
masterPassword: "" | |||||
}; | |||||
render() { | |||||
const { masterPassword } = this.state; | |||||
const { visible, close, onOk, onError } = this.props; | |||||
return ( | |||||
<Portal> | |||||
<Dialog onDismiss={close} visible={visible}> | |||||
<Dialog.Title>Enter your master password</Dialog.Title> | |||||
<Dialog.ScrollArea style={{ maxHeight: 170, paddingHorizontal: 0 }}> | |||||
<ScrollView style={{ padding: 10 }}> | |||||
<TextInput | |||||
style={styles.input} | |||||
mode="outlined" | |||||
label="Master Password" | |||||
value={masterPassword} | |||||
secureTextEntry | |||||
onChangeText={masterPassword => | |||||
this.setState({ masterPassword }) | |||||
} | |||||
/> | |||||
<Text> | |||||
Your master password will be encrypted locally on your device, | |||||
and accessible only with your fingerprint. | |||||
</Text> | |||||
</ScrollView> | |||||
</Dialog.ScrollArea> | |||||
<Dialog.Actions> | |||||
<Button primary onPress={close}> | |||||
Cancel | |||||
</Button> | |||||
<Button | |||||
primary | |||||
disabled={!masterPassword} | |||||
onPress={() => | |||||
TouchID.authenticate() | |||||
.then(success => { | |||||
return setGenericPassword( | |||||
"masterPassword", | |||||
masterPassword | |||||
).then(() => { | |||||
this.setState({ masterPassword: "" }, () => onOk()); | |||||
}); | |||||
}) | |||||
.catch(error => { | |||||
onError(error); | |||||
}) | |||||
} | |||||
> | |||||
Ok | |||||
</Button> | |||||
</Dialog.Actions> | |||||
</Dialog> | |||||
</Portal> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,31 @@ | |||||
import React, { Component } from "react"; | |||||
import { View } from "react-native"; | |||||
import { TextInput } from "react-native-paper"; | |||||
import TouchId from "./TouchId"; | |||||
import styles from "./styles"; | |||||
import Fingerprint from "./Fingerprint"; | |||||
export default class MasterPassword extends Component { | |||||
render() { | |||||
const { masterPassword, onChangeText, hideFingerprint } = this.props; | |||||
return ( | |||||
<View> | |||||
<TextInput | |||||
style={styles.input} | |||||
mode="outlined" | |||||
label="Master Password" | |||||
value={masterPassword} | |||||
secureTextEntry | |||||
onChangeText={masterPassword => onChangeText(masterPassword)} | |||||
/> | |||||
{masterPassword ? ( | |||||
<Fingerprint masterPassword={masterPassword} /> | |||||
) : hideFingerprint ? null : ( | |||||
<TouchId | |||||
onChangeText={masterPassword => onChangeText(masterPassword)} | |||||
/> | |||||
)} | |||||
</View> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,275 @@ | |||||
import React, { Component } from "react"; | |||||
import { | |||||
View, | |||||
TextInput as NativeTextInput, | |||||
KeyboardAvoidingView, | |||||
ScrollView, | |||||
NativeModules, | |||||
Clipboard, | |||||
Text | |||||
} from "react-native"; | |||||
import { Paragraph, Button, IconButton } from "react-native-paper"; | |||||
import Switch from "./Switch"; | |||||
import renderLessPassPassword from "lesspass-render-password"; | |||||
import Slider from "react-native-slider"; | |||||
import Theme from "./Theme"; | |||||
import Header from "./Header"; | |||||
import styles from "./styles"; | |||||
import MasterPassword from "./MasterPassword"; | |||||
import TextInput from "./Input"; | |||||
export default class PasswordGeneratorScreen extends Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = { | |||||
showOptions: false, | |||||
site: "", | |||||
login: "", | |||||
masterPassword: "", | |||||
lowercase: true, | |||||
uppercase: true, | |||||
digits: true, | |||||
symbols: true, | |||||
length: "16", | |||||
counter: "1", | |||||
generatedPassword: null, | |||||
seePassword: false, | |||||
copied: false | |||||
}; | |||||
} | |||||
generatePassword() { | |||||
const { | |||||
site, | |||||
login, | |||||
masterPassword, | |||||
lowercase, | |||||
uppercase, | |||||
digits, | |||||
symbols, | |||||
length, | |||||
counter | |||||
} = this.state; | |||||
NativeModules.LessPass.calcEntropy( | |||||
site, | |||||
login, | |||||
masterPassword, | |||||
counter | |||||
).then(entropy => { | |||||
var options = { | |||||
length, | |||||
lowercase, | |||||
uppercase, | |||||
digits, | |||||
symbols | |||||
}; | |||||
var password = renderLessPassPassword(entropy, options); | |||||
Clipboard.setString(password); | |||||
this.setState({ generatedPassword: password, copied: true }); | |||||
setTimeout(() => { | |||||
this.setState({ copied: false }); | |||||
}, 3000); | |||||
}); | |||||
} | |||||
render() { | |||||
const { | |||||
showOptions, | |||||
site, | |||||
login, | |||||
masterPassword, | |||||
lowercase, | |||||
uppercase, | |||||
digits, | |||||
symbols, | |||||
length, | |||||
counter, | |||||
seePassword, | |||||
copied, | |||||
generatedPassword | |||||
} = this.state; | |||||
return ( | |||||
<ScrollView style={{ flex: 1 }}> | |||||
<Header /> | |||||
<KeyboardAvoidingView | |||||
style={styles.container} | |||||
behavior="padding" | |||||
enabled | |||||
> | |||||
<TextInput | |||||
mode="outlined" | |||||
label="Site" | |||||
value={site} | |||||
onChangeText={site => this.setState({ site })} | |||||
/> | |||||
<TextInput | |||||
mode="outlined" | |||||
label="Login" | |||||
value={login} | |||||
onChangeText={login => this.setState({ login })} | |||||
/> | |||||
<MasterPassword | |||||
masterPassword={masterPassword} | |||||
onChangeText={masterPassword => this.setState({ masterPassword })} | |||||
/> | |||||
<View | |||||
style={{ | |||||
flexDirection: "row", | |||||
justifyContent: "space-between", | |||||
alignItems: "center", | |||||
paddingVertical: 10 | |||||
}} | |||||
> | |||||
{generatedPassword ? ( | |||||
<Button | |||||
icon={copied ? null : "remove-red-eye"} | |||||
mode="contained" | |||||
onPress={() => { | |||||
if (!copied) { | |||||
this.setState(prevState => ({ | |||||
seePassword: !prevState.seePassword | |||||
})); | |||||
} | |||||
}} | |||||
style={{ | |||||
height: 50, | |||||
alignItems: "center", | |||||
justifyContent: "center" | |||||
}} | |||||
> | |||||
<Text uppercase={false}> | |||||
{copied | |||||
? "Copied !" | |||||
: seePassword | |||||
? generatedPassword | |||||
: "****************"} | |||||
</Text> | |||||
</Button> | |||||
) : ( | |||||
<Button | |||||
mode="contained" | |||||
onPress={() => this.generatePassword()} | |||||
style={{ | |||||
height: 50, | |||||
alignItems: "center", | |||||
justifyContent: "center" | |||||
}} | |||||
> | |||||
Generate password | |||||
</Button> | |||||
)} | |||||
<IconButton | |||||
icon="settings" | |||||
color={ | |||||
showOptions ? Theme.colors.primary : Theme.colors.placeholder | |||||
} | |||||
onPress={() => | |||||
this.setState(prevState => ({ | |||||
showOptions: !prevState.showOptions | |||||
})) | |||||
} | |||||
/> | |||||
</View> | |||||
{showOptions ? ( | |||||
<React.Fragment> | |||||
<Switch | |||||
on={lowercase} | |||||
onValueChange={() => | |||||
this.setState(prevState => ({ | |||||
lowercase: !prevState.lowercase | |||||
})) | |||||
} | |||||
> | |||||
Lowercase (a-z) | |||||
</Switch> | |||||
<Switch | |||||
on={uppercase} | |||||
onValueChange={() => | |||||
this.setState(prevState => ({ | |||||
uppercase: !prevState.uppercase | |||||
})) | |||||
} | |||||
> | |||||
Uppercase (A-Z) | |||||
</Switch> | |||||
<Switch | |||||
on={digits} | |||||
onValueChange={() => | |||||
this.setState(prevState => ({ | |||||
digits: !prevState.digits | |||||
})) | |||||
} | |||||
> | |||||
Numbers (0-9) | |||||
</Switch> | |||||
<Switch | |||||
on={symbols} | |||||
onValueChange={() => | |||||
this.setState(prevState => ({ | |||||
symbols: !prevState.symbols | |||||
})) | |||||
} | |||||
> | |||||
Symbols (%!@) | |||||
</Switch> | |||||
<View> | |||||
<View style={styles.sliderTitleContainer}> | |||||
<Paragraph>Length</Paragraph> | |||||
<NativeTextInput | |||||
keyboardType="numeric" | |||||
value={length} | |||||
style={styles.sliderValue} | |||||
onChangeText={text => { | |||||
this.setState({ length: text.replace(/[^0-9]/g, "") }); | |||||
}} | |||||
/> | |||||
</View> | |||||
<Slider | |||||
minimumValue={5} | |||||
maximumValue={35} | |||||
step={1} | |||||
value={length ? parseInt(length, 10) : 1} | |||||
minimumTrackTintColor={Theme.colors.primary} | |||||
maximumTrackTintColor={Theme.colors.disabled} | |||||
trackStyle={styles.sliderTrack} | |||||
thumbTintColor={Theme.colors.primary} | |||||
onValueChange={length => | |||||
this.setState({ length: length.toString() }) | |||||
} | |||||
style={styles.slider} | |||||
/> | |||||
</View> | |||||
<View> | |||||
<View style={styles.sliderTitleContainer}> | |||||
<Paragraph>Counter</Paragraph> | |||||
<NativeTextInput | |||||
keyboardType="numeric" | |||||
value={counter} | |||||
style={styles.sliderValue} | |||||
onChangeText={text => { | |||||
this.setState({ counter: text.replace(/[^0-9]/g, "") }); | |||||
}} | |||||
/> | |||||
</View> | |||||
<Slider | |||||
minimumValue={1} | |||||
maximumValue={10} | |||||
step={1} | |||||
value={counter ? parseInt(counter, 10) : 1} | |||||
minimumTrackTintColor={Theme.colors.primary} | |||||
maximumTrackTintColor={Theme.colors.disabled} | |||||
trackStyle={styles.sliderTrack} | |||||
thumbTintColor={Theme.colors.primary} | |||||
onValueChange={counter => | |||||
this.setState({ counter: counter.toString() }) | |||||
} | |||||
style={styles.slider} | |||||
/> | |||||
</View> | |||||
</React.Fragment> | |||||
) : null} | |||||
</KeyboardAvoidingView> | |||||
</ScrollView> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,76 @@ | |||||
import React, { Component } from "react"; | |||||
import { connect } from "react-redux"; | |||||
import { ScrollView, View } from "react-native"; | |||||
import { Divider } from "react-native-paper"; | |||||
import Header from "./Header"; | |||||
import { setConfig } from "./Config/ConfigActions"; | |||||
import Switch from "./Switch"; | |||||
import KeepMasterPasswordLocallyModal from "./KeepMasterPasswordLocallyModal"; | |||||
export class SettingsScreen extends Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = { | |||||
seeMasterPasswordModal: false | |||||
}; | |||||
} | |||||
_showDialog = () => this.setState({ seeMasterPasswordModal: true }); | |||||
_hideDialog = () => this.setState({ seeMasterPasswordModal: false }); | |||||
render() { | |||||
const { config, setConfig } = this.props; | |||||
const { keepMasterPasswordLocally = false } = config; | |||||
const { seeMasterPasswordModal } = this.state; | |||||
return ( | |||||
<ScrollView style={{ flex: 1 }}> | |||||
<KeepMasterPasswordLocallyModal | |||||
onOk={() => { | |||||
setConfig({ keepMasterPasswordLocally: true }); | |||||
this._hideDialog(); | |||||
}} | |||||
onError={error => { | |||||
console.log("KeepMasterPasswordLocallyModal error", error); | |||||
this._hideDialog(); | |||||
}} | |||||
visible={seeMasterPasswordModal} | |||||
close={this._hideDialog} | |||||
/> | |||||
<Header /> | |||||
<Switch | |||||
on={keepMasterPasswordLocally} | |||||
onValueChange={() => { | |||||
if (keepMasterPasswordLocally) { | |||||
setConfig({ keepMasterPasswordLocally: false }); | |||||
} else { | |||||
this._showDialog(); | |||||
} | |||||
}} | |||||
> | |||||
Keep master password locally | |||||
</Switch> | |||||
<Divider /> | |||||
</ScrollView> | |||||
); | |||||
} | |||||
} | |||||
function mapStateToProps(state) { | |||||
return { | |||||
config: state.config | |||||
}; | |||||
} | |||||
function mapDispatchToProps(dispatch) { | |||||
return { | |||||
setConfig: config => { | |||||
dispatch(setConfig(config)); | |||||
} | |||||
}; | |||||
} | |||||
export default connect( | |||||
mapStateToProps, | |||||
mapDispatchToProps | |||||
)(SettingsScreen); |
@@ -0,0 +1,17 @@ | |||||
import React, { Component } from "react"; | |||||
import {View,Text} from "react-native"; | |||||
export default class SignInScreen extends Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = {}; | |||||
} | |||||
render() { | |||||
return ( | |||||
<View> | |||||
<Text>SignInScreen</Text> | |||||
</View> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
import React, { Component } from "react"; | |||||
import {View,Text} from "react-native"; | |||||
export default class SignUpScreen extends Component { | |||||
constructor(props) { | |||||
super(props); | |||||
this.state = {}; | |||||
} | |||||
render() { | |||||
return ( | |||||
<View> | |||||
<Text>SignUpScreen</Text> | |||||
</View> | |||||
); | |||||
} | |||||
} |
@@ -0,0 +1,25 @@ | |||||
import React, { Component } from "react"; | |||||
import { View, StyleSheet } from "react-native"; | |||||
import { Switch, Paragraph } from "react-native-paper"; | |||||
export default class LessPassSwitch extends Component { | |||||
render() { | |||||
const { on, onValueChange, children } = this.props; | |||||
return ( | |||||
<View style={styles.switch}> | |||||
<Paragraph>{children}</Paragraph> | |||||
<Switch value={on} onValueChange={() => onValueChange()} /> | |||||
</View> | |||||
); | |||||
} | |||||
} | |||||
const styles = StyleSheet.create({ | |||||
switch: { | |||||
flexDirection: "row", | |||||
alignItems: "center", | |||||
justifyContent: "space-between", | |||||
paddingVertical: 8, | |||||
paddingHorizontal: 10 | |||||
} | |||||
}); |
@@ -0,0 +1,22 @@ | |||||
import { DefaultTheme } from "react-native-paper"; | |||||
const Theme = { | |||||
...DefaultTheme, | |||||
colors: { | |||||
...DefaultTheme.colors, | |||||
//accent: "#0275d8", | |||||
accent: "#333333", | |||||
//primary: "#0275d8", | |||||
primary: "#333333", | |||||
//lightBlue: "#a8d6fe", | |||||
lightBlue: "#aaa", | |||||
red: "#f32c1e", | |||||
lightRed: "#fcc3bf", | |||||
white: "#F5F2F6", | |||||
brown: "#A28A7D", | |||||
orange: "#CF9E38", | |||||
purple: "#312430" | |||||
} | |||||
}; | |||||
export default Theme; |
@@ -0,0 +1,56 @@ | |||||
import React, { Component } from "react"; | |||||
import { connect } from "react-redux"; | |||||
import TouchID from "react-native-touch-id"; | |||||
import { View } from "react-native"; | |||||
import { IconButton } from "react-native-paper"; | |||||
import Theme from "./Theme"; | |||||
import { getGenericPassword } from "react-native-keychain"; | |||||
export class TouchId extends Component { | |||||
getMasterPasswordSavedLocally = () => { | |||||
const { onChangeText } = this.props; | |||||
TouchID.authenticate() | |||||
.then(() => { | |||||
return getGenericPassword().then(credentials => { | |||||
if (credentials) { | |||||
onChangeText(credentials.password); | |||||
} | |||||
}); | |||||
}) | |||||
.catch(error => | |||||
console.log("TouchId getMasterPasswordSavedLocally error", error) | |||||
); | |||||
}; | |||||
render() { | |||||
const { config } = this.props; | |||||
const { keepMasterPasswordLocally = false } = config; | |||||
if (!keepMasterPasswordLocally) return null; | |||||
return ( | |||||
<View | |||||
style={{ | |||||
position: "absolute", | |||||
right: 3, | |||||
top: 0, | |||||
bottom: 0, | |||||
justifyContent: "center", | |||||
alignItems: "center" | |||||
}} | |||||
> | |||||
<IconButton | |||||
icon="fingerprint" | |||||
color={Theme.colors.orange} | |||||
onPress={() => this.getMasterPasswordSavedLocally()} | |||||
/> | |||||
</View> | |||||
); | |||||
} | |||||
} | |||||
function mapStateToProps(state) { | |||||
return { | |||||
config: state.config | |||||
}; | |||||
} | |||||
export default connect(mapStateToProps)(TouchId); |
@@ -0,0 +1,24 @@ | |||||
import React from "react"; | |||||
import { createStore, applyMiddleware, combineReducers } from "redux"; | |||||
import { persistStore, persistReducer } from "redux-persist"; | |||||
import storage from "redux-persist/lib/storage"; | |||||
import { default as stateReconciler } from "redux-persist/lib/stateReconciler/autoMergeLevel2"; | |||||
import thunk from "redux-thunk"; | |||||
import ConfigReducer from "./Config/ConfigReducer"; | |||||
const rootReducer = combineReducers({ | |||||
config: ConfigReducer | |||||
}); | |||||
const persistConfig = { | |||||
key: "root", | |||||
storage, | |||||
stateReconciler, | |||||
whitelist: ["config"] | |||||
}; | |||||
const persistedReducer = persistReducer(persistConfig, rootReducer); | |||||
export const store = createStore(persistedReducer, applyMiddleware(thunk)); | |||||
export const persistor = persistStore(store); |
@@ -0,0 +1,45 @@ | |||||
import { StyleSheet } from "react-native"; | |||||
import Theme from "./Theme"; | |||||
const styles = StyleSheet.create({ | |||||
container: { | |||||
paddingHorizontal: 15, | |||||
paddingTop: 15, | |||||
marginBottom: 20, | |||||
flex: 1 | |||||
}, | |||||
input: { | |||||
marginBottom: 5 | |||||
}, | |||||
switch: { | |||||
flexDirection: "row", | |||||
alignItems: "center", | |||||
justifyContent: "space-between", | |||||
paddingVertical: 8, | |||||
paddingHorizontal: 10 | |||||
}, | |||||
sliderTrack: { | |||||
height: 2, | |||||
borderRadius: 1 | |||||
}, | |||||
sliderTitleContainer: { | |||||
flexDirection: "row", | |||||
justifyContent: "space-between", | |||||
alignItems: "center", | |||||
paddingLeft: 10, | |||||
paddingRight: 20, | |||||
paddingTop: 8 | |||||
}, | |||||
sliderValue: { | |||||
textAlign: "right", | |||||
color: Theme.colors.text, | |||||
paddingVertical: 1 | |||||
}, | |||||
slider: { | |||||
marginHorizontal: 10, | |||||
marginVertical: -8 | |||||
} | |||||
}); | |||||
export default styles; |