/*
* Copyright IBM Corp. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
'use strict';
const FabricCAServices = require('fabric-ca-client');
const { Wallets } = require('fabric-network');
const {Client, User, Endorser, DiscoveryService, Discoverer, Committer} = require('fabric-common');
const fs = require('fs');
const path = require('path');
const elliptic = require('elliptic');
const { KEYUTIL } = require('jsrsasign');
const crypto = require('crypto');
async function main() {
try {
const enrollmentID = 'testUser'
var userEnrollmentSecret = 'testUserpw';
var userEnrollment;
// load the network configuration
const ccpPath = path.resolve(__dirname, '..', 'test-network', 'organizations', 'peerOrganizations', 'org1.example.com', 'connection-org1.json');
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
// Create a new CA client for interacting with the CA.
const caInfo = ccp.certificateAuthorities['ca.org1.example.com'];
const caTLSCACerts = caInfo.tlsCACerts.pem;
const ca = new FabricCAServices(caInfo.url, { trustedRoots: caTLSCACerts, verify: false }, caInfo.caName);
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = await Wallets.newFileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled an user.
const userIdentity = await wallet.get(enrollmentID);
if(userIdentity){
console.log('An identity for an user already exists in the wallet');
// Need to do: userEnrollment = userIdentity.getEnrollmentCertificate;
} else {
// Check to see if we've already enrolled the admin user.
const adminIdentity = await wallet.get('admin');
if (!adminIdentity) {
console.log('An identity for the admin user "admin" does not exists in the wallet. Enrolling Now...');
// Enroll the admin user, and import the new identity into the wallet.
const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' });
const x509Identity = {
credentials: {
certificate: enrollment.certificate,
privateKey: enrollment.key.toBytes(),
},
mspId: 'Org1MSP',
type: 'X.509',
};
await wallet.put('admin', x509Identity);
console.log('Successfully enrolled admin user "admin" and imported it into the wallet');
}
const adminId = await wallet.get('admin');
// build a user object for authenticating with the CA
const provider = wallet.getProviderRegistry().getProvider(adminId.type);
const adminUser = await provider.getUserContext(adminId, 'admin');
// Register the user
const userEnrollSecret = await ca.register({
affiliation: 'org1.department1',
enrollmentID: enrollmentID,
enrollmentSecret: userEnrollmentSecret,
role: 'client'
}, adminUser);
// Read CSR from File system
const csr = fs.readFileSync('csr.pem', 'utf8');
const req = {
enrollmentID: enrollmentID,
enrollmentSecret: userEnrollmentSecret,
csr: csr,
};
// Enroll the user with CSR, and import the new identity into the wallet.
userEnrollment = await ca.enroll(req);
const x509Identity = {
credentials: {
certificate: userEnrollment.certificate
},
mspId: 'Org1MSP',
type: 'X.509',
};
await wallet.put(enrollmentID, x509Identity);
console.log('Successfully enrolled an User and imported it into the wallet');
console.log(userEnrollment.certificate)
console.log(userEnrollment.key)
}
// This is a sample code for signing the digest from step 2 with EC.
// Different signature algorithm may have different interfaces
// ECDSA -- ASN1 OID: prime256v1 -- NIST CURVE: P-256 -- Signature Algorithm: ecdsa-with-SHA256 --
const privateKeyPEM = fs.readFileSync("private-key.pem", "utf8");
console.log("My key is: ", privateKeyPEM);
const { prvKeyHex } = KEYUTIL.getKey(privateKeyPEM); // convert the pem encoded key to hex encoded private key
const EC = elliptic.ec;
const ecdsaCurve = elliptic.curves['p256'];
const ecdsa = new EC(ecdsaCurve);
const signKey = ecdsa.keyFromPrivate(prvKeyHex, 'hex');
// Creating Client, Identity Context, etc
const client = new Client('myclient');
const channel = client.newChannel('mychannel');
const user = User.createUser(enrollmentID, userEnrollmentSecret, 'Org1MSP', userEnrollment.certificate, privateKeyPEM);
const idx = client.newIdentityContext(user);
// To get Service Discovery Results if suppose we need to get dynamic Peer and Orderer Info
// Right now - static peer and orderer objects were used
const discoverer = new Discoverer("peer0", client, "Org1MSP");
const endpoint = client.newEndpoint({
url: 'grpcs://localhost:7051',
pem : '-----BEGIN CERTIFICATE-----\n' +
'MIICJzCCAc2gAwIBAgIUa10ti6LkZFxoLszlnVvzkNdS3OAwCgYIKoZIzj0EAwIw\n' +
'cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\n' +
'EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\n' +
'Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwOTA0MDExOTAwWhcNMzcwODMxMDExOTAw\n' +
'WjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\n' +
'BAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\n' +
'Y2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFrx\n' +
'H9SZ/D8HKPDbrg3YY2Q+qyj5Dw/kHKcH4PErUNUNssLEi1SkovkgWda1sxcNpBCi\n' +
'NgnykaU3tMuMcvBm3MyjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\n' +
'AQH/AgEBMB0GA1UdDgQWBBTtq/lyW3VgSOAsty21Q5/4f/k4OTAKBggqhkjOPQQD\n' +
'AgNIADBFAiEA7PFPsmyplE991kF25h+UmscOA1xqDPsYxIAL4QEjXK4CIHxDyUjG\n' +
'RCtIvuZbtg80j2Rtchn+shF5afcIJqCzbcqI\n' +
'-----END CERTIFICATE-----\n',
"ssl-target-name-override" : 'peer0.org1.example.com',
requestTimeout: 3000
});
discoverer.setEndpoint(endpoint);
// await discoverer.connect()
const discovery = new DiscoveryService("basic", channel);
// const endorsement1 = channel.newEndorsement("basic");
// discovery.build(idx, {endorsement: endorsement1});
discovery.build(idx);
discovery.sign(idx);
const discovery_results = await discovery.send({targets: [discoverer], asLocalhost: true});
console.log(JSON.stringify(discovery_results))
// Creating Proposal
const endorsement = channel.newEndorsement("basic");
const build_options = {fcn: 'TransferAsset', args: ['asset2', 'Kavin']};
const proposalBytes = endorsement.build(idx, build_options);
// Calculate Hash for transaction Proposal Bytes
const hash = crypto.createHash('sha256').update(proposalBytes).digest('hex');
// Creating Signature
const sig = ecdsa.sign(Buffer.from(hash, 'hex'), signKey, { canonical: true });
const signature = Buffer.from(sig.toDER());
console.log('signature:', signature)
// Endorserer Objects
const peer0Org1Endorser = new Endorser("peer0Org1", client, "Org1MSP");
const peer0Org1Endpoint = client.newEndpoint({
url: 'grpcs://localhost:7051',
pem : '-----BEGIN CERTIFICATE-----\n' +
'MIICJzCCAc2gAwIBAgIUa10ti6LkZFxoLszlnVvzkNdS3OAwCgYIKoZIzj0EAwIw\n' +
'cDELMAkGA1UEBhMCVVMxFzAVBgNVBAgTDk5vcnRoIENhcm9saW5hMQ8wDQYDVQQH\n' +
'EwZEdXJoYW0xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\n' +
'Lm9yZzEuZXhhbXBsZS5jb20wHhcNMjIwOTA0MDExOTAwWhcNMzcwODMxMDExOTAw\n' +
'WjBwMQswCQYDVQQGEwJVUzEXMBUGA1UECBMOTm9ydGggQ2Fyb2xpbmExDzANBgNV\n' +
'BAcTBkR1cmhhbTEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMT\n' +
'Y2Eub3JnMS5leGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFrx\n' +
'H9SZ/D8HKPDbrg3YY2Q+qyj5Dw/kHKcH4PErUNUNssLEi1SkovkgWda1sxcNpBCi\n' +
'NgnykaU3tMuMcvBm3MyjRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAG\n' +
'AQH/AgEBMB0GA1UdDgQWBBTtq/lyW3VgSOAsty21Q5/4f/k4OTAKBggqhkjOPQQD\n' +
'AgNIADBFAiEA7PFPsmyplE991kF25h+UmscOA1xqDPsYxIAL4QEjXK4CIHxDyUjG\n' +
'RCtIvuZbtg80j2Rtchn+shF5afcIJqCzbcqI\n' +
'-----END CERTIFICATE-----\n',
"ssl-target-name-override" : 'peer0.org1.example.com',
requestTimeout: 3000
});
peer0Org1Endorser.setEndpoint(peer0Org1Endpoint);
await peer0Org1Endorser.connect();
console.log("peer0Org1Endorser status: ", await peer0Org1Endorser.checkConnection())
const peer0Org2Endorser = new Endorser("peer0Org2", client, "Org2MSP");
const peer0Org2Endpoint = client.newEndpoint({
url: 'grpcs://localhost:9051',
pem : '-----BEGIN CERTIFICATE-----\n' +
'MIICHzCCAcWgAwIBAgIUHcDOiu0zeZoOuyE20TgmAIAeahEwCgYIKoZIzj0EAwIw\n' +
'bDELMAkGA1UEBhMCVUsxEjAQBgNVBAgTCUhhbXBzaGlyZTEQMA4GA1UEBxMHSHVy\n' +
'c2xleTEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eub3Jn\n' +
'Mi5leGFtcGxlLmNvbTAeFw0yMjA5MDQwMTE5MDBaFw0zNzA4MzEwMTE5MDBaMGwx\n' +
'CzAJBgNVBAYTAlVLMRIwEAYDVQQIEwlIYW1wc2hpcmUxEDAOBgNVBAcTB0h1cnNs\n' +
'ZXkxGTAXBgNVBAoTEG9yZzIuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2NhLm9yZzIu\n' +
'ZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASuc9tSZ1VhaGCL\n' +
'Z6msge/UIo4jcn1vwpvgQ7Ih8h9FpypQeYqY5DNWLIzgMRD13wSQK8smvfcWQuW1\n' +
'SqNzQu9Po0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAd\n' +
'BgNVHQ4EFgQUzIcp1SbKBNLz3owIypQlg4Z5QdwwCgYIKoZIzj0EAwIDSAAwRQIh\n' +
'AILfLS4GgZYWVtR+MF25xrYRtkAkDhsNKZgsBzKlmHn0AiAmGDRBQ+JhcrOuiORn\n' +
'ghA0uKRpUa/JQbihG85bbXm1Kw==\n' +
'-----END CERTIFICATE-----\n',
"ssl-target-name-override" : 'peer0.org2.example.com',
requestTimeout: 3000
});
peer0Org2Endorser.setEndpoint(peer0Org2Endpoint);
await peer0Org2Endorser.connect();
console.log("peer0Org2Endorser status: ", await peer0Org2Endorser.checkConnection())
// Final - Sending Proposal Request
endorsement.sign(signature);
const proposalResponses = await endorsement.send({targets : [peer0Org1Endorser, peer0Org2Endorser]});
console.log(proposalResponses.responses);
// Committer Objects
const newCommitter = new Committer("orderer.example.com", client, "OrdererMSP");
const newCommitterEndpoint = client.newEndpoint({
url: 'grpcs://localhost:7050',
pem : '-----BEGIN CERTIFICATE-----\n' +
'MIICCzCCAbGgAwIBAgIUDI2rLaEJAyTPibHGw4xk3gXALnYwCgYIKoZIzj0EAwIw\n' +
'YjELMAkGA1UEBhMCVVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcg\n' +
'WW9yazEUMBIGA1UEChMLZXhhbXBsZS5jb20xFzAVBgNVBAMTDmNhLmV4YW1wbGUu\n' +
'Y29tMB4XDTIyMDkwNDAxMTkwMFoXDTM3MDgzMTAxMTkwMFowYjELMAkGA1UEBhMC\n' +
'VVMxETAPBgNVBAgTCE5ldyBZb3JrMREwDwYDVQQHEwhOZXcgWW9yazEUMBIGA1UE\n' +
'ChMLZXhhbXBsZS5jb20xFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMFkwEwYHKoZI\n' +
'zj0CAQYIKoZIzj0DAQcDQgAEUneOJ/VC/2dZkkVJqtrHo+8hBkLnRnxoCQI0y+Sh\n' +
'yrFErNiL7XHCbHRglIoULixoGdcLCo2COOhQrHfMjyc7TqNFMEMwDgYDVR0PAQH/\n' +
'BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFK7gKwF7q/ByOeyr\n' +
'd/qev66CN8OfMAoGCCqGSM49BAMCA0gAMEUCIQDulgwk7Nt/U92BB2QSEdDx6hG+\n' +
'SBypZMmV7o5RWUugMAIgUaQuk9g9g+s1BtbFvlRTfmBP2oaZZiKPp2+iKVfzE+4=\n' +
'-----END CERTIFICATE-----\n',
"ssl-target-name-override" : 'orderer.example.com',
requestTimeout: 3000
});
newCommitter.setEndpoint(newCommitterEndpoint);
await newCommitter.connect();
console.log("Committer Connection Status: ", await newCommitter.checkConnection())
// Commit the Transaction
const commitReq = endorsement.newCommit();
commitReq.build(idx);
commitReq.sign(idx);
const res = await commitReq.send({targets : [newCommitter]});
console.log("Commit Result: ", res)
} catch (error) {
console.error(`Failed to enroll admin user "admin": ${error}`);
process.exit(1);
}
}
main();