Skip to content

Commit

Permalink
[#501] Web-Trails: Update trails submission so that it uses the last …
Browse files Browse the repository at this point in the history
…historically entered event and trails data.
  • Loading branch information
a-stacey committed Sep 9, 2019
1 parent c402d09 commit 1f42ff3
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 33 deletions.
37 changes: 34 additions & 3 deletions projects/web/src/components/submit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,29 @@ import { AuthState } from "../auth";
import { Organisation } from "../business-registry";
import { objectEvent } from "../epcis";
import { EventForm } from "./epcis/event";
import { Redirect } from "react-router-dom";

export interface SubmitProps {
authState: AuthState;
organisation: Organisation;
routeProps?: any;
}

export function Submit(props: SubmitProps) {
const eventState = React.useState(objectEvent());
const [event, _] = eventState;

const submitEvent = () => {
const [trailData, setTrailData] = React.useState(null);

if (trailData !== null) {
return <Redirect to={{
pathname: '/submitTrail',
state: {eventSubmissionTrailData : trailData }
}}
/>
}

const submitEvent = () => {
return fetch(props.organisation.url + '/event', {
method: 'POST',
body: JSON.stringify(event),
Expand All @@ -27,11 +38,31 @@ export function Submit(props: SubmitProps) {
},
}).then(function(res: Response) {
if (res.status === 200) {
alert('Success!');
window.location.href = 'submitTrail';
alert('Successfully Submited!');
return res.json();
} else {
alert('Failed with status: ' + res.status);
}

throw res;
}).then(function(resultData) {
if ((!Array.isArray(resultData)) ||
(resultData.length < 2)) {
throw resultData;
}
const eventId = resultData[1];

const previousSignatures = props.routeProps == null ||
props.routeProps.location == null ||
props.routeProps.location.state == null ||
props.routeProps.location.state.previousSignature == null ?
[] : [props.routeProps.location.state.previousSignature];
const trailData = {
"eventId": eventId,
"previousSignatures": previousSignatures
};
setTrailData(trailData);

}).catch(function(err) {
console.log(err);
});
Expand Down
97 changes: 71 additions & 26 deletions projects/web/src/components/submitTrail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,91 @@ import * as React from "react";
import { Link } from "react-router-dom";

import { myGlobals } from "../globals";
import { UnsignedTrailEntry, SignedTrailEntry } from "../trails";

import { AuthState } from "../auth";
import { Organisation } from "../business-registry";

import { Redirect } from "react-router-dom";


export interface QueryProps {
authState: AuthState;
organisation: Organisation;
routeProps?: any;
}

// Todo: This should be replaced with a canonical JSON representation and signed using the orgs private key, for now we
// simulate just by using a one way hash to save implementation effort.
// The following code to produce the SHA256 hex bytes from a string (converstion from canonicalEntry to
// signatureHexString) is adapted from the example at:
// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest
// and appears to be licensed under public domain (CC0) https://developer.mozilla.org/en-US/docs/MDN/About.
async function signTrailEntry(unsignedTrailEntry : UnsignedTrailEntry) : Promise<SignedTrailEntry> {
const canonicalEntry = JSON.stringify(unsignedTrailEntry);
const utf8 = new TextEncoder().encode(canonicalEntry);
const rawSignature = await crypto.subtle.digest("SHA-256", utf8);
const signatureHexString = Array.from(new Uint8Array(rawSignature)).map(byte => byte.toString(16).padStart(2, '0')).join('');

return {...unsignedTrailEntry, signature:signatureHexString};
}

export function SubmitTrail(props: QueryProps) {
const trailEntry = [
{
"version": 1,
"timestamp": "2016-07-22T00:00:00Z",
"org": "000000",
"event_id": "00000000-0000-0000-0000-000000000000",
"previous_signatures": [] as string[],
"signature": "todo"
}];
const [nextPreviousSignature, setNextPreviousSignature] = React.useState(null);

const submitTrail = () => {
const eventSubmissionTrailData = props.routeProps == null ||
props.routeProps.location == null ||
props.routeProps.location.state == null ||
props.routeProps.location.state.eventSubmissionTrailData == null ?
[] : props.routeProps.location.state.eventSubmissionTrailData;

// If we don't have event data redirect to the event submission.
if ((eventSubmissionTrailData == null) ||
(eventSubmissionTrailData.eventId == null)) {
return <Redirect to='/submit'/>
}

// If we have submitted the trail data redirect to the event submission and persist the useful trail state.
if (nextPreviousSignature !== null) {
return <Redirect to={{
pathname: '/submit',
state: { previousSignature: nextPreviousSignature }
}}
/>
}

const previousSignatures = eventSubmissionTrailData.previousSignatures == null ? [] : eventSubmissionTrailData.previousSignatures;
const newUnsignedTrailEntry = {
"version": 1,
"timestamp": (new Date).toISOString(),
"org": props.organisation.companyPrefix,
"event_id": eventSubmissionTrailData.eventId,
"previous_signatures": previousSignatures as string[]
};

const submitTrail = () => {
// TODO: The URL here needs to be changed to props.organisation.url, but the
// EDAPI that this is currently building against doesn't support the trails
// service yet.
return fetch('http://localhost:8300' + '/trail', {
method: 'POST',
body: JSON.stringify(trailEntry),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + props.authState.getToken().idToken,
},
}).then(function(res: Response) {
if (res.status === 200) {
alert('Success!');
window.location.href = 'submit';
} else {
alert('Failed with status: ' + res.status);
}
return signTrailEntry(newUnsignedTrailEntry).then((trailEntry) => {
return fetch('http://localhost:8300' + '/trail', {
method: 'POST',
body: JSON.stringify([trailEntry]),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + props.authState.getToken().idToken,
}
}).then(function(res: Response) {
if (res.status === 200) {
alert('Success!');

const previousSignature = trailEntry.signature;
setNextPreviousSignature(previousSignature);
} else {
alert('Failed with status: ' + res.status);
}
});
}).catch(function(err) {
console.log(err);
});
Expand All @@ -63,7 +108,7 @@ export function SubmitTrail(props: QueryProps) {
</div>
<div className="column">
<label>Raw Trail Entry</label>
<textarea style={({ height: "20em" })} value={JSON.stringify(trailEntry, null, 2)} readOnly></textarea>
<textarea style={({ height: "20em" })} value={JSON.stringify(newUnsignedTrailEntry, null, 2)} readOnly></textarea>
</div>
</div>
</div>
Expand Down
8 changes: 4 additions & 4 deletions projects/web/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,11 @@ authInit().then((authState) => {
<Route path="/events" exact render={() =>
<EventLog authState={appState.auth} organisation={appState.organisation}></EventLog>} />

<Route path="/submit" exact render={() =>
<Submit authState={appState.auth} organisation={appState.organisation} ></Submit>} />
<Route path="/submit" exact render={(routeProps) =>
<Submit authState={appState.auth} organisation={appState.organisation} routeProps={routeProps}></Submit>} />

<Route path="/submitTrail" exact render={() =>
<SubmitTrail authState={appState.auth} organisation={appState.organisation} ></SubmitTrail>} />
<Route path="/submitTrail" exact render={(routeProps) =>
<SubmitTrail authState={appState.auth} organisation={appState.organisation} routeProps={routeProps}></SubmitTrail>} />

<Route path="/scan/:scanData*" exact render={({ match }) =>
<Scan authState={appState.auth}
Expand Down
13 changes: 13 additions & 0 deletions projects/web/src/trails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { string } from "prop-types";

export interface UnsignedTrailEntry {
version: number;
timestamp: string;
org: string;
event_id:string;
previous_signatures : string[];
}

export interface SignedTrailEntry extends UnsignedTrailEntry {
signature: string;
}

0 comments on commit 1f42ff3

Please sign in to comment.