Skip to content

dovuofficial/guardian-middleware-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

73 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Guardian Middleware API

Release version of DOVU Guardian Policies

This API is currently configured for template policies for DOVU IWA Policies Alpha - 0.1.0

To comply for 0.2.0, request validation classes need to be updated. mainly to use a flat JSON structure.

Developing and testing locally

Setup your environment variables

You can copy env.example to get you going

cp env.example .env.local

Make sure to have the Guardian API running locally and then fill out the GUARDIAN_API_URL with the correct URL in your .env.local file.

For example:

GUARDIAN_API_URL=http://localhost:3000/api/v1

Running the API

Run yarn and then start the development server. This will default to localhost:3000 but will increment if that port is already busy.

yarn install
yarn dev

Docker Compose

We provide a Dockerfile for running the API in a container. You can use the provided docker-compose.yml file to run the API locally. Please note that this builds a production build without any debug information.

Environment variables you have set in .env.local will be used in the container. This can be changed in the docker-compose.yml file.

Please be aware that in order to reference the Guardian API from within the container, you will need to use the host.docker.internal hostname in your .env.local file. This is a special hostname that resolves to the host machine from within the container.

Example: GUARDIAN_API_URL=http://host.docker.internal:3000/api/v1

The following command will run the Guardian Middleware API on port 3001. You can change this in the docker-compose.yml file if required.

docker-compose up -d --build

Run the linter, formatter and basic tests

yarn lint
yarn format
yarn test
yarn types

All the above can be run together using

yarn ci

If you want to run all the tests, including the e2e tests for your config use:

yarn test:all

Postman

A Postman collection is included at the root of the repositorty which will allow you to start testing endpoints. The Postman file includes autogenerated HMAC headers for all requests and will also store the Bearer JWT of the last created/logged in account. All requests will then use this JWT in their Authorization header.

Typescript and the Open API Spec

The types for the API are autogenerated based on the Open API spec found at /src/spec/openapi.json.

When adding a new route follow these steps:

  1. Update the Open API JSON spec to describe the new route
  2. Run yarn codegen ( which uses openapi-typescript) to auto generate the Typescript definitions at /src/spec/openapi.ts
  3. Add the new route to pages/api/ and supply the required middleware for the route
  4. Add a new handler for the route in src/handlers/
  5. If required, create a new validator for the input in /src/validators/

This flow allows us to have a strong contract between the Open API spec and the API types. Typescript checks should avoid issues of the API moving out of sync with the documentation.

Recommended VSCode plugins

This OpenAPI extension provides linting and autocomplete tools for editing the Open API spec https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi

OpenAPI

The OpenAPI documentation can be found at: http://localhost:3000/docs

The OpenAPI JSON definition can be found at: http://localhost:3000/api/docs

Security

Every request apart from api/status and api/docs should include HMAC authentication. We follow Microsoft's HMAC implementation here with a couple of simplifications.

Required Headers

  • host: string - "example.com"
  • x-date: ISO 8601 UTC - "2022-08-01T11:06:23:1234Z"
  • x-content-sha256: SHA256 string - The SHA256 string of the content body
  • x-signature: HMAC string - The HMAC authentication string as defined below

How to authenticate requests using HMAC

The Microsoft Docs do a good job explaining the details. The following describes the simplified implementation that we use which avoids dynamic complexities like requiring SignedHeaders and Credential headers. Also, since we require the Authorization header for the Guardian JWT, we instead use an x-signature header for passing the HMAC signed hash.

Here is an example of how to construct the required HMAC headers to make a successful request:

function signRequest(
	host, // Often added to the header by default in HTTP clients - example.com
	method, // GET, PUT, POST, DELETE
	url, // path+query - /api/posts?order=asc
	body, // request body (undefined if none)
	secret // The private key used to sign the HMAC content
) {
	var verb = method.toUpperCase()
	var utcNow = new Date().toUTCString()

	// If passing body data then generate a Base64 encoded SHA256 hash
	var contentHash = Crypto.createHash('sha256')
		.update(JSON.stringify(body))
		.digest('base64')

	//
	// String to sign if including body data. We follow the `\n` and `;` delimiters inline with the Microsoft spec
	var stringToSign = `${verb}\n${url}\n${utcNow};${host};${contentHash}`

	//
	// String to sign if not including body data
	var stringToSign = `${verb}\n${url}\n${utcNow};${host}`

	//
	// Signature - Base64 encoded SHA256 HMAC signed with secret key
	var signature = Crypto.createHmac('sha256', secret)
		.update(stringToSign)
		.digest('base64')

	//
	// Result request headers
	return [
		{ name: 'host', value: host },
		{ name: 'x-date', value: utcNow },
		{ name: 'x-content-sha256', value: contentHash }, // Omit if not including body data
		{ name: 'x-signature', value: signature },
	]
}

Example Flow

Assumes a Standard Registry account already exists which has published a policy.

  • Create A New Registrant Account
  • Create A New Verifier Account
  • Assign The New Accounts To A Policy
  • Login With The Registrant Account
  • Submit An Application
  • Login With The Standard Registry Account
  • Approve The Application
  • Login With The Registrant Account
  • Submit An Ecological Project
  • Login With The Standard Registry Account
  • Approve The Ecological Project
  • Login With The Registrant Account
  • Submit A New MRV Request
  • Login With The Verifier Account
  • Approve The MRV Request

After the MRV request is approved, tokens will automatically be minted that represent the carbon described in the MRV for this Ecological Project.