web_sandbox_console 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +63 -34
- data/app/assets/stylesheets/web_sandbox_console/common.css +14 -1
- data/app/assets/stylesheets/web_sandbox_console/home.css +28 -0
- data/app/controllers/web_sandbox_console/home_controller.rb +2 -5
- data/app/views/layouts/web_sandbox_console/application.html.erb +1 -1
- data/app/views/web_sandbox_console/home/do_view_file.js.erb +6 -8
- data/app/views/web_sandbox_console/home/index.html.erb +3 -26
- data/lib/web_sandbox_console/common.rb +29 -8
- data/lib/web_sandbox_console/safe_ruby.rb +75 -14
- data/lib/web_sandbox_console/sandbox.rb +9 -6
- data/lib/web_sandbox_console/version.rb +1 -1
- data/lib/web_sandbox_console/view_file.rb +45 -7
- metadata +10 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '01385f4ee72595defa82f0d4c7141d28281c09e1b34c946177bda7c592043273'
|
4
|
+
data.tar.gz: 44a4c34af0ed2b38e018491bcb7711d2b20545b7e6a136851bab564efb341025
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9118a01bb98153510454b4626f04c732c19a094db040f451d72e475294f5a99aef7b4590de7d1f7241e3410b853108d9cc79d55bb365e715c197051807681fd
|
7
|
+
data.tar.gz: 93a338b267b25082cbe0815a3ca695df3702197698ad293beb8b016b4769724d36e0cadcaaf47dc561f9dc6203c3dc75bcd9953b10722de443196aecc2dfd700
|
data/README.md
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
|
4
4
|
这个控制台提供一个类似沙盒的安全环境,这里做的所有数据操作,都会回滚(不会真正写入数据库);你可以配置 ip 白名单、基本认证,来增加访问安全性;另外在这个沙盒中,内置禁止了linux命令的执行,所以不用担心,ruby越界去做了linux的相关事情,当然还禁止了文件的新建、删除、目录的新建、删除等一系列方法;如果你需要更强的限制,你还可以去配置你想禁止使用的哪些方法等等,具体看配置文件。
|
5
5
|
|
6
|
+
此gem基本涵盖了日常使用的常用功能,包括:数据查询、数据修改、数据导出、日志查看、日志时间或内容过滤、文件查看,日志下载等。
|
7
|
+
|
6
8
|
## Usage
|
7
9
|
使用过程相当简单,和一般的gem,安装后你不用特殊去配置任何东西,就可以正常使用。所有的配置选项都是可选的。
|
8
10
|
|
@@ -19,22 +21,21 @@ $ bundle
|
|
19
21
|
```
|
20
22
|
|
21
23
|
此时,如果是在本地,你访问 `http://localhost:3000/web_sandbox_console` 就能看到web控制台了,下面这个样子。
|
24
|
+
|
22
25
|
PS:代码输入框支持代码高亮,你可以像在代码编辑器一样自由编写代码
|
23
26
|

