Browse Source

init

master
lusiyi 1 year ago
commit
0cd194da34
48 changed files with 9672 additions and 0 deletions
  1. +34
    -0
      .drone.yml
  2. +11
    -0
      .gitignore
  3. +335
    -0
      01.ipynb
  4. +5
    -0
      Hello.java
  5. +5
    -0
      README.md
  6. +11
    -0
      person.tsx
  7. +257
    -0
      pom.xml
  8. +48
    -0
      src/main/go-mod/excel.go
  9. +24
    -0
      src/main/go-mod/func.go
  10. +6
    -0
      src/main/go-mod/main.go
  11. +7
    -0
      src/main/go-mod/struct.go
  12. +25
    -0
      src/main/java/com/educoder/bridge/controller/BaseController.java
  13. +49
    -0
      src/main/java/com/educoder/bridge/controller/MainController.java
  14. +38
    -0
      src/main/java/com/educoder/bridge/handler/WebsshHandler.java
  15. +41
    -0
      src/main/java/com/educoder/bridge/model/SSHInfo.java
  16. +45
    -0
      src/main/java/com/educoder/bridge/model/SSHSession.java
  17. +261
    -0
      src/main/java/com/educoder/bridge/service/JchService.java
  18. +52
    -0
      src/main/java/com/educoder/bridge/utils/Base64Util.java
  19. +42
    -0
      src/main/resources/applicationContext.xml
  20. +47
    -0
      src/main/resources/logback.xml
  21. +34
    -0
      src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml
  22. +61
    -0
      src/main/webapp/WEB-INF/pages/index.ftl
  23. +63
    -0
      src/main/webapp/WEB-INF/web.xml
  24. +2
    -0
      src/main/webapp/index.html
  25. +53
    -0
      src/main/webapp/static/css/main.css
  26. +11
    -0
      src/main/webapp/static/css/pure-min.css
  27. +44
    -0
      src/main/webapp/static/css/reset.css
  28. +187
    -0
      src/main/webapp/static/css/style.css
  29. +34
    -0
      src/main/webapp/static/css/supersized.css
  30. +25
    -0
      src/main/webapp/static/css/tooltip.css
  31. +2273
    -0
      src/main/webapp/static/css/xterm.css
  32. BIN
      src/main/webapp/static/image/backgrounds/1.jpg
  33. BIN
      src/main/webapp/static/image/backgrounds/2.jpg
  34. BIN
      src/main/webapp/static/image/backgrounds/3.jpg
  35. BIN
      src/main/webapp/static/image/facebook.png
  36. BIN
      src/main/webapp/static/image/favicon.ico
  37. BIN
      src/main/webapp/static/image/progress.gif
  38. BIN
      src/main/webapp/static/image/twitter.png
  39. +103
    -0
      src/main/webapp/static/js/base64.js
  40. +234
    -0
      src/main/webapp/static/js/formvalid.js
  41. +5
    -0
      src/main/webapp/static/js/jquerymin.js
  42. +124
    -0
      src/main/webapp/static/js/main.js
  43. +30
    -0
      src/main/webapp/static/js/supersized-init.js
  44. +13
    -0
      src/main/webapp/static/js/supersized.3.2.7.min.js
  45. +67
    -0
      src/main/webapp/static/js/ws.js
  46. +4959
    -0
      src/main/webapp/static/js/xterm.js
  47. +1
    -0
      test.txt
  48. +6
    -0
      test3.py

+ 34
- 0
.drone.yml View File

@@ -0,0 +1,34 @@
kind: pipeline
type: docker
name: 1
platform:
os: linuxs
arch: amd64
steps:
- name: maven
image: maven:3-jdk-10
volumes:
- name: cache
path: /root/.m2
commands:
- mvn install -DskipTests=true

- name: run
image: maven:3-jdk-8
volumes:
- name: cache
path: /root/.m2
commands:
- nohup mvn tomcat7:run &

volumes:
- name: cache
host:
path: /var/lib/cache

trigger:
branch:
- master
event:
- push
- pull_request

+ 11
- 0
.gitignore View File

@@ -0,0 +1,11 @@
.DS_Store
.idea/
*.iml
target/
2017*
.project
.classpath
.settings/
*.log
bin/
6666

+ 335
- 0
01.ipynb
File diff suppressed because it is too large
View File


+ 5
- 0
Hello.java View File

@@ -0,0 +1,5 @@
public class {
public static void main(String[] args) {
System.out.println
}
}

+ 5
- 0
README.md View File

@@ -0,0 +1,5 @@
ReadMe 使用 markdown 语法,所以我们需要掌握基础的语法。

markdown 的语法主要包括 标题、段落、链接、引用、代码,语法不复杂,初学者只要多写几次就能记住。

下面是 GitHub 上两个关于 markdown 的项目,它们总结了我们需要的基础语法。

+ 11
- 0
person.tsx View File

@@ -0,0 +1,11 @@
interface IPerson {
name: string;
age: number;
}
function test(opt: IPerson) {
let key: (keyof IPerson);
for (key in opt) {
console.log(opt[key]);
}
}

+ 257
- 0
pom.xml View File

@@ -0,0 +1,257 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.educoder</groupId>
<artifactId>webssh</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>webssh Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<swagger2.version>2.6.1</swagger2.version>
<spring.version>4.3.6.RELEASE</spring.version>
<freemarker.version>2.3.25-incubating</freemarker.version>
<jsch.version>0.1.54</jsch.version>
<javax.version>7.0</javax.version>
<commons-lang.version>2.6</commons-lang.version>
<commons-io.version>2.4</commons-io.version>
<slf4j.version>1.7.21</slf4j.version>
<fastjson.version>1.2.20</fastjson.version>
<jackson.version>2.8.6</jackson.version>
<codec.version>1.10</codec.version>

<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>

<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>${jsch.version}</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger2.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>${javax.version}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.6.RELEASE</version>
</dependency>

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>

<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.4</version>
</dependency>

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${codec.version}</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<address>0.0.0.0</address>
<port>61020</port>
<path>/</path>
<uriEncoding>UTF-8</uriEncoding>
<finalName>webssh</finalName>
<server>tomcat7</server>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>testCompile</id>
<phase>test-compile</phase>
<goals>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>

<finalName>webssh</finalName>
</build>
</project>

+ 48
- 0
src/main/go-mod/excel.go View File

@@ -0,0 +1,48 @@
package excel

import (
"fmt"
"reflect"

"github.com/360EntSecGroup-Skylar/excelize"
)

