diff options
-rw-r--r-- | README | 13 | ||||
-rw-r--r-- | cgit.c | 7 | ||||
-rw-r--r-- | cgit.h | 1 | ||||
-rw-r--r-- | cgit.mk | 27 | ||||
-rw-r--r-- | cgitrc.5.txt | 34 | ||||
-rw-r--r-- | filter.c | 255 | ||||
-rw-r--r-- | filters/email-gravatar.lua | 35 | ||||
-rwxr-xr-x | filters/email-gravatar.py | 3 | ||||
-rw-r--r-- | filters/email-libravatar.lua | 36 | ||||
-rw-r--r-- | filters/file-authentication.lua | 359 | ||||
-rw-r--r-- | filters/gentoo-ldap-authentication.lua | 360 | ||||
-rw-r--r-- | filters/owner-example.lua | 17 | ||||
-rw-r--r-- | filters/simple-authentication.lua | 314 | ||||
-rw-r--r-- | tests/filters/dump.lua | 17 | ||||
-rwxr-xr-x | tests/setup.sh | 19 | ||||
-rwxr-xr-x | tests/t0111-filter.sh | 3 |
16 files changed, 0 insertions, 1500 deletions
diff --git a/README b/README index 7a6b4a4..371cf21 100644 --- a/README +++ b/README | |||
@@ -32,18 +32,6 @@ This will install `cgit.cgi` and `cgit.css` into `/var/www/htdocs/cgit`. You | |||
32 | can configure this location (and a few other things) by providing a `cgit.conf` | 32 | can configure this location (and a few other things) by providing a `cgit.conf` |
33 | file (see the Makefile for details). | 33 | file (see the Makefile for details). |
34 | 34 | ||
35 | If you'd like to compile without Lua support, you may use: | ||
36 | |||
37 | $ make NO_LUA=1 | ||
38 | |||
39 | And if you'd like to specify a Lua implementation, you may use: | ||
40 | |||
41 | $ make LUA_PKGCONFIG=lua5.1 | ||
42 | |||
43 | If this is not specified, the Lua implementation will be auto-detected, | ||
44 | preferring LuaJIT if many are present. Acceptable values are generally "lua", | ||
45 | "luajit", "lua5.1", and "lua5.2". | ||
46 | |||
47 | 35 | ||
48 | Dependencies | 36 | Dependencies |
49 | ------------ | 37 | ------------ |
@@ -51,7 +39,6 @@ Dependencies | |||
51 | * libzip | 39 | * libzip |
52 | * libcrypto (OpenSSL) | 40 | * libcrypto (OpenSSL) |
53 | * libssl (OpenSSL) | 41 | * libssl (OpenSSL) |
54 | * optional: luajit or lua, most reliably used when pkg-config is available | ||
55 | 42 | ||
56 | Apache configuration | 43 | Apache configuration |
57 | -------------------- | 44 | -------------------- |
diff --git a/cgit.c b/cgit.c index 40a266b..f3fe4c7 100644 --- a/cgit.c +++ b/cgit.c | |||
@@ -964,12 +964,6 @@ static void cgit_parse_args(int argc, const char **argv) | |||
964 | for (i = 1; i < argc; i++) { | 964 | for (i = 1; i < argc; i++) { |
965 | if (!strcmp(argv[i], "--version")) { | 965 | if (!strcmp(argv[i], "--version")) { |
966 | printf("CGit %s | https://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION); | 966 | printf("CGit %s | https://git.zx2c4.com/cgit/\n\nCompiled in features:\n", CGIT_VERSION); |
967 | #ifdef NO_LUA | ||
968 | printf("[-] "); | ||
969 | #else | ||
970 | printf("[+] "); | ||
971 | #endif | ||
972 | printf("Lua scripting\n"); | ||
973 | #ifndef HAVE_LINUX_SENDFILE | 967 | #ifndef HAVE_LINUX_SENDFILE |
974 | printf("[-] "); | 968 | printf("[-] "); |
975 | #else | 969 | #else |
@@ -1051,7 +1045,6 @@ int cmd_main(int argc, const char **argv) | |||
1051 | const char *path; | 1045 | const char *path; |
1052 | int err, ttl; | 1046 | int err, ttl; |
1053 | 1047 | ||
1054 | cgit_init_filters(); | ||
1055 | atexit(cgit_cleanup_filters); | 1048 | atexit(cgit_cleanup_filters); |
1056 | 1049 | ||
1057 | prepare_context(); | 1050 | prepare_context(); |
diff --git a/cgit.h b/cgit.h index 69b5c13..72fcd84 100644 --- a/cgit.h +++ b/cgit.h | |||
@@ -385,7 +385,6 @@ extern void cgit_fprintf_filter(struct cgit_filter *filter, FILE *f, const char | |||
385 | extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv); | 385 | extern void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **argv); |
386 | extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype); | 386 | extern struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype); |
387 | extern void cgit_cleanup_filters(void); | 387 | extern void cgit_cleanup_filters(void); |
388 | extern void cgit_init_filters(void); | ||
389 | 388 | ||
390 | extern void cgit_prepare_repo_env(struct cgit_repo * repo); | 389 | extern void cgit_prepare_repo_env(struct cgit_repo * repo); |
391 | 390 | ||
diff --git a/cgit.mk b/cgit.mk index 3fcc1ca..5b9ed5b 100644 --- a/cgit.mk +++ b/cgit.mk | |||
@@ -27,32 +27,6 @@ ifdef NO_C99_FORMAT | |||
27 | CFLAGS += -DNO_C99_FORMAT | 27 | CFLAGS += -DNO_C99_FORMAT |
28 | endif | 28 | endif |
29 | 29 | ||
30 | ifdef NO_LUA | ||
31 | LUA_MESSAGE := linking without specified Lua support | ||
32 | CGIT_CFLAGS += -DNO_LUA | ||
33 | else | ||
34 | ifeq ($(LUA_PKGCONFIG),) | ||
35 | LUA_PKGCONFIG := $(shell for pc in luajit lua lua5.2 lua5.1; do \ | ||
36 | $(PKG_CONFIG) --exists $$pc 2>/dev/null && echo $$pc && break; \ | ||
37 | done) | ||
38 | LUA_MODE := autodetected | ||
39 | else | ||
40 | LUA_MODE := specified | ||
41 | endif | ||
42 | ifneq ($(LUA_PKGCONFIG),) | ||
43 | LUA_MESSAGE := linking with $(LUA_MODE) $(LUA_PKGCONFIG) | ||
44 | LUA_LIBS := $(shell $(PKG_CONFIG) --libs $(LUA_PKGCONFIG) 2>/dev/null) | ||
45 | LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKGCONFIG) 2>/dev/null) | ||
46 | CGIT_LIBS += $(LUA_LIBS) | ||
47 | CGIT_CFLAGS += $(LUA_CFLAGS) | ||
48 | else | ||
49 | LUA_MESSAGE := linking without autodetected Lua support | ||
50 | NO_LUA := YesPlease | ||
51 | CGIT_CFLAGS += -DNO_LUA | ||
52 | endif | ||
53 | |||
54 | endif | ||
55 | |||
56 | # Add -ldl to linker flags on systems that commonly use GNU libc. | 30 | # Add -ldl to linker flags on systems that commonly use GNU libc. |
57 | ifneq (,$(filter $(uname_S),Linux GNU GNU/kFreeBSD)) | 31 | ifneq (,$(filter $(uname_S),Linux GNU GNU/kFreeBSD)) |
58 | CGIT_LIBS += -ldl | 32 | CGIT_LIBS += -ldl |
@@ -130,7 +104,6 @@ $(CGIT_OBJS): %.o: %.c GIT-CFLAGS $(CGIT_PREFIX)CGIT-CFLAGS $(missing_dep_dirs) | |||
130 | $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $< | 104 | $(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $< |
131 | 105 | ||
132 | $(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS) | 106 | $(CGIT_PREFIX)cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS) |
133 | @echo 1>&1 " * $(LUA_MESSAGE)" | ||
134 | $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS) | 107 | $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) $(CGIT_LIBS) |
135 | 108 | ||
136 | CGIT_SP_OBJS := $(patsubst %.o,%.sp,$(CGIT_OBJS)) | 109 | CGIT_SP_OBJS := $(patsubst %.o,%.sp,$(CGIT_OBJS)) |
diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 45db6c7..7dd644a 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt | |||
@@ -632,37 +632,6 @@ specification with the relevant string; available values are: | |||
632 | 'exec:':: | 632 | 'exec:':: |
633 | The default "one process per filter" mode. | 633 | The default "one process per filter" mode. |
634 | 634 | ||
635 | 'lua:':: | ||
636 | Executes the script using a built-in Lua interpreter. The script is | ||
637 | loaded once per execution of cgit, and may be called multiple times | ||
638 | during cgit's lifetime, making it a good choice for repeated filters | ||
639 | such as the 'email filter'. It responds to three functions: | ||
640 | |||
641 | 'filter_open(argument1, argument2, argument3, ...)':: | ||
642 | This is called upon activation of the filter for a particular | ||
643 | set of data. | ||
644 | 'filter_write(buffer)':: | ||
645 | This is called whenever cgit writes data to the webpage. | ||
646 | 'filter_close()':: | ||
647 | This is called when the current filtering operation is | ||
648 | completed. It must return an integer value. Usually 0 | ||
649 | indicates success. | ||
650 | |||
651 | Additionally, cgit exposes to the Lua the following built-in functions: | ||
652 | |||
653 | 'html(str)':: | ||
654 | Writes 'str' to the webpage. | ||
655 | 'html_txt(str)':: | ||
656 | HTML escapes and writes 'str' to the webpage. | ||
657 | 'html_attr(str)':: | ||
658 | HTML escapes for an attribute and writes "str' to the webpage. | ||
659 | 'html_url_path(str)':: | ||
660 | URL escapes for a path and writes 'str' to the webpage. | ||
661 | 'html_url_arg(str)':: | ||
662 | URL escapes for an argument and writes 'str' to the webpage. | ||
663 | 'html_include(file)':: | ||
664 | Includes 'file' in webpage. | ||
665 | |||
666 | 635 | ||
667 | Parameters are provided to filters as follows. | 636 | Parameters are provided to filters as follows. |
668 | 637 | ||
@@ -696,9 +665,6 @@ auth filter:: | |||
696 | with a 302 redirect, and write to output one or more "Set-Cookie" | 665 | with a 302 redirect, and write to output one or more "Set-Cookie" |
697 | HTTP headers, each followed by a newline. | 666 | HTTP headers, each followed by a newline. |
698 | 667 | ||
699 | Please see `filters/simple-authentication.lua` for a clear example | ||
700 | script that may be modified. | ||
701 | |||
702 | commit filter:: | 668 | commit filter:: |
703 | This filter is given no arguments. The commit message text that is to | 669 | This filter is given no arguments. The commit message text that is to |
704 | be filtered is available on standard input and the filtered text is | 670 | be filtered is available on standard input and the filtered text is |
diff --git a/filter.c b/filter.c index fba26aa..2b6c838 100644 --- a/filter.c +++ b/filter.c | |||
@@ -8,12 +8,6 @@ | |||
8 | 8 | ||
9 | #include "cgit.h" | 9 | #include "cgit.h" |
10 | #include "html.h" | 10 | #include "html.h" |
11 | #ifndef NO_LUA | ||
12 | #include <dlfcn.h> | ||
13 | #include <lua.h> | ||
14 | #include <lualib.h> | ||
15 | #include <lauxlib.h> | ||
16 | #endif | ||
17 | 11 | ||
18 | static inline void reap_filter(struct cgit_filter *filter) | 12 | static inline void reap_filter(struct cgit_filter *filter) |
19 | { | 13 | { |
@@ -138,252 +132,6 @@ void cgit_exec_filter_init(struct cgit_exec_filter *filter, char *cmd, char **ar | |||
138 | filter->base.argument_count = 0; | 132 | filter->base.argument_count = 0; |
139 | } | 133 | } |
140 | 134 | ||
141 | #ifdef NO_LUA | ||
142 | void cgit_init_filters(void) | ||
143 | { | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | #ifndef NO_LUA | ||
148 | static size_t (*libc_fwrite)(const void *buf, size_t size, size_t n, FILE *); | ||
149 | static ssize_t (*libc_write)(int fd, const void *buf, size_t size); | ||
150 | static ssize_t (*filter_write)(struct cgit_filter *base, const void *buf, size_t count) = NULL; | ||
151 | static struct cgit_filter *current_write_filter = NULL; | ||
152 | |||
153 | void cgit_init_filters(void) | ||
154 | { | ||
155 | /* | ||
156 | * we need to wrap both functions since the Lua filter may | ||
157 | * have code which calls write(2) directly, bypassing fwrite(3) | ||
158 | */ | ||
159 | libc_fwrite = dlsym(RTLD_NEXT, "fwrite"); | ||
160 | if (!libc_fwrite) | ||
161 | die("Could not locate libc's write function"); | ||
162 | libc_write = dlsym(RTLD_NEXT, "write"); | ||
163 | if (!libc_write) | ||
164 | die("Could not locate libc's write function"); | ||
165 | } | ||
166 | |||
167 | size_t fwrite(const void *buf, size_t size, size_t n, FILE *f) | ||
168 | { | ||
169 | if (f != stdout || !filter_write) | ||
170 | return libc_fwrite(buf, size, n, f); | ||
171 | return filter_write(current_write_filter, buf, size * n); | ||
172 | } | ||
173 | |||
174 | ssize_t write(int fd, const void *buf, size_t count) | ||
175 | { | ||
176 | if (fd != STDOUT_FILENO || !filter_write) | ||
177 | return libc_write(fd, buf, count); | ||
178 | return filter_write(current_write_filter, buf, count); | ||
179 | } | ||
180 | |||
181 | static inline void hook_write(struct cgit_filter *filter, ssize_t (*new_write)(struct cgit_filter *base, const void *buf, size_t count)) | ||
182 | { | ||
183 | /* We want to avoid buggy nested patterns. */ | ||
184 | assert(filter_write == NULL); | ||
185 | assert(current_write_filter == NULL); | ||
186 | current_write_filter = filter; | ||
187 | filter_write = new_write; | ||
188 | } | ||
189 | |||
190 | static inline void unhook_write(void) | ||
191 | { | ||
192 | assert(filter_write != NULL); | ||
193 | assert(current_write_filter != NULL); | ||
194 | filter_write = NULL; | ||
195 | current_write_filter = NULL; | ||
196 | } | ||
197 | |||
198 | struct lua_filter { | ||
199 | struct cgit_filter base; | ||
200 | char *script_file; | ||
201 | lua_State *lua_state; | ||
202 | }; | ||
203 | |||
204 | static void error_lua_filter(struct lua_filter *filter) | ||
205 | { | ||
206 | die("Lua error in %s: %s", filter->script_file, lua_tostring(filter->lua_state, -1)); | ||
207 | lua_pop(filter->lua_state, 1); | ||
208 | } | ||
209 | |||
210 | static ssize_t write_lua_filter(struct cgit_filter *base, const void *buf, size_t count) | ||
211 | { | ||
212 | struct lua_filter *filter = (struct lua_filter *)base; | ||
213 | |||
214 | lua_getglobal(filter->lua_state, "filter_write"); | ||
215 | lua_pushlstring(filter->lua_state, buf, count); | ||
216 | if (lua_pcall(filter->lua_state, 1, 0, 0)) { | ||
217 | error_lua_filter(filter); | ||
218 | errno = EIO; | ||
219 | return -1; | ||
220 | } | ||
221 | return count; | ||
222 | } | ||
223 | |||
224 | static inline int hook_lua_filter(lua_State *lua_state, void (*fn)(const char *txt)) | ||
225 | { | ||
226 | const char *str; | ||
227 | ssize_t (*save_filter_write)(struct cgit_filter *base, const void *buf, size_t count); | ||
228 | struct cgit_filter *save_filter; | ||
229 | |||
230 | str = lua_tostring(lua_state, 1); | ||
231 | if (!str) | ||
232 | return 0; | ||
233 | |||
234 | save_filter_write = filter_write; | ||
235 | save_filter = current_write_filter; | ||
236 | unhook_write(); | ||
237 | fn(str); | ||
238 | hook_write(save_filter, save_filter_write); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int html_lua_filter(lua_State *lua_state) | ||
244 | { | ||
245 | return hook_lua_filter(lua_state, html); | ||
246 | } | ||
247 | |||
248 | static int html_txt_lua_filter(lua_State *lua_state) | ||
249 | { | ||
250 | return hook_lua_filter(lua_state, html_txt); | ||
251 | } | ||
252 | |||
253 | static int html_attr_lua_filter(lua_State *lua_state) | ||
254 | { | ||
255 | return hook_lua_filter(lua_state, html_attr); | ||
256 | } | ||
257 | |||
258 | static int html_url_path_lua_filter(lua_State *lua_state) | ||
259 | { | ||
260 | return hook_lua_filter(lua_state, html_url_path); | ||
261 | } | ||
262 | |||
263 | static int html_url_arg_lua_filter(lua_State *lua_state) | ||
264 | { | ||
265 | return hook_lua_filter(lua_state, html_url_arg); | ||
266 | } | ||
267 | |||
268 | static int html_include_lua_filter(lua_State *lua_state) | ||
269 | { | ||
270 | return hook_lua_filter(lua_state, (void (*)(const char *))html_include); | ||
271 | } | ||
272 | |||
273 | static void cleanup_lua_filter(struct cgit_filter *base) | ||
274 | { | ||
275 | struct lua_filter *filter = (struct lua_filter *)base; | ||
276 | |||
277 | if (!filter->lua_state) | ||
278 | return; | ||
279 | |||
280 | lua_close(filter->lua_state); | ||
281 | filter->lua_state = NULL; | ||
282 | if (filter->script_file) { | ||
283 | free(filter->script_file); | ||
284 | filter->script_file = NULL; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static int init_lua_filter(struct lua_filter *filter) | ||
289 | { | ||
290 | if (filter->lua_state) | ||
291 | return 0; | ||
292 | |||
293 | if (!(filter->lua_state = luaL_newstate())) | ||
294 | return 1; | ||
295 | |||
296 | luaL_openlibs(filter->lua_state); | ||
297 | |||
298 | lua_pushcfunction(filter->lua_state, html_lua_filter); | ||
299 | lua_setglobal(filter->lua_state, "html"); | ||
300 | lua_pushcfunction(filter->lua_state, html_txt_lua_filter); | ||
301 | lua_setglobal(filter->lua_state, "html_txt"); | ||
302 | lua_pushcfunction(filter->lua_state, html_attr_lua_filter); | ||
303 | lua_setglobal(filter->lua_state, "html_attr"); | ||
304 | lua_pushcfunction(filter->lua_state, html_url_path_lua_filter); | ||
305 | lua_setglobal(filter->lua_state, "html_url_path"); | ||
306 | lua_pushcfunction(filter->lua_state, html_url_arg_lua_filter); | ||
307 | lua_setglobal(filter->lua_state, "html_url_arg"); | ||
308 | lua_pushcfunction(filter->lua_state, html_include_lua_filter); | ||
309 | lua_setglobal(filter->lua_state, "html_include"); | ||
310 | |||
311 | if (luaL_dofile(filter->lua_state, filter->script_file)) { | ||
312 | error_lua_filter(filter); | ||
313 | lua_close(filter->lua_state); | ||
314 | filter->lua_state = NULL; | ||
315 | return 1; | ||
316 | } | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int open_lua_filter(struct cgit_filter *base, va_list ap) | ||
321 | { | ||
322 | struct lua_filter *filter = (struct lua_filter *)base; | ||
323 | int i; | ||
324 | |||
325 | if (fflush(stdout)) | ||
326 | return 1; | ||
327 | |||
328 | if (init_lua_filter(filter)) | ||
329 | return 1; | ||
330 | |||
331 | hook_write(base, write_lua_filter); | ||
332 | |||
333 | lua_getglobal(filter->lua_state, "filter_open"); | ||
334 | for (i = 0; i < filter->base.argument_count; ++i) | ||
335 | lua_pushstring(filter->lua_state, va_arg(ap, char *)); | ||
336 | if (lua_pcall(filter->lua_state, filter->base.argument_count, 0, 0)) { | ||
337 | error_lua_filter(filter); | ||
338 | return 1; | ||
339 | } | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int close_lua_filter(struct cgit_filter *base) | ||
344 | { | ||
345 | struct lua_filter *filter = (struct lua_filter *)base; | ||
346 | int ret = 0; | ||
347 | |||
348 | lua_getglobal(filter->lua_state, "filter_close"); | ||
349 | if (lua_pcall(filter->lua_state, 0, 1, 0)) { | ||
350 | error_lua_filter(filter); | ||
351 | ret = -1; | ||
352 | } else { | ||
353 | ret = lua_tonumber(filter->lua_state, -1); | ||
354 | lua_pop(filter->lua_state, 1); | ||
355 | } | ||
356 | |||
357 | unhook_write(); | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static void fprintf_lua_filter(struct cgit_filter *base, FILE *f, const char *prefix) | ||
362 | { | ||
363 | struct lua_filter *filter = (struct lua_filter *)base; | ||
364 | fprintf(f, "%slua:%s\n", prefix, filter->script_file); | ||
365 | } | ||
366 | |||
367 | |||
368 | static struct cgit_filter *new_lua_filter(const char *cmd, int argument_count) | ||
369 | { | ||
370 | struct lua_filter *filter; | ||
371 | |||
372 | filter = xmalloc(sizeof(*filter)); | ||
373 | memset(filter, 0, sizeof(*filter)); | ||
374 | filter->base.open = open_lua_filter; | ||
375 | filter->base.close = close_lua_filter; | ||
376 | filter->base.fprintf = fprintf_lua_filter; | ||
377 | filter->base.cleanup = cleanup_lua_filter; | ||
378 | filter->base.argument_count = argument_count; | ||
379 | filter->script_file = xstrdup(cmd); | ||
380 | |||
381 | return &filter->base; | ||
382 | } | ||
383 | |||
384 | #endif | ||
385 | |||
386 | |||
387 | int cgit_open_filter(struct cgit_filter *filter, ...) | 135 | int cgit_open_filter(struct cgit_filter *filter, ...) |
388 | { | 136 | { |
389 | int result; | 137 | int result; |
@@ -415,9 +163,6 @@ static const struct { | |||
415 | struct cgit_filter *(*ctor)(const char *cmd, int argument_count); | 163 | struct cgit_filter *(*ctor)(const char *cmd, int argument_count); |
416 | } filter_specs[] = { | 164 | } filter_specs[] = { |
417 | { "exec", new_exec_filter }, | 165 | { "exec", new_exec_filter }, |
418 | #ifndef NO_LUA | ||
419 | { "lua", new_lua_filter }, | ||
420 | #endif | ||
421 | }; | 166 | }; |
422 | 167 | ||
423 | struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype) | 168 | struct cgit_filter *cgit_new_filter(const char *cmd, filter_type filtertype) |
diff --git a/filters/email-gravatar.lua b/filters/email-gravatar.lua deleted file mode 100644 index c39b490..0000000 --- a/filters/email-gravatar.lua +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | -- This script may be used with the email-filter or repo.email-filter settings in cgitrc. | ||
2 | -- It adds gravatar icons to author names. It is designed to be used with the lua: | ||
3 | -- prefix in filters. It is much faster than the corresponding python script. | ||
4 | -- | ||
5 | -- Requirements: | ||
6 | -- luaossl | ||
7 | -- <http://25thandclement.com/~william/projects/luaossl.html> | ||
8 | -- | ||
9 | |||
10 | local digest = require("openssl.digest") | ||
11 | |||
12 | function md5_hex(input) | ||
13 | local b = digest.new("md5"):final(input) | ||
14 | local x = "" | ||
15 | for i = 1, #b do | ||
16 | x = x .. string.format("%.2x", string.byte(b, i)) | ||
17 | end | ||
18 | return x | ||
19 | end | ||
20 | |||
21 | function filter_open(email, page) | ||
22 | buffer = "" | ||
23 | md5 = md5_hex(email:sub(2, -2):lower()) | ||
24 | end | ||
25 | |||
26 | function filter_close() | ||
27 | html("<img src='//www.gravatar.com/avatar/" .. md5 .. "?s=13&d=retro' width='13' height='13' alt='Gravatar' /> " .. buffer) | ||
28 | return 0 | ||
29 | end | ||
30 | |||
31 | function filter_write(str) | ||
32 | buffer = buffer .. str | ||
33 | end | ||
34 | |||
35 | |||
diff --git a/filters/email-gravatar.py b/filters/email-gravatar.py index d70440e..012113c 100755 --- a/filters/email-gravatar.py +++ b/filters/email-gravatar.py | |||
@@ -1,8 +1,5 @@ | |||
1 | #!/usr/bin/env python3 | 1 | #!/usr/bin/env python3 |
2 | 2 | ||
3 | # Please prefer the email-gravatar.lua using lua: as a prefix over this script. This | ||
4 | # script is very slow, in comparison. | ||
5 | # | ||
6 | # This script may be used with the email-filter or repo.email-filter settings in cgitrc. | 3 | # This script may be used with the email-filter or repo.email-filter settings in cgitrc. |
7 | # | 4 | # |
8 | # The following environment variables can be used to retrieve the configuration | 5 | # The following environment variables can be used to retrieve the configuration |
diff --git a/filters/email-libravatar.lua b/filters/email-libravatar.lua deleted file mode 100644 index 7336baf..0000000 --- a/filters/email-libravatar.lua +++ /dev/null | |||
@@ -1,36 +0,0 @@ | |||
1 | -- This script may be used with the email-filter or repo.email-filter settings in cgitrc. | ||
2 | -- It adds libravatar icons to author names. It is designed to be used with the lua: | ||
3 | -- prefix in filters. | ||
4 | -- | ||
5 | -- Requirements: | ||
6 | -- luaossl | ||
7 | -- <http://25thandclement.com/~william/projects/luaossl.html> | ||
8 | -- | ||
9 | |||
10 | local digest = require("openssl.digest") | ||
11 | |||
12 | function md5_hex(input) | ||
13 | local b = digest.new("md5"):final(input) | ||
14 | local x = "" | ||
15 | for i = 1, #b do | ||
16 | x = x .. string.format("%.2x", string.byte(b, i)) | ||
17 | end | ||
18 | return x | ||
19 | end | ||
20 | |||
21 | function filter_open(email, page) | ||
22 | buffer = "" | ||
23 | md5 = md5_hex(email:sub(2, -2):lower()) | ||
24 | end | ||
25 | |||
26 | function filter_close() | ||
27 | baseurl = os.getenv("HTTPS") and "https://seccdn.libravatar.org/" or "http://cdn.libravatar.org/" | ||
28 | html("<img src='" .. baseurl .. "avatar/" .. md5 .. "?s=13&d=retro' width='13' height='13' alt='Libravatar' /> " .. buffer) | ||
29 | return 0 | ||
30 | end | ||
31 | |||
32 | function filter_write(str) | ||
33 | buffer = buffer .. str | ||
34 | end | ||
35 | |||
36 | |||
diff --git a/filters/file-authentication.lua b/filters/file-authentication.lua deleted file mode 100644 index 0248804..0000000 --- a/filters/file-authentication.lua +++ /dev/null | |||
@@ -1,359 +0,0 @@ | |||
1 | -- This script may be used with the auth-filter. | ||
2 | -- | ||
3 | -- Requirements: | ||
4 | -- luaossl | ||
5 | -- <http://25thandclement.com/~william/projects/luaossl.html> | ||
6 | -- luaposix | ||
7 | -- <https://github.com/luaposix/luaposix> | ||
8 | -- | ||
9 | local sysstat = require("posix.sys.stat") | ||
10 | local unistd = require("posix.unistd") | ||
11 | local rand = require("openssl.rand") | ||
12 | local hmac = require("openssl.hmac") | ||
13 | |||
14 | -- This file should contain a series of lines in the form of: | ||
15 | -- username1:hash1 | ||
16 | -- username2:hash2 | ||
17 | -- username3:hash3 | ||
18 | -- ... | ||
19 | -- Hashes can be generated using something like `mkpasswd -m sha-512 -R 300000`. | ||
20 | -- This file should not be world-readable. | ||
21 | local users_filename = "/etc/cgit-auth/users" | ||
22 | |||
23 | -- This file should contain a series of lines in the form of: | ||
24 | -- groupname1:username1,username2,username3,... | ||
25 | -- ... | ||
26 | local groups_filename = "/etc/cgit-auth/groups" | ||
27 | |||
28 | -- This file should contain a series of lines in the form of: | ||
29 | -- reponame1:groupname1,groupname2,groupname3,... | ||
30 | -- ... | ||
31 | local repos_filename = "/etc/cgit-auth/repos" | ||
32 | |||
33 | -- Set this to a path this script can write to for storing a persistent | ||
34 | -- cookie secret, which should not be world-readable. | ||
35 | local secret_filename = "/var/cache/cgit/auth-secret" | ||
36 | |||
37 | -- | ||
38 | -- | ||
39 | -- Authentication functions follow below. Swap these out if you want different authentication semantics. | ||
40 | -- | ||
41 | -- | ||
42 | |||
43 | -- Looks up a hash for a given user. | ||
44 | function lookup_hash(user) | ||
45 | local line | ||
46 | for line in io.lines(users_filename) do | ||
47 | local u, h = string.match(line, "(.-):(.+)") | ||
48 | if u:lower() == user:lower() then | ||
49 | return h | ||
50 | end | ||
51 | end | ||
52 | return nil | ||
53 | end | ||
54 | |||
55 | -- Looks up users for a given repo. | ||
56 | function lookup_users(repo) | ||
57 | local users = nil | ||
58 | local groups = nil | ||
59 | local line, group, user | ||
60 | for line in io.lines(repos_filename) do | ||
61 | local r, g = string.match(line, "(.-):(.+)") | ||
62 | if r == repo then | ||
63 | groups = { } | ||
64 | for group in string.gmatch(g, "([^,]+)") do | ||
65 | groups[group:lower()] = true | ||
66 | end | ||
67 | break | ||
68 | end | ||
69 | end | ||
70 | if groups == nil then | ||
71 | return nil | ||
72 | end | ||
73 | for line in io.lines(groups_filename) do | ||
74 | local g, u = string.match(line, "(.-):(.+)") | ||
75 | if groups[g:lower()] then | ||
76 | if users == nil then | ||
77 | users = { } | ||
78 | end | ||
79 | for user in string.gmatch(u, "([^,]+)") do | ||
80 | users[user:lower()] = true | ||
81 | end | ||
82 | end | ||
83 | end | ||
84 | return users | ||
85 | end | ||
86 | |||
87 | |||
88 | -- Sets HTTP cookie headers based on post and sets up redirection. | ||
89 | function authenticate_post() | ||
90 | local hash = lookup_hash(post["username"]) | ||
91 | local redirect = validate_value("redirect", post["redirect"]) | ||
92 | |||
93 | if redirect == nil then | ||
94 | not_found() | ||
95 | return 0 | ||
96 | end | ||
97 | |||
98 | redirect_to(redirect) | ||
99 | |||
100 | if hash == nil or hash ~= unistd.crypt(post["password"], hash) then | ||
101 | set_cookie("cgitauth", "") | ||
102 | else | ||
103 | -- One week expiration time | ||
104 | local username = secure_value("username", post["username"], os.time() + 604800) | ||
105 | set_cookie("cgitauth", username) | ||
106 | end | ||
107 | |||
108 | html("\n") | ||
109 | return 0 | ||
110 | end | ||
111 | |||
112 | |||
113 | -- Returns 1 if the cookie is valid and 0 if it is not. | ||
114 | function authenticate_cookie() | ||
115 | accepted_users = lookup_users(cgit["repo"]) | ||
116 | if accepted_users == nil then | ||
117 | -- We return as valid if the repo is not protected. | ||
118 | return 1 | ||
119 | end | ||
120 | |||
121 | local username = validate_value("username", get_cookie(http["cookie"], "cgitauth")) | ||
122 | if username == nil or not accepted_users[username:lower()] then | ||
123 | return 0 | ||
124 | else | ||
125 | return 1 | ||
126 | end | ||
127 | end | ||
128 | |||
129 | -- Prints the html for the login form. | ||
130 | function body() | ||
131 | html("<h2>Authentication Required</h2>") | ||
132 | html("<form method='post' action='") | ||
133 | html_attr(cgit["login"]) | ||
134 | html("'>") | ||
135 | html("<input type='hidden' name='redirect' value='") | ||
136 | html_attr(secure_value("redirect", cgit["url"], 0)) | ||
137 | html("' />") | ||
138 | html("<table>") | ||
139 | html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>") | ||
140 | html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>") | ||
141 | html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>") | ||
142 | html("</table></form>") | ||
143 | |||
144 | return 0 | ||
145 | end | ||
146 | |||
147 | |||
148 | |||
149 | -- | ||
150 | -- | ||
151 | -- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions. | ||
152 | -- | ||
153 | -- | ||
154 | |||
155 | local actions = {} | ||
156 | actions["authenticate-post"] = authenticate_post | ||
157 | actions["authenticate-cookie"] = authenticate_cookie | ||
158 | actions["body"] = body | ||
159 | |||
160 | function filter_open(...) | ||
161 | action = actions[select(1, ...)] | ||
162 | |||
163 | http = {} | ||
164 | http["cookie"] = select(2, ...) | ||
165 | http["method"] = select(3, ...) | ||
166 | http["query"] = select(4, ...) | ||
167 | http["referer"] = select(5, ...) | ||
168 | http["path"] = select(6, ...) | ||
169 | http["host"] = select(7, ...) | ||
170 | http["https"] = select(8, ...) | ||
171 | |||
172 | cgit = {} | ||
173 | cgit["repo"] = select(9, ...) | ||
174 | cgit["page"] = select(10, ...) | ||
175 | cgit["url"] = select(11, ...) | ||
176 | cgit["login"] = select(12, ...) | ||
177 | |||
178 | end | ||
179 | |||
180 | function filter_close() | ||
181 | return action() | ||
182 | end | ||
183 | |||
184 | function filter_write(str) | ||
185 | post = parse_qs(str) | ||
186 | end | ||
187 | |||
188 | |||
189 | -- | ||
190 | -- | ||
191 | -- Utility functions based on keplerproject/wsapi. | ||
192 | -- | ||
193 | -- | ||
194 | |||
195 | function url_decode(str) | ||
196 | if not str then | ||
197 | return "" | ||
198 | end | ||
199 | str = string.gsub(str, "+", " ") | ||
200 | str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) | ||
201 | str = string.gsub(str, "\r\n", "\n") | ||
202 | return str | ||
203 | end | ||
204 | |||
205 | function url_encode(str) | ||
206 | if not str then | ||
207 | return "" | ||
208 | end | ||
209 | str = string.gsub(str, "\n", "\r\n") | ||
210 | str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end) | ||
211 | str = string.gsub(str, " ", "+") | ||
212 | return str | ||
213 | end | ||
214 | |||
215 | function parse_qs(qs) | ||
216 | local tab = {} | ||
217 | for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do | ||
218 | tab[url_decode(key)] = url_decode(val) | ||
219 | end | ||
220 | return tab | ||
221 | end | ||
222 | |||
223 | function get_cookie(cookies, name) | ||
224 | cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";") | ||
225 | return url_decode(string.match(cookies, ";" .. name .. "=(.-);")) | ||
226 | end | ||
227 | |||
228 | function tohex(b) | ||
229 | local x = "" | ||
230 | for i = 1, #b do | ||
231 | x = x .. string.format("%.2x", string.byte(b, i)) | ||
232 | end | ||
233 | return x | ||
234 | end | ||
235 | |||
236 | -- | ||
237 | -- | ||
238 | -- Cookie construction and validation helpers. | ||
239 | -- | ||
240 | -- | ||
241 | |||
242 | local secret = nil | ||
243 | |||
244 | -- Loads a secret from a file, creates a secret, or returns one from memory. | ||
245 | function get_secret() | ||
246 | if secret ~= nil then | ||
247 | return secret | ||
248 | end | ||
249 | local secret_file = io.open(secret_filename, "r") | ||
250 | if secret_file == nil then | ||
251 | local old_umask = sysstat.umask(63) | ||
252 | local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) | ||
253 | local temporary_file = io.open(temporary_filename, "w") | ||
254 | if temporary_file == nil then | ||
255 | os.exit(177) | ||
256 | end | ||
257 | temporary_file:write(tohex(rand.bytes(32))) | ||
258 | temporary_file:close() | ||
259 | unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. | ||
260 | unistd.unlink(temporary_filename) | ||
261 | sysstat.umask(old_umask) | ||
262 | secret_file = io.open(secret_filename, "r") | ||
263 | end | ||
264 | if secret_file == nil then | ||
265 | os.exit(177) | ||
266 | end | ||
267 | secret = secret_file:read() | ||
268 | secret_file:close() | ||
269 | if secret:len() ~= 64 then | ||
270 | os.exit(177) | ||
271 | end | ||
272 | return secret | ||
273 | end | ||
274 | |||
275 | -- Returns value of cookie if cookie is valid. Otherwise returns nil. | ||
276 | function validate_value(expected_field, cookie) | ||
277 | local i = 0 | ||
278 | local value = "" | ||
279 | local field = "" | ||
280 | local expiration = 0 | ||
281 | local salt = "" | ||
282 | local chmac = "" | ||
283 | |||
284 | if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then | ||
285 | return nil | ||
286 | end | ||
287 | |||
288 | for component in string.gmatch(cookie, "[^|]+") do | ||
289 | if i == 0 then | ||
290 | field = component | ||
291 | elseif i == 1 then | ||
292 | value = component | ||
293 | elseif i == 2 then | ||
294 | expiration = tonumber(component) | ||
295 | if expiration == nil then | ||
296 | expiration = -1 | ||
297 | end | ||
298 | elseif i == 3 then | ||
299 | salt = component | ||
300 | elseif i == 4 then | ||
301 | chmac = component | ||
302 | else | ||
303 | break | ||
304 | end | ||
305 | i = i + 1 | ||
306 | end | ||
307 | |||
308 | if chmac == nil or chmac:len() == 0 then | ||
309 | return nil | ||
310 | end | ||
311 | |||
312 | -- Lua hashes strings, so these comparisons are time invariant. | ||
313 | if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then | ||
314 | return nil | ||
315 | end | ||
316 | |||
317 | if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then | ||
318 | return nil | ||
319 | end | ||
320 | |||
321 | if url_decode(field) ~= expected_field then | ||
322 | return nil | ||
323 | end | ||
324 | |||
325 | return url_decode(value) | ||
326 | end | ||
327 | |||
328 | function secure_value(field, value, expiration) | ||
329 | if value == nil or value:len() <= 0 then | ||
330 | return "" | ||
331 | end | ||
332 | |||
333 | local authstr = "" | ||
334 | local salt = tohex(rand.bytes(16)) | ||
335 | value = url_encode(value) | ||
336 | field = url_encode(field) | ||
337 | authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt | ||
338 | authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) | ||
339 | return authstr | ||
340 | end | ||
341 | |||
342 | function set_cookie(cookie, value) | ||
343 | html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly") | ||
344 | if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then | ||
345 | html("; secure") | ||
346 | end | ||
347 | html("\n") | ||
348 | end | ||
349 | |||
350 | function redirect_to(url) | ||
351 | html("Status: 302 Redirect\n") | ||
352 | html("Cache-Control: no-cache, no-store\n") | ||
353 | html("Location: " .. url .. "\n") | ||
354 | end | ||
355 | |||
356 | function not_found() | ||
357 | html("Status: 404 Not Found\n") | ||
358 | html("Cache-Control: no-cache, no-store\n\n") | ||
359 | end | ||
diff --git a/filters/gentoo-ldap-authentication.lua b/filters/gentoo-ldap-authentication.lua deleted file mode 100644 index 673c88d..0000000 --- a/filters/gentoo-ldap-authentication.lua +++ /dev/null | |||
@@ -1,360 +0,0 @@ | |||
1 | -- This script may be used with the auth-filter. Be sure to configure it as you wish. | ||
2 | -- | ||
3 | -- Requirements: | ||
4 | -- luaossl | ||
5 | -- <http://25thandclement.com/~william/projects/luaossl.html> | ||
6 | -- lualdap >= 1.2 | ||
7 | -- <https://git.zx2c4.com/lualdap/about/> | ||
8 | -- luaposix | ||
9 | -- <https://github.com/luaposix/luaposix> | ||
10 | -- | ||
11 | local sysstat = require("posix.sys.stat") | ||
12 | local unistd = require("posix.unistd") | ||
13 | local lualdap = require("lualdap") | ||
14 | local rand = require("openssl.rand") | ||
15 | local hmac = require("openssl.hmac") | ||
16 | |||
17 | -- | ||
18 | -- | ||
19 | -- Configure these variables for your settings. | ||
20 | -- | ||
21 | -- | ||
22 | |||
23 | -- A list of password protected repositories, with which gentooAccess | ||
24 | -- group is allowed to access each one. | ||
25 | local protected_repos = { | ||
26 | glouglou = "infra", | ||
27 | portage = "dev" | ||
28 | } | ||
29 | |||
30 | -- Set this to a path this script can write to for storing a persistent | ||
31 | -- cookie secret, which should be guarded. | ||
32 | local secret_filename = "/var/cache/cgit/auth-secret" | ||
33 | |||
34 | |||
35 | -- | ||
36 | -- | ||
37 | -- Authentication functions follow below. Swap these out if you want different authentication semantics. | ||
38 | -- | ||
39 | -- | ||
40 | |||
41 | -- Sets HTTP cookie headers based on post and sets up redirection. | ||
42 | function authenticate_post() | ||
43 | local redirect = validate_value("redirect", post["redirect"]) | ||
44 | |||
45 | if redirect == nil then | ||
46 | not_found() | ||
47 | return 0 | ||
48 | end | ||
49 | |||
50 | redirect_to(redirect) | ||
51 | |||
52 | local groups = gentoo_ldap_user_groups(post["username"], post["password"]) | ||
53 | if groups == nil then | ||
54 | set_cookie("cgitauth", "") | ||
55 | else | ||
56 | -- One week expiration time | ||
57 | set_cookie("cgitauth", secure_value("gentoogroups", table.concat(groups, ","), os.time() + 604800)) | ||
58 | end | ||
59 | |||
60 | html("\n") | ||
61 | return 0 | ||
62 | end | ||
63 | |||
64 | |||
65 | -- Returns 1 if the cookie is valid and 0 if it is not. | ||
66 | function authenticate_cookie() | ||
67 | local required_group = protected_repos[cgit["repo"]] | ||
68 | if required_group == nil then | ||
69 | -- We return as valid if the repo is not protected. | ||
70 | return 1 | ||
71 | end | ||
72 | |||
73 | local user_groups = validate_value("gentoogroups", get_cookie(http["cookie"], "cgitauth")) | ||
74 | if user_groups == nil or user_groups == "" then | ||
75 | return 0 | ||
76 | end | ||
77 | for group in string.gmatch(user_groups, "[^,]+") do | ||
78 | if group == required_group then | ||
79 | return 1 | ||
80 | end | ||
81 | end | ||
82 | return 0 | ||
83 | end | ||
84 | |||
85 | -- Prints the html for the login form. | ||
86 | function body() | ||
87 | html("<h2>Gentoo LDAP Authentication Required</h2>") | ||
88 | html("<form method='post' action='") | ||
89 | html_attr(cgit["login"]) | ||
90 | html("'>") | ||
91 | html("<input type='hidden' name='redirect' value='") | ||
92 | html_attr(secure_value("redirect", cgit["url"], 0)) | ||
93 | html("' />") | ||
94 | html("<table>") | ||
95 | html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>") | ||
96 | html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>") | ||
97 | html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>") | ||
98 | html("</table></form>") | ||
99 | |||
100 | return 0 | ||
101 | end | ||
102 | |||
103 | -- | ||
104 | -- | ||
105 | -- Gentoo LDAP support. | ||
106 | -- | ||
107 | -- | ||
108 | |||
109 | function gentoo_ldap_user_groups(username, password) | ||
110 | -- Ensure the user is alphanumeric | ||
111 | if username == nil or username:match("%W") then | ||
112 | return nil | ||
113 | end | ||
114 | |||
115 | local who = "uid=" .. username .. ",ou=devs,dc=gentoo,dc=org" | ||
116 | |||
117 | local ldap, err = lualdap.open_simple { | ||
118 | uri = "ldap://ldap1.gentoo.org", | ||
119 | who = who, | ||
120 | password = password, | ||
121 | starttls = true, | ||
122 | certfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.crt", | ||
123 | keyfile = "/var/www/uwsgi/cgit/gentoo-ldap/star.gentoo.org.key", | ||
124 | cacertfile = "/var/www/uwsgi/cgit/gentoo-ldap/ca.pem" | ||
125 | } | ||
126 | if ldap == nil then | ||
127 | return nil | ||
128 | end | ||
129 | |||
130 | local group_suffix = ".group" | ||
131 | local group_suffix_len = group_suffix:len() | ||
132 | local groups = {} | ||
133 | for dn, attribs in ldap:search { base = who, scope = "subtree" } do | ||
134 | local access = attribs["gentooAccess"] | ||
135 | if dn == who and access ~= nil then | ||
136 | for i, v in ipairs(access) do | ||
137 | local vlen = v:len() | ||
138 | if vlen > group_suffix_len and v:sub(-group_suffix_len) == group_suffix then | ||
139 | table.insert(groups, v:sub(1, vlen - group_suffix_len)) | ||
140 | end | ||
141 | end | ||
142 | end | ||
143 | end | ||
144 | |||
145 | ldap:close() | ||
146 | |||
147 | return groups | ||
148 | end | ||
149 | |||
150 | -- | ||
151 | -- | ||
152 | -- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions. | ||
153 | -- | ||
154 | -- | ||
155 | |||
156 | local actions = {} | ||
157 | actions["authenticate-post"] = authenticate_post | ||
158 | actions["authenticate-cookie"] = authenticate_cookie | ||
159 | actions["body"] = body | ||
160 | |||
161 | function filter_open(...) | ||
162 | action = actions[select(1, ...)] | ||
163 | |||
164 | http = {} | ||
165 | http["cookie"] = select(2, ...) | ||
166 | http["method"] = select(3, ...) | ||
167 | http["query"] = select(4, ...) | ||
168 | http["referer"] = select(5, ...) | ||
169 | http["path"] = select(6, ...) | ||
170 | http["host"] = select(7, ...) | ||
171 | http["https"] = select(8, ...) | ||
172 | |||
173 | cgit = {} | ||
174 | cgit["repo"] = select(9, ...) | ||
175 | cgit["page"] = select(10, ...) | ||
176 | cgit["url"] = select(11, ...) | ||
177 | cgit["login"] = select(12, ...) | ||
178 | |||
179 | end | ||
180 | |||
181 | function filter_close() | ||
182 | return action() | ||
183 | end | ||
184 | |||
185 | function filter_write(str) | ||
186 | post = parse_qs(str) | ||
187 | end | ||
188 | |||
189 | |||
190 | -- | ||
191 | -- | ||
192 | -- Utility functions based on keplerproject/wsapi. | ||
193 | -- | ||
194 | -- | ||
195 | |||
196 | function url_decode(str) | ||
197 | if not str then | ||
198 | return "" | ||
199 | end | ||
200 | str = string.gsub(str, "+", " ") | ||
201 | str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) | ||
202 | str = string.gsub(str, "\r\n", "\n") | ||
203 | return str | ||
204 | end | ||
205 | |||
206 | function url_encode(str) | ||
207 | if not str then | ||
208 | return "" | ||
209 | end | ||
210 | str = string.gsub(str, "\n", "\r\n") | ||
211 | str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end) | ||
212 | str = string.gsub(str, " ", "+") | ||
213 | return str | ||
214 | end | ||
215 | |||
216 | function parse_qs(qs) | ||
217 | local tab = {} | ||
218 | for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do | ||
219 | tab[url_decode(key)] = url_decode(val) | ||
220 | end | ||
221 | return tab | ||
222 | end | ||
223 | |||
224 | function get_cookie(cookies, name) | ||
225 | cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";") | ||
226 | return string.match(cookies, ";" .. name .. "=(.-);") | ||
227 | end | ||
228 | |||
229 | function tohex(b) | ||
230 | local x = "" | ||
231 | for i = 1, #b do | ||
232 | x = x .. string.format("%.2x", string.byte(b, i)) | ||
233 | end | ||
234 | return x | ||
235 | end | ||
236 | |||
237 | -- | ||
238 | -- | ||
239 | -- Cookie construction and validation helpers. | ||
240 | -- | ||
241 | -- | ||
242 | |||
243 | local secret = nil | ||
244 | |||
245 | -- Loads a secret from a file, creates a secret, or returns one from memory. | ||
246 | function get_secret() | ||
247 | if secret ~= nil then | ||
248 | return secret | ||
249 | end | ||
250 | local secret_file = io.open(secret_filename, "r") | ||
251 | if secret_file == nil then | ||
252 | local old_umask = sysstat.umask(63) | ||
253 | local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) | ||
254 | local temporary_file = io.open(temporary_filename, "w") | ||
255 | if temporary_file == nil then | ||
256 | os.exit(177) | ||
257 | end | ||
258 | temporary_file:write(tohex(rand.bytes(32))) | ||
259 | temporary_file:close() | ||
260 | unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. | ||
261 | unistd.unlink(temporary_filename) | ||
262 | sysstat.umask(old_umask) | ||
263 | secret_file = io.open(secret_filename, "r") | ||
264 | end | ||
265 | if secret_file == nil then | ||
266 | os.exit(177) | ||
267 | end | ||
268 | secret = secret_file:read() | ||
269 | secret_file:close() | ||
270 | if secret:len() ~= 64 then | ||
271 | os.exit(177) | ||
272 | end | ||
273 | return secret | ||
274 | end | ||
275 | |||
276 | -- Returns value of cookie if cookie is valid. Otherwise returns nil. | ||
277 | function validate_value(expected_field, cookie) | ||
278 | local i = 0 | ||
279 | local value = "" | ||
280 | local field = "" | ||
281 | local expiration = 0 | ||
282 | local salt = "" | ||
283 | local chmac = "" | ||
284 | |||
285 | if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then | ||
286 | return nil | ||
287 | end | ||
288 | |||
289 | for component in string.gmatch(cookie, "[^|]+") do | ||
290 | if i == 0 then | ||
291 | field = component | ||
292 | elseif i == 1 then | ||
293 | value = component | ||
294 | elseif i == 2 then | ||
295 | expiration = tonumber(component) | ||
296 | if expiration == nil then | ||
297 | expiration = -1 | ||
298 | end | ||
299 | elseif i == 3 then | ||
300 | salt = component | ||
301 | elseif i == 4 then | ||
302 | chmac = component | ||
303 | else | ||
304 | break | ||
305 | end | ||
306 | i = i + 1 | ||
307 | end | ||
308 | |||
309 | if chmac == nil or chmac:len() == 0 then | ||
310 | return nil | ||
311 | end | ||
312 | |||
313 | -- Lua hashes strings, so these comparisons are time invariant. | ||
314 | if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then | ||
315 | return nil | ||
316 | end | ||
317 | |||
318 | if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then | ||
319 | return nil | ||
320 | end | ||
321 | |||
322 | if url_decode(field) ~= expected_field then | ||
323 | return nil | ||
324 | end | ||
325 | |||
326 | return url_decode(value) | ||
327 | end | ||
328 | |||
329 | function secure_value(field, value, expiration) | ||
330 | if value == nil or value:len() <= 0 then | ||
331 | return "" | ||
332 | end | ||
333 | |||
334 | local authstr = "" | ||
335 | local salt = tohex(rand.bytes(16)) | ||
336 | value = url_encode(value) | ||
337 | field = url_encode(field) | ||
338 | authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt | ||
339 | authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) | ||
340 | return authstr | ||
341 | end | ||
342 | |||
343 | function set_cookie(cookie, value) | ||
344 | html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly") | ||
345 | if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then | ||
346 | html("; secure") | ||
347 | end | ||
348 | html("\n") | ||
349 | end | ||
350 | |||
351 | function redirect_to(url) | ||
352 | html("Status: 302 Redirect\n") | ||
353 | html("Cache-Control: no-cache, no-store\n") | ||
354 | html("Location: " .. url .. "\n") | ||
355 | end | ||
356 | |||
357 | function not_found() | ||
358 | html("Status: 404 Not Found\n") | ||
359 | html("Cache-Control: no-cache, no-store\n\n") | ||
360 | end | ||
diff --git a/filters/owner-example.lua b/filters/owner-example.lua deleted file mode 100644 index 50fc25a..0000000 --- a/filters/owner-example.lua +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | -- This script is an example of an owner-filter. It replaces the | ||
2 | -- usual query link with one to a fictional homepage. This script may | ||
3 | -- be used with the owner-filter or repo.owner-filter settings in | ||
4 | -- cgitrc with the `lua:` prefix. | ||
5 | |||
6 | function filter_open() | ||
7 | buffer = "" | ||
8 | end | ||
9 | |||
10 | function filter_close() | ||
11 | html(string.format("<a href=\"%s\">%s</a>", "http://wiki.example.com/about/" .. buffer, buffer)) | ||
12 | return 0 | ||
13 | end | ||
14 | |||
15 | function filter_write(str) | ||
16 | buffer = buffer .. str | ||
17 | end | ||
diff --git a/filters/simple-authentication.lua b/filters/simple-authentication.lua deleted file mode 100644 index 23d3457..0000000 --- a/filters/simple-authentication.lua +++ /dev/null | |||
@@ -1,314 +0,0 @@ | |||
1 | -- This script may be used with the auth-filter. Be sure to configure it as you wish. | ||
2 | -- | ||
3 | -- Requirements: | ||
4 | -- luaossl | ||
5 | -- <http://25thandclement.com/~william/projects/luaossl.html> | ||
6 | -- luaposix | ||
7 | -- <https://github.com/luaposix/luaposix> | ||
8 | -- | ||
9 | local sysstat = require("posix.sys.stat") | ||
10 | local unistd = require("posix.unistd") | ||
11 | local rand = require("openssl.rand") | ||
12 | local hmac = require("openssl.hmac") | ||
13 | |||
14 | -- | ||
15 | -- | ||
16 | -- Configure these variables for your settings. | ||
17 | -- | ||
18 | -- | ||
19 | |||
20 | -- A list of password protected repositories along with the users who can access them. | ||
21 | local protected_repos = { | ||
22 | glouglou = { laurent = true, jason = true }, | ||
23 | qt = { jason = true, bob = true } | ||
24 | } | ||
25 | |||
26 | -- A list of users and hashes, generated with `mkpasswd -m sha-512 -R 300000`. | ||
27 | local users = { | ||
28 | jason = "$6$rounds=300000$YYJct3n/o.ruYK$HhpSeuCuW1fJkpvMZOZzVizeLsBKcGA/aF2UPuV5v60JyH2MVSG6P511UMTj2F3H75.IT2HIlnvXzNb60FcZH1", | ||
29 | laurent = "$6$rounds=300000$dP0KNHwYb3JKigT$pN/LG7rWxQ4HniFtx5wKyJXBJUKP7R01zTNZ0qSK/aivw8ywGAOdfYiIQFqFhZFtVGvr11/7an.nesvm8iJUi.", | ||
30 | bob = "$6$rounds=300000$jCLCCt6LUpTz$PI1vvd1yaVYcCzqH8QAJFcJ60b6W/6sjcOsU7mAkNo7IE8FRGW1vkjF8I/T5jt/auv5ODLb1L4S2s.CAyZyUC" | ||
31 | } | ||
32 | |||
33 | -- Set this to a path this script can write to for storing a persistent | ||
34 | -- cookie secret, which should be guarded. | ||
35 | local secret_filename = "/var/cache/cgit/auth-secret" | ||
36 | |||
37 | -- | ||
38 | -- | ||
39 | -- Authentication functions follow below. Swap these out if you want different authentication semantics. | ||
40 | -- | ||
41 | -- | ||
42 | |||
43 | -- Sets HTTP cookie headers based on post and sets up redirection. | ||
44 | function authenticate_post() | ||
45 | local hash = users[post["username"]] | ||
46 | local redirect = validate_value("redirect", post["redirect"]) | ||
47 | |||
48 | if redirect == nil then | ||
49 | not_found() | ||
50 | return 0 | ||
51 | end | ||
52 | |||
53 | redirect_to(redirect) | ||
54 | |||
55 | if hash == nil or hash ~= unistd.crypt(post["password"], hash) then | ||
56 | set_cookie("cgitauth", "") | ||
57 | else | ||
58 | -- One week expiration time | ||
59 | local username = secure_value("username", post["username"], os.time() + 604800) | ||
60 | set_cookie("cgitauth", username) | ||
61 | end | ||
62 | |||
63 | html("\n") | ||
64 | return 0 | ||
65 | end | ||
66 | |||
67 | |||
68 | -- Returns 1 if the cookie is valid and 0 if it is not. | ||
69 | function authenticate_cookie() | ||
70 | accepted_users = protected_repos[cgit["repo"]] | ||
71 | if accepted_users == nil then | ||
72 | -- We return as valid if the repo is not protected. | ||
73 | return 1 | ||
74 | end | ||
75 | |||
76 | local username = validate_value("username", get_cookie(http["cookie"], "cgitauth")) | ||
77 | if username == nil or not accepted_users[username:lower()] then | ||
78 | return 0 | ||
79 | else | ||
80 | return 1 | ||
81 | end | ||
82 | end | ||
83 | |||
84 | -- Prints the html for the login form. | ||
85 | function body() | ||
86 | html("<h2>Authentication Required</h2>") | ||
87 | html("<form method='post' action='") | ||
88 | html_attr(cgit["login"]) | ||
89 | html("'>") | ||
90 | html("<input type='hidden' name='redirect' value='") | ||
91 | html_attr(secure_value("redirect", cgit["url"], 0)) | ||
92 | html("' />") | ||
93 | html("<table>") | ||
94 | html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autofocus /></td></tr>") | ||
95 | html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' /></td></tr>") | ||
96 | html("<tr><td colspan='2'><input value='Login' type='submit' /></td></tr>") | ||
97 | html("</table></form>") | ||
98 | |||
99 | return 0 | ||
100 | end | ||
101 | |||
102 | |||
103 | |||
104 | -- | ||
105 | -- | ||
106 | -- Wrapper around filter API, exposing the http table, the cgit table, and the post table to the above functions. | ||
107 | -- | ||
108 | -- | ||
109 | |||
110 | local actions = {} | ||
111 | actions["authenticate-post"] = authenticate_post | ||
112 | actions["authenticate-cookie"] = authenticate_cookie | ||
113 | actions["body"] = body | ||
114 | |||
115 | function filter_open(...) | ||
116 | action = actions[select(1, ...)] | ||
117 | |||
118 | http = {} | ||
119 | http["cookie"] = select(2, ...) | ||
120 | http["method"] = select(3, ...) | ||
121 | http["query"] = select(4, ...) | ||
122 | http["referer"] = select(5, ...) | ||
123 | http["path"] = select(6, ...) | ||
124 | http["host"] = select(7, ...) | ||
125 | http["https"] = select(8, ...) | ||
126 | |||
127 | cgit = {} | ||
128 | cgit["repo"] = select(9, ...) | ||
129 | cgit["page"] = select(10, ...) | ||
130 | cgit["url"] = select(11, ...) | ||
131 | cgit["login"] = select(12, ...) | ||
132 | |||
133 | end | ||
134 | |||
135 | function filter_close() | ||
136 | return action() | ||
137 | end | ||
138 | |||
139 | function filter_write(str) | ||
140 | post = parse_qs(str) | ||
141 | end | ||
142 | |||
143 | |||
144 | -- | ||
145 | -- | ||
146 | -- Utility functions based on keplerproject/wsapi. | ||
147 | -- | ||
148 | -- | ||
149 | |||
150 | function url_decode(str) | ||
151 | if not str then | ||
152 | return "" | ||
153 | end | ||
154 | str = string.gsub(str, "+", " ") | ||
155 | str = string.gsub(str, "%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) | ||
156 | str = string.gsub(str, "\r\n", "\n") | ||
157 | return str | ||
158 | end | ||
159 | |||
160 | function url_encode(str) | ||
161 | if not str then | ||
162 | return "" | ||
163 | end | ||
164 | str = string.gsub(str, "\n", "\r\n") | ||
165 | str = string.gsub(str, "([^%w ])", function(c) return string.format("%%%02X", string.byte(c)) end) | ||
166 | str = string.gsub(str, " ", "+") | ||
167 | return str | ||
168 | end | ||
169 | |||
170 | function parse_qs(qs) | ||
171 | local tab = {} | ||
172 | for key, val in string.gmatch(qs, "([^&=]+)=([^&=]*)&?") do | ||
173 | tab[url_decode(key)] = url_decode(val) | ||
174 | end | ||
175 | return tab | ||
176 | end | ||
177 | |||
178 | function get_cookie(cookies, name) | ||
179 | cookies = string.gsub(";" .. cookies .. ";", "%s*;%s*", ";") | ||
180 | return url_decode(string.match(cookies, ";" .. name .. "=(.-);")) | ||
181 | end | ||
182 | |||
183 | function tohex(b) | ||
184 | local x = "" | ||
185 | for i = 1, #b do | ||
186 | x = x .. string.format("%.2x", string.byte(b, i)) | ||
187 | end | ||
188 | return x | ||
189 | end | ||
190 | |||
191 | -- | ||
192 | -- | ||
193 | -- Cookie construction and validation helpers. | ||
194 | -- | ||
195 | -- | ||
196 | |||
197 | local secret = nil | ||
198 | |||
199 | -- Loads a secret from a file, creates a secret, or returns one from memory. | ||
200 | function get_secret() | ||
201 | if secret ~= nil then | ||
202 | return secret | ||
203 | end | ||
204 | local secret_file = io.open(secret_filename, "r") | ||
205 | if secret_file == nil then | ||
206 | local old_umask = sysstat.umask(63) | ||
207 | local temporary_filename = secret_filename .. ".tmp." .. tohex(rand.bytes(16)) | ||
208 | local temporary_file = io.open(temporary_filename, "w") | ||
209 | if temporary_file == nil then | ||
210 | os.exit(177) | ||
211 | end | ||
212 | temporary_file:write(tohex(rand.bytes(32))) | ||
213 | temporary_file:close() | ||
214 | unistd.link(temporary_filename, secret_filename) -- Intentionally fails in the case that another process is doing the same. | ||
215 | unistd.unlink(temporary_filename) | ||
216 | sysstat.umask(old_umask) | ||
217 | secret_file = io.open(secret_filename, "r") | ||
218 | end | ||
219 | if secret_file == nil then | ||
220 | os.exit(177) | ||
221 | end | ||
222 | secret = secret_file:read() | ||
223 | secret_file:close() | ||
224 | if secret:len() ~= 64 then | ||
225 | os.exit(177) | ||
226 | end | ||
227 | return secret | ||
228 | end | ||
229 | |||
230 | -- Returns value of cookie if cookie is valid. Otherwise returns nil. | ||
231 | function validate_value(expected_field, cookie) | ||
232 | local i = 0 | ||
233 | local value = "" | ||
234 | local field = "" | ||
235 | local expiration = 0 | ||
236 | local salt = "" | ||
237 | local chmac = "" | ||
238 | |||
239 | if cookie == nil or cookie:len() < 3 or cookie:sub(1, 1) == "|" then | ||
240 | return nil | ||
241 | end | ||
242 | |||
243 | for component in string.gmatch(cookie, "[^|]+") do | ||
244 | if i == 0 then | ||
245 | field = component | ||
246 | elseif i == 1 then | ||
247 | value = component | ||
248 | elseif i == 2 then | ||
249 | expiration = tonumber(component) | ||
250 | if expiration == nil then | ||
251 | expiration = -1 | ||
252 | end | ||
253 | elseif i == 3 then | ||
254 | salt = component | ||
255 | elseif i == 4 then | ||
256 | chmac = component | ||
257 | else | ||
258 | break | ||
259 | end | ||
260 | i = i + 1 | ||
261 | end | ||
262 | |||
263 | if chmac == nil or chmac:len() == 0 then | ||
264 | return nil | ||
265 | end | ||
266 | |||
267 | -- Lua hashes strings, so these comparisons are time invariant. | ||
268 | if chmac ~= tohex(hmac.new(get_secret(), "sha256"):final(field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt)) then | ||
269 | return nil | ||
270 | end | ||
271 | |||
272 | if expiration == -1 or (expiration ~= 0 and expiration <= os.time()) then | ||
273 | return nil | ||
274 | end | ||
275 | |||
276 | if url_decode(field) ~= expected_field then | ||
277 | return nil | ||
278 | end | ||
279 | |||
280 | return url_decode(value) | ||
281 | end | ||
282 | |||
283 | function secure_value(field, value, expiration) | ||
284 | if value == nil or value:len() <= 0 then | ||
285 | return "" | ||
286 | end | ||
287 | |||
288 | local authstr = "" | ||
289 | local salt = tohex(rand.bytes(16)) | ||
290 | value = url_encode(value) | ||
291 | field = url_encode(field) | ||
292 | authstr = field .. "|" .. value .. "|" .. tostring(expiration) .. "|" .. salt | ||
293 | authstr = authstr .. "|" .. tohex(hmac.new(get_secret(), "sha256"):final(authstr)) | ||
294 | return authstr | ||
295 | end | ||
296 | |||
297 | function set_cookie(cookie, value) | ||
298 | html("Set-Cookie: " .. cookie .. "=" .. value .. "; HttpOnly") | ||
299 | if http["https"] == "yes" or http["https"] == "on" or http["https"] == "1" then | ||
300 | html("; secure") | ||
301 | end | ||
302 | html("\n") | ||
303 | end | ||
304 | |||
305 | function redirect_to(url) | ||
306 | html("Status: 302 Redirect\n") | ||
307 | html("Cache-Control: no-cache, no-store\n") | ||
308 | html("Location: " .. url .. "\n") | ||
309 | end | ||
310 | |||
311 | function not_found() | ||
312 | html("Status: 404 Not Found\n") | ||
313 | html("Cache-Control: no-cache, no-store\n\n") | ||
314 | end | ||
diff --git a/tests/filters/dump.lua b/tests/filters/dump.lua deleted file mode 100644 index 1f15c93..0000000 --- a/tests/filters/dump.lua +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | function filter_open(...) | ||
2 | buffer = "" | ||
3 | for i = 1, select("#", ...) do | ||
4 | buffer = buffer .. select(i, ...) .. " " | ||
5 | end | ||
6 | end | ||
7 | |||
8 | function filter_close() | ||
9 | html(buffer) | ||
10 | return 0 | ||
11 | end | ||
12 | |||
13 | function filter_write(str) | ||
14 | buffer = buffer .. string.upper(str) | ||
15 | end | ||
16 | |||
17 | |||
diff --git a/tests/setup.sh b/tests/setup.sh index 8db810f..31e7d5b 100755 --- a/tests/setup.sh +++ b/tests/setup.sh | |||
@@ -60,12 +60,6 @@ fi | |||
60 | 60 | ||
61 | FILTER_DIRECTORY=$(cd ../filters && pwd) | 61 | FILTER_DIRECTORY=$(cd ../filters && pwd) |
62 | 62 | ||
63 | if cgit --version | grep -F -q "[+] Lua scripting"; then | ||
64 | export CGIT_HAS_LUA=1 | ||
65 | else | ||
66 | export CGIT_HAS_LUA=0 | ||
67 | fi | ||
68 | |||
69 | mkrepo() { | 63 | mkrepo() { |
70 | name=$1 | 64 | name=$1 |
71 | count=$2 | 65 | count=$2 |
@@ -144,19 +138,6 @@ repo.email-filter=exec:$FILTER_DIRECTORY/dump.sh | |||
144 | repo.source-filter=exec:$FILTER_DIRECTORY/dump.sh | 138 | repo.source-filter=exec:$FILTER_DIRECTORY/dump.sh |
145 | repo.readme=master:a+b | 139 | repo.readme=master:a+b |
146 | EOF | 140 | EOF |
147 | |||
148 | if [ $CGIT_HAS_LUA -eq 1 ]; then | ||
149 | cat >>cgitrc <<EOF | ||
150 | repo.url=filter-lua | ||
151 | repo.path=$PWD/repos/filter/.git | ||
152 | repo.desc=filtered repo | ||
153 | repo.about-filter=lua:$FILTER_DIRECTORY/dump.lua | ||
154 | repo.commit-filter=lua:$FILTER_DIRECTORY/dump.lua | ||
155 | repo.email-filter=lua:$FILTER_DIRECTORY/dump.lua | ||
156 | repo.source-filter=lua:$FILTER_DIRECTORY/dump.lua | ||
157 | repo.readme=master:a+b | ||
158 | EOF | ||
159 | fi | ||
160 | } | 141 | } |
161 | 142 | ||
162 | cgit_query() | 143 | cgit_query() |
diff --git a/tests/t0111-filter.sh b/tests/t0111-filter.sh index 2fdc366..e5d3575 100755 --- a/tests/t0111-filter.sh +++ b/tests/t0111-filter.sh | |||
@@ -4,9 +4,6 @@ test_description='Check filtered content' | |||
4 | . ./setup.sh | 4 | . ./setup.sh |
5 | 5 | ||
6 | prefixes="exec" | 6 | prefixes="exec" |
7 | if [ $CGIT_HAS_LUA -eq 1 ]; then | ||
8 | prefixes="$prefixes lua" | ||
9 | fi | ||
10 | 7 | ||
11 | for prefix in $prefixes | 8 | for prefix in $prefixes |
12 | do | 9 | do |