diff --git a/src/App.js b/src/App.js
index 79c7e8f9..e82ee775 100644
--- a/src/App.js
+++ b/src/App.js
@@ -19,6 +19,7 @@ import MainSideMenu from "@SideMenu/MainSideMenu"
import NoteSideMenu from "@SideMenu/NoteSideMenu"
import Settings from "@Screens/Settings/Settings"
import InputModal from "@Screens/InputModal"
+import ManagePrivileges from "@Screens/ManagePrivileges"
import Authenticate from "@Screens/Authentication/Authenticate"
import SideMenuManager from "@SideMenu/SideMenuManager"
@@ -76,12 +77,16 @@ const AuthenticateModalStack = createStackNavigator({
Screen1: Authenticate
})
+const ManagePrivilegesStack = createStackNavigator({
+ Screen1: ManagePrivileges
+})
+
const AppDrawer = createStackNavigator({
Home: AppDrawerStack,
Settings: SettingsStack,
InputModal: InputModalStack,
Authenticate: AuthenticateModalStack,
-
+ ManagePrivileges: ManagePrivilegesStack
}, {
mode: "modal",
headerMode: 'none',
diff --git a/src/lib/sfjs/privilegesManager.js b/src/lib/sfjs/privilegesManager.js
index 117cdf71..4cc329c7 100644
--- a/src/lib/sfjs/privilegesManager.js
+++ b/src/lib/sfjs/privilegesManager.js
@@ -59,6 +59,9 @@ export default class PrivilegesManager extends SFPrivilegesManager {
let sources = await this.sourcesForAction(action);
+ let sessionLengthOptions = await this.getSessionLengthOptions();
+ let selectedSessionLength = await this.getSelectedSessionLength();
+
navigation.navigate("Authenticate", {
leftButton: {
title: ApplicationState.isIOS ? "Cancel" : null,
@@ -66,7 +69,10 @@ export default class PrivilegesManager extends SFPrivilegesManager {
},
authenticationSources: sources,
hasCancelOption: true,
- onSuccess: () => {
+ sessionLengthOptions: sessionLengthOptions,
+ selectedSessionLength: selectedSessionLength,
+ onSuccess: (selectedSessionLength) => {
+ this.setSessionLength(selectedSessionLength);
customSuccess();
},
onCancel: () => {
diff --git a/src/screens/Authentication/Authenticate.js b/src/screens/Authentication/Authenticate.js
index d5730180..ecb0b930 100644
--- a/src/screens/Authentication/Authenticate.js
+++ b/src/screens/Authentication/Authenticate.js
@@ -35,6 +35,8 @@ export default class Authenticate extends Abstract {
source.initializeForInterface();
}
+ this._sessionLength = this.getProp("selectedSessionLength");
+
// if(__DEV__) {
// props.navigation.setParams({
// leftButton: {
@@ -131,7 +133,7 @@ export default class Authenticate extends Abstract {
componentWillBlur() {
super.componentWillBlur();
if(this.successful) {
- this.getProp("onSuccess")();
+ this.getProp("onSuccess")(this._sessionLength);
}
}
@@ -140,6 +142,15 @@ export default class Authenticate extends Abstract {
this.forceUpdate();
}
+ get sessionLengthOptions() {
+ return this.getProp("sessionLengthOptions");
+ }
+
+ setSessionLength(length) {
+ this._sessionLength = length;
+ this.forceUpdate();
+ }
+
_renderAuthenticationSoure = (source, index) => {
let isLast = index == this.sources.length - 1;
@@ -215,6 +226,22 @@ export default class Authenticate extends Abstract {
onPress={() => this.submitPressed()}
/>
+ {this.sessionLengthOptions && this.sessionLengthOptions.length > 0 &&
+
+
+ {this.sessionLengthOptions.map((option, index) =>
+ {return option.value == this._sessionLength}}
+ onPress={() => {this.setSessionLength(option.value)}}
+ />
+ )}
+
+ }
+
)
@@ -222,12 +249,11 @@ export default class Authenticate extends Abstract {
loadStyles() {
this.styles = {
- authSourceSection: {
- },
authSourceSectionNotLast: {
marginBottom: 10
},
- submitButtonCell: {
+ rememberForSection: {
+ marginTop: 10
}
}
}
diff --git a/src/screens/ManagePrivileges.js b/src/screens/ManagePrivileges.js
new file mode 100644
index 00000000..2d20e129
--- /dev/null
+++ b/src/screens/ManagePrivileges.js
@@ -0,0 +1,169 @@
+import React, { Component } from 'react';
+import { TextInput, View, Text, Platform, SafeAreaView, ScrollView } from 'react-native';
+import StyleKit from "@Style/StyleKit"
+import TableSection from "@Components/TableSection";
+import SectionedTableCell from "@Components/SectionedTableCell";
+import SectionedOptionsTableCell from "@Components/SectionedOptionsTableCell";
+import SectionedAccessoryTableCell from "@Components/SectionedAccessoryTableCell"
+import SectionHeader from "@Components/SectionHeader";
+import ButtonCell from "@Components/ButtonCell";
+import Abstract from "@Screens/Abstract"
+import LockedView from "@Containers/LockedView";
+import ApplicationState from "@Lib/ApplicationState"
+import Auth from "@SFJS/authManager"
+import KeysManager from "@Lib/keysManager"
+import PrivilegesManager from "@SFJS/privilegesManager"
+
+export default class ManagePrivileges extends Abstract {
+
+ static navigationOptions = ({ navigation, navigationOptions }) => {
+ let templateOptions = {
+ title: "Privileges",
+ leftButton: {
+ title: ApplicationState.isIOS ? "Done" : null,
+ iconName: ApplicationState.isIOS ? null : StyleKit.nameForIcon("checkmark"),
+ }
+ }
+ return Abstract.getDefaultNavigationOptions({navigation, navigationOptions, templateOptions});
+ };
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ availableActions: [],
+ availableCredentials: []
+ }
+
+ props.navigation.setParams({
+ leftButton: {
+ title: ApplicationState.isIOS ? "Done" : null,
+ iconName: ApplicationState.isIOS ? null : StyleKit.nameForIcon("checkmark"),
+ onPress: () => {
+ this.dismiss();
+ }
+ }
+ })
+
+ this.hasPasscode = KeysManager.get().hasOfflinePasscode();
+ this.hasAccount = !Auth.get().offline();
+
+ this.reloadPrivileges();
+ }
+
+ displayInfoForCredential(credential) {
+ return PrivilegesManager.get().displayInfoForCredential(credential).label;
+ }
+
+ displayInfoForAction(action) {
+ return PrivilegesManager.get().displayInfoForAction(action).label;
+ }
+
+ isCredentialRequiredForAction(action, credential) {
+ if(!this.privileges) {
+ return false;
+ }
+ return this.privileges.isCredentialRequiredForAction(action, credential);
+ }
+
+ clearSession = () => {
+ PrivilegesManager.get().clearSession().then(() => {
+ this.reloadPrivileges();
+ })
+ }
+
+ async reloadPrivileges() {
+ this.privileges = await PrivilegesManager.get().getPrivileges();
+ let availableCredentials = PrivilegesManager.get().getAvailableCredentials();
+ let availableActions = PrivilegesManager.get().getAvailableActions();
+
+ this.credentialDisplayInfo = {};
+ for(let cred of availableCredentials) {
+ this.credentialDisplayInfo[cred] = this.displayInfoForCredential(cred);
+ }
+
+ let sessionEndDate = await PrivilegesManager.get().getSessionExpirey();
+ this.setState({
+ availableActions: availableActions,
+ availableCredentials: availableCredentials,
+ sessionExpirey: sessionEndDate.toLocaleString(),
+ sessionExpired: new Date() >= sessionEndDate
+ });
+ }
+
+ valueChanged(action, credential) {
+ this.privileges.toggleCredentialForAction(action, credential);
+ PrivilegesManager.get().savePrivileges();
+ this.forceUpdate();
+ }
+
+ render() {
+ if(this.state.lockContent) {
+ return ();
+ }
+
+ return (
+
+
+
+ {this.state.sessionExpirey && !this.state.sessionExpired &&
+
+
+
+
+ You will not be asked to authenticate until {this.state.sessionExpirey}.
+
+
+
+
+ }
+
+ {this.state.availableActions.map((action, actionIndex) =>
+
+
+ {this.state.availableCredentials.map((credential, credIndex) =>
+ {return this.isCredentialRequiredForAction(action, credential)}}
+ onPress={() => {this.valueChanged(action, credential)}}
+ />
+ )}
+
+ )}
+
+
+
+
+
+ Privileges represent interface level authentication for accessing certain items and features. Privileges are meant to protect against unwanted access in the event of an unlocked application, but do not affect data encryption state.
+
+
+ Privileges sync across your other devices—however, note that if you require a "Local Passcode" privilege, and another device does not have a local passcode set up, the local passcode requirement will be ignored on that device.
+
+
+
+
+
+ );
+ }
+
+ loadStyles() {
+ this.styles = {
+ section: {
+ marginBottom: 8
+ },
+ cellText: {
+ lineHeight: 19,
+ fontSize: 16,
+ color: StyleKit.variables.stylekitForegroundColor,
+ },
+ aboutText: {
+ marginBottom: 8
+ }
+ }
+ }
+
+}
diff --git a/src/screens/Settings/Sections/OptionsSection.js b/src/screens/Settings/Sections/OptionsSection.js
index d0b2a691..f204cde3 100644
--- a/src/screens/Settings/Sections/OptionsSection.js
+++ b/src/screens/Settings/Sections/OptionsSection.js
@@ -95,13 +95,15 @@ class OptionsSection extends Abstract {
+
+
{signedIn &&
-
+
}
{this.props.navigation.navigate("ManagePrivileges")}}
/>