diff --git a/src/common/common.js b/src/common/common.js index bc7cceb..6b563a9 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -57,6 +57,8 @@ Common.LOGIN_PEER_SSL_TARGET = 'Peer SSL Target'; Common.LOGIN_ORDERER_SSL_TARGET = 'Orderer SSL Target'; Common.LOGIN_CA_SERVER_URL = 'CA Server Url'; +// user register page +Common.REGISTER_USERNAME = 'User Name'; Common.WARN = { chaincodeName: 'chaincode name can not be null!', diff --git a/src/common/common_cn.js b/src/common/common_cn.js index 094069e..89776d6 100644 --- a/src/common/common_cn.js +++ b/src/common/common_cn.js @@ -55,6 +55,8 @@ Common.LOGIN_PEER_SSL_TARGET = '组织节点SSL域名'; Common.LOGIN_ORDERER_SSL_TARGET = '排序节点SSL域名'; Common.LOGIN_CA_SERVER_URL = 'CA节点地址'; +// user register page +Common.REGISTER_USERNAME = '用户名'; Common.WARN = { chaincodeName: '链码名称不能为空!', diff --git a/src/components/BasicLayout.jsx b/src/components/BasicLayout.jsx index ec04848..6b50fb7 100644 --- a/src/components/BasicLayout.jsx +++ b/src/components/BasicLayout.jsx @@ -6,6 +6,7 @@ import { Layout, Menu, Icon } from 'antd'; import DataContent from './content/DataContent'; import ChaincodeInvokeContent from './content/ChaincodeInvokeContent'; import ChaincodeInstallContent from './content/ChaincodeInstallContent'; +import CARegisterContent from './content/CARegisterContent'; import { deleteFabricClientSingleton } from '../util/fabric'; import { getConfigDBSingleton, getInvokeDBSingleton, getChaincodeDBSingleton } from '../util/createDB'; @@ -35,6 +36,8 @@ function ContentRoute(props) { return ; } else if (props.contentKey === 4) { return ; + } else if (props.contentKey === 5) { + return ; } return

The sidebar button is not bound to corresponding content

