web_sandbox_console 0.1.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 +143 -6
- data/app/assets/images/web_sandbox_console/logo-icon.png +0 -0
- data/app/assets/javascripts/web_sandbox_console/application.js +0 -1
- data/app/assets/javascripts/web_sandbox_console/code_editor.js +0 -0
- data/app/assets/javascripts/web_sandbox_console/codemirror.js +9778 -0
- data/app/assets/javascripts/web_sandbox_console/matchbrackets.js +158 -0
- data/app/assets/javascripts/web_sandbox_console/ruby.js +298 -0
- data/app/assets/stylesheets/web_sandbox_console/application.css +85 -14
- data/app/assets/stylesheets/web_sandbox_console/codemirror.css +349 -0
- data/app/assets/stylesheets/web_sandbox_console/common.css +231 -0
- data/app/assets/stylesheets/web_sandbox_console/docs.css +274 -0
- data/app/assets/stylesheets/web_sandbox_console/home.css +47 -0
- data/app/assets/stylesheets/web_sandbox_console/lucario.css +45 -0
- data/app/controllers/web_sandbox_console/application_controller.rb +4 -0
- data/app/controllers/web_sandbox_console/authorization_controller.rb +82 -0
- data/app/controllers/web_sandbox_console/home_controller.rb +44 -4
- data/app/views/layouts/web_sandbox_console/application.html.erb +82 -11
- data/app/views/web_sandbox_console/authorization/auth_page.html.erb +33 -0
- data/app/views/web_sandbox_console/home/do_view_file.js.erb +14 -0
- data/app/views/web_sandbox_console/home/download_page.html.erb +22 -0
- data/app/views/web_sandbox_console/home/eval_code.js.erb +1 -1
- data/app/views/web_sandbox_console/home/index.html.erb +34 -7
- data/app/views/web_sandbox_console/home/view_file.html.erb +39 -0
- data/config/routes.rb +12 -0
- data/lib/generators/web_sandbox_console/templates/web_sandbox_console.rb +20 -3
- data/lib/generators/web_sandbox_console/templates/web_sandbox_console.yml +5 -0
- data/lib/generators/web_sandbox_console/web_sandbox_console_generator.rb +5 -0
- data/lib/web_sandbox_console.rb +4 -0
- data/lib/web_sandbox_console/common.rb +29 -8
- data/lib/web_sandbox_console/configuration.rb +9 -1
- data/lib/web_sandbox_console/safe_ruby.rb +116 -16
- data/lib/web_sandbox_console/sandbox.rb +119 -20
- data/lib/web_sandbox_console/sandbox_error.rb +4 -0
- data/lib/web_sandbox_console/version.rb +1 -1
- data/lib/web_sandbox_console/view_file.rb +257 -0
- data/lib/web_sandbox_console/view_file_error.rb +4 -0
- metadata +28 -6
- data/app/jobs/web_sandbox_console/application_job.rb +0 -4
@@ -0,0 +1,39 @@
|
|
1
|
+
<h3>查看文件</h3>
|
2
|
+
<div class="view_file">
|
3
|
+
<%= form_tag do_view_file_path, method: :post, remote: true do %>
|
4
|
+
<table>
|
5
|
+
<tr>
|
6
|
+
<td>文件/目录路径</td>
|
7
|
+
<td>
|
8
|
+
<%= text_field_tag :file_or_dir, nil, class: 'file_or_dir', placeholder: '请输入文件路径...'%>
|
9
|
+
</td>
|
10
|
+
<td>起始行数</td>
|
11
|
+
<td><%= text_field_tag :start_line_num, nil, class: 'h30', placeholder: '默认从第1行开始...' %></td>
|
12
|
+
<td>结束行数</td>
|
13
|
+
<td><%= text_field_tag :end_line_num, nil, class: 'h30', placeholder: '默认从第100行结束...' %></td>
|
14
|
+
|
15
|
+
</tr>
|
16
|
+
<tr>
|
17
|
+
<td>过滤内容</td>
|
18
|
+
<td>
|
19
|
+
<%= text_field_tag :grep_content, nil, class: 'file_or_dir' %>
|
20
|
+
</td>
|
21
|
+
<td>过滤开始时间</td>
|
22
|
+
<td><%= text_field_tag :sed_start_time, nil, class: 'h30', placeholder: Time.current.strftime("%F %T") %></td>
|
23
|
+
|
24
|
+
<td>过滤结束时间</td>
|
25
|
+
<td><%= text_field_tag :sed_end_time, nil, class: 'h30', placeholder: Time.current.strftime("%F %T") %></td>
|
26
|
+
<td><%= submit_tag '提交', data: { disable_with: "已发送,处理中..." }, class: 'view-file-button' %></td>
|
27
|
+
</tr>
|
28
|
+
</table>
|
29
|
+
<% end %>
|
30
|
+
<span class="tip">注意:过滤时将忽略筛选行数;过滤内容中不能出现单引号</span>
|
31
|
+
</div>
|
32
|
+
|
33
|
+
<div class="output-content">
|
34
|
+
|
35
|
+
</div>
|
36
|
+
|
37
|
+
<style type="text/css">
|
38
|
+
|
39
|
+
</style>
|
data/config/routes.rb
CHANGED
@@ -2,4 +2,16 @@ WebSandboxConsole::Engine.routes.draw do
|
|
2
2
|
root "home#index"
|
3
3
|
|
4
4
|
post :eval_code, to: "home#eval_code"
|
5
|
+
get :view_file, to: "home#view_file"
|
6
|
+
post :do_view_file, to: "home#do_view_file"
|
7
|
+
|
8
|
+
# 授权相关
|
9
|
+
get :fetch_token, to: "authorization#fetch_token"
|
10
|
+
get :auth_page, to: "authorization#auth_page"
|
11
|
+
post :auth, to: "authorization#auth"
|
12
|
+
|
13
|
+
# 文件下载
|
14
|
+
get :download_page, to: "home#download_page"
|
15
|
+
get :download, to: "home#download"
|
5
16
|
end
|
17
|
+
|
@@ -1,3 +1,8 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
config_file_path = "#{Rails.root}/config/web_sandbox_console.yml"
|
4
|
+
config_hash = File.exists?(config_file_path) ? YAML.load_file(config_file_path).with_indifferent_access[:web_sandbox_console] : {}
|
5
|
+
|
1
6
|
# web_sandbox_console 配置文件
|
2
7
|
# 以下配置 都是可选的 缺少的情况下用默认值 或者 不生效
|
3
8
|
WebSandboxConsole.setup do |config|
|
@@ -7,8 +12,10 @@ WebSandboxConsole.setup do |config|
|
|
7
12
|
# 配置 ip 白名单
|
8
13
|
# config.ip_whitelist = %w(192.168.23.12 192.145.2.0/24)
|
9
14
|
|
10
|
-
#
|
11
|
-
#
|
15
|
+
# 配置 基本认证 在 config/web_sandbox_console.yml中配置
|
16
|
+
# PS: 1. 即使config/web_sandbox_console.yml文件不存在,也不会有任何使用上的影响,效果相当于没有开启
|
17
|
+
# 2. 下面这行不用注释掉,只要不配置yml文件就行
|
18
|
+
config.http_basic_auth = config_hash[:http_basic_auth]
|
12
19
|
|
13
20
|
# # 配置 黑名单 类方法
|
14
21
|
# config.class_method_blacklist = {File: %i(delete read write),Dir: %i(new delete mkdir)}
|
@@ -16,7 +23,17 @@ WebSandboxConsole.setup do |config|
|
|
16
23
|
# # 配置 黑名单 实例方法
|
17
24
|
# config.instance_method_blacklist = {Kernel: %i(system exec `),File: %i(chmod chown)}
|
18
25
|
|
26
|
+
# 文件黑名单列表 (如果是目录 则目录下所有文件都不可用)目录以 / 结尾
|
27
|
+
# 默认都是项目路径下的
|
28
|
+
# config.view_file_blacklist = %w(config/secrets.yml vendor/)
|
29
|
+
|
30
|
+
# 配置 文件权限,是否仅能查看log文件,默认开启
|
31
|
+
#config.only_view_log_file = false
|
32
|
+
|
33
|
+
# 通过非对称加密方式 升级权限,授权通过后,可获得执行数据权限(PS: 数据操作不再回滚)
|
34
|
+
# PS:配置同 http_basic_auth
|
35
|
+
config.public_key = config_hash[:public_key]
|
36
|
+
|
19
37
|
# # 配置 日志路径 默认路径位于项目下
|
20
38
|
# config.console_log_path = "log/web_sandbox_console.log"
|
21
39
|
end
|
22
|
-
|
@@ -0,0 +1,5 @@
|
|
1
|
+
web_sandbox_console:
|
2
|
+
http_basic_auth:
|
3
|
+
name: dmy
|
4
|
+
password: 123456
|
5
|
+
public_key: "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMbJOE1vQT1jFpaH1GPYzdRJN/\nLh8VePmzXs5BYOLHB0xIjArL1NlXMbCJ+AS2rv3/oHIOdHhEuZw0tmm9DhG100R8\nRjBpsEKCDI88jl9qRkFmD3CVk8XQXv6c2IkRZCYSTvgDkmnKAlORksfw+p0cR2AQ\nlAtAsNsNviKYBzXKfQIDAQAB\n-----END PUBLIC KEY-----\n"
|
@@ -5,4 +5,9 @@ class WebSandboxConsoleGenerator < Rails::Generators::Base
|
|
5
5
|
# 源文件 目标位置
|
6
6
|
copy_file "web_sandbox_console.rb", "config/initializers/web_sandbox_console.rb"
|
7
7
|
end
|
8
|
+
|
9
|
+
# 生成配置yaml文件
|
10
|
+
def copy_config_file
|
11
|
+
copy_file "web_sandbox_console.yml", "config/web_sandbox_console.yml.example"
|
12
|
+
end
|
8
13
|
end
|
data/lib/web_sandbox_console.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
+
require 'fileutils'
|
1
2
|
require "web_sandbox_console/engine"
|
3
|
+
require "web_sandbox_console/sandbox_error"
|
2
4
|
require "web_sandbox_console/configuration"
|
3
5
|
require "web_sandbox_console/common.rb"
|
4
6
|
require "web_sandbox_console/safe_ruby"
|
5
7
|
require "web_sandbox_console/sandbox"
|
8
|
+
require "web_sandbox_console/view_file_error"
|
9
|
+
require "web_sandbox_console/view_file"
|
6
10
|
|
7
11
|
|
8
12
|
module WebSandboxConsole
|
@@ -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
|
@@ -9,13 +9,21 @@ module WebSandboxConsole
|
|
9
9
|
mattr_accessor :class_method_blacklist
|
10
10
|
# 实例方法 黑名单 hash
|
11
11
|
mattr_accessor :instance_method_blacklist
|
12
|
+
# 文件列表 黑名单
|
13
|
+
mattr_accessor :view_file_blacklist
|
14
|
+
# 仅能查看日志文件
|
15
|
+
mattr_accessor :only_view_log_file
|
12
16
|
# 日志路径
|
13
17
|
mattr_accessor :console_log_path
|
14
18
|
# 挂载 引擎路由位置
|
15
19
|
mattr_accessor :mount_engine_route_path
|
20
|
+
# 公钥
|
21
|
+
mattr_accessor :public_key
|
16
22
|
|
17
23
|
# 默认 引擎路由位置
|
18
24
|
@@mount_engine_route_path = '/web_sandbox_console'
|
25
|
+
# 默认 开启仅可查看日志
|
26
|
+
@@only_view_log_file = true
|
19
27
|
|
20
28
|
# 内置 实例方法 黑名单
|
21
29
|
INSTANT_METOD_BUILT_IN_BLACKLIST = {
|
@@ -26,7 +34,7 @@ module WebSandboxConsole
|
|
26
34
|
# 内置 类方法 黑名单
|
27
35
|
CLASS_METHOD_BUILT_IN_BLACKLIST = {
|
28
36
|
Kernel: %i(system exec `),
|
29
|
-
File: %i(chmod chown new
|
37
|
+
File: %i(chmod chown new delete read write open),
|
30
38
|
Dir: %i(new delete mkdir)
|
31
39
|
}
|
32
40
|
|
@@ -5,17 +5,16 @@ module WebSandboxConsole
|
|
5
5
|
sanitize_constants
|
6
6
|
sanitize_instance_methods
|
7
7
|
sanitize_class_methods
|
8
|
+
sanitize_logger_new
|
9
|
+
sanitize_csv
|
10
|
+
compatible_file_cache
|
11
|
+
compatible_i18n_translate
|
12
|
+
blacklist_method_remind
|
8
13
|
end
|
9
14
|
|
10
15
|
# 净化 类方法
|
11
16
|
def sanitize_class_methods
|
12
|
-
|
13
|
-
merge_method_hash(CLASS_METHOD_BUILT_IN_BLACKLIST, class_method_blacklist)
|
14
|
-
else
|
15
|
-
CLASS_METHOD_BUILT_IN_BLACKLIST
|
16
|
-
end
|
17
|
-
|
18
|
-
blacklist.each do |klass, methods|
|
17
|
+
class_method_blacklists.each do |klass, methods|
|
19
18
|
klass = Object.const_get(klass)
|
20
19
|
methods.each do |method|
|
21
20
|
next if klass.singleton_methods.exclude?(method)
|
@@ -26,13 +25,7 @@ module WebSandboxConsole
|
|
26
25
|
|
27
26
|
# 净化 实例方法
|
28
27
|
def sanitize_instance_methods
|
29
|
-
|
30
|
-
merge_method_hash(INSTANT_METOD_BUILT_IN_BLACKLIST,instance_method_blacklist)
|
31
|
-
else
|
32
|
-
INSTANT_METOD_BUILT_IN_BLACKLIST
|
33
|
-
end
|
34
|
-
|
35
|
-
blacklist.each do |klass, methods|
|
28
|
+
instance_method_blacklists.each do |klass, methods|
|
36
29
|
klass = Object.const_get(klass)
|
37
30
|
methods.each do |method|
|
38
31
|
next if (klass != Kernel) && klass.instance_methods.exclude?(method)
|
@@ -41,6 +34,24 @@ module WebSandboxConsole
|
|
41
34
|
end
|
42
35
|
end
|
43
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
|
+
|
44
55
|
# 净化 常量
|
45
56
|
def sanitize_constants
|
46
57
|
return unless constant_blacklist
|
@@ -52,13 +63,13 @@ module WebSandboxConsole
|
|
52
63
|
# 将两个hash 内部数组也同时合并,并去重
|
53
64
|
def merge_method_hash(hash1, hash2)
|
54
65
|
# 格式统一
|
55
|
-
hash2.transform_keys!(&:to_sym).transform_values!{|
|
66
|
+
hash2.transform_keys!(&:to_sym).transform_keys!(&:to_sym).transform_values!{|i| i.map(&:to_sym)}
|
56
67
|
# 共有的key
|
57
68
|
common_keys = hash2.keys & hash1.keys
|
58
69
|
# hash2 特有keys
|
59
70
|
hash2_special_keys = hash2.keys - hash1.keys
|
60
71
|
# 特有keys 直接合到 hash1
|
61
|
-
hash1.merge!(hash2.slice(hash2_special_keys))
|
72
|
+
hash1.merge!(hash2.slice(*hash2_special_keys))
|
62
73
|
# 共用keys 数组去重
|
63
74
|
common_keys.each do |key|
|
64
75
|
hash1[key] = (hash1[key] | hash2[key]).uniq
|
@@ -66,5 +77,94 @@ module WebSandboxConsole
|
|
66
77
|
hash1
|
67
78
|
end
|
68
79
|
|
80
|
+
# 发现代码 中有 Logger.new(Rails.root.join('log', 'hubar')) 写法, 会 触发 File.open方法
|
81
|
+
# 封装后避免调用 File.open(禁用)
|
82
|
+
def sanitize_logger_new
|
83
|
+
Logger.instance_eval do
|
84
|
+
def new(logdev, shift_age = 0, shift_size = 1048576)
|
85
|
+
instance = allocate
|
86
|
+
instance.send(:initialize, logdev.to_s, shift_age, shift_size)
|
87
|
+
instance
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# 净化 csv
|
93
|
+
def sanitize_csv
|
94
|
+
require 'csv' unless defined? CSV
|
95
|
+
|
96
|
+
CSV.instance_eval do
|
97
|
+
# 重写方法 以写日志方式 写数据
|
98
|
+
def open(filename, mode="r", **options)
|
99
|
+
# 无论输入什么路径 都只会在log下创建文件
|
100
|
+
basename = File.basename(filename, ".*")
|
101
|
+
file_path = "#{Rails.root}/log/#{basename}.csv"
|
102
|
+
logger = Logger.new(file_path)
|
103
|
+
logger.formatter = proc {|severity, datetime, progname, msg| msg}
|
104
|
+
|
105
|
+
logger.instance_exec do
|
106
|
+
# 支持类型 csv 数据写入方式
|
107
|
+
def << (data_arr)
|
108
|
+
self.info data_arr.join(",") + "\n"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
yield(logger)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
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
|
+
|
69
169
|
end
|
70
170
|
end
|
@@ -1,47 +1,146 @@
|
|
1
1
|
module WebSandboxConsole
|
2
2
|
class Sandbox
|
3
|
-
attr_accessor :code
|
4
|
-
attr_accessor :uuid
|
3
|
+
attr_accessor :code # 代码
|
4
|
+
attr_accessor :uuid # 唯一标识
|
5
|
+
attr_accessor :pass_auth # 是否通过授权
|
6
|
+
attr_accessor :exe_tmp_file # 执行临时文件(由code 组成的运行代码)
|
5
7
|
|
6
|
-
def initialize(code = nil)
|
7
|
-
@code
|
8
|
-
@uuid
|
8
|
+
def initialize(code = nil, pass_auth = false)
|
9
|
+
@code = code
|
10
|
+
@uuid = SecureRandom.uuid
|
11
|
+
@pass_auth = pass_auth.presence || false
|
12
|
+
@exe_tmp_file = "#{Rails.root}/tmp/sandbox/#{uuid}.rb"
|
9
13
|
end
|
10
14
|
|
15
|
+
# 同步执行
|
11
16
|
def evalotor
|
12
|
-
|
13
|
-
|
17
|
+
evalotor_block do
|
18
|
+
exec_rails_runner
|
19
|
+
get_result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# 异步后台执行
|
24
|
+
def asyn_evalotor
|
25
|
+
evalotor_block do
|
26
|
+
Thread.new {exec_rails_runner}
|
27
|
+
["已在后台执行,请耐心等待😊"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# 执行结构块
|
32
|
+
def evalotor_block
|
33
|
+
begin
|
34
|
+
check_syntax
|
35
|
+
write_exe_tmp_file
|
36
|
+
yield
|
37
|
+
rescue SandboxError => e
|
38
|
+
[e.message]
|
39
|
+
rescue Exception => e
|
40
|
+
["发生未知错误: #{e.inspect};#{e.backtrace[0..2].join('\r\n')}"]
|
41
|
+
end
|
14
42
|
end
|
15
43
|
|
16
44
|
def runner_code
|
17
45
|
str =<<-CODE
|
18
|
-
WebSandboxConsole.init_safe_env
|
19
46
|
result = nil
|
20
47
|
begin
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
48
|
+
WebSandboxConsole.current_uuid("#{self.uuid}")
|
49
|
+
WebSandboxConsole.init_safe_env
|
50
|
+
WebSandboxConsole.logger_sql
|
51
|
+
#{self.pass_auth ? no_rollback_code : rollback_code}
|
25
52
|
rescue Exception => e
|
26
|
-
WebSandboxConsole.log_p(e
|
53
|
+
WebSandboxConsole.log_p(e)
|
27
54
|
rescue SyntaxError => e
|
28
|
-
WebSandboxConsole.log_p(e
|
55
|
+
WebSandboxConsole.log_p(e)
|
29
56
|
end
|
30
|
-
WebSandboxConsole.log_p(result
|
57
|
+
WebSandboxConsole.log_p(result)
|
31
58
|
CODE
|
32
59
|
end
|
33
60
|
|
34
|
-
|
35
|
-
|
61
|
+
# 回滚code
|
62
|
+
def rollback_code
|
63
|
+
<<-EOF
|
64
|
+
ActiveRecord::Base.transaction(requires_new: true) do
|
65
|
+
result = eval(#{self.code.inspect})
|
66
|
+
raise ActiveRecord::Rollback
|
67
|
+
end
|
68
|
+
EOF
|
69
|
+
end
|
70
|
+
|
71
|
+
# 不回滚code
|
72
|
+
def no_rollback_code
|
73
|
+
<<-EOF
|
74
|
+
result = eval(#{self.code.inspect})
|
75
|
+
EOF
|
76
|
+
end
|
77
|
+
|
78
|
+
# 临时文件目录
|
79
|
+
def tmp_file_dir
|
80
|
+
File.dirname(self.exe_tmp_file)
|
81
|
+
end
|
82
|
+
|
83
|
+
# 添加临时文件目录
|
84
|
+
def add_tmp_file_dir
|
85
|
+
FileUtils.mkdir_p(tmp_file_dir) unless File.directory?(tmp_file_dir)
|
86
|
+
end
|
87
|
+
|
88
|
+
# 临时文件 需要清理?
|
89
|
+
def tmp_file_need_clean?
|
90
|
+
Dir["#{tmp_file_dir}/*"].count > 6
|
91
|
+
end
|
92
|
+
|
93
|
+
# 自动删除临时文件
|
94
|
+
def auto_clean_tmp_file
|
95
|
+
FileUtils.rm_rf(Dir["#{tmp_file_dir}/*"]) if tmp_file_need_clean?
|
96
|
+
end
|
97
|
+
|
98
|
+
# 写入 执行临时文件
|
99
|
+
def write_exe_tmp_file
|
100
|
+
add_tmp_file_dir
|
101
|
+
auto_clean_tmp_file
|
102
|
+
File.open(self.exe_tmp_file, 'w'){|f| f << runner_code}
|
103
|
+
end
|
104
|
+
|
105
|
+
# 准备检查语法
|
106
|
+
def prepare_check_syntax
|
107
|
+
add_tmp_file_dir
|
108
|
+
File.open(self.exe_tmp_file, 'w'){|f| f << self.code}
|
109
|
+
end
|
110
|
+
|
111
|
+
# 检查 语法
|
112
|
+
def check_syntax
|
113
|
+
prepare_check_syntax
|
114
|
+
unless `ruby -c #{self.exe_tmp_file}`.include?('Syntax OK')
|
115
|
+
raise SandboxError, "存在语法错误"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# 运行rails runner
|
120
|
+
def exec_rails_runner
|
121
|
+
@stdout = `RAILS_ENV=#{Rails.env} bundle exec rails runner #{self.exe_tmp_file}`
|
122
|
+
end
|
123
|
+
|
124
|
+
# 返回结果
|
125
|
+
def return_result_arr
|
126
|
+
last_10_lines = `tail -n 100 #{WebSandboxConsole.log_path} | grep #{self.uuid}`
|
36
127
|
|
37
128
|
last_10_lines.split("\n").map do |line|
|
38
129
|
line.split("#{self.uuid}:").last.split("|||")
|
39
130
|
end.flatten
|
40
131
|
end
|
41
132
|
|
42
|
-
#
|
43
|
-
def
|
44
|
-
|
133
|
+
# 最终结果
|
134
|
+
def get_result
|
135
|
+
if @stdout.present?
|
136
|
+
stdout_arr = ['------------ 打印值 ----------']
|
137
|
+
stdout_arr.concat(@stdout.to_s.split("\n"))
|
138
|
+
stdout_arr << '------------ 返回值 ----------'
|
139
|
+
stdout_arr.concat(return_result_arr)
|
140
|
+
else
|
141
|
+
return_result_arr
|
142
|
+
end
|
45
143
|
end
|
144
|
+
|
46
145
|
end
|
47
146
|
end
|