anyproxy
Version:
A fully configurable HTTP/HTTPS proxy in Node.js
290 lines (255 loc) • 8.36 kB
JSX
/*
* 页面顶部菜单的组件
*/
import React, { PropTypes } from 'react';
import ClassBind from 'classnames/bind';
import { connect } from 'react-redux';
import InlineSVG from 'svg-inline-react';
import { message, Modal, Popover, Button } from 'antd';
import { getQueryParameter } from 'common/commonUtil';
import { MenuKeyMap } from 'common/constant';
import {
resumeRecording,
stopRecording,
updateLocalInterceptHttpsFlag,
updateLocalGlobalProxyFlag,
toggleRemoteInterceptHttpsFlag,
toggleRemoteGlobalProxyFlag,
updateShouldClearRecord,
updateIsRootCAExists,
showFilter,
updateLocalAppVersion
} from 'action/globalStatusAction';
const {
RECORD_FILTER: RECORD_FILTER_MENU_KEY
} = MenuKeyMap;
import { getJSON } from 'common/apiUtil';
import Style from './header-menu.less';
const StyleBind = ClassBind.bind(Style);
class HeaderMenu extends React.Component {
constructor() {
super();
this.state = {
ruleSummary: '',
inAppMode: getQueryParameter('in_app_mode'),
runningDetailVisible: false
};
this.stopRecording = this.stopRecording.bind(this);
this.resumeRecording = this.resumeRecording.bind(this);
this.clearAllRecord = this.clearAllRecord.bind(this);
this.initEvent = this.initEvent.bind(this);
this.fetchData = this.fetchData.bind(this);
this.togglerHttpsIntercept = this.togglerHttpsIntercept.bind(this);
this.showRunningInfo = this.showRunningInfo.bind(this);
this.handleRuningInfoVisibleChange = this.handleRuningInfoVisibleChange.bind(this);
this.toggleGlobalProxyFlag = this.toggleGlobalProxyFlag.bind(this);
this.showFilter = this.showFilter.bind(this);
}
static propTypes = {
dispatch: PropTypes.func,
globalStatus: PropTypes.object,
resumeRefreshFunc: PropTypes.func
}
stopRecording() {
this.props.dispatch(stopRecording());
}
resumeRecording() {
console.info('Resuming...');
this.props.dispatch(resumeRecording());
}
clearAllRecord() {
this.props.dispatch(updateShouldClearRecord(true));
this.props.resumeRefreshFunc && this.props.resumeRefreshFunc();
}
handleRuningInfoVisibleChange(visible) {
this.setState({
runningDetailVisible: visible
});
}
showRunningInfo() {
this.setState({
runningDetailVisible: true
});
}
showFilter() {
this.props.dispatch(showFilter());
}
togglerHttpsIntercept() {
const self = this;
// if no rootCA exists, inform the user about trust the root
if (!this.props.globalStatus.isRootCAFileExists) {
Modal.info({
title: 'AnyProxy is about to generate the root CA for you',
content: (
<div>
<span>Trust the root CA before AnyProxy can do HTTPS proxy for you.</span>
<span>They will be located in
<a href="javascript:void(0)" >{' ' + this.state.rootCADirPath}</a>
</span>
</div>
),
width: 500,
onOk() {
doToggleRemoteIntercept();
this.props.dispatch(updateIsRootCAExists(true));
}
});
} else {
doToggleRemoteIntercept();
}
function doToggleRemoteIntercept() {
const currentHttpsFlag = self.props.globalStatus.interceptHttpsFlag;
self.props.dispatch(toggleRemoteInterceptHttpsFlag(!currentHttpsFlag));
}
}
toggleGlobalProxyFlag() {
const currentGlobalProxyFlag = this.props.globalStatus.globalProxyFlag;
this.props.dispatch(toggleRemoteGlobalProxyFlag(!currentGlobalProxyFlag));
}
initEvent() {
document.addEventListener('keyup', (e) => {
if (e.keyCode === 88 && e.ctrlKey) {
this.clearAllRecord();
}
});
}
fetchData() {
getJSON('/api/getInitData')
.then((response) => {
this.setState({
ruleSummary: response.ruleSummary,
rootCADirPath: response.rootCADirPath,
ipAddress: response.ipAddress,
port: response.port
});
this.props.dispatch(updateLocalInterceptHttpsFlag(response.currentInterceptFlag));
this.props.dispatch(updateLocalGlobalProxyFlag(response.currentGlobalProxyFlag));
this.props.dispatch(updateLocalAppVersion(response.appVersion));
this.props.dispatch(updateIsRootCAExists(response.rootCAExists));
})
.catch((error) => {
console.error(error);
message.error('Failed to get rule summary');
});
}
componentDidMount() {
this.fetchData();
this.initEvent();
}
render() {
const { globalStatus } = this.props;
const { activeMenuKey } = globalStatus;
const { ipAddress, inAppMode } = this.state;
const stopMenuStyle = StyleBind('menuItem', { disabled: globalStatus.recording !== true });
const resumeMenuStyle = StyleBind('menuItem', { disabled: globalStatus.recording === true });
const runningTipStyle = StyleBind('menuItem', 'rightMenuItem', { active: this.state.runningDetailVisible });
const showFilterMenuStyle = StyleBind('menuItem', { active: activeMenuKey === RECORD_FILTER_MENU_KEY });
const addressDivs = ipAddress ? (
this.state.ipAddress.map((singleIpAddress) => {
return <div key={singleIpAddress} className={Style.ipAddress}>{singleIpAddress}</div>;
})) : null;
const runningInfoDiv = (
<div >
<ul>
<li>
<strong>Active Rule:</strong>
<span>{this.state.ruleSummary}</span>
</li>
<li>
<strong>Host Address:</strong>
<span>{addressDivs}</span>
</li>
<li>
<strong>Listening on:</strong>
<span>{this.state.port}</span>
</li>
<li>
<strong>Proxy Protocol:</strong>
<span>HTTP</span>
</li>
</ul>
<div className={Style.okButton}>
<Button type="primary" onClick={this.handleRuningInfoVisibleChange.bind(this, false)} > OK </Button>
</div>
</div>
);
const stopRecordingMenu = (
<a
className={stopMenuStyle}
href="javascript:void(0)"
onClick={this.stopRecording}
>
<div className={Style.filterIcon}>
<InlineSVG src={require('svg-inline-loader!assets/stop.svg')} />
</div>
<span>Stop</span>
</a>
);
const resumeRecordingMenu = (
<a
className={resumeMenuStyle}
href="javascript:void(0)"
onClick={this.resumeRecording}
>
<div className={Style.stopIcon}>
<InlineSVG src={require('svg-inline-loader!assets/play.svg')} />
</div>
<span>Resume</span>
</a>
);
const filterMenu = (
<a
className={showFilterMenuStyle}
href="javascript:void(0)"
onClick={this.showFilter}
>
<div className={Style.stopIcon}>
<InlineSVG src={require('svg-inline-loader!assets/filter.svg')} />
</div>
<span>Filter</span>
</a>
);
return (
<div className={Style.wrapper} >
<div className={Style.menuList} >
{globalStatus.recording ? stopRecordingMenu : resumeRecordingMenu}
<a
className={Style.menuItem}
href="javascript:void(0)"
onClick={this.clearAllRecord}
title="Ctrl + X"
>
<InlineSVG src={require('svg-inline-loader!assets/clear.svg')} />
<span>Clear</span>
</a>
{inAppMode ? filterMenu : null}
<Popover
content={runningInfoDiv}
trigger="click"
title="AnyProxy Running Info"
visible={this.state.runningDetailVisible}
onVisibleChange={this.handleRuningInfoVisibleChange}
placement="bottomRight"
overlayClassName={Style.runningInfoDivWrapper}
>
<a
className={runningTipStyle}
href="javascript:void(0)"
>
<div className={Style.tipIcon} >
<InlineSVG src={require('svg-inline-loader!assets/tip.svg')} />
</div>
<span>Proxy Info</span>
</a>
</Popover>
</div>
</div>
);
}
}
function select(state) {
return {
globalStatus: state.globalStatus
};
}
export default connect(select)(HeaderMenu)