; } @@ -123,6 +126,10 @@ export default class BasicLayout extends React.Component { {this.state.language === 'cn' ? '通道管理' : 'Channel Management' } + this.switchContent(5)}> + + {this.state.language === 'cn' ? 'CA注册' : 'CA Register' } + diff --git a/src/components/UserLayout.jsx b/src/components/UserLayout.jsx index e6632c0..f7ca116 100644 --- a/src/components/UserLayout.jsx +++ b/src/components/UserLayout.jsx @@ -85,24 +85,22 @@ export default class UserLayout extends React.Component { tlsOrdererPath: this.state.tlsOrdererPath, peerSSLTarget: this.state.peerSSLTarget, ordererSSLTarget: this.state.ordererSSLTarget, + caServerUrl: this.state.caServerUrl, + keyPath: this.state.keyPath, + certPath: this.state.certPath, path: 'resources/key/users/' } }, {}, () => { - getFabricClientSingleton().then((fabricClient) => { - fabricClient.importCer(this.state.keyPath, this.state.certPath).then((result) => { - db.update({ id: 0 }, - { $set: { isSign: 2 } }, - {}, () => { - }); - this.props.onGetChildMessage(2); - logger.info('result', result); - }, () => { - message.error(this.state.Common.ERROR.certificateFailed); - }); + getFabricClientSingleton().then(() => { + db.update({ id: 0 }, + { $set: { isSign: 2 } }, + {}, () => { + }); + this.props.onGetChildMessage(2); + }, () => { + message.error(this.state.Common.ERROR.certificateFailed); }); }); - - logger.info(this.state.certPath); } peerGrpcUrlChange(event) { this.setState({ peerGrpcUrl: event.target.value }); diff --git a/src/components/content/CARegisterContent.jsx b/src/components/content/CARegisterContent.jsx new file mode 100644 index 0000000..1591c28 --- /dev/null +++ b/src/components/content/CARegisterContent.jsx @@ -0,0 +1,212 @@ +// Copyright 2018 The hyperledger-fabric-desktop Authors. All rights reserved. + +// main feature: CA register and enroll +import React from 'react'; +import { Button, Input } from 'antd'; +import { getFabricClientSingleton } from '../../util/fabric'; + +const logger = require('electron-log'); + +/** + * register参数:用户名、affiliation, role等等 + * enroll参数:用户名、密码 + */ + +export default class CARegisterContent extends React.Component { + constructor(props) { + super(props); + this.state = { + Common: localStorage.getItem('language') === 'cn' ? require('../../common/common_cn') : require('../../common/common'), + + registerUserName: '', + registerAffiliation: '', + registerRole: '', + registerOptional: '', + + enrollUserName: '', + enrollUserPassword: '', + enrollOptional: '', + }; + + this.onChangeRegisterUserName = this.onChangeRegisterUserName.bind(this); + this.onChangeRegisterAffiliation = this.onChangeRegisterAffiliation.bind(this); + this.onChangeRegisterRole = this.onChangeRegisterRole.bind(this); + this.onChangeRegisterOptional = this.onChangeRegisterOptional.bind(this); + this.onChangeEnrollUserName = this.onChangeEnrollUserName.bind(this); + this.onChangeEnrollUserPassword = this.onChangeEnrollUserPassword.bind(this); + this.onChangeEnrollOptional = this.onChangeEnrollOptional.bind(this); + + this.handleRegister = this.handleRegister.bind(this); + this.handleEnroll = this.handleEnroll.bind(this); + } + + onChangeRegisterUserName(event) { + this.setState({ registerUserName: event.target.value }); + } + onChangeRegisterAffiliation(event) { + this.setState({ registerAffiliation: event.target.value }); + } + onChangeRegisterRole(event) { + this.setState({ registerRole: event.target.value }); + } + onChangeRegisterOptional(event) { + this.setState({ registerOptional: event.target.value }); + } + onChangeEnrollUserName(event) { + this.setState({ enrollUserName: event.target.value }); + } + onChangeEnrollUserPassword(event) { + this.setState({ enrollUserPassword: event.target.value }); + } + onChangeEnrollOptional(event) { + this.setState({ enrollOptional: event.target.value }); + } + + handleRegister() { + // FIXME: Object.assign is shallow copy. Be careful. + const tmpReq = { + enrollmentID: this.state.registerUserName, + affiliation: this.state.registerAffiliation, + role: this.state.role, + }; + let req = tmpReq; + if (this.state.registerOptional) { + req = Object.assign({}, tmpReq, JSON.parse(this.state.registerOptional)); + } + + logger.info('start to register user, RegisterRequest: ', req); + getFabricClientSingleton() + .then((client) => { + logger.info('client: ', client.toString()); + return client.register(req); + }) + .then((enrollment) => { + // TODO: 输出密码,到页面上。 + logger.info('register successfully, enrollment: ', enrollment); + }) + .catch((err) => { + logger.info('fail to register user, err: ', err); + throw err; + }); + } + + handleEnroll() { + + } + + render() { + const outerDivStyle = { + padding: '24px', + }; + const spanStyle = { + marginRight: '10px', + display: 'inline-block', + width: '100px', + }; + const SpanStyle = { + marginTop: '30px', + }; + const fileStyle = { + width: '0.1px', + height: '0.1px', + opacity: 0, + overflow: 'hidden', + position: 'absolute', + zIndex: -1, + }; + const labelStyle = { + fontSize: '1.1em', + border: '1px solid rgb(217, 217, 217)', + borderRadius: '4px', + display: 'block', + width: '60%', + height: '32px', + verticalAlign: 'middle', + textAlign: 'center', + lineHeight: '30px', + cursor: 'pointer', + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + overflow: 'hidden', + marginLeft: '146px', + marginTop: '-25px', + }; + const configInputStyle = { + marginLeft: '30px', + width: '60%', + }; + const CreateInputStyle = { + marginLeft: '36px', + width: '40%', + }; + const AddInputStyle = { + marginLeft: '36px', + width: '40%', + }; + const DivStyle = { + width: '560px', + marginBottom: '30px', + }; + const ButtonStyle = { + marginLeft: '20px', + width: '15%', + }; + const TipDivStyle = { + display: 'inline-block', + float: 'right', + marginRight: '20px', + }; + const asteriskStyle = { + float: 'left', + color: '#ff0000', + }; + return ( +
+ +
注册
+
+ * + {this.state.Common.REGISTER_USERNAME} + +
+
+ * + 组织归属 + +
+
+ * + 角色类型 + +
+
+ 其他属性 + +
+
+ +
+ +
证书私钥领取
+
+ * + 用户名 + +
+
+ * + 密码 + +
+
+ 其他属性 + +
+
+ +
+
+ + ); + } +} diff --git a/src/util/fabric.js b/src/util/fabric.js index 8a8f3a8..3caf677 100644 --- a/src/util/fabric.js +++ b/src/util/fabric.js @@ -83,27 +83,11 @@ class FabricClient { const self = this; const usrName = self.config.mspid; logger.info('start to load member user.', ' store_path: ', self.store_path); - return FabricClientSDK.newDefaultKeyValueStore({ path: self.store_path, - }).then((stateStore) => { - logger.info('get stateStore: ', stateStore); - - // assign the store to the fabric client - self.fabricClient.setStateStore(stateStore); - const cryptoSuite = FabricClientSDK.newCryptoSuite(); - - // use the same location for the state store (where the users' certificate are kept) - // and the crypto store (where the users' keys are kept) - const cryptoStore = FabricClientSDK.newCryptoKeyStore({ path: self.store_path }); - cryptoSuite.setCryptoKeyStore(cryptoStore); - self.fabricClient.setCryptoSuite(cryptoSuite); - - logger.info('almost done'); - return self.fabricClient.getUserContext(usrName, true) // FIXME: usernaem和mspid可能要分开 - .then((user) => { - self.user = user; - return Promise.resolve(user); - }); - }); + return self.fabricClient.getUserContext(usrName, true) + .then((user) => { + self.user = user; + return Promise.resolve(user); + }); } /** @@ -497,31 +481,55 @@ class FabricClient { * 生成证书私钥 * @returns {Promise} */ - importCer(keyPath, certPath) { + importCer() { + const keyPath = this.config.keyPath; + const certPath = this.config.certPath; + const mspid = this.config.mspid; + + const self = this; + logger.debug('keyPath: ', keyPath); + logger.debug('certPath: ', certPath); // -------------------- admin start --------- - logger.info('start to create admin user.'); - return this.fabricClient.createUser({ - username: this.config.mspid, - mspid: this.config.mspid, - cryptoContent: { - privateKey: keyPath, - signedCert: certPath, - }, - }) - .then((user) => { - if (user && user.isEnrolled()) { - logger.info('Successfully loaded user1 from persistence, user:', user.toString()); - } else { - logger.error('Failed to get user1.... run registerUser.js'); - return Promise.reject(new Error('Failed to get user1.... run registerUser.js')); - } - logger.info('create fabric client success'); - return Promise.resolve('success'); + logger.info('start to create user, namely importing certificate and privkey.'); + return FabricClientSDK.newDefaultKeyValueStore({ path: self.store_path, + }).then((stateStore) => { + logger.info('get stateStore: ', stateStore); + + // assign the store to the fabric client + self.fabricClient.setStateStore(stateStore); + const cryptoSuite = FabricClientSDK.newCryptoSuite(); + + // use the same location for the state store (where the users' certificate are kept) + // and the crypto store (where the users' keys are kept) + const cryptoStore = FabricClientSDK.newCryptoKeyStore({ path: self.store_path }); + cryptoSuite.setCryptoKeyStore(cryptoStore); + self.fabricClient.setCryptoSuite(cryptoSuite); + + logger.info('almost done'); + + return this.fabricClient.createUser({ + mspid, + username: mspid, + cryptoContent: { + privateKey: keyPath, + signedCert: certPath, + }, }) - .catch((err) => { - logger.error(`Fail to instantiate chaincode. Error message: ${err.stack}` ? err.stack : err); - return Promise.reject('fail'); - }); + .then((user) => { + if (user && user.isEnrolled()) { + logger.info('Successfully loaded user1 from persistence, user:', user.toString()); + } else { + logger.error('Failed to get user1.... run registerUser.js'); + return Promise.reject(new Error('Failed to get user1.... run registerUser.js')); + } + logger.info('create fabric client success'); + return Promise.resolve('success'); + }) + .catch((err) => { + logger.error(`Fail to instantiate chaincode. Error message: ${err.stack}` ? err.stack : err); + return Promise.reject('fail'); + }); + }); // ---------------admin finish --------------- } @@ -828,6 +836,7 @@ export function getFabricClientSingletonHelper(dbConfig) { __fabricClient = new FabricClient(); return __fabricClient._getConfig(dbConfig) .then(input => __fabricClient._config(input)) + .then(() => __fabricClient.importCer()) .then(() => __fabricClient._loginUser()) .then(() => Promise.resolve(__fabricClient)); }