diff --git a/package-lock.json b/package-lock.json
index 29912d8..58db022 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,16 @@
{
"name": "veritable-authority",
- "version": "0.1.1",
+ "version": "0.1.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "veritable-authority",
- "version": "0.1.1",
+ "version": "0.1.2",
"license": "Apache-2.0",
"dependencies": {
"buffer": "^6.0.3",
+ "moment": "^2.29.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-json-view": "^1.21.3",
@@ -16760,6 +16761,14 @@
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
+ "node_modules/moment": {
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+ "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -40475,6 +40484,11 @@
}
}
},
+ "moment": {
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+ "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+ },
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
diff --git a/package.json b/package.json
index 277aa93..d792c19 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "veritable-authority",
- "version": "0.1.1",
+ "version": "0.1.2",
"description": "Front-end for Veritable authority",
"author": "Digital Catapult (https://www.digicatapult.org.uk/)",
"license": "Apache-2.0",
@@ -14,6 +14,7 @@
},
"dependencies": {
"buffer": "^6.0.3",
+ "moment": "^2.29.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-json-view": "^1.21.3",
diff --git a/src/components/AgentAuthority/ContentWrap/ContentWrap.js b/src/components/AgentAuthority/ContentWrap/ContentWrap.js
index 7b37cab..422f35e 100644
--- a/src/components/AgentAuthority/ContentWrap/ContentWrap.js
+++ b/src/components/AgentAuthority/ContentWrap/ContentWrap.js
@@ -6,9 +6,12 @@
import ColumnLeftWrap from '../ColumnLeft/ColumnLeftWrap'
import ColumnRightWrap from '../ColumnRight/ColumnRightWrap'
+import IssueLicense from '../IssueLicense'
+
export default function ContentWrap({ origin }) {
return (
<>
+
>
diff --git a/src/components/AgentAuthority/IssueLicense/IssueLicense.js b/src/components/AgentAuthority/IssueLicense/IssueLicense.js
new file mode 100644
index 0000000..f044a05
--- /dev/null
+++ b/src/components/AgentAuthority/IssueLicense/IssueLicense.js
@@ -0,0 +1,88 @@
+import { useEffect, useState } from 'react'
+import { AUTHORITY_LABEL, LICENSE_SCHEMA_NAME } from '../../../utils/env.js'
+
+import useIssueLicense from '../../../interface/hooks/use-issue-license'
+import useGetLoopedPresentProofRecords from '../../../interface/hooks/use-get-looped-present-proof-records'
+import useGetCredDefinitionsCreated from '../../../interface/hooks/use-get-cred-definitions-created'
+import usePostSchemas from '../../../interface/hooks/use-post-schemas'
+import usePostCredentialDefinitions from '../../../interface/hooks/use-post-credential-definitions'
+
+import Error from '../../Common/Misc/Error'
+
+export default function IssueLicense({ origin }) {
+ const [licenseCredDefId, setLicenseCredDefId] = useState('')
+ const [, errorIssue, startIssueLicense] = useIssueLicense()
+ const [statusRecords, errorRecords, startGetRecordsHandler] =
+ useGetLoopedPresentProofRecords()
+ const [errorDefinitionsCreated, startFetchHandlerDefinitionsCreated] =
+ useGetCredDefinitionsCreated()
+
+ const [errorPostSchema, startPostSchema] = usePostSchemas()
+ const [errorPostCredDefs, startPostCredDef] = usePostCredentialDefinitions()
+
+ useEffect(() => {
+ const issueLicenses = (proposals) => {
+ proposals.forEach((proposal) => {
+ if (licenseCredDefId) {
+ startIssueLicense(origin, proposal, licenseCredDefId)
+ }
+ })
+ }
+
+ const intervalIdFetch = startGetRecordsHandler(
+ origin,
+ 'proposal-received',
+ issueLicenses
+ )
+ if (statusRecords !== 'started') clearInterval(intervalIdFetch)
+ return function clear() {
+ return clearInterval(intervalIdFetch)
+ }
+ }, [
+ origin,
+ statusRecords,
+ startGetRecordsHandler,
+ licenseCredDefId,
+ startIssueLicense,
+ ])
+
+ useEffect(() => {
+ startFetchHandlerDefinitionsCreated(origin, (credDefIds) => {
+ const licenseCredDefId = credDefIds.find((credDefId) =>
+ credDefId.includes(LICENSE_SCHEMA_NAME)
+ )
+ if (licenseCredDefId) {
+ setLicenseCredDefId(licenseCredDefId)
+ } else {
+ startPostSchema(origin, LICENSE_SCHEMA_NAME, (schemaId) => {
+ startPostCredDef(
+ origin,
+ schemaId,
+ AUTHORITY_LABEL,
+ setLicenseCredDefId
+ )
+ })
+ }
+ })
+ }, [
+ origin,
+ startFetchHandlerDefinitionsCreated,
+ startPostSchema,
+ startPostCredDef,
+ setLicenseCredDefId,
+ ])
+
+ return (
+ <>
+
+ >
+ )
+}
diff --git a/src/components/AgentAuthority/IssueLicense/index.js b/src/components/AgentAuthority/IssueLicense/index.js
new file mode 100644
index 0000000..f8b8eff
--- /dev/null
+++ b/src/components/AgentAuthority/IssueLicense/index.js
@@ -0,0 +1 @@
+export { default } from './IssueLicense'
diff --git a/src/components/Common/Misc/Error/Error.js b/src/components/Common/Misc/Error/Error.js
new file mode 100644
index 0000000..3a4fcc6
--- /dev/null
+++ b/src/components/Common/Misc/Error/Error.js
@@ -0,0 +1,23 @@
+export default function Error({ errors }) {
+ return (
+ <>
+
error != undefined) ? 'd-block' : 'd-none'
+ }`}
+ style={{
+ position: 'fixed',
+ width: '10%',
+ height: '10%',
+ inset: '0px',
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
+ zIndex: 100,
+ }}
+ >
+
+ {errors.toString()}
+
+
+ >
+ )
+}
diff --git a/src/components/Common/Misc/Error/index.js b/src/components/Common/Misc/Error/index.js
new file mode 100644
index 0000000..2ce4206
--- /dev/null
+++ b/src/components/Common/Misc/Error/index.js
@@ -0,0 +1 @@
+export { default } from './Error'
diff --git a/src/interface/hooks/use-delete-record.js b/src/interface/hooks/use-delete-record.js
new file mode 100644
index 0000000..1afb900
--- /dev/null
+++ b/src/interface/hooks/use-delete-record.js
@@ -0,0 +1,24 @@
+/**
+ * It returns a function that can be used to delete a connection.
+ */
+import { useCallback, useState } from 'react'
+import del from '../api/helpers/del'
+
+export default function useDeleteRecord() {
+ const path = '/present-proof-2.0/records/'
+ const transformData = (retrievedData) => retrievedData
+ const [error, setError] = useState(null)
+ const [status, setStatus] = useState('idle')
+ const onStartFetch = useCallback((origin, presExId, setStoreData) => {
+ del(
+ origin,
+ path + presExId,
+ {},
+ setStatus,
+ setError,
+ setStoreData,
+ transformData
+ )
+ }, [])
+ return [status, error, onStartFetch]
+}
diff --git a/src/interface/hooks/use-get-cred-definitions-created.js b/src/interface/hooks/use-get-cred-definitions-created.js
new file mode 100644
index 0000000..5f39325
--- /dev/null
+++ b/src/interface/hooks/use-get-cred-definitions-created.js
@@ -0,0 +1,19 @@
+/**
+ * This function returns a function that, will fetch the credential
+ * definitions created by the user
+ */
+import { useCallback, useState } from 'react'
+import get from '../api/helpers/get'
+
+export default function useGetCredDefinitionsCreated() {
+ const path = '/credential-definitions/created'
+ const transformData = (retrievedData) =>
+ retrievedData.credential_definition_ids
+
+ const [error, setError] = useState(null)
+
+ const onStartFetch = useCallback((fetchOrigin, setStoreData) => {
+ get(fetchOrigin, path, {}, () => {}, setError, setStoreData, transformData)
+ }, [])
+ return [error, onStartFetch]
+}
diff --git a/src/interface/hooks/use-get-looped-present-proof-records.js b/src/interface/hooks/use-get-looped-present-proof-records.js
new file mode 100644
index 0000000..915b7eb
--- /dev/null
+++ b/src/interface/hooks/use-get-looped-present-proof-records.js
@@ -0,0 +1,28 @@
+/**
+ * This function returns continuously the present proof records
+ */
+import { useCallback, useState } from 'react'
+import getLooped from '../api/helpers/get-looped'
+export default function useGetLoopedPresentProofRecords() {
+ const path = '/present-proof-2.0/records'
+ const transformData = (retData) => retData.results
+ const statusOptions = ['started', 'error', 'stopped']
+ const [status, setStatus] = useState(statusOptions[0])
+ const [error, setError] = useState(null)
+ const onStartFetch = useCallback((origin, state, setStoreData) => {
+ const params = state ? `state=${state}` : {}
+ const intervalId = setInterval(() => {
+ getLooped(
+ origin,
+ path,
+ params,
+ setStatus,
+ setError,
+ setStoreData,
+ transformData
+ )
+ }, 1000)
+ return intervalId
+ }, [])
+ return [status, error, onStartFetch]
+}
diff --git a/src/interface/hooks/use-get-present-proof-records.js b/src/interface/hooks/use-get-present-proof-records.js
new file mode 100644
index 0000000..0a9bac3
--- /dev/null
+++ b/src/interface/hooks/use-get-present-proof-records.js
@@ -0,0 +1,24 @@
+/**
+ * This function returns continuously the present proof records
+ */
+import { useCallback, useState } from 'react'
+import get from '../api/helpers/get'
+export default function useGetPresentProofRecord() {
+ const path = '/present-proof-2.0/records'
+ const transformData = (retData) => retData
+ const statusOptions = ['started', 'error', 'stopped']
+ const [status, setStatus] = useState(statusOptions[0])
+ const [error, setError] = useState(null)
+ const onStartFetch = useCallback((origin, presExId, setStoreData) => {
+ get(
+ origin,
+ `${path}/${presExId}`,
+ {},
+ setStatus,
+ setError,
+ setStoreData,
+ transformData
+ )
+ }, [])
+ return [status, error, onStartFetch]
+}
diff --git a/src/interface/hooks/use-issue-license.js b/src/interface/hooks/use-issue-license.js
new file mode 100644
index 0000000..3a4b939
--- /dev/null
+++ b/src/interface/hooks/use-issue-license.js
@@ -0,0 +1,156 @@
+/**
+ * Polls for presentation proof proposals, then requests and verifies proofs.
+ * Finally issues a license and deletes the proof
+ */
+import { useState, useCallback } from 'react'
+import moment from 'moment'
+
+import usePostPresentProofSendRequest from './use-post-present-proof-send-request'
+import useGetPresentProofRecord from './use-get-present-proof-records'
+import usePostIssueCredentialSendOffer from './use-post-issue-credential-send-offer'
+import useDeleteRecord from './use-delete-record'
+
+const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
+
+export default function useIssueLicense() {
+ const [inflight, setInflight] = useState(new Set())
+ const [status, setStatus] = useState('')
+ const [timeoutError, setTimeoutError] = useState(null)
+
+ const [statusRequest, errorRequest, postRequest] =
+ usePostPresentProofSendRequest()
+ const [statusDelete, errorDelete, deleteRecord] = useDeleteRecord()
+ const [statusRecords, errorRecords, getRecord] = useGetPresentProofRecord()
+ const [statusIssueCred, errorIssueCred, postCredOffer] =
+ usePostIssueCredentialSendOffer()
+
+ const postRequestP = useCallback(
+ (origin, proposal) =>
+ new Promise((resolve) => {
+ postRequest(
+ origin,
+ proposal.pres_proposal.comment,
+ proposal.connection_id,
+ proposal.by_format.pres_proposal.indy,
+ moment().format('YYYY-MM-DD'),
+ (data) => {
+ resolve(data)
+ }
+ )
+ }),
+ [postRequest]
+ )
+
+ const deleteRecordP = useCallback(
+ (origin, presExId) =>
+ new Promise((resolve) => {
+ deleteRecord(origin, presExId, () => {
+ resolve()
+ })
+ }),
+ [deleteRecord]
+ )
+
+ const getRecordP = useCallback(
+ (origin, presExId) =>
+ new Promise((resolve) => {
+ getRecord(origin, presExId, (data) => {
+ resolve(data)
+ })
+ }),
+ [getRecord]
+ )
+
+ const postCredOfferP = useCallback(
+ (origin, verifiedRecord, licenseCredDefId) =>
+ new Promise((resolve) => {
+ const attr =
+ verifiedRecord.by_format.pres.indy.requested_proof.revealed_attrs
+ const expiry = moment().add(2, 'years').format('YYYYMMDD')
+
+ postCredOffer(
+ origin,
+ verifiedRecord.connection_id,
+ licenseCredDefId,
+ attr['0_id_uuid'].raw,
+ attr['0_type_uuid'].raw,
+ expiry,
+ verifiedRecord.pres_request.comment,
+ (data) => {
+ resolve(data)
+ }
+ )
+ }),
+ [postCredOffer]
+ )
+
+ const waitForVerifiedRecord = useCallback(
+ async (origin, requestPresExId) => {
+ let i = 0
+ const retryCount = 10
+ for (; i < retryCount; i++) {
+ const record = await getRecordP(origin, requestPresExId)
+ if (record?.state === 'done') {
+ return record
+ }
+ await delay(3000)
+ }
+ if (i === retryCount) {
+ setTimeoutError('timeout')
+ return null
+ }
+ },
+ [getRecordP]
+ )
+
+ const onStartFetch = useCallback(
+ async (origin, proposal, licenseCredDefId) => {
+ if (!inflight.has(proposal.pres_ex_id)) {
+ setInflight((prev) => new Set(prev.add(proposal.pres_ex_id)))
+
+ const requestPresExId = await postRequestP(origin, proposal)
+ await deleteRecordP(origin, proposal.pres_ex_id)
+ const verified = await waitForVerifiedRecord(origin, requestPresExId)
+ if (!verified) return
+ const licenseId = await postCredOfferP(
+ origin,
+ verified,
+ licenseCredDefId
+ )
+ await deleteRecordP(origin, verified.pres_ex_id)
+
+ setInflight(
+ (prev) => new Set([...prev].filter((id) => id != proposal.pres_ex_id))
+ )
+ setStatus('done')
+ return licenseId
+ }
+ },
+ [
+ inflight,
+ postRequestP,
+ deleteRecordP,
+ waitForVerifiedRecord,
+ postCredOfferP,
+ ]
+ )
+
+ if (
+ statusRequest === 'error' ||
+ statusRecords === 'error' ||
+ statusIssueCred === 'error' ||
+ statusDelete === 'error'
+ ) {
+ setStatus('error')
+ }
+
+ return [
+ status,
+ errorRequest ||
+ errorRecords ||
+ errorIssueCred ||
+ errorDelete ||
+ timeoutError,
+ onStartFetch,
+ ]
+}
diff --git a/src/interface/hooks/use-post-credential-definitions.js b/src/interface/hooks/use-post-credential-definitions.js
new file mode 100644
index 0000000..bfb71fc
--- /dev/null
+++ b/src/interface/hooks/use-post-credential-definitions.js
@@ -0,0 +1,46 @@
+/**
+ * This function is used to create a credential definition
+ */
+import { useCallback, useState } from 'react'
+import post from '../api/helpers/post'
+
+export default function usePostCredentialDefinitions() {
+ const path = '/credential-definitions'
+ const transformData = (retrievedData) =>
+ retrievedData.credential_definition_id
+ const [error, setError] = useState(null)
+ const onStartFetch = useCallback(
+ (fetchOrigin, schemaId, persona, setStoreData) => {
+ const params = {}
+ const createBody = (schemaId, persona) => {
+ const supportRevocation = false
+
+ const schemaDefName = schemaId.split(':')[2]
+ const schemaDefTagName = schemaDefName.replace(/\s+/g, '_')
+ const schemaDefTagPrefix = `${persona}.agent`
+ const credDefTag = `${schemaDefTagPrefix}.${schemaDefTagName}`
+ const did = schemaId.split(':')[0]
+ const definitionBody = {
+ schema_id: schemaId,
+ support_revocation: supportRevocation,
+ tag: credDefTag,
+ did: did,
+ }
+ return definitionBody
+ }
+ const body = createBody(schemaId, persona)
+ post(
+ fetchOrigin,
+ path,
+ params,
+ body,
+ () => {},
+ setError,
+ setStoreData,
+ transformData
+ )
+ },
+ []
+ )
+ return [error, onStartFetch]
+}
diff --git a/src/interface/hooks/use-post-issue-credential-send-offer.js b/src/interface/hooks/use-post-issue-credential-send-offer.js
new file mode 100644
index 0000000..a66e33f
--- /dev/null
+++ b/src/interface/hooks/use-post-issue-credential-send-offer.js
@@ -0,0 +1,90 @@
+/**
+ * This function is used to send with POST a credential offer to the server
+ */
+import { useCallback, useState } from 'react'
+import post from '../api/helpers/post'
+
+const convertToNameValueArr = (obj) =>
+ Object.entries(obj).reduce((acc, [name, value]) => {
+ acc.push({ name, value })
+ return acc
+ }, [])
+
+export default function usePostIssueCredentialSendOffer() {
+ const path = '/issue-credential-2.0/send-offer'
+ const transformData = (retrievedData) => retrievedData.cred_ex_id
+ const [error, setError] = useState(null)
+ const [status, setStatus] = useState('idle')
+
+ const onStartFetch = useCallback(
+ (
+ origin,
+ connectionId,
+ credDefId,
+ id,
+ type,
+ expiry,
+ testCertReferent,
+ setStoreData
+ ) => {
+ const createBody = (
+ connectionId,
+ credDefId,
+ id,
+ type,
+ expiry,
+ testCertReferent
+ ) => {
+ const CRED_PREVIEW_TYPE =
+ 'https://didcomm.org/issue-credential/2.0/credential-preview'
+
+ const getTimestamp = () => {
+ const timestamp = new Date() / 1000
+ return timestamp.toFixed()
+ }
+
+ const credAttrs = {
+ id: id,
+ type: type,
+ expiration_dateint: expiry,
+ timestamp: getTimestamp(),
+ test_cert_referent: testCertReferent,
+ }
+
+ return {
+ connection_id: connectionId,
+ comment: `Offer on cred def id ${credDefId}`,
+ auto_remove: false,
+ credential_preview: {
+ '@type': CRED_PREVIEW_TYPE,
+ attributes: convertToNameValueArr(credAttrs),
+ },
+ filter: { indy: { cred_def_id: credDefId } },
+ trace: false,
+ }
+ }
+
+ const params = {}
+ const body = createBody(
+ connectionId,
+ credDefId,
+ id,
+ type,
+ expiry,
+ testCertReferent
+ )
+ post(
+ origin,
+ path,
+ params,
+ body,
+ setStatus,
+ setError,
+ setStoreData,
+ transformData
+ )
+ },
+ []
+ )
+ return [status, error, onStartFetch]
+}
diff --git a/src/interface/hooks/use-post-present-proof-send-request.js b/src/interface/hooks/use-post-present-proof-send-request.js
new file mode 100644
index 0000000..f8cdcb7
--- /dev/null
+++ b/src/interface/hooks/use-post-present-proof-send-request.js
@@ -0,0 +1,72 @@
+/**
+ * This function is used to send with POST a proposal for a present proof
+ */
+import { useCallback, useState } from 'react'
+import post from '../api/helpers/post'
+
+// dateStr should be in format YYYY-MM-DD
+const dateStrToNum = (dateStr) => {
+ const [yearStr, monthStr, dayStr] = dateStr.split('-')
+ const year = parseInt(yearStr, 10),
+ month = parseInt(monthStr, 10),
+ day = parseInt(dayStr, 10)
+ return year * 100 * 100 + month * 100 + day
+}
+
+export default function usePostPresentProofSendRequest() {
+ const path = '/present-proof-2.0/send-request'
+
+ const [error, setError] = useState(null)
+ const [status, setStatus] = useState('idle')
+
+ const createBody = (comment, connectionId, proposal, validity) => {
+ const predicates = [
+ {
+ name: 'expiration_dateint',
+ p_type: '>=',
+ p_value: dateStrToNum(validity),
+ restrictions: [{ schema_name: 'drone schema' }],
+ },
+ ]
+
+ const proofProposalWebRequest = {
+ comment,
+ connection_id: connectionId,
+ presentation_request: {
+ indy: {
+ name: proposal.name,
+ version: proposal.version,
+ requested_attributes: proposal.requested_attributes,
+ requested_predicates: Object.fromEntries(
+ predicates.map((e) => [`0_${e.name}_GE_uuid`, e])
+ ),
+ },
+ },
+
+ trace: false,
+ }
+ return proofProposalWebRequest
+ }
+
+ const onStartFetch = useCallback(
+ (origin, comment, connectionId, proposal, validity, setStoreData) => {
+ const params = {}
+ const body = createBody(comment, connectionId, proposal, validity)
+
+ const transformData = (retrievedData) => retrievedData.pres_ex_id
+
+ post(
+ origin,
+ path,
+ params,
+ body,
+ setStatus,
+ setError,
+ setStoreData,
+ transformData
+ )
+ },
+ []
+ )
+ return [status, error, onStartFetch]
+}
diff --git a/src/interface/hooks/use-post-schemas.js b/src/interface/hooks/use-post-schemas.js
new file mode 100644
index 0000000..89bc060
--- /dev/null
+++ b/src/interface/hooks/use-post-schemas.js
@@ -0,0 +1,44 @@
+/**
+ * It creates a function that will post a schema to the server.
+ */
+import { useCallback, useState } from 'react'
+import post from '../api/helpers/post'
+
+export default function usePostSchemas() {
+ const path = '/schemas'
+ const transformData = (retrievedData) => retrievedData.schema_id
+ const [error, setError] = useState(null)
+ const onStartFetch = useCallback((fetchOrigin, schemaName, setStoreData) => {
+ const createBody = (schemaName) => {
+ const version = () => {
+ const major = parseInt(Math.random() * 10 + 0)
+ const minor = parseInt(Math.random() * 100 + 0)
+ return `${major}.${minor}`
+ }
+ return {
+ schema_name: schemaName,
+ schema_version: version(),
+ attributes: [
+ 'id',
+ 'type',
+ 'expiration_dateint',
+ 'timestamp',
+ 'test_cert_referent',
+ ],
+ }
+ }
+
+ const body = createBody(schemaName)
+ post(
+ fetchOrigin,
+ path,
+ {},
+ body,
+ () => {},
+ setError,
+ setStoreData,
+ transformData
+ )
+ }, [])
+ return [error, onStartFetch]
+}
diff --git a/src/utils/env.js b/src/utils/env.js
index 695a41d..aa1a087 100644
--- a/src/utils/env.js
+++ b/src/utils/env.js
@@ -1,2 +1,6 @@
export const API_HOST = process.env.REACT_APP_API_HOST || 'localhost'
export const API_PORT = process.env.REACT_APP_API_PORT || 8051
+export const AUTHORITY_LABEL =
+ process.env.REACT_APP_AUTHORITY_LABEL || 'authority'
+export const LICENSE_SCHEMA_NAME =
+ process.env.REACT_APP_LICENSE_SCHEMA_NAME || 'AuthorityLicense'