// WriteXlsx 生成表格到本地服务器
func WriteXlsx(sheet string, records interface{}) *excelize.File {
f := excelize.NewFile() // new file
index := f.NewSheet(sheet) // new sheet
f.SetActiveSheet(index) // set active (default) sheet
firstCharacter := 65 // start from 'A' line
t := reflect.TypeOf(records)

if t.Kind() != reflect.Slice {
return f
}

s := reflect.ValueOf(records)
for i := 0; i < s.Len(); i++ {
elem := s.Index(i).Interface()
elemType := reflect.TypeOf(elem)
elemValue := reflect.ValueOf(elem)
for j := 0; j < elemType.NumField(); j++ {
field := elemType.Field(j)
// 结构体中xlsx 类似json
tag := field.Tag.Get("xlsx")
name := tag
column := string(firstCharacter + j)
if tag == "" {
continue
}
// 设置表头
if i == 0 {
f.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+1), name)
}
// 设置列宽
f.SetColWidth(sheet, "A", fmt.Sprintf("%s", column), 20)

// 设置内容
f.SetCellValue(sheet, fmt.Sprintf("%s%d", column, i+2), elemValue.Field(j).Interface())
}
}
return f
}

+ 24
- 0
src/main/go-mod/func.go View File

@@ -0,0 +1,24 @@
package main

import "fmt"

type Publisher struct {
name string
address string
}
type Book struct {
title, name string
publisher Publisher
}

func main() {
var book = Book{"title","name",Publisher{"pub","beijing"}}
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!")
fmt.Println(book)

}

func test (book Book) (b1 Book, b2 Book){
return book,book
}

+ 6
- 0
src/main/go-mod/main.go View File

@@ -0,0 +1,6 @@
package main

func main(){
printf('hello wold')
io.out('ok')
}

+ 7
- 0
src/main/go-mod/struct.go View File

@@ -0,0 +1,7 @@
package test
type Books struct {
title string
author string
subject string
book_id int
}

+ 25
- 0
src/main/java/com/educoder/bridge/controller/BaseController.java View File

@@ -0,0 +1,25 @@
package com.educoder.bridge.controller;

import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


/**
* @author lqk
* @version 0.1
*/
public class BaseController {
protected HttpServletRequest request;
protected HttpServletResponse response;
protected HttpSession session;

@ModelAttribute
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
this.session = request.getSession();
}
}

+ 49
- 0
src/main/java/com/educoder/bridge/controller/MainController.java View File

@@ -0,0 +1,49 @@
package com.educoder.bridge.controller;

import io.swagger.annotations.Api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

/**
* @author guange
*
* @date 2017/08/02
*/

@Api(value = "提供webssh连接", hidden = true)
@RestController
public class MainController extends BaseController {
private final static Logger logger = LoggerFactory.getLogger(MainController.class);
//
// @RequestMapping(value={"/"}, method= RequestMethod.GET)
// public ModelAndView index(@RequestParam("host")String host,
// @RequestParam("port")int port,
// @RequestParam("username")String username,
// @RequestParam("password")String password,
// @RequestParam("rows")int rows) {
// logger.debug("/ssh: 接收到连接请求, host: {}, port: {}", host, port);
// ModelAndView mv = new ModelAndView();
// mv.setViewName("index");
// mv.addObject("host", host);
// mv.addObject("port", port);
// mv.addObject("username", username);
// mv.addObject("password", password);
// mv.addObject("rows", rows);
// mv.addObject("digest", System.currentTimeMillis());
// return mv;
// }

@RequestMapping(value={"/"}, method= RequestMethod.GET)
public ModelAndView index() {
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
mv.addObject("digest", System.currentTimeMillis());
return mv;
}

}

+ 38
- 0
src/main/java/com/educoder/bridge/handler/WebsshHandler.java View File

@@ -0,0 +1,38 @@
package com.educoder.bridge.handler;

import com.educoder.bridge.service.JchService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class WebsshHandler extends TextWebSocketHandler {

@Autowired
JchService jchService;

@Override
public void afterConnectionEstablished(WebSocketSession wsSession) throws Exception {
super.afterConnectionEstablished(wsSession);
jchService.add(wsSession);
}

/**
* 重写handleTextMessage方法,用于处理从websocket接收到的信息
*/
@Override
protected void handleTextMessage(WebSocketSession wsSession, TextMessage message) throws Exception {
jchService.recv(message.getPayload(), wsSession);
super.handleTextMessage(wsSession, message);
}


@Override
public void afterConnectionClosed(WebSocketSession wsSession, CloseStatus status) throws Exception {
super.afterConnectionClosed(wsSession, status);
jchService.closeByWebSocket(wsSession);
}
}

+ 41
- 0
src/main/java/com/educoder/bridge/model/SSHInfo.java View File

@@ -0,0 +1,41 @@
package com.educoder.bridge.model;

public class SSHInfo {
private String host;
private String port;
private String username;
private String password;

public void setHost(String host) {
this.host = host;
}

public void setPort(String port) {
this.port = port;
}

public void setUsername(String username) {
this.username = username;
}

public void setPassword(String password) {
this.password = password;
}

public String getHost() {
return host;
}

public int getPort() {
return Integer.parseInt(port);
}

public String getUsername() {
return username;
}

public String getPassword() {
return password;
}

}

+ 45
- 0
src/main/java/com/educoder/bridge/model/SSHSession.java View File

@@ -0,0 +1,45 @@
package com.educoder.bridge.model;

import com.jcraft.jsch.ChannelShell;
import org.springframework.web.socket.WebSocketSession;

import java.io.OutputStream;

public class SSHSession {
private WebSocketSession webSocketSession;
private OutputStream outputStream;
private ChannelShell channel;
private SSHInfo SSHInfo;

public SSHInfo getSSHInfo() {
return SSHInfo;
}

public void setSSHInfo(SSHInfo SSHInfo) {
this.SSHInfo = SSHInfo;
}

public ChannelShell getChannel() {
return channel;
}

public void setChannel(ChannelShell channel) {
this.channel = channel;
}

public WebSocketSession getWebSocketSession() {
return webSocketSession;
}

public void setWebSocketSession(WebSocketSession webSocketSession) {
this.webSocketSession = webSocketSession;
}

public OutputStream getOutputStream() {
return outputStream;
}

public void setOutputStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
}

+ 261
- 0
src/main/java/com/educoder/bridge/service/JchService.java View File

@@ -0,0 +1,261 @@
package com.educoder.bridge.service;

import com.alibaba.fastjson.JSONObject;
import com.educoder.bridge.model.SSHInfo;
import com.educoder.bridge.model.SSHSession;
import com.educoder.bridge.utils.Base64Util;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Service
public class JchService {

private static List<SSHSession> sshSessionQueue = new CopyOnWriteArrayList<>();
private ExecutorService executorService = Executors.newCachedThreadPool();
private Logger logger = LoggerFactory.getLogger(getClass());

com.jcraft.jsch.Logger jschLogger = new com.jcraft.jsch.Logger() {

@Override
public boolean isEnabled(int arg0) {
return true;
}

@Override
public void log(int arg0, String arg1) {
if (logger.isTraceEnabled()) {
logger.trace("JSch Log [Level " + arg0 + "]: " + arg1);
}
}
};


/**
* 在webSocket连接时,初始化一个ssh连接
*
* @param webSocketSession webSocket连接
*/
public void add(WebSocketSession webSocketSession) {

SSHSession sshSession = new SSHSession();
sshSession.setWebSocketSession(webSocketSession);

sshSessionQueue.add(sshSession);
}

/**
* 处理客户端发过来的数据
* @param buffer 数据
* @param webSocketSession webSocket连接
*/
public void recv(String buffer, WebSocketSession webSocketSession) {

SSHSession sshSession = null;
try {
logger.debug("webSocketSessionID: {}, 信息: {}", webSocketSession.getId(), buffer);
JSONObject info = JSONObject.parseObject(buffer);
String tp = info.getString("tp");
sshSession = findByWebSocketSession(webSocketSession);

//初始化连接
if ("init".equals(tp)) {
// {"tp":"init","data":{"host":"127.0.0.1","port":"41080","username":"root","password":"123123"}}
SSHInfo sshInfo = info.getObject("data", SSHInfo.class);
sshSession.setSSHInfo(sshInfo);

if (sshSession != null) {
SSHSession finalSSHSession = sshSession;

// 新开一个线程建立连接,连接开启之后以一直监听来自客户端的输入
executorService.execute(() -> {
connectTossh(finalSSHSession);
});
}
} else if ("client".equals(tp)) {
String data = info.getString("data");

// 将网页输入的数据传送给后端服务器
if (sshSession != null) {
transTossh(sshSession.getOutputStream(), data);
}
}
} catch (Exception e) {
logger.error("转发命令到ssh出错: {}", e);

close(sshSession);
}

}

/**
* 将数据传送给服务端作为SSH的输入
*
* @param outputStream
* @param data
* @throws IOException
*/
private void transTossh(OutputStream outputStream, String data) throws IOException {
if (outputStream != null) {
outputStream.write(data.getBytes());
outputStream.flush();
}
}

/**
* 连接ssh
*
* @param sshSession ssh连接需要的信息
*/
private void connectTossh(SSHSession sshSession){
Session jschSession = null;
SSHInfo SSHInfo = sshSession.getSSHInfo();
try {
JSch jsch = new JSch();
JSch.setLogger(jschLogger);

//启动线程
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
jschSession = jsch.getSession(SSHInfo.getUsername(), SSHInfo.getHost(), SSHInfo.getPort());

jschSession.setConfig(config);
jschSession.setPassword(SSHInfo.getPassword());
jschSession.setUserInfo(new UserInfo() {
@Override
public String getPassphrase() {
return null;
}

@Override
public String getPassword() {
return null;
}

@Override
public boolean promptPassword(String s) {
return false;
}

@Override
public boolean promptPassphrase(String s) {
return false;
}

@Override
public boolean promptYesNo(String s) {
return true;
} // Accept all server keys

@Override
public void showMessage(String s) {
}
});

jschSession.connect();
ChannelShell channel = (ChannelShell) jschSession.openChannel("shell");
channel.setPtyType("xterm");

channel.connect();

sshSession.setChannel(channel);
InputStream inputStream = channel.getInputStream();
sshSession.setOutputStream(channel.getOutputStream());

sshSession.setSSHInfo(SSHInfo);
logger.debug("主机: {} 连接成功!", SSHInfo.getHost());

// 循环读取,jsch的输入为服务器执行命令之后的返回数据
byte[] buf = new byte[1024];
while (true) {
int length = inputStream.read(buf);
if (length < 0) {
close(sshSession);
throw new Exception("读取出错,数据长度:" + length);
}
sendMsg(sshSession.getWebSocketSession(), Arrays.copyOfRange(buf, 0, length));
}

} catch (Exception e) {
logger.error("ssh连接出错, e: {}", e);
} finally {
logger.info("连接关闭, {}", SSHInfo.getHost());
if (jschSession != null) {
jschSession.disconnect();
}

close(sshSession);
}
}


/**
* 发送数据回websocket
*
* @param webSocketSession webSocket连接
* @param buffer 数据
* @throws IOException
*/
public void sendMsg(WebSocketSession webSocketSession, byte[] buffer) throws IOException {
logger.debug("服务端返回的数据: {}", new String(buffer, "UTF-8"));

webSocketSession.sendMessage(new TextMessage(Base64Util.encodeBytes(buffer)));
}

/**
* 通过webSocket连接在队列中找到对应的SSH连接
*
* @param webSocketSession webSocket连接
*/
public SSHSession findByWebSocketSession(WebSocketSession webSocketSession) {
Optional<SSHSession> optional = sshSessionQueue.stream().filter(webscoketObj -> webscoketObj.getWebSocketSession() == webSocketSession).findFirst();
if (optional.isPresent()) {
return optional.get();
}
return null;
}

/**
* 关闭ssh和websocket连接
*
* @param sshSession ssh连接
*/
private void close(SSHSession sshSession) {
if (sshSession != null) {
sshSession.getChannel().disconnect();
try {
sshSession.getWebSocketSession().close();
sshSession.getOutputStream().close();
} catch (IOException e) {
logger.error("连接关闭失败!e: {}", e);
}

sshSessionQueue.remove(sshSession);
}
}

/**
* 通过webSocketSession关闭ssh与webSocket连接
*
* @param webSocketSession
*/
public void closeByWebSocket(WebSocketSession webSocketSession) {
close(findByWebSocketSession(webSocketSession));
}
}

+ 52
- 0
src/main/java/com/educoder/bridge/utils/Base64Util.java View File

@@ -0,0 +1,52 @@
package com.educoder.bridge.utils;


import org.apache.commons.codec.binary.Base64;

import java.nio.charset.StandardCharsets;

