diff --git a/README.md b/README.md index 33e8175e..f8ba15c9 100644 --- a/README.md +++ b/README.md @@ -48,52 +48,60 @@ npm run start:dev ## REST API -If everything went well, you can now make basic asset transfer REST calls! For example... +If everything went well, you can now make basic asset transfer REST calls! + +The examples below require a `SAMPLE_APIKEY` environment variable which must be set to an API key from the `.env` file created above. + +For example, to use the ORG1_APIKEY... + +``` +SAMPLE_APIKEY=$(grep ORG1_APIKEY .env | cut -d '=' -f 2-) +``` ### Get all assets... ```shell -curl http://localhost:3000/api/assets +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets ``` ### Check whether an asset exists... ```shell -curl --include --request OPTIONS http://localhost:3000/api/assets/asset7 +curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request OPTIONS http://localhost:3000/api/assets/asset7 ``` ### Create an asset... ```shell -curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets ``` ### Read transaction status... ```shell -curl --header "api-key:Api-Key " http://localhost:3000/api/transactions/__transaction_id__ +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/transactions/__transaction_id__ ``` ### Read an asset... ```shell -curl --header "api-key:Api-Key " http://localhost:3000/api/assets/asset7 +curl --header "X-Api-Key: ${SAMPLE_APIKEY}" http://localhost:3000/api/assets/asset7 ``` ### Update an asset... ```shell -curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 ``` ### Transfer an asset... ```shell -curl --include --header "Content-Type: application/json" --header "api-key:Api-Key " --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 +curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7 ``` ### Delete an asset... ```shell -curl --include --header "api-key:Api-Key " --request DELETE http://localhost:3000/api/assets/asset7 +curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request DELETE http://localhost:3000/api/assets/asset7 ``` diff --git a/asset-transfer-basic/rest-api-typescript/demo.http b/asset-transfer-basic/rest-api-typescript/demo.http new file mode 100644 index 00000000..163c7632 --- /dev/null +++ b/asset-transfer-basic/rest-api-typescript/demo.http @@ -0,0 +1,84 @@ +// Demo file for use with REST Client for Visual Studio Code +// See https://github.com/Huachao/vscode-restclient +// +// Edit the values below to match your environment if required +@hostname = localhost +@port = {{$dotenv PORT}} +@baseUrl = http://{{hostname}}:{{port}} +@apiUrl = {{baseUrl}}/api +@api-key = {{$dotenv ORG1_APIKEY}} + +### Check the server is ready + +GET {{baseUrl}}/ready HTTP/1.1 + +### Check the server is still live + +GET {{baseUrl}}/live HTTP/1.1 + +### Get all assets + +GET {{apiUrl}}/assets HTTP/1.1 +X-Api-Key: {{api-key}} + +### Check if asset exists + +OPTIONS {{apiUrl}}/assets/asset7 HTTP/1.1 +X-Api-Key: {{api-key}} + +### Create asset + +POST {{apiUrl}}/assets HTTP/1.1 +content-type: application/json +X-Api-Key: {{api-key}} + +{ + "id": "asset7", + "color": "red", + "size": 42, + "owner": "Jean", + "appraisedValue": 101 +} + +### Read transaction status + +GET {{apiUrl}}/transactions/__transaction_id__ HTTP/1.1 +X-Api-Key: {{api-key}} + +### Read asset + +GET {{apiUrl}}/assets/asset7 HTTP/1.1 +X-Api-Key: {{api-key}} + +### Update asset + +PUT {{apiUrl}}/assets/asset7 HTTP/1.1 +content-type: application/json +X-Api-Key: {{api-key}} + +{ + "id": "asset7", + "color": "red", + "size": 11, + "owner": "Jean", + "appraisedValue": 101 +} + +### Transfer asset + +PATCH {{apiUrl}}/assets/asset7 HTTP/1.1 +content-type: application/json +X-Api-Key: {{api-key}} + +[ + { + "op": "replace", + "path": "/owner", + "value": "Ashleigh" + } +] + +### Delete asset + +DELETE {{apiUrl}}/assets/asset7 HTTP/1.1 +X-Api-Key: {{api-key}} diff --git a/asset-transfer-basic/rest-api-typescript/src/auth.ts b/asset-transfer-basic/rest-api-typescript/src/auth.ts index dcd3e724..fe56dd0e 100644 --- a/asset-transfer-basic/rest-api-typescript/src/auth.ts +++ b/asset-transfer-basic/rest-api-typescript/src/auth.ts @@ -1,24 +1,61 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */ + import { logger } from './logger'; +import passport from 'passport'; +import { NextFunction, Request, Response } from 'express'; import { HeaderAPIKeyStrategy } from 'passport-headerapikey'; +import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import * as config from './config'; + +const { UNAUTHORIZED } = StatusCodes; + export const fabricAPIKeyStrategy: HeaderAPIKeyStrategy = new HeaderAPIKeyStrategy( - { header: 'api-key', prefix: 'Api-Key ' }, - true, + { header: 'X-API-Key', prefix: '' }, + false, function (apikey, done) { + logger.debug({ apikey }, 'Checking X-API-Key'); const user: { org: string } = { org: '', }; if (apikey === config.org1ApiKey) { user.org = 'Org1'; - logger.info('Organisation set to Org1'); + logger.debug('Organisation set to Org1'); done(null, user); //todo //add org2 apikey check } else { - logger.debug('APIKEY Mismatch'); + logger.debug({ apikey }, 'No valid X-API-Key'); return done(null, false); } } ); + +export const authenticateApiKey = ( + req: Request, + res: Response, + next: NextFunction +): void => { + passport.authenticate( + 'headerapikey', + { session: false }, + function (err, user, _info) { + if (err) return next(err); + if (!user) + return res.status(UNAUTHORIZED).json({ + status: getReasonPhrase(UNAUTHORIZED), + reason: 'NO_VALID_APIKEY', + timestamp: new Date().toISOString(), + }); + req.logIn(user, { session: false }, (err) => { + if (err) { + return next(err); + } + return next(); + }); + } + )(req, res, next); +}; diff --git a/asset-transfer-basic/rest-api-typescript/src/server.ts b/asset-transfer-basic/rest-api-typescript/src/server.ts index a57dfcda..1b900248 100644 --- a/asset-transfer-basic/rest-api-typescript/src/server.ts +++ b/asset-transfer-basic/rest-api-typescript/src/server.ts @@ -22,7 +22,7 @@ const { SERVICE_UNAVAILABLE, } = StatusCodes; -import { fabricAPIKeyStrategy } from './auth'; +import { authenticateApiKey, fabricAPIKeyStrategy } from './auth'; import passport from 'passport'; export const createServer = async (): Promise => { const app = express(); @@ -98,16 +98,8 @@ export const createServer = async (): Promise => { throw new Error('Example error'); }); - app.use( - '/api/assets', - passport.authenticate('headerapikey', { session: false }), - assetsRouter - ); - app.use( - '/api/transactions', - passport.authenticate('headerapikey', { session: false }), - transactionsRouter - ); + app.use('/api/assets', authenticateApiKey, assetsRouter); + app.use('/api/transactions', authenticateApiKey, transactionsRouter); // For everything else app.use((_req, res) => diff --git a/demo.http b/demo.http deleted file mode 100644 index b682c53e..00000000 --- a/demo.http +++ /dev/null @@ -1,74 +0,0 @@ -// Demo file for use with REST Client for Visual Studio Code -// See https://github.com/Huachao/vscode-restclient -@hostname = localhost -@port = 3000 -@baseUrl = http://{{hostname}}:{{port}}/api - -//Get the apikey from .env file -@api-key= Api-Key 295069C9-ABF5-4D2A-A020-2FF9F4E8DF07 - -### Get all assets -GET {{baseUrl}}/assets HTTP/1.1 -api-key: {{api-key}} - -### Check if asset exists - -OPTIONS {{baseUrl}}/assets/asset7 HTTP/1.1 -api-key: {{api-key}} - -### Create asset - -POST {{baseUrl}}/assets HTTP/1.1 -content-type: application/json -api-key: {{api-key}} - -{ - "id": "asset7", - "color": "red", - "size": 42, - "owner": "Jean", - "appraisedValue": 101 -} - -### Read transaction status - -GET {{baseUrl}}/transactions/__transaction_id__ HTTP/1.1 -api-key: {{api-key}} - -### Read asset - -GET {{baseUrl}}/assets/asset7 HTTP/1.1 -api-key: {{api-key}} - -### Update asset - -PUT {{baseUrl}}/assets/asset7 HTTP/1.1 -content-type: application/json -api-key: {{api-key}} - -{ - "id": "asset7", - "color": "red", - "size": 11, - "owner": "Jean", - "appraisedValue": 101 -} - -### Transfer asset - -PATCH {{baseUrl}}/assets/asset7 HTTP/1.1 -content-type: application/json -api-key: {{api-key}} - -[ - { - "op": "replace", - "path": "/owner", - "value": "Ashleigh" - } -] - -### Delete asset - -DELETE {{baseUrl}}/assets/asset7 HTTP/1.1 -api-key: {{api-key}}