Skip to content

Commit

Permalink
chore(coordinator): add logger
Browse files Browse the repository at this point in the history
- [x] Add logger for auth guard
- [x] Add logger for crypto service
- [x] Add logger for proof generator service
- [x] Add logger for app controller
- [x] Minor swagger fix
  • Loading branch information
0xmad committed May 16, 2024
1 parent ca1ec90 commit c0c99fd
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 16 deletions.
2 changes: 1 addition & 1 deletion coordinator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"**/*.(t|j)s",
"!<rootDir>/ts/main.ts",
"!<rootDir>/ts/jest/*.js",
"!<rootDir>/hardhat.config.ts"
"!<rootDir>/hardhat.config.js"
],
"coverageDirectory": "<rootDir>/coverage",
"testEnvironment": "node"
Expand Down
2 changes: 1 addition & 1 deletion coordinator/tests/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe("AppController (e2e)", () => {
const publicKey = await fs.promises.readFile(process.env.COORDINATOR_PUBLIC_KEY_PATH!);
const signature = await signer.signMessage("message");
const digest = Buffer.from(getBytes(hashMessage("message"))).toString("hex");
return CryptoService.getInstance().encrypt(publicKey, `${signature}:${digest}`);
return `Bearer ${CryptoService.getInstance().encrypt(publicKey, `${signature}:${digest}`)}`;
};

beforeAll(async () => {
Expand Down
26 changes: 20 additions & 6 deletions coordinator/ts/app.controller.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
import { Body, Controller, HttpException, HttpStatus, Post, UseGuards } from "@nestjs/common";
import { ApiBody, ApiHeader, ApiResponse, ApiTags } from "@nestjs/swagger";
import { Body, Controller, HttpException, HttpStatus, Logger, Post, UseGuards } from "@nestjs/common";
import { ApiBearerAuth, ApiBody, ApiResponse, ApiTags } from "@nestjs/swagger";

import { AccountSignatureGuard } from "./auth/AccountSignatureGuard.service";
import { GenerateProofDto } from "./proof/dto";
import { ProofGeneratorService } from "./proof/proof.service";
import { IGenerateData } from "./proof/types";

@ApiTags("v1/proof")
@ApiHeader({
name: "Authorization",
description: "The value is encrypted with RSA public key you generated before (see README.md)",
})
@ApiBearerAuth()
@Controller("v1/proof")
@UseGuards(AccountSignatureGuard)
export class AppController {
/**
* Logger
*/
private readonly logger = new Logger(AppController.name);

/**
* Initialize AppController
*
* @param proofGeneratorService - proof generator service
*/
constructor(private readonly proofGeneratorService: ProofGeneratorService) {}

/**
* Generate proofs api method
*
* @param args - generate proof dto
* @returns
*/
@ApiBody({ type: GenerateProofDto })
@ApiResponse({ status: HttpStatus.CREATED, description: "The proofs have been successfully generated" })
@ApiResponse({ status: HttpStatus.FORBIDDEN, description: "Forbidden" })
@ApiResponse({ status: HttpStatus.BAD_REQUEST, description: "BadRequest" })
@Post("generate")
async generate(@Body() args: GenerateProofDto): Promise<IGenerateData> {
return this.proofGeneratorService.generate(args).catch((error: Error) => {
this.logger.error(`Error:`, error);
throw new HttpException(error.message, HttpStatus.BAD_REQUEST);
});
}
Expand Down
16 changes: 13 additions & 3 deletions coordinator/ts/auth/AccountSignatureGuard.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CanActivate, type ExecutionContext, Injectable } from "@nestjs/common";
import { Logger, CanActivate, type ExecutionContext, Injectable } from "@nestjs/common";
import { ethers } from "ethers";

import fs from "fs";
Expand Down Expand Up @@ -27,7 +27,12 @@ export class AccountSignatureGuard implements CanActivate {
/**
* Crypto service
*/
private cryptoService = CryptoService.getInstance();
private readonly cryptoService = CryptoService.getInstance();

/**
* Logger
*/
private readonly logger = new Logger(AccountSignatureGuard.name);

/**
* This function should return a boolean, indicating whether the request is allowed or not based on message signature and digest.
Expand All @@ -41,13 +46,17 @@ export class AccountSignatureGuard implements CanActivate {
const encryptedHeader = request.headers.authorization;

if (!encryptedHeader) {
this.logger.warn("No authorization header");
return false;
}

const privateKey = await fs.promises.readFile(path.resolve(process.env.COORDINATOR_PRIVATE_KEY_PATH!));
const [signature, digest] = this.cryptoService.decrypt(privateKey, encryptedHeader).split(":");
const [signature, digest] = this.cryptoService
.decrypt(privateKey, encryptedHeader.replace("Bearer", "").trim())
.split(":");

if (!signature || !digest) {
this.logger.warn("No signature or digest");
return false;
}

Expand All @@ -56,6 +65,7 @@ export class AccountSignatureGuard implements CanActivate {

return address === coordinatorAddress;
} catch (error) {
this.logger.error("Error", error);
return false;
}
}
Expand Down
11 changes: 10 additions & 1 deletion coordinator/ts/crypto/crypto.service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Logger } from "@nestjs/common";

import { publicEncrypt, privateDecrypt, type KeyLike } from "crypto";

import { ErrorCodes } from "../common";
Expand All @@ -11,11 +13,16 @@ export class CryptoService {
*/
private static INSTANCE?: CryptoService;

/**
* Logger
*/
private readonly logger: Logger;

/**
* Empty constructor
*/
private constructor() {
// use singleton initialization
this.logger = new Logger(CryptoService.name);
}

/**
Expand Down Expand Up @@ -44,6 +51,7 @@ export class CryptoService {

return encrypted.toString("base64");
} catch (error) {
this.logger.error(`Error: ${ErrorCodes.ENCRYPTION}`, error);
throw new Error(ErrorCodes.ENCRYPTION);
}
}
Expand All @@ -61,6 +69,7 @@ export class CryptoService {

return decryptedData.toString();
} catch (error) {
this.logger.error(`Error: ${ErrorCodes.DECRYPTION}`, error);
throw new Error(ErrorCodes.DECRYPTION);
}
}
Expand Down
5 changes: 4 additions & 1 deletion coordinator/ts/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ dotenv.config({ path: [path.resolve(__dirname, "../.env"), path.resolve(__dirnam

async function bootstrap() {
const { AppModule } = await import("./app.module");
const app = await NestFactory.create(AppModule);
const app = await NestFactory.create(AppModule, {
logger: ["log", "fatal", "error", "warn"],
});

app.useGlobalPipes(new ValidationPipe({ transform: true }));
app.use(
Expand All @@ -32,6 +34,7 @@ async function bootstrap() {
.setDescription("Coordinator service API methods")
.setVersion("1.0")
.addTag("coordinator")
.addBearerAuth()
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup("api", app, document);
Expand Down
17 changes: 14 additions & 3 deletions coordinator/ts/proof/proof.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Injectable } from "@nestjs/common";
import { Logger, Injectable } from "@nestjs/common";
import { ZeroAddress } from "ethers";
import hre from "hardhat";
import { Deployment, EContracts, ProofGenerator, type Poll, type MACI, type AccQueue } from "maci-contracts";
Expand All @@ -20,12 +20,17 @@ export class ProofGeneratorService {
/**
* Deployment helper
*/
private deployment: Deployment;
private readonly deployment: Deployment;

/**
* CryptoService for user sensitive data decryption
*/
private cryptoService: CryptoService;
private readonly cryptoService: CryptoService;

/**
* Logger
*/
private readonly logger: Logger;

/**
* Proof generator initialization
Expand All @@ -34,6 +39,7 @@ export class ProofGeneratorService {
this.deployment = Deployment.getInstance(hre);
this.deployment.setHre(hre);
this.cryptoService = CryptoService.getInstance();
this.logger = new Logger(ProofGeneratorService.name);
}

/**
Expand Down Expand Up @@ -61,6 +67,7 @@ export class ProofGeneratorService {
const pollAddress = await maciContract.polls(poll);

if (pollAddress.toLowerCase() === ZeroAddress.toLowerCase()) {
this.logger.error(`Error: ${ErrorCodes.POLL_NOT_FOUND}, Poll ${poll} not found`);
throw new Error(ErrorCodes.POLL_NOT_FOUND);
}

Expand All @@ -77,6 +84,7 @@ export class ProofGeneratorService {
const isStateAqMerged = await pollContract.stateMerged();

if (!isStateAqMerged) {
this.logger.error(`Error: ${ErrorCodes.NOT_MERGED_STATE_TREE}, state tree is not merged`);
throw new Error(ErrorCodes.NOT_MERGED_STATE_TREE);
}

Expand All @@ -85,6 +93,7 @@ export class ProofGeneratorService {
const mainRoot = await messageAq.getMainRoot(messageTreeDepth.toString());

if (mainRoot.toString() === "0") {
this.logger.error(`Error: ${ErrorCodes.NOT_MERGED_MESSAGE_TREE}, message tree is not merged`);
throw new Error(ErrorCodes.NOT_MERGED_MESSAGE_TREE);
}

Expand All @@ -97,6 +106,7 @@ export class ProofGeneratorService {
]);

if (!coordinatorKeypair.pubKey.equals(publicKey)) {
this.logger.error(`Error: ${ErrorCodes.PRIVATE_KEY_MISMATCH}, wrong private key`);
throw new Error(ErrorCodes.PRIVATE_KEY_MISMATCH);
}

Expand All @@ -118,6 +128,7 @@ export class ProofGeneratorService {
const foundPoll = maciState.polls.get(BigInt(poll));

if (!foundPoll) {
this.logger.error(`Error: ${ErrorCodes.POLL_NOT_FOUND}, Poll ${poll} not found in maci state`);
throw new Error(ErrorCodes.POLL_NOT_FOUND);
}

Expand Down

0 comments on commit c0c99fd

Please sign in to comment.