Unverified Commit e12b10c4 authored by 老广's avatar 老广 Committed by GitHub

Merge pull request #46 from jumpserver/dev

支持sftp
parents 4b6f5c40 d3ceac9b
......@@ -49,5 +49,9 @@
"confirm": "确认",
"document": "文档",
"support": "商业支持",
"speed": "速度"
"speed": "速度",
"File Manager": "文件管理",
"File": "文件管理",
"New Connection": "连接",
"Connect": "连接"
}
cn.json
\ No newline at end of file
{
"reset": "重置",
"submit": "提交",
"email subject prefix": "邮件主题前缀",
"basic setting": "基本设置",
"email setting": "邮件设置",
"ldap setting": "LDAP设置",
"terminal setting": "终端设置",
"current site url": "当前站点URL",
"user guide url": "用户向导URL",
"user first login update profile done redirect to it": "用户第一次登录,修改profile后重定向到地址",
"server": "服务器",
"view": "视图",
"help": "帮助",
"hide left manager": "隐藏左边栏",
"show left manager": "显示左边栏",
"disconnect all": "断开所有链接",
"disconnect": "断开链接",
"website": "官网",
"search": "搜索",
"settings": "系统设置",
"job center": "作业中心",
"sessions": "会话管理",
"perms": "权限管理",
"assets": "资产管理",
"users": "用户管理",
"dashboard": "仪表盘",
"task": "任务",
"session online": "在线会话",
"session offline": "离线会话",
"commands": "命令记录",
"terminal": "终端管理",
"asset perminssion": "资产授权",
"asset": "资产",
"asset group": "资产组",
"cluster": "集群",
"admin user": "管理用户",
"system user": "系统用户",
"labels": "标签管理",
"user": "用户",
"user group": "用户组",
"login logs": "登陆日志",
"language": "语言选择",
"found": "发现",
"users ": "用户",
"choose a user": "选择一个用户",
"please choose a user": "请选择一个用户",
"cancel": "取消",
"confirm": "确认",
"document": "文档",
"support": "商业支持",
"speed": "速度",
"file manager": "文件管理",
"new connection": "连接",
"connect": "连接"
}
cn.json
\ No newline at end of file
{
"reset": "重置",
"submit": "提交",
"email subject prefix": "邮件主题前缀",
"basic setting": "基本设置",
"email setting": "邮件设置",
"ldap setting": "LDAP设置",
"terminal setting": "终端设置",
"current site url": "当前站点URL",
"user guide url": "用户向导URL",
"user first login update profile done redirect to it": "用户第一次登录,修改profile后重定向到地址",
"server": "服务器",
"view": "视图",
"help": "帮助",
"hide left manager": "隐藏左边栏",
"show left manager": "显示左边栏",
"disconnect all": "断开所有链接",
"disconnect": "断开链接",
"website": "官网",
"search": "搜索",
"settings": "系统设置",
"job center": "作业中心",
"sessions": "会话管理",
"perms": "权限管理",
"assets": "资产管理",
"users": "用户管理",
"dashboard": "仪表盘",
"task": "任务",
"session online": "在线会话",
"session offline": "离线会话",
"commands": "命令记录",
"terminal": "终端管理",
"asset perminssion": "资产授权",
"asset": "资产",
"asset group": "资产组",
"cluster": "集群",
"admin user": "管理用户",
"system user": "系统用户",
"labels": "标签管理",
"user": "用户",
"user group": "用户组",
"login logs": "登陆日志",
"language": "语言选择",
"found": "发现",
"users ": "用户",
"choose a user": "选择一个用户",
"please choose a user": "请选择一个用户",
"cancel": "取消",
"confirm": "确认",
"document": "文档",
"support": "商业支持",
"speed": "速度",
"File Manager": "文件管理",
"File": "文件管理",
"New Connection": "连接",
"Connect": "连接"
}
......@@ -18,7 +18,7 @@ import socket
import logging
import select
from coco.models import WSProxy, Client, Request, Connection
from coco.httpd import ProxyNamespace
from coco.httpd.ws import ProxyNamespace
logger = logging.getLogger(__file__)
logger.setLevel(logging.DEBUG)
......
This diff is collapsed.
{
"name": "luna",
"version": "1.3.2",
"version": "1.4.3",
"license": "GPLv3",
"scripts": {
"ng": "ng",
......@@ -25,6 +25,7 @@
"@angular/router": "5.2.0",
"@swimlane/ngx-datatable": "^11.3.2",
"@swimlane/ngx-ui": "^20.2.1",
"@types/jquery": "^3.3.6",
"@types/socket.io-client": "^1.4.32",
"ajv": "^6.5.0",
"animate.css": "^3.6.1",
......
......@@ -8,10 +8,19 @@
"secure": false
},
"/socket.io/": {
"target": "http://127.0.0.1:5001",
"target": "http://127.0.0.1:5000",
"secure": false,
"ws": true
},
"/coco/": {
"target": "http://127.0.0.1:5000",
"secure:": false,
"ws": true
},
"/static": {
"target": "http://127.0.0.1:5000",
"secure:": false
},
"/rdp/socket.io/": {
"target": "http://localhost:9250",
"pathRewrite": {
......
......@@ -31,6 +31,7 @@ import {DialogService, ElementDialogAlertComponent} from './elements/dialog/dial
import {PluginModules} from './plugins/plugins';
import {TestPageComponent} from './test-page/test-page.component';
import {AssetTreeDialogComponent} from './elements/asset-tree/asset-tree.component';
import {SftpComponent} from './elements/sftp/sftp.component';
@NgModule({
......@@ -48,6 +49,7 @@ import {AssetTreeDialogComponent} from './elements/asset-tree/asset-tree.compone
...Pipes,
...ElementComponents,
...PagesComponents,
SftpComponent,
],
entryComponents: [
AssetTreeDialogComponent,
......
<ul id="ztree" class="ztree"></ul>
<div #rMenu *ngIf="isShowRMenu" class="basicContext" [style.top]="pos.top" [style.left]="pos.left">
<table>
<tbody>
<tr class="basicContext__item ">
<td class="basicContext__data" data-num="0" (click)="connectTerminal()"> <span class="basicContext__icon fa fa-terminal new-connection"></span>{{ "New Connection"|trans }}</td>
</tr>
<tr class="basicContext__item basicContext__item--separator"></tr>
<tr class="basicContext__item ">
<td class="basicContext__data" data-num="2" (click)="connectFileManager()"><span class="basicContext__icon fa fa-file refresh"></span>{{ "File Manager"|trans }}</td>
</tr>
</tbody>
</table>
</div>
......@@ -5,3 +5,101 @@
}
.basicContext {
background: #000;
border: none;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
margin: 0;
box-shadow: 0 3px 6px 0px rgba(0,0,0,0.16);
position: absolute;
opacity: 1;
padding: 6px 0;
z-index: 1000;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.basicContext, .basicContext * {
box-sizing: border-box;
}
.basicContextContainer {
position: fixed;
width: 100%;
height: 100%;
z-index: 1000;
-webkit-tap-highlight-color: transparent;
}
.basicContext tr {
margin: 0;
}
.fa {
width: 24px;
height: 24px;
line-height: 24px;
background-size: 18px;
background-position: 3px 3px;
margin-left: -30px;
position: absolute;
margin-right: 10px;
text-align: center;
display: inline-block;
}
.basicContext__item {
cursor: pointer;
padding: 0 6px;
}
.basicContext td {
display: block;
padding: 0 35px;
text-decoration: none;
width: auto;
opacity: 1;
white-space: nowrap;
line-height: 24px;
text-shadow: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
cursor: pointer;
}
.basicContext__item.basicContext__item--separator {
background: #181414;
border: 0;
border-top: none;
height: 1px;
min-height: 1px;
max-height: 1px;
padding: 0;
border-left: none;
text-shadow: 0 0 0 transparent;
box-shadow: 0;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
margin: 2px 0;
}
tr {
display: table-row;
vertical-align: inherit;
border-color: inherit;
}
tr:hover {
background-color: #463e3e;
}
.basicContext table {
border-spacing: 0 !important;
}
.basicContext__data {
padding: 0 6px;
}
import {Component, Input, OnInit, Inject, SimpleChanges, OnChanges, EventEmitter} from '@angular/core';
import {Component, Input, OnInit, Inject, SimpleChanges, OnChanges, ElementRef, ViewChild} from '@angular/core';
import {NavList, View} from '../../pages/control/control/control.component';
import {AppService, LogService} from '../../app.service';
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material';
......@@ -16,6 +16,7 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
@Input() Data: any;
@Input() query: string;
@Input() searchEvt$: BehaviorSubject<string>;
@ViewChild('rMenu') rMenu: ElementRef;
nodes = [];
setting = {
view: {
......@@ -31,11 +32,16 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
}
},
callback: {
onClick: this.onCzTreeOnClick.bind(this)
onClick: this.onCzTreeOnClick.bind(this),
onRightClick: this.onRightClick.bind(this)
},
};
pos = {left: '100px', top: '200px'};
hiddenNodes: any;
expandNodes: any;
zTree: any;
isShowRMenu = false;
rightClickSelectNode: any;
onCzTreeOnClick(event, treeId, treeNode, clickFlag) {
if (treeNode.isParent) {
......@@ -56,6 +62,7 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
if (this.Data) {
this.draw();
}
document.addEventListener('click', this.hideRMenu.bind(this), false);
this.searchEvt$.asObservable()
.debounceTime(300)
.distinctUntilChanged()
......@@ -122,9 +129,33 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
}
});
$.fn.zTree.init($('#ztree'), this.setting, this.nodes);
const zTree = $.fn.zTree.getZTreeObj('ztree');
const root = zTree.getNodes()[0];
zTree.expandNode(root, true);
this.zTree = $.fn.zTree.getZTreeObj('ztree');
const root = this.zTree.getNodes()[0];
this.zTree.expandNode(root, true);
}
showRMenu(left, top) {
this.pos.left = left + 'px';
this.pos.top = top + 'px';
this.isShowRMenu = true;
}
hideRMenu() {
this.isShowRMenu = false;
}
onRightClick(event, treeId, treeNode) {
if (!treeNode || treeNode.isParent || treeNode.platform.toLowerCase() === 'windows') {
return null;
}
if (!treeNode && event.target.tagName.toLowerCase() !== 'button' && $(event.target).parents('a').length === 0) {
this.zTree.cancelSelectedNode();
this.showRMenu(event.clientX, event.clientY);
} else if (treeNode && !treeNode.noR) {
this.zTree.selectNode(treeNode);
this.showRMenu(event.clientX, event.clientY);
this.rightClickSelectNode = treeNode;
}
}
Connect(host) {
......@@ -160,6 +191,27 @@ export class ElementAssetTreeComponent implements OnInit, OnChanges {
}
}
connectFileManager() {
const host = this.rightClickSelectNode;
const id = NavList.List.length - 1;
if (host) {
NavList.List[id].nick = '[FILE]' + host.name;
NavList.List[id].connected = true;
NavList.List[id].edit = false;
NavList.List[id].closed = false;
NavList.List[id].host = host;
NavList.List[id].type = 'sftp';
NavList.List.push(new View());
NavList.Active = id;
}
this._logger.debug(NavList);
}
connectTerminal() {
const host = this.rightClickSelectNode;
this.Connect(host);
}
login(host, user) {
const id = NavList.List.length - 1;
this._logger.debug(NavList);
......
......@@ -4,7 +4,7 @@
<li><a href="/"><img src="static/imgs/logo.png" height="26px"/></a>
</li>
<li *ngFor="let v of DataStore.Nav" [ngClass]="{'dropdown': v.children}">
<a>{{v.name | trans}}</a>
<a>{{v.name|trans}}</a>
<ul [ngClass]="{'dropdown-content': v.children}">
<li *ngFor="let vv of v.children" [ngClass]="{'disabled': vv.disable}">
<a *ngIf="vv.href" [routerLink]="[vv.href]">{{vv.name|trans}}</a>
......
......@@ -47,7 +47,10 @@ export class ElementNavComponent implements OnInit {
CleftbarComponent.Reload();
break;
}
case 'ConnectSFTP': {
window.open('/coco/elfinder/sftp/');
break;
}
case 'HideLeft': {
CleftbarComponent.Hide();
break;
......@@ -182,18 +185,6 @@ export class ElementNavComponent implements OnInit {
'id': 'File',
'name': 'Server',
'children': [
// {
// 'id': 'NewConnection',
// 'href': '',
// 'name': 'New connection',
// 'disable': true
// },
// {
// 'id': 'Connect',
// 'click': 'Connect',
// 'name': 'Connect',
// 'disable': true
// },
{
'id': 'Disconnect',
'click': 'Disconnect',
......@@ -235,6 +226,17 @@ export class ElementNavComponent implements OnInit {
// }
]
}, {
'id': 'FileManager',
'name': 'File Manager',
'children': [
{
'id': 'Connect',
'click': 'ConnectSFTP',
'name': 'Connect'
},
]
},
{
'id': 'View',
'name': 'View',
'children': [
......@@ -266,11 +268,6 @@ export class ElementNavComponent implements OnInit {
'id': 'Help',
'name': 'Help',
'children': [
// {
// 'id': 'EnterLicense',
// 'click': 'EnterLicense',
// 'name': 'Enter License'
// },
{
'id': 'Website',
'click': 'Website',
......@@ -316,9 +313,7 @@ export class ElementNavComponent implements OnInit {
moveType: 1
}, function (value, index) {
DataStore.socket.emit('key', value);
// layer.msg(value); //得到value
layer.close(index);
});
}
......
<!--<iframe src="/elfinder/sftp/host123/" width="100%" height="100%" ></iframe>-->
<iframe #sftp [src]="target" width="100%" height="100%" ></iframe>
iframe {
border: none;
background-color: white;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SftpComponent } from './sftp.component';
describe('SftpComponent', () => {
let component: SftpComponent;
let fixture: ComponentFixture<SftpComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SftpComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SftpComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, OnInit, Input, ElementRef, ViewChild} from '@angular/core';
import {DataStore} from '../../globals';
import {DomSanitizer} from '@angular/platform-browser';
@Component({
selector: 'app-sftp',
templateUrl: './sftp.component.html',
styleUrls: ['./sftp.component.scss']
})
export class SftpComponent implements OnInit {
@Input() host: any;
target: any;
@ViewChild('sftp') el: ElementRef;
constructor(private sanitizer: DomSanitizer) {
if (!this.host) {
DataStore.NavShow = false;
}
}
ngOnInit() {
let _target = '/coco/elfinder/sftp/';
if (this.host) {
// _target += 'f5857eee-c114-4564-af8f-96329c400a8a' + '/';
_target += this.host.id + '/';
}
this.trust(_target);
}
trust(url) {
this.target = this.sanitizer.bypassSecurityTrustResourceUrl(url);
}
}
......@@ -15,6 +15,8 @@
[userid]="m.user.id"
*ngIf="m.type=='rdp'">
</elements-guacamole>
<app-sftp *ngIf="m.type=='sftp'" [host]="m.host">
</app-sftp>
<!--<elements-settings [index]="i"-->
<!--*ngIf="m.type=='settings'">-->
<!--</elements-settings>-->
......
......@@ -52,7 +52,6 @@ export class ControlComponent implements OnInit {
NavList.List.forEach((v, k) => {
v.hide = id.toString() !== k;
});
NavList.Active = id;
}
......
......@@ -15,6 +15,7 @@ import {PagesReplayComponent} from '../pages/replay/replay.component';
import {PagesControlComponent} from '../pages/control/control.component';
import {PagesNotFoundComponent} from '../pages/not-found/not-found.component';
import {PagesMonitorComponent} from '../pages/monitor/monitor.component';
import {SftpComponent} from '../elements/sftp/sftp.component';
const appRoutes: Routes = [
......@@ -22,6 +23,7 @@ const appRoutes: Routes = [
{path: 'monitor/:token', component: PagesMonitorComponent},
{path: 'test', component: TestPageComponent},
{path: 'connect', component: PagesConnectComponent},
{path: 'sftp', component: SftpComponent},
{path: 'undefined', component: PagesBlankComponent},
{path: '', component: PagesControlComponent},
{path: '**', component: PagesNotFoundComponent}
......
......@@ -2,5 +2,5 @@ export const environment = {
production: true
};
// export const version = '1.3.0-{{BUILD_NUMBER}} GPLv2.';
// export const version = '1.3.3-101 GPLv2.';
export const version = '1.4.1-{{BUILD_NUMBER}} GPLv2.';
export const version = '1.4.3-101 GPLv2.';
// export const version = '1.4.1-{{BUILD_NUMBER}} GPLv2.';
......@@ -103,3 +103,17 @@ body ::-webkit-scrollbar-thumb {
/*background-color: #3a3333;*/
/*color: white*/
/*}*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
background: #F9F9F9;
border: none !important;
line-height: 15px;
font-weight: bold;
color: #676a6c;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
}
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active {
color: white;
font-weight: bolder;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment