Skip to content

Commit a18fae3

Browse files
committed
Merge remote-tracking branch 'origin/develop'
2 parents 0922106 + 560baf2 commit a18fae3

File tree

106 files changed

+2393
-1799
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

106 files changed

+2393
-1799
lines changed

.eslintrc.js

+7-11
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ module.exports = {
4040
'prefer-const': ['error'],
4141
semi: ['error', 'never'],
4242
'use-isnan': ['error'],
43-
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
43+
'@typescript-eslint/array-type': ['error', 'array-simple'],
4444
'@typescript-eslint/ban-types': [
4545
'error',
4646
{
@@ -54,27 +54,23 @@ module.exports = {
5454
],
5555
'react/jsx-uses-vars': ['warn'],
5656
// PascalCase for classes
57-
'@typescript-eslint/class-name-casing': ['off'],
57+
'@typescript-eslint/class-name-casing': ['error'],
5858
// don't prefix interface names with 'I'
59-
'@typescript-eslint/interface-name-prefix': ['off'],
59+
'@typescript-eslint/interface-name-prefix': ['error', 'never'],
6060
// don't conflict <Types> and JSX
61-
'@typescript-eslint/no-angle-bracket-type-assertion': ['off'],
61+
'@typescript-eslint/no-angle-bracket-type-assertion': ['error'],
6262
// lose out on typing benefits with any
6363
'@typescript-eslint/no-explicit-any': ['error'],
6464
'@typescript-eslint/no-empty-interface': ['off'],
6565
'@typescript-eslint/no-inferrable-types': ['error'],
6666
// namespaces and modules are outdated, use ES6 style
6767
'@typescript-eslint/no-namespace': ['error'],
6868
// use ES6-style imports instead
69-
'@typescript-eslint/no-triple-slash-reference': ['off'],
69+
'@typescript-eslint/no-triple-slash-reference': ['error'],
7070
'@typescript-eslint/no-var-requires': ['off'],
7171
'@typescript-eslint/no-use-before-define': ['off'],
7272
'@typescript-eslint/explicit-function-return-type': ['off'],
73-
'import/no-duplicates': ['off'],
73+
'import/no-duplicates': ['error'],
7474
},
75-
ignorePatterns: [
76-
'package.json',
77-
'jest.config.js',
78-
'app.json',
79-
],
75+
ignorePatterns: ['package.json', 'jest.config.js', 'app.json'],
8076
}

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
# Sentry auth
22
sentry.properties
33
sentry-auth/
4+
5+
# Secrets
46
android-secrets/
57
ios-certificates
68
appcenter-secrets
79
report.xml
810
.bundle/
911
vendor/
1012
poeditor-key/
13+
key.json
1114

1215
# App connect keys
1316
app-store-connect-auth

README.md

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
Jolocom SmartWallet - An application to manage your digital identity.
2+
3+
Interested in our vision? Take a look at our [whitepaper](https://jolocom.io/wp-content/uploads/2019/12/Jolocom-Whitepaper-v2.1-A-Decentralized-Open-Source-Solution-for-Digital-Identity-and-Access-Management.pdf).
4+
5+
[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/jolocom/SmartWallet)
6+
7+
## Prerequisites
8+
9+
- Set-up requires [Node.js](https://nodejs.org/en/download/) to be installed on your computer.
10+
- The Jolocom SmartWallet requires `Node.js v12+` to build the project. You can either manually install Node version above 12, or you can delegate it to `Volta` (follow [this link](https://docs.volta.sh/guide/getting-started) to install `Volta`). Node `12.4.1` is pinned to the project
11+
- We use [Yarn](https://yarnpkg.com) as our package manager.
12+
- We use [CocoaPods](https://cocoapods.org/) for `iOS` dependency management.
13+
14+
## Installation
15+
16+
1. Clone the repository to a directory of your choice.
17+
2. `cd` into the cloned repo and run `yarn` from your terminal to install the required depencencies .
18+
19+
### Running a debug version for development
20+
21+
#### Android
22+
23+
3. Please set up an Android development environment and install the required SDKs.
24+
- The [Getting Started](https://facebook.github.io/react-native/docs/getting-started) guide for React Native may come in handy.
25+
- Look for the instructions under React Native CLI Quickstart.
26+
4. Connect an Android device and enable USB debugging **OR** start an Android AVD emulator
27+
5. Run `yarn android` to install the application and run it.
28+
- NOTE: this will start a metro bundler server automatically, with stdout/stderr discarded. You can close this and run `yarn start` to manually start the bundler and receive more detailed output.
29+
30+
### iOS
31+
32+
3. Please set up an appropriate Xcode development environment.
33+
- The [Getting Started](https://facebook.github.io/react-native/docs/getting-started) guide for React Native may come in handy.
34+
- Look for the instructions under React Native CLI Quickstart.
35+
4. `cd` into the `ios` folder, and install the native dependencies using the `pod install` command.
36+
5. Run `yarn ios` to install and run the application in an emulator.
37+
- This will default to an iPhone X emulator.
38+
- The device can be specified by adding `--simulator` and the device name.
39+
- e.g. `yarn ios --simulator "iPhone SE"`
40+
- `NOTE`: this will start a metro bundler server automatically, with stdout/stderr discarded. You can close this and run `yarn start` to manually start the bundler and receive more detailed output.
41+
- `NOTE`: A debug build can also be built through Xcode.
42+
43+
Running a build on a physical device requires the appropriate code signing certificates.
44+
45+
## Testing
46+
We use Jest + [React Native Testing Library](https://testing-library.com/docs/react-native-testing-library/intro/) for unit testing.
47+
48+
To run unit tests with watch and testing coverage:
49+
```bash
50+
yarn test --watch --coverage
51+
```
52+
## Code Style and Formatting
53+
54+
- We use [ESLint](https://eslint.org/) and [Prettier](https://prettier.io/) to keep a consistent style across the codebase.
55+
- There are plugins available for a range of IDEs and text editors; automatic formatting on save is also supported in some editors.
56+
- Check the `yarn lint:fix` and `yarn prettier:format` scripts.
57+
58+
Copyright (C) 2014-2019 JOLOCOM GmbH
59+
60+

__tests__/suits/Form/CredentialForm.test.tsx

+14-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useRoute } from '@react-navigation/native'
44
import { renderWithSafeArea } from '../../utils/renderWithSafeArea'
55
import { AttributeTypes, ClaimKeys } from '~/types/credentials'
66
import { mockSelectorReturn } from '../../mocks/libs/react-redux'
7-
import { fireEvent, waitFor } from '@testing-library/react-native'
7+
import { act, fireEvent, waitFor } from '@testing-library/react-native'
88
import { editAttr, updateAttrs } from '~/modules/attributes/actions'
99
import { getMockedDispatch } from '../../mocks/libs/react-redux'
1010
import { mockedAgent } from '../../mocks/agent'
@@ -51,6 +51,19 @@ jest.mock('../../../src/hooks/sdk', () => ({
5151

5252
const renderCredentialForm = () => {
5353
const queries = renderWithSafeArea(<CredentialForm />)
54+
const headerContainer = queries.getByTestId('collapsable-header-container')
55+
56+
// NOTE: The @Collapsible renders the scroll content only if the header has registered
57+
// the layout
58+
act(() => {
59+
fireEvent(headerContainer, 'onLayout', {
60+
nativeEvent: {
61+
layout: {
62+
height: 100,
63+
},
64+
},
65+
})
66+
})
5467

5568
const emailInput = queries.getByTestId('credential-form-input')
5669
expect(emailInput).toBeDefined()

__tests__/suits/History/RecordAssembler.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ const genericOfferArgs = {
5353
...buildSummary({
5454
offerSummary: [{ type: 'test-type', credential: { name: 'test-name' } }],
5555
issued: [{ type: 'test-type', name: 'test-name' }],
56+
credentialsValidity: [true, true],
5657
}),
5758
flowType: FlowType.CredentialOffer,
5859
messageTypes: [

__tests__/suits/LocalDeviceAuth/ChangePin.test.tsx

+18-21
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { waitFor } from '@testing-library/react-native'
22
import React from 'react'
3-
import * as keychain from 'react-native-keychain'
3+
import { SecureStorage } from 'react-native-jolocom'
44
import ChangePin from '~/screens/LoggedIn/Settings/ChangePin'
55
import { strings } from '~/translations'
6-
import { PIN_SERVICE, PIN_USERNAME } from '~/utils/keychainConsts'
76
import { renderWithSafeArea } from '../../utils/renderWithSafeArea'
87
import { inputPasscode } from '../../utils/inputPasscode'
8+
import { SecureStorageKeys } from '~/hooks/secureStorage'
99

1010
const mockNavigation = jest.fn()
1111
const mockNavigationBack = jest.fn()
@@ -19,12 +19,12 @@ jest.mock('@react-navigation/native', () => ({
1919
}),
2020
}))
2121

22-
jest.mock('react-native-keychain', () => ({
23-
STORAGE_TYPE: {
24-
AES: 'aes',
22+
jest.mock('react-native-jolocom', () => ({
23+
SecureStorage: {
24+
storeValue: jest.fn(),
25+
getValue: jest.fn().mockResolvedValue(null),
26+
removeValue: jest.fn(),
2527
},
26-
setGenericPassword: jest.fn(),
27-
getGenericPassword: jest.fn().mockResolvedValue({ password: '5555' }),
2828
}))
2929

3030
jest.mock('../../../src/hooks/sdk', () => ({
@@ -47,14 +47,11 @@ jest.mock('../../../src/hooks/loader', () => ({
4747
useLoader: jest
4848
.fn()
4949
.mockImplementation(
50-
() => async (
51-
cb: () => Promise<void>,
52-
_: object,
53-
onSuccess: () => void,
54-
) => {
55-
await cb()
56-
onSuccess()
57-
},
50+
() =>
51+
async (cb: () => Promise<void>, _: object, onSuccess: () => void) => {
52+
await cb()
53+
onSuccess()
54+
},
5855
),
5956
}))
6057

@@ -65,7 +62,7 @@ jest.mock('../../../src/hooks/navigation', () => ({
6562

6663
xdescribe('Change passcode', () => {
6764
it('should successfully change the passcode', async () => {
68-
const setGenericPasswordSpy = jest.spyOn(keychain, 'setGenericPassword')
65+
const setEncryptedPasswordSpy = jest.spyOn(SecureStorage, 'storeValue')
6966

7067
const { getByText, getByTestId } = await waitFor(() =>
7168
renderWithSafeArea(<ChangePin />),
@@ -88,11 +85,11 @@ xdescribe('Change passcode', () => {
8885
inputPasscode(getByTestId, [3, 3, 3, 3])
8986

9087
await waitFor(() => {
91-
expect(setGenericPasswordSpy).toHaveBeenCalledTimes(1)
92-
expect(setGenericPasswordSpy).toHaveBeenCalledWith(PIN_USERNAME, '3333', {
93-
service: PIN_SERVICE,
94-
storage: keychain.STORAGE_TYPE.AES,
95-
})
88+
expect(setEncryptedPasswordSpy).toHaveBeenCalledTimes(1)
89+
expect(setEncryptedPasswordSpy).toHaveBeenCalledWith(
90+
SecureStorageKeys.passcode,
91+
'3333',
92+
)
9693
})
9794
})
9895

__tests__/suits/LocalDeviceAuth/Lock.test.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ describe('Without biometry', () => {
7171
isBiometrySelected: false,
7272
})
7373
})
74-
test('Lock screen renders all necessary UI details', () => {
74+
xtest('Lock screen renders all necessary UI details', () => {
7575
const { getByText, getByTestId } = renderWithSafeArea(<Lock />)
7676

7777
mockGetBiometry.mockResolvedValue(undefined)
@@ -81,7 +81,7 @@ describe('Without biometry', () => {
8181
expect(getByTestId('passcode-keyboard')).toBeDefined()
8282
})
8383

84-
test("The app is locked if pins don't match", async () => {
84+
xtest("The app is locked if pins don't match", async () => {
8585
const { getByText, getByTestId } = renderWithSafeArea(<Lock />)
8686

8787
inputPasscode(getByTestId, [3, 3, 3, 3])
@@ -91,7 +91,7 @@ describe('Without biometry', () => {
9191
})
9292
})
9393

94-
test('The app is unlocked', () => {
94+
xtest('The app is unlocked', () => {
9595
const useDispatchSpy = jest.spyOn(redux, 'useDispatch')
9696
const mockDispatchFn = jest.fn()
9797
useDispatchSpy.mockReturnValue(mockDispatchFn)
@@ -119,7 +119,7 @@ describe('With biometry', () => {
119119
})
120120
})
121121

122-
test('unlocks the app', async () => {
122+
xtest('unlocks the app', async () => {
123123
mockBiometryAuthenticate.mockResolvedValue({
124124
success: true,
125125
})
@@ -140,7 +140,7 @@ describe('With biometry', () => {
140140
})
141141
})
142142

143-
test('do not unlock the app', async () => {
143+
xtest('do not unlock the app', async () => {
144144
mockBiometryAuthenticate.mockResolvedValue({
145145
success: false,
146146
})

__tests__/suits/LocalDeviceAuth/RegisterPin.test.tsx

+26-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React from 'react'
22
import { waitFor } from '@testing-library/react-native'
3-
import { setGenericPassword, STORAGE_TYPE } from 'react-native-keychain'
3+
import { SecureStorage } from 'react-native-jolocom'
44

55
import RegisterPin from '~/screens/Modals/DeviceAuthentication/RegisterPin'
66
import { renderWithSafeArea } from '../../utils/renderWithSafeArea'
7-
import { PIN_USERNAME, PIN_SERVICE } from '~/utils/keychainConsts'
87
import { inputPasscode } from '../../utils/inputPasscode'
8+
import { SecureStorageKeys } from '~/hooks/secureStorage'
99

1010
const mockNavigation = jest.fn()
1111
const mockNavigationBack = jest.fn()
@@ -27,16 +27,30 @@ jest.mock('react-redux', () => ({
2727
useDispatch: () => mockedDispatch,
2828
}))
2929

30-
jest.mock('react-native-keychain', () => ({
31-
STORAGE_TYPE: {
32-
AES: 'aes',
30+
jest.mock('react-native-jolocom', () => ({
31+
SecureStorage: {
32+
storeValue: jest.fn(),
33+
getValue: jest.fn().mockResolvedValue(null),
34+
removeValue: jest.fn(),
3335
},
34-
setGenericPassword: jest.fn(() => Promise.resolve(true)),
35-
resetGenericPassword: jest.fn(() => Promise.resolve(true)),
36+
}))
37+
38+
jest.mock('@react-navigation/native', () => ({
39+
useIsFocused: jest.fn().mockReturnValue(true),
40+
useNavigation: () => ({
41+
navigate: jest.fn(),
42+
}),
43+
createNavigatorFactory: jest.fn(),
44+
}))
45+
46+
jest.mock('../../../src/hooks/settings', () => () => ({
47+
get: jest.fn(),
48+
set: jest.fn(),
3649
}))
3750

3851
describe('Register Passcode', () => {
3952
it('User is able to set up pin', async () => {
53+
const setEncryptedPasswordSpy = jest.spyOn(SecureStorage, 'storeValue')
4054
const { getByText, getByTestId, queryByText } = renderWithSafeArea(
4155
<RegisterPin />,
4256
)
@@ -59,10 +73,10 @@ describe('Register Passcode', () => {
5973

6074
inputPasscode(getByTestId, [1, 1, 1, 1])
6175

62-
expect(setGenericPassword).toHaveBeenCalledTimes(1)
63-
expect(setGenericPassword).toHaveBeenCalledWith(PIN_USERNAME, '1111', {
64-
service: PIN_SERVICE,
65-
storage: STORAGE_TYPE.AES,
66-
})
76+
expect(setEncryptedPasswordSpy).toHaveBeenCalledTimes(1)
77+
expect(setEncryptedPasswordSpy).toHaveBeenCalledWith(
78+
SecureStorageKeys.passcode,
79+
'1111',
80+
)
6781
})
6882
})

__tests__/suits/LoggedOut/Recovery.test.tsx

+11
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ jest.mock('../../../src/hooks/sdk.ts', () => ({
5757
}),
5858
}))
5959

60+
jest.mock('../../../src/hooks/settings', () => () => ({
61+
get: jest.fn(),
62+
set: jest.fn(),
63+
}))
64+
65+
jest.mock('../../../src/hooks/toasts', () => ({
66+
useToasts: () => ({
67+
scheduleErrorWarning: jest.fn(),
68+
}),
69+
}))
70+
6071
describe('User on a Recovery screen', () => {
6172
test('sees screen with initial state', () => {
6273
const useDispatchSpy = jest.spyOn(redux, 'useDispatch')

__tests__/suits/components/Passcode.test.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,17 @@ jest.mock('@react-navigation/native', () => ({
1616
...jest.requireActual('@react-navigation/native'),
1717
// eslint-disable-next-line
1818
useFocusEffect: jest.fn().mockImplementation(() => {}),
19+
useIsFocused: jest.fn(() => true),
1920
useNavigation: () => ({
2021
navigate: mockNavigate,
2122
}),
2223
}))
2324

25+
jest.mock('../../../src/hooks/settings', () => () => ({
26+
get: jest.fn(),
27+
set: jest.fn(),
28+
}))
29+
2430
describe('Passcode', () => {
2531
afterEach(cleanup)
2632

@@ -48,7 +54,7 @@ describe('Passcode', () => {
4854

4955
await waitFor(() => {
5056
expect(mockSubmit).toHaveBeenCalledTimes(1)
51-
expect(mockSubmit).toHaveBeenCalledWith('1111')
57+
expect(mockSubmit).toHaveBeenCalledWith('1111', expect.anything())
5258
})
5359
})
5460

0 commit comments

Comments
 (0)