Skip to content

Commit 49328b4

Browse files
Initial build
Signed-off-by: Peter Broadhurst <[email protected]>
1 parent c7c80f8 commit 49328b4

File tree

12 files changed

+153
-14
lines changed

12 files changed

+153
-14
lines changed

.github/workflows/tsc.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Typescript
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
jobs:
11+
build:
12+
name: tsc
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v1
16+
- name: install node v16
17+
uses: actions/setup-node@v1
18+
with:
19+
node-version: 16
20+
- name: npm install
21+
run: npm install
22+
- name: tsc
23+
run: npm t

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
node_modules
2-
build
2+
build
3+
coverage
4+
.nyc_output

package.json

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"build": "npm run clean && tsc && npm run copy-swagger",
1010
"start:dev": "nodemon",
1111
"start": "node build/index.js",
12-
"dev": "ts-node src/index.ts"
12+
"dev": "ts-node src/index.ts",
13+
"test": "nyc mocha"
1314
},
1415
"repository": {
1516
"type": "git",
@@ -26,22 +27,57 @@
2627
"form-data": "^4.0.0",
2728
"jsrsasign": "^10.4.1",
2829
"swagger-ui-express": "^4.1.6",
29-
"ts-node": "^10.4.0",
3030
"uuid": "^8.3.2",
3131
"ws": "^8.2.3",
3232
"yamljs": "^0.3.0"
3333
},
3434
"devDependencies": {
3535
"@types/bunyan": "^1.8.7",
3636
"@types/busboy": "^0.3.1",
37+
"@types/chai": "^4.2.22",
3738
"@types/express": "^4.17.13",
3839
"@types/jsrsasign": "^8.0.13",
40+
"@types/mocha": "^9.0.0",
3941
"@types/node": "^16.11.5",
4042
"@types/swagger-ui-express": "^4.1.3",
4143
"@types/uuid": "^8.3.1",
4244
"@types/ws": "^8.2.0",
4345
"@types/yamljs": "^0.2.31",
46+
"chai": "^4.3.4",
47+
"moment": "^2.29.1",
4448
"rimraf": "^3.0.2",
49+
"sinon": "^11.1.2",
50+
"sinon-chai": "^3.7.0",
51+
"source-map-support": "^0.5.20",
52+
"ts-node": "^10.4.0",
53+
"ts-sinon": "^2.0.2",
4554
"typescript": "^4.4.4"
55+
},
56+
"nyc": {
57+
"extension": [
58+
".ts",
59+
".tsx"
60+
],
61+
"exclude": [
62+
"coverage",
63+
"test",
64+
"build",
65+
"**/*.d.ts"
66+
],
67+
"reporter": [
68+
"html",
69+
"text-summary"
70+
],
71+
"all": true
72+
},
73+
"mocha": {
74+
"recursive": true,
75+
"extension": [
76+
"ts"
77+
],
78+
"require": [
79+
"ts-node/register",
80+
"source-map-support/register"
81+
]
4682
}
4783
}

src/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,4 @@ export const stop = async () => {
168168
log.info("FireFly Data Exchange has stopped all webservers, exiting");
169169
process.exit();
170170
};
171+

