smr/src/smr.c

337 lines
9.2 KiB
C

#include <kore/kore.h>
#include <kore/http.h>
#ifdef BUILD_PROD
#include <luajit.h>
#else
#define LUA_OK 0
#endif
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#include "smr.h"
#include "libkore.h"
#include "libcrypto.h"
#include <dirent.h>
#include <kore/seccomp.h>
int home(struct http_request *);
int post_story(struct http_request *);
int edit_story(struct http_request *);
int edit_bio(struct http_request *);
int read_story(struct http_request *);
int login(struct http_request *);
int logout(struct http_request *);
int claim(struct http_request *);
int download(struct http_request *);
int preview(struct http_request *);
int search(struct http_request *);
int archive(struct http_request *);
int api(struct http_request *);
int style(struct http_request *);
int miligram(struct http_request *);
int delete(struct http_request *);
int do_lua(struct http_request *req, const char *name);
int errhandeler(lua_State *);
lua_State *L;
/*
These should be defined in in kore somewhere and included here
*/
void kore_worker_configure(void);
void kore_worker_teardown(void);
/*
static / index
static / _post post
static / _edit edit
dynamic / .* read
static / _login login
static / _claim claim
*/
/*Allow seccomp things for luajit and sqlite*/
KORE_SECCOMP_FILTER("app",
KORE_SYSCALL_ALLOW(pread64),
KORE_SYSCALL_ALLOW(pwrite64),
KORE_SYSCALL_ALLOW(fdatasync),
KORE_SYSCALL_ALLOW(unlinkat),
KORE_SYSCALL_ALLOW(mremap),
KORE_SYSCALL_ALLOW(newfstatat),
KORE_SYSCALL_ALLOW(getdents64),
KORE_SYSCALL_ALLOW(gettimeofday),
KORE_SYSCALL_ALLOW(fchown)
);
int
errhandeler(lua_State *state){
printf("Error: %s\n",lua_tostring(state,1));//"error"
lua_getglobal(state,"debug");//"error",{debug}
lua_getglobal(state,"print");//"error",{debug},print()
lua_getfield(state,-2,"traceback");//"error",{debug},print(),traceback()
lua_call(state,0,1);//"error",{debug},print(),"traceback"
lua_call(state,1,0);//"error",{debug}
printf("Called print()\n");
lua_getfield(state,-1,"traceback");//"error",{debug},traceback()
printf("got traceback\n");
lua_call(state,0,1);//"error",{debug},"traceback"
lua_pushstring(state,"\n");
printf("called traceback\n");
lua_pushvalue(state,-4);//"error",{debug},"traceback","error"
printf("pushed error\n");
lua_concat(state,3);//"error",{debug},"traceback .. error"
printf("concated\n");
int ref = luaL_ref(state,LUA_REGISTRYINDEX);//"error",{debug}
lua_pop(state,2);//
lua_rawgeti(state,LUA_REGISTRYINDEX,ref);//"traceback .. error"
return 1;
}
int
do_lua(struct http_request *req, const char *name){
//printf("About to do lua %s\n",name);
lua_pushcfunction(L,errhandeler);
lua_getglobal(L,name);//err(),name()
if(!lua_isfunction(L,-1)){
printf("Could not find a method named %s\n",name);
lua_pop(L,2);//
return (KORE_RESULT_OK);
}
lua_pushlightuserdata(L,req);//err,name(),ud_req
int err = lua_pcall(L,1,0,-3);
if(err != LUA_OK){
size_t retlen;
const char *ret = lua_tolstring(L,-1,&retlen);
printf("Failed to run %s: %s\n",name,lua_tostring(L,-1));
http_response(req, 500, ret, retlen);
lua_pop(L,lua_gettop(L));
return (KORE_RESULT_OK);
}
return KORE_RESULT_OK;
}
#define route(method, lua_method) \
int\
method(struct http_request *req){\
return do_lua(req,#lua_method);\
}
/* md
@name http/_paste
Called at the endpoint <domain>/_paste.
This method doesn't need any parameters for GET requests.
This method expects the following for POST requests:
* title :: string - story title
* text :: string - text to put through markup
* markup :: string - a valid markup type
In addition to the normal assets, this page includes
suggest_tags.js, which suggests tags that have been
submitted to the site before.
@custom http_method GET POST
*/
/* md
@name lua/paste
This function is called automatically with the request submitted at
<endpoint>/_paste
@param http_request req The request to service
*/
route(post_story,"paste");
/***
Called at the endpoint <domain>/_edit.
This method requires the following for GET requests:
* story :: string - The url of the story to edit
This method requires the following for POST requests:
* title :: string - story title
* text :: string - text to put through markup
* markup :: string - a valid markup type
* story :: string - the story we're editing
In addition to normal assets, this page includes
suggest_tags.js, which suggests tags that have been
submitted to the site before.
@function _G.edit
@custom http_method GET POST
@param http_request req The request to service
***/
route(edit_story, "edit");
/***
Called at the endpoint <domain>/_bio
This method does not need any parameters for GET requests.
This method requires the following for POST requests:
* text :: string - The text to use as the author bio
* author :: string - The author to modify
If the logged in user does not match the author being
modified, the user recives a 401 Unauthorized error.
@function _G.edit_bio
@custom http_method GET POST
@param http_request req The request to service
***/
route(edit_bio, "edit_bio");
/***
Called at the endpoint <domain>/[^_]*
This method does not require any parameters for GET requests, but may include:
* load_comments :: 0 | 1 - Legacy parameter for loading comments
* pwd :: [0-9a-f]{128} - If the post is marked as "unlisted", this parameter is
needed, if it is not passed, the user receives a 401 Unauthorized error.
This method requires the following for POST requests:
* text :: string - Comment text
* postas :: string - The user to post as, if this is not "Anonymous", the
request must include a session cookie. If it does not, the user receives
a 401 Unauthorized error.
* pwd :: [0-9a-f]{128} - Currently unused, but it's intended use is to validate
the user has the password for unlisted stories.
@function _G.read
@custom http_method GET POST
@param http_request req The request to service
***/
route(read_story, "read");
/***
Called at the endpoint <domain>/_login
This method does not require any parameters for GET requests.
This method requiries the following for POST requests:
* user :: [a-z0-9]{1,30} - The username to log in as
* pass :: any - The passfile for this user
To overload login functionality in an addon, see @{api.authenticate}
@function _G.login
@custom http_method GET POST
@param http_request req The request to service.
***/
int
login(struct http_request *req){
return do_lua(req,"login");
}
int
logout(struct http_request *req){
return do_lua(req,"logout");
}
int
claim(struct http_request *req){
return do_lua(req,"claim");
}
int
download(struct http_request *req){
return do_lua(req,"download");
}
int
preview(struct http_request *req){
return do_lua(req,"preview");
}
int
search(struct http_request *req){
return do_lua(req,"search");
}
int
archive(struct http_request *req){
/*
struct kore_fileref *ref = kore_fileref_get("data/archive.zip",1);
if(ref != NULL){
http_response_fileref(ref,HTTP_STATUS_OK,ref);
kore_fileref_release(ref);
return KORE_RESULT_OK;
}else{
char msg[] = "Failed to create file ref";
http_response(req,200,msg,strlen(msg));
return KORE_RESULT_OK;
}
*/
return do_lua(req,"archive");
}
int
api(struct http_request *req){
return do_lua(req,"api");
}
int
home(struct http_request *req){
return do_lua(req,"home");
}
int
delete(struct http_request *req){
return do_lua(req,"delete");
}
void
kore_worker_configure(void){
printf("Configuring worker...\n");
int err;
/*DIR *dp;*/
/*struct dirent *ep;*/
/*dp = opendir("./");*/
/*if(dp != NULL){*/
/*while(ep = readdir(dp)){*/
/*printf("%s\n",ep->d_name);*/
/*}*/
/*closedir(dp);*/
/*}*/
L = luaL_newstate();
// Open libraries
luaL_openlibs(L);
load_kore_libs(L);
load_crypto_libs(L);
// Set package.path
lua_getglobal(L,"package"); // {package}
lua_getfield(L,-1,"path"); // {package}, "package.path"
lua_pushstring(L,";/var/smr/?.lua;/usr/local/share/lua/5.1/?.lua"); // {package}, "package.path", "/var/smr/?.lua"
lua_concat(L,2); //{package}, "package.path;/var/app_name/?.lua"
lua_setfield(L,-2,"path"); //{package}
lua_getfield(L,-1,"cpath");
lua_pushstring(L,";/usr/local/lib/lua/5.1/?.so");
lua_concat(L,2);
lua_setfield(L,-2,"cpath");
lua_pop(L,1);
// Run init
lua_pushcfunction(L,errhandeler);
printf("About to run loadfile...\n");
luaL_loadfile(L,SM_INIT);
printf("Done running loadfile...\n");
if(!lua_isfunction(L,-1)){//failed to loadfile()
printf("Failed to load %s: %s\n",SM_INIT,lua_tostring(L,-1));
lua_pop(L,1);
return;
}
printf("About to pcall\n");
err = lua_pcall(L,0,LUA_MULTRET,-2);
printf("Done pcalling\n");
//err = luaL_dofile(L,"init.lua");
if(err){
printf("Failed to run %s\n",SM_INIT);
return;
}
lua_pushcfunction(L,errhandeler);
lua_getglobal(L,"configure");
err = lua_pcall(L,0,0,-2);
if(err != LUA_OK){
printf("Failed to run configure(): %s\n",lua_tostring(L,-1));
lua_pop(L,2);
return;
}
lua_pop(L,lua_gettop(L));
printf("Finished configuring worker\n");
}
void
kore_worker_teardown(void){
int err;
lua_pushcfunction(L,errhandeler);
lua_getglobal(L,"teardown");
err = lua_pcall(L,0,0,1);
if(err != LUA_OK){
printf("Failed to run configure(): %s\n",lua_tostring(L,-1));
lua_pop(L,2);
return;
}
lua_close(L);
}