diff --git a/server/service/gateway.go b/server/service/gateway.go index 3b4770384..4e7793311 100644 --- a/server/service/gateway.go +++ b/server/service/gateway.go @@ -93,7 +93,9 @@ func (r gatewayService) LoadAll() error { } if len(sshGateways) > 0 { for i := range sshGateways { - r.loadSshGateway(&sshGateways[i]) + if _, err := r.loadSshGateway(&sshGateways[i]); err != nil { + log.Warn("loadSshGateway failed, id=" + sshGateways[i].ID + " err=" + err.Error()) + } } } return nil diff --git a/web-backup/.env.development.local b/web-backup/.env.development.local deleted file mode 100644 index 0d87cccd7..000000000 --- a/web-backup/.env.development.local +++ /dev/null @@ -1,2 +0,0 @@ -REACT_APP_ENV=development -ESLINT_NO_DEV_ERRORS=true diff --git a/web-backup/.env.production.local b/web-backup/.env.production.local deleted file mode 100644 index d25c75655..000000000 --- a/web-backup/.env.production.local +++ /dev/null @@ -1,3 +0,0 @@ -REACT_APP_ENV=production -GENERATE_SOURCEMAP=false -DISABLE_ESLINT_PLUGIN=true diff --git a/web-backup/.gitignore b/web-backup/.gitignore deleted file mode 100644 index 748b4584e..000000000 --- a/web-backup/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Project exclude paths -/node_modules/ \ No newline at end of file diff --git a/web-backup/LICENSE b/web-backup/LICENSE deleted file mode 100644 index d159169d1..000000000 --- a/web-backup/LICENSE +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/web-backup/README.md b/web-backup/README.md deleted file mode 100644 index ecf96aea4..000000000 --- a/web-backup/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Next Terminal dashboard -just do go dashboard - -## 安装依赖 - -```shell -npm install -``` diff --git a/web-backup/config-overrides.js b/web-backup/config-overrides.js deleted file mode 100644 index 89a99429d..000000000 --- a/web-backup/config-overrides.js +++ /dev/null @@ -1,8 +0,0 @@ -const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin'); - -module.exports = function override(config, env) { - config.plugins.push(new MonacoWebpackPlugin({ - languages: ['json'] - })); - return config; -} \ No newline at end of file diff --git a/web-backup/package.json b/web-backup/package.json deleted file mode 100644 index f52c06b23..000000000 --- a/web-backup/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "next-terminal", - "version": "1.3.9", - "private": true, - "dependencies": { - "@ant-design/charts": "^1.4.2", - "@ant-design/icons": "^4.7.0", - "@ant-design/pro-components": "1.1.21", - "@turf/bbox": "^6.5.0", - "antd": "4.23.5", - "asciinema-player": "^3.0.1", - "axios": "0.27.2", - "dayjs": "1.11.2", - "guacamole-common-js": "1.4.0-a", - "js-base64": "3.7.2", - "monaco-editor": "^0.34.1", - "monaco-editor-webpack-plugin": "^7.0.1", - "qs": "6.10.3", - "react": "^18.2.0", - "react-app-rewired": "^2.2.1", - "react-dom": "^18.2.0", - "react-draggable": "^4.4.3", - "react-monaco-editor": "^0.50.1", - "react-query": "^3.39.2", - "react-router-dom": "^6.3.0", - "react-scripts": "^5.0.1", - "xterm": "4.18.0", - "xterm-addon-fit": "0.5.0", - "xterm-addon-web-links": "0.5.1" - }, - "scripts": { - "start": "react-app-rewired start", - "build": "react-app-rewired build", - "test": "react-app-rewired test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": "react-app", - "rules": { - "jsx-a11y/anchor-is-valid": "off" - } - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ], - "homepage": "." -} diff --git a/web-backup/public/favicon.ico b/web-backup/public/favicon.ico deleted file mode 100644 index ec65bdedb..000000000 Binary files a/web-backup/public/favicon.ico and /dev/null differ diff --git a/web-backup/public/index.html b/web-backup/public/index.html deleted file mode 100644 index ad99b40f3..000000000 --- a/web-backup/public/index.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - -
- - - diff --git a/web-backup/src/App.css b/web-backup/src/App.css deleted file mode 100644 index 55b5901a0..000000000 --- a/web-backup/src/App.css +++ /dev/null @@ -1,215 +0,0 @@ -@import '~antd/dist/antd.min.css'; -@import '~@ant-design/pro-components/dist/components.css'; - -.trigger { - font-size: 18px; - line-height: 64px; - padding: 0 24px; - cursor: pointer; - transition: color 0.3s; -} - -.trigger:hover { - color: #1890ff; -} - -.logo { - margin: 30px 17px; - text-align: center; -} - -.logo > h1 { - color: white; - font-weight: bold; - line-height: 32px; /*设置line-height与父级元素的height相等*/ - text-align: center; /*设置文本水平居中*/ - display: inline-block; -} - -.site-page-header-ghost-wrapper { - background-color: #FFF; -} - -.layout-header { - height: 60px; - align-items: center; - background: #fff; - box-shadow: 0 1px 4px rgba(0, 21, 41, .08); - position: relative; - display: flex; -} - -.layout-header-left { - flex: 1 1 0; - margin-left: 24px; -} - -.layout-header-right { - text-align: right; - margin-right: 24px; -} - -.layout-header-right-item { - cursor: pointer; - display: inline-flex; - align-items: center; - padding: 0 8px; -} - -.page-herder { - margin: 16px 16px 0 16px; -} - -.page-search { - background-color: white; -} - -.page-search label { - font-weight: bold; -} - -.page-search .ant-form-item { - margin-bottom: 0; -} - -.page-container { - margin: 16px; -} - -.page-container-white { - margin: 16px; - padding: 24px; - background-color: white; -} - -.page-detail-warp { - margin: 16px; - padding: 0 16px 0 16px; -} - -.page-detail-info { - background-color: white; - padding: 24px; -} - -.page-card { - margin: 16px; -} - -.user-in-menu { - align-items: center; - text-align: center; - margin: 10px auto; - color: white; -} - -.user-in-menu > .nickname { - margin-top: 20px; - margin-right: auto; - margin-left: auto; - font-weight: bold; - padding: 2px 5px; - border-style: solid; - border-width: 1px; - border-color: white; - width: fit-content; - border-radius: 5%; -} - -.modal-no-padding .ant-modal-body { - padding: 0; -} - -.modal-no-padding-bg-xterm .ant-modal-body { - background-color: #121314; -} - -.disabled-icon { - cursor: not-allowed; - color: #ccc; -} - -.disabled-icon:hover { - color: #ccc; -} - -.nt-container { - width: 80%; - margin: 20px auto 0; -} - -.km-header { - color: white; - width: 80%; - margin: 0 auto; - position: relative; - display: flex; - align-items: center; - height: 100%; - /*padding: 0 16px;*/ -} - -.km-header-right { - text-align: left; - height: 100%; - margin: 0 8px; -} - -.kd-content { - margin-top: 20px; - background-color: white; -} - -.kd-page-header { - background-color: white; - margin-top: 20px; -} - -.ant-page-header { - padding: 0 !important; -} - -.danger { - color: red; -} - -.danger:hover { - color: red !important; -} - -.xterm-viewport::-webkit-scrollbar { - background-color: transparent; - width: 12px; -} - -.xterm-viewport::-webkit-scrollbar-thumb { - background-color: inherit; - border-radius: 8px; - background-clip: content-box; - border: 2px solid transparent; -} - -.xterm-viewport[scroll]::-webkit-scrollbar-thumb, -.xterm-viewport::-webkit-scrollbar-thumb:hover { - background-color: #bfbfbf; - transition: 0s; -} - -/*.ant-layout-sider::-webkit-scrollbar {*/ -/* background-color: transparent;*/ -/* !*background-color: red;*!*/ -/* width: 10px;*/ -/*}*/ - -/*.ant-layout-sider::-webkit-scrollbar-thumb {*/ -/* background-color: inherit;*/ -/* border-radius: 8px;*/ -/* background-clip: content-box;*/ -/* border: 2px solid transparent;*/ -/*}*/ - -/*.ant-layout-sider[scroll]::-webkit-scrollbar-thumb,*/ -/*.ant-layout-sider::-webkit-scrollbar-thumb:hover {*/ -/* background-color: #bfbfbf;*/ -/* transition: 0s;*/ -/*}*/ \ No newline at end of file diff --git a/web-backup/src/App.js b/web-backup/src/App.js deleted file mode 100644 index 1e7ba77e3..000000000 --- a/web-backup/src/App.js +++ /dev/null @@ -1,127 +0,0 @@ -import React, {Suspense} from 'react'; -import {Outlet, Route, Routes} from "react-router-dom"; - -import './App.css'; -import './Arco.css'; -import ManagerLayout from "./layout/ManagerLayout"; -import UserLayout from "./layout/UserLayout"; - -import NoMatch from "./components/NoMatch"; -import Landing from "./components/Landing"; -import NoPermission from "./components/NoPermission"; -import Redirect from "./components/Redirect"; - -const GuacdMonitor = React.lazy(() => import("./components/session/GuacdMonitor")); -const GuacdPlayback = React.lazy(() => import("./components/session/GuacdPlayback")); -const TermMonitor = React.lazy(() => import("./components/session/TermMonitor")); -const TermPlayback = React.lazy(() => import("./components/session/TermPlayback")); - -const BatchCommand = React.lazy(() => import("./components/devops/BatchCommand")); -const LoginPolicyDetail = React.lazy(() => import("./components/security/LoginPolicyDetail")); -const Login = React.lazy(() => import("./components/Login")); -const Dashboard = React.lazy(() => import("./components/dashboard/Dashboard")); -const Monitoring = React.lazy(() => import("./components/dashboard/Monitoring")); - -const Asset = React.lazy(() => import("./components/asset/Asset")); -const AssetDetail = React.lazy(() => import("./components/asset/AssetDetail")); -const MyFile = React.lazy(() => import("./components/worker/MyFile")); -const AccessGateway = React.lazy(() => import("./components/asset/AccessGateway")); -const MyAsset = React.lazy(() => import("./components/worker/MyAsset")); -const MyCommand = React.lazy(() => import("./components/worker/MyCommand")); -const MyInfo = React.lazy(() => import("./components/worker/MyInfo")); - -const Guacd = React.lazy(() => import("./components/access/Guacd")); -const Term = React.lazy(() => import("./components/access/Term")); - -const User = React.lazy(() => import("./components/user/user/User")); -const UserDetailPage = React.lazy(() => import("./components/user/user/UserDetailPage")); -const Role = React.lazy(() => import("./components/user/Role")); -const RoleDetail = React.lazy(() => import("./components/user/RoleDetail")); -const UserGroup = React.lazy(() => import("./components/user/UserGroup")); -const UserGroupDetail = React.lazy(() => import("./components/user/UserGroupDetail")); - -const Strategy = React.lazy(() => import("./components/authorised/Strategy")); -const StrategyDetail = React.lazy(() => import("./components/authorised/StrategyDetail")); -const Info = React.lazy(() => import("./components/Info")); - -const OnlineSession = React.lazy(() => import("./components/session/OnlineSession")); -const OfflineSession = React.lazy(() => import("./components/session/OfflineSession")); -const Command = React.lazy(() => import("./components/asset/Command")); -const ExecuteCommand = React.lazy(() => import("./components/devops/ExecuteCommand")); -const Credential = React.lazy(() => import("./components/asset/Credential")); - -const Job = React.lazy(() => import("./components/devops/Job")); -const LoginLog = React.lazy(() => import("./components/log-audit/LoginLog")); -const Security = React.lazy(() => import("./components/security/Security")); -const Storage = React.lazy(() => import("./components/devops/Storage")); - -const Setting = React.lazy(() => import("./components/setting/Setting")); -const LoginPolicy = React.lazy(() => import("./components/security/LoginPolicy")); - -const App = () => { - - return ( - - - }/> - - }> - - - }> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - - - }> - }/> - }/> - - }/> - }/> - }/> - }/> - }/> - }/> - - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - - - }> - }/> - }/> - }/> - }/> - - - ); -} - -export default App; diff --git a/web-backup/src/App.test.js b/web-backup/src/App.test.js deleted file mode 100644 index a754b201b..000000000 --- a/web-backup/src/App.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; - -it('renders without crashing', () => { - const div = document.createElement('div'); - ReactDOM.render(, div); - ReactDOM.unmountComponentAtNode(div); -}); diff --git a/web-backup/src/Arco.css b/web-backup/src/Arco.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/web-backup/src/api/access-gateway.js b/web-backup/src/api/access-gateway.js deleted file mode 100644 index 9c1a6f086..000000000 --- a/web-backup/src/api/access-gateway.js +++ /dev/null @@ -1,10 +0,0 @@ -import Api from "./api"; - -class AccessGatewayApi extends Api{ - constructor() { - super("access-gateways"); - } -} - -let accessGatewayApi = new AccessGatewayApi(); -export default accessGatewayApi; \ No newline at end of file diff --git a/web-backup/src/api/account.js b/web-backup/src/api/account.js deleted file mode 100644 index 1d77c7eb5..000000000 --- a/web-backup/src/api/account.js +++ /dev/null @@ -1,78 +0,0 @@ -import request from "../common/request"; -import qs from "qs"; - -class AccountApi { - - group = 'account'; - - logout = async () => { - let result = await request.post('/account/logout'); - return result['code'] === 1 - } - - getUserInfo = async () => { - let result = await request.get(`/${this.group}/info`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - assetPaging = async (params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/assets?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - getAccessToken = async () => { - let result = await request.get(`/${this.group}/access-token`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - createAccessToken = async () => { - let result = await request.post(`/${this.group}/access-token`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - deleteAccessToken = async () => { - let result = await request.delete(`/${this.group}/access-token`); - return result['code'] === 1; - } - - changePassword = async (values) => { - let result = await request.post(`/${this.group}/change-password`, values); - return result.code === 1; - } - - reloadTotp = async () => { - let result = await request.get('/account/reload-totp'); - if (result.code === 1) { - return result.data; - } else { - return {} - } - } - - confirmTotp = async (values) => { - let result = await request.post(`/${this.group}/confirm-totp`, values); - return result.code === 1; - } - - - resetTotp = async () => { - let result = await request.post(`/${this.group}/reset-totp`); - return result.code === 1; - } -} - -let accountApi = new AccountApi(); -export default accountApi; \ No newline at end of file diff --git a/web-backup/src/api/api.js b/web-backup/src/api/api.js deleted file mode 100644 index 6602edcab..000000000 --- a/web-backup/src/api/api.js +++ /dev/null @@ -1,50 +0,0 @@ -import request from "../common/request"; -import qs from "qs"; - -export default class Api { - group = ""; - - constructor(group) { - this.group = group; - } - - getById = async (id) => { - let result = await request.get(`/${this.group}/${id}`); - if (result['code'] !== 1) { - return; - } - return result['data']; - } - - getPaging = async (params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/paging?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - getAll = async () => { - let result = await request.get(`/${this.group}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } - - create = async (data) => { - const result = await request.post(`/${this.group}`, data); - return result['code'] === 1; - } - - updateById = async (id, data) => { - const result = await request.put(`/${this.group}/${id}`, data); - return result['code'] === 1; - } - - deleteById = async (id) => { - const result = await request.delete(`/${this.group}/${id}`); - return result['code'] === 1; - } -} \ No newline at end of file diff --git a/web-backup/src/api/asset.js b/web-backup/src/api/asset.js deleted file mode 100644 index 1534660b8..000000000 --- a/web-backup/src/api/asset.js +++ /dev/null @@ -1,42 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class AssetApi extends Api { - constructor() { - super("assets"); - } - - GetAll = async (protocol = '') => { - let result = await request.get(`/${this.group}?protocol=${protocol}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } - - connTest = async (id) => { - let result = await request.post(`/${this.group}/${id}/tcping`); - if (result.code !== 1) { - return [false, result.message]; - } - return [result['data']['active'], result['data']['message']]; - } - - importAsset = async (file) => { - const formData = new FormData(); - formData.append("file", file,); - let result = await request.post(`/${this.group}/import`, formData, {'Content-Type': 'multipart/form-data'}); - if (result.code !== 1) { - return [false, result.message]; - } - return [true, result['data']]; - } - - changeOwner = async (id, owner) => { - let result = await request.post(`/${this.group}/${id}/change-owner?owner=${owner}`); - return result['code'] === 1; - } -} - -const assetApi = new AssetApi(); -export default assetApi; \ No newline at end of file diff --git a/web-backup/src/api/authorised.js b/web-backup/src/api/authorised.js deleted file mode 100644 index 4c29a1edd..000000000 --- a/web-backup/src/api/authorised.js +++ /dev/null @@ -1,66 +0,0 @@ -import qs from "qs"; -import request from "../common/request"; - -class AuthorisedApi { - - group = "authorised"; - - GetAssetPaging = async (params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/assets/paging?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - GetUserPaging = async (params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/users/paging?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - GetUserGroupPaging = async (params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/user-groups/paging?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - AuthorisedAssets = async (data) => { - const result = await request.post(`/${this.group}/assets`, data); - return result['code'] === 1; - } - - AuthorisedUsers = async (data) => { - const result = await request.post(`/${this.group}/users`, data); - return result['code'] === 1; - } - - AuthorisedUserGroups = async (data) => { - const result = await request.post(`/${this.group}/user-groups`, data); - return result['code'] === 1; - } - - GetSelected = async (params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/selected?${paramsStr}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } - - DeleteById = async (id) => { - const result = await request.delete(`/${this.group}/${id}`); - return result['code'] === 1; - } -} - -const authorisedApi = new AuthorisedApi(); -export default authorisedApi; \ No newline at end of file diff --git a/web-backup/src/api/branding.js b/web-backup/src/api/branding.js deleted file mode 100644 index 35165cadb..000000000 --- a/web-backup/src/api/branding.js +++ /dev/null @@ -1,15 +0,0 @@ -import request from "../common/request"; - -class BrandingApi { - - getBranding = async () => { - let result = await request.get(`/branding`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } -} - -let brandingApi = new BrandingApi(); -export default brandingApi; \ No newline at end of file diff --git a/web-backup/src/api/command-filter-rule.js b/web-backup/src/api/command-filter-rule.js deleted file mode 100644 index f014b8470..000000000 --- a/web-backup/src/api/command-filter-rule.js +++ /dev/null @@ -1,10 +0,0 @@ -import Api from "./api"; - -class CommandFilterRuleApi extends Api{ - constructor() { - super("command-filter-rules"); - } -} - -const commandFilterRuleApi = new CommandFilterRuleApi(); -export default commandFilterRuleApi; \ No newline at end of file diff --git a/web-backup/src/api/command-filter.js b/web-backup/src/api/command-filter.js deleted file mode 100644 index ab53ff0b6..000000000 --- a/web-backup/src/api/command-filter.js +++ /dev/null @@ -1,38 +0,0 @@ -import request from "../common/request"; -import Api from "./api"; - -class CommandFilterApi extends Api{ - - constructor() { - super("command-filters"); - } - - Bind = async (id, data) => { - const result = await request.post(`/${this.group}/${id}/bind`, data); - return result['code'] === 1; - } - - Unbind = async (id, data) => { - const result = await request.post(`/${this.group}/${id}/unbind`, data); - return result['code'] === 1; - } - - GetAssetIdByCommandFilterId = async (commandFilterId) => { - let result = await request.get(`/${this.group}/${commandFilterId}/assets/id`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } - - GetAll = async () => { - let result = await request.get(`/${this.group}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -const commandFilterApi = new CommandFilterApi(); -export default commandFilterApi; \ No newline at end of file diff --git a/web-backup/src/api/command.js b/web-backup/src/api/command.js deleted file mode 100644 index b0a09536b..000000000 --- a/web-backup/src/api/command.js +++ /dev/null @@ -1,16 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class CommandApi extends Api{ - constructor() { - super("commands"); - } - - changeOwner = async (id, owner) => { - let result = await request.post(`/${this.group}/${id}/change-owner?owner=${owner}`); - return result['code'] === 1; - } -} - -let commandApi = new CommandApi(); -export default commandApi; \ No newline at end of file diff --git a/web-backup/src/api/credential.js b/web-backup/src/api/credential.js deleted file mode 100644 index d8621a74b..000000000 --- a/web-backup/src/api/credential.js +++ /dev/null @@ -1,19 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class CredentialApi extends Api{ - constructor() { - super("credentials"); - } - - getAll = async () => { - let result = await request.get(`/${this.group}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -let credentialApi = new CredentialApi(); -export default credentialApi; \ No newline at end of file diff --git a/web-backup/src/api/job.js b/web-backup/src/api/job.js deleted file mode 100644 index b5b365587..000000000 --- a/web-backup/src/api/job.js +++ /dev/null @@ -1,36 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; -import qs from "qs"; - -class JobApi extends Api { - constructor() { - super("jobs"); - } - - changeStatus = async (id, status) => { - let result = await request.post(`/${this.group}/${id}/change-status?status=${status}`); - return result['code'] !== 1; - } - - exec = async (id) => { - let result = await request.post(`/${this.group}/${id}/exec`); - return result['code'] !== 1; - } - - getLogPaging = async (id, params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/${id}/logs/paging?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - deleteLogByJobId = async (id) => { - let result = await request.delete(`/${this.group}/${id}/logs`); - return result['code'] !== 1; - } -} - -let jobApi = new JobApi(); -export default jobApi; \ No newline at end of file diff --git a/web-backup/src/api/license.js b/web-backup/src/api/license.js deleted file mode 100644 index 3a891503e..000000000 --- a/web-backup/src/api/license.js +++ /dev/null @@ -1,17 +0,0 @@ -import request from "../common/request"; - -export const GetLicense = async () => { - let result = await request.get('/license'); - if (result['code'] !== 1) { - return; - } - return result['data']; -} - -export const GetMachineId = async () => { - let result = await request.get('/license/machine-id'); - if (result['code'] !== 1) { - return; - } - return result['data']; -} \ No newline at end of file diff --git a/web-backup/src/api/login-log.js b/web-backup/src/api/login-log.js deleted file mode 100644 index 7ea57b86a..000000000 --- a/web-backup/src/api/login-log.js +++ /dev/null @@ -1,16 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class LoginLogApi extends Api{ - constructor() { - super("login-logs"); - } - - Clear = async () => { - const result = await request.post(`/${this.group}/clear`); - return result['code'] === 1; - } -} - -let loginLogApi = new LoginLogApi(); -export default loginLogApi; \ No newline at end of file diff --git a/web-backup/src/api/login-policy.js b/web-backup/src/api/login-policy.js deleted file mode 100644 index 4341b7e36..000000000 --- a/web-backup/src/api/login-policy.js +++ /dev/null @@ -1,40 +0,0 @@ -import request from "../common/request"; -import qs from "qs"; -import Api from "./api"; - -class LoginPolicyApi extends Api{ - - constructor() { - super("login-policies"); - } - - Bind = async (id, data) => { - const result = await request.post(`/${this.group}/${id}/bind`, data); - return result['code'] === 1; - } - - Unbind = async (id, data) => { - const result = await request.post(`/${this.group}/${id}/unbind`, data); - return result['code'] === 1; - } - - GetUserPagingByForbiddenCommandId = async (id, params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/${id}/users/paging?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - GetUserIdByLoginPolicyId = async (id) => { - let result = await request.get(`/${this.group}/${id}/users/id`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -const loginPolicyApi = new LoginPolicyApi(); -export default loginPolicyApi; \ No newline at end of file diff --git a/web-backup/src/api/monitor.js b/web-backup/src/api/monitor.js deleted file mode 100644 index ece4980f0..000000000 --- a/web-backup/src/api/monitor.js +++ /dev/null @@ -1,37 +0,0 @@ -import request from "../common/request"; - -class MonitorApi { - getData = async () => { - let result = await request.get('/overview/ps'); - if (result['code'] !== 1) { - return {}; - } - let data = result['data']; - let netIO = []; - for (let i = 0; i < data['netIO'].length; i++) { - let item = data['netIO'][i]; - netIO.push({ - time: item['time'], - read: item['read'] / 1024 / 1024 / 1024, - write: item['write'] / 1024 / 1024 / 1024, - }); - } - data['netIO'] = netIO; - - let diskIO = []; - for (let i = 0; i < data['diskIO'].length; i++) { - let item = data['diskIO'][i]; - diskIO.push({ - time: item['time'], - read: item['read'] / 1024 / 1024 / 1024, - write: item['write'] / 1024 / 1024 / 1024, - }); - } - data['diskIO'] = diskIO; - - return data - } -} - -let monitorApi = new MonitorApi(); -export default monitorApi; \ No newline at end of file diff --git a/web-backup/src/api/permission.js b/web-backup/src/api/permission.js deleted file mode 100644 index 8b2ddb171..000000000 --- a/web-backup/src/api/permission.js +++ /dev/null @@ -1,16 +0,0 @@ -import request from "../common/request"; - -class PermissionApi { - group = "permissions"; - - getMenus = async () => { - let result = await request.get(`/menus`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -let permissionApi = new PermissionApi(); -export default permissionApi; \ No newline at end of file diff --git a/web-backup/src/api/role.js b/web-backup/src/api/role.js deleted file mode 100644 index d25dcc4b3..000000000 --- a/web-backup/src/api/role.js +++ /dev/null @@ -1,19 +0,0 @@ -import request from "../common/request"; -import Api from "./api"; - -class RoleApi extends Api { - constructor() { - super("roles"); - } - - GetAll = async () => { - let result = await request.get(`/${this.group}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -let roleApi = new RoleApi(); -export default roleApi; \ No newline at end of file diff --git a/web-backup/src/api/security.js b/web-backup/src/api/security.js deleted file mode 100644 index 53e011630..000000000 --- a/web-backup/src/api/security.js +++ /dev/null @@ -1,10 +0,0 @@ -import Api from "./api"; - -class SecurityApi extends Api { - constructor() { - super("securities"); - } -} - -let securityApi = new SecurityApi(); -export default securityApi; \ No newline at end of file diff --git a/web-backup/src/api/session.js b/web-backup/src/api/session.js deleted file mode 100644 index cc08c477f..000000000 --- a/web-backup/src/api/session.js +++ /dev/null @@ -1,57 +0,0 @@ -import Api from "./api"; -import qs from "qs"; -import request from "../common/request"; - -class SessionApi extends Api { - constructor() { - super("sessions"); - } - - GetCommandPagingBySessionId = async (sessionId, params) => { - let paramsStr = qs.stringify(params); - let result = await request.get(`/${this.group}/${sessionId}/commands/paging?${paramsStr}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - create = async (assetsId, mode) => { - let result = await request.post(`/${this.group}?assetId=${assetsId}&mode=${mode}`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - connect = async (sessionId) => { - let result = await request.post(`/${this.group}/${sessionId}/connect`); - return result['code'] === 1; - } - - disconnect = async (sessionId) => { - let result = await request.post(`/${this.group}/${sessionId}/disconnect`); - return result['code'] === 1; - } - - clear = async () => { - let result = await request.post(`/${this.group}/clear`); - return result['code'] === 1; - } - - stats = async (sessionId) => { - let result = await request.get(`/${this.group}/${sessionId}/stats`); - if (result['code'] !== 1) { - return {}; - } - return result['data']; - } - - resize = async (sessionId, width, height) => { - let result = await request.post(`/sessions/${sessionId}/resize?width=${width}&height=${height}`); - return result.code === 1; - } -} - -const sessionApi = new SessionApi(); -export default sessionApi; \ No newline at end of file diff --git a/web-backup/src/api/storage-log.js b/web-backup/src/api/storage-log.js deleted file mode 100644 index d90c8b5d5..000000000 --- a/web-backup/src/api/storage-log.js +++ /dev/null @@ -1,23 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class StorageLogApi extends Api { - constructor() { - super("storage-logs"); - } - - create = () => { - } - getById = () => { - } - updateById = () => { - } - - Clear = async () => { - const result = await request.post(`/${this.group}/clear`); - return result['code'] === 1; - } -} - -const storageLogApi = new StorageLogApi(); -export default storageLogApi; \ No newline at end of file diff --git a/web-backup/src/api/storage.js b/web-backup/src/api/storage.js deleted file mode 100644 index 2964bb5ff..000000000 --- a/web-backup/src/api/storage.js +++ /dev/null @@ -1,10 +0,0 @@ -import Api from "./api"; - -class StorageApi extends Api{ - constructor() { - super("storages"); - } -} - -let storageApi = new StorageApi(); -export default storageApi; \ No newline at end of file diff --git a/web-backup/src/api/strategy.js b/web-backup/src/api/strategy.js deleted file mode 100644 index b97249e3a..000000000 --- a/web-backup/src/api/strategy.js +++ /dev/null @@ -1,19 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class StrategyApi extends Api { - constructor() { - super("strategies"); - } - - GetAll = async () => { - let result = await request.get(`/${this.group}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -const strategyApi = new StrategyApi(); -export default strategyApi; \ No newline at end of file diff --git a/web-backup/src/api/tag.js b/web-backup/src/api/tag.js deleted file mode 100644 index 19ee86a7f..000000000 --- a/web-backup/src/api/tag.js +++ /dev/null @@ -1,15 +0,0 @@ -import request from "../common/request"; - -class TagApi { - - getAll = async () => { - let result = await request.get(`/tags`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -let tagApi = new TagApi(); -export default tagApi; \ No newline at end of file diff --git a/web-backup/src/api/user-group.js b/web-backup/src/api/user-group.js deleted file mode 100644 index a719aa813..000000000 --- a/web-backup/src/api/user-group.js +++ /dev/null @@ -1,19 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class UserGroupApi extends Api { - constructor() { - super("user-groups"); - } - - GetAll = async () => { - let result = await request.get(`/${this.group}`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -const userGroupApi = new UserGroupApi(); -export default userGroupApi; \ No newline at end of file diff --git a/web-backup/src/api/user.js b/web-backup/src/api/user.js deleted file mode 100644 index 28b08c1bf..000000000 --- a/web-backup/src/api/user.js +++ /dev/null @@ -1,28 +0,0 @@ -import Api from "./api"; -import request from "../common/request"; - -class UserApi extends Api { - constructor() { - super("users"); - } - - resetTotp = async (id) => { - let result = await request.post(`/${this.group}/${id}/reset-totp`); - return result['code'] === 1; - } - - changePassword = async (id, password) => { - let formData = new FormData(); - formData.set('password', password); - let result = await request.post(`/${this.group}/${id}/change-password`, formData); - return result['code'] === 1; - } - - changeStatus = async (id, status) => { - let result = await request.patch(`/${this.group}/${id}/status?status=${status}`); - return result['code'] !== 1; - } -} - -const userApi = new UserApi(); -export default userApi; \ No newline at end of file diff --git a/web-backup/src/api/worker/asset.js b/web-backup/src/api/worker/asset.js deleted file mode 100644 index e6bf5286b..000000000 --- a/web-backup/src/api/worker/asset.js +++ /dev/null @@ -1,19 +0,0 @@ -import Api from "../api"; -import request from "../../common/request"; - -class WorkAssetApi extends Api{ - constructor() { - super("worker/assets"); - } - - tags = async () => { - let result = await request.get(`/${this.group}/tags`); - if (result['code'] !== 1) { - return []; - } - return result['data']; - } -} - -let workAssetApi = new WorkAssetApi(); -export default workAssetApi; \ No newline at end of file diff --git a/web-backup/src/api/worker/command.js b/web-backup/src/api/worker/command.js deleted file mode 100644 index 6bf8747b1..000000000 --- a/web-backup/src/api/worker/command.js +++ /dev/null @@ -1,10 +0,0 @@ -import Api from "../api"; - -class WorkCommandApi extends Api{ - constructor() { - super("worker/commands"); - } -} - -let workCommandApi = new WorkCommandApi(); -export default workCommandApi; \ No newline at end of file diff --git a/web-backup/src/common/auth.js b/web-backup/src/common/auth.js deleted file mode 100644 index db0027f91..000000000 --- a/web-backup/src/common/auth.js +++ /dev/null @@ -1,8 +0,0 @@ -export const HasPermission = (permission) => { - let permissionsStr = sessionStorage.getItem('permissions'); - let permissions = JSON.parse(permissionsStr); - if (!permissions) { - return false; - } - return permissions.includes(permission); -} \ No newline at end of file diff --git a/web-backup/src/common/constants.js b/web-backup/src/common/constants.js deleted file mode 100644 index ce1ddb58b..000000000 --- a/web-backup/src/common/constants.js +++ /dev/null @@ -1,13 +0,0 @@ -export const PROTOCOL_COLORS = { - 'rdp': 'cyan', - 'ssh': 'blue', - 'telnet': 'geekblue', - 'vnc': 'purple', - 'kubernetes': 'volcano' -} - -export const MODE_COLORS = { - 'guacd': 'green', - 'native': 'orange', - 'terminal': 'purple', -} \ No newline at end of file diff --git a/web-backup/src/common/env.js b/web-backup/src/common/env.js deleted file mode 100644 index 4c947fff1..000000000 --- a/web-backup/src/common/env.js +++ /dev/null @@ -1,28 +0,0 @@ -function env() { - if (process.env.REACT_APP_ENV === 'development') { - // 本地开发环境 - return { - server: '//127.0.0.1:8088', - wsServer: 'ws://127.0.0.1:8088', - prefix: '', - } - } else { - // 生产环境 - let wsPrefix; - if (window.location.protocol === 'https:') { - wsPrefix = 'wss:' - } else { - wsPrefix = 'ws:' - } - return { - server: '', - wsServer: wsPrefix + window.location.host, - prefix: window.location.protocol + '//' + window.location.host, - } - } -} -export default env(); - -export const server = env().server; -export const wsServer = env().wsServer; -export const prefix = env().prefix; \ No newline at end of file diff --git a/web-backup/src/common/request.js b/web-backup/src/common/request.js deleted file mode 100644 index 22f4b8422..000000000 --- a/web-backup/src/common/request.js +++ /dev/null @@ -1,146 +0,0 @@ -import axios from 'axios' -import {server} from "./env"; -import {message} from 'antd'; -import {getHeaders} from "../utils/utils"; - -// 测试地址 -// axios.defaults.baseURL = server; -// 线上地址 -axios.defaults.baseURL = server; - -const handleError = (error) => { - if ("Network Error" === error.toString()) { - message.error('网络异常'); - return false; - } - if (error.response !== undefined && error.response.status === 401) { - window.location.href = '#/login'; - return false; - } - if (error.response !== undefined) { - message.error(error.response.data.message); - return false; - } - return true; -}; - -const handleResult = (result) => { - if (result['code'] === 401) { - window.location.href = '#/login'; - return false; - }if (result['code'] === 403) { - window.location.href = '#/permission-denied'; - return false; - } else if (result['code'] === 100) { - return true; - } else if (result['code'] !== 1) { - message.error(result['message']); - return false; - } - return true; -} - -const request = { - - get: function (url) { - const headers = getHeaders(); - - return new Promise((resolve, reject) => { - axios.get(url, {headers: headers}) - .then((response) => { - let contentType = response.headers['content-type']; - if (contentType !== '' && contentType.includes('application/json')) { - handleResult(response.data); - } - resolve(response.data); - }) - .catch((error) => { - if (!handleError(error)) { - return; - } - reject(error); - }); - }) - }, - - post: function (url, params, header) { - - const headers = getHeaders(); - if (header) { - for (const k in header) { - headers[k] = header[k]; - } - } - - - return new Promise((resolve, reject) => { - axios.post(url, params, {headers: headers}) - .then((response) => { - handleResult(response.data); - resolve(response.data); - }) - .catch((error) => { - if (!handleError(error)) { - return; - } - reject(error); - }); - }) - }, - - put: function (url, params) { - - const headers = getHeaders(); - - return new Promise((resolve, reject) => { - axios.put(url, params, {headers: headers}) - .then((response) => { - handleResult(response.data); - resolve(response.data); - }) - .catch((error) => { - if (!handleError(error)) { - return; - } - reject(error); - }); - }) - }, - - delete: function (url) { - const headers = getHeaders(); - - return new Promise((resolve, reject) => { - axios.delete(url, {headers: headers}) - .then((response) => { - handleResult(response.data); - resolve(response.data); - }) - .catch((error) => { - if (!handleError(error)) { - return; - } - reject(error); - }); - }) - }, - - patch: function (url, params) { - const headers = getHeaders(); - - return new Promise((resolve, reject) => { - axios.patch(url, params, {headers: headers}) - .then((response) => { - handleResult(response.data); - resolve(response.data); - }) - .catch((error) => { - if (!handleError(error)) { - return; - } - reject(error); - }); - }) - }, -}; -export default request diff --git a/web-backup/src/common/router.js b/web-backup/src/common/router.js deleted file mode 100644 index 82ed19db3..000000000 --- a/web-backup/src/common/router.js +++ /dev/null @@ -1,11 +0,0 @@ -import {useLocation, useNavigate, useParams, useSearchParams} from "react-router-dom"; - -export const withRouter = (Component) => { - return (props) => { - const location = useLocation(); - const navigate = useNavigate(); - const params = useParams(); - const searchParams = useSearchParams(); - return ; - }; -} \ No newline at end of file diff --git a/web-backup/src/components/AccessToken.js b/web-backup/src/components/AccessToken.js deleted file mode 100644 index 460040d27..000000000 --- a/web-backup/src/components/AccessToken.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import {Button, Descriptions, Space, Typography} from "antd"; -import {useQuery} from "react-query"; -import accountApi from "../api/account"; - - -const {Title, Text} = Typography; - -const AccessToken = () => { - - let tokenQuery = useQuery('getAccessToken', accountApi.getAccessToken); - - const genAccessToken = async () => { - await accountApi.createAccessToken(); - await tokenQuery.refetch(); - } - - const clearAccessToken = async () => { - let success = await accountApi.deleteAccessToken(); - if (success) { - await tokenQuery.refetch(); - } - } - - return ( -
- 授权令牌 -
- - - {tokenQuery.data?.token} - - - {tokenQuery.data?.created} - - - - - - - -
- ); -}; - -export default AccessToken; \ No newline at end of file diff --git a/web-backup/src/components/Info.js b/web-backup/src/components/Info.js deleted file mode 100644 index 9b3cd15d9..000000000 --- a/web-backup/src/components/Info.js +++ /dev/null @@ -1,118 +0,0 @@ -import React, {useState} from 'react'; -import {Button, Form, Input, Layout, message, Tabs, Typography} from "antd"; -import accountApi from "../api/account"; -import Totp from "./Totp"; - -const {Content} = Layout; -const {Title} = Typography; - -const Info = () => { - - let [newPassword1, setNewPassword1] = useState(''); - let [newPassword2, setNewPassword2] = useState(''); - let [newPasswordStatus, setNewPasswordStatus] = useState({}); - - const onNewPasswordChange = (value) => { - setNewPassword1(value.target.value); - setNewPasswordStatus(validateNewPassword(value.target.value, newPassword2)); - } - - const onNewPassword2Change = (value) => { - setNewPassword2(value.target.value); - setNewPasswordStatus(validateNewPassword(newPassword1, value.target.value)); - } - - const validateNewPassword = (newPassword1, newPassword2) => { - if (newPassword2 === newPassword1) { - return { - validateStatus: 'success', - errorMsg: null, - }; - } - return { - validateStatus: 'error', - errorMsg: '两次输入的密码不一致', - }; - } - - const changePassword = async (values) => { - let success = await accountApi.changePassword(values); - if (success) { - message.success('密码修改成功,即将跳转至登录页面'); - window.location.href = '/#'; - } - } - - return ( - <> - - - - 修改密码 -
-
- - - - - - onNewPasswordChange(value)} style={{width: 240}}/> - - - onNewPassword2Change(value)} style={{width: 240}}/> - - - - -
-
- - {/**/} - {/* */} - {/**/} - - - - -
-
- - ); -} - -export default Info; diff --git a/web-backup/src/components/Landing.js b/web-backup/src/components/Landing.js deleted file mode 100644 index cd51b8e7b..000000000 --- a/web-backup/src/components/Landing.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -const Landing = () => { - return ( -
-
正在努力加载中...
-
- ); -}; - -export default Landing; \ No newline at end of file diff --git a/web-backup/src/components/Login.css b/web-backup/src/components/Login.css deleted file mode 100644 index 06b794669..000000000 --- a/web-backup/src/components/Login.css +++ /dev/null @@ -1,20 +0,0 @@ -.login-form { - max-width: 300px; - min-width: 300px; -} - -.login-form-forgot { - float: right; -} - -.login-form-button { - width: 100%; -} - -.login-card { - position: absolute; - left: 50%; - top: 40%; - margin-left: -175px; - margin-top: -189px; -} \ No newline at end of file diff --git a/web-backup/src/components/Login.js b/web-backup/src/components/Login.js deleted file mode 100644 index e1d96f7ae..000000000 --- a/web-backup/src/components/Login.js +++ /dev/null @@ -1,133 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {Button, Card, Checkbox, Form, Input, message, Modal, Typography} from "antd"; -import './Login.css' -import request from "../common/request"; -import {LockOutlined, UserOutlined} from '@ant-design/icons'; -import {setToken} from "../utils/utils"; -import brandingApi from "../api/branding"; -import strings from "../utils/strings"; -import {useNavigate} from "react-router-dom"; -import {setCurrentUser} from "../service/permission"; -import PromptModal from "../dd/prompt-modal/prompt-modal"; - -const {Title, Text} = Typography; - -const LoginForm = () => { - - const navigate = useNavigate(); - - let [inLogin, setInLogin] = useState(false); - let [branding, setBranding] = useState({}); - let [prompt, setPrompt] = useState(false); - let [account, setAccount] = useState({}); - - useEffect(() => { - const x = async () => { - let branding = await brandingApi.getBranding(); - document.title = branding['name']; - setBranding(branding); - } - x(); - }, []); - - const afterLoginSuccess = async (data) => { - // 跳转登录 - sessionStorage.removeItem('current'); - sessionStorage.removeItem('openKeys'); - setToken(data['token']); - - let user = data['info']; - setCurrentUser(user); - if (user) { - if (user['type'] === 'user') { - navigate('/my-asset'); - } else { - navigate('/'); - } - } - } - - const login = async (values) => { - let result = await request.post('/login', values); - if (result['code'] === 1) { - Modal.destroyAll(); - await afterLoginSuccess(result['data']); - } - } - - const handleOk = (loginAccount, totp) => { - if (!strings.hasText(totp)) { - message.warn("请输入双因素认证码"); - return false; - } - loginAccount['totp'] = totp; - login(loginAccount); - return false; - } - - const handleSubmit = async params => { - setInLogin(true); - - try { - let result = await request.post('/login', params); - if (result.code === 100) { - // 进行双因素认证 - setPrompt(true); - setAccount(params); - return; - } - if (result.code !== 1) { - return; - } - - afterLoginSuccess(result['data']); - } catch (e) { - message.error(e.message); - } finally { - setInLogin(false); - } - }; - - return ( -
- -
- {branding['name']} - {branding['description']} -
-
- - } placeholder="登录账号"/> - - - } placeholder="登录密码"/> - - - 保持登录 - - - - -
-
- - { - handleOk(account, value) - }} - onCancel={() => setPrompt(false)} - placeholder={"请输入双因素认证码"} - > - - -
- - ); -} - -export default LoginForm; diff --git a/web-backup/src/components/NoMatch.js b/web-backup/src/components/NoMatch.js deleted file mode 100644 index 07d12e0ed..000000000 --- a/web-backup/src/components/NoMatch.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import {Button, Layout, Result, Space} from "antd"; -import {Link, useNavigate} from "react-router-dom"; - -const {Content} = Layout; - -const NoMatch = () => { - - let navigate = useNavigate(); - - return ( -
- - - - - - - } - /> - -
- ); -}; - -export default NoMatch; \ No newline at end of file diff --git a/web-backup/src/components/NoPermission.js b/web-backup/src/components/NoPermission.js deleted file mode 100644 index 1300c7a05..000000000 --- a/web-backup/src/components/NoPermission.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import {Button, Layout, Result, Space} from "antd"; -import {Link, useNavigate} from "react-router-dom"; - -const {Content} = Layout; - -const NoPermission = () => { - - const navigate = useNavigate(); - - return ( -
- - - - - - - } - /> - -
- ); -}; - -export default NoPermission; \ No newline at end of file diff --git a/web-backup/src/components/Redirect.js b/web-backup/src/components/Redirect.js deleted file mode 100644 index bcdba24d1..000000000 --- a/web-backup/src/components/Redirect.js +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import {useQuery} from "react-query"; -import accountApi from "../api/account"; -import {setCurrentUser} from "../service/permission"; -import {useNavigate} from "react-router-dom"; -import Landing from "./Landing"; - -const Redirect = () => { - - let navigate = useNavigate(); - - let infoQuery = useQuery('infoQuery', accountApi.getUserInfo, { - onSuccess: data => { - setCurrentUser(data); - if (data.type === 'user') { - navigate('/my-asset'); - } else if (data.type === 'admin'){ - navigate('/dashboard'); - } - } - }); - - return ( -
- -
- ); -}; - -export default Redirect; \ No newline at end of file diff --git a/web-backup/src/components/Totp.js b/web-backup/src/components/Totp.js deleted file mode 100644 index 7a741882b..000000000 --- a/web-backup/src/components/Totp.js +++ /dev/null @@ -1,131 +0,0 @@ -import React, {useState} from 'react'; -import {Button, Form, Image, Input, message, Modal, Result, Space, Typography} from "antd"; -import {ExclamationCircleOutlined, ReloadOutlined} from "@ant-design/icons"; -import accountApi from "../api/account"; -import {useQuery} from "react-query"; - -const {Title} = Typography; - -const Totp = () => { - - let infoQuery = useQuery('infoQuery', accountApi.getUserInfo); - let [totp, setTotp] = useState({}); - - const resetTOTP = async () => { - let totp = await accountApi.reloadTotp(); - setTotp(totp); - } - - const confirmTOTP = async (values) => { - values['secret'] = totp['secret']; - let success = await accountApi.confirmTotp(values); - if (success) { - message.success('TOTP启用成功'); - await infoQuery.refetch(); - setTotp({}); - } - } - - const renderBindingTotpPage = (qr) => { - if (!qr) { - return undefined; - } - return - } - - return ( -
- 双因素认证 - - - { - renderBindingTotpPage(totp.qr) - } - -
- ); -}; - -export default Totp; \ No newline at end of file diff --git a/web-backup/src/components/access/BatchCommandTerm.css b/web-backup/src/components/access/BatchCommandTerm.css deleted file mode 100644 index 52025ee8a..000000000 --- a/web-backup/src/components/access/BatchCommandTerm.css +++ /dev/null @@ -1,3 +0,0 @@ -.console-card .ant-card-body { - padding: 0; -} \ No newline at end of file diff --git a/web-backup/src/components/access/BatchCommandTerm.js b/web-backup/src/components/access/BatchCommandTerm.js deleted file mode 100644 index 0d78cb196..000000000 --- a/web-backup/src/components/access/BatchCommandTerm.js +++ /dev/null @@ -1,186 +0,0 @@ -import React, {Component} from 'react'; -import "xterm/css/xterm.css" -import {Terminal} from "xterm"; -import qs from "qs"; -import {wsServer} from "../../common/env"; -import "./BatchCommandTerm.css" -import {getToken, isEmpty} from "../../utils/utils"; -import {FitAddon} from 'xterm-addon-fit' -import request from "../../common/request"; -import {message} from "antd"; -import Message from './Message' - -class BatchCommandTerm extends Component { - - state = { - term: undefined, - webSocket: undefined, - fitAddon: undefined - }; - - componentDidMount = async () => { - - let command = this.props.command; - let assetId = this.props.assetId; - - let sessionId = await this.createSession(assetId); - if (isEmpty(sessionId)) { - return; - } - - let term = new Terminal({ - fontFamily: 'monaco, Consolas, "Lucida Console", monospace', - fontSize: 14, - theme: { - background: '#1b1b1b' - }, - rightClickSelectsWord: true, - }); - - term.open(this.refs.terminal); - const fitAddon = new FitAddon(); - term.loadAddon(fitAddon); - fitAddon.fit(); - term.focus(); - - term.writeln('Trying to connect to the server ...'); - - term.onData(data => { - let webSocket = this.state.webSocket; - if (webSocket !== undefined) { - webSocket.send(new Message(Message.Data, data).toString()); - } - }); - - let token = getToken(); - let params = { - 'cols': term.cols, - 'rows': term.rows, - 'sessionId': sessionId, - 'X-Auth-Token': token - }; - - let paramStr = qs.stringify(params); - - let webSocket = new WebSocket(`${wsServer}/sessions/${sessionId}/ssh?${paramStr}`); - - this.props.appendWebsocket({'id': assetId, 'ws': webSocket}); - - webSocket.onopen = (e => { - this.onWindowResize(); - }); - - webSocket.onerror = (e) => { - term.writeln("Failed to connect to server."); - } - webSocket.onclose = (e) => { - term.writeln("Connection is closed."); - } - - let executedCommand = false - webSocket.onmessage = (e) => { - let msg = Message.parse(e.data); - switch (msg['type']) { - case Message.Connected: - term.clear(); - this.updateSessionStatus(sessionId); - break; - case Message.Data: - term.write(msg['content']); - break; - case Message.Closed: - term.writeln(`\x1B[1;3;31m${msg['content']}\x1B[0m `) - webSocket.close(); - break; - default: - break; - } - - if (!executedCommand) { - if (command !== '') { - let webSocket = this.state.webSocket; - if (webSocket !== undefined && webSocket.readyState === WebSocket.OPEN) { - webSocket.send(new Message(Message.Data, command + String.fromCharCode(13)).toString()); - } - } - executedCommand = true; - } - } - - this.setState({ - term: term, - fitAddon: fitAddon, - webSocket: webSocket, - }); - - window.addEventListener('resize', this.onWindowResize); - } - - componentWillUnmount() { - let webSocket = this.state.webSocket; - if (webSocket) { - webSocket.close() - } - } - - async createSession(assetsId) { - let result = await request.post(`/sessions?assetId=${assetsId}&mode=native`); - if (result['code'] !== 1) { - this.showMessage(result['message']); - return null; - } - return result['data']['id']; - } - - updateSessionStatus = async (sessionId) => { - let result = await request.post(`/sessions/${sessionId}/connect`); - if (result['code'] !== 1) { - message.error(result['message']); - } - } - - onWindowResize = (e) => { - let term = this.state.term; - let fitAddon = this.state.fitAddon; - let webSocket = this.state.webSocket; - this.setState({ - width: window.innerWidth, - height: window.innerHeight, - }, () => { - if (webSocket && webSocket.readyState === WebSocket.OPEN) { - fitAddon.fit(); - this.focus(); - let terminalSize = { - cols: term.cols, - rows: term.rows - } - webSocket.send(new Message(Message.Resize, window.btoa(JSON.stringify(terminalSize))).toString()); - } - }); - }; - - focus = () => { - let term = this.state.term; - if (term) { - term.focus(); - } - } - - render() { - return ( -
-
-
-
- -
- ); - } -} - -export default BatchCommandTerm; diff --git a/web-backup/src/components/access/Guacd.css b/web-backup/src/components/access/Guacd.css deleted file mode 100644 index a1758a9fc..000000000 --- a/web-backup/src/components/access/Guacd.css +++ /dev/null @@ -1,3 +0,0 @@ -#display > div { - margin: 0 auto; -} \ No newline at end of file diff --git a/web-backup/src/components/access/Guacd.js b/web-backup/src/components/access/Guacd.js deleted file mode 100644 index 1540de774..000000000 --- a/web-backup/src/components/access/Guacd.js +++ /dev/null @@ -1,560 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {useSearchParams} from "react-router-dom"; -import sessionApi from "../../api/session"; -import strings from "../../utils/strings"; -import Guacamole from "guacamole-common-js"; -import {wsServer} from "../../common/env"; -import {exitFull, getToken, requestFullScreen} from "../../utils/utils"; -import qs from "qs"; -import {Affix, Button, Drawer, Dropdown, Menu, message, Modal} from "antd"; -import { - CopyOutlined, - ExclamationCircleOutlined, - ExpandOutlined, - FolderOutlined, - WindowsOutlined -} from "@ant-design/icons"; -import {Base64} from "js-base64"; -import Draggable from "react-draggable"; -import FileSystem from "../devops/FileSystem"; -import GuacdClipboard from "./GuacdClipboard"; -import {debounce} from "../../utils/fun"; -import './Guacd.css'; - -let fixedSize = false; - -const STATE_IDLE = 0; -const STATE_CONNECTING = 1; -const STATE_WAITING = 2; -const STATE_CONNECTED = 3; -const STATE_DISCONNECTING = 4; -const STATE_DISCONNECTED = 5; - -const Guacd = () => { - - let [searchParams] = useSearchParams(); - let assetId = searchParams.get('assetId'); - let assetName = searchParams.get('assetName'); - let protocol = searchParams.get('protocol'); - let width = searchParams.get('width'); - let height = searchParams.get('height'); - - if (width && height) { - fixedSize = true; - } else { - width = window.innerWidth; - height = window.innerHeight; - } - - let [box, setBox] = useState({width, height}); - let [guacd, setGuacd] = useState({}); - let [session, setSession] = useState({}); - let [clipboardText, setClipboardText] = useState(''); - let [fullScreened, setFullScreened] = useState(false); - let [clipboardVisible, setClipboardVisible] = useState(false); - let [fileSystemVisible, setFileSystemVisible] = useState(false); - - useEffect(() => { - document.title = assetName; - createSession(); - }, [assetId, assetName]); - - const createSession = async () => { - let session = await sessionApi.create(assetId, 'guacd'); - if (!strings.hasText(session['id'])) { - return; - } - setSession(session); - renderDisplay(session['id'], protocol, width, height); - } - - const renderDisplay = (sessionId, protocol, width, height) => { - let tunnel = new Guacamole.WebSocketTunnel(`${wsServer}/sessions/${sessionId}/tunnel`); - let client = new Guacamole.Client(tunnel); - - // 处理从虚拟机收到的剪贴板内容 - client.onclipboard = handleClipboardReceived; - - // 处理客户端的状态变化事件 - client.onstatechange = (state) => { - onClientStateChange(state, sessionId); - }; - - client.onerror = onError; - tunnel.onerror = onError; - - // Get display div from document - const displayEle = document.getElementById("display"); - - // Add client to display div - const element = client.getDisplay().getElement(); - displayEle.appendChild(element); - - let dpi = 96; - if (protocol === 'telnet') { - dpi = dpi * 2; - } - - let token = getToken(); - - let params = { - 'width': width, - 'height': height, - 'dpi': dpi, - 'X-Auth-Token': token - }; - - let paramStr = qs.stringify(params); - - client.connect(paramStr); - let display = client.getDisplay(); - display.onresize = function (width, height) { - display.scale(Math.min( - window.innerHeight / display.getHeight(), - window.innerWidth / display.getHeight() - )) - } - - const sink = new Guacamole.InputSink(); - displayEle.appendChild(sink.getElement()); - sink.focus(); - - const keyboard = new Guacamole.Keyboard(sink.getElement()); - - keyboard.onkeydown = (keysym) => { - console.log('aaa') - client.sendKeyEvent(1, keysym); - if (keysym === 65288) { - return false; - } - }; - keyboard.onkeyup = (keysym) => { - client.sendKeyEvent(0, keysym); - }; - - const sinkFocus = debounce(() => { - sink.focus(); - }); - - const mouse = new Guacamole.Mouse(element); - - mouse.onmousedown = mouse.onmouseup = function (mouseState) { - sinkFocus(); - client.sendMouseState(mouseState); - } - - mouse.onmousemove = function (mouseState) { - sinkFocus(); - client.getDisplay().showCursor(false); - mouseState.x = mouseState.x / display.getScale(); - mouseState.y = mouseState.y / display.getScale(); - client.sendMouseState(mouseState); - }; - - const touch = new Guacamole.Mouse.Touchpad(element); // or Guacamole.Touchscreen - - touch.onmousedown = touch.onmousemove = touch.onmouseup = function (state) { - client.sendMouseState(state); - }; - - - - setGuacd({ - client, - sink, - }); - } - - useEffect(() => { - let resize = debounce(() => { - onWindowResize(); - }); - window.addEventListener('resize', resize); - window.addEventListener('beforeunload', handleUnload); - window.addEventListener('focus', handleWindowFocus); - - return () => { - window.removeEventListener('resize', resize); - window.removeEventListener('beforeunload', handleUnload); - window.removeEventListener('focus', handleWindowFocus); - }; - }, [guacd]) - - const onWindowResize = () => { - if (guacd.client && !fixedSize) { - const display = guacd.client.getDisplay(); - let width = window.innerWidth; - let height = window.innerHeight; - setBox({width, height}); - let scale = Math.min( - height / display.getHeight(), - width / display.getHeight() - ); - display.scale(scale); - guacd.client.sendSize(width, height); - } - } - - const handleUnload = (e) => { - const message = "要离开网站吗?"; - (e || window.event).returnValue = message; //Gecko + IE - return message; - } - - const focus = () => { - console.log(guacd.sink) - if (guacd.sink) { - guacd.sink.focus(); - } - } - - const handleWindowFocus = (e) => { - if (navigator.clipboard) { - try { - navigator.clipboard.readText().then((text) => { - sendClipboard({ - 'data': text, - 'type': 'text/plain' - }); - }) - } catch (e) { - console.error('复制剪贴板失败', e); - } - } - }; - - const handleClipboardReceived = (stream, mimetype) => { - if (session['copy'] === '0') { - // message.warn('禁止复制'); - return - } - - if (/^text\//.exec(mimetype)) { - let reader = new Guacamole.StringReader(stream); - let data = ''; - reader.ontext = function textReceived(text) { - data += text; - }; - reader.onend = async () => { - setClipboardText(data); - if (navigator.clipboard) { - await navigator.clipboard.writeText(data); - } - // message.success('您选择的内容已复制到您的粘贴板中,在右侧的输入框中可同时查看到。'); - }; - } else { - let reader = new Guacamole.BlobReader(stream, mimetype); - reader.onend = () => { - setClipboardText(reader.getBlob()); - } - } - }; - - const sendClipboard = (data) => { - if (!guacd.client) { - return; - } - if (session['paste'] === '0') { - message.warn('禁止粘贴'); - return - } - const stream = guacd.client.createClipboardStream(data.type); - if (typeof data.data === 'string') { - let writer = new Guacamole.StringWriter(stream); - writer.sendText(data.data); - writer.sendEnd(); - } else { - let writer = new Guacamole.BlobWriter(stream); - writer.oncomplete = function clipboardSent() { - writer.sendEnd(); - }; - writer.sendBlob(data.data); - } - - if (data.data && data.data.length > 0) { - // message.info('您输入的内容已复制到远程服务器上'); - } - } - - const onClientStateChange = (state, sessionId) => { - const key = 'message'; - switch (state) { - case STATE_IDLE: - message.destroy(key); - message.loading({content: '正在初始化中...', duration: 0, key: key}); - break; - case STATE_CONNECTING: - message.destroy(key); - message.loading({content: '正在努力连接中...', duration: 0, key: key}); - break; - case STATE_WAITING: - message.destroy(key); - message.loading({content: '正在等待服务器响应...', duration: 0, key: key}); - break; - case STATE_CONNECTED: - Modal.destroyAll(); - message.destroy(key); - message.success({content: '连接成功', duration: 3, key: key}); - // 向后台发送请求,更新会话的状态 - sessionApi.connect(sessionId); - break; - case STATE_DISCONNECTING: - - break; - case STATE_DISCONNECTED: - message.info({content: '连接已关闭', duration: 3, key: key}); - break; - default: - break; - } - }; - - const sendCombinationKey = (keys) => { - if (!guacd.client) { - return; - } - for (let i = 0; i < keys.length; i++) { - guacd.client.sendKeyEvent(1, keys[i]); - } - for (let j = 0; j < keys.length; j++) { - guacd.client.sendKeyEvent(0, keys[j]); - } - message.success('发送组合键成功'); - } - - const showMessage = (msg) => { - message.destroy(); - Modal.confirm({ - title: '提示', - icon: , - content: msg, - centered: true, - okText: '重新连接', - cancelText: '关闭页面', - onOk() { - window.location.reload(); - }, - onCancel() { - window.close(); - }, - }); - } - - const onError = (status) => { - switch (status.code) { - case 256: - showMessage('未支持的访问'); - break; - case 512: - showMessage('远程服务异常,请检查目标设备能否正常访问。'); - break; - case 513: - showMessage('服务器忙碌'); - break; - case 514: - showMessage('服务器连接超时'); - break; - case 515: - showMessage('远程服务异常'); - break; - case 516: - showMessage('资源未找到'); - break; - case 517: - showMessage('资源冲突'); - break; - case 518: - showMessage('资源已关闭'); - break; - case 519: - showMessage('远程服务未找到'); - break; - case 520: - showMessage('远程服务不可用'); - break; - case 521: - showMessage('会话冲突'); - break; - case 522: - showMessage('会话连接超时'); - break; - case 523: - showMessage('会话已关闭'); - break; - case 768: - showMessage('网络不可达'); - break; - case 769: - showMessage('服务器密码验证失败'); - break; - case 771: - showMessage('客户端被禁止'); - break; - case 776: - showMessage('客户端连接超时'); - break; - case 781: - showMessage('客户端异常'); - break; - case 783: - showMessage('错误的请求类型'); - break; - case 800: - showMessage('会话不存在'); - break; - case 801: - showMessage('创建隧道失败,请检查Guacd服务是否正常。'); - break; - case 802: - showMessage('管理员强制关闭了此会话'); - break; - default: - if (status.message) { - // guacd 无法处理中文字符,所以进行了base64编码。 - showMessage(Base64.decode(status.message)); - } else { - showMessage('未知错误。'); - } - - } - }; - - const fullScreen = () => { - if (fullScreened) { - exitFull(); - setFullScreened(false); - } else { - requestFullScreen(document.documentElement); - setFullScreened(true); - } - focus(); - } - - const hotKeyMenu = ( - - sendCombinationKey(['65507', '65513', '65535'])}>Ctrl+Alt+Delete - sendCombinationKey(['65507', '65513', '65288'])}>Ctrl+Alt+Backspace - sendCombinationKey(['65515', '100'])}>Windows+D - sendCombinationKey(['65515', '101'])}>Windows+E - sendCombinationKey(['65515', '114'])}>Windows+R - sendCombinationKey(['65515', '120'])}>Windows+X - sendCombinationKey(['65515'])}>Windows - - ); - - return ( -
-
-
-
- - - -
- ); -}; - -export default Guacd; \ No newline at end of file diff --git a/web-backup/src/components/access/GuacdClipboard.js b/web-backup/src/components/access/GuacdClipboard.js deleted file mode 100644 index 9aae1f6e7..000000000 --- a/web-backup/src/components/access/GuacdClipboard.js +++ /dev/null @@ -1,48 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {Form, Input, Modal} from "antd"; - -const GuacdClipboard = ({visible, clipboardText, handleOk, handleCancel}) => { - - const [form] = Form.useForm(); - let [confirmLoading, setConfirmLoading] = useState(false); - - useEffect(() => { - form.setFieldsValue({ - 'clipboard': clipboardText - }) - }, [visible]); - - return ( -
- { - form.validateFields() - .then(values => { - setConfirmLoading(true); - try { - handleOk(values['clipboard']); - } finally { - setConfirmLoading(false); - } - }) - .catch(info => { - - }); - }} - confirmLoading={confirmLoading} - onCancel={handleCancel} - > -
- - - -
-
-
- ); -}; - -export default GuacdClipboard; \ No newline at end of file diff --git a/web-backup/src/components/access/Message.js b/web-backup/src/components/access/Message.js deleted file mode 100644 index 241561529..000000000 --- a/web-backup/src/components/access/Message.js +++ /dev/null @@ -1,23 +0,0 @@ -const Message = class Message { - constructor(type, content) { - this.type = type; - this.content = content; - } - - toString() { - return this.type + this.content; - } - - static Closed = 0; - static Connected = 1; - static Data = 2; - static Resize = 3; - static Ping = 4; - - static parse(s) { - let type = parseInt(s.substring(0, 1)); - let content = s.substring(1, s.length); - return new Message(type, content); - } -}; -export default Message; \ No newline at end of file diff --git a/web-backup/src/components/access/Stats.css b/web-backup/src/components/access/Stats.css deleted file mode 100644 index f4e192ab0..000000000 --- a/web-backup/src/components/access/Stats.css +++ /dev/null @@ -1,5 +0,0 @@ -.description-content { - align-items: center; - justify-content: center; - vertical-align: middle; -} \ No newline at end of file diff --git a/web-backup/src/components/access/Stats.js b/web-backup/src/components/access/Stats.js deleted file mode 100644 index de8c478ea..000000000 --- a/web-backup/src/components/access/Stats.js +++ /dev/null @@ -1,197 +0,0 @@ -import React, {useState} from 'react'; -import {Col, Descriptions, Progress, Row} from "antd"; -import {renderSize} from "../../utils/utils"; -import './Stats.css' -import {useQuery} from "react-query"; -import sessionApi from "../../api/session"; - -const defaultStats = { - uptime: 0, - load1: 0, - load5: 0, - load10: 0, - memTotal: 0, - memFree: 0, - memAvailable: 0, - memBuffers: 0, - memCached: 0, - swapTotal: 0, - swapFree: 0, - network: {}, - fileSystems: [], - cpu: { - user: 0, - system: 0, - nice: 0, - idle: 0, - ioWait: 0, - irq: 0, - softIrq: 0, - guest: 0 - } -} - -const Stats = ({sessionId, visible, queryInterval = 5000}) => { - - let [stats, setStats] = useState(defaultStats); - let [prevStats, setPrevStats] = useState({}); - - useQuery("stats", () => sessionApi.stats(sessionId), { - refetchInterval: queryInterval, - enabled: visible, - onSuccess: (data) => { - setPrevStats(stats); - setStats(data); - } - }); - - const upDays = parseInt((stats.uptime / 1000 / 60 / 60 / 24).toString()); - const memUsage = ((stats.memTotal - stats.memAvailable) * 100 / stats.memTotal).toFixed(2); - let network = stats.network; - let fileSystems = stats.fileSystems; - - let swapUsage = 0; - if (stats.swapTotal !== 0) { - swapUsage = ((stats.swapTotal - stats.swapFree) * 100 / stats.swapTotal).toFixed(2) - } - - return ( -
- - {stats.hostname} - {upDays}天 - - - - - - -
- -
-
- -
- -
-
- -
- -
-
-
- -
- - - - - {stats.cpu['user'].toFixed(2)}% - - - {stats.cpu['system'].toFixed(2)}% - - - {stats.cpu['idle'].toFixed(2)}% - - - {stats.cpu['ioWait'].toFixed(2)}% - - - {stats.cpu['irq'].toFixed(2)}% - - - {stats.cpu['softIrq'].toFixed(2)}% - - - {stats.cpu['nice'].toFixed(2)}% - - - {stats.cpu['guest'].toFixed(2)}% - - - - - {renderSize(stats.memTotal)} - {renderSize(stats.memFree)} - {renderSize(stats.memAvailable)} - -
- -
-
- {renderSize(stats.memBuffers)} / {renderSize(stats.memCached)} - {renderSize(stats.swapTotal)} - {renderSize(stats.swapFree)} - -
- -
-
-
- - - { - fileSystems.map((item, index) => { - return ( - - - {item['mountPoint']} - - - {renderSize(item['used'])} - - - {renderSize(item['free'])} - - -
- -
-
-
- ); - }) - } -
- - - { - Object.keys(network).map((key, index) => { - let prevNetwork = prevStats.network; - let rxOfSeconds = 0, txOfSeconds = 0; - if (prevNetwork[key] !== undefined) { - rxOfSeconds = (network[key]['rx'] - prevNetwork[key]['rx']) / 5; - } - if (prevNetwork[key] !== undefined) { - txOfSeconds = (network[key]['tx'] - prevNetwork[key]['tx']) / 5; - } - - return ( - - {key} - - {network[key]['ipv4']} - - - {renderSize(network[key]['rx'])}   {renderSize(rxOfSeconds)}/秒 - - - {renderSize(network[key]['tx'])}   {renderSize(txOfSeconds)}/秒 - - - ); - }) - } - -
- ); -}; - -export default Stats; \ No newline at end of file diff --git a/web-backup/src/components/access/Term.js b/web-backup/src/components/access/Term.js deleted file mode 100644 index 9c424c572..000000000 --- a/web-backup/src/components/access/Term.js +++ /dev/null @@ -1,357 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {useSearchParams} from "react-router-dom"; -import {Terminal} from "xterm"; -import {FitAddon} from "xterm-addon-fit"; -import {getToken} from "../../utils/utils"; -import request from "../../common/request"; -import {Affix, Button, Drawer, Dropdown, Menu, message, Select, Space, Typography} from "antd"; -import Message from "./Message"; -import qs from "qs"; -import {wsServer} from "../../common/env"; -import Draggable from "react-draggable"; -import {CodeOutlined, FolderOutlined, LineChartOutlined} from "@ant-design/icons"; -import FileSystem from "../devops/FileSystem"; -import "xterm/css/xterm.css" -import Stats from "./Stats"; -import {debounce} from "../../utils/fun"; -import commandApi from "../../api/command"; -import strings from "../../utils/strings"; -import workCommandApi from "../../api/worker/command"; -import {xtermScrollPretty} from "../../utils/xterm-scroll-pretty"; - -const {Text} = Typography; - -const Term = () => { - - const [searchParams] = useSearchParams(); - const assetId = searchParams.get('assetId'); - const assetName = searchParams.get('assetName'); - const isWorker = searchParams.get('isWorker'); - const [box, setBox] = useState({width: window.innerWidth, height: window.innerHeight}); - - let [commands, setCommands] = useState([]); - - let [term, setTerm] = useState(); - let [fitAddon, setFitAddon] = useState(); - let [websocket, setWebsocket] = useState(); - let [session, setSession] = useState({}); - - let [fileSystemVisible, setFileSystemVisible] = useState(false); - let [statsVisible, setStatsVisible] = useState(false); - let [enterBtnZIndex, setEnterBtnZIndex] = useState(999); - let [queryInterval, setQueryInterval] = useState(5000); - - const createSession = async (assetsId) => { - let result = await request.post(`/sessions?assetId=${assetsId}&mode=native`); - if (result['code'] !== 1) { - return [undefined, result['message']]; - } - return [result['data'], '']; - } - - const writeErrorMessage = (term, message) => { - term.writeln(`\x1B[1;3;31m${message}\x1B[0m `); - } - - const updateSessionStatus = async (sessionId) => { - let result = await request.post(`/sessions/${sessionId}/connect`); - if (result['code'] !== 1) { - message.error(result['message']); - } - } - - const writeCommand = (command) => { - if (websocket) { - websocket.send(new Message(Message.Data, command)); - } - } - - const getCommands = async () => { - if (strings.hasText(isWorker)) { - let items = await workCommandApi.getAll(); - setCommands(items); - } else { - let items = await commandApi.getAll(); - setCommands(items); - } - } - - const focus = () => { - if (term) { - term.focus(); - } - } - - const fit = () => { - if (fitAddon) { - fitAddon.fit(); - } - } - - const onWindowResize = () => { - setBox({width: window.innerWidth, height: window.innerHeight}); - }; - - const init = async (assetId) => { - let term = new Terminal({ - fontFamily: 'monaco, Consolas, "Lucida Console", monospace', - fontSize: 15, - theme: { - background: '#1b1b1b' - }, - }); - let elementTerm = document.getElementById('terminal'); - term.open(elementTerm); - const fitAddon = new FitAddon(); - term.loadAddon(fitAddon); - fitAddon.fit(); - term.focus(); - - if (!assetId) { - writeErrorMessage(term, `参数缺失,请关闭此页面后重新打开。`) - return; - } - - let [session, errMsg] = await createSession(assetId); - if (!session) { - writeErrorMessage(term, `创建会话失败,${errMsg}`) - return; - } - - let sessionId = session['id']; - - term.writeln('trying to connect to the server ...'); - - document.body.oncopy = (event) => { - event.preventDefault(); - if (session['copy'] === '0') { - message.warn('禁止复制') - return false; - } else { - return true; - } - } - - document.body.onpaste = (event) => { - event.preventDefault(); - if (session['paste'] === '0') { - message.warn('禁止粘贴') - return false; - } else { - return true; - } - } - - let token = getToken(); - let params = { - 'cols': term.cols, - 'rows': term.rows, - 'X-Auth-Token': token - }; - - let paramStr = qs.stringify(params); - - let webSocket = new WebSocket(`${wsServer}/sessions/${sessionId}/ssh?${paramStr}`); - - let pingInterval; - webSocket.onopen = (e => { - pingInterval = setInterval(() => { - webSocket.send(new Message(Message.Ping, "").toString()); - }, 10000); - xtermScrollPretty(); - }); - - webSocket.onerror = (e) => { - writeErrorMessage(term, `websocket error ${e.data}`) - } - - webSocket.onclose = (e) => { - console.log(`e`, e); - term.writeln("connection is closed."); - if (pingInterval) { - clearInterval(pingInterval); - } - } - - term.onData(data => { - if (webSocket !== undefined) { - webSocket.send(new Message(Message.Data, data).toString()); - } - }); - - webSocket.onmessage = (e) => { - let msg = Message.parse(e.data); - switch (msg['type']) { - case Message.Connected: - term.clear(); - updateSessionStatus(sessionId); - getCommands(); - break; - case Message.Data: - term.write(msg['content']); - break; - case Message.Closed: - console.log(`服务端通知需要关闭连接`) - term.writeln(`\x1B[1;3;31m${msg['content']}\x1B[0m `); - webSocket.close(); - break; - default: - break; - } - } - - setSession(session); - setTerm(term); - setFitAddon(fitAddon); - setWebsocket(webSocket); - } - - const handleUnload = (e) => { - const message = "要离开网站吗?"; - (e || window.event).returnValue = message; //Gecko + IE - return message; - } - - useEffect(() => { - document.title = assetName; - init(assetId); - }, [assetId]); - - useEffect(() => { - if (term && websocket && fitAddon && websocket.readyState === WebSocket.OPEN) { - fit(); - focus(); - let terminalSize = { - cols: term.cols, - rows: term.rows - } - websocket.send(new Message(Message.Resize, window.btoa(JSON.stringify(terminalSize))).toString()); - } - window.addEventListener('beforeunload', handleUnload); - - let resize = debounce(() => { - onWindowResize(); - }); - - window.addEventListener('resize', resize); - - return () => { - // if (websocket) { - // websocket.close(); - // } - window.removeEventListener('resize', resize); - window.removeEventListener('beforeunload', handleUnload); - } - }, [box.width, box.height]); - - const cmdMenuItems = commands.map(item => { - return { - key: item['id'], - label: item['name'], - }; - }); - - const handleCmdMenuClick = (e) => { - for (const command of commands) { - if (command['id'] === e.key) { - writeCommand(command['content']); - } - } - } - - return ( -
-
- - - -
- ); -}; - -export default Term; \ No newline at end of file diff --git a/web-backup/src/components/asset/AccessGateway.js b/web-backup/src/components/asset/AccessGateway.js deleted file mode 100644 index 01762118c..000000000 --- a/web-backup/src/components/asset/AccessGateway.js +++ /dev/null @@ -1,208 +0,0 @@ -import React, {useState} from 'react'; - -import {Badge, Button, Layout, Popconfirm, Tag, Tooltip} from "antd"; -import accessGatewayApi from "../../api/access-gateway"; -import {ProTable} from "@ant-design/pro-components"; -import AccessGatewayModal from "./AccessGatewayModal"; -import ColumnState, {useColumnState} from "../../hook/column-state"; -import Show from "../../dd/fi/show"; - -const {Content} = Layout; - -const api = accessGatewayApi; - -const actionRef = React.createRef(); - -const AccessGateway = () => { - let [visible, setVisible] = useState(false); - let [confirmLoading, setConfirmLoading] = useState(false); - let [selectedRowKey, setSelectedRowKey] = useState(undefined); - - const [columnsStateMap, setColumnsStateMap] = useColumnState(ColumnState.ACCESS_GATEWAY); - - const columns = [ - { - dataIndex: 'index', - valueType: 'indexBorder', - width: 48, - }, - { - title: '名称', - dataIndex: 'name', - }, - { - title: 'IP', - dataIndex: 'ip', - key: 'ip', - sorter: true, - hideInSearch: true - }, { - title: '端口', - dataIndex: 'port', - key: 'port', - hideInSearch: true - }, { - title: '账户类型', - dataIndex: 'accountType', - key: 'accountType', - hideInSearch: true, - render: (accountType) => { - if (accountType === 'private-key') { - return ( - 密钥 - ); - } else { - return ( - 密码 - ); - } - } - }, { - title: '授权账户', - dataIndex: 'username', - key: 'username', - hideInSearch: true - }, { - title: '状态', - dataIndex: 'connected', - key: 'connected', - hideInSearch: true, - render: (text, record) => { - if (text) { - return ( - - - - ) - } else { - return ( - - - - ) - } - } - }, - { - title: '创建时间', - key: 'created', - dataIndex: 'created', - hideInSearch: true, - }, - { - title: '操作', - valueType: 'option', - key: 'option', - render: (text, record, _, action) => [ - - { - setVisible(true); - setSelectedRowKey(record['id']); - }} - > - 编辑 - - , - - { - await api.deleteById(record.id); - actionRef.current.reload(); - }} - okText="确认" - cancelText="取消" - > - 删除 - - , - ], - }, - ]; - - return ( - { - - let field = ''; - let order = ''; - if (Object.keys(sort).length > 0) { - field = Object.keys(sort)[0]; - order = Object.values(sort)[0]; - } - - let queryParams = { - pageIndex: params.current, - pageSize: params.pageSize, - name: params.name, - field: field, - order: order - } - let result = await api.getPaging(queryParams); - return { - data: result['items'], - success: true, - total: result['total'] - }; - }} - rowKey="id" - search={{ - labelWidth: 'auto', - }} - pagination={{ - defaultPageSize: 10, - }} - dateFormatter="string" - headerTitle="接入网关列表" - toolBarRender={() => [ - - - , - ]} - /> - - { - setVisible(false); - setSelectedRowKey(undefined); - }} - handleOk={async (values) => { - setConfirmLoading(true); - - try { - let success; - if (values['id']) { - success = await api.updateById(values['id'], values); - } else { - success = await api.create(values); - } - if (success) { - setVisible(false); - } - actionRef.current.reload(); - } finally { - setConfirmLoading(false); - } - }} - /> - - ); -} - -export default AccessGateway; diff --git a/web-backup/src/components/asset/AccessGatewayModal.js b/web-backup/src/components/asset/AccessGatewayModal.js deleted file mode 100644 index 172e64e24..000000000 --- a/web-backup/src/components/asset/AccessGatewayModal.js +++ /dev/null @@ -1,136 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import {Form, Input, InputNumber, Modal, Select} from "antd"; -import accessGatewayApi from "../../api/access-gateway"; - -const formItemLayout = { - labelCol: {span: 6}, - wrapperCol: {span: 14}, -}; - -const {TextArea} = Input; -const api = accessGatewayApi; - -const AccessGatewayModal = ({ - visible, - handleOk, - handleCancel, - confirmLoading, - id, - }) => { - - const [form] = Form.useForm(); - let [accountType, setAccountType] = useState('password'); - - const handleAccountTypeChange = v => { - setAccountType(v); - } - - useEffect(() => { - - const getItem = async () => { - let data = await api.getById(id); - if (data) { - form.setFieldsValue(data); - setAccountType(data['accountType']); - } - } - - if (visible) { - if(id){ - getItem(); - }else { - form.setFieldsValue({ - accountType: 'password', - port: 22, - }); - } - } else { - form.resetFields(); - } - }, [visible]); - - return ( - { - form - .validateFields() - .then(async values => { - let ok = await handleOk(values); - if (ok) { - form.resetFields(); - } - }); - }} - onCancel={() => { - form.resetFields(); - handleCancel(); - }} - confirmLoading={confirmLoading} - okText='确定' - cancelText='取消' - > - -
- - - - - - - - - - - - - - - - - - - - - { - accountType === 'password' ? - <> - - - - - - - - - - : - <> - - - - - -