src/handlers/blobs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ export const deliverBlob = async ({ blobPath, recipient, recipientURL, requestID
105105
requestID
106106
} as IBlobDeliveredEvent);
107107
log.trace(`Blob delivered`);
108-
} catch (err) {
108+
} catch (err: any) {
109109
eventEmitter.emit('event', {
110110
id: uuidV4(),
111111
type: 'blob-failed',

src/handlers/messages.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const deliverMessage = async ({ message, recipient, recipientURL, request
6363
requestID
6464
} as IMessageDeliveredEvent);
6565
log.trace(`Message delivered`);
66-
} catch(err) {
66+
} catch(err: any) {
6767
eventEmitter.emit('event', {
6868
id: uuidV4(),
6969
type: 'message-failed',

src/lib/config.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const loadConfig = async () => {
4242
try {
4343
log.debug(`Reading peers file ${peersFilePath}`);
4444
data.peers = JSON.parse(await fs.readFile(peersFilePath, 'utf8'));
45-
} catch (err) {
45+
} catch (err: any) {
4646
// if file does not exist, just set peers to either the peers from config.json (if migrating from older version) or to an empty list
4747
log.debug(`Error code when reading peers file ${err.code}`);
4848
if (err.code === 'ENOENT') {
@@ -59,6 +59,7 @@ const loadConfig = async () => {
5959
}
6060
}
6161
} else {
62+
log.error("Config file parsing failed", validateConfig.errors)
6263
throw new Error('Invalid configuration files');
6364
}
6465
} catch(err) {
@@ -75,7 +76,7 @@ export const persistPeers = async () => {
7576
const ensurePeersDirectoryExists = async () => {
7677
try {
7778
await fs.access(peersFilePath);
78-
} catch(err) {
79+
} catch(err: any) {
7980
if(err.code === 'ENOENT') {
8081
await createPeersDirectory();
8182
} else {
@@ -88,7 +89,7 @@ const createPeersDirectory = async () => {
8889
try {
8990
await fs.mkdir(path.parse(peersFilePath).dir, { recursive: true });
9091
log.info('Peers subdirectory created');
91-
} catch(err) {
92+
} catch(err: any) {
9293
log.error(`Failed to create peers subdirectory ${err.code}`);
9394
}
9495
};

src/lib/utils.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
// limitations under the License.
1616

1717
import axios, { AxiosRequestConfig } from 'axios';
18-
import Busboy from 'busboy';
18+
import Busboy, { BusboyHeaders } from 'busboy';
1919
import { Request } from 'express';
2020
import { promises as fs } from 'fs';
2121
import { X509 } from 'jsrsasign';
@@ -54,7 +54,7 @@ export const fileExists = async (filePath: string): Promise<boolean> => {
5454
try {
5555
const stats = await fs.stat(filePath);
5656
return !stats.isDirectory();
57-
} catch (err) {
57+
} catch (err: any) {
5858
if (err.errno === -2) {
5959
return false;
6060
} else {
@@ -67,7 +67,7 @@ export const fileExists = async (filePath: string): Promise<boolean> => {
6767
export const extractFileFromMultipartForm = (req: Request): Promise<IFile> => {
6868
return new Promise(async (resolve, reject) => {
6969
let fileFound = false;
70-
req.pipe(new Busboy({ headers: req.headers })
70+
req.pipe(new Busboy({ headers: req.headers as BusboyHeaders })
7171
.on('file', (fieldname, readableStream, fileName) => {
7272
fileFound = true;
7373
resolve({
@@ -86,7 +86,7 @@ export const extractFileFromMultipartForm = (req: Request): Promise<IFile> => {
8686
export const extractMessageFromMultipartForm = (req: Request): Promise<string> => {
8787
return new Promise(async (resolve, reject) => {
8888
let fieldFound = false;
89-
req.pipe(new Busboy({ headers: req.headers })
89+
req.pipe(new Busboy({ headers: req.headers as BusboyHeaders })
9090
.on('field', (fieldname, value) => {
9191
if(fieldname === 'message') {
9292
fieldFound = true;
@@ -107,7 +107,7 @@ export const axiosWithRetry = async (config: AxiosRequestConfig) => {
107107
try {
108108
log.debug(`${config.method} ${config.url}`);
109109
return await axios(config);
110-
} catch (err) {
110+
} catch (err: any) {
111111
const data = err.response?.data;
112112
log.error(`${config.method} ${config.url} attempt ${attempts} [${err.response?.status}]`, (data && !data.on) ? data : err.stack);
113113
if (err.response?.status === 404) {

src/routers/api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ router.delete('/peers/:id', async (req, res, next) => {
113113
}
114114
try {
115115
await fs.rm(path.join(utils.constants.DATA_DIRECTORY, utils.constants.PEER_CERTS_SUBDIRECTORY, `${req.params.id}.pem`));
116-
} catch (err) {
116+
} catch (err: any) {
117117
if (err.errno !== -2) {
118118
throw new RequestError(`Failed to remove peer certificate`);
119119
}

test/app.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { join } from 'path';
2+
import { promises as fs } from 'fs';
3+
import moment from 'moment';
4+
import * as chai from 'chai';
5+
import { expect }from 'chai';
6+
import { KEYUTIL, KJUR } from 'jsrsasign';
7+
import { stub } from 'sinon';
8+
import sinonChai from 'sinon-chai';
9+
chai.use(sinonChai);
10+
11+
// Set sandbox dir as config before initializing utils
12+
const sandboxDir = join(__dirname, 'resources', 'sandbox');
13+
process.env.DATA_DIRECTORY = sandboxDir;
14+
15+
import * as app from '../src/app';
16+
17+
describe('app', () => {
18+
19+
beforeEach(async () => {
20+
if ((await fs.stat(sandboxDir)).isDirectory()) {
21+
await fs.rm(sandboxDir, { recursive: true, force: true})
22+
}
23+
await fs.mkdir(sandboxDir)
24+
await fs.mkdir(join(sandboxDir, 'peer-certs'))
25+
26+
const start = moment().utc().subtract(1, 'minute');
27+
const end = moment(start).add(12, 'months');
28+
const startUTC = start.format('YYYYMMDDHHmmss\\Z');
29+
const endUTC = end.format('YYYYMMDDHHmmss\\Z');
30+
const keypair = KEYUTIL.generateKeypair('EC', 'secp256r1');
31+
const keyPEM = KEYUTIL.getPEM(keypair.prvKeyObj, "PKCS8PRV")
32+
const certPEM = KJUR.asn1.x509.X509Util.newCertPEM({
33+
serial: { int: 4 },
34+
sigalg: { name: "SHA256withECDSA" },
35+
issuer: { str: "/C=US/O=a" },
36+
notbefore: { str: startUTC },
37+
notafter: { str: endUTC },
38+
subject: { str: "/C=US/O=b" },
39+
sbjpubkey: keypair.pubKeyObj,
40+
sbjprvkey: keypair.prvKeyObj,
41+
cakey: keypair.prvKeyObj,
42+
} as any);
43+
await fs.writeFile(join(sandboxDir, 'key.pem'), keyPEM);
44+
await fs.writeFile(join(sandboxDir, 'cert.pem'), certPEM);
45+
46+
await fs.writeFile(join(sandboxDir, 'config.json'), JSON.stringify({
47+
api: {
48+
hostname: "localhost",
49+
port: 10101,
50+
},
51+
p2p: {
52+
hostname: "localhost",
53+
port: 10102,
54+
}
55+
}, null, 2));
56+
57+
stub(process, 'exit');
58+
});
59+
60+
afterEach(() => {
61+
(process.exit as any).restore();
62+
})
63+
64+
it('starts and stops', async () => {
65+
66+
await app.start();
67+
await app.stop();
68+
69+
expect(process.exit).to.be.called;
70+
71+
})
72+
73+
})

0 commit comments

Comments
 (0)