diff --git a/app/client/mobile/ios/Databag.xcodeproj/project.pbxproj b/app/client/mobile/ios/Databag.xcodeproj/project.pbxproj
index 52f06f34..e97fb077 100644
--- a/app/client/mobile/ios/Databag.xcodeproj/project.pbxproj
+++ b/app/client/mobile/ios/Databag.xcodeproj/project.pbxproj
@@ -605,7 +605,10 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
- OTHER_LDFLAGS = "$(inherited) ";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ " ",
+ );
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
@@ -677,7 +680,10 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
- OTHER_LDFLAGS = "$(inherited) ";
+ OTHER_LDFLAGS = (
+ "$(inherited)",
+ " ",
+ );
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
diff --git a/app/client/mobile/ios/Databag/PrivacyInfo.xcprivacy b/app/client/mobile/ios/Databag/PrivacyInfo.xcprivacy
index 5b037f0c..d634def7 100644
--- a/app/client/mobile/ios/Databag/PrivacyInfo.xcprivacy
+++ b/app/client/mobile/ios/Databag/PrivacyInfo.xcprivacy
@@ -9,8 +9,8 @@
NSPrivacyAccessedAPICategoryFileTimestamp
NSPrivacyAccessedAPITypeReasons
- C617.1
3B52.1
+ C617.1
diff --git a/app/client/mobile/ios/Podfile.lock b/app/client/mobile/ios/Podfile.lock
index 784ca797..6799d3fe 100644
--- a/app/client/mobile/ios/Podfile.lock
+++ b/app/client/mobile/ios/Podfile.lock
@@ -956,6 +956,8 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
+ - react-native-rsa-native (2.0.5):
+ - React
- react-native-safe-area-context (4.11.0):
- React-Core
- react-native-sqlite-storage (6.0.1):
@@ -1210,15 +1212,15 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- - RNImageCropPicker (0.39.0):
+ - RNImageCropPicker (0.41.2):
- React-Core
- React-RCTImage
- - RNImageCropPicker/QBImagePickerController (= 0.39.0)
- - TOCropViewController
- - RNImageCropPicker/QBImagePickerController (0.39.0):
+ - RNImageCropPicker/QBImagePickerController (= 0.41.2)
+ - TOCropViewController (~> 2.7.4)
+ - RNImageCropPicker/QBImagePickerController (0.41.2):
- React-Core
- React-RCTImage
- - TOCropViewController
+ - TOCropViewController (~> 2.7.4)
- RNReanimated (3.15.2):
- DoubleConversion
- glog
@@ -1306,6 +1308,8 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
+ - RNSecureRandom (1.0.1):
+ - React
- RNVectorIcons (10.2.0):
- DoubleConversion
- glog
@@ -1365,6 +1369,7 @@ DEPENDENCIES:
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- React-Mapbuffer (from `../node_modules/react-native/ReactCommon`)
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
+ - react-native-rsa-native (from `../node_modules/react-native-rsa-native`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-sqlite-storage (from `../node_modules/react-native-sqlite-storage`)
- React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
@@ -1394,6 +1399,7 @@ DEPENDENCIES:
- RNImageCropPicker (from `../node_modules/react-native-image-crop-picker`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
+ - RNSecureRandom (from `../node_modules/react-native-securerandom`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
@@ -1466,6 +1472,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon"
react-native-blur:
:path: "../node_modules/@react-native-community/blur"
+ react-native-rsa-native:
+ :path: "../node_modules/react-native-rsa-native"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-sqlite-storage:
@@ -1524,6 +1532,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-reanimated"
RNScreens:
:path: "../node_modules/react-native-screens"
+ RNSecureRandom:
+ :path: "../node_modules/react-native-securerandom"
RNVectorIcons:
:path: "../node_modules/react-native-vector-icons"
Yoga:
@@ -1561,6 +1571,7 @@ SPEC CHECKSUMS:
React-logger: fa92ba4d3a5d39ac450f59be2a3cec7b099f0304
React-Mapbuffer: 9f68550e7c6839d01411ac8896aea5c868eff63a
react-native-blur: 30d91a67da86a4d4d924b0c7c36f6e01479a246b
+ react-native-rsa-native: 12132eb627797529fdb1f0d22fd0f8f9678df64a
react-native-safe-area-context: 851c62c48dce80ccaa5637b6aa5991a1bc36eca9
react-native-sqlite-storage: f6d515e1c446d1e6d026aa5352908a25d4de3261
React-nativeconfig: fa5de9d8f4dbd5917358f8ad3ad1e08762f01dcb
@@ -1587,9 +1598,10 @@ SPEC CHECKSUMS:
React-utils: a06061b3887c702235d2dac92dacbd93e1ea079e
ReactCommon: f00e436b3925a7ae44dfa294b43ef360fbd8ccc4
RNGestureHandler: 67e78f16895947f7e57ab91e75e914d3e9ef7239
- RNImageCropPicker: 14fe1c29298fb4018f3186f455c475ab107da332
+ RNImageCropPicker: 771e2ca319d2cf92e04ebf334ece892ee9a6728f
RNReanimated: 70454122c0c5cf9b661d5a505c3408f29c85b180
RNScreens: aa943ad421c3ced3ef5a47ede02b0cbfc43a012e
+ RNSecureRandom: 07efbdf2cd99efe13497433668e54acd7df49fef
RNVectorIcons: 845eda5c7819bd29699cafd0fc98c9d4afe28c96
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
TOCropViewController: 80b8985ad794298fb69d3341de183f33d1853654
diff --git a/app/client/mobile/package.json b/app/client/mobile/package.json
index d1b09281..26882d32 100644
--- a/app/client/mobile/package.json
+++ b/app/client/mobile/package.json
@@ -15,9 +15,9 @@
"@react-navigation/drawer": "^6.7.2",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
- "databag-client-sdk": "^0.0.22",
"@types/crypto-js": "^4.2.2",
"crypto-js": "^4.2.0",
+ "databag-client-sdk": "^0.0.22",
"jsencrypt": "^3.3.2",
"react": "18.2.0",
"react-dom": "^18.3.1",
@@ -30,6 +30,7 @@
"react-native-rsa-native": "^2.0.5",
"react-native-safe-area-context": "^4.10.8",
"react-native-screens": "^3.34.0",
+ "react-native-securerandom": "^1.0.1",
"react-native-sqlite-storage": "^6.0.1",
"react-native-vector-icons": "^10.1.0",
"react-router-dom": "^6.26.0",
diff --git a/app/client/mobile/src/NativeCrypto.ts b/app/client/mobile/src/NativeCrypto.ts
index f6f4979a..974374ff 100644
--- a/app/client/mobile/src/NativeCrypto.ts
+++ b/app/client/mobile/src/NativeCrypto.ts
@@ -2,13 +2,14 @@ import { Crypto } from 'databag-client-sdk';
import CryptoJS from 'crypto-js';
import { JSEncrypt } from 'jsencrypt'
import { RSA } from 'react-native-rsa-native';
+import { generateSecureRandom } from 'react-native-securerandom';
export class NativeCrypto implements Crypto {
// generate salt for pbk function
public async pbkdfSalt(): Promise<{ saltHex: string }> {
- const salt = CryptoJS.lib.WordArray.random(128 / 8);
- const saltHex = salt.toString();
+ const salt = await generateSecureRandom(16);
+ const saltHex = this.uint8ToHexStr(salt);
return { saltHex };
}
@@ -22,15 +23,15 @@ export class NativeCrypto implements Crypto {
// generate random aes key
public async aesKey(): Promise<{ aesKeyHex: string }> {
- const aes = CryptoJS.lib.WordArray.random(256 / 8);
- const aesKeyHex = aes.toString();
+ const aes = await generateSecureRandom(32);
+ const aesHex = this.uint8ToHexStr(aes);
return { aesKeyHex };
}
// generate iv to use to aes function
public async aesIv(): Promise<{ ivHex: string }> {
- const iv = CryptoJS.lib.WordArray.random(128 / 8);
- const ivHex = iv.toString();
+ const iv = await generateSecureRandom(16);
+ const ivHex = this.uint8ToHexStr(iv);
return { ivHex };
}
@@ -102,7 +103,13 @@ export class NativeCrypto implements Crypto {
}
}
return encoded
-};
-
+ };
+ private uint8ToHexStr(bin: Uint8Array) {
+ let hex = '';
+ bin.forEach(val => {
+ hex += val.toString(16);
+ });
+ return hex;
+ }
}
diff --git a/app/client/mobile/src/settings/Settings.styled.ts b/app/client/mobile/src/settings/Settings.styled.ts
index 10c9923e..295b7f6d 100644
--- a/app/client/mobile/src/settings/Settings.styled.ts
+++ b/app/client/mobile/src/settings/Settings.styled.ts
@@ -60,8 +60,9 @@ export const styles = StyleSheet.create({
display: 'flex',
flexDirection: 'row',
gap: 16,
- paddingTop: 16,
justifyContent: 'flex-end',
+ alignItems: 'center',
+ marginTop: 16,
},
modalDescription: {
paddingTop: 16,
@@ -192,6 +193,13 @@ export const styles = StyleSheet.create({
height: '100%',
backgroundColor: 'transparent',
},
+ modalOption: {
+ backgroundColor: 'transparent',
+ flexGrow: 1,
+ },
+ deleteButton: {
+ backgroundColor: Colors.danger,
+ },
label: {
fontSize: 16,
},
diff --git a/app/client/mobile/src/settings/Settings.tsx b/app/client/mobile/src/settings/Settings.tsx
index c4c1901b..a922fd29 100644
--- a/app/client/mobile/src/settings/Settings.tsx
+++ b/app/client/mobile/src/settings/Settings.tsx
@@ -6,6 +6,7 @@ import {useSettings} from './useSettings.hook';
import ImagePicker from 'react-native-image-crop-picker';
import {BlurView} from '@react-native-community/blur';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';
+import { Colors } from '../constants/Colors';
export function Settings({ showLogout }: { showLogout: boolean }) {
const { state, actions } = useSettings();
@@ -20,6 +21,7 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
const [savingRegistry, setSavingRegistry] = useState(false);
const [savingNotifications, setSavingNotifications] = useState(false);
const [showPassword, setShowPassword] = useState(false);
+ const [showConfirm, setShowConfirm] = useState(false);
const selectImage = async () => {
try {
@@ -45,9 +47,7 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
actions.setSealPassword('');
actions.setSealConfirm('');
actions.setSealDelete('');
- sealOpen();
- setSavingSeal(true);
- setSavingSeal(false);
+ setSealing(true);
}
}
@@ -100,7 +100,6 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
if (!savingSeal) {
setSavingSeal(true);
try {
- await new Promise(r => setTimeout(r, 100));
await actions.setSeal();
setSealing(false);
} catch (err) {
@@ -260,7 +259,7 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
- setSealing(true)}>
+
{state.strings.manageTopics}
@@ -435,51 +434,38 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
reducedTransparencyFallbackColor="dark"
/>
-
+
{ state.strings.manageTopics }
setSealing(false)} />
{ !sealDelete && !sealReset && state.config.sealSet && state.config.sealUnlocked && (
<>
- seal is unlocked
+ { state.strings.sealUnlocked }
{ !sealConfig && (
- hide options
+
+ {setSealConfig(true)}} />
+
+
+
)}
{ sealConfig && (
- show options
+
+
+
+ {setSealConfig(false)}} />
+
)}
>
)}
{ !sealDelete && sealReset && state.config.sealSet && state.config.sealUnlocked && (
<>
- update seal password
- >
- )}
- { !sealDelete && state.config.sealSet && !state.config.sealUnlocked && (
- <>
- seal is locked
- { !sealConfig && (
- hide options
- )}
- { sealConfig && (
- show options
- )}
- >
- )}
- { sealDelete && state.config.sealSet && (
- <>
- deleting seal
- >
- )}
- { !state.config.sealSet && (
- <>
- { state.strings.sealUnset }
+ { state.strings.changePassword }
}
@@ -496,11 +482,133 @@ export function Settings({ showLogout }: { showLogout: boolean }) {
/>
)
}
- onChangeText={value => actions.setPassword(value)}
+ onChangeText={value => actions.setSealPassword(value)}
+ />
+ }
+ right={
+ showPassword ? (
+ setShowConfirm(false)}
+ />
+ ) : (
+ setShowConfirm(true)}
+ />
+ )
+ }
+ onChangeText={value => actions.setSealConfirm(value)}
/>
-
+
+
+ >
+ )}
+ { !sealDelete && state.config.sealSet && !state.config.sealUnlocked && (
+ <>
+ { state.strings.sealLocked }
+ }
+ right={
+ showPassword ? (
+ setShowPassword(false)}
+ />
+ ) : (
+ setShowPassword(true)}
+ />
+ )
+ }
+ onChangeText={value => actions.setSealPassword(value)}
+ />
+ { !sealConfig && (
+
+ {setSealConfig(true)}} />
+
+
+
+ )}
+ { sealConfig && (
+
+
+ {setSealConfig(false)}} />
+
+ )}
+ >
+ )}
+ { sealDelete && state.config.sealSet && (
+ <>
+ { state.strings.sealDelete }
+ }
+ onChangeText={value => actions.setSealDelete(value)}
+ />
+
+
+
+ >
+ )}
+ { !state.config.sealSet && (
+ <>
+ { state.strings.sealUnset }
+ { state.strings.delayMessage }
+ }
+ right={
+ showPassword ? (
+ setShowPassword(false)}
+ />
+ ) : (
+ setShowPassword(true)}
+ />
+ )
+ }
+ onChangeText={value => actions.setSealPassword(value)}
+ />
+
+
+
>
)}
diff --git a/app/client/mobile/yarn.lock b/app/client/mobile/yarn.lock
index 76a7350b..bc87a0be 100644
--- a/app/client/mobile/yarn.lock
+++ b/app/client/mobile/yarn.lock
@@ -2791,6 +2791,13 @@ __metadata:
languageName: node
linkType: hard
+"@types/crypto-js@npm:^4.2.2":
+ version: 4.2.2
+ resolution: "@types/crypto-js@npm:4.2.2"
+ checksum: 727daa0d2db35f0abefbab865c23213b6ee6a270e27e177939bbe4b70d1e84c2202d9fac4ea84859c4b4d49a4ee50f948f601327a39b69ec013288018ba07ca5
+ languageName: node
+ linkType: hard
+
"@types/graceful-fs@npm:^4.1.3":
version: 4.1.9
resolution: "@types/graceful-fs@npm:4.1.9"
@@ -3141,23 +3148,28 @@ __metadata:
"@react-navigation/drawer": ^6.7.2
"@react-navigation/native": ^6.1.18
"@react-navigation/native-stack": ^6.11.0
+ "@types/crypto-js": ^4.2.2
"@types/react": ^18.2.6
"@types/react-test-renderer": ^18.0.0
babel-jest: ^29.6.3
+ crypto-js: ^4.2.0
databag-client-sdk: ^0.0.22
eslint: ^8.19.0
jest: ^29.6.3
+ jsencrypt: ^3.3.2
prettier: 2.8.8
react: 18.2.0
react-dom: ^18.3.1
react-native: 0.74.3
react-native-gesture-handler: ^2.19.0
- react-native-image-crop-picker: ^0.39.0
+ react-native-image-crop-picker: ^0.41.2
react-native-keyboard-aware-scroll-view: ^0.9.5
react-native-paper: ^5.12.5
react-native-reanimated: ^3.15.2
+ react-native-rsa-native: ^2.0.5
react-native-safe-area-context: ^4.10.8
react-native-screens: ^3.34.0
+ react-native-securerandom: ^1.0.1
react-native-sqlite-storage: ^6.0.1
react-native-vector-icons: ^10.1.0
react-router-dom: ^6.26.0
@@ -3632,7 +3644,7 @@ __metadata:
languageName: node
linkType: hard
-"base64-js@npm:^1.3.1, base64-js@npm:^1.5.1":
+"base64-js@npm:*, base64-js@npm:^1.3.1, base64-js@npm:^1.5.1":
version: 1.5.1
resolution: "base64-js@npm:1.5.1"
checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005
@@ -4172,6 +4184,13 @@ __metadata:
languageName: node
linkType: hard
+"crypto-js@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "crypto-js@npm:4.2.0"
+ checksum: f051666dbc077c8324777f44fbd3aaea2986f198fe85092535130d17026c7c2ccf2d23ee5b29b36f7a4a07312db2fae23c9094b644cc35f7858b1b4fcaf27774
+ languageName: node
+ linkType: hard
+
"csstype@npm:^3.0.2":
version: 3.1.3
resolution: "csstype@npm:3.1.3"
@@ -6735,6 +6754,13 @@ __metadata:
languageName: node
linkType: hard
+"jsencrypt@npm:^3.3.2":
+ version: 3.3.2
+ resolution: "jsencrypt@npm:3.3.2"
+ checksum: b78e896dc1c3d6bb2e9ce2437e679c1abd4dda098c29f3d1d00024543b03f7e962d0be08b5c1024a94e400c32eb40c720f8293cb5fe6b4b3859cf6b31eabf6a4
+ languageName: node
+ linkType: hard
+
"jsesc@npm:^2.5.1":
version: 2.5.2
resolution: "jsesc@npm:2.5.2"
@@ -8247,12 +8273,12 @@ __metadata:
languageName: node
linkType: hard
-"react-native-image-crop-picker@npm:^0.39.0":
- version: 0.39.0
- resolution: "react-native-image-crop-picker@npm:0.39.0"
+"react-native-image-crop-picker@npm:^0.41.2":
+ version: 0.41.2
+ resolution: "react-native-image-crop-picker@npm:0.41.2"
peerDependencies:
react-native: ">=0.40.0"
- checksum: cb524d99e1b85ea798aa397e7216851f8d777cf469664556c319abe0f38ccb4f62f6850da327d9aebc034a8ea7dbf7d5f4dadbefc2072efadd2d2f961ea00026
+ checksum: c1333b3b761e948bd0bc856773f68dcc859c7ce39dda3e14d2c32c17d55927735bfc5cbbb7ac5e8bac21feda87c93399f2a596aca7d5b0611cc1e8203d97ad2e
languageName: node
linkType: hard
@@ -8316,6 +8342,13 @@ __metadata:
languageName: node
linkType: hard
+"react-native-rsa-native@npm:^2.0.5":
+ version: 2.0.5
+ resolution: "react-native-rsa-native@npm:2.0.5"
+ checksum: 7a720ab3ef1898a4f365decc2913139dbfb090901806bf4c20932c1511bde32cd02586725142e9c273bb575c907a5ee87a84edc8c0b01cce252ad80436370740
+ languageName: node
+ linkType: hard
+
"react-native-safe-area-context@npm:^4.10.8":
version: 4.11.0
resolution: "react-native-safe-area-context@npm:4.11.0"
@@ -8339,6 +8372,17 @@ __metadata:
languageName: node
linkType: hard
+"react-native-securerandom@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "react-native-securerandom@npm:1.0.1"
+ dependencies:
+ base64-js: "*"
+ peerDependencies:
+ react-native: "*"
+ checksum: ccf42b8a8a83809fd77097aa141efd2e9533e94c094e8dcb0054659707e276cbb6466d3408d0e0594f0bd67af4fbc5881f2ad2d93513b5b2aae25dfd2888274b
+ languageName: node
+ linkType: hard
+
"react-native-sqlite-storage@npm:^6.0.1":
version: 6.0.1
resolution: "react-native-sqlite-storage@npm:6.0.1"