/**
* Created by guange on 23/02/2017.
*/
public class Base64Util {

/**
* base64编码
*
* @param code
* @return
*/
public static String encode(String code) {
byte[] encode = Base64.encodeBase64URLSafe(code.getBytes(StandardCharsets.UTF_8));
return new String(encode, StandardCharsets.UTF_8);
}

public static byte[] encodeBytes(byte[] codes) {
return Base64.encodeBase64(codes);
}


/**
* base64解码
*
* @param code
* @return
*/
public static String decode(String code) {
byte[] decode = Base64.decodeBase64(code);
return new String(decode, StandardCharsets.UTF_8);
}

/**
* base64再解码,把原本的非URL safe编码转换为URL safe编码
*
* @param code
* @return
*/
public static String reencode(String code) {
String str = decode(code);
str = str.replace("\n", "\r\n");
return encode(str);
}

}

+ 42
- 0
src/main/resources/applicationContext.xml View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd">

<aop:aspectj-autoproxy/>
<context:component-scan base-package="com.educoder.bridge.controller"/>
<context:component-scan base-package="com.educoder.bridge.service"/>
<context:component-scan base-package="com.educoder.bridge.handler"/>

<!-- freemaker配置 -->
<bean id="freemarkerConfig"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/pages/" />
<property name="freemarkerSettings">
<props>
<prop key="template_update_delay">0</prop>
<prop key="default_encoding">UTF-8</prop>
<prop key="number_format">0.##########</prop>
<prop key="datetime_format">yyyy-MM-dd HH:mm:ss</prop>
<prop key="classic_compatible">true</prop>
<prop key="template_exception_handler">ignore</prop>
</props>
</property>
</bean>

<!--注册消息处理器,指定WebsshHandler处理消息,并将/ws映射到其中-->
<websocket:handlers allowed-origins="*">
<websocket:mapping path="/ws" handler="websshHandler"/>
</websocket:handlers>

<bean id="websshHandler" class="com.educoder.bridge.handler.WebsshHandler"/>

</beans>

+ 47
- 0
src/main/resources/logback.xml View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="log_path" value="/home/ww/test/tomcat-test/logs/"/>

<!-- 打印在标准控制台 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d:时间,%thread:线程名,%-5level:级别从左显示5个字符宽度,
%logger{50}:输出日志的类, 50代表包名加类名的总长度限制, %M 方法名 %L 行号 %msg:日志消息,%n是换行符-->
<pattern>%d{MM-dd HH:mm:ss} [%thread] %-5level %logger{30} %M %L - %msg%n</pattern>
</encoder>

<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
</appender>

<!-- 错误信息 -->
<appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Encoding>UTF-8</Encoding>
<encoder>
<pattern>%d{MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{30} %M - %msg%n%L</pattern>
</encoder>
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log_path}error.%d{MM-dd}.log</fileNamePattern>
</rollingPolicy>
</appender>

<!-- 屏蔽框架输出 -->
<logger name="org.slf4j" level="ERROR"/>
<logger name="org.springframework" level="ERROR"/>
<logger name="io.swagger" level="ERROR"/>
<logger name="ch.qos.logback" level="OFF"/>
<logger name="springfox.documentation" level="ERROR"/>

<!-- 所有的日志同时应用“STDOUT”和“EROOR”的策略 -->
<root>
<level value="DEBUG"/>
<!--<appender-ref ref="TPM"/>-->
<appender-ref ref="ERROR"/>
<appender-ref ref="STDOUT"/>
</root>

</configuration>

+ 34
- 0
src/main/webapp/WEB-INF/mvc-dispatcher-servlet.xml View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">


<!--指明 controller 所在包,并扫描其中的注解-->
<context:component-scan base-package="com.educoder.bridge.controller"/>

<!-- 静态资源(js、image等)的访问 -->
<mvc:default-servlet-handler/>

<!--ViewResolver 视图解析器-->
<!--用于支持freemarker视图解析-->
<!--视图解释器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="suffix">
<value>.ftl</value>
</property>
<property name="contentType" value="text/html;charset=UTF-8"></property>
</bean>


<!-- 开启注解 -->
<mvc:annotation-driven/>

<bean class="springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration" id="swagger2Config"/>
<mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
<mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>

</beans>

+ 61
- 0
src/main/webapp/WEB-INF/pages/index.ftl View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<title>JWebssh</title>
<link rel='shortcut icon' type='image/x-icon' href='/static/image/favicon.ico'/>
<link rel="stylesheet" href="/static/css/pure-min.css">
<link href="/static/css/xterm.css" rel="stylesheet" type="text/css"/>
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=PT+Sans:400,700'>
<link rel="stylesheet" href="/static/css/reset.css">
<link rel="stylesheet" href="/static/css/supersized.css">
<link rel="stylesheet" href="/static/css/style.css">

<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>

<body>

<div class="page-container" id="form" name="form" >
<h1>JWebssh</h1>
<form action="" method="post">
<fieldset>
<input id="terminalRow" name="terminalRow" type="hidden" value=100>
<div class="pure-item">
<input id="host" name="host" type="text" placeholder="Host" value=${host}>
</div>
<div class="pure-item">
<input id="port" name="port" type="text" placeholder="Port" value=${port}>
</div>
<div class="pure-item">
<input id="username" name="username" type="text" placeholder="Username" value=${username}>
</div>
<div class="pure-item">
<input id="password" name="password" type="password" placeholder="Password" value=${password}>
</div>
<button type="button" onclick="connect()">Connect</button>
</fieldset>
</form>
</div>

<div id="term" align="center"></div>

<!-- Javascript -->
<script src="/static/js/jquerymin.js"></script>
<script src="/static/js/supersized.3.2.7.min.js"></script>
<script src="/static/js/supersized-init.js"></script>
<script src="/static/js/base64.js"></script>
<script src="/static/js/jquerymin.js"></script>
<script src="/static/js/xterm.js"></script>
<script src="/static/js/ws.js"></script>
<script src="/static/js/formvalid.js"></script>
<script src="/static/js/main.js?${digest}"></script>

</body>

</html>

+ 63
- 0
src/main/webapp/WEB-INF/web.xml View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

<display-name>educoder bridge</display-name>

<!-- Spring 上下文参数 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>

<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>

<!-- logback -->
<context-param>
<param-name>logbackConfigLocation</param-name>
<param-value>classpath:logback.xml</param-value>
</context-param>

<listener>
<listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class>
</listener>

<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
<welcome-file></welcome-file>
</welcome-file-list>

</web-app>

+ 2
- 0
src/main/webapp/index.html View File

@@ -0,0 +1,2 @@
<!--保留以防后续看swagger UI界面需要-->
<!--<meta http-equiv="refresh" content="0; url=/swagger-ui.html" />-->

+ 53
- 0
src/main/webapp/static/css/main.css View File

@@ -0,0 +1,53 @@
.aside {
text-align: center;
background: #1f8dd6;
height: 100px;
color: #fff;
vertical-align: middle;
line-height: 100px;
font-size: 30px
}

