Commit f7c3c7aa authored by Hidde-Jan Jongsma's avatar Hidde-Jan Jongsma

Add rudimentary verifier and issue controllers

parent 112d591c
......@@ -4,6 +4,8 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { IssueModule } from './issue/issue.module';
import { VerifyModule } from './verify/verify.module';
import { UtilsModule } from './utils/utils.module';
@Module({
imports: [
......@@ -14,6 +16,8 @@ import { IssueModule } from './issue/issue.module';
autoLoadEntities: true,
}),
IssueModule,
VerifyModule,
UtilsModule,
],
controllers: [AppController],
providers: [AppService],
......
......@@ -35,7 +35,7 @@ export class JolocomService implements ConnectorService {
/* JolocomService specific */
async createWalletForOrganization(organization: Organization) {
this.logger.log(`Creating wallet for ${organization.name}`);
this.logger.debug(`Creating wallet for ${organization.name}`);
const seed = JolocomWallet.randomSeed();
const password = JolocomWallet.randomPassword();
const keyProvider = JolocomLib.KeyProvider.fromSeed(seed, password);
......@@ -46,18 +46,18 @@ export class JolocomService implements ConnectorService {
wallet.encryptedSeedHex = keyProvider.encryptedSeed; // Already in hex format
await this.walletRepository.save(wallet);
this.logger.log(`Created wallet for ${organization.name}`);
this.logger.debug(`Created wallet for ${organization.name}`);
return wallet;
}
async registerWallet(wallet: JolocomWallet) {
this.logger.log(`Wallet registration started`);
this.logger.debug(`Wallet registration started`);
const keyProvider = this.getKeyProvider(wallet);
const identityWallet = await this.registry.create(
keyProvider,
wallet.password,
);
this.logger.log(`Wallet registration successful`);
this.logger.debug(`Wallet registration successful`);
// TODO: Maybe we shouldn't return here.
return identityWallet;
......@@ -73,10 +73,10 @@ export class JolocomService implements ConnectorService {
}
async fuelWallet(wallet: JolocomWallet) {
this.logger.log(`Wallet fueling started`);
this.logger.debug(`Wallet fueling started`);
const publicEthKey = this.getPublicEthKey(wallet);
await JolocomLib.util.fuelKeyWithEther(publicEthKey);
this.logger.log(`Wallet fueling started`);
this.logger.debug(`Wallet fueling started`);
}
getPublicEthKey(wallet: JolocomWallet) {
......@@ -103,7 +103,7 @@ export class JolocomService implements ConnectorService {
// requestId: request.requestId,
// qr: await QRCode.toDataURL(token),
// };
// console.log('Jolocom CredentialOfferToken: ', credOffer.encode());
// console.debug('Jolocom CredentialOfferToken: ', credOffer.encode());
// return response.render('jolocom/issue', viewData);
// }
......
import { Controller } from '@nestjs/common';
import { Controller, Get, Param, Query } from '@nestjs/common';
import { GetConnectorPipe } from '../connectors/get-connector.pipe';
import { ConnectorService } from '../connectors/connector-service.interface';
import { GetIssueRequestPipe } from '../requests/get-request.pipe';
import { CredentialIssueRequest } from '../requests/credential-issue-request.entity';
@Controller('issue')
export class IssueController {}
export class IssueController {
@Get(':connector')
async receiveCredentialIssueRequest(
@Param('connector', GetConnectorPipe) connectorService: ConnectorService,
@Query('token', GetIssueRequestPipe)
issueRequest: CredentialIssueRequest,
) {
return issueRequest;
}
}
import { Module } from '@nestjs/common';
import { IssueController } from './issue.controller';
import { ConnectorsModule } from 'src/connectors/connectors.module';
import { RequestsModule } from 'src/requests/requests.module';
@Module({
controllers: [IssueController]
imports: [ConnectorsModule, RequestsModule],
controllers: [IssueController],
})
export class IssueModule {}
......@@ -21,6 +21,10 @@ export class OrganizationsService {
return this.organizationsRepository.find();
}
async find(id: number | string) {
return this.organizationsRepository.findOne(id);
}
async findByIdentifier(uuid: string) {
return this.organizationsRepository.findOne({
uuid,
......@@ -28,7 +32,7 @@ export class OrganizationsService {
}
async createFromName(name: string) {
this.logger.log(`Creating organization with name ${name}`);
this.logger.debug(`Creating organization with name ${name}`);
const organization = new Organization();
organization.name = name;
organization.sharedSecret = Organization.randomSecret();
......@@ -37,7 +41,7 @@ export class OrganizationsService {
// TODO: Move to queue if needed.
await this.connectorsService.registerOrganization(organization);
this.logger.log(`Created organization (id: ${organization.id})`);
this.logger.debug(`Created organization (id: ${organization.id})`);
return organization;
}
}
import {
PipeTransform,
Injectable,
ArgumentMetadata,
Inject,
} from '@nestjs/common';
import { RequestsService } from './requests.service';
@Injectable()
export class GetVerifyRequestPipe implements PipeTransform {
constructor(
@Inject(RequestsService) private requestsService: RequestsService,
) {}
transform(jwtToken: string, metatdata: ArgumentMetadata) {
return this.requestsService.decodeVerifyRequestToken(jwtToken);
}
}
export class GetIssueRequestPipe implements PipeTransform {
constructor(
@Inject(RequestsService) private requestsService: RequestsService,
) {}
transform(jwtToken: string, metatdata: ArgumentMetadata) {
return this.requestsService.decodeIssueRequestToken(jwtToken);
}
}
......@@ -4,13 +4,14 @@ import { OrganizationsModule } from '../organizations/organizations.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CredentialIssueRequest } from './credential-issue-request.entity';
import { CredentialVerifyRequest } from './credential-verify-request.entity';
import { GetIssueRequestPipe, GetVerifyRequestPipe } from './get-request.pipe';
@Module({
imports: [
TypeOrmModule.forFeature([CredentialIssueRequest, CredentialVerifyRequest]),
OrganizationsModule,
],
providers: [RequestsService],
exports: [RequestsService],
providers: [RequestsService, GetIssueRequestPipe, GetVerifyRequestPipe],
exports: [RequestsService, GetIssueRequestPipe, GetVerifyRequestPipe],
})
export class RequestsModule {}
import { Injectable } from '@nestjs/common';
import { Injectable, Logger } from '@nestjs/common';
import { decode, verify } from 'jsonwebtoken';
import { OrganizationsService } from 'src/organizations/organizations.service';
......@@ -20,13 +20,17 @@ const JWT_MAX_AGE = '300s';
@Injectable()
export class RequestsService {
logger: Logger;
constructor(
private organizationsService: OrganizationsService,
@InjectRepository(CredentialIssueRequest)
private issueRequestRepository: Repository<CredentialIssueRequest>,
@InjectRepository(CredentialVerifyRequest)
private verifyRequestRepository: Repository<CredentialVerifyRequest>,
) {}
) {
this.logger = new Logger(RequestsService.name);
}
async findVerifyRequestByIdentifier(uuid: string) {
return this.verifyRequestRepository.findOne({ uuid });
......@@ -114,7 +118,9 @@ export class RequestsService {
// Check if issuer is set
if (!decoded || !decoded.iss) {
throw new Error('Could not decode issuer');
throw new Error(
`Could not decode issuer from: ${JSON.stringify(decoded)}`,
);
}
const requestor = await this.organizationsService.findByIdentifier(
......@@ -122,7 +128,7 @@ export class RequestsService {
);
if (!requestor) {
throw new Error('Could not find requestor');
throw new Error(`Could not find requestor from: ${decoded.iss}`);
}
// Verify that jwt is signed by specified issuer
......@@ -140,6 +146,7 @@ export class RequestsService {
// is valid.
return { request: (request as unknown) as T, requestor };
} catch (e) {
this.logger.error(`Received error during JWT decoding: ${e}`);
throw new InvalidRequestJWT('Could not decode request JWT');
}
}
......
import { Test, TestingModule } from '@nestjs/testing';
import { UtilsController } from './utils.controller';
describe('Utils Controller', () => {
let controller: UtilsController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [UtilsController],
}).compile();
controller = module.get<UtilsController>(UtilsController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
import { Controller, Post, Body, Param } from '@nestjs/common';
import { OrganizationsService } from 'src/organizations/organizations.service';
import { UtilsService } from './utils.service';
@Controller('utils')
export class UtilsController {
constructor(
private organizationsService: OrganizationsService,
private utilsService: UtilsService,
) {}
@Post('jwt/:organizationId')
async generateJwt(
@Param('organizationId') organizationId: string,
@Body() body: object,
) {
const organization = await this.organizationsService.find(organizationId);
const jwt = this.utilsService.createSignedJwt(body, organization);
return jwt;
}
}
import { Module } from '@nestjs/common';
import { UtilsController } from './utils.controller';
import { OrganizationsModule } from 'src/organizations/organizations.module';
import { RequestsModule } from 'src/requests/requests.module';
import { UtilsService } from './utils.service';
@Module({
imports: [RequestsModule, OrganizationsModule],
controllers: [UtilsController],
providers: [UtilsService],
})
export class UtilsModule {}
import { Test, TestingModule } from '@nestjs/testing';
import { UtilsService } from './utils.service';
describe('UtilsService', () => {
let service: UtilsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [UtilsService],
}).compile();
service = module.get<UtilsService>(UtilsService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
import { Injectable } from '@nestjs/common';
import { sign } from 'jsonwebtoken';
import { randomBytes } from 'crypto';
import { Organization } from '../organizations/organization.entity';
const JWT_ID_SIZE = 9;
@Injectable()
export class UtilsService {
createSignedJwt(data: string | object, organization: Organization) {
const jwtId = randomBytes(JWT_ID_SIZE).toString('base64');
return sign(data, organization.sharedSecret, {
jwtid: jwtId,
issuer: organization.uuid,
});
}
}
import { Test, TestingModule } from '@nestjs/testing';
import { VerifyController } from './verify.controller';
describe('Verify Controller', () => {
let controller: VerifyController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [VerifyController],
}).compile();
controller = module.get<VerifyController>(VerifyController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
import { Controller, Get, Param, Query } from '@nestjs/common';
import { GetConnectorPipe } from '../connectors/get-connector.pipe';
import { ConnectorService } from 'src/connectors/connector-service.interface';
import { GetVerifyRequestPipe } from 'src/requests/get-request.pipe';
import { CredentialVerifyRequest } from 'src/requests/credential-verify-request.entity';
@Controller('verify')
export class VerifyController {
@Get(':connector')
async receiveCredentialVerifyRequest(
@Param('connector', GetConnectorPipe) connectorService: ConnectorService,
@Query('token', GetVerifyRequestPipe)
verifyRequest: CredentialVerifyRequest,
) {
return verifyRequest;
}
}
import { Module } from '@nestjs/common';
import { ConnectorsModule } from '../connectors/connectors.module';
import { RequestsModule } from '../requests/requests.module';
import { VerifyController } from './verify.controller';
@Module({
imports: [ConnectorsModule, RequestsModule],
controllers: [VerifyController],
})
export class VerifyModule {}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment