(feat) CRU Log Rekam Medis + Obat
This commit is contained in:
parent
3778b555a8
commit
a3bd6e028a
|
|
@ -9,6 +9,7 @@ import { TindakanDokterModule } from './modules/tindakandokter/tindakandokter.mo
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { PrismaModule } from './modules/prisma/prisma.module';
|
import { PrismaModule } from './modules/prisma/prisma.module';
|
||||||
import { AuthModule } from './modules/auth/auth.module';
|
import { AuthModule } from './modules/auth/auth.module';
|
||||||
|
import { FabricModule } from './modules/fabric/fabric.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
|
@ -22,7 +23,7 @@ import { AuthModule } from './modules/auth/auth.module';
|
||||||
RekamMedisModule,
|
RekamMedisModule,
|
||||||
ObatModule,
|
ObatModule,
|
||||||
PrismaModule,
|
PrismaModule,
|
||||||
AuthModule,
|
FabricModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
|
|
|
||||||
5
backend/api/src/common/crypto/hash.ts
Normal file
5
backend/api/src/common/crypto/hash.ts
Normal 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');
|
||||||
|
};
|
||||||
|
|
@ -1,24 +1,18 @@
|
||||||
import { connect, signers } from '@hyperledger/fabric-gateway';
|
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 crypto from 'node:crypto';
|
||||||
import fs from 'node:fs/promises';
|
import fs from 'node:fs/promises';
|
||||||
import path from 'node:path';
|
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 channelName = process.env.CHANNEL_NAME || 'mychannel';
|
||||||
const chaincodeName = process.env.CHAINCODE_NAME || 'logVerification';
|
const chaincodeName = process.env.CHAINCODE_NAME || 'logVerification';
|
||||||
const mspId = process.env.MSP_ID || 'HospitalMSP';
|
const mspId = process.env.MSP_ID || 'HospitalMSP';
|
||||||
|
|
||||||
// Path to crypto materials - adjusted for your hospital network structure
|
|
||||||
const cryptoPath =
|
const cryptoPath =
|
||||||
process.env.CRYPTO_PATH ||
|
process.env.CRYPTO_PATH ||
|
||||||
path.resolve(
|
path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
'../../',
|
'../../../../',
|
||||||
'blockchain',
|
'blockchain',
|
||||||
'network',
|
'network',
|
||||||
'organizations',
|
'organizations',
|
||||||
|
|
@ -26,26 +20,27 @@ const cryptoPath =
|
||||||
'hospital.com',
|
'hospital.com',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Path to user private key directory
|
|
||||||
const keyDirectoryPath =
|
const keyDirectoryPath =
|
||||||
process.env.KEY_DIRECTORY_PATH ||
|
process.env.KEY_DIRECTORY_PATH ||
|
||||||
path.resolve(cryptoPath, 'users', 'Admin@hospital.com', 'msp', 'keystore');
|
path.resolve(cryptoPath, 'users', 'Admin@hospital.com', 'msp', 'keystore');
|
||||||
|
|
||||||
// Path to user certificate directory
|
|
||||||
const certDirectoryPath =
|
const certDirectoryPath =
|
||||||
process.env.CERT_DIRECTORY_PATH ||
|
process.env.CERT_DIRECTORY_PATH ||
|
||||||
path.resolve(cryptoPath, 'users', 'Admin@hospital.com', 'msp', 'signcerts');
|
path.resolve(cryptoPath, 'users', 'Admin@hospital.com', 'msp', 'signcerts');
|
||||||
|
|
||||||
// Path to peer tls certificate
|
|
||||||
const tlsCertPath =
|
const tlsCertPath =
|
||||||
process.env.TLS_CERT_PATH ||
|
process.env.TLS_CERT_PATH ||
|
||||||
path.resolve(cryptoPath, 'peers', 'peer0.hospital.com', 'tls', 'ca.crt');
|
path.resolve(cryptoPath, 'peers', 'peer0.hospital.com', 'tls', 'ca.crt');
|
||||||
|
|
||||||
// Gateway peer endpoint
|
|
||||||
const peerEndpoint = process.env.PEER_ENDPOINT || 'localhost:7051';
|
const peerEndpoint = process.env.PEER_ENDPOINT || 'localhost:7051';
|
||||||
const peerHostAlias = process.env.PEER_HOST_ALIAS || 'peer0.hospital.com';
|
const peerHostAlias = process.env.PEER_HOST_ALIAS || 'peer0.hospital.com';
|
||||||
|
|
||||||
class FabricGateway {
|
class FabricGateway {
|
||||||
|
gateway: any;
|
||||||
|
network: any;
|
||||||
|
contract: any;
|
||||||
|
client: any;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.gateway = null;
|
this.gateway = null;
|
||||||
this.network = null;
|
this.network = null;
|
||||||
|
|
@ -53,9 +48,6 @@ class FabricGateway {
|
||||||
this.client = null;
|
this.client = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new gRPC connection to the gateway server
|
|
||||||
*/
|
|
||||||
async newGrpcConnection() {
|
async newGrpcConnection() {
|
||||||
const tlsRootCert = await fs.readFile(tlsCertPath);
|
const tlsRootCert = await fs.readFile(tlsCertPath);
|
||||||
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
|
const tlsCredentials = grpc.credentials.createSsl(tlsRootCert);
|
||||||
|
|
@ -63,20 +55,31 @@ class FabricGateway {
|
||||||
'grpc.ssl_target_name_override': peerHostAlias,
|
'grpc.ssl_target_name_override': peerHostAlias,
|
||||||
'grpc.keepalive_time_ms': 120000,
|
'grpc.keepalive_time_ms': 120000,
|
||||||
'grpc.keepalive_timeout_ms': 5000,
|
'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.max_pings_without_data': 0,
|
||||||
'grpc.http2.min_time_between_pings_ms': 10000,
|
'grpc.http2.min_time_between_pings_ms': 10000,
|
||||||
'grpc.http2.min_ping_interval_without_data_ms': 300000,
|
'grpc.http2.min_ping_interval_without_data_ms': 300000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async ensureConnected() {
|
||||||
* Create a new identity for the user
|
if (!this.contract) {
|
||||||
*/
|
console.log('Not connected, attempting to reconnect...');
|
||||||
|
await this.connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async newIdentity() {
|
async newIdentity() {
|
||||||
const certificateDirectoryPath = certDirectoryPath;
|
const certificateDirectoryPath = certDirectoryPath;
|
||||||
const certificateFiles = await fs.readdir(certificateDirectoryPath);
|
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(
|
const certificatePath = path.resolve(
|
||||||
certificateDirectoryPath,
|
certificateDirectoryPath,
|
||||||
certificateFile,
|
certificateFile,
|
||||||
|
|
@ -85,9 +88,6 @@ class FabricGateway {
|
||||||
return { mspId, credentials: certificate };
|
return { mspId, credentials: certificate };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new signer for the user's private key
|
|
||||||
*/
|
|
||||||
async newSigner() {
|
async newSigner() {
|
||||||
const keyDirectoryFiles = await fs.readdir(keyDirectoryPath);
|
const keyDirectoryFiles = await fs.readdir(keyDirectoryPath);
|
||||||
const keyFile = keyDirectoryFiles[0];
|
const keyFile = keyDirectoryFiles[0];
|
||||||
|
|
@ -97,26 +97,19 @@ class FabricGateway {
|
||||||
return signers.newPrivateKeySigner(privateKey);
|
return signers.newPrivateKeySigner(privateKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize and connect to the Fabric network
|
|
||||||
*/
|
|
||||||
async connect() {
|
async connect() {
|
||||||
try {
|
try {
|
||||||
console.log('Connecting to Hyperledger Fabric network...');
|
console.log('Connecting to Hyperledger Fabric network...');
|
||||||
|
|
||||||
// Create gRPC connection
|
|
||||||
this.client = await this.newGrpcConnection();
|
this.client = await this.newGrpcConnection();
|
||||||
|
|
||||||
// Create identity and signer
|
|
||||||
const identity = await this.newIdentity();
|
const identity = await this.newIdentity();
|
||||||
const signer = await this.newSigner();
|
const signer = await this.newSigner();
|
||||||
|
|
||||||
// Connect to gateway
|
|
||||||
this.gateway = connect({
|
this.gateway = connect({
|
||||||
client: this.client,
|
client: this.client,
|
||||||
identity,
|
identity,
|
||||||
signer,
|
signer,
|
||||||
// Default timeouts for different gRPC calls
|
|
||||||
evaluateOptions: () => {
|
evaluateOptions: () => {
|
||||||
return { deadline: Date.now() + 5000 };
|
return { deadline: Date.now() + 5000 };
|
||||||
},
|
},
|
||||||
|
|
@ -131,7 +124,6 @@ class FabricGateway {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get network and contract
|
|
||||||
this.network = this.gateway.getNetwork(channelName);
|
this.network = this.gateway.getNetwork(channelName);
|
||||||
this.contract = this.network.getContract(chaincodeName);
|
this.contract = this.network.getContract(chaincodeName);
|
||||||
|
|
||||||
|
|
@ -143,9 +135,6 @@ class FabricGateway {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Disconnect from the network
|
|
||||||
*/
|
|
||||||
async disconnect() {
|
async disconnect() {
|
||||||
if (this.gateway) {
|
if (this.gateway) {
|
||||||
this.gateway.close();
|
this.gateway.close();
|
||||||
|
|
@ -156,62 +145,22 @@ class FabricGateway {
|
||||||
console.log('Disconnected from Fabric network');
|
console.log('Disconnected from Fabric network');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async storeLog(
|
||||||
* Log verification result to blockchain (evaluate only, no commit)
|
id: string,
|
||||||
* @param {string} proofHash - Hash of the proof
|
event: string,
|
||||||
* @param {string} idVisit - Visit ID
|
user_id: string,
|
||||||
* @param {boolean} isValid - Whether the proof is valid
|
payload: string,
|
||||||
* @param {Date} timestamp - Timestamp of verification
|
): Promise<{ transactionId: string; status: string }> {
|
||||||
*/
|
|
||||||
async logVerification(proofHash, idVisit, isValid, timestamp) {
|
|
||||||
try {
|
try {
|
||||||
|
await this.ensureConnected();
|
||||||
if (!this.contract) {
|
if (!this.contract) {
|
||||||
throw new Error('Not connected to network. Call connect() first.');
|
throw new Error('Not connected to network. Call connect() first.');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Evaluating verification log on blockchain...');
|
console.log(`Submitting log storage transaction for log ID: ${id}...`);
|
||||||
|
const payloadString: string = payload;
|
||||||
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...');
|
|
||||||
|
|
||||||
const transaction = this.contract.newProposal('storeLog', {
|
const transaction = this.contract.newProposal('storeLog', {
|
||||||
arguments: [
|
arguments: [id, event, user_id, payloadString],
|
||||||
idVisit,
|
|
||||||
JSON.stringify(proofHash),
|
|
||||||
isValid.toString(),
|
|
||||||
timestamp.toISOString(),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const transactionId = await transaction.getTransactionId();
|
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 {
|
return {
|
||||||
transactionId,
|
transactionId,
|
||||||
status: commitStatus,
|
status: commitStatus,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to submit verification transaction:', error);
|
console.error('Failed to store log:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
async getLogById(id: string) {
|
||||||
* Query verification logs by visit ID
|
|
||||||
* @param {string} idVisit - Visit ID to query
|
|
||||||
*/
|
|
||||||
async queryVerificationsByVisitId(idVisit) {
|
|
||||||
try {
|
try {
|
||||||
if (!this.contract) {
|
if (!this.contract) {
|
||||||
throw new Error('Not connected to network. Call connect() first.');
|
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(
|
const resultBytes = await this.contract.evaluateTransaction(
|
||||||
'readLog',
|
'getLogById',
|
||||||
idVisit,
|
id,
|
||||||
);
|
);
|
||||||
const resultString = new TextDecoder().decode(resultBytes);
|
const resultJson = new TextDecoder().decode(resultBytes);
|
||||||
const result = JSON.parse(resultString);
|
const result = JSON.parse(resultJson);
|
||||||
|
|
||||||
console.log('Query successful');
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to query verifications:', error);
|
console.error('Failed to get log by ID:', 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);
|
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -323,5 +213,4 @@ class FabricGateway {
|
||||||
|
|
||||||
export default FabricGateway;
|
export default FabricGateway;
|
||||||
|
|
||||||
// Export a singleton instance for convenience
|
|
||||||
export const fabricGateway = new FabricGateway();
|
export const fabricGateway = new FabricGateway();
|
||||||
|
|
@ -10,6 +10,7 @@ import { ValidationPipe } from '@nestjs/common';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
|
app.enableShutdownHooks();
|
||||||
const configService = app.get(ConfigService);
|
const configService = app.get(ConfigService);
|
||||||
app.setGlobalPrefix('api/');
|
app.setGlobalPrefix('api/');
|
||||||
app.enableCors({
|
app.enableCors({
|
||||||
|
|
@ -26,6 +27,7 @@ async function bootstrap() {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
app.use(cookieParser(configService.get<string>('COOKIE_SECRET')));
|
app.use(cookieParser(configService.get<string>('COOKIE_SECRET')));
|
||||||
|
|
||||||
await app.listen(configService.get<number>('PORT') ?? 1323);
|
await app.listen(configService.get<number>('PORT') ?? 1323);
|
||||||
}
|
}
|
||||||
bootstrap();
|
bootstrap();
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
},
|
||||||
|
);
|
||||||
8
backend/api/src/modules/fabric/fabric.module.ts
Normal file
8
backend/api/src/modules/fabric/fabric.module.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { FabricService } from './fabric.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [FabricService],
|
||||||
|
exports: [FabricService],
|
||||||
|
})
|
||||||
|
export class FabricModule {}
|
||||||
18
backend/api/src/modules/fabric/fabric.service.spec.ts
Normal file
18
backend/api/src/modules/fabric/fabric.service.spec.ts
Normal 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();
|
||||||
|
});
|
||||||
|
});
|
||||||
39
backend/api/src/modules/fabric/fabric.service.ts
Normal file
39
backend/api/src/modules/fabric/fabric.service.ts
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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' })
|
@IsNotEmpty({ message: 'Event wajib diisi' })
|
||||||
@IsString({ message: 'Event harus berupa string' })
|
@IsString({ message: 'Event harus berupa string' })
|
||||||
@IsEnum(
|
@IsEnum(
|
||||||
|
|
@ -22,19 +33,11 @@ export class CreateLogDto {
|
||||||
@Length(1, 100, { message: 'Event maksimal 100 karakter' })
|
@Length(1, 100, { message: 'Event maksimal 100 karakter' })
|
||||||
event: string;
|
event: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: 'User ID wajib diisi' })
|
||||||
|
@IsNumber({}, { message: 'User ID harus berupa angka' })
|
||||||
|
user_id: number;
|
||||||
|
|
||||||
@IsNotEmpty({ message: 'Payload wajib diisi' })
|
@IsNotEmpty({ message: 'Payload wajib diisi' })
|
||||||
@IsJSON({ message: 'Payload harus berupa JSON yang valid' })
|
@IsString({ message: 'Payload harus berupa string' })
|
||||||
payload: {
|
payload: string;
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
@ -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')
|
@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();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { LogController } from './log.controller';
|
import { LogController } from './log.controller';
|
||||||
import { LogService } from './log.service';
|
import { LogService } from './log.service';
|
||||||
|
import { FabricModule } from '../fabric/fabric.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
|
imports: [FabricModule],
|
||||||
controllers: [LogController],
|
controllers: [LogController],
|
||||||
providers: [LogService]
|
providers: [LogService],
|
||||||
|
exports: [LogService],
|
||||||
})
|
})
|
||||||
export class LogModule {}
|
export class LogModule {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,20 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { StoreLogDto } from './dto/store-log.dto';
|
||||||
|
import { FabricService } from '../fabric/fabric.service';
|
||||||
|
|
||||||
@Injectable()
|
@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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
22
backend/api/src/modules/obat/dto/create-obat-dto.ts
Normal file
22
backend/api/src/modules/obat/dto/create-obat-dto.ts
Normal 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;
|
||||||
|
}
|
||||||
8
backend/api/src/modules/obat/dto/update-obat-dto.ts
Normal file
8
backend/api/src/modules/obat/dto/update-obat-dto.ts
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -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 { ObatService } from './obat.service';
|
||||||
import { AuthGuard } from '../auth/guard/auth.guard';
|
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')
|
@Controller('obat')
|
||||||
export class ObatController {
|
export class ObatController {
|
||||||
|
|
@ -25,4 +38,35 @@ export class ObatController {
|
||||||
order,
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
|
||||||
import { ObatController } from './obat.controller';
|
import { ObatController } from './obat.controller';
|
||||||
import { ObatService } from './obat.service';
|
import { ObatService } from './obat.service';
|
||||||
import { PrismaModule } from '../prisma/prisma.module';
|
import { PrismaModule } from '../prisma/prisma.module';
|
||||||
|
import { LogModule } from '../log/log.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [PrismaModule],
|
imports: [PrismaModule, LogModule],
|
||||||
controllers: [ObatController],
|
controllers: [ObatController],
|
||||||
providers: [ObatService],
|
providers: [ObatService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,42 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { BadRequestException, Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
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()
|
@Injectable()
|
||||||
export class ObatService {
|
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: {
|
async getAllObat(params: {
|
||||||
take?: number;
|
take?: number;
|
||||||
|
|
@ -43,4 +76,111 @@ export class ObatService {
|
||||||
totalCount: count,
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -4,13 +4,17 @@ import {
|
||||||
Get,
|
Get,
|
||||||
Header,
|
Header,
|
||||||
HttpCode,
|
HttpCode,
|
||||||
|
Param,
|
||||||
Post,
|
Post,
|
||||||
|
Put,
|
||||||
Query,
|
Query,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { RekammedisService } from './rekammedis.service';
|
import { RekammedisService } from './rekammedis.service';
|
||||||
import { CreateRekamMedisDto } from './dto/create-rekammedis.dto';
|
import { CreateRekamMedisDto } from './dto/create-rekammedis.dto';
|
||||||
import { AuthGuard } from '../auth/guard/auth.guard';
|
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')
|
@Controller('/rekammedis')
|
||||||
export class RekamMedisController {
|
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('/')
|
@Post('/')
|
||||||
@Header('Content-Type', 'application/json')
|
@Header('Content-Type', 'application/json')
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
async createRekamMedis(@Body() dto: CreateRekamMedisDto) {
|
async createRekamMedis(
|
||||||
return this.rekammedisService.createRekamMedis(dto);
|
@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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@ import { RekamMedisController } from './rekammedis.controller';
|
||||||
import { RekammedisService } from './rekammedis.service';
|
import { RekammedisService } from './rekammedis.service';
|
||||||
import { PrismaModule } from '../prisma/prisma.module';
|
import { PrismaModule } from '../prisma/prisma.module';
|
||||||
import { JwtModule } from '@nestjs/jwt';
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
import { LogModule } from '../log/log.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [PrismaModule],
|
imports: [PrismaModule, LogModule],
|
||||||
controllers: [RekamMedisController],
|
controllers: [RekamMedisController],
|
||||||
providers: [RekammedisService],
|
providers: [RekammedisService],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,14 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
import { Prisma, rekam_medis } from '@dist/generated/prisma';
|
import { Prisma, rekam_medis } from '@dist/generated/prisma';
|
||||||
import { CreateRekamMedisDto } from './dto/create-rekammedis.dto';
|
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()
|
@Injectable()
|
||||||
export class RekammedisService {
|
export class RekammedisService {
|
||||||
// Define known values as constants to avoid hardcoding everywhere
|
|
||||||
private readonly KNOWN_BLOOD_TYPES = ['A', 'B', 'AB', 'O'];
|
private readonly KNOWN_BLOOD_TYPES = ['A', 'B', 'AB', 'O'];
|
||||||
private readonly KNOWN_TINDAK_LANJUT = [
|
private readonly KNOWN_TINDAK_LANJUT = [
|
||||||
'Dipulangkan untuk Kontrol',
|
'Dipulangkan untuk Kontrol',
|
||||||
|
|
@ -26,7 +29,35 @@ export class RekammedisService {
|
||||||
'Selesai Pelayanan Rawat Jalan',
|
'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: {
|
async getAllRekamMedis(params: {
|
||||||
take?: number;
|
take?: number;
|
||||||
|
|
@ -58,13 +89,18 @@ export class RekammedisService {
|
||||||
tanggal_end,
|
tanggal_end,
|
||||||
umur_min,
|
umur_min,
|
||||||
umur_max,
|
umur_max,
|
||||||
jenis_kelamin,
|
|
||||||
kode_diagnosa,
|
kode_diagnosa,
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
const golDarahArray = params.gol_darah?.split(',') || [];
|
const golDarahArray = params.gol_darah?.split(',') || [];
|
||||||
const tindakLanjutArray = params.tindak_lanjut?.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 take = params.take ? parseInt(params.take.toString()) : 10;
|
||||||
const skipValue = skip
|
const skipValue = skip
|
||||||
? parseInt(skip.toString())
|
? parseInt(skip.toString())
|
||||||
|
|
@ -158,7 +194,7 @@ export class RekammedisService {
|
||||||
lte: parseInt(umur_max, 10),
|
lte: parseInt(umur_max, 10),
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
jenis_kelamin: jenis_kelamin ? { equals: jenis_kelamin } : undefined,
|
jenis_kelamin: jkCharacter ? { equals: jkCharacter } : undefined,
|
||||||
kode_diagnosa: kode_diagnosa ? { contains: kode_diagnosa } : undefined,
|
kode_diagnosa: kode_diagnosa ? { contains: kode_diagnosa } : undefined,
|
||||||
...golDarahFilter,
|
...golDarahFilter,
|
||||||
...tindakLanjutFilter,
|
...tindakLanjutFilter,
|
||||||
|
|
@ -169,7 +205,7 @@ export class RekammedisService {
|
||||||
take: take,
|
take: take,
|
||||||
where: whereClause,
|
where: whereClause,
|
||||||
orderBy: orderBy
|
orderBy: orderBy
|
||||||
? { [orderBy]: order || 'asc' }
|
? { [orderBy]: order || 'desc' }
|
||||||
: { waktu_visit: order ? order : 'asc' },
|
: { 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({
|
const latestId = await this.prisma.rekam_medis.findFirst({
|
||||||
orderBy: { waktu_visit: 'desc' },
|
orderBy: { waktu_visit: 'desc' },
|
||||||
});
|
});
|
||||||
|
|
@ -239,7 +281,7 @@ export class RekammedisService {
|
||||||
waktu_visit: new Date(),
|
waktu_visit: new Date(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const logData: CreateLogDto = {
|
const logData = {
|
||||||
event: 'rekam_medis_created',
|
event: 'rekam_medis_created',
|
||||||
payload: {
|
payload: {
|
||||||
dokter_id: 123,
|
dokter_id: 123,
|
||||||
|
|
@ -256,17 +298,21 @@ export class RekammedisService {
|
||||||
data: rekamMedis,
|
data: rekamMedis,
|
||||||
});
|
});
|
||||||
|
|
||||||
await tx.blockchain_log_queue.create({
|
const logPayload = JSON.stringify(logData.payload);
|
||||||
data: {
|
const payloadHash = sha256(logPayload);
|
||||||
event: logData.event,
|
const data = {
|
||||||
user_id: 9,
|
id: `REKAM_${newId}`,
|
||||||
payload: logData.payload,
|
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;
|
return newRekamMedis;
|
||||||
|
|
@ -275,4 +321,76 @@ export class RekammedisService {
|
||||||
throw error;
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,22 @@ export class TindakanDokterController {
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
async getAllTindakanDokter(
|
async getAllTindakanDokter(
|
||||||
@Query('take') take: number,
|
@Query('take') take: number,
|
||||||
|
@Query('id_visit') id_visit: string,
|
||||||
@Query('tindakan') tindakan: string,
|
@Query('tindakan') tindakan: string,
|
||||||
|
@Query('kelompok') kelompok_tindakan: string,
|
||||||
|
@Query('kategori') kategori_tindakan: string,
|
||||||
@Query('skip') skip: number,
|
@Query('skip') skip: number,
|
||||||
@Query('page') page: number,
|
@Query('page') page: number,
|
||||||
@Query('orderBy') orderBy: string,
|
@Query('orderBy') orderBy: string,
|
||||||
@Query('order') order: 'asc' | 'desc',
|
@Query('order') order: 'asc' | 'desc',
|
||||||
) {
|
) {
|
||||||
|
console.log();
|
||||||
return await this.tindakanDokterService.getAllTindakanDokter({
|
return await this.tindakanDokterService.getAllTindakanDokter({
|
||||||
take,
|
take,
|
||||||
|
id_visit,
|
||||||
tindakan,
|
tindakan,
|
||||||
|
kelompok_tindakan,
|
||||||
|
kategori_tindakan,
|
||||||
skip,
|
skip,
|
||||||
page,
|
page,
|
||||||
orderBy: orderBy ? { [orderBy]: order || 'asc' } : undefined,
|
orderBy: orderBy ? { [orderBy]: order || 'asc' } : undefined,
|
||||||
|
|
|
||||||
|
|
@ -10,28 +10,75 @@ export class TindakanDokterService {
|
||||||
skip?: number;
|
skip?: number;
|
||||||
take?: number;
|
take?: number;
|
||||||
page?: number;
|
page?: number;
|
||||||
|
id_visit?: string;
|
||||||
|
kelompok_tindakan?: string;
|
||||||
|
kategori_tindakan?: string;
|
||||||
tindakan?: string;
|
tindakan?: string;
|
||||||
orderBy?: Prisma.pemberian_tindakanOrderByWithRelationInput;
|
orderBy?: Prisma.pemberian_tindakanOrderByWithRelationInput;
|
||||||
order?: 'asc' | 'desc';
|
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 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
|
const skipValue = skip
|
||||||
? parseInt(skip.toString())
|
? parseInt(skip.toString())
|
||||||
: page
|
: page
|
||||||
? (parseInt(page.toString()) - 1) * take
|
? (parseInt(page.toString()) - 1) * take
|
||||||
: 0;
|
: 0;
|
||||||
|
console.log('Kelompok Tindakan Array:', kelompok_tindakanArray);
|
||||||
|
console.log('Kategori Tindakan Array:', kategori_tindakanArray);
|
||||||
const results = await this.prisma.pemberian_tindakan.findMany({
|
const results = await this.prisma.pemberian_tindakan.findMany({
|
||||||
skip: skipValue,
|
skip: skipValue,
|
||||||
take: take,
|
take: take,
|
||||||
where: {
|
where: {
|
||||||
tindakan: tindakan ? { contains: tindakan } : undefined,
|
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
|
orderBy: orderBy
|
||||||
? { [Object.keys(orderBy)[0]]: order || 'asc' }
|
? { [Object.keys(orderBy)[0]]: order || 'asc' }
|
||||||
: undefined,
|
: 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,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,8 +37,12 @@ export class UserController {
|
||||||
@UseGuards(AuthGuard, RolesGuard)
|
@UseGuards(AuthGuard, RolesGuard)
|
||||||
@Roles(UserRole.Admin)
|
@Roles(UserRole.Admin)
|
||||||
@HttpCode(200)
|
@HttpCode(200)
|
||||||
getAllUsers(): Promise<QueryUsersResponseDto[]> {
|
getAllUsers(
|
||||||
return this.userService.getAllUsers();
|
@Query('username') username: string,
|
||||||
|
@Query('page') page: number,
|
||||||
|
@Query('take') take: number,
|
||||||
|
) {
|
||||||
|
return this.userService.getAllUsers({ username, page, take: take });
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('/set-cookie')
|
@Get('/set-cookie')
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,32 @@ import { UserRole } from '../auth/dto/auth.dto';
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserService {
|
export class UserService {
|
||||||
constructor(private prisma: PrismaService) {}
|
constructor(private prisma: PrismaService) {}
|
||||||
async getAllUsers(): Promise<QueryUsersResponseDto[]> {
|
async getAllUsers(params: {
|
||||||
const users = await this.prisma.users.findMany();
|
username?: string;
|
||||||
return users.map((user) => ({
|
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,
|
id: user.id,
|
||||||
name: user.nama_lengkap,
|
name: user.nama_lengkap,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
|
|
@ -16,5 +39,9 @@ export class UserService {
|
||||||
created_at: user.created_at || undefined,
|
created_at: user.created_at || undefined,
|
||||||
updated_at: user.updated_at || undefined,
|
updated_at: user.updated_at || undefined,
|
||||||
}));
|
}));
|
||||||
|
return {
|
||||||
|
...usersResponse,
|
||||||
|
totalCount: count,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
backend/blockchain/.gitignore
vendored
Normal file
3
backend/blockchain/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
node_modules/*
|
||||||
|
channel-artifacts/*
|
||||||
|
organizations/*
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
coverage
|
||||||
39
backend/blockchain/chaincode/logVerification/.eslintrc.js
Normal file
39
backend/blockchain/chaincode/logVerification/.eslintrc.js
Normal 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 }]
|
||||||
|
}
|
||||||
|
};
|
||||||
15
backend/blockchain/chaincode/logVerification/.gitignore
vendored
Normal file
15
backend/blockchain/chaincode/logVerification/.gitignore
vendored
Normal 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
|
||||||
6
backend/blockchain/chaincode/logVerification/index.js
Normal file
6
backend/blockchain/chaincode/logVerification/index.js
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const logVerification = require('./lib/logVerification');
|
||||||
|
|
||||||
|
module.exports.LogVerification = logVerification;
|
||||||
|
module.exports.contracts = [logVerification];
|
||||||
|
|
@ -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;
|
||||||
3948
backend/blockchain/chaincode/logVerification/npm-shrinkwrap.json
generated
Normal file
3948
backend/blockchain/chaincode/logVerification/npm-shrinkwrap.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
50
backend/blockchain/chaincode/logVerification/package.json
Normal file
50
backend/blockchain/chaincode/logVerification/package.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
25
backend/blockchain/generate-artifacts.sh
Executable file
25
backend/blockchain/generate-artifacts.sh
Executable 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
|
||||||
BIN
backend/blockchain/network/channel-artifacts/config_block.pb
Normal file
BIN
backend/blockchain/network/channel-artifacts/config_block.pb
Normal file
Binary file not shown.
BIN
backend/blockchain/network/channel-artifacts/genesis.block
Normal file
BIN
backend/blockchain/network/channel-artifacts/genesis.block
Normal file
Binary file not shown.
BIN
backend/blockchain/network/channel-artifacts/mychannel.block
Normal file
BIN
backend/blockchain/network/channel-artifacts/mychannel.block
Normal file
Binary file not shown.
BIN
backend/blockchain/network/channel-artifacts/mychannel.tx
Normal file
BIN
backend/blockchain/network/channel-artifacts/mychannel.tx
Normal file
Binary file not shown.
11
backend/blockchain/network/config/collections_config.json
Normal file
11
backend/blockchain/network/config/collections_config.json
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "HospitalPrivateCollection",
|
||||||
|
"policy": "OR('HospitalMSP.member')",
|
||||||
|
"requiredPeerCount": 1,
|
||||||
|
"maxPeerCount": 3,
|
||||||
|
"blockToLive": 1000000,
|
||||||
|
"memberOnlyRead": true,
|
||||||
|
"memberOnlyWrite": true
|
||||||
|
}
|
||||||
|
]
|
||||||
179
backend/blockchain/network/config/configtx.yaml
Normal file
179
backend/blockchain/network/config/configtx.yaml
Normal 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
|
||||||
791
backend/blockchain/network/config/core.yaml
Normal file
791
backend/blockchain/network/config/core.yaml
Normal 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 channel’s 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 channel’s 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:
|
||||||
81
backend/blockchain/network/config/crypto-config.yaml
Normal file
81
backend/blockchain/network/config/crypto-config.yaml
Normal 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"
|
||||||
115
backend/blockchain/network/deployChaincode.sh
Executable file
115
backend/blockchain/network/deployChaincode.sh
Executable 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 "$@"
|
||||||
5
backend/blockchain/network/docker/.env
Normal file
5
backend/blockchain/network/docker/.env
Normal 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
|
||||||
150
backend/blockchain/network/docker/docker-compose.yaml
Normal file
150
backend/blockchain/network/docker/docker-compose.yaml
Normal 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
|
||||||
39
backend/blockchain/network/network.sh
Executable file
39
backend/blockchain/network/network.sh
Executable 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
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgYFDSkvlA3Ef+oZUT
|
||||||
|
9LDbeafnrwEuv23OhxneaQbdBkChRANCAAR2oP4J049hk9R2/JEyv4h5Ui0Iq6kN
|
||||||
|
JKbxFXZwZNa2Jms8uxopqlE1mrwQQM4DgFF4P1jckzcIB7Z/k2qxzOwj
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgD2ZA+jFQ8/sFuKOy
|
||||||
|
MasGELTJXhdPz5la44nK+reGAjGhRANCAAQ6ocKy3b9sgjCtqTMCP/uPlhi6aIlw
|
||||||
|
WMCTl3Lz9JkeVxXSUkMxWSp9OJm3K2pUjLYVX7ejsxtpdOE0Fz2EBPLN
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/ARTlMcxKEEhlMxA
|
||||||
|
TQVjBmsRRKiqobEPOSN/uI8GBi2hRANCAARJkiv9loBDyZ33XbOg8M0WZKdH+ba8
|
||||||
|
WT9ZuMunUOV/wVqgP4BN6c7MDQYYG4OKBFdYc1SLsOdkoIkL+5C2TpUi
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPhMkXhdQyGjzneZf
|
||||||
|
XQqXqIfXtjfWHST73Gu438vXgeqhRANCAASHs8anhwHeyHd4brPA5IPcLBlg70Yf
|
||||||
|
pVSyYXttHAB8p7cIX6NzJt15TvJwu2BfeLewjDtSXA2kqtC3b/uWZfAW
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNDSkX+blUZWH93Ho
|
||||||
|
zGD9hWiBT/boL5P2e2aX7fYE1iehRANCAAQoa32nhG94nCj3uzBGa9SgPfs0rCaE
|
||||||
|
PxJIpFQ3dWoUJePvnsF4RnhpqjAaWXbdwjy7dUC9EAUeIRJeu0eHuPJI
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgvpxkslG5HZI0fAhR
|
||||||
|
0TXMV97rPHYohdTsGlfSYjfHN6mhRANCAAQPdH/qSDVEmiir2kTlZJ7fT1gZ7Pj3
|
||||||
|
00LpDbbfeq1176lXHtjWZT4GeAYODqoRybmM+3cBn+VF4a3YqTn0qAe4
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg2kwHcYJUJ7oHbSlm
|
||||||
|
/2Koc1xt6RB5o0nKJNcMSb7kcIehRANCAATIigu5i2LnUdYr/S2YC9AsJhjFrXQC
|
||||||
|
mSOAe6WfY+l9sk9Kfd0U0D4Alxf72s6oTHUyz9AKiSEliJD63isElZ0W
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgg77lfA99A7OmI7bT
|
||||||
|
Qo4ZW5av+cpH7uokB+qL96t9eGOhRANCAARrYrhVWDHfkxDAvD7q0Qr3gX/8wvAL
|
||||||
|
k/R/acLIhAAfD65JbSJMHs2w/WpwHnIyIDlXpAGuWsX1S8iMTeMtP+OG
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgaHNDQ85FC1jSvPKA
|
||||||
|
dHRZz6kFyZoVMoR5MkJt8nQbj8ehRANCAASmtbVIjgi6WvNDzXxOCmxrvLY0wc7X
|
||||||
|
kClsv3CN7Im5Kiz6AE0fNSo348TPiYjv+ZLaPioBxoiJUutmPvKOQvsK
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgzGBT3anTXStu86ju
|
||||||
|
BCIDGm2G+SeH30af2nQeEdWuLaKhRANCAARfR4n+P7IQIuChln6SpcnV34ZGId7l
|
||||||
|
DfriFg0w1eSCsfPyU6FZoQVb35Vgvi/OhCI+vbKiAHgxJFPtm2xAKiy1
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoXVksNj43L20RjMj
|
||||||
|
807+tIkTPi6fj2jLinDbUs0EuWOhRANCAAQ/OoJOw0OgqzJTFKROenTRIC4ywPDl
|
||||||
|
tBoAgSJQWQOU1SFcTomSFYZuQpD9QZRXKnFq0DQjSasbsJyxdxBJKp7U
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgitvB9obBLXABTpkm
|
||||||
|
tlvP2xR6QSLGUEg7KRzZD1Zlb+6hRANCAAR45jYHDm7UUvYHPum7sywe48VVXaX0
|
||||||
|
V66/IitCjB+wEdhQcR7xUXWKM97FP3qWuxvBZYmQuqgpGdqYgtbF2SVg
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -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-----
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZ3LcIMhnQi5ePQxf
|
||||||
|
S3M6DAFDgF7OZ7Vfn9MaPm9EzIWhRANCAAQZNuW/APjYkWcc6FyqGJRGQl+0i8sx
|
||||||
|
SlmS+bQ4vzJaBr+ALy3j/L6Ai+4yH/oFNvOf1n5uI6541xAbjCusfyA2
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
|
|
@ -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
Loading…
Reference in New Issue
Block a user