#main {
margin-top: 20px;
}

#ratio-group {
float: right;
}

.pure-item {
margin: 0 auto 10px;
width: 300px;
position: relative;
}

.pure-radio {
margin-left: 10px;
}

.pure-item:after {
content: "";
display: table;
clear: both;
}

.pure-item label {
float: left;
line-height: 34px;
}

.pure-item input {
float: right;
}

.terminal {
float: none;
border: #000 solid 5px;
font-family: "Monaco", "DejaVu Sans Mono", "Liberation Mono", monospace;
font-size: 11px;
color: #f0f0f0;
width: 600px;
background: #000;
box-shadow: rgba(0, 0, 0, 0.8) 2px 2px 20px;
}

+ 11
- 0
src/main/webapp/static/css/pure-min.css
File diff suppressed because it is too large
View File


+ 44
- 0
src/main/webapp/static/css/reset.css View File

@@ -0,0 +1,44 @@

/* ------- This is the CSS Reset ------- */

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, a,
abbr, acronym, address, big, cite, code, del,
dfn, em, img, ins, kbd, q, s, samp, small,
strike, strong, sub, sup, tt, var, u, i, center,
dl, dt, dd, ol, ul, li, fieldset, form, label,
legend, table, caption, tbody, tfoot, thead, tr,
th, td, article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup, menu,
nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}

/* ------- HTML5 display-role reset for older browsers ------- */

article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after, q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}


+ 187
- 0
src/main/webapp/static/css/style.css View File

@@ -0,0 +1,187 @@
/*
*
* Template Name: Fullscreen Login
* Description: Login Template with Fullscreen Background Slideshow
* Author: Anli Zaimi
* Author URI: http://azmind.com
*
*/


body {
background: #f8f8f8;
font-family: 'PT Sans', Helvetica, Arial, sans-serif;
text-align: center;
color: #fff;
}

.page-container {
margin: 120px auto 0 auto;
}

h1 {
font-size: 30px;
font-weight: 700;
text-shadow: 0 1px 4px rgba(0,0,0,.2);
}

form {
position: relative;
width: 305px;
margin: 15px auto 0 auto;
text-align: center;
}

input {
width: 270px;
height: 42px;
margin-top: 25px;
padding: 0 15px;
background: #2d2d2d; /* browsers that don't support rgba */
background: rgba(45,45,45,.15);
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
border: 1px solid #3d3d3d; /* browsers that don't support rgba */
border: 1px solid rgba(255,255,255,.15);
-moz-box-shadow: 0 2px 3px 0 rgba(0,0,0,.1) inset;
-webkit-box-shadow: 0 2px 3px 0 rgba(0,0,0,.1) inset;
box-shadow: 0 2px 3px 0 rgba(0,0,0,.1) inset;
font-family: 'PT Sans', Helvetica, Arial, sans-serif;
font-size: 14px;
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.1);
-o-transition: all .2s;
-moz-transition: all .2s;
-webkit-transition: all .2s;
-ms-transition: all .2s;
}

