From 9d0b51a2abdacb5fc4eed95cb3249934b607fdc7 Mon Sep 17 00:00:00 2001
From: Chris Xiong <chirs241097@gmail.com>
Date: Sat, 9 Feb 2019 00:04:45 +0800
Subject: Navigator.

---
 xp/navigator/cgi-src/navigator_cgi.cpp | 329 +++++++++++++++++++++++++++++++++
 1 file changed, 329 insertions(+)
 create mode 100644 xp/navigator/cgi-src/navigator_cgi.cpp

(limited to 'xp/navigator/cgi-src')

diff --git a/xp/navigator/cgi-src/navigator_cgi.cpp b/xp/navigator/cgi-src/navigator_cgi.cpp
new file mode 100644
index 0000000..20e152e
--- /dev/null
+++ b/xp/navigator/cgi-src/navigator_cgi.cpp
@@ -0,0 +1,329 @@
+#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);
+*/
-- 
cgit v1.2.3