UNPKG

@decaf-ts/fabric-weaver

Version:
784 lines 137 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CoreCLI = void 0; const logging_1 = require("@decaf-ts/logging"); const base_cli_1 = require("./base-cli.cjs"); const ca_server_1 = require("../scripts/ca-server.cjs"); const parsers_1 = require("../../utils/parsers.cjs"); const constants_1 = require("../constants/constants.cjs"); const ca_client_1 = require("../scripts/ca-client.cjs"); const configtxgen_1 = require("../scripts/configtxgen.cjs"); const node_ou_1 = require("../../fabric/node-ou/node-ou.cjs"); const orderer_1 = require("../scripts/orderer.cjs"); const peer_1 = require("../scripts/peer.cjs"); const osn_admin_1 = require("../scripts/osn-admin.cjs"); const peer_middleware_1 = require("../constants/peer-middleware.cjs"); const PeerMiddleware_1 = require("../middlewares/PeerMiddleware.cjs"); const compile_1 = require("../contracts/compile.cjs"); class CoreCLI extends base_cli_1.BaseCLI { constructor() { super("weaver-core", "CLI for core fabric functionality"); this.setup(); } setup() { const methodNames = Object.getOwnPropertyNames(Object.getPrototypeOf(this)).filter((name) => name !== "constructor" && typeof this[name] === "function" && name !== "setup"); for (const methodName of methodNames) { try { this[methodName](); } catch (error) { console.error(`Error calling method ${methodName}:`, error); } } } issueFabricCAServer() { this.program .command("issue-ca") .description("Generates a Fabric CA Server config file") .option("-d, --debug", "Enables debug mode") .option("--config-version <string>", "Fabric CA Server Config version") .option("--port <number>", "Port number for the Fabric CA Server", parsers_1.safeParseInt) .option("--cors-enabled", "Enable CORS") .option("--cors-origins <CommaSeparatedValues>", "Comma Separated List of allowed CORS origins", parsers_1.safeParseCSV) .option("--crl-size <number>", "CRL Size Limit", parsers_1.safeParseInt) .option("--tls-enabled", "Enable TLS") .option("--tls-certfile <string>", "TLS Certificate File") .option("--tls-keyfile <string>", "TLS Key File") .option("--tls-client-certfiles <CSV>", "TLS Client Certificate Files", parsers_1.safeParseCSV) .option("--tls-client-type <string>", "TLS Client Type") .option("--ca-name <string>", "CA Name") .option("--ca-keyfile <string>", "CA Key File") .option("--ca-certfile <string>", "CA Certificate File") .option("--ca-chainfile <string>", "CA Chain File") .option("--ca-reenroll-ignore-cert-expiry", "Reenroll Ignore Cert Expiry Flag") //TODO: Change so it can handle multiple identities .option("--bootstrap-users <USER:PASSWORD>", "Bootstrap user:password") .option("--no-tls-profile", "Remove tls profile") .option("--no-ca-profile", "Remove ca profile") .option("--csr-cn <string>", "CSR Common Name") .option("--csr-hosts <CSV>", "CSR Hosts", parsers_1.safeParseCSV) .option("--csr-keyrequest-algo <string>", "CSR Key Request Algo") .option("--csr-keyrequest-size <number>", "CSR Key Request Size", parsers_1.safeParseInt) .option("--csr-ca-expiry <string>", "CSR CA Expiry") .option("--csr-ca-pathlength <number>", "CSR CA Pathlength", parsers_1.safeParseInt) //TODO: Missing a way to deal with names in CSR //TODO: Map setMaxEnrollments //TODO: Map setDatabase //TODO: Map setLDAP //TODO: Map setAffiliations //TODO: Map setSigning //TODO: Map setIdemix //TODO: Map setBCCSP //TODO: Map setCACount //TODO: Map setCAFiles //TODO: Map setIntermediate //TODO: Map setPasswordAttempts .option("--operations-listen-address <string>", "Operations Listen Address") .option("--operations-tls-enabled", "Operations TLS Enabled") .option("--operations-tls-certfile <string>", "Operations TLS Certificate File") .option("--operations-tls-keyfile <string>", "Operations TLS Key File") .option("--operations-tls-clientauth-required", "Operations TLS Client Auth Required") .option("--operations-tls-clientauth-rootcas <CSV>", "List of client root ca files", parsers_1.safeParseCSV) .option("--home <string>", "Home directory for the Fabric CA Server") .option("--metrics-provider <string>", "Metrics Provider") .option("--metrics-statsd-network", "Metrics StatsD Network") .option("--metrics-statsd-address", "Metrics StatsD Address") .option("--metrics-statsd-prefix", "Metrics StatsD Prefix") .option("--metris-statsd-write-interval", "Metrics StatsD Write Interval") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Issuing Fabric CA Server config..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); let user, password; if (options.bootstrapUsers !== undefined) { [user, password] = options.bootstrapUsers.split(constants_1.COLON_SEPARATOR); } this.log.info(`Bootstrap users: ${user}:${password}`); try { (0, ca_server_1.issueCA)(this.log, options.home, options.configVersion, options.port, { enabled: options.corsEnabled, origins: options.corsOrigins, }, options.debug, options.crlSize, { enabled: options.tlsEnabled, certfile: options.tlsCertfile, keyfile: options.tlsKeyfile, clientauth: { type: options.tlsClientType, certfiles: options.tlsClientCertfiles, }, }, { name: options.caName, keyfile: options.caKeyfile, certfile: options.caCertfile, chainfile: options.caChainfile, reenrollIgnoreCertExpiry: options.caReenrollIgnoreCertExpiry, }, [ { name: user, pass: password, }, ], options.caProfile, options.tlsProfile, { cn: options.csrCn, hosts: options.csrHosts, keyrequest: { algo: options.csrKeyrequestAlgo, size: options.csrKeyrequestSize, }, ca: { expiry: options.csrCaExpiry, pathlength: options.csrCaPathlength, }, names: undefined, // TODO: Implement names in CSR }, { listenAddress: options.operationsListenAddress, tls: { enabled: options.operationsTlsEnabled, cert: { file: options.operationsTlsCertfile, }, key: { file: options.operationsTlsKeyfile, }, clientAuthRequired: options.operationsTlsClientauthRequired, clientRootCAs: { files: options.operationsTlsClientauthRootcas, }, }, }, { provider: options.metricsProvider, statsd: { network: options.metricsStatsdNetwork, address: options.metricsStatsdAddress, prefix: options.metricsStatsdPrefix, writeInterval: options.metricsStatsdWriteInterval, }, }); } catch (error) { this.log.error(`"Error issuing Fabric CA Server config: ${error}"`); return; } this.log.info("Fabric CA Server config issued successfully!"); }); } startFabricCAServer() { this.program .command("start") .description("Starts the Fabric CA Server") .option("-d, --debug", "Enables debug mode") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Starting Fabric CA Server..."); try { await (0, ca_server_1.startCA)(this.log); } catch (error) { this.log.error(`Error starting Fabric CA Server: ${error}`); return; } this.log.info("Fabric CA Server started successfully!"); }); } bootCAServer() { this.program .command("boot-ca") .description("Generates a Fabric CA Server config file") .option("-d, --debug", "Enables debug mode") .option("--config-version <string>", "Fabric CA Server Config version") .option("--port <number>", "Port number for the Fabric CA Server", parsers_1.safeParseInt) .option("--cors-enabled", "Enable CORS") .option("--cors-origins <CommaSeparatedValues>", "Comma Separated List of allowed CORS origins", parsers_1.safeParseCSV) .option("--crl-size <number>", "CRL Size Limit", parsers_1.safeParseInt) .option("--tls-enabled", "Enable TLS") .option("--tls-certfile <string>", "TLS Certificate File") .option("--tls-keyfile <string>", "TLS Key File") .option("--tls-client-certfiles <CSV>", "TLS Client Certificate Files", parsers_1.safeParseCSV) .option("--tls-client-type <string>", "TLS Client Type") .option("--ca-name <string>", "CA Name") .option("--ca-keyfile <string>", "CA Key File") .option("--ca-certfile <string>", "CA Certificate File") .option("--ca-chainfile <string>", "CA Chain File") .option("--ca-reenroll-ignore-cert-expiry", "Reenroll Ignore Cert Expiry Flag") //TODO: Change so it can handle multiple identities .option("--bootstrap-users <USER:PASSWORD>", "Bootstrap user:password") .option("--no-tls-profile", "Remove tls profile") .option("--no-ca-profile", "Remove ca profile") .option("--csr-cn <string>", "CSR Common Name") .option("--csr-hosts <CSV>", "CSR Hosts", parsers_1.safeParseCSV) .option("--csr-keyrequest-algo <string>", "CSR Key Request Algo") .option("--csr-keyrequest-size <number>", "CSR Key Request Size", parsers_1.safeParseInt) .option("--csr-ca-expiry <string>", "CSR CA Expiry") .option("--csr-ca-pathlength <number>", "CSR CA Pathlength", parsers_1.safeParseInt) //TODO: Missing a way to deal with names in CSR //TODO: Map setMaxEnrollments //TODO: Map setDatabase //TODO: Map setLDAP //TODO: Map setAffiliations //TODO: Map setSigning //TODO: Map setIdemix //TODO: Map setBCCSP //TODO: Map setCACount //TODO: Map setCAFiles //TODO: Map setIntermediate //TODO: Map setPasswordAttempts .option("--operations-listen-address <string>", "Operations Listen Address") .option("--operations-tls-enabled", "Operations TLS Enabled") .option("--operations-tls-certfile <string>", "Operations TLS Certificate File") .option("--operations-tls-keyfile <string>", "Operations TLS Key File") .option("--operations-tls-clientauth-required", "Operations TLS Client Auth Required") .option("--operations-tls-clientauth-rootcas <CSV>", "List of client root ca files", parsers_1.safeParseCSV) .option("--home <string>", "Home directory for the Fabric CA Server") .option("--metrics-provider <string>", "Metrics Provider") .option("--metrics-statsd-network", "Metrics StatsD Network") .option("--metrics-statsd-address", "Metrics StatsD Address") .option("--metrics-statsd-prefix", "Metrics StatsD Prefix") .option("--metris-statsd-write-interval", "Metrics StatsD Write Interval") .option("--boot-file <string>", "Fabric CA Server Config File Path") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Booting fabric CA Server..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); let user, password; if (options.bootstrapUsers !== undefined) { [user, password] = options.bootstrapUsers.split(constants_1.COLON_SEPARATOR); } this.log.info(`Bootstrap users: ${user}:${password}`); try { await (0, ca_server_1.bootCA)(this.log, options.home, options.configVersion, options.port, { enabled: options.corsEnabled, origins: options.corsOrigins, }, options.debug, options.crlSize, { enabled: options.tlsEnabled, certfile: options.tlsCertfile, keyfile: options.tlsKeyfile, clientauth: { type: options.tlsClientType, certfiles: options.tlsClientCertfiles, }, }, { name: options.caName, keyfile: options.caKeyfile, certfile: options.caCertfile, chainfile: options.caChainfile, reenrollIgnoreCertExpiry: options.caReenrollIgnoreCertExpiry, }, [ { name: user, pass: password, }, ], options.caProfile, options.tlsProfile, { cn: options.csrCn, hosts: options.csrHosts, keyrequest: { algo: options.csrKeyrequestAlgo, size: options.csrKeyrequestSize, }, ca: { expiry: options.csrCaExpiry, pathlength: options.csrCaPathlength, }, names: undefined, // TODO: Implement names in CSR }, { listenAddress: options.operationsListenAddress, tls: { enabled: options.operationsTlsEnabled, cert: { file: options.operationsTlsCertfile, }, key: { file: options.operationsTlsKeyfile, }, clientAuthRequired: options.operationsTlsClientauthRequired, clientRootCAs: { files: options.operationsTlsClientauthRootcas, }, }, }, { provider: options.metricsProvider, statsd: { network: options.metricsStatsdNetwork, address: options.metricsStatsdAddress, prefix: options.metricsStatsdPrefix, writeInterval: options.metricsStatsdWriteInterval, }, }, options.bootFile); } catch (error) { this.log.error(`"Error issuing Fabric CA Server config: ${error}"`); return; } this.log.info("Fabric CA Server config issued successfully!"); }); } clientEnrollment() { this.program .command("client-enrollment") .description("Command to handle identities register and enroll") .option("-d, --debug", "Enables debug mode") .option("--command <string>", "Command to execute (enroll or register)") .option("--csr-cn <string>", "CSR Common Name") .option("--csr-hosts <CSV>", "CSR Hosts", parsers_1.safeParseCSV) .option("--csr-keyrequest-algo <string>", "CSR Key Request Algo") .option("--csr-keyrequest-size <number>", "CSR Key Request Size", parsers_1.safeParseInt) .option("--csr-keyrequest-reusekey", "CSR Key Request Reuse Key") .option("--csr-names <CSV>", "CSR Names", parsers_1.safeParseCSV) .option("--csr-serialnumber <string>", "CSR Serial Number") .option("--home <string>", "Home directory for the client") .option("--ca-name <string>", "CA Name") .option("--url <string>", "URL for the Fabric CA Server") .option("--enrollment-attrs <CSV>", "Enrollment Attributes", parsers_1.safeParseCSV) .option("--enrollment-profile <string>", "Enrollment Profile") .option("--enrollment-label <string>", "Enrollment Label") .option("--enrollment-type <string>", "Enrollment Type") .option("--id-affiliation <string>", "ID Affiliation") .option("--id-maxenrollments <number>", "ID Maximum Enrollments") .option("--id-name <string>", "ID Name") .option("--id-secret <string>", "ID Secret") .option("--id-type <string>", "ID Type") //TODO: This should be a list of csv strings but those strings might be csv strings need to find a way to handle that .option("--id-attrs <string>", "ID Attributes") .option("--mspdir <string>", "MSP Directory") .option("--my-host <string>", "My Host") .option("--tls-certfiles <CSV>", "TLS Certfile location", parsers_1.safeParseCSV) .option("--tls-client-certfile <string>", "TLS Client Certfile") .option("--tls-client-keyfile <string>", "TLS Client Keyfile") .option("--idemix-curve <string>", "IDMix Curve") .option("--key-destination-dir <string>", "Copy Key to the server MSP Directory") .option("--rename-key", "Rename Key in MSP Directory") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running fabric CA client enrollment command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); (0, ca_client_1.clientEnrollment)(this.log, options.command, { cn: options.csrCn, hosts: options.csrHosts, keyrequest: { algo: options.csrKeyrequestAlgo, size: options.csrKeyrequestSize, reusekey: options.csrKeyrequestReusekey, }, serialnumber: options.csrSerialnumber, names: options.csrNames, }, options.home, options.caName, options.url, { attrs: options.enrollmentAttrs, profile: options.enrollmentProfile, label: options.enrollmentLabel, type: options.enrollmentType, }, { affiliation: options.idAffiliation, maxenrollments: options.idMaxenrollments, name: options.idName, secret: options.idSecret, type: options.idType, attrs: options.idAttrs, }, options.idemixCurve, options.mspdir, options.myHost, { certfiles: options.tlsCertfiles, client: { certfile: options.tlsClientCertfile, keyfile: options.tlsClientKeyfile, }, }, options.keyDestinationDir, options.renameKey); this.log.info("Command completed successfully!"); }); } configtxgen() { this.program .command("configtxgen") .description("Command to generate configuration transactions") .option("-d, --debug", "Enables debug mode") .option("--as-org <string>", "Organization") .option("--channel-create-txbase-profile <string>", "Channel Create Tx Base Profile") .option("--channel-id <string>", "Channel ID") .option("--config-path <string>", "Config Path") .option("--inspect-block <string>", "Inspect Block") .option("--inspect-channel-create-tx <string>", "Channel Create Tx") .option("--output-anchor-peers-update <string>", "Inspect Anchor Peers Updated") .option("--output-block <string>", "Output block") .option("--output-create-channel-tx <string>", "Output Channel Tx") .option("--print-org <string>", "Print Org") .option("--profile <string>", "Profile") .option("--configtxgen-version", "Configtxgen Version") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running configtxgen command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); (0, configtxgen_1.configtxgen)(options.asOrg, options.channelCreateTxbaseProfile, options.channelId, options.configPath, options.inspectBlock, options.inspectChannelCreateTx, options.outputAnchorPeersUpdate, options.outputBlock, options.outputCreateChannelTx, options.printOrg, options.profile, options.configtxgenVersion); this.log.info("Command completed successfully!"); }); } nodeOu() { this.program .command("node-ou") .description("Command to manage node organizations") .option("-d, --debug", "Enables debug mode") .option("--enable", "Enable node organizational unit") .option("--path <string>", "Path to output directory", "cacerts") .option("--mspdir <string>", "mspdirlocation") .option("--cert <string>", "Cert file name") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running node-ou command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); try { (0, node_ou_1.createNodeOU)(options.enable, options.path, options.mspdir, options.cert); } catch (error) { this.log.error(`Error: ${error.message}`); process.exit(1); } this.log.info("Command completed successfully!"); }); } bootOrderer() { this.program .command("boot-orderer") .description("Command to manage boot orderers") .option("-d, --debug", "Enables debug mode") .option("--listen-address <string>", "Listen Address") .option("--port <number>", "Port", parsers_1.safeParseInt) .option("--msp-dir <string>", "MSP Directory") .option("--msp-id <string>", "MSP ID") .option("--admin-listen-address <string>", "Admin Listen Address") .option("--admin-tls-enabled", "Enable Admin TLS") .option("--admin-tls-certificate <string>", "Admin TLS Certificate") .option("--admin-tls-key <string>", "Admin TLS Key") .option("--admin-tls-rootcas <CSV>", "Admin TLS Root CA Certificate location", parsers_1.safeParseCSV) .option("--admin-tls-client-authrequired", "Enable Admin TLS client authentication") .option("--admin-tls-client-rootcas <CSV>", "Admin TLS Client Root CA Certificate location", parsers_1.safeParseCSV) .option("--consensus-snapdir <string>", "Consensus Snapshot Directory") .option("--consensus-waldir <string>", "Consensus Write-Ahead Log Directory") .option("--operations-address <string>", "Operations Address") .option("--config-path <string>", "Config Path") .option("--tls-enabled", "Enable TLS") .option("--tls-rootcas <CSV>", "Root CA Certificate location", parsers_1.safeParseCSV) .option("--tls-cert <string>", "TLS Certificate") .option("--tls-key <string>", "TLS Key") .option("--tls-client-authrequired", "Enable TLS client authentication") .option("--tls-client-rootcas <CSV>", "Client Root CA Certificate location", parsers_1.safeParseCSV) .option("--bootstrap-method <string>", "Bootstrap Method") .option("--channel-participation-enabled", "Enable Channel Participation") //TODO: Implement all functionality in this command .action((options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running boot-orderer command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); (0, orderer_1.bootOrderer)(this.log, options.configPath, { WALDir: options.consensusWaldir, SnapDir: options.consensusSnapdir, }, { Enabled: options.channelParticipationEnabled, }, { ListenAddress: options.adminListenAddress, TLS: { Enabled: options.adminTlsEnabled, Certificate: options.adminTlsCertificate, RootCAs: options.adminTlsRootcas, PrivateKey: options.adminTlsKey, ClientAuthRequired: options.adminTlsClientAuthrequired, ClientRootCAs: options.adminTlsClientRootcas, }, }, { Enabled: options.tlsEnabled, RootCAs: options.tlsRootcas, Certificate: options.tlsCert, PrivateKey: options.tlsKey, ClientAuthRequired: options.tlsClientAuthrequired, ClientRootCAs: options.tlsClientRootcas, }, options.port, options.listenAddress, {}, {}, {}, { BootstrapMethod: options.bootstrapMethod }, { LocalMSPDir: options.mspDir, LocalMSPID: options.mspId }, {}, {}, { ListenAddress: options.operationsAddress }, {}, undefined, undefined, {}, {}); this.log.info("Command completed successfully!"); }); } bootPeer() { this.program .command("boot-peer") .description("Command to manage boot peers") .option("-d, --debug", "Enables debug mode") .option("--config-path <string>", "Config Path") .option("--gossip-bootstrap <string>", "Gossip Bootstrap Address") .option("--gossip-external-endpoint <string>", "Gossip External Address") .option("--tls-enabled", "Enable TLS") .option("--tls-client-authrequired", "Enable TLS client authentication") .option("--tls-cert <string>", "TLS Certificate File") .option("--tls-key <string>", "TLS Key File") .option("--tls-rootca <string>", "TLS Root Certificate File") .option("--tls-client-cert <string>", "TLS Client Certificate File") .option("--tls-client-key <string>", "TLS Client Key File") .option("--tls-client-rootcas <CSV>", "TLS Client Root Certificate File", parsers_1.safeParseCSV) .option("--peer-id <string>", "Peer ID") .option("--network-id <string>", "Network ID") .option("--listen-address <string>", "Listen Address") .option("--address <string>", "Address") .option("--file-system-path <string>", "File System Path") .option("--local-mspid <string>", "Local MSP ID") .option("--local-mspdir <string>", "Local MSP DIR") .option("--vm-network-mode <string>", "VM Network Mode") .option("--state-database <string>", "State Database") .option("--couchdb-address <string>", "Address for CouchDB") .option("--couchdb-username <string>", "Username for CouchDB") .option("--couchdb-password <string>", "Password for CouchDB") .option("--chaincode-listen-address <string>", "Address for the chaincode to listen on") .option("--operations-address <string>", "Address for the operations server to listen on") .option("--snapshot-root-dir <string>", "Snapshot Root Directory") .action((options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running boot-peer command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); (0, peer_1.bootPeer)(this.log, options.configPath, { bootstrap: options.gossipBootstrap, externalEndpoint: options.gossipExternalEndpoint, }, { enabled: options.tlsEnabled, clientAuthRequired: options.tlsClientAuthrequired, cert: { file: options.tlsCert, }, key: { file: options.tlsKey, }, rootcert: { file: options.tlsRootca, }, clientCert: { file: options.tlsClientCert, }, clientKey: { file: options.tlsClientKey, }, clientRootCAs: { files: options.tlsClientRootcas, }, }, undefined, {}, {}, { id: options.peerId, networkId: options.networkId, address: options.address, listenAddress: options.listenAddress, fileSystemPath: options.fileSystemPath, chaincodeListenAddress: options.chaincodeListenAddress, }, {}, { mspConfigPath: options.localMspdir, localMspId: options.localMspid, }, undefined, {}, {}, {}, {}, {}, {}, {}, { stateDatabase: options.stateDatabase, couchDBConfig: { couchDBAddress: options.couchdbAddress, username: options.couchdbUsername, password: options.couchdbPassword, }, }, undefined, undefined, {}, options.snapshotRootDir, { listenAddress: options.operationsAddress }, {}, { docker: { hostConfig: { NetworkMode: options.vmNetworkMode, }, }, }); this.log.info("Command completed successfully!"); }); } peerBlockFetch() { this.program .command("peer-fetch-genesis-block") .description("Command to manage boot peers") .option("-d, --debug", "Enables debug mode") .option("--channel-id <string>", "Channel ID") .option("--orderer-address <string>", "Orderer Address") .option("--block-number <string>", "Block number") .option("--output-file <string>", "Output file") .option("--tls", "Enable TLS") .option("--tls-ca-cert-file <string>", "TLS CA Certificate File") .action((options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running peer fetch command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); (0, peer_1.peerFetchGenesisBlock)(this.log, options.channelId, options.ordererAddress, options.blockNumber, options.outputFile, options.tls, options.tlsCaCertFile); this.log.info("Command completed successfully!"); }); } peerJoinChannel() { this.program .command("peer-join-channel") .description("Command to manage boot peers") .option("-d, --debug", "Enables debug mode") .option("--blockpath <string>", "Block number") .action((options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running peer fetch command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); (0, peer_1.peerJoinChannel)(this.log, options.blockpath); this.log.info("Command completed successfully!"); }); } osnAdminJoin() { this.program .command("osn-admin-join") .description("OSN admin join commnad") .option("-d, --debug", "Enables debug mode") .option("--channel-id <string>", "Channel ID") .option("--config-block <string>", "Config Block") .option("--admin-address <string>", "Admin address") .option("--tls-ca <string>", "Path to TLS CA certificate") .option("--tls-cert <string>", "Path to TLS certificate") .option("--tls-key <string>", "Path to TLS key") .option("--no-status", "No status") .option("--help", "Displays help for osn-admin-join command") .action((options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Running osn-admin-join command..."); this.log.debug(`Options: ${JSON.stringify(options, null, 2)}`); (0, osn_admin_1.osnAdminJoin)(this.log, options.channelId, options.configBlock, options.adminAddress, options.tlsCa, options.tlsCert, options.tlsKey, options.noStatus, options.help); this.log.info("Command completed successfully!"); }); } packageChaincode() { this.program .command("package-chaincode") .option("-d, --debug", "Enables debug mode") .option("--chaincode-path <string>", "Path to the chaincode directory") .option("--lang <string>", "Language of the chaincode") .option("--chaincode-output <string>", "output location of the chaincode") .option("--chaincode-name <string>", "Name of the chaincode") .option("--chaincode-version <string>", "Version of the chaincode") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Packaging Chaincode..."); (0, peer_1.packageChaincode)(this.log, options.chaincodeOutput, options.chaincodePath, options.lang, options.chaincodeName, options.chaincodeVersion); this.log.info("Chaincode packaged successfully!"); }); } installChaincode() { this.program .command("install-chaincode") .option("-d, --debug", "Enables debug mode") .option("--chaincode-path <string>", "Path to the chaincode directory") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Packaging Chaincode..."); (0, peer_1.installChaincode)(this.log, options.chaincodePath); this.log.info("Chaincode installed successfully!"); }); } approveChaincode() { this.program .command("approve-chaincode") .option("-d, --debug", "Enables debug mode") .option("--orderer-address <string>", "Orderer Address") .option("--channel-id <string>", "Channel ID") .option("--chaincode-name <string>", "Chaincode name") .option("--chaincode-version <string>", "Version of the chaincode") .option("--sequence <number>", "Sequence of the chaincode") .option("--enable-tls", "enable TLS") .option("--tls-ca-cert-file <string>", "TLS CA Certificate File") .option("--collections-config <string>", "Collections configuration file") .option("--orderer-hostname-override <string>", "The hostname override to use when validating the TLS connection to the orderer") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Packaging Chaincode..."); (0, peer_1.approveChaincode)(this.log, options.ordererAddress, options.channelId, options.chaincodeName, options.chaincodeVersion, options.sequence, options.enableTls, options.tlsCaCertFile, options.collectionsConfig, options.ordererHostnameOverride); this.log.info("Chaincode approved successfully!"); }); } commitChaincode() { this.program .command("commit-chaincode") .option("-d, --debug", "Enables debug mode") .option("--orderer-address <string>", "Orderer Address") .option("--channel-id <string>", "Channel ID") .option("--chaincode-name <string>", "Chaincode name") .option("--chaincode-version <string>", "Version of the chaincode") .option("--sequence <number>", "Sequence of the chaincode") .option("--enable-tls", "enable TLS") .option("--tls-ca-cert-file <string>", "TLS CA Certificate File") .option("--collections-config <string>", "Collections configuration file") .option("--orderer-hostname-override <string>", "The hostname override to use when validating the TLS connection to the orderer") .option("--peer-addresses <CSV>", "Peer Address", parsers_1.safeParseCSV, undefined) .option("--peer-root-tls <CSV>", "Peer Address", parsers_1.safeParseCSV, undefined) .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Commiting Chaincode..."); this.log.info(JSON.stringify(options.peerAddresses, null, 2)); this.log.info(JSON.stringify(options.peerRootTls, null, 2)); (0, peer_1.commitChainCode)(this.log, options.ordererAddress, options.channelId, options.chaincodeName, options.chaincodeVersion, options.sequence, options.enableTls, options.tlsCaCertFile, options.collectionsConfig, options.ordererHostnameOverride, options.peerAddresses, options.peerRootTls); this.log.info("Chaincode commited successfully!"); }); } bootMiddleware() { this.program .command("boot-peer-middleware") .option("-d, --debug", "Enables debug mode") .option("--port <number>", "middleware port", parsers_1.safeParseInt, peer_middleware_1.DEFAULT_PORT) .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Booting Middleware..."); const middleware = new PeerMiddleware_1.PeerMiddleware(options.port); middleware.listen(); this.log.info("Middleware booted successfully!"); }); } compileContract() { this.program .command("compile-contract") .option("-d, --debug", "Enables debug mode") .option("--contract-file <string>", "Path to the contract entry file") .option("--output-dir <string>", "Output path for the compiled contract") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Compiling Contract..."); (0, compile_1.compileStandaloneFile)(options.contractFile, options.outputDir); this.log.info("Contract compiled successfully!"); }); } addPackagesToContract() { this.program .command("add-contract-packages") .option("-d, --debug", "Enables debug mode") .option("--contract-filename <string>", "Contract filename without extension") .option("--contract-version <string>", "Version of the contract") .option("--output-path <string>", "Output path for the compiled contract") .action(async (options) => { this.log.setConfig({ level: options.debug ? logging_1.LogLevel.debug : logging_1.LogLevel.info, }); this.log.info("Compiling Contract..."); this.log.info(options.contractVersion); (0, compile_1.addPackage)(options.contractFilename, options.contractVersion, options.outputPath); this.log.info("Contract compiled successfully!"); }); } } exports.CoreCLI = CoreCLI; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZS1jbGkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29yZS9jbGkvY29yZS1jbGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsK0NBQTZDO0FBQzdDLHlDQUFxQztBQUNyQyxvREFBZ0U7QUFDaEUsaURBQWlFO0FBQ2pFLHNEQUF5RDtBQUN6RCxvREFBd0Q7QUFDeEQsd0RBQXFEO0FBQ3JELDBEQUE0RDtBQUM1RCxnREFBaUQ7QUFDakQsMENBUXlCO0FBQ3pCLG9EQUFvRDtBQUNwRCxrRUFBNEQ7QUFDNUQsa0VBQStEO0FBQy9ELGtEQUF5RTtBQUV6RSxNQUFhLE9BQVEsU0FBUSxrQkFBTztJQUNsQztRQUNFLEtBQUssQ0FBQyxhQUFhLEVBQUUsbUNBQW1DLENBQUMsQ0FBQztRQUUxRCxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDZixDQUFDO0lBRU8sS0FBSztRQUNYLE1BQU0sV0FBVyxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FDNUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FDNUIsQ0FBQyxNQUFNLENBQ04sQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUNQLElBQUksS0FBSyxhQUFhO1lBQ3RCLE9BQU8sSUFBSSxDQUFDLElBQXFCLENBQUMsS0FBSyxVQUFVO1lBQ2pELElBQUksS0FBSyxPQUFPLENBQ25CLENBQUM7UUFFRixLQUFLLE1BQU0sVUFBVSxJQUFJLFdBQVcsRUFBRSxDQUFDO1lBQ3JDLElBQUksQ0FBQztnQkFDSCxJQUFJLENBQUMsVUFBMkIsQ0FBQyxFQUFFLENBQUM7WUFDdEMsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsT0FBTyxDQUFDLEtBQUssQ0FBQyx3QkFBd0IsVUFBVSxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDOUQsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDO0lBRU8sbUJBQW1CO1FBQ3pCLElBQUksQ0FBQyxPQUFPO2FBQ1Qs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