-
Notifications
You must be signed in to change notification settings - Fork 0
/
sandbox.code.js
225 lines (213 loc) · 6.68 KB
/
sandbox.code.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*
* 该文件中的所有代码必须在sandbox中执行
*/
//函数定义中若包含CQ码,可用此原型方法查看
Function.prototype.view = function () {
return this.toString().replace(/[&\[\]]/g, (s) => {
if (s === "&") return "&"
if (s === "[") return "["
if (s === "]") return "]"
})
}
delete globalThis
delete console
const contextify = (o) => {
const contextified = []
const tmp = (o) => {
switch (typeof o) {
case "object":
case "function":
if (o !== null) {
if (contextified.includes(o))
return
Object.freeze(o)
contextified.push(o)
for (let k of Reflect.ownKeys(o)) {
tmp(o[k])
}
}
break
default:
break
}
}
tmp(o)
}
//环境变量
Object.defineProperty(this, "data", {
configurable: false,
enumerable: false,
writable: true,
value: {}
})
const error403 = this.error403 = new Error("403 forbidden")
//群数据库
this.database = this.database && typeof this.database === "object" ? this.database : {}
this.database = new Proxy(this.database, {
get: (o, k) => {
if (parseInt(k) !== this.data.group_id && !this.isMaster())
throw error403
if (!o.hasOwnProperty(k))
o[k] = {}
return o[k]
},
set: (o, k, v, r) => {
throw error403
},
has: (o, k) => {
throw error403
},
deleteProperty: (o, k) => {
throw error403
},
defineProperty: (o, k, d) => {
throw error403
},
ownKeys: (o) => {
if (this.isMaster())
return Reflect.ownKeys(o)
throw error403
},
preventExtensions: (o) => {
throw error403
},
setPrototypeOf: (o, prototype) => {
throw error403
}
})
Object.defineProperty(this, "database", {
configurable: false,
enumerable: true,
writable: false,
value: this.database
})
// set历史记录
this.set_history = this.set_history && typeof this.set_history === "object" ? this.set_history : {}
this.set_history = new Proxy(this.set_history, {
set: (o, k, v) => {
if (!this.set_history_allowed)
throw error403
return Reflect.set(o, k, v)
},
has: (o, k) => {
throw error403
},
deleteProperty: (o, k) => {
throw error403
},
defineProperty: (o, k, d) => {
throw error403
},
ownKeys: (o) => {
if (this.isMaster())
return Reflect.ownKeys(o)
throw error403
},
preventExtensions: (o) => {
throw error403
},
setPrototypeOf: (o, prototype) => {
throw error403
}
})
Object.defineProperty(this, "set_history", {
configurable: false,
enumerable: true,
writable: false,
value: this.set_history
})
Object.defineProperty(this, "recordSetHistory", {
configurable: false,
enumerable: false,
writable: false,
value: (k) => {
if (k !== "data" && this.data.user_id) {
try {
this.set_history[k] = {
qq: this.data.user_id,
name: this.data.sender.nickname,
group: this.data.group_id,
gname: this.data.group_name !== undefined ? this.data.group_name : undefined,
card: this.data.group_id ? this.data.sender.card : undefined,
time: Date.now()
}
} catch (e) { }
}
}
})
//主人qq 必须是包含qq号的字符串
if (typeof this.master !== "string")
this.master = ""
Object.defineProperty(this, "isMaster", {
configurable: false,
enumerable: false,
writable: false,
value: () => {
if (typeof this.root === "string" && this.root.includes(this.data.user_id))
return true
return !this.data.user_id || (typeof this.master === "string" && this.master.includes(this.data.user_id))
}
})
const isMaster = this.isMaster
// 钩子函数
if (typeof this.afterInit !== "function") //sandbox加载之后被执行
this.afterInit = () => { }
if (typeof this.beforeExec !== "function") //用户代码执行之前被执行
this.beforeExec = (code) => { }
if (typeof this.afterExec !== "function") //用户代码执行之后被执行
this.afterExec = (res) => { }
if (typeof this.onEvents !== "function") //所有QQ事件
this.onEvents = () => { }
// 受保护属性只有主人可以设置和删除
// 默认的受保护属性为 master,beforeExec,afterExec,onEvents 四个
// 受保护属性不能是引用类型(对象&数组),只能是基础类型或函数,否则无法被保护
this.protected_properties = this.protected_properties && typeof this.protected_properties === "object" ? this.protected_properties : ["master", "afterInit", "beforeExec", "afterExec", "onEvents"]
this.protected_properties = new Proxy(this.protected_properties, {
set: (o, k, v) => {
if (this.isMaster())
return Reflect.set(o, k, v)
throw error403
},
deleteProperty: (o, k) => {
if (this.isMaster())
return Reflect.deleteProperty(o, k)
throw error403
},
defineProperty: (o, k, d) => {
throw error403
},
preventExtensions: (o) => {
throw error403
},
setPrototypeOf: (o, prototype) => {
throw error403
}
})
Object.defineProperty(this, "protected_properties", {
configurable: false,
enumerable: true,
writable: false,
value: this.protected_properties
})
Object.defineProperty(this, "isProtected", {
configurable: false,
enumerable: false,
writable: false,
value: (k) => {
return this.protected_properties.includes(k)
}
})
const isProtected = this.isProtected
/*
五个主要变量:
● this.master ※主人qq列表(字符串,默认是被保护的),使用this.isMaster()判断是否主人
● this.data ※环境变量
● this.database ※群数据库
● this.set_history ※变量定义历史记录
● this.protected_properties ※受保护的变量(只有master可以修改,this.isProtected()判断是被保护)
钩子事件函数(默认是被保护的,只有master可以修改):
● this.afterInit() ※sandbox加载之后被执行
● this.beforeExec(code) ※执行用户代码之前执行,code是用户代码(如果该函数中抛出未捕获的错误,则用户代码不会被不会执行)
● this.afterExec(res) ※执行用户代码之后执行,res是用户代码执行结果(如果用户代码中抛出未捕获的错误,该函数不会被执行)
● this.onEvents() ※所有qq事件
*/