input:-moz-placeholder { color: #fff; }
input:-ms-input-placeholder { color: #fff; }
input::-webkit-input-placeholder { color: #fff; }

input:focus {
outline: none;
-moz-box-shadow:
0 2px 3px 0 rgba(0,0,0,.1) inset,
0 2px 7px 0 rgba(0,0,0,.2);
-webkit-box-shadow:
0 2px 3px 0 rgba(0,0,0,.1) inset,
0 2px 7px 0 rgba(0,0,0,.2);
box-shadow:
0 2px 3px 0 rgba(0,0,0,.1) inset,
0 2px 7px 0 rgba(0,0,0,.2);
}

button {
cursor: pointer;
width: 300px;
height: 44px;
margin-top: 25px;
padding: 0;
background: #ef4300;
-moz-border-radius: 6px;
-webkit-border-radius: 6px;
border-radius: 6px;
border: 1px solid #ff730e;
-moz-box-shadow:
0 15px 30px 0 rgba(255,255,255,.25) inset,
0 2px 7px 0 rgba(0,0,0,.2);
-webkit-box-shadow:
0 15px 30px 0 rgba(255,255,255,.25) inset,
0 2px 7px 0 rgba(0,0,0,.2);
box-shadow:
0 15px 30px 0 rgba(255,255,255,.25) inset,
0 2px 7px 0 rgba(0,0,0,.2);
font-family: 'PT Sans', Helvetica, Arial, sans-serif;
font-size: 14px;
font-weight: 700;
color: #fff;
text-shadow: 0 1px 2px rgba(0,0,0,.1);
-o-transition: all .2s;
-moz-transition: all .2s;
-webkit-transition: all .2s;
-ms-transition: all .2s;
}

button:hover {
-moz-box-shadow:
0 15px 30px 0 rgba(255,255,255,.15) inset,
0 2px 7px 0 rgba(0,0,0,.2);
-webkit-box-shadow:
0 15px 30px 0 rgba(255,255,255,.15) inset,
0 2px 7px 0 rgba(0,0,0,.2);
box-shadow:
0 15px 30px 0 rgba(255,255,255,.15) inset,
0 2px 7px 0 rgba(0,0,0,.2);
}

button:active {
-moz-box-shadow:
0 15px 30px 0 rgba(255,255,255,.15) inset,
0 2px 7px 0 rgba(0,0,0,.2);
-webkit-box-shadow:
0 15px 30px 0 rgba(255,255,255,.15) inset,
0 2px 7px 0 rgba(0,0,0,.2);
box-shadow:
0 5px 8px 0 rgba(0,0,0,.1) inset,
0 1px 4px 0 rgba(0,0,0,.1);

border: 0px solid #ef4300;
}

.error {
display: none;
position: absolute;
top: 27px;
right: -55px;
width: 40px;
height: 40px;
background: #2d2d2d; /* browsers that don't support rgba */
background: rgba(45,45,45,.25);
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
border-radius: 8px;
}

.error span {
display: inline-block;
margin-left: 2px;
font-size: 40px;
font-weight: 700;
line-height: 40px;
text-shadow: 0 1px 2px rgba(0,0,0,.1);
-o-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);

}

.connect {
width: 305px;
margin: 35px auto 0 auto;
font-size: 18px;
font-weight: 700;
text-shadow: 0 1px 3px rgba(0,0,0,.2);
}

.connect a {
display: inline-block;
width: 32px;
height: 35px;
margin-top: 15px;
-o-transition: all .2s;
-moz-transition: all .2s;
-webkit-transition: all .2s;
-ms-transition: all .2s;
}

.connect a.facebook { background: url(../image/facebook.png) center center no-repeat; }
.connect a.twitter { background: url(../image/twitter.png) center center no-repeat; }

.connect a:hover { background-position: center bottom; }




+ 34
- 0
src/main/webapp/static/css/supersized.css View File

@@ -0,0 +1,34 @@
/*

Supersized - Fullscreen Slideshow jQuery Plugin
Version : 3.2.7
Site : www.buildinternet.com/project/supersized
Author : Sam Dunn
Company : One Mighty Roar (www.onemightyroar.com)
License : MIT License / GPL License
*/

* { margin:0; padding:0; }
body { background:#111; height:100%; }
img { border:none; }
#supersized-loader { position:absolute; top:50%; left:50%; z-index:0; width:60px; height:60px; margin:-30px 0 0 -30px; text-indent:-999em; background:url(../image/progress.gif) no-repeat center center;}
#supersized { display:block; position:fixed; left:0; top:0; overflow:hidden; z-index:-999; height:100%; width:100%; }
#supersized img { width:auto; height:auto; position:relative; display:none; outline:none; border:none; }
#supersized.speed img { -ms-interpolation-mode:nearest-neighbor; image-rendering: -moz-crisp-edges; } /*Speed*/
#supersized.quality img { -ms-interpolation-mode:bicubic; image-rendering: optimizeQuality; } /*Quality*/
#supersized li { display:block; list-style:none; z-index:-30; position:fixed; overflow:hidden; top:0; left:0; width:100%; height:100%; background:#111; }
#supersized a { width:100%; height:100%; display:block; }
#supersized li.prevslide { z-index:-20; }
#supersized li.activeslide { z-index:-10; }
#supersized li.image-loading { background:#111 url(../image/progress.gif) no-repeat center center; width:100%; height:100%; }
#supersized li.image-loading img{ visibility:hidden; }
#supersized li.prevslide img, #supersized li.activeslide img{ display:inline; }


#supersized img { max-width: none !important }


+ 25
- 0
src/main/webapp/static/css/tooltip.css View File

@@ -0,0 +1,25 @@
.tooltip{
position: absolute;
max-width: 300px;
top: 3px;
left: 105%;
padding: 8px 10px;
border-radius: 5px;
color: #fff;
background: #000000;
box-shadow: 0 2px 2px 0 #7F7C7C;
white-space: nowrap;
}
.tooltip:after{
content: '';
position: absolute;
top: 35%;
right:100%;
margin-left: 10px;
width: 0;
height: 0;
border: 5px solid transparent;
border-right: 7px #000;
border-left-width: 7px;
}


+ 2273
- 0
src/main/webapp/static/css/xterm.css
File diff suppressed because it is too large
View File


BIN
src/main/webapp/static/image/backgrounds/1.jpg View File

Before After
Width: 800  |  Height: 561  |  Size: 72 kB

BIN
src/main/webapp/static/image/backgrounds/2.jpg View File

Before After
Width: 800  |  Height: 561  |  Size: 69 kB

BIN
src/main/webapp/static/image/backgrounds/3.jpg View File


BIN
src/main/webapp/static/image/facebook.png View File

Before After
Width: 18  |  Height: 30  |  Size: 623 B

BIN
src/main/webapp/static/image/favicon.ico View File

Before After

BIN
src/main/webapp/static/image/progress.gif View File

Before After
Width: 31  |  Height: 31  |  Size: 2.6 kB

BIN
src/main/webapp/static/image/twitter.png View File

Before After
Width: 32  |  Height: 30  |  Size: 933 B

+ 103
- 0
src/main/webapp/static/js/base64.js View File

@@ -0,0 +1,103 @@
function Base64() {
// private property
_keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
// public method for encoding
this.encode = function (input) {
var output = "";
var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
var i = 0;
input = _utf8_encode(input);
while (i < input.length) {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output +
_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
}
return output;
}
// public method for decoding
this.decode = function (input) {
var output = "";
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
while (i < input.length) {
enc1 = _keyStr.indexOf(input.charAt(i++));
enc2 = _keyStr.indexOf(input.charAt(i++));
enc3 = _keyStr.indexOf(input.charAt(i++));
enc4 = _keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
}
output = _utf8_decode(output);
return output;
}
// private method for UTF-8 encoding
_utf8_encode = function (string) {
string = string.replace(/\r\n/g,"\n");
var utftext = "";
for (var n = 0; n < string.length; n++) {
var c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if((c > 127) && (c < 2048)) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
}
return utftext;
}
// private method for UTF-8 decoding
_utf8_decode = function (utftext) {
var string = "";
var i = 0;
var c = c1 = c2 = 0;
while ( i < utftext.length ) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c2 = utftext.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = utftext.charCodeAt(i+1);
c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
}
}

+ 234
- 0
src/main/webapp/static/js/formvalid.js View File

@@ -0,0 +1,234 @@
/*
Jquery
janchie 2010.1
1.02版
*/

var validResult = {};
var errorMsg = {};

(function ($) {
$.fn.extend({
valid: function () {
if (!$(this).is("form")) return;

var items = $.isArray(arguments[0]) ? arguments[0] : [],
isBindSubmit = typeof arguments[1] === "boolean" ? arguments[1] : true,
isAlert = typeof arguments[2] === "boolean" ? arguments[2] : false,

rule = {
"eng": /^[A-Za-z]+$/,
"chn": /^[\u0391-\uFFE5]+$/,
"mail": /\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/,
"url": /^http[s]?:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/,
"currency": /^\d+(\.\d+)?$/,
"number": /^\d+$/,
"int": /^[0-9]{1,30}$/,
"double": /^[-\+]?\d+(\.\d+)?$/,
"username": /^[a-zA-Z]{1}([a-zA-Z0-9]|[._]){3,19}$/,
"password": /^[\w\W]{6,20}$/,
"safe": />|<|,|\[|\]|\{|\}|\?|\/|\+|=|\||\'|\\|\"|:|;|\~|\!|\@|\#|\*|\$|\%|\^|\&|\(|\)|`/i,
"dbc": /[a-zA-Z0-9!@#¥%^&*()_+{}[]|:"';.,/?<>`~ ]/,
"qq": /[1-9][0-9]{4,}/,
"date": /^((((1[6-9]|[2-9]\d)\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\d|3[01]))|(((1[6-9]|[2-9]\d)\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\d|30))|(((1[6-9]|[2-9]\d)\d{2})-0?2-(0?[1-9]|1\d|2[0-8]))|(((1[6-9]|[2-9]\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$/,
"year": /^(19|20)[0-9]{2}$/,
"month": /^(0?[1-9]|1[0-2])$/,
"day": /^((0?[1-9])|((1|2)[0-9])|30|31)$/,
"hour": /^((0?[1-9])|((1|2)[0-3]))$/,
"minute": /^((0?[1-9])|((1|5)[0-9]))$/,
"second": /^((0?[1-9])|((1|5)[0-9]))$/,
"mobile": /^((\(\d{2,3}\))|(\d{3}\-))?13\d{9}$/,
"phone": /^[+]{0,1}(\d){1,3}[ ]?([-]?((\d)|[ ]){1,12})+$/,
"zipcode": /^[1-9]\d{5}$/,
"IDcard": /^((1[1-5])|(2[1-3])|(3[1-7])|(4[1-6])|(5[0-4])|(6[1-5])|71|(8[12])|91)\d{4}((19\d{2}(0[13-9]|1[012])(0[1-9]|[12]\d|30))|(19\d{2}(0[13578]|1[02])31)|(19\d{2}02(0[1-9]|1\d|2[0-8]))|(19([13579][26]|[2468][048]|0[48])0229))\d{3}(\d|X|x)?$/,
"ip": /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/,
"file": /^[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/,
"image": /.+\.(jpg|gif|png|bmp)$/i,
"word": /.+\.(doc|rtf|pdf)$/i,

"port": function (port) {
return (!isNaN(port) && port > 0 && port < 65536) ? true : false;
},
"eq": function (arg1, arg2) {
return arg1 == arg2 ? true : false;
},
"gt": function (arg1, arg2) {
return arg1 > arg2 ? true : false;
},
"gte": function (arg1, arg2) {
return arg1 >= arg2 ? true : false;
},
"lt": function (arg1, arg2) {
return arg1 < arg2 ? true : false;
},
"lte": function (arg1, arg2) {
return arg1 <= arg2 ? true : false;
}

},

msgSuffix = {
"eng": "only english welcomed",
"chn": "only chinese welcomed",
"mail": "invalid email format",
"url": "invalid url format",
"currency": "invalid number format",
"number": "only number welcomed",
"int": "only integer welcomed",
"double": "only float welcomed",
"username": "invalid username format,4-20 characters",
"password": "warning, you'd better use 6-20 characters",
"safe": "forbidden special characters",
"dbc": "forbidden full width characters",
"qq": "invalid qq format",
"date": "invalid date format",
"year": "invalid year format",
"month": "invalid month format",
"day": "invalid day format",
"hour": "invalid hour format",
"minute": "invalid minute format",
"second": "invalid second format",
"mobile": "invalid mobile format",
"phone": "invalid phone format",
"zipcode": "invalid zipcode format",
"IDcard": "invalid identity format",
"ip": "invalid ip format",
"port": "invalid port format",
"file": "invalid file format",
"image": "invalid image format",
"word": "invalid word file format",
"eq": "not equal",
"gt": "no greater than",
"gte": "no greater than or equal",
"lt": "no smaller than",
"lte": "no smaller than or equal"
},

msg = "", formObj = $(this), checkRet = true, isAll,
tipname = function (namestr) {
return "tip_" + namestr.replace(/([a-zA-Z0-9])/g, "-$1");
},

typeTest = function () {
var result = true, args = arguments;
if (rule.hasOwnProperty(args[0])) {
var t = rule[args[0]], v = args[1];
result = args.length > 2 ? t.apply(arguments, [].slice.call(args, 1)) : ($.isFunction(t) ? t(v) : t.test(v));
}
return result;
},

showError = function (fieldObj, filedName, warnInfo) {
checkRet = false;
var tipObj = $("#" + tipname(filedName));
if (tipObj.length > 0) tipObj.remove();
var tipPosition = fieldObj.next().length > 0 ? fieldObj.nextAll().eq(this.length - 1) : fieldObj.eq(this.length - 1);
//tipPosition.after("<span class='tooltip' id='" + tipname(filedName) + "'> " + warnInfo + " </span>");
validResult[filedName] = false;
errorMsg[filedName] = warnInfo;
if (isAlert && isAll) msg = warnInfo;
},

showRight = function (fieldObj, filedName) {
var tipObj = $("#" + tipname(filedName));
if (tipObj.length > 0) tipObj.remove();
var tipPosition = fieldObj.next().length > 0 ? fieldObj.nextAll().eq(this.length - 1) : fieldObj.eq(this.length - 1);
//tipPosition.after("<span class='tooltip' id='" + tipname(filedName) + "'>correct</span>");
validResult[filedName] = true;
},

findTo = function (objName) {
var find;
$.each(items, function () {
if (this.name == objName && this.simple) {
find = this.simple;
return false;
}
});
if (!find) find = $("[name='" + objName + "']")[0].name;
return find;
},

fieldCheck = function (item) {
var i = item, field = $("[name='" + i.name + "']", formObj[0]);
if (!field[0]) return;

var warnMsg, fv = $.trim(field.val()), isRq = typeof i.require === "boolean" ? i.require : true;

if (isRq && ((field.is(":radio") || field.is(":checkbox")) && !field.is(":checked"))) {
warnMsg = i.message || "choice needed";
showError(field, i.name, warnMsg);

} else if (isRq && fv == "") {
warnMsg = i.message || ( field.is("select") ? "choice needed" : "not none" );
showError(field, i.name, warnMsg);

} else if (fv != "") {
if (i.min || i.max) {
var len = fv.length, min = i.min || 0, max = i.max;
warnMsg = i.message || (max ? "range" + min + "~" + max + "" : "min length" + min);

if ((max && (len > max || len < min)) || (!max && len < min)) {
showError(field, i.name, warnMsg);
return;
}
}
if (i.type) {
var matchVal = i.to ? $.trim($("[name='" + i.to + "']").val()) : i.value;
var matchRet = matchVal ? typeTest(i.type, fv, matchVal) : typeTest(i.type, fv);

warnMsg = i.message || msgSuffix[i.type];
if (matchVal) warnMsg += (i.to ? findTo(i.to) + "value" : i.value);

if (!matchRet) showError(field, i.name, warnMsg);
else showRight(field, i.name);

} else {
showRight(field, i.name);
}

} else if (isRq) {
showRight(field, i.name);
}

},

validate = function () {
$.each(items, function () {
isAll = true;
fieldCheck(this);
});

if (isAlert && msg != "") {
alert(msg);
msg = "";
}
return checkRet;
};

$.each(items, function () {
var field = $("[name='" + this.name + "']", formObj[0]);
if (field.is(":hidden")) return;

var obj = this, toCheck = function () {
isAll = false;
fieldCheck(obj);
};
if (field.is(":file") || field.is("select")) {
field.change(toCheck);
} else {
field.blur(toCheck);
}
});

if (isBindSubmit) {
$(this).submit(validate);
} else {
return validate();
}

}

});

})(jQuery);

+ 5
- 0
src/main/webapp/static/js/jquerymin.js
File diff suppressed because it is too large
View File


+ 124
- 0
src/main/webapp/static/js/main.js View File

@@ -0,0 +1,124 @@
function openTerminal(options) {
//var CONNECT_TIME = 0; // 请求连接次数
$("#form").hide();
Rows = parseInt(options.Rows);
var client = new WSSHClient();
var base64 = new Base64();
var term = new Terminal({cols: 80, rows: Rows, screenKeys: true, useStyle: true});

// 发送客户端数据
term.on('data', function (data) {
console.log("xterm data: ");
console.log(data);
client.sendClientData(data);
});
term.open();
$('.terminal').detach().appendTo('#term');
$("#term").show();
term.write("Connecting...");
console.debug(options);

//var interTime = setInterval(client_connect, 1000)
setTimeout(client_connect, 3000);

var intervalId = null;

function client_connect() {
// var TIMEINIT = 0; // 初始化时间
// var TIMEOUT = 60 * 15; // 超时时间
var CONNECTED = false; // 是否连接成功过
console.log("连接中....");
console.log(options);

client.connect({
onError: function (error) {
term.write('Error: ' + error + '\r\n');
console.log('error happened');
},
onConnect: function () {
console.log('connection established');
// 连接上之后发送初始化数据
client.sendInitData(options);
term.focus();
},
onClose: function () {
console.log("连接关闭");
term.write("\r\nconnection closed");
if (CONNECTED) {
console.log('connection reset by peer');
$('term').hide();
}
},
// 当收到服务端返回的数据
onData: function (data) {
if (!CONNECTED) {
console.log("first connected.");
term.write("\r"); //换行
term.focus(); //焦点移动到框上
}
/*if(interTime){
clearInterval(interTime);
}*/
CONNECTED = true;

data = base64.decode(data);
/* TIMEINIT = 0;*/
term.write(data);
console.log('get data:' + data);
}
})
}
}

var charWidth = 6.2;
var charHeight = 15.2;

/**
* for full screen
* @returns {{w: number, h: number}}
*/
function getTerminalSize() {
var width = window.innerWidth;
var height = window.innerHeight;
return {
w: Math.floor(width / charWidth),
h: Math.floor(height / charHeight)
};
}


function store(options) {
window.localStorage.host = options.host
window.localStorage.port = options.port
window.localStorage.username = options.username
window.localStorage.ispwd = options.ispwd
window.localStorage.password = options.password
}

function check() {
return validResult["host"] && validResult["port"] && validResult["username"];
}

function connect() {
var remember = $("#remember").is(":checked")
var options = {
host: $("#host").val(),
port: $("#port").val(),
username: $("#username").val(),
password: $("#password").val(),
Rows: $("#terminalRow").val(),
}
if (remember) {
store(options)
}
if (true) {
openTerminal(options)
} else {
for (var key in validResult) {
if (!validResult[key]) {
alert(errorMsg[key]);
break;
}
}
}
}

+ 30
- 0
src/main/webapp/static/js/supersized-init.js View File

@@ -0,0 +1,30 @@
jQuery(function($){

$.supersized({

// Functionality
slide_interval : 4000, // Length between transitions
transition : 1, // 0-None, 1-Fade, 2-Slide Top, 3-Slide Right, 4-Slide Bottom, 5-Slide Left, 6-Carousel Right, 7-Carousel Left
transition_speed : 1000, // Speed of transition
performance : 1, // 0-Normal, 1-Hybrid speed/quality, 2-Optimizes image quality, 3-Optimizes transition speed // (Only works for Firefox/IE, not Webkit)

// Size & Position
min_width : 0, // Min width allowed (in pixels)
min_height : 0, // Min height allowed (in pixels)
vertical_center : 1, // Vertically center background
horizontal_center : 1, // Horizontally center background
fit_always : 0, // Image will never exceed browser width or height (Ignores min. dimensions)
fit_portrait : 1, // Portrait images will not exceed browser height
fit_landscape : 0, // Landscape images will not exceed browser width

// Components
slide_links : 'blank', // Individual links for each slide (Options: false, 'num', 'name', 'blank')
slides : [ // Slideshow Images
{image : '/static/image/backgrounds/1.jpg'},
{image : '/static/image/backgrounds/2.jpg'},
{image : '/static/image/backgrounds/3.jpg'}
]

});

});

+ 13
- 0
src/main/webapp/static/js/supersized.3.2.7.min.js
File diff suppressed because it is too large
View File


+ 67
- 0
src/main/webapp/static/js/ws.js View File

@@ -0,0 +1,67 @@
function WSSHClient() {
};

WSSHClient.prototype._generateEndpoint = function () {
if (window.location.protocol == 'https:') {
var protocol = 'wss://';
} else {
var protocol = 'ws://';
}
var endpoint = protocol + window.location.host + '/ws';
return endpoint;
};

WSSHClient.prototype.connect = function (options) {
var endpoint = this._generateEndpoint();

if (window.WebSocket) {
this._connection = new WebSocket(endpoint);
}
else if (window.MozWebSocket) {
this._connection = MozWebSocket(endpoint);
}
else {
options.onError('WebSocket Not Supported');
return;
}

this._connection.onopen = function () {
options.onConnect();
};

this._connection.onmessage = function (evt) {
var data = evt.data.toString()
options.onData(data);
};


this._connection.onclose = function (evt) {
options.onClose();
};
};

WSSHClient.prototype.close = function () {
this._connection.close();
};

WSSHClient.prototype.send = function (data) {
this._connection.send(JSON.stringify(data));
};

WSSHClient.prototype.sendInitData = function (options) {
var data = {
hostname: options.host,
port: options.port,
username: options.username,
password: options.password
};
this._connection.send(JSON.stringify({"tp": "init", "data": options}))
console.log("发送初始化数据:" + options)
}

WSSHClient.prototype.sendClientData = function (data) {
this._connection.send(JSON.stringify({"tp": "client", "data": data}))
console.log("发送客户端数据:" + data)
}

var client = new WSSHClient();

+ 4959
- 0
src/main/webapp/static/js/xterm.js
File diff suppressed because it is too large
View File


+ 1
- 0
test.txt View File

@@ -0,0 +1 @@
测试push

+ 6
- 0
test3.py View File

@@ -0,0 +1,6 @@
printf('1111')

这是第一个变更


print(123)

Loading…
Cancel
Save