aboutsummaryrefslogblamecommitdiff
path: root/xp/navigator/cgi-src/navigator_cgi.cpp
blob: 20e152e2f8b4a1168c9fc34464ffe3c0a542a8c5 (plain) (tree)








































































































































































































































































































































                                                                                                                                        
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <string>
#include <sstream>

#include <jsoncpp/json/json.h>

#include <mysql/my_global.h>
#include <mysql/mysql.h>
MYSQL* sql;
const char* rand_ch="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Json::Value do_login(Json::Value o)
{
	MYSQL_RES* sqlr=NULL;
	MYSQL_ROW row;
	char q[256];
	Json::Value ret;
	std::string usrname=o["username"].asString();
	std::string passwd=o["passwd"].asString();
	std::string sessname=o["sessionname"].asString();
	std::string token;
	std::string qpwd;
	if(usrname.length()<1){ret["result"]=1;goto fail;}
	for(size_t i=0;i<usrname.length();++i)if(!isalnum(usrname[i])&&usrname[i]!='-'&&usrname[i]!='_'){ret["result"]=1;goto fail;}
	for(size_t i=0;i<passwd.length();++i)if(!isalnum(passwd[i])){ret["result"]=1;goto fail;}
	for(size_t i=0;i<sessname.length();++i)if(!isalnum(sessname[i])&&sessname[i]!='-'&&sessname[i]!='_'){ret["result"]=1;goto fail;}
	
	snprintf(q,256,"select password from navigator_user where username='%s'",usrname.c_str());
	mysql_query(sql,q);
	sqlr=mysql_store_result(sql);
	if(mysql_num_rows(sqlr)!=1){ret["result"]=4;goto fail;}
	row=mysql_fetch_row(sqlr);
	qpwd=std::string(row[0],64);
	if(passwd!=qpwd)
	{
		ret["result"]=1;
		goto fail;
	}
	mysql_free_result(sqlr);sqlr=NULL;

	if(!sessname.length())
	{
		snprintf(q,256,"delete from navigator_session where sessionname='' and username='%s'",usrname.c_str());
		mysql_query(sql,q);
		mysql_commit(sql);
	}
	else
	{
		snprintf(q,256,"select sessionname from navigator_session where sessionname='%s' and username='%s'",
		sessname.c_str(),usrname.c_str());
		mysql_query(sql,q);
		sqlr=mysql_store_result(sql);
		if(mysql_num_rows(sqlr)>0){ret["result"]=2;goto fail;}
		mysql_free_result(sqlr);sqlr=NULL;
	}

	do{
		if(sqlr){mysql_free_result(sqlr);sqlr=NULL;}
		token="";
		for(int i=0;i<32;++i)token.push_back(rand_ch[rand()%62]);
		snprintf(q,256,"select token from navigator_session where token='%s'",
		token.c_str());
		mysql_query(sql,q);
		sqlr=mysql_store_result(sql);
	}while(mysql_num_rows(sqlr));
	mysql_free_result(sqlr);sqlr=NULL;
	
	snprintf(q,256,"insert into navigator_session values('%s','%s','%s',%lld)",
		usrname.c_str(),
		token.c_str(),
		sessname.c_str(),
		time(NULL)
	);
	mysql_query(sql,q);
	mysql_commit(sql);
	ret["result"]=0;
	ret["token"]=token;
fail:
	if(sqlr){mysql_free_result(sqlr);sqlr=NULL;}
	return ret;
}
const int tsl[]={1800,86400,604800,1296000,2592000,5184000,7776000,15552000,31104000};
void set_session_length(std::string user,int c)
{
	char q[256];
	if(c>7)c=7;if(c<0)c=0;
	snprintf(q,256,"update navigator_user set session_length=%d where username='%s'",user.c_str());
	mysql_query(sql,q);
	mysql_commit(sql);
}
int get_session_length(std::string user)
{
	MYSQL_RES* sqlr=NULL;
	MYSQL_ROW row;
	char q[256];
	snprintf(q,256,"select session_length from navigator_user where username='%s'",user.c_str());
	mysql_query(sql,q);
	sqlr=mysql_store_result(sql);
	if(mysql_num_rows(sqlr)!=1){mysql_free_result(sqlr);return -1;}
	row=mysql_fetch_row(sqlr);
	int sl=atoi(row[0]);
	mysql_free_result(sqlr);
	return sl;
}
std::string authenticate(std::string token)
{
	MYSQL_RES* sqlr=NULL;
	MYSQL_ROW row;
	char q[256];
	if(token.length()!=32)return "";
	snprintf(q,256,"select username,sessionname,date from navigator_session where token='%s'",token.c_str());
	mysql_query(sql,q);
	sqlr=mysql_store_result(sql);
	if(mysql_num_rows(sqlr)!=1){mysql_free_result(sqlr);return "";}
	row=mysql_fetch_row(sqlr);
	std::string ret=std::string(row[0]);
	bool is_temporary=strlen(row[1])>0;
	long long d=atoll(row[2]);
	mysql_free_result(sqlr);
	int sl=get_session_length(ret);
	if(sl<0||sl>7){return "";}
	int reall=tsl[is_temporary?0:sl+1];
	if(time(NULL)-d>reall)
	{
		snprintf(q,256,"delete from navigator_session where token='%s'",token.c_str());
		mysql_query(sql,q);
		mysql_commit(sql);
		return "";
	}
	return ret;
}
Json::Value set_option(Json::Value o)
{
	Json::Value ret;
	std::string token=o["token"].asString();
	std::string usr=authenticate(token);
	int opt=o["option"].asInt();
	int val=o["value"].asInt();
	if(!usr.length()){ret["result"]=1;goto fail;}
	switch(opt)
	{
		case 0:
			ret["result"]=0;
			set_session_length(usr,val);
		break;
		default:
		ret["result"]=1;
	}
fail:
	return ret;
}
Json::Value get_option(Json::Value o)
{
	Json::Value ret;
	std::string token=o["token"].asString();
	std::string usr=authenticate(token);
	int opt=o["option"].asInt();
	if(!usr.length()){ret["result"]=1;goto fail;}
	switch(opt)
	{
		case 0:
			ret["result"]=0;
			ret["value"]=get_session_length(usr);
		break;
		default:
		ret["result"]=1;
	}
fail:
	return ret;
}
Json::Value get_bookmarks(Json::Value o)
{
	MYSQL_RES* sqlr=NULL;
	MYSQL_ROW row;
	char q[256];
	Json::Value ret;
	std::string token=o["token"].asString();
	std::string usr=authenticate(token);
	if(!usr.length()){ret["result"]=1;goto fail;}
	snprintf(q,256,"select bookmarks from navigator_user where username='%s'",usr.c_str());
	mysql_query(sql,q);
	sqlr=mysql_store_result(sql);
	if(mysql_num_rows(sqlr)!=1){mysql_free_result(sqlr);sqlr=NULL;ret["result"]=4;goto fail;}
	row=mysql_fetch_row(sqlr);
	ret["result"]=0;
	ret["bookmarks"]=std::string(row[0]);
	mysql_free_result(sqlr);sqlr=NULL;
fail:
	if(sqlr){mysql_free_result(sqlr);sqlr=NULL;}
	return ret;
}
Json::Value set_bookmarks(Json::Value o)
{
	char *q=(char*)malloc(65537);
	Json::Value ret;
	std::string token=o["token"].asString();
	std::string usr=authenticate(token);
	if(!usr.length()){ret["result"]=1;goto fail;}
	snprintf(q,65536,"update navigator_user set bookmarks='%s' where username='%s'",o["bookmarks"].asString().c_str(),usr.c_str());
	mysql_query(sql,q);
	mysql_commit(sql);
	ret["result"]=0;
fail:
	free(q);
	return ret;
}
Json::Value list_sessions(Json::Value o)
{
	MYSQL_RES* sqlr=NULL;
	MYSQL_ROW row;
	char q[256];
	Json::Value ret,ss;
	std::string token=o["token"].asString();
	std::string usr=authenticate(token);
	if(!usr.length()){ret["result"]=1;goto fail;}
	snprintf(q,256,"select sessionname,date from navigator_session where username='%s'",usr.c_str());
	
	mysql_query(sql,q);
	sqlr=mysql_store_result(sql);
	for(int i=0;row=mysql_fetch_row(sqlr);++i)
	{
		Json::Value c;
		c["sessionname"]=std::string(row[0]);
		c["date"]=atoi(row[1]);
		ss[i]=c;
	}
	mysql_free_result(sqlr);sqlr=NULL;
	ret["result"]=0;ret["sessions"]=ss;
fail:
	return ret;
}
Json::Value remove_session(Json::Value o)
{
	char q[256];
	Json::Value ret;
	std::string token=o["token"].asString();
	std::string usr=authenticate(token);
	std::string sess=o["session"].asString();
	if(!usr.length()){ret["result"]=1;goto fail;}
	snprintf(q,256,"delete from navigator_session where username='%s' and sessionname='%s'",usr.c_str(),sess.c_str());
	mysql_query(sql,q);
	mysql_commit(sql);
	ret["result"]=0;
fail:
	return ret;
}
int main()
{
	if(!getenv("CONTENT_LENGTH"))return -1;
	int len=atoi(getenv("CONTENT_LENGTH"));
	char *buf;buf=(char*)malloc(len+1);
	fread(buf,1,len,stdin);buf[len]=0;
	std::string sbuf(buf,len);
	free(buf);
	std::stringstream ss(sbuf);
	Json::Value o,r;ss>>o;
	
	sql=mysql_init(NULL);
	if(!sql)return -1;
	if(!mysql_real_connect(sql,"localhost","chrisoft",NULL,"chrisoft",0,"/var/run/mysqld/mysqld.sock",0))
	return -1;
	
	switch(o.get("op",-1).asInt())
	{
		case 0://login
			r=do_login(o);
		break;
		case 1://get bookmarks
			r=get_bookmarks(o);
		break;
		case 2://set bookmarks
			r=set_bookmarks(o);
		break;
		case 3://list sessions
			r=list_sessions(o);
		break;
		case 4://remove session
			r=remove_session(o);
		break;
		case 5://set option
			r=set_option(o);
		break;
		case 6://get option
			r=get_option(o);
		break;
	}
	printf("Status: 200 OK\r\n");
	printf("Content-type: application/json; charset=utf-8\r\n\r\n");
	std::ostringstream oss;
	oss<<r;
	fputs(oss.str().c_str(),stdout);
	return 0;
}
//TODO: set cookie in HTTP header

/*
 * session_length:
 * 0=1d=86400
 * 1=7d=604800
 * 2=15d=1296000
 * 3=30d=2592000
 * 4=60d=5184000
 * 5=90d=7776000
 * 6=180d=15552000
 * 7=360d=31104000
 */
/*navigator_user:
 * username:varchar(PRI) passwd:char(64) bookmarks:text
 *navigator_session:
 * username:varchar token:char(32)(PRI) sessionname:varchar date:bigint
 */
/*
create table navigator_user(
  username varchar(32),
  password char(64),
  bookmarks text,
  session_length int,
  primary key(username)
);
create table navigator_session(
  username varchar(32) not null,
  token char(32),
  sessionname varchar(32),
  date bigint,
  primary key(token)
);
insert into navigator_user values('chrisoft','8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92','',6);
*/