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
|
import os
import subprocess
import shlex
from flask import Flask, flash, request, redirect, make_response, url_for
from werkzeug.utils import secure_filename
import subprocess
import resource
# Maximal virtual memory for subprocesses (in bytes).
MAX_VIRTUAL_MEMORY = 20 * 1024 * 1024 # 2 MB
def limit_virtual_memory():
# The tuple below is of the form (soft limit, hard limit). Limit only
# the soft part so that the limit can be increased later (setting also
# the hard limit would prevent that).
# When the limit cannot be changed, setrlimit() raises ValueError.
resource.setrlimit(resource.RLIMIT_AS, (MAX_VIRTUAL_MEMORY, resource.RLIM_INFINITY))
app = Flask(__name__)
PRELUDE = b"""
(defn all-bindings [&] (error "Function all-bindings not allowed"))
(defn all-dynamics [&] (error "Function all-dynamics not allowed"))
(defn bad-compile [&] (error "Function bad-compile not allowed"))
(defn bad-parse [&] (error "Function bad-parse not allowed"))
(defn cli-main [&] (error "Function cli-main not allowed"))
(defn compile [&] (error "Function compile not allowed"))
(defn curenv [&] (error "Function curenv not allowed"))
(defn debug [&] (error "Function debug not allowed"))
(defn debug/arg-stack [&] (error "Function debug/arg-stack not allowed"))
(defn debug/break [&] (error "Function debug/break not allowed"))
(defn debug/fbreak [&] (error "Function debug/fbreak not allowed"))
(defn debug/lineage [&] (error "Function debug/lineage not allowed"))
(defn debug/stack [&] (error "Function debug/stack not allowed"))
(defn debug/stacktrace [&] (error "Function debug/stacktrace not allowed"))
(defn debug/step [&] (error "Function debug/step not allowed"))
(defn debug/unbreak [&] (error "Function debug/unbreak not allowed"))
(defn debug/unfbreak [&] (error "Function debug/unfbreak not allowed"))
(defn debugger-env [&] (error "Function debugger-env not allowed"))
(defn dofile [&] (error "Function dofile not allowed"))
(defn env-lookup [&] (error "Function env-lookup not allowed"))
(defn eval [&] (error "Function eval not allowed"))
(defn eval-string [&] (error "Function eval-string not allowed"))
(defn fiber/getenv [&] (error "Function fiber/getenv not allowed"))
(defn fiber/setenv [&] (error "Function fiber/setenv not allowed"))
(defn file/close [&] (error "Function file/close not allowed"))
(defn file/flush [&] (error "Function file/flush not allowed"))
(defn file/open [&] (error "Function file/open not allowed"))
(defn file/popen [&] (error "Function file/popen not allowed"))
(defn file/read [&] (error "Function file/read not allowed"))
(defn file/seek [&] (error "Function file/seek not allowed"))
(defn file/temp [&] (error "Function file/temp not allowed"))
(defn file/write [&] (error "Function file/write not allowed"))
(defn import [&] (error "Function import not allowed"))
(defn import* [&] (error "Function import* not allowed"))
(defn load-image [&] (error "Function load-image not allowed"))
(defn load-image-dict [&] (error "Function load-image-dict not allowed"))
(defn make-env [&] (error "Function make-env not allowed"))
(defn make-image [&] (error "Function make-image not allowed"))
(defn make-image-dict [&] (error "Function make-image-dict not allowed"))
(defn marshal [&] (error "Function marshal not allowed"))
(defn module/add-paths [&] (error "Function module/add-paths not allowed"))
(defn module/cache [&] (error "Function module/cache not allowed"))
(defn module/expand-path [&] (error "Function module/expand-path not allowed"))
(defn module/find [&] (error "Function module/find not allowed"))
(defn module/loaders [&] (error "Function module/loaders not allowed"))
(defn module/loading [&] (error "Function module/loading not allowed"))
(defn module/paths [&] (error "Function module/paths not allowed"))
(defn net/accept [&] (error "Function net/accept not allowed"))
(defn net/accept-loop [&] (error "Function net/accept-loop not allowed"))
(defn net/address [&] (error "Function net/address not allowed"))
(defn net/chunk [&] (error "Function net/chunk not allowed"))
(defn net/close [&] (error "Function net/close not allowed"))
(defn net/connect [&] (error "Function net/connect not allowed"))
(defn net/flush [&] (error "Function net/flush not allowed"))
(defn net/listen [&] (error "Function net/listen not allowed"))
(defn net/read [&] (error "Function net/read not allowed"))
(defn net/recv-from [&] (error "Function net/recv-from not allowed"))
(defn net/send-to [&] (error "Function net/send-to not allowed"))
(defn net/server [&] (error "Function net/server not allowed"))
(defn net/write [&] (error "Function net/write not allowed"))
(defn os/cd [&] (error "Function os/cd not allowed"))
(defn os/chmod [&] (error "Function os/chmod not allowed"))
(defn os/clock [&] (error "Function os/clock not allowed"))
(defn os/cryptorand [&] (error "Function os/cryptorand not allowed"))
(defn os/cwd [&] (error "Function os/cwd not allowed"))
(defn os/date [&] (error "Function os/date not allowed"))
(defn os/dir [&] (error "Function os/dir not allowed"))
(defn os/environ [&] (error "Function os/environ not allowed"))
(defn os/execute [&] (error "Function os/execute not allowed"))
(defn os/exit [&] (error "Function os/exit not allowed"))
(defn os/getenv [&] (error "Function os/getenv not allowed"))
(defn os/link [&] (error "Function os/link not allowed"))
(defn os/lstat [&] (error "Function os/lstat not allowed"))
(defn os/mkdir [&] (error "Function os/mkdir not allowed"))
(defn os/sleep [&] (error "Function os/sleep not allowed"))
(defn os/mktime [&] (error "Function os/mktime not allowed"))
(defn os/open [&] (error "Function os/open not allowed"))
(defn os/perm-int [&] (error "Function os/perm-int not allowed"))
(defn os/perm-string [&] (error "Function os/perm-string not allowed"))
(defn os/pipe [&] (error "Function os/pipe not allowed"))
(defn os/proc-close [&] (error "Function os/proc-close not allowed"))
(defn os/proc-kill [&] (error "Function os/proc-kill not allowed"))
(defn os/proc-wait [&] (error "Function os/proc-wait not allowed"))
(defn os/readlink [&] (error "Function os/readlink not allowed"))
(defn os/realpath [&] (error "Function os/realpath not allowed"))
(defn os/rename [&] (error "Function os/rename not allowed"))
(defn os/rm [&] (error "Function os/rm not allowed"))
(defn os/rmdir [&] (error "Function os/rmdir not allowed"))
(defn os/setenv [&] (error "Function os/setenv not allowed"))
(defn os/shell [&] (error "Function os/shell not allowed"))
(defn os/spawn [&] (error "Function os/spawn not allowed"))
(defn os/stat [&] (error "Function os/stat not allowed"))
(defn os/symlink [&] (error "Function os/symlink not allowed"))
(defn os/time [&] (error "Function os/time not allowed"))
(defn os/touch [&] (error "Function os/touch not allowed"))
(defn os/umask [&] (error "Function os/umask not allowed"))
(defn os/which [&] (error "Function os/which not allowed"))
(defn repl [&] (error "Function repl not allowed"))
(defn require [&] (error "Function require not allowed"))
(defn root-env [&] (error "Function root-env not allowed"))
(defn run-context [&] (error "Function run-context not allowed"))
(defn signal [&] (error "Function signal not allowed"))
(defn symbol [&] (error "Function symbol not allowed"))
(defn symbol/slice [&] (error "Function symbol/slice not allowed"))
(defn thread/close [&] (error "Function thread/close not allowed"))
(defn thread/current [&] (error "Function thread/current not allowed"))
(defn thread/exit [&] (error "Function thread/exit not allowed"))
(defn thread/new [&] (error "Function thread/new not allowed"))
(defn thread/receive [&] (error "Function thread/receive not allowed"))
(defn thread/send [&] (error "Function thread/send not allowed"))
(defn trace [&] (error "Function trace not allowed"))
(defn tracev [&] (error "Function tracev not allowed"))
(defn unmarshal [&] (error "Function unmarshal not allowed"))
(defn use [&] (error "Function use not allowed"))
"""
PROC = {}
@app.route('/', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
# Limit one process per IP.
if request.remote_addr in PROC:
PROC[request.remote_addr].kill()
del PROC[request.remote_addr]
source_code = request.get_data()
proc = subprocess.Popen(
['build/janet', '/dev/stdin'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
preexec_fn=limit_virtual_memory
)
PROC[request.remote_addr] = proc
result = "Something went wrong..."
try:
result = proc.communicate(input=PRELUDE + source_code, timeout=10*60)
result = result[0]
except Exception:
pass
response = make_response(result, 200)
response.mimetype = "text/plain"
return response
return '''
<!DOCTYPE html>
<html>
<head>
<title>Janet REPL</title>
</head>
<body>
<p>Janet Script:</p>
<textarea cols="80" id="code" name="" rows="10"></textarea>
<br>
<button id="send">Run me!</button>
<p>Program output:</p>
<textarea cols="80" id="response" name="" rows="10" readonly>
Janet 1.1.0-dev-6887dd05 Copyright (C) 2017-2019 Calvin Rose
janet:0:>
</textarea>
<script>
let code = document.getElementById("code");
let response = document.getElementById("response");
let button = document.getElementById("send");
button.addEventListener("click", () => {
let http = new XMLHttpRequest();
let url = '/';
let params = code.value;
http.open('POST', url, true);
// Send the proper header information along with the request
http.setRequestHeader('Content-type', 'text/plain');
http.onreadystatechange = () => {
if (http.readyState == 4 && http.status == 200) {
response.value = http.responseText;
}
}
http.send(params);
});
</script>
</body>
</html>
'''
|