(feat) CRU Log Rekam Medis + Obat

This commit is contained in:
yosaphatprs 2025-11-06 14:10:04 +07:00
parent 3778b555a8
commit a3bd6e028a
146 changed files with 10336 additions and 1318 deletions

View File

@ -9,6 +9,7 @@ import { TindakanDokterModule } from './modules/tindakandokter/tindakandokter.mo
import { ConfigModule } from '@nestjs/config';
import { PrismaModule } from './modules/prisma/prisma.module';
import { AuthModule } from './modules/auth/auth.module';
import { FabricModule } from './modules/fabric/fabric.module';
@Module({
imports: [
@ -22,7 +23,7 @@ import { AuthModule } from './modules/auth/auth.module';
RekamMedisModule,
ObatModule,
PrismaModule,
AuthModule,
FabricModule,
],
controllers: [AppController],
providers: [AppService],

View File

@ -0,0 +1,5 @@
import crypto from 'node:crypto';
export const sha256 = (input: string | Buffer): string => {
return crypto.createHash('sha256').update(input).digest('hex');
};

View File

@ -1,24 +1,18 @@
import { connect, signers } from '@hyperledger/fabric-gateway';
import grpc from '@grpc/grpc-js';
import * as grpc from '@grpc/grpc-js';
import crypto from 'node:crypto';
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Network configuration
const channelName = process.env.CHANNEL_NAME || 'mychannel';
const chaincodeName = process.env.CHAINCODE_NAME || 'logVerification';
const mspId = process.env.MSP_ID || 'HospitalMSP';
// Path to crypto materials - adjusted for your hospital network structure
const cryptoPath =
process.env.CRYPTO_PATH ||
path.resolve(
__dirname,
'../../',
'../../../../',
'blockchain',
'network',
'organizations',
@ -26,26 +20,27 @@ const cryptoPath =
'hospital.com',
);
// Path to user private key directory
const keyDirectoryPath =
process.env.KEY_DIRECTORY_PATH ||
path.resolve(cryptoPath, 'users', 'Admin@hospital.com', 'msp', 'keystore');
// Path to user certificate directory
const certDirectoryPath =
process.env.CERT_DIRECTORY_PATH ||
path.resolve(cryptoPath, 'users', 'Admin@hospital.com', 'msp', 'signcerts');
// Path to peer tls certificate
const tlsCertPath =
process.env.TLS_CERT_PATH ||
path.resolve(cryptoPath, 'peers', 'peer0.hospital.com', 'tls', 'ca.crt');
// Gateway peer endpoint
const peerEndpoint = process.env.PEER_ENDPOINT || 'localhost:7051';
const peerHostAlias = process.env.PEER_HOST_ALIAS || 'peer0.hospital.com';
class FabricGateway {
gateway: any;
network: any;
contract: any;
client: any;
constructor() {
this.gateway = null;
this.network = null;
@ -53,9 +48,6 @@ class FabricGateway {
this.client = null;
}
/**
* Create a new gRPC connection to the gateway server
*/
async newGrpcConnection() {
const tlsRootCert = await fs.readFile(tlsCertPath);
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
@ -63,20 +55,31 @@ class FabricGateway {
'grpc.ssl_target_name_override': peerHostAlias,
'grpc.keepalive_time_ms': 120000,
'grpc.keepalive_timeout_ms': 5000,
'grpc.keepalive_permit_without_calls': true,
'grpc.keepalive_permit_without_calls': 1,
'grpc.http2.max_pings_without_data': 0,
'grpc.http2.min_time_between_pings_ms': 10000,
'grpc.http2.min_ping_interval_without_data_ms': 300000,
});
}
/**
* Create a new identity for the user
*/
async ensureConnected() {
if (!this.contract) {
console.log('Not connected, attempting to reconnect...');
await this.connect();
}
}
async newIdentity() {
const certificateDirectoryPath = certDirectoryPath;
const certificateFiles = await fs.readdir(certificateDirectoryPath);
const certificateFile = certificateFiles[0];
const certificateFile = certificateFiles.find(
(file) => file.endsWith('-cert.pem') || file.endsWith('.pem'),
);
if (!certificateFile) {
throw new Error(
`No certificate file found in ${certificateDirectoryPath}`,
);
}
const certificatePath = path.resolve(
certificateDirectoryPath,
certificateFile,
@ -85,9 +88,6 @@ class FabricGateway {
return { mspId, credentials: certificate };
}
/**
* Create a new signer for the user's private key
*/
async newSigner() {
const keyDirectoryFiles = await fs.readdir(keyDirectoryPath);
const keyFile = keyDirectoryFiles[0];
@ -97,26 +97,19 @@ class FabricGateway {
return signers.newPrivateKeySigner(privateKey);
}
/**
* Initialize and connect to the Fabric network
*/
async connect() {
try {
console.log('Connecting to Hyperledger Fabric network...');
// Create gRPC connection
this.client = await this.newGrpcConnection();
// Create identity and signer
const identity = await this.newIdentity();
const signer = await this.newSigner();
// Connect to gateway
this.gateway = connect({
client: this.client,
identity,
signer,
// Default timeouts for different gRPC calls
evaluateOptions: () => {
return { deadline: Date.now() + 5000 };
},
@ -131,7 +124,6 @@ class FabricGateway {
},
});
// Get network and contract
this.network = this.gateway.getNetwork(channelName);
this.contract = this.network.getContract(chaincodeName);
@ -143,9 +135,6 @@ class FabricGateway {
}
}
/**
* Disconnect from the network
*/
async disconnect() {
if (this.gateway) {
this.gateway.close();
@ -156,62 +145,22 @@ class FabricGateway {
console.log('Disconnected from Fabric network');
}
/**
* Log verification result to blockchain (evaluate only, no commit)
* @param {string} proofHash - Hash of the proof
* @param {string} idVisit - Visit ID
* @param {boolean} isValid - Whether the proof is valid
* @param {Date} timestamp - Timestamp of verification
*/
async logVerification(proofHash, idVisit, isValid, timestamp) {
async storeLog(
id: string,
event: string,
user_id: string,
payload: string,
): Promise<{ transactionId: string; status: string }> {
try {
await this.ensureConnected();
if (!this.contract) {
throw new Error('Not connected to network. Call connect() first.');
}
console.log('Evaluating verification log on blockchain...');
const resultBytes = await this.contract.evaluateTransaction(
'logExists',
idVisit,
);
const exists = new TextDecoder().decode(resultBytes);
console.log('Log existence check:', exists);
return {
exists: exists === 'true',
message: `Log for visit ${idVisit} ${
exists === 'true' ? 'already exists' : 'does not exist'
}`,
};
} catch (error) {
console.error('Failed to check log verification:', error);
throw error;
}
}
/**
* Submit a transaction to log verification
* @param {string} proofHash - Hash of the proof
* @param {string} idVisit - Visit ID
* @param {boolean} isValid - Whether the proof is valid
* @param {Date} timestamp - Timestamp of verification
*/
async submitLogVerification(proofHash, idVisit, isValid, timestamp) {
try {
if (!this.contract) {
throw new Error('Not connected to network. Call connect() first.');
}
console.log('Submitting verification log transaction...');
console.log(`Submitting log storage transaction for log ID: ${id}...`);
const payloadString: string = payload;
const transaction = this.contract.newProposal('storeLog', {
arguments: [
idVisit,
JSON.stringify(proofHash),
isValid.toString(),
timestamp.toISOString(),
],
arguments: [id, event, user_id, payloadString],
});
const transactionId = await transaction.getTransactionId();
@ -225,97 +174,38 @@ class FabricGateway {
);
}
console.log('Transaction committed successfully:', transactionId);
console.log(
'Log stored successfully with transaction ID:',
transactionId,
);
return {
transactionId,
status: commitStatus,
};
} catch (error) {
console.error('Failed to submit verification transaction:', error);
console.error('Failed to store log:', error);
throw error;
}
}
/**
* Query verification logs by visit ID
* @param {string} idVisit - Visit ID to query
*/
async queryVerificationsByVisitId(idVisit) {
async getLogById(id: string) {
try {
if (!this.contract) {
throw new Error('Not connected to network. Call connect() first.');
}
console.log(`Querying verifications for visit ID: ${idVisit}`);
console.log(`Evaluating getLogById transaction for log ID: ${id}...`);
const resultBytes = await this.contract.evaluateTransaction(
'readLog',
idVisit,
'getLogById',
id,
);
const resultString = new TextDecoder().decode(resultBytes);
const result = JSON.parse(resultString);
const resultJson = new TextDecoder().decode(resultBytes);
const result = JSON.parse(resultJson);
console.log('Query successful');
return result;
} catch (error) {
console.error('Failed to query verifications:', error);
throw error;
}
}
/**
* Query all verification logs
*/
async queryAllVerifications() {
try {
if (!this.contract) {
throw new Error('Not connected to network. Call connect() first.');
}
console.log('Querying all verifications...');
const resultBytes = await this.contract.evaluateTransaction('getAllLogs');
const resultString = new TextDecoder().decode(resultBytes);
const result = JSON.parse(resultString);
console.log('Query successful');
return result;
} catch (error) {
console.error('Failed to query all verifications:', error);
throw error;
}
}
/**
* Initialize the ledger (should be called only once)
*/
async initLedger() {
try {
if (!this.contract) {
throw new Error('Not connected to network. Call connect() first.');
}
console.log('Initializing ledger...');
const transaction = this.contract.newProposal('InitLedger');
const transactionId = await transaction.getTransactionId();
const endorseResult = await transaction.endorse();
const submitResult = await endorseResult.submit();
const commitStatus = await submitResult.getStatus();
if (!commitStatus.successful) {
throw new Error(
`Init ledger transaction ${transactionId} failed to commit with status: ${commitStatus.code}`,
);
}
console.log('Ledger initialized successfully:', transactionId);
return {
transactionId,
status: commitStatus,
};
} catch (error) {
console.error('Failed to initialize ledger:', error);
console.error('Failed to get log by ID:', error);
throw error;
}
}
@ -323,5 +213,4 @@ class FabricGateway {
export default FabricGateway;
// Export a singleton instance for convenience
export const fabricGateway = new FabricGateway();

View File

@ -10,6 +10,7 @@ import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableShutdownHooks();
const configService = app.get(ConfigService);
app.setGlobalPrefix('api/');
app.enableCors({
@ -26,6 +27,7 @@ async function bootstrap() {
}),
);
app.use(cookieParser(configService.get<string>('COOKIE_SECRET')));
await app.listen(configService.get<number>('PORT') ?? 1323);
}
bootstrap();

View File

@ -0,0 +1,16 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { UserRole } from '../dto/auth.dto';
export interface ActiveUserPayload {
sub: number;
username: string;
role: UserRole;
csrf: string;
}
export const CurrentUser = createParamDecorator(
(_data: unknown, ctx: ExecutionContext): ActiveUserPayload => {
const request = ctx.switchToHttp().getRequest();
return request.user as ActiveUserPayload;
},
);

View File

@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { FabricService } from './fabric.service';
@Module({
providers: [FabricService],
exports: [FabricService],
})
export class FabricModule {}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { FabricService } from './fabric.service';
describe('FabricService', () => {
let service: FabricService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [FabricService],
}).compile();
service = module.get<FabricService>(FabricService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,39 @@
import FabricGateway from '@api/common/fabric-gateway';
import {
Injectable,
Logger,
OnApplicationShutdown,
OnModuleInit,
} from '@nestjs/common';
@Injectable()
export class FabricService implements OnModuleInit, OnApplicationShutdown {
private readonly logger = new Logger(FabricService.name);
private readonly gateway = new FabricGateway();
async onModuleInit() {
this.logger.log('Attempting to connect to Fabric network...');
try {
await this.gateway.connect();
this.logger.log('Successfully connected to Fabric network.');
} catch (error) {
this.logger.error('Failed to connect to Fabric network:', error);
throw new Error('Failed to connect to Fabric network');
}
}
async onApplicationShutdown(signal?: string) {
this.logger.log('Disconnecting from Fabric network...');
await this.gateway.disconnect();
}
async storeLog(id: string, event: string, user_id: string, payload: string) {
this.logger.log(`Storing log with ID: ${id}`);
return this.gateway.storeLog(id, event, user_id, payload);
}
async getLogById(id: string) {
this.logger.log(`Retrieving log with ID: ${id}`);
return this.gateway.getLogById(id);
}
}

View File

@ -1,6 +1,17 @@
import { IsString, IsNotEmpty, Length, IsJSON, IsEnum } from 'class-validator';
import {
IsString,
IsNotEmpty,
Length,
IsJSON,
IsEnum,
IsNumber,
} from 'class-validator';
export class StoreLogDto {
@IsNotEmpty({ message: 'ID wajib diisi' })
@IsString({ message: 'ID harus berupa string' })
id: string;
export class CreateLogDto {
@IsNotEmpty({ message: 'Event wajib diisi' })
@IsString({ message: 'Event harus berupa string' })
@IsEnum(
@ -22,19 +33,11 @@ export class CreateLogDto {
@Length(1, 100, { message: 'Event maksimal 100 karakter' })
event: string;
@IsNotEmpty({ message: 'User ID wajib diisi' })
@IsNumber({}, { message: 'User ID harus berupa angka' })
user_id: number;
@IsNotEmpty({ message: 'Payload wajib diisi' })
@IsJSON({ message: 'Payload harus berupa JSON yang valid' })
payload: {
dokter_id: number;
visit_id: string;
tindakan?: string;
kategori_tindakan?: string;
kelompok_tindakan?: string;
obat?: string;
jumlah_obat?: number;
aturan_pakai?: string;
anamnese?: string;
jenis_kasus?: string;
tindak_lanjut?: string;
};
@IsString({ message: 'Payload harus berupa string' })
payload: string;
}

View File

@ -1,4 +1,27 @@
import { Controller } from '@nestjs/common';
import { Body, Controller, Get, Param, Post } from '@nestjs/common';
import { StoreLogDto } from './dto/store-log.dto';
import { LogService } from './log.service';
import { FabricService } from '../fabric/fabric.service';
@Controller('log')
export class LogController {}
export class LogController {
constructor(
private readonly logService: LogService,
private readonly fabricService: FabricService,
) {}
// @Post()
// storeLog(@Body() dto: StoreLogDto) {
// return this.logService.storeLog(dto);
// }
// @Get(':id')
// getLogById(@Param('id') id: string) {
// return this.logService.getLogById(id);
// }
// @Get()
// getAllLogs() {
// return this.logService.getAllLogs();
// }
}

View File

@ -1,9 +1,12 @@
import { Module } from '@nestjs/common';
import { LogController } from './log.controller';
import { LogService } from './log.service';
import { FabricModule } from '../fabric/fabric.module';
@Module({
imports: [FabricModule],
controllers: [LogController],
providers: [LogService]
providers: [LogService],
exports: [LogService],
})
export class LogModule {}

View File

@ -1,4 +1,20 @@
import { Injectable } from '@nestjs/common';
import { StoreLogDto } from './dto/store-log.dto';
import { FabricService } from '../fabric/fabric.service';
@Injectable()
export class LogService {}
export class LogService {
constructor(private readonly fabricService: FabricService) {}
async storeLog(dto: StoreLogDto) {
const { id, event, user_id, payload } = dto;
return this.fabricService.storeLog(id, event, user_id.toString(), payload);
}
async getLogById(id: string) {
const result = await this.fabricService.getLogById(id);
return result;
}
async getAllLogs() {
// return this.fabricService.getAllLogs();
}
}

View File

@ -0,0 +1,22 @@
import { IsString, IsNotEmpty, IsInt, Min, Length } from 'class-validator';
import { Transform } from 'class-transformer';
export class CreateObatDto {
@IsNotEmpty({ message: 'ID Visit wajib diisi' })
@IsString()
id_visit: string;
@IsNotEmpty({ message: 'Obat wajib diisi' })
@IsString()
@Length(1, 100, { message: 'Obat maksimal 100 karakter' })
obat: string;
@IsNotEmpty({ message: 'Jumlah obat wajib diisi' })
@IsInt({ message: 'Jumlah obat harus berupa angka bulat' })
@Min(1, { message: 'Jumlah obat minimal 1' })
@Transform(({ value }) => (value ? parseInt(value) : null))
jumlah_obat: number;
@IsString()
aturan_pakai: string;
}

View File

@ -0,0 +1,8 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateObatDto } from './create-obat-dto';
import { IsOptional } from 'class-validator';
export class UpdateObatDto extends PartialType(CreateObatDto) {
@IsOptional()
id_visit?: string;
}

View File

@ -1,6 +1,19 @@
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
import {
Body,
Controller,
Get,
Param,
Post,
Put,
Query,
UseGuards,
} from '@nestjs/common';
import { ObatService } from './obat.service';
import { AuthGuard } from '../auth/guard/auth.guard';
import { UpdateObatDto } from './dto/update-obat-dto';
import { CurrentUser } from '../auth/decorator/current-user.decorator';
import type { ActiveUserPayload } from '../auth/decorator/current-user.decorator';
import { CreateObatDto } from './dto/create-obat-dto';
@Controller('obat')
export class ObatController {
@ -25,4 +38,35 @@ export class ObatController {
order,
});
}
@Get(':id')
@UseGuards(AuthGuard)
async getObatById(@Param('id') id: number) {
return await this.obatService.getObatById(id);
}
@Post('/')
@UseGuards(AuthGuard)
async createObat(
@Body() dto: CreateObatDto,
@CurrentUser() user: ActiveUserPayload,
) {
return await this.obatService.createObat(dto, user);
}
@Put(':id')
@UseGuards(AuthGuard)
async updateObatById(
@Param('id') id: number,
@Body() dto: UpdateObatDto,
@CurrentUser() user: ActiveUserPayload,
) {
return await this.obatService.updateObatById(id, dto, user);
}
@Get('/:id/log')
@UseGuards(AuthGuard)
async getObatLogs(@Param('id') id: string) {
return await this.obatService.getLogObatById(id);
}
}

View File

@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
import { ObatController } from './obat.controller';
import { ObatService } from './obat.service';
import { PrismaModule } from '../prisma/prisma.module';
import { LogModule } from '../log/log.module';
@Module({
imports: [PrismaModule],
imports: [PrismaModule, LogModule],
controllers: [ObatController],
providers: [ObatService],
})

View File

@ -1,9 +1,42 @@
import { Injectable } from '@nestjs/common';
import { BadRequestException, Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { UpdateObatDto } from './dto/update-obat-dto';
import { LogService } from '../log/log.service';
import { sha256 } from '@api/common/crypto/hash';
import { ActiveUserPayload } from '../auth/decorator/current-user.decorator';
import { CreateObatDto } from './dto/create-obat-dto';
@Injectable()
export class ObatService {
constructor(private prisma: PrismaService) {}
constructor(
private prisma: PrismaService,
private logService: LogService,
) {}
createHashingPayload(currentData: any): string {
return sha256(JSON.stringify(currentData));
}
determineStatus(rawFabricLog: any, index: number, arrLength: number): any {
console.log('Inside determineStatus with index:', index);
console.log('Raw Fabric Log:', rawFabricLog);
const flatLog = {
...rawFabricLog.value,
txId: rawFabricLog.txId,
timestamp: rawFabricLog.value.timestamp,
};
if (
index === arrLength - 1 &&
rawFabricLog.value.event === 'obat_created'
) {
flatLog.status = 'ORIGINAL';
} else {
flatLog.status = 'UPDATED';
}
return flatLog;
}
async getAllObat(params: {
take?: number;
@ -43,4 +76,111 @@ export class ObatService {
totalCount: count,
};
}
async getObatById(id: number) {
return await this.prisma.pemberian_obat.findUnique({
where: {
id: id,
},
});
}
async getLogObatById(id: string) {
const idLog = `OBAT_${id}`;
const rawLogs = await this.logService.getLogById(idLog);
const currentData = await this.getObatById(parseInt(id, 10));
if (!currentData) {
throw new Error(`Obat with id ${id} not found`);
}
const currentDataHash = this.createHashingPayload({
obat: currentData.obat,
jumlah_obat: currentData.jumlah_obat,
aturan_pakai: currentData.aturan_pakai,
});
const latestPayload = rawLogs[0].value.payload;
const isTampered = currentDataHash !== latestPayload;
const chronologicalLogs = [...rawLogs];
const processedLogs = chronologicalLogs.map((log, index) => {
return this.determineStatus(log, index, chronologicalLogs.length);
});
return {
logs: processedLogs,
isTampered: isTampered,
currentDataHash: currentDataHash,
};
}
async createObat(dto: CreateObatDto, user: ActiveUserPayload) {
const visitExists = await this.prisma.rekam_medis.findUnique({
where: { id_visit: dto.id_visit },
});
if (!visitExists) {
throw new BadRequestException(`Visit with id ${dto.id_visit} not found`);
}
const res = await this.prisma.pemberian_obat.create({
data: {
id_visit: dto.id_visit,
obat: dto.obat,
jumlah_obat: dto.jumlah_obat,
aturan_pakai: dto.aturan_pakai,
},
});
console.log('Created Obat:', dto);
const logPayload = JSON.stringify(dto);
const payloadHash = sha256(logPayload);
const data = {
id: `OBAT_${res.id}`,
event: 'obat_created',
user_id: user.sub,
payload: payloadHash,
};
const logResult = await this.logService.storeLog(data);
return {
...res,
...logResult,
};
}
async updateObatById(
id: number,
dto: UpdateObatDto,
user: ActiveUserPayload,
) {
const res = await this.prisma.pemberian_obat.update({
where: {
id: id,
},
data: {
obat: dto.obat,
jumlah_obat: dto.jumlah_obat,
aturan_pakai: dto.aturan_pakai,
},
});
console.log('Updated Obat:', dto);
const logPayload = JSON.stringify(dto);
const payloadHash = sha256(logPayload);
const data = {
id: `OBAT_${id}`,
event: 'obat_updated',
user_id: user.sub,
payload: payloadHash,
};
const logResult = await this.logService.storeLog(data);
return {
...res,
...logResult,
};
}
}

View File

@ -0,0 +1,18 @@
import { IsEnum, IsNumber, IsString } from 'class-validator';
export class PayloadRekamMedisDto {
@IsNumber({}, { message: 'ID dokter harus berupa angka' })
dokter_id: number;
@IsString({ message: 'ID kunjungan harus berupa string' })
visit_id: string;
@IsEnum({}, { message: 'Anamnese harus berupa enum' })
anamnese: string;
@IsEnum({}, { message: 'Jenis kasus harus berupa enum' })
jenis_kasus: string;
@IsEnum({}, { message: 'Tindak lanjut harus berupa enum' })
tindak_lanjut: string;
}

View File

@ -4,13 +4,17 @@ import {
Get,
Header,
HttpCode,
Param,
Post,
Put,
Query,
UseGuards,
} from '@nestjs/common';
import { RekammedisService } from './rekammedis.service';
import { CreateRekamMedisDto } from './dto/create-rekammedis.dto';
import { AuthGuard } from '../auth/guard/auth.guard';
import { CurrentUser } from '../auth/decorator/current-user.decorator';
import type { ActiveUserPayload } from '../auth/decorator/current-user.decorator';
@Controller('/rekammedis')
export class RekamMedisController {
@ -58,10 +62,40 @@ export class RekamMedisController {
});
}
@Get('/:id_visit')
@Header('Content-Type', 'application/json')
@HttpCode(200)
@UseGuards(AuthGuard)
async getRekamMedisById(@Param('id_visit') id_visit: string) {
return this.rekammedisService.getRekamMedisById(id_visit);
}
@Post('/')
@Header('Content-Type', 'application/json')
@UseGuards(AuthGuard)
async createRekamMedis(@Body() dto: CreateRekamMedisDto) {
return this.rekammedisService.createRekamMedis(dto);
async createRekamMedis(
@Body() dto: CreateRekamMedisDto,
@CurrentUser() user: ActiveUserPayload,
) {
return this.rekammedisService.createRekamMedis(dto, user);
}
@Get('/:id_visit/log')
@Header('Content-Type', 'application/json')
@HttpCode(200)
@UseGuards(AuthGuard)
async getRekamMedisLogById(@Param('id_visit') id_visit: string) {
return this.rekammedisService.getRekamMedisLogById(id_visit);
}
@Put('/:id_visit')
@Header('Content-Type', 'application/json')
@UseGuards(AuthGuard)
async updateRekamMedis(
@Param('id_visit') id_visit: string,
@Body() dto: CreateRekamMedisDto,
@CurrentUser() user: ActiveUserPayload,
) {
return this.rekammedisService.updateRekamMedis(id_visit, dto, user);
}
}

View File

@ -3,9 +3,10 @@ import { RekamMedisController } from './rekammedis.controller';
import { RekammedisService } from './rekammedis.service';
import { PrismaModule } from '../prisma/prisma.module';
import { JwtModule } from '@nestjs/jwt';
import { LogModule } from '../log/log.module';
@Module({
imports: [PrismaModule],
imports: [PrismaModule, LogModule],
controllers: [RekamMedisController],
providers: [RekammedisService],
})

View File

@ -2,11 +2,14 @@ import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { Prisma, rekam_medis } from '@dist/generated/prisma';
import { CreateRekamMedisDto } from './dto/create-rekammedis.dto';
import { CreateLogDto } from '../log/dto/create-log.dto';
import { LogService } from '../log/log.service';
import { sha256 } from '@api/common/crypto/hash';
import { ActiveUserPayload } from '../auth/decorator/current-user.decorator';
import { PayloadRekamMedisDto } from './dto/payload-rekammedis.dto';
// import { CreateLogDto } from '../log/dto/create-log.dto';
@Injectable()
export class RekammedisService {
// Define known values as constants to avoid hardcoding everywhere
private readonly KNOWN_BLOOD_TYPES = ['A', 'B', 'AB', 'O'];
private readonly KNOWN_TINDAK_LANJUT = [
'Dipulangkan untuk Kontrol',
@ -26,7 +29,35 @@ export class RekammedisService {
'Selesai Pelayanan Rawat Jalan',
];
constructor(private prisma: PrismaService) {}
constructor(
private prisma: PrismaService,
private log: LogService,
) {}
createHashingPayload(currentData: PayloadRekamMedisDto): string {
return sha256(JSON.stringify(currentData));
}
determineStatus(rawFabricLog: any, index: number, arrLength: number): any {
const flatLog = {
...rawFabricLog.value,
txId: rawFabricLog.txId,
timestamp: rawFabricLog.value.timestamp,
};
console.log('Processed flat log:', flatLog);
if (
index === arrLength - 1 &&
rawFabricLog.value.event === 'rekam_medis_created'
) {
flatLog.status = 'ORIGINAL';
} else {
flatLog.status = 'UPDATED';
}
return flatLog;
}
async getAllRekamMedis(params: {
take?: number;
@ -58,13 +89,18 @@ export class RekammedisService {
tanggal_end,
umur_min,
umur_max,
jenis_kelamin,
kode_diagnosa,
} = params;
const golDarahArray = params.gol_darah?.split(',') || [];
const tindakLanjutArray = params.tindak_lanjut?.split(',') || [];
console.log('Params Received:', params);
const jkCharacter =
params.jenis_kelamin == 'perempuan'
? 'P'
: params.jenis_kelamin == 'laki-laki'
? 'L'
: '';
const take = params.take ? parseInt(params.take.toString()) : 10;
const skipValue = skip
? parseInt(skip.toString())
@ -158,7 +194,7 @@ export class RekammedisService {
lte: parseInt(umur_max, 10),
}
: undefined,
jenis_kelamin: jenis_kelamin ? { equals: jenis_kelamin } : undefined,
jenis_kelamin: jkCharacter ? { equals: jkCharacter } : undefined,
kode_diagnosa: kode_diagnosa ? { contains: kode_diagnosa } : undefined,
...golDarahFilter,
...tindakLanjutFilter,
@ -169,7 +205,7 @@ export class RekammedisService {
take: take,
where: whereClause,
orderBy: orderBy
? { [orderBy]: order || 'asc' }
? { [orderBy]: order || 'desc' }
: { waktu_visit: order ? order : 'asc' },
});
@ -209,7 +245,13 @@ export class RekammedisService {
};
}
async createRekamMedis(data: CreateRekamMedisDto) {
async getRekamMedisById(id_visit: string) {
return this.prisma.rekam_medis.findUnique({
where: { id_visit },
});
}
async createRekamMedis(data: CreateRekamMedisDto, user: ActiveUserPayload) {
const latestId = await this.prisma.rekam_medis.findFirst({
orderBy: { waktu_visit: 'desc' },
});
@ -239,7 +281,7 @@ export class RekammedisService {
waktu_visit: new Date(),
};
const logData: CreateLogDto = {
const logData = {
event: 'rekam_medis_created',
payload: {
dokter_id: 123,
@ -256,17 +298,21 @@ export class RekammedisService {
data: rekamMedis,
});
await tx.blockchain_log_queue.create({
data: {
event: logData.event,
user_id: 9,
payload: logData.payload,
},
});
const logPayload = JSON.stringify(logData.payload);
const payloadHash = sha256(logPayload);
const data = {
id: `REKAM_${newId}`,
event: 'rekam_medis_created',
user_id: user.sub,
payload: payloadHash,
};
// Input Into Fabric Here
const createdLog = await this.log.storeLog(data);
return createdRekamMedis;
return {
...createdRekamMedis,
log: createdLog,
};
});
return newRekamMedis;
@ -275,4 +321,76 @@ export class RekammedisService {
throw error;
}
}
async getRekamMedisLogById(id_visit: string) {
const idLog = `REKAM_${id_visit}`;
const rawLogs = await this.log.getLogById(idLog);
const currentData = await this.getRekamMedisById(id_visit);
if (!currentData) {
throw new Error(`Rekam Medis with id_visit ${id_visit} not found`);
}
const currentDataHash = this.createHashingPayload({
dokter_id: 123,
visit_id: currentData.id_visit,
anamnese: currentData.anamnese ?? '',
jenis_kasus: currentData.jenis_kasus ?? '',
tindak_lanjut: currentData.tindak_lanjut ?? '',
});
const latestPayload = rawLogs[0].value.payload;
const isTampered = currentDataHash !== latestPayload;
const chronologicalLogs = [...rawLogs];
const processedLogs = chronologicalLogs.map((log, index) => {
return this.determineStatus(log, index, chronologicalLogs.length);
});
return {
logs: processedLogs,
isTampered: isTampered,
currentDataHash: currentDataHash,
};
}
async updateRekamMedis(
id_visit: string,
data: CreateRekamMedisDto,
user: ActiveUserPayload,
) {
const rekamMedis = await this.prisma.rekam_medis.update({
where: { id_visit },
data: {
...data,
},
});
const logData = {
event: 'rekam_medis_updated',
payload: {
dokter_id: 123,
visit_id: id_visit,
anamnese: data.anamnese,
jenis_kasus: data.jenis_kasus,
tindak_lanjut: data.tindak_lanjut,
},
};
const logPayload = JSON.stringify(logData.payload);
const payloadHash = sha256(logPayload);
const logDto = {
id: `REKAM_${id_visit}`,
event: 'rekam_medis_updated',
user_id: user.sub,
payload: payloadHash,
};
const createdLog = await this.log.storeLog(logDto);
return {
...rekamMedis,
log: createdLog,
};
}
}

View File

@ -18,15 +18,22 @@ export class TindakanDokterController {
@UseGuards(AuthGuard)
async getAllTindakanDokter(
@Query('take') take: number,
@Query('id_visit') id_visit: string,
@Query('tindakan') tindakan: string,
@Query('kelompok') kelompok_tindakan: string,
@Query('kategori') kategori_tindakan: string,
@Query('skip') skip: number,
@Query('page') page: number,
@Query('orderBy') orderBy: string,
@Query('order') order: 'asc' | 'desc',
) {
console.log();
return await this.tindakanDokterService.getAllTindakanDokter({
take,
id_visit,
tindakan,
kelompok_tindakan,
kategori_tindakan,
skip,
page,
orderBy: orderBy ? { [orderBy]: order || 'asc' } : undefined,

View File

@ -10,28 +10,75 @@ export class TindakanDokterService {
skip?: number;
take?: number;
page?: number;
id_visit?: string;
kelompok_tindakan?: string;
kategori_tindakan?: string;
tindakan?: string;
orderBy?: Prisma.pemberian_tindakanOrderByWithRelationInput;
order?: 'asc' | 'desc';
}) {
const { skip, page, tindakan, orderBy, order } = params;
const {
skip,
page,
tindakan,
orderBy,
order,
id_visit,
kelompok_tindakan,
kategori_tindakan,
} = params;
const take = params.take ? parseInt(params.take.toString()) : 10;
const kelompok_tindakanArray = params.kelompok_tindakan
? params.kelompok_tindakan.split(',')
: [];
const kategori_tindakanArray = params.kategori_tindakan
? params.kategori_tindakan.split(',')
: [];
const skipValue = skip
? parseInt(skip.toString())
: page
? (parseInt(page.toString()) - 1) * take
: 0;
console.log('Kelompok Tindakan Array:', kelompok_tindakanArray);
console.log('Kategori Tindakan Array:', kategori_tindakanArray);
const results = await this.prisma.pemberian_tindakan.findMany({
skip: skipValue,
take: take,
where: {
tindakan: tindakan ? { contains: tindakan } : undefined,
id_visit: id_visit ? { contains: id_visit } : undefined,
kelompok_tindakan:
kelompok_tindakanArray.length > 0
? { in: kelompok_tindakanArray }
: undefined,
kategori_tindakan:
kategori_tindakanArray.length > 0
? { in: kategori_tindakanArray }
: undefined,
},
orderBy: orderBy
? { [Object.keys(orderBy)[0]]: order || 'asc' }
: undefined,
});
return results;
const count = await this.prisma.pemberian_tindakan.count({
where: {
tindakan: tindakan ? { contains: tindakan } : undefined,
id_visit: id_visit ? { contains: id_visit } : undefined,
kelompok_tindakan:
kelompok_tindakanArray.length > 0
? { in: kelompok_tindakanArray }
: undefined,
kategori_tindakan:
kategori_tindakanArray.length > 0
? { in: kategori_tindakanArray }
: undefined,
},
});
return {
...results,
totalCount: count,
};
}
}

View File

@ -37,8 +37,12 @@ export class UserController {
@UseGuards(AuthGuard, RolesGuard)
@Roles(UserRole.Admin)
@HttpCode(200)
getAllUsers(): Promise<QueryUsersResponseDto[]> {
return this.userService.getAllUsers();
getAllUsers(
@Query('username') username: string,
@Query('page') page: number,
@Query('take') take: number,
) {
return this.userService.getAllUsers({ username, page, take: take });
}
@Get('/set-cookie')

View File

@ -6,9 +6,32 @@ import { UserRole } from '../auth/dto/auth.dto';
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
async getAllUsers(): Promise<QueryUsersResponseDto[]> {
const users = await this.prisma.users.findMany();
return users.map((user) => ({
async getAllUsers(params: {
username?: string;
take?: number;
skip?: number;
page?: number;
orderBy?: any;
order?: 'asc' | 'desc';
}) {
const { username, skip, page } = params;
console.log('Fetching users with filter:', username);
const take = params.take ? parseInt(params.take.toString()) : 10;
const skipValue = skip
? parseInt(skip.toString())
: page
? (parseInt(page.toString()) - 1) * take
: 0;
const users = await this.prisma.users.findMany({
where: {
username: {
contains: username,
mode: 'insensitive',
},
},
});
const count = await this.prisma.users.count();
const usersResponse = users.map((user) => ({
id: user.id,
name: user.nama_lengkap,
username: user.username,
@ -16,5 +39,9 @@ export class UserService {
created_at: user.created_at || undefined,
updated_at: user.updated_at || undefined,
}));
return {
...usersResponse,
totalCount: count,
};
}
}

3
backend/blockchain/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules/*
channel-artifacts/*
organizations/*

View File

@ -0,0 +1,5 @@
#
# SPDX-License-Identifier: Apache-2.0
#
coverage

View File

@ -0,0 +1,39 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/
module.exports = {
env: {
node: true,
mocha: true,
es6: true
},
parserOptions: {
ecmaVersion: 8,
sourceType: 'script'
},
extends: "eslint:recommended",
rules: {
indent: ['error', 4],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always'],
'no-unused-vars': ['error', { args: 'none' }],
'no-console': 'off',
curly: 'error',
eqeqeq: 'error',
'no-throw-literal': 'error',
strict: 'error',
'no-var': 'error',
'dot-notation': 'error',
'no-tabs': 'error',
'no-trailing-spaces': 'error',
'no-use-before-define': 'error',
'no-useless-call': 'error',
'no-with': 'error',
'operator-linebreak': 'error',
yoda: 'error',
'quote-props': ['error', 'as-needed'],
'no-constant-condition': ["error", { "checkLoops": false }]
}
};

View File

@ -0,0 +1,15 @@
#
# SPDX-License-Identifier: Apache-2.0
#
# Coverage directory used by tools like istanbul
coverage
# Report cache used by istanbul
.nyc_output
# Dependency directories
node_modules/
jspm_packages/
package-lock.json

View File

@ -0,0 +1,6 @@
'use strict';
const logVerification = require('./lib/logVerification');
module.exports.LogVerification = logVerification;
module.exports.contracts = [logVerification];

View File

@ -0,0 +1,155 @@
"use strict";
const stringify = require("json-stringify-deterministic");
const sortKeysRecursive = require("sort-keys-recursive");
const { Contract } = require("fabric-contract-api");
const timestampToISOString = (timestamp) => {
if (!timestamp) {
return undefined;
}
const seconds =
typeof timestamp.seconds?.toInt === "function"
? timestamp.seconds.toInt()
: Number(timestamp.seconds || 0);
const millis = seconds * 1000 + Math.floor((timestamp.nanos || 0) / 1e6);
return new Date(millis).toISOString();
};
class LogVerification extends Contract {
async beforeTransaction(ctx) {
this.TxId = ctx.stub.getTxID();
console.log(`Transaction ID: ${this.TxId}`);
}
async InitLedger(ctx) {
const logs = [
{
id: "TINDAKAN_01",
event: "Tindakan Dokter",
user_id: "1",
payload: "hash1",
timestamp: "2023-10-01T09:00:00Z",
},
{
id: "OBAT_01",
event: "Pemberian Obat",
user_id: "1",
payload: "hash1",
timestamp: "2023-10-01T09:00:00Z",
},
];
for (const log of logs) {
await ctx.stub.putState(
log.id,
Buffer.from(stringify(sortKeysRecursive(log)))
);
}
}
async storeLog(ctx, id, event, user_id, payload) {
if (!id || !event || !user_id || !payload) {
throw new Error("All parameters must be provided and non-empty");
}
const txTimestamp = ctx.stub.getTxTimestamp();
const timestamp = timestampToISOString(txTimestamp);
const log = {
id: id,
event: event,
user_id: user_id,
payload: payload,
timestamp: timestamp,
};
try {
await ctx.stub.putState(
id,
Buffer.from(stringify(sortKeysRecursive(log)))
);
return stringify({
success: true,
message: `Log ${id} stored successfully`,
});
} catch (error) {
throw new Error(`Failed to store log: ${error}`);
}
}
async getLogById(ctx, id) {
const iterator = await ctx.stub.getHistoryForKey(id);
const logs = [];
try {
while (true) {
const res = await iterator.next();
if (res.value && res.value.value.length > 0) {
const payload = res.value.value.toString("utf8");
logs.push({
txId: res.value.txId,
value: JSON.parse(payload),
});
}
if (res.done) {
break;
}
}
} finally {
await iterator.close();
}
if (logs.length === 0) {
throw new Error(`Log ${id} does not exist`);
}
return logs;
}
async deleteLogById(ctx, id) {
const exists = await this.logExists(ctx, id);
if (!exists) {
throw new Error(`Log ${id} does not exist`);
}
await ctx.stub.deleteState(id);
}
async getAllLogs(ctx) {
const allResults = [];
const iterator = await ctx.stub.getStateByRange("", "");
try {
while (true) {
const result = await iterator.next();
if (result.value && result.value.value.length > 0) {
const strValue = result.value.value.toString("utf8");
try {
allResults.push(JSON.parse(strValue));
} catch (err) {
console.log(err);
allResults.push(strValue);
}
}
if (result.done) {
break;
}
}
} finally {
await iterator.close();
}
return allResults;
}
async logExists(ctx, id) {
const logJSON = await ctx.stub.getState(id);
return logJSON && logJSON.length > 0;
}
async afterTransaction(ctx, result) {
console.log(`Transaction ${this.TxId} has been committed.`);
}
}
module.exports = LogVerification;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
{
"name": "log-verification",
"version": "1.0.0",
"description": "Log Verification contract implemented in JavaScript",
"main": "index.js",
"engines": {
"node": ">=20"
},
"scripts": {
"lint": "eslint *.js */**.js",
"pretest": "npm run lint",
"test": "nyc mocha --recursive",
"start": "fabric-chaincode-node start"
},
"engineStrict": true,
"author": "Hyperledger",
"license": "Apache-2.0",
"dependencies": {
"fabric-contract-api": "^2.5.8",
"fabric-shim": "^2.5.8",
"json-stringify-deterministic": "^1.0.0",
"sort-keys-recursive": "^2.1.0"
},
"devDependencies": {
"chai": "^4.4.1",
"eslint": "^8.57.0",
"mocha": "^10.4.0",
"nyc": "^15.1.0",
"sinon": "^18.0.0",
"sinon-chai": "^3.7.0"
},
"nyc": {
"exclude": [
"coverage/**",
"test/**",
"index.js",
".eslintrc.js"
],
"reporter": [
"text-summary",
"html"
],
"all": true,
"check-coverage": true,
"statements": 100,
"branches": 100,
"functions": 100,
"lines": 100
}
}

View File

@ -0,0 +1,25 @@
#!/bin/bash
export FABRIC_CFG_PATH=${PWD}/network/config/
rm -rf ./network/organizations ./network/channel-artifacts
mkdir -p ./network/channel-artifacts
cryptogen generate --config=./network/config/crypto-config.yaml --output=./network/organizations
if [ "$?" -ne 0 ]; then
echo "Failed to generate certificates..."
exit 1
fi
echo "--- Generating genesis block for Hospital profile ---"
configtxgen -profile HospitalGenesis -outputBlock ./network/channel-artifacts/genesis.block -channelID system-channel
if [ "$?" -ne 0 ]; then
echo "Failed to generate genesis block..."
exit 1
fi
configtxgen -profile HospitalChannel -outputCreateChannelTx ./network/channel-artifacts/mychannel.tx -channelID mychannel
if [ "$?" -ne 0 ]; then
echo "Failed to generate channel transaction..."
exit 1
fi

View File

@ -0,0 +1,11 @@
[
{
"name": "HospitalPrivateCollection",
"policy": "OR('HospitalMSP.member')",
"requiredPeerCount": 1,
"maxPeerCount": 3,
"blockToLive": 1000000,
"memberOnlyRead": true,
"memberOnlyWrite": true
}
]

View File

@ -0,0 +1,179 @@
---
################################################################################
#
# Bagian: Organisasi
#
# - Bagian ini berisi mengenai pendefinisian organisasi yang akan digunakan
# dalam konfigurasi jaringan kemudian
#
################################################################################
Organizations:
# !PENTING! pastikan terdapat minimal 2 organisasi, orderer dan peer.
- &OrdererOrg
Name: OrdererOrg
ID: OrdererMSP
MSPDir: ../organizations/ordererOrganizations/hospital.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Writers:
Type: Signature
Rule: "OR('OrdererMSP.member')"
Admins:
Type: Signature
Rule: "OR('OrdererMSP.admin')"
OrdererEndpoints:
# OrdererEndpoints berisi IP atau domain beserta port yang digunakan
# Jika menjalankan dalam environment lokal seperti WSL, dapat menggunakan
# orderer.example.com:7050 sebagai domain endpoints sesuai dengan dokumentasi
- "orderer.hospital.com:7050"
- &Hospital
Name: HospitalMSP
ID: HospitalMSP
MSPDir: ../organizations/peerOrganizations/hospital.com/msp
Policies:
Readers:
Type: Signature
Rule: "OR('HospitalMSP.admin', 'HospitalMSP.peer', 'HospitalMSP.client')"
Writers:
Type: Signature
Rule: "OR('HospitalMSP.admin', 'HospitalMSP.client')"
Admins:
Type: Signature
Rule: "OR('HospitalMSP.admin')"
Endorsement:
Type: Signature
Rule: "OR('HospitalMSP.peer')"
AnchorPeers:
- Host: peer0.hospital.com
Port: 7051
# Default
Capabilities:
Channel: &ChannelCapabilities
V2_0: true
Orderer: &OrdererCapabilities
V2_0: true
Application: &ApplicationCapabilities
V2_5: true
# Default
Application: &ApplicationDefaults
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
LifecycleEndorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Endorsement:
Type: ImplicitMeta
Rule: "MAJORITY Endorsement"
Capabilities:
<<: *ApplicationCapabilities
################################################################################
#
# Bagian: Orderer
#
# - Bagian ini berisi mengenai konfigurasi orderer yang akan digunakan
# dalam konfigurasi transaksi jaringan atau genesis block terkait parameter
# orderer yang digunakan.
#
################################################################################
Orderer:
&OrdererDefaults # Berisi konfigurasi untuk konsensus Raft, sesuaikan dengan orderer yang digunakan
OrdererType: etcdraft
Addresses:
# Daftar alamat orderer yang digunakan dalam jaringan, dapat menggunakan
# IP atau domain sama seperti yang digunakan pada bagian OrdererEndpoints.
- "orderer.hospital.com:7050"
BatchTimeout: 2s
BatchSize:
MaxMessageCount: 10
AbsoluteMaxBytes: 99 MB
PreferredMaxBytes: 512 KB
EtcdRaft:
Consenters:
- Host: orderer.hospital.com
Port: 7050
ClientTLSCert: ../organizations/ordererOrganizations/hospital.com/orderers/orderer.hospital.com/tls/server.crt
ServerTLSCert: ../organizations/ordererOrganizations/hospital.com/orderers/orderer.hospital.com/tls/server.crt
Organizations:
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
BlockValidation:
Type: ImplicitMeta
Rule: "ANY Writers"
# Default
Channel: &ChannelDefaults
Policies:
Readers:
Type: ImplicitMeta
Rule: "ANY Readers"
Writers:
Type: ImplicitMeta
Rule: "ANY Writers"
Admins:
Type: ImplicitMeta
Rule: "MAJORITY Admins"
Capabilities:
- *ChannelCapabilities
################################################################################
#
# Profile
#
# - Bagian ini berisi mengenai konfigurasi profil yang akan digunakan sebagai
# parameter pada configtxgen tool untuk menghasilkan genesis block dan channel.
#
################################################################################
Profiles:
HospitalGenesis:
<<: *ChannelDefaults
Orderer:
# Menggunakan konfigurasi yang telah didefinisikan sebelumnya
<<: *OrdererDefaults
Organizations:
# Menggunakan organisasi orderer yang telah didefinisikan sebelumnya
- *OrdererOrg
Capabilities: *OrdererCapabilities
Consortiums:
SampleConsortium:
Organizations:
# Sesuaikan jumlah organisasi yang digunakan dalam konsorsium
- *Hospital
Application:
<<: *ApplicationDefaults
Organizations:
# Sesuaikan organisasi yang digunakan dalam aplikasi
- *Hospital
Capabilities: *ApplicationCapabilities
HospitalChannel:
Consortium: SampleConsortium
<<: *ChannelDefaults
Application:
<<: *ApplicationDefaults
Organizations:
- *Hospital
Capabilities:
- *ApplicationCapabilities

View File

@ -0,0 +1,791 @@
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
###############################################################################
#
# Peer section
#
###############################################################################
peer:
# The peer id provides a name for this peer instance and is used when
# naming docker resources.
id: hospital-peer0
# The networkId allows for logical separation of networks and is used when
# naming docker resources.
networkId: dev
# The Address at local network interface this Peer will listen on.
# By default, it will listen on all network interfaces
listenAddress: 0.0.0.0:7051
# The endpoint this peer uses to listen for inbound chaincode connections.
# If this is commented-out, the listen address is selected to be
# the peer's address (see below) with port 7052
# chaincodeListenAddress: 0.0.0.0:7052
# The endpoint the chaincode for this peer uses to connect to the peer.
# If this is not specified, the chaincodeListenAddress address is selected.
# And if chaincodeListenAddress is not specified, address is selected from
# peer address (see below). If specified peer address is invalid then it
# will fallback to the auto detected IP (local IP) regardless of the peer
# addressAutoDetect value.
# chaincodeAddress: 0.0.0.0:7052
# When used as peer config, this represents the endpoint to other peers
# in the same organization. For peers in other organization, see
# gossip.externalEndpoint for more info.
# When used as CLI config, this means the peer's endpoint to interact with
address: 0.0.0.0:7051
# Whether the Peer should programmatically determine its address
# This case is useful for docker containers.
# When set to true, will override peer address.
addressAutoDetect: false
# Settings for the Peer's gateway server.
gateway:
# Whether the gateway is enabled for this Peer.
enabled: true
# endorsementTimeout is the duration the gateway waits for a response
# from other endorsing peers before returning a timeout error to the client.
endorsementTimeout: 30s
# broadcastTimeout is the duration the gateway waits for a response
# from ordering nodes before returning a timeout error to the client.
broadcastTimeout: 30s
# dialTimeout is the duration the gateway waits for a connection
# to other network nodes.
dialTimeout: 2m
# Keepalive settings for peer server and clients
keepalive:
# Interval is the duration after which if the server does not see
# any activity from the client it pings the client to see if it's alive
interval: 7200s
# Timeout is the duration the server waits for a response
# from the client after sending a ping before closing the connection
timeout: 20s
# MinInterval is the minimum permitted time between client pings.
# If clients send pings more frequently, the peer server will
# disconnect them
minInterval: 60s
# Client keepalive settings for communicating with other peer nodes
client:
# Interval is the time between pings to peer nodes. This must
# greater than or equal to the minInterval specified by peer
# nodes
interval: 60s
# Timeout is the duration the client waits for a response from
# peer nodes before closing the connection
timeout: 20s
# DeliveryClient keepalive settings for communication with ordering
# nodes.
deliveryClient:
# Interval is the time between pings to ordering nodes. This must
# greater than or equal to the minInterval specified by ordering
# nodes.
interval: 60s
# Timeout is the duration the client waits for a response from
# ordering nodes before closing the connection
timeout: 20s
# Gossip related configuration
gossip:
# Bootstrap set to initialize gossip with.
# This is a list of other peers that this peer reaches out to at startup.
# Important: The endpoints here have to be endpoints of peers in the same
# organization, because the peer would refuse connecting to these endpoints
# unless they are in the same organization as the peer.
bootstrap: 127.0.0.1:7051
# NOTE: orgLeader and useLeaderElection parameters are mutual exclusive.
# Setting both to true would result in the termination of the peer
# since this is undefined state. If the peers are configured with
# useLeaderElection=false, make sure there is at least 1 peer in the
# organization that its orgLeader is set to true.
# Defines whenever peer will initialize dynamic algorithm for
# "leader" selection, where leader is the peer to establish
# connection with ordering service and use delivery protocol
# to pull ledger blocks from ordering service.
useLeaderElection: false
# Statically defines peer to be an organization "leader",
# where this means that current peer will maintain connection
# with ordering service and disseminate block across peers in
# its own organization. Multiple peers or all peers in an organization
# may be configured as org leaders, so that they all pull
# blocks directly from ordering service.
orgLeader: true
# Interval for membershipTracker polling
membershipTrackerInterval: 5s
# Overrides the endpoint that the peer publishes to peers
# in its organization. For peers in foreign organizations
# see 'externalEndpoint'
endpoint:
# Maximum count of blocks stored in memory
maxBlockCountToStore: 10
# Max time between consecutive message pushes(unit: millisecond)
maxPropagationBurstLatency: 10ms
# Max number of messages stored until a push is triggered to remote peers
maxPropagationBurstSize: 10
# Number of times a message is pushed to remote peers
propagateIterations: 1
# Number of peers selected to push messages to
propagatePeerNum: 3
# Determines frequency of pull phases(unit: second)
# Must be greater than digestWaitTime + responseWaitTime
pullInterval: 4s
# Number of peers to pull from
pullPeerNum: 3
# Determines frequency of pulling state info messages from peers(unit: second)
requestStateInfoInterval: 4s
# Determines frequency of pushing state info messages to peers(unit: second)
publishStateInfoInterval: 4s
# Maximum time a stateInfo message is kept until expired
stateInfoRetentionInterval:
# Time from startup certificates are included in Alive messages(unit: second)
publishCertPeriod: 10s
# Should we skip verifying block messages or not (currently not in use)
skipBlockVerification: false
# Dial timeout(unit: second)
dialTimeout: 3s
# Connection timeout(unit: second)
connTimeout: 2s
# Buffer size of received messages
recvBuffSize: 20
# Buffer size of sending messages
sendBuffSize: 200
# Time to wait before pull engine processes incoming digests (unit: second)
# Should be slightly smaller than requestWaitTime
digestWaitTime: 1s
# Time to wait before pull engine removes incoming nonce (unit: milliseconds)
# Should be slightly bigger than digestWaitTime
requestWaitTime: 1500ms
# Time to wait before pull engine ends pull (unit: second)
responseWaitTime: 2s
# Alive check interval(unit: second)
aliveTimeInterval: 5s
# Alive expiration timeout(unit: second)
aliveExpirationTimeout: 25s
# Reconnect interval(unit: second)
reconnectInterval: 25s
# Max number of attempts to connect to a peer
maxConnectionAttempts: 120
# Message expiration factor for alive messages
msgExpirationFactor: 20
# This is an endpoint that is published to peers outside of the organization.
# If this isn't set, the peer will not be known to other organizations and will not be exposed via service discovery.
externalEndpoint:
# Leader election service configuration
election:
# Longest time peer waits for stable membership during leader election startup (unit: second)
startupGracePeriod: 15s
# Interval gossip membership samples to check its stability (unit: second)
membershipSampleInterval: 1s
# Time passes since last declaration message before peer decides to perform leader election (unit: second)
leaderAliveThreshold: 10s
# Time between peer sends propose message and declares itself as a leader (sends declaration message) (unit: second)
leaderElectionDuration: 5s
pvtData:
# pullRetryThreshold determines the maximum duration of time private data corresponding for a given block
# would be attempted to be pulled from peers until the block would be committed without the private data
pullRetryThreshold: 60s
# As private data enters the transient store, it is associated with the peer's ledger's height at that time.
# transientstoreMaxBlockRetention defines the maximum difference between the current ledger's height upon commit,
# and the private data residing inside the transient store that is guaranteed not to be purged.
# Private data is purged from the transient store when blocks with sequences that are multiples
# of transientstoreMaxBlockRetention are committed.
transientstoreMaxBlockRetention: 1000
# pushAckTimeout is the maximum time to wait for an acknowledgement from each peer
# at private data push at endorsement time.
pushAckTimeout: 3s
# Block to live pulling margin, used as a buffer
# to prevent peer from trying to pull private data
# from peers that is soon to be purged in next N blocks.
# This helps a newly joined peer catch up to current
# blockchain height quicker.
btlPullMargin: 10
# the process of reconciliation is done in an endless loop, while in each iteration reconciler tries to
# pull from the other peers the most recent missing blocks with a maximum batch size limitation.
# reconcileBatchSize determines the maximum batch size of missing private data that will be reconciled in a
# single iteration.
reconcileBatchSize: 10
# reconcileSleepInterval determines the time reconciler sleeps from end of an iteration until the beginning
# of the next reconciliation iteration.
reconcileSleepInterval: 1m
# reconciliationEnabled is a flag that indicates whether private data reconciliation is enable or not.
reconciliationEnabled: true
# skipPullingInvalidTransactionsDuringCommit is a flag that indicates whether pulling of invalid
# transaction's private data from other peers need to be skipped during the commit time and pulled
# only through reconciler.
skipPullingInvalidTransactionsDuringCommit: false
# implicitCollectionDisseminationPolicy specifies the dissemination policy for the peer's own implicit collection.
# When a peer endorses a proposal that writes to its own implicit collection, below values override the default values
# for disseminating private data.
# Note that it is applicable to all channels the peer has joined. The implication is that requiredPeerCount has to
# be smaller than the number of peers in a channel that has the lowest numbers of peers from the organization.
implicitCollectionDisseminationPolicy:
# requiredPeerCount defines the minimum number of eligible peers to which the peer must successfully
# disseminate private data for its own implicit collection during endorsement. Default value is 0.
requiredPeerCount: 0
# maxPeerCount defines the maximum number of eligible peers to which the peer will attempt to
# disseminate private data for its own implicit collection during endorsement. Default value is 1.
maxPeerCount: 1
# Gossip state transfer related configuration
state:
# indicates whenever state transfer is enabled or not
# default value is false, i.e. state transfer is active
# and takes care to sync up missing blocks allowing
# lagging peer to catch up to speed with rest network.
# Keep in mind that when peer.gossip.useLeaderElection is true
# and there are several peers in the organization,
# or peer.gossip.useLeaderElection is false alongside with
# peer.gossip.orgleader being false, the peer's ledger may lag behind
# the rest of the peers and will never catch up due to state transfer
# being disabled.
enabled: false
# checkInterval interval to check whether peer is lagging behind enough to
# request blocks via state transfer from another peer.
checkInterval: 10s
# responseTimeout amount of time to wait for state transfer response from
# other peers
responseTimeout: 3s
# batchSize the number of blocks to request via state transfer from another peer
batchSize: 10
# blockBufferSize reflects the size of the re-ordering buffer
# which captures blocks and takes care to deliver them in order
# down to the ledger layer. The actual buffer size is bounded between
# 0 and 2*blockBufferSize, each channel maintains its own buffer
blockBufferSize: 20
# maxRetries maximum number of re-tries to ask
# for single state transfer request
maxRetries: 3
# TLS Settings
tls:
# Require server-side TLS
enabled: false
# Require client certificates / mutual TLS for inbound connections.
# Note that clients that are not configured to use a certificate will
# fail to connect to the peer.
clientAuthRequired: false
# X.509 certificate used for TLS server
cert:
file: tls/server.crt
# Private key used for TLS server
key:
file: tls/server.key
# rootcert.file represents the trusted root certificate chain used for verifying certificates
# of other nodes during outbound connections.
# It is not required to be set, but can be used to augment the set of TLS CA certificates
# available from the MSPs of each channels configuration.
rootcert:
file: tls/ca.crt
# If mutual TLS is enabled, clientRootCAs.files contains a list of additional root certificates
# used for verifying certificates of client connections.
# It augments the set of TLS CA certificates available from the MSPs of each channels configuration.
# Minimally, set your organization's TLS CA root certificate so that the peer can receive join channel requests.
clientRootCAs:
files:
- tls/ca.crt
# Private key used for TLS when making client connections.
# If not set, peer.tls.key.file will be used instead
clientKey:
file:
# X.509 certificate used for TLS when making client connections.
# If not set, peer.tls.cert.file will be used instead
clientCert:
file:
# Authentication contains configuration parameters related to authenticating
# client messages
authentication:
# the acceptable difference between the current server time and the
# client's time as specified in a client request message.
# timewindow is checked on requests to the delivery service only.
timewindow: 15m
# Path on the file system where peer will store data (eg ledger). This
# location must be access control protected to prevent unintended
# modification that might corrupt the peer operations.
# The path may be relative to FABRIC_CFG_PATH or an absolute path.
fileSystemPath: /var/hyperledger/production
# BCCSP (Blockchain crypto provider): Select which crypto implementation or
# library to use
BCCSP:
Default: SW
# Settings for the SW crypto provider (i.e. when DEFAULT: SW)
SW:
# TODO: The default Hash and Security level needs refactoring to be
# fully configurable. Changing these defaults requires coordination
# SHA2 is hardcoded in several places, not only BCCSP
Hash: SHA2
Security: 256
# Location of Key Store
FileKeyStore:
# If "", defaults to 'mspConfigPath'/keystore
KeyStore:
# Settings for the PKCS#11 crypto provider (i.e. when DEFAULT: PKCS11)
PKCS11:
# Location of the PKCS11 module library
Library:
# Token Label
Label:
# User PIN
Pin:
Hash:
Security:
SoftwareVerify:
Immutable:
AltID:
KeyIds:
# Path on the file system where peer will find MSP local configurations
# The path may be relative to FABRIC_CFG_PATH or an absolute path.
mspConfigPath: msp
# Identifier of the local MSP
# ----!!!!IMPORTANT!!!-!!!IMPORTANT!!!-!!!IMPORTANT!!!!----
# Deployers need to change the value of the localMspId string.
# In particular, the name of the local MSP ID of a peer needs
# to match the name of one of the MSPs in each of the channel
# that this peer is a member of. Otherwise this peer's messages
# will not be identified as valid by other nodes.
localMspId: SampleOrg
# CLI common client config options
client:
# connection timeout
connTimeout: 3s
# Delivery service related config
deliveryclient:
# Enables this peer to disseminate blocks it pulled from the ordering service
# via gossip.
# Note that 'gossip.state.enabled' controls point to point block replication
# of blocks committed in the past.
blockGossipEnabled: true
# It sets the total time the delivery service may spend in reconnection
# attempts until its retry logic gives up and returns an error,
# ignored if peer is a static leader
reconnectTotalTimeThreshold: 3600s
# It sets the delivery service <-> ordering service node connection timeout
connTimeout: 3s
# It sets the delivery service maximal delay between consecutive retries.
# Time between retries will have exponential backoff until hitting this threshold.
reConnectBackoffThreshold: 3600s
# A list of orderer endpoint addresses which should be overridden
# when found in channel configurations.
addressOverrides:
# - from:
# to:
# caCertsFile:
# - from:
# to:
# caCertsFile:
# Type for the local MSP - by default it's of type bccsp
localMspType: bccsp
# Used with Go profiling tools only in none production environment. In
# production, it should be disabled (eg enabled: false)
profile:
enabled: false
listenAddress: 0.0.0.0:6060
# Handlers defines custom handlers that can filter and mutate
# objects passing within the peer, such as:
# Auth filter - reject or forward proposals from clients
# Decorators - append or mutate the chaincode input passed to the chaincode
# Endorsers - Custom signing over proposal response payload and its mutation
# Valid handler definition contains:
# - A name which is a factory method name defined in
# core/handlers/library/library.go for statically compiled handlers
# - library path to shared object binary for pluggable filters
# Auth filters and decorators are chained and executed in the order that
# they are defined. For example:
# authFilters:
# -
# name: FilterOne
# library: /opt/lib/filter.so
# -
# name: FilterTwo
# decorators:
# -
# name: DecoratorOne
# -
# name: DecoratorTwo
# library: /opt/lib/decorator.so
# Endorsers are configured as a map that its keys are the endorsement system chaincodes that are being overridden.
# Below is an example that overrides the default ESCC and uses an endorsement plugin that has the same functionality
# as the default ESCC.
# If the 'library' property is missing, the name is used as the constructor method in the builtin library similar
# to auth filters and decorators.
# endorsers:
# escc:
# name: DefaultESCC
# library: /etc/hyperledger/fabric/plugin/escc.so
handlers:
authFilters:
- name: DefaultAuth
- name: ExpirationCheck # This filter checks identity x509 certificate expiration
decorators:
- name: DefaultDecorator
endorsers:
escc:
name: DefaultEndorsement
library:
validators:
vscc:
name: DefaultValidation
library:
# library: /etc/hyperledger/fabric/plugin/escc.so
# Number of goroutines that will execute transaction validation in parallel.
# By default, the peer chooses the number of CPUs on the machine. Set this
# variable to override that choice.
# NOTE: overriding this value might negatively influence the performance of
# the peer so please change this value only if you know what you're doing
validatorPoolSize:
# The discovery service is used by clients to query information about peers,
# such as - which peers have joined a certain channel, what is the latest
# channel config, and most importantly - given a chaincode and a channel,
# what possible sets of peers satisfy the endorsement policy.
discovery:
enabled: true
# Whether the authentication cache is enabled or not.
authCacheEnabled: true
# The maximum size of the cache, after which a purge takes place
authCacheMaxSize: 1000
# The proportion (0 to 1) of entries that remain in the cache after the cache is purged due to overpopulation
authCachePurgeRetentionRatio: 0.75
# Whether to allow non-admins to perform non channel scoped queries.
# When this is false, it means that only peer admins can perform non channel scoped queries.
orgMembersAllowedAccess: false
# Limits is used to configure some internal resource limits.
limits:
# Concurrency limits the number of concurrently running requests to a service on each peer.
# Currently this option is only applied to endorser service and deliver service.
# When the property is missing or the value is 0, the concurrency limit is disabled for the service.
concurrency:
# endorserService limits concurrent requests to endorser service that handles chaincode deployment, query and invocation,
# including both user chaincodes and system chaincodes.
endorserService: 2500
# deliverService limits concurrent event listeners registered to deliver service for blocks and transaction events.
deliverService: 2500
# gatewayService limits concurrent requests to gateway service that handles the submission and evaluation of transactions.
gatewayService: 500
# Since all nodes should be consistent it is recommended to keep
# the default value of 100MB for MaxRecvMsgSize & MaxSendMsgSize
# Max message size in bytes GRPC server and client can receive
maxRecvMsgSize: 104857600
# Max message size in bytes GRPC server and client can send
maxSendMsgSize: 104857600
###############################################################################
#
# VM section
#
###############################################################################
vm:
# Endpoint of the vm management system. For docker can be one of the following in general
# unix:///var/run/docker.sock
# http://localhost:2375
# https://localhost:2376
# If you utilize external chaincode builders and don't need the default Docker chaincode builder,
# the endpoint should be unconfigured so that the peer's Docker health checker doesn't get registered.
endpoint: unix:///var/run/docker.sock
# settings for docker vms
docker:
tls:
enabled: false
ca:
file: docker/ca.crt
cert:
file: docker/tls.crt
key:
file: docker/tls.key
# Enables/disables the standard out/err from chaincode containers for
# debugging purposes
attachStdout: false
# Parameters on creating docker container.
# Container may be efficiently created using ipam & dns-server for cluster
# NetworkMode - sets the networking mode for the container. Supported
# standard values are: `host`(default),`bridge`,`ipvlan`,`none`.
# Dns - a list of DNS servers for the container to use.
# Note: `Privileged` `Binds` `Links` and `PortBindings` properties of
# Docker Host Config are not supported and will not be used if set.
# LogConfig - sets the logging driver (Type) and related options
# (Config) for Docker. For more info,
# https://docs.docker.com/engine/admin/logging/overview/
# Note: Set LogConfig using Environment Variables is not supported.
hostConfig:
NetworkMode: host
Dns:
# - 192.168.0.1
LogConfig:
Type: json-file
Config:
max-size: "50m"
max-file: "5"
Memory: 2147483648
###############################################################################
#
# Chaincode section
#
###############################################################################
chaincode:
# The id is used by the Chaincode stub to register the executing Chaincode
# ID with the Peer and is generally supplied through ENV variables
# the `path` form of ID is provided when installing the chaincode.
# The `name` is used for all other requests and can be any string.
id:
path:
name:
# Generic builder environment, suitable for most chaincode types
builder: $(DOCKER_NS)/fabric-ccenv:$(TWO_DIGIT_VERSION)
# Enables/disables force pulling of the base docker images (listed below)
# during user chaincode instantiation.
# Useful when using moving image tags (such as :latest)
pull: false
golang:
# golang will never need more than baseos
runtime: $(DOCKER_NS)/fabric-baseos:$(TWO_DIGIT_VERSION)
# whether or not golang chaincode should be linked dynamically
dynamicLink: false
java:
# This is an image based on java:openjdk-8 with addition compiler
# tools added for java shim layer packaging.
# This image is packed with shim layer libraries that are necessary
# for Java chaincode runtime.
runtime: $(DOCKER_NS)/fabric-javaenv:$(TWO_DIGIT_VERSION)
node:
# This is an image based on node:$(NODE_VER)-alpine
runtime: $(DOCKER_NS)/fabric-nodeenv:$(TWO_DIGIT_VERSION)
# List of directories to treat as external builders and launchers for
# chaincode. The external builder detection processing will iterate over the
# builders in the order specified below.
# If you don't need to fallback to the default Docker builder, also unconfigure vm.endpoint above.
# To override this property via env variable use CORE_CHAINCODE_EXTERNALBUILDERS: [{name: x, path: dir1}, {name: y, path: dir2}]
# The path must be an absolute path.
externalBuilders:
- name: ccaas_builder
path: /opt/hyperledger/ccaas_builder
propagateEnvironment:
- CHAINCODE_AS_A_SERVICE_BUILDER_CONFIG
# The maximum duration to wait for the chaincode build and install process
# to complete.
installTimeout: 300s
# Timeout duration for starting up a container and waiting for Register
# to come through.
startuptimeout: 300s
# Timeout duration for Invoke and Init calls to prevent runaway.
# This timeout is used by all chaincodes in all the channels, including
# system chaincodes.
# Note that during Invoke, if the image is not available (e.g. being
# cleaned up when in development environment), the peer will automatically
# build the image, which might take more time. In production environment,
# the chaincode image is unlikely to be deleted, so the timeout could be
# reduced accordingly.
executetimeout: 30s
# There are 2 modes: "dev" and "net".
# In dev mode, user runs the chaincode after starting peer from
# command line on local machine.
# In net mode, peer will run chaincode in a docker container.
mode: net
# keepalive in seconds. In situations where the communication goes through a
# proxy that does not support keep-alive, this parameter will maintain connection
# between peer and chaincode.
# A value <= 0 turns keepalive off
keepalive: 0
# enabled system chaincodes
system:
_lifecycle: enable
cscc: enable
lscc: enable
qscc: enable
# Logging section for the chaincode container
logging:
# Default level for all loggers within the chaincode container
level: info
# Override default level for the 'shim' logger
shim: warning
# Format for the chaincode container logs
format: "%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -> %{level:.4s} %{id:03x}%{color:reset} %{message}"
###############################################################################
#
# Ledger section - ledger configuration encompasses both the blockchain
# and the state
#
###############################################################################
ledger:
blockchain:
state:
# stateDatabase - options are "goleveldb", "CouchDB"
# goleveldb - default state database stored in goleveldb.
# CouchDB - store state database in CouchDB
stateDatabase: goleveldb
# Limit on the number of records to return per query
totalQueryLimit: 100000
couchDBConfig:
# It is recommended to run CouchDB on the same server as the peer, and
# not map the CouchDB container port to a server port in docker-compose.
# Otherwise proper security must be provided on the connection between
# CouchDB client (on the peer) and server.
couchDBAddress: 127.0.0.1:5984
# This username must have read and write authority on CouchDB
username:
# The password is recommended to pass as an environment variable
# during start up (eg CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD).
# If it is stored here, the file must be access control protected
# to prevent unintended users from discovering the password.
password:
# Number of retries for CouchDB errors
maxRetries: 3
# Number of retries for CouchDB errors during peer startup.
# The delay between retries doubles for each attempt.
# Default of 10 retries results in 11 attempts over 2 minutes.
maxRetriesOnStartup: 10
# CouchDB request timeout (unit: duration, e.g. 20s)
requestTimeout: 35s
# Limit on the number of records per each CouchDB query
# Note that chaincode queries are only bound by totalQueryLimit.
# Internally the chaincode may execute multiple CouchDB queries,
# each of size internalQueryLimit.
internalQueryLimit: 1000
# Limit on the number of records per CouchDB bulk update batch
maxBatchUpdateSize: 1000
# Create the _global_changes system database
# This is optional. Creating the global changes database will require
# additional system resources to track changes and maintain the database
createGlobalChangesDB: false
# CacheSize denotes the maximum mega bytes (MB) to be allocated for the in-memory state
# cache. Note that CacheSize needs to be a multiple of 32 MB. If it is not a multiple
# of 32 MB, the peer would round the size to the next multiple of 32 MB.
# To disable the cache, 0 MB needs to be assigned to the cacheSize.
cacheSize: 64
history:
# enableHistoryDatabase - options are true or false
# Indicates if the history of key updates should be stored.
# All history 'index' will be stored in goleveldb, regardless if using
# CouchDB or alternate database for the state.
enableHistoryDatabase: true
pvtdataStore:
# the maximum db batch size for converting
# the ineligible missing data entries to eligible missing data entries
collElgProcMaxDbBatchSize: 5000
# the minimum duration (in milliseconds) between writing
# two consecutive db batches for converting the ineligible missing data entries to eligible missing data entries
collElgProcDbBatchesInterval: 1000
# The missing data entries are classified into two categories:
# (1) prioritized
# (2) deprioritized
# Initially, all missing data are in the prioritized list. When the
# reconciler is unable to fetch the missing data from other peers,
# the unreconciled missing data would be moved to the deprioritized list.
# The reconciler would retry deprioritized missing data after every
# deprioritizedDataReconcilerInterval (unit: minutes). Note that the
# interval needs to be greater than the reconcileSleepInterval
deprioritizedDataReconcilerInterval: 60m
# The frequency to purge private data (in number of blocks).
# Private data is purged from the peer's private data store based on
# the collection property blockToLive or an explicit chaincode call to PurgePrivateData().
purgeInterval: 100
# Whether to log private data keys purged from private data store (INFO level) when explicitly purged via chaincode
purgedKeyAuditLogging: true
snapshots:
# Path on the file system where peer will store ledger snapshots
# The path must be an absolute path.
rootDir: /var/hyperledger/production/snapshots
###############################################################################
#
# Operations section
#
###############################################################################
operations:
# host and port for the operations server
listenAddress: 127.0.0.1:9443
# TLS configuration for the operations endpoint
tls:
# TLS enabled
enabled: false
# path to PEM encoded server certificate for the operations server
# The paths in this section may be relative to FABRIC_CFG_PATH or an absolute path.
cert:
file:
# path to PEM encoded server key for the operations server
key:
file:
# most operations service endpoints require client authentication when TLS
# is enabled. clientAuthRequired requires client certificate authentication
# at the TLS layer to access all resources.
clientAuthRequired: false
# paths to PEM encoded ca certificates to trust for client authentication
clientRootCAs:
files: []
###############################################################################
#
# Metrics section
#
###############################################################################
metrics:
# metrics provider is one of statsd, prometheus, or disabled
provider: disabled
# statsd configuration
statsd:
# network type: tcp or udp
network: udp
# statsd server address
address: 127.0.0.1:8125
# the interval at which locally cached counters and gauges are pushed
# to statsd; timings are pushed immediately
writeInterval: 10s
# prefix is prepended to all emitted statsd metrics
prefix:

View File

@ -0,0 +1,81 @@
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
# ---------------------------------------------------------------------------
# Org1
# ---------------------------------------------------------------------------
- Name: Hospital
Domain: hospital.com
EnableNodeOUs: true
# ---------------------------------------------------------------------------
# "Specs"
# ---------------------------------------------------------------------------
# Uncomment this section to enable the explicit definition of hosts in your
# configuration. Most users will want to use Template, below
#
# Specs is an array of Spec entries. Each Spec entry consists of two fields:
# - Hostname: (Required) The desired hostname, sans the domain.
# - CommonName: (Optional) Specifies the template or explicit override for
# the CN. By default, this is the template:
#
# "{{.Hostname}}.{{.Domain}}"
#
# which obtains its values from the Spec.Hostname and
# Org.Domain, respectively.
# ---------------------------------------------------------------------------
# - Hostname: foo # implicitly "foo.org1.example.com"
# CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
# - Hostname: bar
# - Hostname: baz
# ---------------------------------------------------------------------------
# "Template"
# ---------------------------------------------------------------------------
# Allows for the definition of 1 or more hosts that are created sequentially
# from a template. By default, this looks like "peer%d" from 0 to Count-1.
# You may override the number of nodes (Count), the starting index (Start)
# or the template used to construct the name (Hostname).
#
# Note: Template and Specs are not mutually exclusive. You may define both
# sections and the aggregate nodes will be created for you. Take care with
# name collisions
# ---------------------------------------------------------------------------
Template:
# Ubah sesuai dengan jumlah node peer yang digunakan.
Count: 3
SANS:
# List dari Subject Alternative Names (SANS) yang akan disertakan dalam sertifikat TLS
# untuk node peer. Ini dapat mencakup alamat IP, nama host, atau
# pengenal lain yang akan digunakan oleh node peer untuk berkomunikasi secara aman
- localhost
- "127.0.0.1"
- peer0.hospital.com
- peer1.hospital.com
- peer2.hospital.com
# Start: 5
# Hostname: {{.Prefix}}{{.Index}} # default
# ---------------------------------------------------------------------------
# "Users"
# ---------------------------------------------------------------------------
# Count: The number of user accounts _in addition_ to Admin
# ---------------------------------------------------------------------------
Users:
Count: 1
# Ubah sesuai dengan jumlah node orderer yang digunakan dalam jaringan.
OrdererOrgs:
- Name: Orderer
Domain: hospital.com
Specs:
- Hostname: orderer
SANS:
# List dari Subject Alternative Names (SANS) yang akan disertakan dalam sertifikat TLS
# untuk node orderer. Ini dapat mencakup alamat IP, nama host, atau
# pengenal lain yang akan digunakan oleh node orderer untuk berkomunikasi secara aman
- "localhost"
- "hospital.com"

View File

@ -0,0 +1,115 @@
#!/bin/bash
set -euo pipefail
# -----------------------------------------------------------------------------
# Chaincode deployment helper based on chaincode.txt guide
# -----------------------------------------------------------------------------
CHANNEL_NAME=${CHANNEL_NAME:-mychannel}
CC_NAME=${CC_NAME:-logVerification}
CC_VERSION=${CC_VERSION:-1.0}
CC_SEQUENCE=${CC_SEQUENCE:-1}
CC_LABEL="${CC_NAME}_${CC_VERSION}"
CC_SRC_PATH=${CC_SRC_PATH:-./chaincode/logVerification}
CLI_CONTAINER=${CLI_CONTAINER:-cli}
ORDERER_ADDRESS=${ORDERER_ADDRESS:-orderer.hospital.com:7050}
ORDERER_TLS_HOSTNAME=${ORDERER_TLS_HOSTNAME:-orderer.hospital.com}
ORG_ROOT=/opt/gopath/src/github.com/hyperledger/fabric/peer
ORDERER_CA=${ORDERER_CA:-${ORG_ROOT}/organizations/ordererOrganizations/hospital.com/orderers/orderer.hospital.com/msp/tlscacerts/tlsca.hospital.com-cert.pem}
MSP_PATH=${MSP_PATH:-${ORG_ROOT}/organizations/peerOrganizations/hospital.com/users/Admin@hospital.com/msp}
PEER0_TLS=${ORG_ROOT}/organizations/peerOrganizations/hospital.com/peers/peer0.hospital.com/tls/ca.crt
PEER1_TLS=${ORG_ROOT}/organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/tls/ca.crt
PEER2_TLS=${ORG_ROOT}/organizations/peerOrganizations/hospital.com/peers/peer2.hospital.com/tls/ca.crt
PACKAGE_FILE=${CC_LABEL}.tar.gz
info() { echo "[INFO] $*"; }
err() { echo "[ERROR] $*" >&2; }
run_cli() {
docker exec "${CLI_CONTAINER}" bash -lc "$*"
}
set_peer_env() {
local tls=$1 addr=$2
echo "export CORE_PEER_TLS_ENABLED=true"
echo "export CORE_PEER_LOCALMSPID=HospitalMSP"
echo "export CORE_PEER_TLS_ROOTCERT_FILE=${tls}"
echo "export CORE_PEER_MSPCONFIGPATH=${MSP_PATH}"
echo "export CORE_PEER_ADDRESS=${addr}"
}
create_channel_artifacts() {
info "Creating channel ${CHANNEL_NAME}"
run_cli "export ORDERER_CA=${ORDERER_CA}; \
peer channel create -o ${ORDERER_ADDRESS} -c ${CHANNEL_NAME} -f ./channel-artifacts/${CHANNEL_NAME}.tx --outputBlock ./channel-artifacts/${CHANNEL_NAME}.block --tls --cafile \$ORDERER_CA"
run_cli "export ORDERER_CA=${ORDERER_CA}; \
peer channel fetch config ./channel-artifacts/config_block.pb -o ${ORDERER_ADDRESS} --ordererTLSHostnameOverride ${ORDERER_TLS_HOSTNAME} -c ${CHANNEL_NAME} --tls --cafile \$ORDERER_CA"
}
join_peers() {
info "Joining peers to ${CHANNEL_NAME}"
run_cli "$(set_peer_env ${PEER0_TLS} peer0.hospital.com:7051 | paste -sd ';' -) ; peer channel join -b ./channel-artifacts/${CHANNEL_NAME}.block"
run_cli "$(set_peer_env ${PEER1_TLS} peer1.hospital.com:8051 | paste -sd ';' -) ; peer channel join -b ./channel-artifacts/${CHANNEL_NAME}.block"
run_cli "$(set_peer_env ${PEER2_TLS} peer2.hospital.com:9051 | paste -sd ';' -) ; peer channel join -b ./channel-artifacts/${CHANNEL_NAME}.block"
}
package_chaincode() {
info "Packaging chaincode ${CC_LABEL}"
run_cli "rm -f ${PACKAGE_FILE}"
run_cli "peer lifecycle chaincode package ${PACKAGE_FILE} --path ${CC_SRC_PATH} --lang node --label ${CC_LABEL}"
}
install_chaincode() {
info "Installing package on peers"
run_cli "$(set_peer_env ${PEER0_TLS} peer0.hospital.com:7051 | paste -sd ';' -); peer lifecycle chaincode install ${PACKAGE_FILE}"
run_cli "$(set_peer_env ${PEER1_TLS} peer1.hospital.com:8051 | paste -sd ';' -); peer lifecycle chaincode install ${PACKAGE_FILE}"
run_cli "$(set_peer_env ${PEER2_TLS} peer2.hospital.com:9051 | paste -sd ';' -); peer lifecycle chaincode install ${PACKAGE_FILE}"
}
query_package_id() {
info "Querying installed chaincode for package ID"
PACKAGE_ID=$(docker exec "${CLI_CONTAINER}" bash -lc "$(set_peer_env ${PEER0_TLS} peer0.hospital.com:7051 | paste -sd ';' -); peer lifecycle chaincode queryinstalled | grep 'Label: ${CC_LABEL}' | sed -n 's/^Package ID: \([^,]*\),.*/\1/p'")
if [[ -z ${PACKAGE_ID} ]]; then
err "Failed to find package ID for label ${CC_LABEL}"
exit 1
fi
echo "PACKAGE_ID=${PACKAGE_ID}"
}
approve_chaincode() {
info "Approving chaincode for HospitalMSP"
run_cli "$(set_peer_env ${PEER0_TLS} peer0.hospital.com:7051 | paste -sd ';' -); \
peer lifecycle chaincode approveformyorg -o ${ORDERER_ADDRESS} --ordererTLSHostnameOverride ${ORDERER_TLS_HOSTNAME} --channelID ${CHANNEL_NAME} --name ${CC_NAME} --version ${CC_VERSION} --package-id ${PACKAGE_ID} --sequence ${CC_SEQUENCE} --tls --cafile ${ORDERER_CA}"
}
check_commit_readiness() {
info "Checking commit readiness"
run_cli "$(set_peer_env ${PEER0_TLS} peer0.hospital.com:7051 | paste -sd ';' -); \
peer lifecycle chaincode checkcommitreadiness -o ${ORDERER_ADDRESS} --channelID ${CHANNEL_NAME} --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} --tls --cafile ${ORDERER_CA} --output json"
}
commit_chaincode() {
info "Committing chaincode definition"
run_cli "peer lifecycle chaincode commit -o ${ORDERER_ADDRESS} --ordererTLSHostnameOverride ${ORDERER_TLS_HOSTNAME} --channelID ${CHANNEL_NAME} --name ${CC_NAME} --version ${CC_VERSION} --sequence ${CC_SEQUENCE} --tls --cafile ${ORDERER_CA} --peerAddresses peer0.hospital.com:7051 --tlsRootCertFiles ${PEER0_TLS}"
}
main() {
local CREATE_CHANNEL=${CREATE_CHANNEL:-false}
if [[ ${CREATE_CHANNEL} == "true" ]]; then
create_channel_artifacts
join_peers
fi
package_chaincode
install_chaincode
query_package_id
approve_chaincode
check_commit_readiness
commit_chaincode
info "Chaincode ${CC_NAME} (version ${CC_VERSION}, sequence ${CC_SEQUENCE}) deployed on ${CHANNEL_NAME}."
info "If this chaincode requires initialization, invoke with --isInit before normal use."
}
main "$@"

View File

@ -0,0 +1,5 @@
# POSTGRES_PASSWORD=password
# JWT_SECRET_KEY=masukkan_jwt_secret_dengan_format_SHA256
# INITIAL_ADMIN_USER=masukkan_username_admin
# INITIAL_ADMIN_PASSWORD=masukkan_pasword_admin
# ENCRYPTION_KEY=masukkan_key_32byte

View File

@ -0,0 +1,150 @@
networks:
hospital_net:
name: hospital_net
ipam:
driver: default
config:
- subnet: 172.20.0.0/16
services:
orderer.hospital.com:
container_name: orderer.hospital.com
image: hyperledger/fabric-orderer:2.5
environment:
- FABRIC_LOGGING_SPEC=INFO
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_LISTENPORT=7050
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
- ORDERER_GENERAL_TLS_ENABLED=true
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
- ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
- ORDERER_KAFKA_VERBOSE=true
- ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: orderer
volumes:
- ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ../organizations/ordererOrganizations/hospital.com/orderers/orderer.hospital.com/msp:/var/hyperledger/orderer/msp
- ../organizations/ordererOrganizations/hospital.com/orderers/orderer.hospital.com/tls:/var/hyperledger/orderer/tls
ports:
- 7050:7050
networks:
hospital_net:
ipv4_address: 172.20.0.10
peer0.hospital.com:
container_name: peer0.hospital.com
image: hyperledger/fabric-peer:2.5
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=hospital_net
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_ID=peer0.hospital.com
- CORE_PEER_ADDRESS=peer0.hospital.com:7051
- CORE_PEER_LISTENADDRESS=0.0.0.0:7051
- CORE_PEER_CHAINCODEADDRESS=peer0.hospital.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.hospital.com:7051
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.hospital.com:7051
- CORE_PEER_LOCALMSPID=HospitalMSP
volumes:
- /var/run/:/host/var/run/
- ../organizations/peerOrganizations/hospital.com/peers/peer0.hospital.com/msp:/etc/hyperledger/fabric/msp
- ../organizations/peerOrganizations/hospital.com/peers/peer0.hospital.com/tls:/etc/hyperledger/fabric/tls
ports:
- 7051:7051
networks:
hospital_net:
ipv4_address: 172.20.0.11
peer1.hospital.com:
container_name: peer1.hospital.com
image: hyperledger/fabric-peer:2.5
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=hospital_net
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_ID=peer1.hospital.com
- CORE_PEER_ADDRESS=peer1.hospital.com:8051
- CORE_PEER_LISTENADDRESS=0.0.0.0:8051
- CORE_PEER_CHAINCODEADDRESS=peer1.hospital.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.hospital.com:7051 # <-- Bootstrap ke peer0
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.hospital.com:8051
- CORE_PEER_LOCALMSPID=HospitalMSP
volumes:
- /var/run/:/host/var/run/
- ../organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/msp:/etc/hyperledger/fabric/msp
- ../organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/tls:/etc/hyperledger/fabric/tls
ports:
- 8051:8051
networks:
hospital_net:
ipv4_address: 172.20.0.12
peer2.hospital.com:
container_name: peer2.hospital.com
image: hyperledger/fabric-peer:2.5
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=hospital_net
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_ID=peer2.hospital.com
- CORE_PEER_ADDRESS=peer2.hospital.com:9051
- CORE_PEER_LISTENADDRESS=0.0.0.0:9051
- CORE_PEER_CHAINCODEADDRESS=peer2.hospital.com:7052
- CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
- CORE_PEER_GOSSIP_BOOTSTRAP=peer0.hospital.com:7051 # <-- Bootstrap ke peer0
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer2.hospital.com:9051
- CORE_PEER_LOCALMSPID=HospitalMSP
volumes:
- /var/run/:/host/var/run/
- ../organizations/peerOrganizations/hospital.com/peers/peer2.hospital.com/msp:/etc/hyperledger/fabric/msp
- ../organizations/peerOrganizations/hospital.com/peers/peer2.hospital.com/tls:/etc/hyperledger/fabric/tls
ports:
- 9051:9051
networks:
hospital_net:
ipv4_address: 172.20.0.13
cli:
container_name: cli
image: hyperledger/fabric-tools:2.5
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_LOCALMSPID=HospitalMSP
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/peers/peer0.hospital.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/users/Admin@hospital.com/msp
- CORE_PEER_ADDRESS=peer0.hospital.com:7051
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ../../chaincode:/opt/gopath/src/github.com/hyperledger/fabric/peer/chaincode
- ../organizations:/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations
- ../channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- orderer.hospital.com
- peer0.hospital.com
- peer1.hospital.com
- peer2.hospital.com
networks:
- hospital_net

View File

@ -0,0 +1,39 @@
#!/bin/bash
export COMPOSE_PROJECT_NAME=hospital
export IMAGE_TAG=latest
function networkUp() {
docker compose -f ./docker/docker-compose.yaml up -d
echo "--- Network is up ---"
}
function networkDown() {
docker compose -f ./docker/docker-compose.yaml down --volumes --remove-orphans
echo "--- Network is down ---"
}
function createChannel() {
docker exec cli peer channel create -o orderer.hospital.com:7050 -c mychannel -f ./channel-artifacts/mychannel.tx --outputBlock ./channel-artifacts/mychannel.block --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/hospital.com/orderers/orderer.hospital.com/msp/tlscacerts/tlsca.hospital.com-cert.pem
# Join Peer 0
docker exec -e CORE_PEER_LOCALMSPID="HospitalMSP" -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/peers/peer0.hospital.com/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/users/Admin@hospital.com/msp -e CORE_PEER_ADDRESS=peer0.hospital.com:7051 cli peer channel join -b ./channel-artifacts/mychannel.block
# Join Peer 1
docker exec -e CORE_PEER_LOCALMSPID="HospitalMSP" -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/peers/peer1.hospital.com/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/users/Admin@hospital.com/msp -e CORE_PEER_ADDRESS=peer1.hospital.com:8051 cli peer channel join -b ./channel-artifacts/mychannel.block
# Join Peer 2
docker exec -e CORE_PEER_LOCALMSPID="HospitalMSP" -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/peers/peer2.hospital.com/tls/ca.crt -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/hospital.com/users/Admin@hospital.com/msp -e CORE_PEER_ADDRESS=peer2.hospital.com:9051 cli peer channel join -b ./channel-artifacts/mychannel.block
}
MODE=$1
if [ "$MODE" == "up" ]; then
networkUp
elif [ "$MODE" == "down" ]; then
networkDown
elif [ "$MODE" == "createChannel" ]; then
createChannel
else
echo "Usage: ./network.sh [up|down|createChannel]"
exit 1
fi

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQW6ZwqaAXjAJe9/QD9kmFDjAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR2oP4J049hk9R2/JEyv4h5
Ui0Iq6kNJKbxFXZwZNa2Jms8uxopqlE1mrwQQM4DgFF4P1jckzcIB7Z/k2qxzOwj
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIGIkuHV4DfHdyPjEPAvTLFsc
9Qm/WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0cAMEQCICAerWiu4ulFe1C+afnF
J0+iCEtp+tfm1lhoKC0s8hreAiB6eAJeOV0Y7BXNf3EomcBeZpdUW10WQPsy9Pk5
dYcXUA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgYFDSkvlA3Ef+oZUT
9LDbeafnrwEuv23OhxneaQbdBkChRANCAAR2oP4J049hk9R2/JEyv4h5Ui0Iq6kN
JKbxFXZwZNa2Jms8uxopqlE1mrwQQM4DgFF4P1jckzcIB7Z/k2qxzOwj
-----END PRIVATE KEY-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICDjCCAbSgAwIBAgIRAK/mWLCDrmUfc3ucL5JBskswCgYIKoZIzj0EAwIwazEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEYMBYGA1UEAxMPY2EuaG9z
cGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowVzELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFu
Y2lzY28xGzAZBgNVBAMMEkFkbWluQGhvc3BpdGFsLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABChrfaeEb3icKPe7MEZr1KA9+zSsJoQ/EkikVDd1ahQl4++e
wXhGeGmqMBpZdt3CPLt1QL0QBR4hEl67R4e48kijTTBLMA4GA1UdDwEB/wQEAwIH
gDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIGIkuHV4DfHdyPjEPAvTLFsc9Qm/
WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0gAMEUCIQCZ/vliKquBinrgGtU853mu
lEOIjJD1kbOKSwompWK3TQIgd04F2MqJiZ1hih+A2zrNflOmpO4iK9ThNHTT301J
WX0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQW6ZwqaAXjAJe9/QD9kmFDjAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR2oP4J049hk9R2/JEyv4h5
Ui0Iq6kNJKbxFXZwZNa2Jms8uxopqlE1mrwQQM4DgFF4P1jckzcIB7Z/k2qxzOwj
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIGIkuHV4DfHdyPjEPAvTLFsc
9Qm/WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0cAMEQCICAerWiu4ulFe1C+afnF
J0+iCEtp+tfm1lhoKC0s8hreAiB6eAJeOV0Y7BXNf3EomcBeZpdUW10WQPsy9Pk5
dYcXUA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICRjCCAe2gAwIBAgIQMwWpJ4ejuY9l/O28y47bVzAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASHs8anhwHeyHd4
brPA5IPcLBlg70YfpVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3
b/uWZfAWo20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIHi4WNdHBn7lRXxo
OIWpy4KbM0EYLza9hhsohgbntuGaMAoGCCqGSM49BAMCA0cAMEQCIH8+y8Q134Gt
SMcUetKrqrpFLD1cmweyhh72PJskhV5/AiAtG7ZUBL+QTeoi2vnTm5V931UR+Rsd
XRb6eWYOpeFWRg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICDjCCAbSgAwIBAgIRAK/mWLCDrmUfc3ucL5JBskswCgYIKoZIzj0EAwIwazEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEYMBYGA1UEAxMPY2EuaG9z
cGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowVzELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFu
Y2lzY28xGzAZBgNVBAMMEkFkbWluQGhvc3BpdGFsLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABChrfaeEb3icKPe7MEZr1KA9+zSsJoQ/EkikVDd1ahQl4++e
wXhGeGmqMBpZdt3CPLt1QL0QBR4hEl67R4e48kijTTBLMA4GA1UdDwEB/wQEAwIH
gDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIGIkuHV4DfHdyPjEPAvTLFsc9Qm/
WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0gAMEUCIQCZ/vliKquBinrgGtU853mu
lEOIjJD1kbOKSwompWK3TQIgd04F2MqJiZ1hih+A2zrNflOmpO4iK9ThNHTT301J
WX0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQW6ZwqaAXjAJe9/QD9kmFDjAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR2oP4J049hk9R2/JEyv4h5
Ui0Iq6kNJKbxFXZwZNa2Jms8uxopqlE1mrwQQM4DgFF4P1jckzcIB7Z/k2qxzOwj
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIGIkuHV4DfHdyPjEPAvTLFsc
9Qm/WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0cAMEQCICAerWiu4ulFe1C+afnF
J0+iCEtp+tfm1lhoKC0s8hreAiB6eAJeOV0Y7BXNf3EomcBeZpdUW10WQPsy9Pk5
dYcXUA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgD2ZA+jFQ8/sFuKOy
MasGELTJXhdPz5la44nK+reGAjGhRANCAAQ6ocKy3b9sgjCtqTMCP/uPlhi6aIlw
WMCTl3Lz9JkeVxXSUkMxWSp9OJm3K2pUjLYVX7ejsxtpdOE0Fz2EBPLN
-----END PRIVATE KEY-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICDzCCAbagAwIBAgIRAM4e/huh2ZN60YAq9dgBS84wCgYIKoZIzj0EAwIwazEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEYMBYGA1UEAxMPY2EuaG9z
cGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowWTELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFu
Y2lzY28xHTAbBgNVBAMTFG9yZGVyZXIuaG9zcGl0YWwuY29tMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEOqHCst2/bIIwrakzAj/7j5YYumiJcFjAk5dy8/SZHlcV
0lJDMVkqfTiZtytqVIy2FV+3o7MbaXThNBc9hATyzaNNMEswDgYDVR0PAQH/BAQD
AgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgYiS4dXgN8d3I+MQ8C9MsWxz1
Cb9YqOZAcNyl4QIfldEwCgYIKoZIzj0EAwIDRwAwRAIgCrzzx19oifglBEZIvhSb
DjdhiCjPGiNqJrtedc5+2GICIBWTwSCEO/q8QwDSUQFq/mK4pBYeFISsy6Dm3hyv
G2/+
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICRjCCAe2gAwIBAgIQMwWpJ4ejuY9l/O28y47bVzAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASHs8anhwHeyHd4
brPA5IPcLBlg70YfpVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3
b/uWZfAWo20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIHi4WNdHBn7lRXxo
OIWpy4KbM0EYLza9hhsohgbntuGaMAoGCCqGSM49BAMCA0cAMEQCIH8+y8Q134Gt
SMcUetKrqrpFLD1cmweyhh72PJskhV5/AiAtG7ZUBL+QTeoi2vnTm5V931UR+Rsd
XRb6eWYOpeFWRg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICRjCCAe2gAwIBAgIQMwWpJ4ejuY9l/O28y47bVzAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASHs8anhwHeyHd4
brPA5IPcLBlg70YfpVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3
b/uWZfAWo20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIHi4WNdHBn7lRXxo
OIWpy4KbM0EYLza9hhsohgbntuGaMAoGCCqGSM49BAMCA0cAMEQCIH8+y8Q134Gt
SMcUetKrqrpFLD1cmweyhh72PJskhV5/AiAtG7ZUBL+QTeoi2vnTm5V931UR+Rsd
XRb6eWYOpeFWRg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICdTCCAhygAwIBAgIQYDtqEAPMqf8gukEP32ywlDAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBZMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEdMBsGA1UEAxMUb3JkZXJlci5ob3NwaXRhbC5jb20wWTATBgcqhkjO
PQIBBggqhkjOPQMBBwNCAARJkiv9loBDyZ33XbOg8M0WZKdH+ba8WT9ZuMunUOV/
wVqgP4BN6c7MDQYYG4OKBFdYc1SLsOdkoIkL+5C2TpUio4GwMIGtMA4GA1UdDwEB
/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/
BAIwADArBgNVHSMEJDAigCB4uFjXRwZ+5UV8aDiFqcuCmzNBGC82vYYbKIYG57bh
mjBBBgNVHREEOjA4ghRvcmRlcmVyLmhvc3BpdGFsLmNvbYIHb3JkZXJlcoIJbG9j
YWxob3N0ggxob3NwaXRhbC5jb20wCgYIKoZIzj0EAwIDRwAwRAIgPtxsJped+dgp
2rSTE3pjE9ZgUvOcOm0wGZPV4otYW7YCIAPhKu82z5/po4U/Zh9kFCY6rEiaug1b
DKDvjzVArk+i
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/ARTlMcxKEEhlMxA
TQVjBmsRRKiqobEPOSN/uI8GBi2hRANCAARJkiv9loBDyZ33XbOg8M0WZKdH+ba8
WT9ZuMunUOV/wVqgP4BN6c7MDQYYG4OKBFdYc1SLsOdkoIkL+5C2TpUi
-----END PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPhMkXhdQyGjzneZf
XQqXqIfXtjfWHST73Gu438vXgeqhRANCAASHs8anhwHeyHd4brPA5IPcLBlg70Yf
pVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3b/uWZfAW
-----END PRIVATE KEY-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICRjCCAe2gAwIBAgIQMwWpJ4ejuY9l/O28y47bVzAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASHs8anhwHeyHd4
brPA5IPcLBlg70YfpVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3
b/uWZfAWo20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIHi4WNdHBn7lRXxo
OIWpy4KbM0EYLza9hhsohgbntuGaMAoGCCqGSM49BAMCA0cAMEQCIH8+y8Q134Gt
SMcUetKrqrpFLD1cmweyhh72PJskhV5/AiAtG7ZUBL+QTeoi2vnTm5V931UR+Rsd
XRb6eWYOpeFWRg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICDjCCAbSgAwIBAgIRAK/mWLCDrmUfc3ucL5JBskswCgYIKoZIzj0EAwIwazEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEYMBYGA1UEAxMPY2EuaG9z
cGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowVzELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFu
Y2lzY28xGzAZBgNVBAMMEkFkbWluQGhvc3BpdGFsLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABChrfaeEb3icKPe7MEZr1KA9+zSsJoQ/EkikVDd1ahQl4++e
wXhGeGmqMBpZdt3CPLt1QL0QBR4hEl67R4e48kijTTBLMA4GA1UdDwEB/wQEAwIH
gDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIGIkuHV4DfHdyPjEPAvTLFsc9Qm/
WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0gAMEUCIQCZ/vliKquBinrgGtU853mu
lEOIjJD1kbOKSwompWK3TQIgd04F2MqJiZ1hih+A2zrNflOmpO4iK9ThNHTT301J
WX0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQW6ZwqaAXjAJe9/QD9kmFDjAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR2oP4J049hk9R2/JEyv4h5
Ui0Iq6kNJKbxFXZwZNa2Jms8uxopqlE1mrwQQM4DgFF4P1jckzcIB7Z/k2qxzOwj
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIGIkuHV4DfHdyPjEPAvTLFsc
9Qm/WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0cAMEQCICAerWiu4ulFe1C+afnF
J0+iCEtp+tfm1lhoKC0s8hreAiB6eAJeOV0Y7BXNf3EomcBeZpdUW10WQPsy9Pk5
dYcXUA==
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNDSkX+blUZWH93Ho
zGD9hWiBT/boL5P2e2aX7fYE1iehRANCAAQoa32nhG94nCj3uzBGa9SgPfs0rCaE
PxJIpFQ3dWoUJePvnsF4RnhpqjAaWXbdwjy7dUC9EAUeIRJeu0eHuPJI
-----END PRIVATE KEY-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICDjCCAbSgAwIBAgIRAK/mWLCDrmUfc3ucL5JBskswCgYIKoZIzj0EAwIwazEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEYMBYGA1UEAxMPY2EuaG9z
cGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowVzELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFu
Y2lzY28xGzAZBgNVBAMMEkFkbWluQGhvc3BpdGFsLmNvbTBZMBMGByqGSM49AgEG
CCqGSM49AwEHA0IABChrfaeEb3icKPe7MEZr1KA9+zSsJoQ/EkikVDd1ahQl4++e
wXhGeGmqMBpZdt3CPLt1QL0QBR4hEl67R4e48kijTTBLMA4GA1UdDwEB/wQEAwIH
gDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIGIkuHV4DfHdyPjEPAvTLFsc9Qm/
WKjmQHDcpeECH5XRMAoGCCqGSM49BAMCA0gAMEUCIQCZ/vliKquBinrgGtU853mu
lEOIjJD1kbOKSwompWK3TQIgd04F2MqJiZ1hih+A2zrNflOmpO4iK9ThNHTT301J
WX0=
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICRjCCAe2gAwIBAgIQMwWpJ4ejuY9l/O28y47bVzAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASHs8anhwHeyHd4
brPA5IPcLBlg70YfpVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3
b/uWZfAWo20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIHi4WNdHBn7lRXxo
OIWpy4KbM0EYLza9hhsohgbntuGaMAoGCCqGSM49BAMCA0cAMEQCIH8+y8Q134Gt
SMcUetKrqrpFLD1cmweyhh72PJskhV5/AiAtG7ZUBL+QTeoi2vnTm5V931UR+Rsd
XRb6eWYOpeFWRg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICRjCCAe2gAwIBAgIQMwWpJ4ejuY9l/O28y47bVzAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASHs8anhwHeyHd4
brPA5IPcLBlg70YfpVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3
b/uWZfAWo20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIG
CCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIHi4WNdHBn7lRXxo
OIWpy4KbM0EYLza9hhsohgbntuGaMAoGCCqGSM49BAMCA0cAMEQCIH8+y8Q134Gt
SMcUetKrqrpFLD1cmweyhh72PJskhV5/AiAtG7ZUBL+QTeoi2vnTm5V931UR+Rsd
XRb6eWYOpeFWRg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICLzCCAdWgAwIBAgIQe7GKXAvB/0RLi8cG5pwQvjAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBXMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEbMBkGA1UEAwwSQWRtaW5AaG9zcGl0YWwuY29tMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAED3R/6kg1RJooq9pE5WSe309YGez499NC6Q2233qtde+p
Vx7Y1mU+BngGDg6qEcm5jPt3AZ/lReGt2Kk59KgHuKNsMGowDgYDVR0PAQH/BAQD
AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
MCsGA1UdIwQkMCKAIHi4WNdHBn7lRXxoOIWpy4KbM0EYLza9hhsohgbntuGaMAoG
CCqGSM49BAMCA0gAMEUCIQClB6GEZss+mfxLfyjndDAsNnwZIY0sTm+8MXEo/sOx
MQIgEejkLd1/CFzxUoKIAjhIffufsKVhaRTij9lHwBrUy6g=
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvpxkslG5HZI0fAhR
0TXMV97rPHYohdTsGlfSYjfHN6mhRANCAAQPdH/qSDVEmiir2kTlZJ7fT1gZ7Pj3
00LpDbbfeq1176lXHtjWZT4GeAYODqoRybmM+3cBn+VF4a3YqTn0qAe4
-----END PRIVATE KEY-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQH0YqnsCA7grqaNkTpbBY6DAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATIigu5i2LnUdYr/S2YC9As
JhjFrXQCmSOAe6WfY+l9sk9Kfd0U0D4Alxf72s6oTHUyz9AKiSEliJD63isElZ0W
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIIkMxsxI8VsKJogFPSdKak9z
++POEq9gse2ueyRdGVAmMAoGCCqGSM49BAMCA0cAMEQCIAyUMuN2wzgKS6oIQ4Sw
Fsk7vC5XQbSzSCKl7+m3+QlQAiASzYtDzLPYYe6OtMmvcFigFmCYutEhlnY88/2O
gO2YhQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2kwHcYJUJ7oHbSlm
/2Koc1xt6RB5o0nKJNcMSb7kcIehRANCAATIigu5i2LnUdYr/S2YC9AsJhjFrXQC
mSOAe6WfY+l9sk9Kfd0U0D4Alxf72s6oTHUyz9AKiSEliJD63isElZ0W
-----END PRIVATE KEY-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQH0YqnsCA7grqaNkTpbBY6DAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATIigu5i2LnUdYr/S2YC9As
JhjFrXQCmSOAe6WfY+l9sk9Kfd0U0D4Alxf72s6oTHUyz9AKiSEliJD63isElZ0W
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIIkMxsxI8VsKJogFPSdKak9z
++POEq9gse2ueyRdGVAmMAoGCCqGSM49BAMCA0cAMEQCIAyUMuN2wzgKS6oIQ4Sw
Fsk7vC5XQbSzSCKl7+m3+QlQAiASzYtDzLPYYe6OtMmvcFigFmCYutEhlnY88/2O
gO2YhQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: orderer

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSDCCAe6gAwIBAgIRAKGluYd28isXUJzCGMxHZV4wCgYIKoZIzj0EAwIwbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIS4qL4gtG2T5
B54Vr2JJ7H7M2EzyOrRzvqgX3FWNrl/p3j1albcaaQZGPQtZsnltJH3MMNII3Vgm
bW908vh286NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBfMKNMs3IpZGj2
DABPe1+jLwHEGvaSdesz+yMOavu9OjAKBggqhkjOPQQDAgNIADBFAiB4C9RpAU4s
nuqX4hvOeyoXukChN7kh9gbOB3tVB0mtaAIhAM27SDfOwCN/Wa5p8ph2UR1tFVeO
hcjBpSsxFF/vXfay
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQH0YqnsCA7grqaNkTpbBY6DAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATIigu5i2LnUdYr/S2YC9As
JhjFrXQCmSOAe6WfY+l9sk9Kfd0U0D4Alxf72s6oTHUyz9AKiSEliJD63isElZ0W
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIIkMxsxI8VsKJogFPSdKak9z
++POEq9gse2ueyRdGVAmMAoGCCqGSM49BAMCA0cAMEQCIAyUMuN2wzgKS6oIQ4Sw
Fsk7vC5XQbSzSCKl7+m3+QlQAiASzYtDzLPYYe6OtMmvcFigFmCYutEhlnY88/2O
gO2YhQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: orderer

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgg77lfA99A7OmI7bT
Qo4ZW5av+cpH7uokB+qL96t9eGOhRANCAARrYrhVWDHfkxDAvD7q0Qr3gX/8wvAL
k/R/acLIhAAfD65JbSJMHs2w/WpwHnIyIDlXpAGuWsX1S8iMTeMtP+OG
-----END PRIVATE KEY-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICHTCCAcOgAwIBAgIRAJi7Frowz9TbFBH79/hpWbYwCgYIKoZIzj0EAwIwazEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEYMBYGA1UEAxMPY2EuaG9z
cGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowZjELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFu
Y2lzY28xDTALBgNVBAsTBHBlZXIxGzAZBgNVBAMTEnBlZXIwLmhvc3BpdGFsLmNv
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGtiuFVYMd+TEMC8PurRCveBf/zC
8AuT9H9pwsiEAB8PrkltIkwezbD9anAecjIgOVekAa5axfVLyIxN4y0/44ajTTBL
MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIIkMxsxI
8VsKJogFPSdKak9z++POEq9gse2ueyRdGVAmMAoGCCqGSM49BAMCA0gAMEUCIQCl
Uf3N8F+lrcnnFvikX2uHs/KH75DlWHbxJoBJ7ai4oQIgUx7gewxurP+Wx+JNQqrz
V8zwA1wm4EnwfOpIDisF+jg=
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSDCCAe6gAwIBAgIRAKGluYd28isXUJzCGMxHZV4wCgYIKoZIzj0EAwIwbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIS4qL4gtG2T5
B54Vr2JJ7H7M2EzyOrRzvqgX3FWNrl/p3j1albcaaQZGPQtZsnltJH3MMNII3Vgm
bW908vh286NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBfMKNMs3IpZGj2
DABPe1+jLwHEGvaSdesz+yMOavu9OjAKBggqhkjOPQQDAgNIADBFAiB4C9RpAU4s
nuqX4hvOeyoXukChN7kh9gbOB3tVB0mtaAIhAM27SDfOwCN/Wa5p8ph2UR1tFVeO
hcjBpSsxFF/vXfay
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSDCCAe6gAwIBAgIRAKGluYd28isXUJzCGMxHZV4wCgYIKoZIzj0EAwIwbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIS4qL4gtG2T5
B54Vr2JJ7H7M2EzyOrRzvqgX3FWNrl/p3j1albcaaQZGPQtZsnltJH3MMNII3Vgm
bW908vh286NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBfMKNMs3IpZGj2
DABPe1+jLwHEGvaSdesz+yMOavu9OjAKBggqhkjOPQQDAgNIADBFAiB4C9RpAU4s
nuqX4hvOeyoXukChN7kh9gbOB3tVB0mtaAIhAM27SDfOwCN/Wa5p8ph2UR1tFVeO
hcjBpSsxFF/vXfay
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICpDCCAkqgAwIBAgIQb0W21UMZpFkblXQ60HX5rjAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBXMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEbMBkGA1UEAxMScGVlcjAuaG9zcGl0YWwuY29tMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEprW1SI4IulrzQ818Tgpsa7y2NMHO15ApbL9wjeyJuSos
+gBNHzUqN+PEz4mI7/mS2j4qAcaIiVLrZj7yjkL7CqOB4DCB3TAOBgNVHQ8BAf8E
BAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQC
MAAwKwYDVR0jBCQwIoAgXzCjTLNyKWRo9gwAT3tfoy8BxBr2knXrM/sjDmr7vTow
cQYDVR0RBGowaIIScGVlcjAuaG9zcGl0YWwuY29tggVwZWVyMIIJbG9jYWxob3N0
ghJwZWVyMC5ob3NwaXRhbC5jb22CEnBlZXIxLmhvc3BpdGFsLmNvbYIScGVlcjIu
aG9zcGl0YWwuY29thwR/AAABMAoGCCqGSM49BAMCA0gAMEUCIQDVJcPthHbVnJAa
24Qypnm7ENLuMqo2hoam58IsHLt0HwIgCDtWtXYJsmYwpi+6JYPa1NoHWARje8lt
+8mQmCtSm1c=
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaHNDQ85FC1jSvPKA
dHRZz6kFyZoVMoR5MkJt8nQbj8ehRANCAASmtbVIjgi6WvNDzXxOCmxrvLY0wc7X
kClsv3CN7Im5Kiz6AE0fNSo348TPiYjv+ZLaPioBxoiJUutmPvKOQvsK
-----END PRIVATE KEY-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQH0YqnsCA7grqaNkTpbBY6DAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATIigu5i2LnUdYr/S2YC9As
JhjFrXQCmSOAe6WfY+l9sk9Kfd0U0D4Alxf72s6oTHUyz9AKiSEliJD63isElZ0W
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIIkMxsxI8VsKJogFPSdKak9z
++POEq9gse2ueyRdGVAmMAoGCCqGSM49BAMCA0cAMEQCIAyUMuN2wzgKS6oIQ4Sw
Fsk7vC5XQbSzSCKl7+m3+QlQAiASzYtDzLPYYe6OtMmvcFigFmCYutEhlnY88/2O
gO2YhQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: orderer

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgzGBT3anTXStu86ju
BCIDGm2G+SeH30af2nQeEdWuLaKhRANCAARfR4n+P7IQIuChln6SpcnV34ZGId7l
DfriFg0w1eSCsfPyU6FZoQVb35Vgvi/OhCI+vbKiAHgxJFPtm2xAKiy1
-----END PRIVATE KEY-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICHDCCAcOgAwIBAgIRAIrl3qhzDSVM4wIorHf2aUwwCgYIKoZIzj0EAwIwazEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEYMBYGA1UEAxMPY2EuaG9z
cGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowZjELMAkG
A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFu
Y2lzY28xDTALBgNVBAsTBHBlZXIxGzAZBgNVBAMTEnBlZXIxLmhvc3BpdGFsLmNv
bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF9Hif4/shAi4KGWfpKlydXfhkYh
3uUN+uIWDTDV5IKx8/JToVmhBVvflWC+L86EIj69sqIAeDEkU+2bbEAqLLWjTTBL
MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIIkMxsxI
8VsKJogFPSdKak9z++POEq9gse2ueyRdGVAmMAoGCCqGSM49BAMCA0cAMEQCIC5L
zaqfrOGKn9ilsiLaW2yUCf6SKXFtScU+I8v6RnUGAiBYAeVRkz1USU40Bru9Kpz7
5qKdDCdEGGVAzVWq+OJmKw==
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSDCCAe6gAwIBAgIRAKGluYd28isXUJzCGMxHZV4wCgYIKoZIzj0EAwIwbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIS4qL4gtG2T5
B54Vr2JJ7H7M2EzyOrRzvqgX3FWNrl/p3j1albcaaQZGPQtZsnltJH3MMNII3Vgm
bW908vh286NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBfMKNMs3IpZGj2
DABPe1+jLwHEGvaSdesz+yMOavu9OjAKBggqhkjOPQQDAgNIADBFAiB4C9RpAU4s
nuqX4hvOeyoXukChN7kh9gbOB3tVB0mtaAIhAM27SDfOwCN/Wa5p8ph2UR1tFVeO
hcjBpSsxFF/vXfay
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSDCCAe6gAwIBAgIRAKGluYd28isXUJzCGMxHZV4wCgYIKoZIzj0EAwIwbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIS4qL4gtG2T5
B54Vr2JJ7H7M2EzyOrRzvqgX3FWNrl/p3j1albcaaQZGPQtZsnltJH3MMNII3Vgm
bW908vh286NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBfMKNMs3IpZGj2
DABPe1+jLwHEGvaSdesz+yMOavu9OjAKBggqhkjOPQQDAgNIADBFAiB4C9RpAU4s
nuqX4hvOeyoXukChN7kh9gbOB3tVB0mtaAIhAM27SDfOwCN/Wa5p8ph2UR1tFVeO
hcjBpSsxFF/vXfay
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICozCCAkqgAwIBAgIQBMT6520mXab8k70zsb9LGTAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBXMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEbMBkGA1UEAxMScGVlcjEuaG9zcGl0YWwuY29tMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEPzqCTsNDoKsyUxSkTnp00SAuMsDw5bQaAIEiUFkDlNUh
XE6JkhWGbkKQ/UGUVypxatA0I0mrG7CcsXcQSSqe1KOB4DCB3TAOBgNVHQ8BAf8E
BAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQC
MAAwKwYDVR0jBCQwIoAgXzCjTLNyKWRo9gwAT3tfoy8BxBr2knXrM/sjDmr7vTow
cQYDVR0RBGowaIIScGVlcjEuaG9zcGl0YWwuY29tggVwZWVyMYIJbG9jYWxob3N0
ghJwZWVyMC5ob3NwaXRhbC5jb22CEnBlZXIxLmhvc3BpdGFsLmNvbYIScGVlcjIu
aG9zcGl0YWwuY29thwR/AAABMAoGCCqGSM49BAMCA0cAMEQCIHi7kh+pbCzdpTpO
Fqj03dh05XrWc/o53AG/+1FJXrMxAiB4pMORPxz/Ew3Ro470cSiuZXeIGM6VWdw0
MstyqrhBlg==
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoXVksNj43L20RjMj
807+tIkTPi6fj2jLinDbUs0EuWOhRANCAAQ/OoJOw0OgqzJTFKROenTRIC4ywPDl
tBoAgSJQWQOU1SFcTomSFYZuQpD9QZRXKnFq0DQjSasbsJyxdxBJKp7U
-----END PRIVATE KEY-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICQDCCAeegAwIBAgIQH0YqnsCA7grqaNkTpbBY6DAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBrMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3NwaXRh
bC5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATIigu5i2LnUdYr/S2YC9As
JhjFrXQCmSOAe6WfY+l9sk9Kfd0U0D4Alxf72s6oTHUyz9AKiSEliJD63isElZ0W
o20wazAOBgNVHQ8BAf8EBAMCAaYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMBMA8GA1UdEwEB/wQFMAMBAf8wKQYDVR0OBCIEIIkMxsxI8VsKJogFPSdKak9z
++POEq9gse2ueyRdGVAmMAoGCCqGSM49BAMCA0cAMEQCIAyUMuN2wzgKS6oIQ4Sw
Fsk7vC5XQbSzSCKl7+m3+QlQAiASzYtDzLPYYe6OtMmvcFigFmCYutEhlnY88/2O
gO2YhQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,14 @@
NodeOUs:
Enable: true
ClientOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: client
PeerOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: peer
AdminOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: admin
OrdererOUIdentifier:
Certificate: cacerts/ca.hospital.com-cert.pem
OrganizationalUnitIdentifier: orderer

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgitvB9obBLXABTpkm
tlvP2xR6QSLGUEg7KRzZD1Zlb+6hRANCAAR45jYHDm7UUvYHPum7sywe48VVXaX0
V66/IitCjB+wEdhQcR7xUXWKM97FP3qWuxvBZYmQuqgpGdqYgtbF2SVg
-----END PRIVATE KEY-----

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICHDCCAcKgAwIBAgIQZJlhQ2QHKszWsSdXAQ+0iDAKBggqhkjOPQQDAjBrMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRgwFgYDVQQDEw9jYS5ob3Nw
aXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBmMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j
aXNjbzENMAsGA1UECxMEcGVlcjEbMBkGA1UEAxMScGVlcjIuaG9zcGl0YWwuY29t
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeOY2Bw5u1FL2Bz7pu7MsHuPFVV2l
9FeuvyIrQowfsBHYUHEe8VF1ijPexT96lrsbwWWJkLqoKRnamILWxdklYKNNMEsw
DgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgiQzGzEjx
WwomiAU9J0pqT3P7484Sr2Cx7a57JF0ZUCYwCgYIKoZIzj0EAwIDSAAwRQIhALIk
iorT1/TsR0L7Gn7Od1VEHVlbK4hUWXbEgqz9B1NRAiBQx25OMZfQM0+j1slQwYgE
TexwSa8LfFPPVyKfc6m02Q==
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSDCCAe6gAwIBAgIRAKGluYd28isXUJzCGMxHZV4wCgYIKoZIzj0EAwIwbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIS4qL4gtG2T5
B54Vr2JJ7H7M2EzyOrRzvqgX3FWNrl/p3j1albcaaQZGPQtZsnltJH3MMNII3Vgm
bW908vh286NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBfMKNMs3IpZGj2
DABPe1+jLwHEGvaSdesz+yMOavu9OjAKBggqhkjOPQQDAgNIADBFAiB4C9RpAU4s
nuqX4hvOeyoXukChN7kh9gbOB3tVB0mtaAIhAM27SDfOwCN/Wa5p8ph2UR1tFVeO
hcjBpSsxFF/vXfay
-----END CERTIFICATE-----

View File

@ -0,0 +1,15 @@
-----BEGIN CERTIFICATE-----
MIICSDCCAe6gAwIBAgIRAKGluYd28isXUJzCGMxHZV4wCgYIKoZIzj0EAwIwbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMB4XDTI1MTEwMzA4NDIwMFoXDTM1MTEwMTA4NDIwMFowbjEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG
cmFuY2lzY28xFTATBgNVBAoTDGhvc3BpdGFsLmNvbTEbMBkGA1UEAxMSdGxzY2Eu
aG9zcGl0YWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIS4qL4gtG2T5
B54Vr2JJ7H7M2EzyOrRzvqgX3FWNrl/p3j1albcaaQZGPQtZsnltJH3MMNII3Vgm
bW908vh286NtMGswDgYDVR0PAQH/BAQDAgGmMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdDgQiBCBfMKNMs3IpZGj2
DABPe1+jLwHEGvaSdesz+yMOavu9OjAKBggqhkjOPQQDAgNIADBFAiB4C9RpAU4s
nuqX4hvOeyoXukChN7kh9gbOB3tVB0mtaAIhAM27SDfOwCN/Wa5p8ph2UR1tFVeO
hcjBpSsxFF/vXfay
-----END CERTIFICATE-----

View File

@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICozCCAkqgAwIBAgIQXQ74jH1BzgHXY5rLZ1I1kjAKBggqhkjOPQQDAjBuMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEVMBMGA1UEChMMaG9zcGl0YWwuY29tMRswGQYDVQQDExJ0bHNjYS5o
b3NwaXRhbC5jb20wHhcNMjUxMTAzMDg0MjAwWhcNMzUxMTAxMDg0MjAwWjBXMQsw
CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy
YW5jaXNjbzEbMBkGA1UEAxMScGVlcjIuaG9zcGl0YWwuY29tMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEGTblvwD42JFnHOhcqhiURkJftIvLMUpZkvm0OL8yWga/
gC8t4/y+gIvuMh/6BTbzn9Z+biOueNcQG4wrrH8gNqOB4DCB3TAOBgNVHQ8BAf8E
BAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQC
MAAwKwYDVR0jBCQwIoAgXzCjTLNyKWRo9gwAT3tfoy8BxBr2knXrM/sjDmr7vTow
cQYDVR0RBGowaIIScGVlcjIuaG9zcGl0YWwuY29tggVwZWVyMoIJbG9jYWxob3N0
ghJwZWVyMC5ob3NwaXRhbC5jb22CEnBlZXIxLmhvc3BpdGFsLmNvbYIScGVlcjIu
aG9zcGl0YWwuY29thwR/AAABMAoGCCqGSM49BAMCA0cAMEQCIGnUbAf13PqwKCH3
nmXiwV3A3C4DAagIgK9nZP/yx0PyAiB5bTh0n/jUF2CSUEM0BRbzdc18dr4PpwZp
SF1K/M/w8g==
-----END CERTIFICATE-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZ3LcIMhnQi5ePQxf
S3M6DAFDgF7OZ7Vfn9MaPm9EzIWhRANCAAQZNuW/APjYkWcc6FyqGJRGQl+0i8sx
SlmS+bQ4vzJaBr+ALy3j/L6Ai+4yH/oFNvOf1n5uI6541xAbjCusfyA2
-----END PRIVATE KEY-----

View File

@ -0,0 +1,5 @@
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoVEf3rgW6VAU+YyX
9VWzV3A3j7Xny3Ocle5O5t7IXfOhRANCAAQhLioviC0bZPkHnhWvYknsfszYTPI6
tHO+qBfcVY2uX+nePVqVtxppBkY9C1myeW0kfcww0gjdWCZtb3Ty+Hbz
-----END PRIVATE KEY-----

Some files were not shown because too many files have changed in this diff Show More