注:本文很多代码已被删减,留下的是本人觉得可以参考的代码,本篇主要注重叙述该技术实现的逻辑和构思,以及对大多数运维软件进行审计时以视频的形式保存历史监控会话所构思的一个新的技术做法
技术背景:
进行审计时查看运维人员终端历史操作回放,一般都通过视频的形式进行回放, 在Linux中script命令可进行终端操作的录制和回放功能,以此为基础,可以模拟Linux中的script命令进行终端历史操作回放。
script命令其实质是将终端所操作的页面的终端控制字符全部记录在一个文件中,同时也创建与之对应的timing文件(timing文件中保存等待的时间和所要输出的字符),通过读取这两个文件可实现操作回放。
文件内容如下:
因此在进行回放时只需要按照timing文件的规范去读取typescript文件里的字节内容输出出来即可实现
·
技术栈
● Spring Boot
● Websocket
● Xterm.js
● linux下script命令
● JavaScript、Css、Vue
·
技术实现:
● 首先,需要有读取两个文件并保存在list里的静态方法(按行读取)
public static ArrayList<String> readFileTOList(String timingFileName) {
ArrayList<String> readFileList = new ArrayList<>();
try {
FileReader fileReader = new FileReader(timingFileName);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String str;
int i = 0;
while ((str = bufferedReader.readLine()) != null) {
readFileList.add(i, str);
i++;
}
} catch (FileNotFoundException e) {
System.out.println("没有找到该文件");
} catch (IOException e) {
e.printStackTrace();
}
return readFileList;
}
·
● 由于需要保证在播放时除了发送数据还可以同步设置改变终端窗口大小并且拥有暂停播放,继续播放以及拖动条定位播放功能,不适合以多线程去执行,因为在执行线程暂停时,wait方法并不能很好的在多线程中获得到相应线程的锁,因此我们将所有的数据格式化并整理在一条时间线上发送数据,同时读取文件的字节流有可能导致线程紊乱,为了更快地执行操作,需在整理合并的时间线上保存已经读好的内容而不是要读的字节数。
因此需要先整理好读取的文本数据。
public static ArrayList<String> getData(ArrayList<String> readTimeFileList) {
/*
读取updateTimeFile实例,进一步进行逻辑实现按照多少时间睡眠后执行什么操作的形式
*/
return dataOrgansizeList;
}
public static ArrayList<String> getUpdateTimeFile(ArrayList<String> readTimeFileList) {
int time = 0; //设置初始时间
int toBeReadLength = 0;
ArrayList<String> updateTimeFileList = new ArrayList<>(); //timing文件整理
for (int i = 0; i < readTimeFileList.size(); i++) {
/*
逻辑实现0秒时间重叠,形成完整数据字节时间线
*/
time += addTime;
if (addTime != 0) {
String strings = time + "\t" + toBeReadLength + "\t" + "sendLine";
updateTimeFileList.add(strings);
}
toBeReadLength += addReadLength;
if (i == readTimeFileList.size() - 1) {
String strings = time + "\t" + toBeReadLength + "\t" + "sendLine";
updateTimeFileList.add(strings);
}
}
return updateTimeFileList;
}
·
这里在结构化数据时,有三种数据格式,文本字节(line),窗口大小(size),当前时间(tTime),将其做成枚举类型,并添加优先级
enum FrameType {
TYPESCRIPT(100),
SIZE(200),
TIME(300),
;
// 优先级
private Integer priority;
FrameType(Integer priority) {
this.priority = priority;
}
public Integer getPriority() {
return priority;
}
}
·
我们将在这条时间线上的每一条数据当成一条数据帧,创建抽象帧工厂类,同时实现接口Comparable,使得所有抽象工厂类的子类在添加时按照时间和三种数据格式的优先级大小来自动排序
abstract class AbstractAuditFrame implements Comparable<AbstractAuditFrame> {
private Long time;
public AbstractAuditFrame(Long time) {
this.time = time;
}
public Long getTime