Skip to content

Commit f264b39

Browse files
d2 depracated, used runtime adapter instead. Fixing security issues with passwords
1 parent 71b07cc commit f264b39

File tree

8 files changed

+1513
-1351
lines changed

8 files changed

+1513
-1351
lines changed

package-lock.json

Lines changed: 1462 additions & 1264 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,23 @@
2222
"@testing-library/react": "^11.1.0",
2323
"@testing-library/user-event": "^12.1.10",
2424
"axios": "^0.21.1",
25-
"cryptr": "^6.0.2",
26-
"d2": "^31.8.2",
25+
"d2": "31.9.0",
2726
"d2-ui-components": "^2.2.0",
2827
"dhis2-api-wrapper": "git+ssh://[email protected]/WISCENTD-UPC/dhis2-api-wrapper.git#develop",
2928
"dhis2-godata-interoperability": "git+ssh://[email protected]/WISCENTD-UPC/dhis2-godata-interoperability.git#develop",
3029
"dotenv": "^8.2.0",
3130
"godata-api-wrapper": "git+ssh://[email protected]/WISCENTD-UPC/godata-api-wrapper.git#develop",
3231
"lodash": "^4.17.20",
3332
"ramda": "^0.27.1",
34-
"react": "^17.0.1",
35-
"react-dom": "^17.0.1",
33+
"react": "^16",
34+
"react-dom": "^16",
3635
"react-router-dom": "^5.2.0",
3736
"rxjs": "^6.6.3",
3837
"styled-components": "^5.2.1",
3938
"styled-jsx": "^3.3.2",
40-
"typeface-roboto": "^1.1.13"
39+
"typeface-roboto": "^1.1.13",
40+
"typescript": "3.4.3",
41+
"@dhis2/app-runtime-adapter-d2": "^1.0.2"
4142
},
4243
"devDependencies": {
4344
"@types/react-router-dom": "^5.1.6",
@@ -74,7 +75,8 @@
7475
"appType": "APP",
7576
"activities": {
7677
"dhis": {
77-
"href": "*"
78+
"href": "*",
79+
"namespace": "dhis-godata-interoperability"
7880
}
7981
},
8082
"icons": {

src/api/Actions.js

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useEffect, useState } from 'react'
2-
import { getInstance } from 'd2'
2+
import { useD2 } from '@dhis2/app-runtime-adapter-d2'
33
import { Button, Card } from '@dhis2/ui-core'
44
import { Radio, RadioGroup, FormControlLabel, Stepper, Step, StepLabel, StepContent } from '@material-ui/core'
55
import StorageIcon from '@material-ui/icons/Storage'
@@ -12,7 +12,7 @@ import { copyOrganisationUnits, fullTransfer, copyCases, createOutbreaks, copyCo
1212
import '../styles/Actions.css'
1313
import { getFullSteps, getFullStepContent, getSteps, getStepContent } from '../utils/labels'
1414

15-
const Actions = ({ cryptr }) => {
15+
const Actions = () => {
1616
const [config, setConfig] = useState({})
1717
const [dhis2, setDhis2] = useState(null)
1818
const [godata, setGoData] = useState(null)
@@ -28,29 +28,26 @@ const Actions = ({ cryptr }) => {
2828
const [done, setDone] = useState(false)
2929
const [messages, setMessages] = useState([])
3030

31+
const { d2 } = useD2()
32+
3133
useEffect(() => {
3234
async function initInstances() {
33-
const d2 = await getInstance()
34-
const generalNamespace = await d2.dataStore.get("interoperability")
35-
const userNamespace = await d2.currentUser.dataStore.get("interoperability")
35+
const generalNamespace = await d2.dataStore.get("dhis-godata-interoperability")
36+
const userNamespace = await d2.currentUser.dataStore.get("dhis-godata-interoperability")
3637
const baseConf = await generalNamespace.get("base-config")
37-
const cred = await userNamespace.get("cred-config")
38-
const credConf = _.cloneDeep(cred)
39-
40-
const godataPass = cred.GoDataAPIConfig.credentials.password
41-
const dhis2Pass = cred.DHIS2APIConfig.credentials.password
42-
43-
credConf.GoDataAPIConfig.credentials.password = cryptr.decrypt(godataPass)
44-
credConf.DHIS2APIConfig.credentials.password = cryptr.decrypt(dhis2Pass)
45-
38+
const credConf = await userNamespace.get("cred-config")
39+
const password = await userNamespace.get("password")
40+
credConf.GoDataAPIConfig.credentials.password = password.password
4641
const conf = mergeAll([baseConf, credConf])
4742
setConfig(conf)
4843
setDhis2(new DHIS2API(conf.DHIS2APIConfig))
4944
setGoData(new GoDataAPI(conf.GoDataAPIConfig))
5045

5146
}
52-
initInstances()
53-
}, [])
47+
if (d2) {
48+
initInstances()
49+
}
50+
}, [d2])
5451

5552
const logAction = (message) => setMessages(prevArray => [...prevArray, { text: message, done: false }])
5653
const logDone = () => setMessages(prevArray => {

src/components/FileForm.js

Lines changed: 21 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -5,41 +5,45 @@ import IconButton from '@material-ui/core/IconButton'
55
import Visibility from '@material-ui/icons/Visibility'
66
import VisibilityOff from '@material-ui/icons/VisibilityOff'
77
import i18n from '@dhis2/d2-i18n' //do translations!
8-
import { getInstance } from 'd2'
8+
import { useD2 } from '@dhis2/app-runtime-adapter-d2'
99
import _ from 'lodash'
1010
import '../styles/FileForm.css'
1111
import config from '../utils/config'
12+
import { getBaseUrl } from '../index'
1213

1314

14-
const FileForm = ({ cryptr }) => {
15+
const FileForm = () => {
1516
const [formData, setFormData] = useState(config)
1617
const [isOk, setOk] = useState(true)
1718
const [isUploaded, setUploaded] = useState(false)
1819
const [wrong, setWrong] = useState(false)
1920
const [show1, setShow1] = useState(false)
2021
const [show2, setShow2] = useState(false)
22+
23+
const { d2 } = useD2()
2124

2225
function onFormSubmit() {
2326

2427
async function submit(data) {
25-
const d2 = await getInstance()
26-
if(await d2.currentUser.dataStore.has("interoperability")) {
27-
const namespace = await d2.currentUser.dataStore.get("interoperability")
28-
await namespace.set("cred-config", data)
28+
const conf = _.cloneDeep(data)
29+
conf.DHIS2APIConfig.baseURL = await getBaseUrl() + '/api'
30+
31+
const password = conf.GoDataAPIConfig.credentials.password
32+
conf.GoDataAPIConfig.credentials.password = null
33+
34+
if(await d2.currentUser.dataStore.has("dhis-godata-interoperability")) {
35+
const namespace = await d2.currentUser.dataStore.get("dhis-godata-interoperability")
36+
await namespace.set("password", { 'password': password }, false, true)
37+
await namespace.set("cred-config", conf)
2938
} else {
30-
const namespace = await d2.currentUser.dataStore.create("interoperability")
31-
await namespace.set("cred-config", data)
39+
const namespace = await d2.currentUser.dataStore.create("dhis-godata-interoperability")
40+
await namespace.set("password", { 'password': password }, false, true)
41+
await namespace.set("cred-config", conf)
3242
}
3343
}
3444

3545
if (isOk === true) {
36-
const conf = _.cloneDeep(formData)
37-
const godataPass = formData.GoDataAPIConfig.credentials.password
38-
const dhis2Pass = formData.DHIS2APIConfig.credentials.password
39-
40-
conf.GoDataAPIConfig.credentials.password = cryptr.encrypt(godataPass)
41-
conf.DHIS2APIConfig.credentials.password = cryptr.encrypt(dhis2Pass)
42-
submit(conf)
46+
submit(formData)
4347
setUploaded(true)
4448
} else {
4549
setWrong(true)
@@ -142,42 +146,8 @@ const FileForm = ({ cryptr }) => {
142146
>
143147
{ show1 ? <Visibility /> : <VisibilityOff /> }
144148
</IconButton>
145-
<p className="p">Dhis2 API Configuration</p>
146-
<span className="subtitle">BaseURL:</span>
147-
<input
148-
className="text-input"
149-
size="30"
150-
name="DHIS2APIConfig.baseURL"
151-
value={ formData["DHIS2APIConfig"].baseURL }
152-
onChange={ handleOnChange }
153-
/>
154-
<br />
155-
<span className="subtitle">User:</span>
156-
<input
157-
className="text-input"
158-
size="15"
159-
name="DHIS2APIConfig.credentials.user"
160-
value={ formData["DHIS2APIConfig"].credentials.user }
161-
onChange={ handleOnChange }
162-
/>
163-
<br />
164-
<span className="subtitle">Password:</span>
165-
<input
166-
className="text-input"
167-
type={ show2 ? "text" : "password" }
168-
size="15"
169-
name="DHIS2APIConfig.credentials.password"
170-
value={ formData["DHIS2APIConfig"].credentials.password }
171-
onChange={ handleOnChange }
172-
/>
173-
<IconButton
174-
className="icon-button"
175-
aria-label="toggle password visibility"
176-
onClick={ handleClickShowPassword2 }
177-
onMouseDown={ handleMouseDownPassword }
178-
>
179-
{ show2 ? <Visibility /> : <VisibilityOff /> }
180-
</IconButton>
149+
150+
181151
</div>
182152
<div className="import">
183153
<Button

src/components/Form.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import RadioGroup from '@material-ui/core/RadioGroup'
55
import FormControlLabel from '@material-ui/core/FormControlLabel'
66
import TuneIcon from '@material-ui/icons/Tune'
77
import i18n from '@dhis2/d2-i18n' //do translations!
8-
import { getInstance } from 'd2'
8+
import { useD2 } from '@dhis2/app-runtime-adapter-d2'
99
import '../styles/Form.css'
1010
import config from '../utils/config.base'
1111

@@ -14,15 +14,16 @@ const Form = () => {
1414
const [formData, setFormData] = useState(config)
1515
const [isUploaded, setUploaded] = useState(false)
1616
const showOutbreakGroupingLevel = formData.outbreakCreationMode===0
17+
18+
const { d2 } = useD2()
1719

1820
function onFormSubmit() {
1921
async function submit() {
20-
const d2 = await getInstance()
21-
if(await d2.dataStore.has("interoperability")) {
22-
const namespace = await d2.dataStore.get("interoperability")
22+
if(await d2.dataStore.has("dhis-godata-interoperability")) {
23+
const namespace = await d2.dataStore.get("dhis-godata-interoperability")
2324
await namespace.set("base-config", formData)
2425
} else {
25-
const namespace = await d2.dataStore.create("interoperability")
26+
const namespace = await d2.dataStore.create("dhis-godata-interoperability")
2627
await namespace.set("base-config", formData)
2728
}
2829
}

src/components/Main.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,19 @@ import {
44
Switch,
55
Route,
66
} from 'react-router-dom'
7-
import Cryptr from 'cryptr'
87
import FileForm from './FileForm'
98
import Form from './Form'
109
import SideBar from './SideBar'
1110
import Actions from '../api/Actions'
1211

1312
const Main = () => {
14-
const cryptr = new Cryptr(process.env.REACT_APP_SECRET_KEY)
1513
return (
1614
<Router>
1715
<SideBar />
1816
<Switch>
19-
<Route exact path="/credentials" render={ () => <FileForm cryptr={ cryptr }/> }/>
17+
<Route exact path="/credentials" component={ FileForm }/>
2018
<Route exact path="/settings" component={ Form }/>
21-
<Route exact path="/export" render={ () => <Actions cryptr={ cryptr }/> }/>
19+
<Route exact path="/export" component={ Actions }/>
2220
</Switch>
2321
</Router>
2422
)

src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ dotenv.config()
1313
const appName = process.env.REACT_APP_DHIS2_APP_NAME
1414
const apiVersion = process.env.REACT_APP_DHIS2_API_VERSION
1515

16-
async function getBaseUrl() {
16+
export async function getBaseUrl() {
1717
if (process.env.NODE_ENV === "development") {
1818
const baseUrl = process.env.REACT_APP_DHIS2_BASE_URL || "http://localhost:8080"
1919
console.info(`[DEV] DHIS2 instance: ${baseUrl}`)

src/utils/config.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ const config = {
88
},
99
DHIS2APIConfig: {
1010
baseURL: 'http://localhost:8080/api',
11-
credentials: {
12-
user: 'admin',
13-
password: 'district'
14-
}
1511
}
1612
}
1713

0 commit comments

Comments
 (0)