|
24
27
|
|
25
28
|
## 配置
|
26
|
-
|
27
|
-
在bundle后,就可以使用一些基础的功能了;
|
28
|
-
如果你不满足基础的功能、或者需要更高的安全性,很有必要仔细了解配置选项,总之还是很推荐对项目进行适当配置;
|
29
|
-
关于配置的详细介绍,在生成的文件中也有详细的说明,参照说明配置即可;
|
30
|
-
```
|
29
|
+
在bundle后,就可以直接使用了,为了安全起见,建议进一步配置基本认证;如果需要数据修改权限,还需要配置公钥;关于配置选项的具体说明,请参阅配置文件注释。
|
31
30
|
|
32
31
|
在 rails 项目路径下,执行:
|
33
32
|
```bash
|
34
33
|
$ rails g web_sandbox_console
|
35
34
|
```
|
36
35
|
|
37
|
-
|
36
|
+
会在项目路径下,创建两个配置文件
|
37
|
+
一、config/initializers/web_sandbox_console.rb文件
|
38
|
+
|
38
39
|
```ruby
|
39
40
|
# config/initializers/web_sandbox_console.rb
|
40
41
|
|
@@ -79,7 +80,9 @@ WebSandboxConsole.setup do |config|
|
|
79
80
|
end
|
80
81
|
```
|
81
82
|
|
82
|
-
|
83
|
+
二、config/web_sandbox_console.yml.example 文件
|
84
|
+
|
85
|
+
主要用于配置基本授权、升级权限需要用到的公钥,参照example文件创建yml文件即可
|
83
86
|
```ruby
|
84
87
|
# config/web_sandbox_console.yml.example
|
85
88
|
|
@@ -91,29 +94,44 @@ web_sandbox_console:
|
|
91
94
|
|
92
95
|
```
|
93
96
|
|
97
|
+
关于配置的补充说明:
|
98
|
+
|
99
|
+
> 建议不要轻易配置黑名单方法,因为禁用某些方法后,可能会导致许多意想不到问题;有可能不小心禁用到rails框架或gem使用的一些方法;
|
100
|
+
>
|
101
|
+
> 对于此gem内置禁用的方法,gem内部是做了一些兼容性的处理的,因此不会有什么问题
|
102
|
+
|
94
103
|
## 深入了解
|
104
|
+
|
95
105
|
主要包含三大功能块:代码执行、文件查看、日志下载,下面分别介绍
|
96
106
|
|
97
107
|
### 代码执行
|
98
108
|
1. 提交和异步执行
|
99
109
|
|
100
|
-
>
|
110
|
+
> 提交后代码会立即执行,及时返回执行结果
|
111
|
+
>
|
112
|
+
> 异步执行,代码会在后台异步执行,这对于执行时间非常长的代码,强烈建议异步执行;比如批量更新数据、导出数据等
|
101
113
|
|
102
114
|
2. 升级权限
|
103
|
-

|
115
|
+

|
116
|
+
|
117
|
+
> 大多数时候,可能用到的操作就是查数据,但是,有时你可能需要修改某条数据,那么功能就不够用了
|
118
|
+
>
|
119
|
+
> 为了支持数据的修改,同时保证安全性,加入了升级权限这个功能
|
120
|
+
>
|
121
|
+
> 整个过程相当简单,在yaml文件中配置好公钥 -> 获取token -> 本地加密后回传 -> 授权成功
|
122
|
+
>
|
123
|
+
> 授权成功后,所有数据操作将不再执行回滚(PS:未升级授权时,做的所有数据操作都会执行回滚,不会真正写入数据库)
|
104
124
|
|
105
|
-
```
|
106
|
-
通常你能做的操作就是,查查数据等,数据的所有操作都不会写入到数据库,这样很安全;但是每当你需要修改数据时,还是需要让运维处理;为了满足可以数据写入、和安全性的要求;开发了升级权限这个功能。
|
107
125
|
|
108
|
-
升级权限你需要在配置文件中配置公钥,自己保存私钥;整个过程采用非对称加密的方式,进行授权,还是比较安全的。
|
109
|
-
升级授权成功后,代码执行将不再回滚,会直接写入数据库。
|
110
|
-
```
|
111
126
|
|
112
127
|
升级权限流程如下:
|
113
|
-
>
|
114
|
-
>
|
115
|
-
>
|
116
|
-
>
|
128
|
+
> 1. config/web_sandbox_console.yml`中配置公钥
|
129
|
+
>
|
130
|
+
> 2. 进入授权页面,点击获取令牌
|
131
|
+
>
|
132
|
+
> 3. 用私钥对令牌加密,然后用base64加密
|
133
|
+
>
|
134
|
+
> 4. 将加密的打印结果(注意是puts 文本),输入加密密文框,提交
|
117
135
|
|
118
136
|
```ruby
|
119
137
|
# 本地生成 加密密文代码
|
@@ -131,35 +149,46 @@ puts encode_text
|
|
131
149
|

|
132
150
|
1. 目录和文件
|
133
151
|
|
134
|
-
> 你可以查看一个目录下有哪些文件夹或文件,你也可以直接查看文件的内容,默认返回一个文件的前100行
|
152
|
+
> 你可以查看一个目录下有哪些文件夹或文件,你也可以直接查看文件的内容,默认返回一个文件的前100行
|
135
153
|
|
136
154
|
2. 指定行数
|
137
|
-
```
|
138
|
-
你可以根据文件总行数,指定查看文件的开始行数、结束行数。
|
139
|
-
PS: a. 在过滤文件(过滤内容/过滤时间)的时候,此时指定行数将被忽略
|
140
|
-
b. 对于大文件(默认超过10M),处于性能考虑,此时指定行数也会被忽略
|
141
|
-
```
|
142
155
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
156
|
+
> 你可以根据文件总行数,指定查看文件的开始行数、结束行数。
|
157
|
+
> PS: a. 在过滤文件(过滤内容/过滤时间)的时候,此时指定行数将被忽略
|
158
|
+
> b. 对于大文件(默认超过10M),处于性能考虑,此时指定行数也会被忽略
|
159
|
+
3. 过滤内容
|
160
|
+
|
161
|
+
> 当过滤内容时,仅返回匹配的行,匹配行的上下文是不会返回的
|
162
|
+
>
|
163
|
+
> 因此如果需要查看匹配行的上下文,需要再次根据匹配行的时间做过滤(PS:此时需清掉内容输入框)
|
148
164
|
|
165
|
+
4. 过滤时间
|
166
|
+
|
167
|
+
> 可以只填开始时间,不填结束时间,此时返回该时间的日志
|
149
168
|
4. 权限
|
150
169
|
|
151
|
-
> 默认情况,只能查看日志文件或目录,当然你也可以去配置做调整。
|
170
|
+
> 默认情况,只能查看日志文件或目录,当然你也可以去配置做调整。
|
171
|
+
|
172
|
+
5. 其它
|
173
|
+
|
174
|
+
> 1. 可以根据返回内容的提示,了解当前查询(文件总行数、当前按照某种方式返回)
|
175
|
+
> 2. 查询的逻辑如下:
|
176
|
+
> 3. 如果只指定文件名,且文件比较小(小文件),默认返回文件前100行
|
177
|
+
> 4. 如果只指定文件名,文件比较大(大文件),默认返回文件最后1000行
|
178
|
+
> 5. 如果指定了文件名、过滤内容,则忽略行数查找,直接依据过滤内容匹配行,如果匹配到的行数超过1000行,则返回匹配出的前1000行
|
179
|
+
> 6. 如果指定了文件名、过滤内容、过滤时间,则先按照时间匹配出内容,然后根据内容进行匹配
|
152
180
|
|
153
181
|
### 日志下载
|
182
|
+
|
154
183
|

|
155
184
|
你可以直接输入文件名(需要带后缀)下载日志
|
156
185
|
|
157
186
|
### 关于数据导出
|
158
|
-
|
187
|
+
|
188
|
+
可以先在代码执行页面,用`CSV.open`方式生成 csv文件,然后在日志下载中去下载创建的csv文件
|
159
189
|
|
160
190
|
有一下几点需注意:
|
161
|
-
> 1.
|
162
|
-
> 2. 文件名以你路径中(/分隔)的最后一个名称为准
|
191
|
+
> 1. 在`CSV.open`中写的任何路径,都不会生效,最终只会在log目录下创建csv文件;比如`CSV.open('#{Rails.root}/hu/bar.txt') 会在log目录下,生成bar.csv文件
|
163
192
|
> 3. csv 文件下载后,会自动删除掉,因此只能下载一次
|
164
193
|
|
165
194
|
|
@@ -167,4 +196,4 @@ PS: a. 在过滤文件(过滤内容/过滤时间)的时候,此时指定行
|
|
167
196
|
Contribution directions go here.
|
168
197
|
|
169
198
|
## License
|
170
|
-
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
199
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
@@ -186,6 +186,8 @@ img {
|
|
186
186
|
position: relative;
|
187
187
|
margin-left: 200px;
|
188
188
|
/*padding-top: 70px;*/
|
189
|
+
margin-right: 30px;
|
190
|
+
min-height: 800px;
|
189
191
|
z-index: 100
|
190
192
|
}
|
191
193
|
|
@@ -215,4 +217,15 @@ img {
|
|
215
217
|
|
216
218
|
.mr-auto {
|
217
219
|
margin-right: auto!important;
|
218
|
-
}
|
220
|
+
}
|
221
|
+
|
222
|
+
|
223
|
+
pre {
|
224
|
+
white-space: pre-wrap; /* Since CSS 2.1 */
|
225
|
+
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
|
226
|
+
white-space: -pre-wrap; /* Opera 4-6 */
|
227
|
+
white-space: -o-pre-wrap; /* Opera 7 */
|
228
|
+
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
229
|
+
line-height: 18px;
|
230
|
+
margin-top: 0px;
|
231
|
+
}
|
@@ -20,4 +20,32 @@
|
|
20
20
|
font-size: 15px;
|
21
21
|
color: white;
|
22
22
|
cursor: pointer;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* 执行代码页面样式 */
|
26
|
+
.wrapper-console {
|
27
|
+
position: relative;
|
28
|
+
top: 8px;
|
29
|
+
width: 100%;
|
30
|
+
height: 300px;
|
31
|
+
}
|
32
|
+
|
33
|
+
.left {
|
34
|
+
height: 100%;
|
35
|
+
/* 为了不占用绝对定位的宽度 这里计算下宽度*/
|
36
|
+
width: calc(100% - 200px);
|
37
|
+
}
|
38
|
+
|
39
|
+
.right {
|
40
|
+
position: absolute;
|
41
|
+
width: 180px;
|
42
|
+
top: 0;
|
43
|
+
bottom: 0;
|
44
|
+
right: 0;
|
45
|
+
padding-left: 15px;
|
46
|
+
}
|
47
|
+
|
48
|
+
/* 选中后code背景色*/
|
49
|
+
.CodeMirror-selected {
|
50
|
+
background: #20aee3 !important;
|
23
51
|
}
|
@@ -22,11 +22,8 @@ module WebSandboxConsole
|
|
22
22
|
|
23
23
|
# 查看文件
|
24
24
|
def do_view_file
|
25
|
-
|
26
|
-
@
|
27
|
-
@total_line_num = results[:total_line_num]
|
28
|
-
@touch_grep_protect = results[:touch_grep_protect]
|
29
|
-
@content_is_trimed = results[:content_is_trimed]
|
25
|
+
@result_hash = ViewFile.new(params).view
|
26
|
+
@tip_hash = WebSandboxConsole::ViewFile::PageTips
|
30
27
|
end
|
31
28
|
|
32
29
|
# 下载文件页面
|
@@ -1,16 +1,14 @@
|
|
1
1
|
$(".output-content").empty();
|
2
|
-
<% line_num_show = @total_line_num ? "原始文件总行数:#{@total_line_num}" : "" %>
|
3
2
|
|
3
|
+
<% line_num_show = @result_hash[:total_line_num] ? "原始文件总行数:#{@result_hash[:total_line_num]}" : "" %>
|
4
4
|
$(".output-content").append("<p>============ <%= Time.current %> 查找结果如下 <%= line_num_show %> ===============</p>");
|
5
5
|
|
6
|
-
<%
|
7
|
-
|
6
|
+
<% @tip_hash.each do |key,value| %>
|
7
|
+
<% if @result_hash[key.to_sym] %>
|
8
|
+
$(".output-content").append("<p>PS: <%= value %></p>");
|
9
|
+
<% end %>
|
8
10
|
<% end %>
|
9
11
|
|
10
|
-
<%
|
11
|
-
$(".output-content").append("<p>PS: 当前返回内容太多,仅展示满足条件的1000行</p>");
|
12
|
-
<% end %>
|
13
|
-
|
14
|
-
<% @lines.each do |result| %>
|
12
|
+
<% @result_hash[:lines].each do |result| %>
|
15
13
|
$(".output-content").append('<pre><%= escape_javascript result %></pre>');
|
16
14
|
<% end %>
|
@@ -1,30 +1,5 @@
|
|
1
1
|
<h3>执行代码</h3>
|
2
2
|
|
3
|
-
<style type="text/css">
|
4
|
-
.wrapper-console {
|
5
|
-
position: relative;
|
6
|
-
top: 8px;
|
7
|
-
width: 100%;
|
8
|
-
height: 300px;
|
9
|
-
}
|
10
|
-
|
11
|
-
.left {
|
12
|
-
height: 100%;
|
13
|
-
/* 为了不占用绝对定位的宽度 这里计算下宽度*/
|
14
|
-
width: calc(100% - 200px);
|
15
|
-
}
|
16
|
-
|
17
|
-
.right {
|
18
|
-
position: absolute;
|
19
|
-
width: 180px;
|
20
|
-
top: 0;
|
21
|
-
bottom: 0;
|
22
|
-
right: 0;
|
23
|
-
padding-left: 15px;
|
24
|
-
}
|
25
|
-
</style>
|
26
|
-
|
27
|
-
|
28
3
|
<div class="wrapper-console">
|
29
4
|
<%= form_tag(web_sandbox_console.eval_code_path, remote: true, class: 'form') do %>
|
30
5
|
<div class= "left">
|
@@ -60,6 +35,8 @@
|
|
60
35
|
indentWithTabs: true,
|
61
36
|
theme: 'lucario',
|
62
37
|
tabSize: 2,
|
63
|
-
lineNumbers: true
|
38
|
+
lineNumbers: true,
|
39
|
+
lineWrapping: true, /* 自动换行 */
|
40
|
+
fixedGutter: false
|
64
41
|
});
|
65
42
|
</script>
|
@@ -1,17 +1,38 @@
|
|
1
1
|
module WebSandboxConsole
|
2
2
|
module Common
|
3
|
-
|
4
|
-
def
|
5
|
-
@
|
3
|
+
|
4
|
+
def current_uuid(uuid=nil)
|
5
|
+
@uuid ||= uuid
|
6
|
+
end
|
7
|
+
|
8
|
+
# logger sql语句
|
9
|
+
def logger_sql
|
10
|
+
logger = fetch_logger
|
11
|
+
logger.level = 0
|
12
|
+
logger.formatter = proc {|severity, time, progname, msg| "#{current_uuid}: #{msg}\n"}
|
13
|
+
ActiveRecord::Base.logger = logger
|
14
|
+
end
|
6
15
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
16
|
+
# uuid 方便取出日志
|
17
|
+
def log_p(msg_or_exce, is_general_text = false)
|
18
|
+
uuid = current_uuid
|
19
|
+
logger = fetch_logger
|
20
|
+
|
21
|
+
if msg_or_exce.respond_to?(:message) # 异常
|
22
|
+
logger.info "#{uuid}:" + msg_or_exce.message
|
23
|
+
logger.info "#{uuid}:" + msg_or_exce.backtrace.join("|||")
|
24
|
+
elsif is_general_text # 普通文本
|
25
|
+
logger.info "#{uuid}:" + msg_or_exce.inspect
|
26
|
+
else # 返回值
|
27
|
+
logger.info "#{uuid}: => " + msg_or_exce.inspect
|
12
28
|
end
|
13
29
|
end
|
14
30
|
|
31
|
+
# 获取 logger
|
32
|
+
def fetch_logger
|
33
|
+
@logger ||= Logger.new(log_path, 'daily')
|
34
|
+
end
|
35
|
+
|
15
36
|
def log_path
|
16
37
|
"#{Rails.root}/#{self.console_log_path || "log/web_sandbox_console.log"}"
|
17
38
|
end
|
@@ -7,17 +7,14 @@ module WebSandboxConsole
|
|
7
7
|
sanitize_class_methods
|
8
8
|
sanitize_logger_new
|
9
9
|
sanitize_csv
|
10
|
+
compatible_file_cache
|
11
|
+
compatible_i18n_translate
|
12
|
+
blacklist_method_remind
|
10
13
|
end
|
11
14
|
|
12
15
|
# 净化 类方法
|
13
16
|
def sanitize_class_methods
|
14
|
-
|
15
|
-
merge_method_hash(CLASS_METHOD_BUILT_IN_BLACKLIST, class_method_blacklist)
|
16
|
-
else
|
17
|
-
CLASS_METHOD_BUILT_IN_BLACKLIST
|
18
|
-
end
|
19
|
-
|
20
|
-
blacklist.each do |klass, methods|
|
17
|
+
class_method_blacklists.each do |klass, methods|
|
21
18
|
klass = Object.const_get(klass)
|
22
19
|
methods.each do |method|
|
23
20
|
next if klass.singleton_methods.exclude?(method)
|
@@ -28,13 +25,7 @@ module WebSandboxConsole
|
|
28
25
|
|
29
26
|
# 净化 实例方法
|
30
27
|
def sanitize_instance_methods
|
31
|
-
|
32
|
-
merge_method_hash(INSTANT_METOD_BUILT_IN_BLACKLIST,instance_method_blacklist)
|
33
|
-
else
|
34
|
-
INSTANT_METOD_BUILT_IN_BLACKLIST
|
35
|
-
end
|
36
|
-
|
37
|
-
blacklist.each do |klass, methods|
|
28
|
+
instance_method_blacklists.each do |klass, methods|
|
38
29
|
klass = Object.const_get(klass)
|
39
30
|
methods.each do |method|
|
40
31
|
next if (klass != Kernel) && klass.instance_methods.exclude?(method)
|
@@ -43,6 +34,24 @@ module WebSandboxConsole
|
|
43
34
|
end
|
44
35
|
end
|
45
36
|
|
37
|
+
# 类方法黑名单列表
|
38
|
+
def class_method_blacklists
|
39
|
+
blacklist = if class_method_blacklist
|
40
|
+
merge_method_hash(CLASS_METHOD_BUILT_IN_BLACKLIST, class_method_blacklist)
|
41
|
+
else
|
42
|
+
CLASS_METHOD_BUILT_IN_BLACKLIST
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# 实例方法黑名单列表
|
47
|
+
def instance_method_blacklists
|
48
|
+
blacklist = if instance_method_blacklist
|
49
|
+
merge_method_hash(INSTANT_METOD_BUILT_IN_BLACKLIST,instance_method_blacklist)
|
50
|
+
else
|
51
|
+
INSTANT_METOD_BUILT_IN_BLACKLIST
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
46
55
|
# 净化 常量
|
47
56
|
def sanitize_constants
|
48
57
|
return unless constant_blacklist
|
@@ -105,5 +114,57 @@ module WebSandboxConsole
|
|
105
114
|
end
|
106
115
|
end
|
107
116
|
|
117
|
+
# 兼容文件缓存
|
118
|
+
def compatible_file_cache
|
119
|
+
ActiveSupport::Cache::FileStore.class_exec do
|
120
|
+
def write_entry(key, entry, options)
|
121
|
+
true
|
122
|
+
end
|
123
|
+
|
124
|
+
def delete_entry(key, options)
|
125
|
+
true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# 兼容翻译
|
131
|
+
def compatible_i18n_translate
|
132
|
+
I18n.instance_exec do
|
133
|
+
def translate(*args)
|
134
|
+
"ActiveRecord::RecordInvalid: 校验失败"
|
135
|
+
end
|
136
|
+
alias :t :translate
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# 当拦截黑名单方法时提醒
|
141
|
+
def blacklist_method_remind
|
142
|
+
Kernel.class_exec do
|
143
|
+
# 发现此处method_missing Array 没有flatten方法
|
144
|
+
def flatten_arr(arr)
|
145
|
+
new_arr = []
|
146
|
+
arr.each do |e|
|
147
|
+
if e.is_a?(Array)
|
148
|
+
new_arr.concat(flatten_arr(e))
|
149
|
+
else
|
150
|
+
new_arr << e
|
151
|
+
end
|
152
|
+
end
|
153
|
+
new_arr
|
154
|
+
end
|
155
|
+
|
156
|
+
def method_missing(name,*params)
|
157
|
+
class_methods = WebSandboxConsole.class_method_blacklists.values
|
158
|
+
instance_methods = WebSandboxConsole.instance_method_blacklists.values
|
159
|
+
|
160
|
+
if flatten_arr([class_methods, instance_methods]).include?(name.to_sym)
|
161
|
+
msg = "PS:当前代码执行过程中可能调用了黑名单方法,若代码正常返回,请忽略此条提醒"
|
162
|
+
WebSandboxConsole.log_p(msg, true)
|
163
|
+
end
|
164
|
+
super
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
108
169
|
end
|
109
170
|
end
|
@@ -43,16 +43,18 @@ module WebSandboxConsole
|
|
43
43
|
|
44
44
|
def runner_code
|
45
45
|
str =<<-CODE
|
46
|
-
WebSandboxConsole.init_safe_env
|
47
46
|
result = nil
|
48
47
|
begin
|
48
|
+
WebSandboxConsole.current_uuid("#{self.uuid}")
|
49
|
+
WebSandboxConsole.init_safe_env
|
50
|
+
WebSandboxConsole.logger_sql
|
49
51
|
#{self.pass_auth ? no_rollback_code : rollback_code}
|
50
52
|
rescue Exception => e
|
51
|
-
WebSandboxConsole.log_p(e
|
53
|
+
WebSandboxConsole.log_p(e)
|
52
54
|
rescue SyntaxError => e
|
53
|
-
WebSandboxConsole.log_p(e
|
55
|
+
WebSandboxConsole.log_p(e)
|
54
56
|
end
|
55
|
-
WebSandboxConsole.log_p(result
|
57
|
+
WebSandboxConsole.log_p(result)
|
56
58
|
CODE
|
57
59
|
end
|
58
60
|
|
@@ -121,7 +123,7 @@ module WebSandboxConsole
|
|
121
123
|
|
122
124
|
# 返回结果
|
123
125
|
def return_result_arr
|
124
|
-
last_10_lines = `tail -n
|
126
|
+
last_10_lines = `tail -n 100 #{WebSandboxConsole.log_path} | grep #{self.uuid}`
|
125
127
|
|
126
128
|
last_10_lines.split("\n").map do |line|
|
127
129
|
line.split("#{self.uuid}:").last.split("|||")
|
@@ -131,7 +133,8 @@ module WebSandboxConsole
|
|
131
133
|
# 最终结果
|
132
134
|
def get_result
|
133
135
|
if @stdout.present?
|
134
|
-
stdout_arr =
|
136
|
+
stdout_arr = ['------------ 打印值 ----------']
|
137
|
+
stdout_arr.concat(@stdout.to_s.split("\n"))
|
135
138
|
stdout_arr << '------------ 返回值 ----------'
|
136
139
|
stdout_arr.concat(return_result_arr)
|
137
140
|
else
|
@@ -8,21 +8,32 @@ module WebSandboxConsole
|
|
8
8
|
attr_accessor :grep_content # 过滤内容
|
9
9
|
attr_accessor :touch_grep_protect # 是否触发过滤保护
|
10
10
|
attr_accessor :content_is_trimed # 内容是否有裁剪
|
11
|
+
|
12
|
+
# 页面相关提示
|
13
|
+
PageTips = {
|
14
|
+
touch_grep_protect: "由于过滤执行时间太长,已触发过滤保护,返回内容为最后1000行",
|
15
|
+
content_is_trimed: "当前返回内容太多,仅展示满足条件的1000行",
|
16
|
+
is_big_file_return: "当前文件视为大文件,返回最后1000行",
|
17
|
+
special_line_return: "当前按指定行数返回,若未指定行数,则默认返回文件前100行"
|
18
|
+
}.freeze
|
11
19
|
|
12
20
|
def initialize(opts = {})
|
13
21
|
@file_or_dir = opts[:file_or_dir]
|
14
22
|
@start_line_num = (opts[:start_line_num].presence || 1).to_i
|
15
23
|
@end_line_num = (opts[:end_line_num].presence || 100).to_i
|
16
|
-
@sed_start_time =
|
17
|
-
@sed_end_time =
|
24
|
+
@sed_start_time = opts[:sed_start_time]
|
25
|
+
@sed_end_time = opts[:sed_end_time]
|
18
26
|
@grep_content = opts[:grep_content]
|
19
|
-
@touch_grep_protect
|
20
|
-
@content_is_trimed
|
27
|
+
@touch_grep_protect = false
|
28
|
+
@content_is_trimed = false
|
29
|
+
@is_big_file_return = false
|
30
|
+
@special_line_return = false
|
21
31
|
end
|
22
32
|
|
23
33
|
def view
|
24
34
|
begin
|
25
35
|
check_param
|
36
|
+
correction_line_num
|
26
37
|
file_or_dir_exists
|
27
38
|
check_blacklist
|
28
39
|
check_only_view_log
|
@@ -38,6 +49,13 @@ module WebSandboxConsole
|
|
38
49
|
raise ViewFileError, "过滤内容中不能出现单引号" if grep_content.to_s.include?("'")
|
39
50
|
end
|
40
51
|
|
52
|
+
# 纠正起始行数
|
53
|
+
def correction_line_num
|
54
|
+
if @start_line_num > @end_line_num
|
55
|
+
@end_line_num = @start_line_num + 100
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
41
59
|
# 转换成项目路径
|
42
60
|
def project_path(path)
|
43
61
|
"#{Rails.root}/#{path}"
|
@@ -117,11 +135,14 @@ module WebSandboxConsole
|
|
117
135
|
if is_directory?(file_or_dir_path)
|
118
136
|
files_in_dir
|
119
137
|
else # 文件
|
138
|
+
parse_start_and_end_time
|
120
139
|
lines = if need_grep?
|
121
140
|
grep_file_content
|
122
141
|
elsif is_big_file?
|
142
|
+
@is_big_file_return = true
|
123
143
|
tail_any_line(1000)
|
124
144
|
else
|
145
|
+
@special_line_return = true
|
125
146
|
special_line_content
|
126
147
|
end
|
127
148
|
# 修剪行数
|
@@ -131,7 +152,9 @@ module WebSandboxConsole
|
|
131
152
|
lines: add_line_num(lines),
|
132
153
|
total_line_num: cal_file_total_line_num,
|
133
154
|
touch_grep_protect: @touch_grep_protect,
|
134
|
-
content_is_trimed: @content_is_trimed
|
155
|
+
content_is_trimed: @content_is_trimed,
|
156
|
+
is_big_file_return: @is_big_file_return,
|
157
|
+
special_line_return: @special_line_return
|
135
158
|
}
|
136
159
|
end
|
137
160
|
end
|
@@ -210,8 +233,23 @@ module WebSandboxConsole
|
|
210
233
|
|
211
234
|
private
|
212
235
|
# 解析时间
|
213
|
-
def
|
214
|
-
|
236
|
+
def parse_start_and_end_time
|
237
|
+
formatter = datetime_formatter
|
238
|
+
@sed_start_time = DateTime.parse(@sed_start_time).strftime(formatter) rescue nil
|
239
|
+
@sed_end_time = DateTime.parse(@sed_end_time).strftime(formatter) rescue nil
|
240
|
+
end
|
241
|
+
|
242
|
+
# 日志时间格式是否为标准格式
|
243
|
+
def logger_datetime_is_default_formatter
|
244
|
+
# 抽取日志的第二行
|
245
|
+
logger_line = `head -n 2 #{file_or_dir_path} | tail -n 1`
|
246
|
+
datatime_part = logger_line.split(/DEBUG:|INFO:|WARN:|ERROR:|FATAL:|UNKNOWN:/).first.to_s
|
247
|
+
datatime_part.include?("T")
|
248
|
+
end
|
249
|
+
|
250
|
+
# 解析日期格式
|
251
|
+
def datetime_formatter
|
252
|
+
logger_datetime_is_default_formatter ? "%FT%T" : "%F %T"
|
215
253
|
end
|
216
254
|
|
217
255
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web_sandbox_console
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dongmingyan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -38,8 +38,13 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description:
|
42
|
-
|
41
|
+
description: At work, many times, we need to connect to the server to enter the rails
|
42
|
+
c query or some data. When the operator has plenty of time, the situation is relatively
|
43
|
+
good; if an operator is responsible for many servers at the same time, it will waste
|
44
|
+
a lot of time to help with the query; to solve this problem, I want to find a secure
|
45
|
+
and convenient query console, after searching some gem, found and did not meet my
|
46
|
+
expectations gem, so decided to write a related function of the console designed
|
47
|
+
to provide a safe, convenient web.
|
43
48
|
email:
|
44
49
|
- dongmingyan01@gmail.com
|
45
50
|
executables: []
|
@@ -115,5 +120,5 @@ requirements: []
|
|
115
120
|
rubygems_version: 3.0.8
|
116
121
|
signing_key:
|
117
122
|
specification_version: 4
|
118
|
-
summary:
|
123
|
+
summary: A secure, convenient web console
|
119
124
|
test_files: []
|