Newer
Older
/*******************************************************************************
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*******************************************************************************/
class AuthDB : public libhttppp::HttpEvent{
public:
AuthDB(authdb::AuthBackend &backend,netplus::socket *ssock) : HttpEvent(ssock), _Backend(backend){
_Indexpage.loadFile(_IndexElement,"../data/index.html");
void listUsers(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
_Backend.lock();
size_t rd=sizeof(authdb::AuthHeader),end=_Backend.end();
libhtmlpp::HtmlElement *content=root.getElementbyID("content");
userlist <<"<div><p>UserList:</p><table class=\"userlist\">";
_Backend.read((unsigned char*)&cur,sizeof(AuthData::Record));
if(cur.type == UserData && strcmp(cur.fieldname,"username")==0){
class UserData udat(cur.uuid);
user.info(_Backend,udat,upos);
char cruid[20];
uuid_unparse(cur.uuid,cruid);
userlist << "<tr><td class=\"list_username\">"
<< udat.getUsername()
<< "</td></tr>"
<< "<tr><td><img class=\"list_picture\" style=\"height:100px;\" src=\"/admin/getavatar/" << cruid << ".jpg\" alt=\"avatar\">"
<< "</li>"
<< "<li><span>Firstname:</span><span>" << udat.getFirstname() << "</span></li>"
<< "<li><span>Lastname:</span><span>" << udat.getLastname() << "</span></li>"
<< "<li><span>Email:</span><span>" << udat.getMail() << "</span></li>"
<< "</ul></td><td><ul class=\"usertoolbar\" >"
<< "<li><a class=\"button\" href=\"/admin/edituser/" << cruid << "\">EditUser</a></li>"
<< "<li><a class=\"button\" href=\"/admin/removeuser/" << cruid << "\">RemoveUser</a></li>"
<< "</ul></td></tr>";
}catch(AuthBackendError &e){
std::cerr << e.what() << std::endl;
userlist << "</table></div><div><ul class=\"usertoolbar\" ><li><a class=\"button\" href=\"/admin/createuser\">CreateUser</a></li></ul></div>";
content->insertChild(userlist.parse());
libhtmlpp::print(&root,out,true);
rep.setContentType("text/html");
rep.send(curreq,out.c_str(),out.size());
}
void createUser(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
libhttppp::HttpResponse rep;
libhttppp::HttpForm curform;
curform.parse(curreq);
if (curform.getBoundary()) {
uuid_t uid;
uuid_generate(uid);
for (libhttppp::HttpForm::MultipartForm::Data* curformdat = curform.MultipartFormData.getFormData();
curformdat; curformdat = curformdat->nextData()) {
if(curformdat->Value.empty())
continue;
std::string name;
int stortype=TextStorage;
for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
curdispo; curdispo=curdispo->nextContentDisposition()
){
std::string tmp=curdispo->getKey();
std::transform(tmp.begin(), tmp.end(), tmp.begin(),
[](unsigned char c){ return std::tolower(c); });
if(tmp=="name")
name=curdispo->getValue();
if(tmp=="filename"){
stortype=BinaryStorage;
}
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
if(name.empty() || stortype == EmptyStorage)
continue;
struct AuthData::Record cudat;
memset(&cudat,0,sizeof(AuthData::Record));
cudat.start=0xFE;
uuid_copy(cudat.uuid,uid);
cudat.type=UserData;
cudat.storage=stortype;
strcpy(cudat.fieldname,name.c_str());
if(cudat.storage==BinaryStorage){
cudat.datasize=curformdat->Value.size();
cudat.data=new char[cudat.datasize];
memcpy(cudat.data,curformdat->Value.data(),
cudat.datasize);
}else{
cudat.datasize=curformdat->Value.size()+1;
cudat.data=new char[cudat.datasize];
memcpy(cudat.data,curformdat->Value.data(),
curformdat->Value.size());
cudat.data[curformdat->Value.size()]='\0';
}
udat.Data->append(cudat);
delete[] cudat.data;
}
libhtmlpp::HtmlString form,out;
form << "<form method=\"post\" enctype=\"multipart/form-data\">"
<< "<table>"
<< "<tr><td><label for=\"username\">username:</label></td>"
<< "<td><input type=\"text\" name=\"username\"></td></tr>"
<< "<tr><td><label for=\"firstname\">firstname:</label></td>"
<< "<td><input type=\"text\" name=\"firstname\"></td></tr>"
<< "<tr><td><label for=\"lastname\">lastname:</label></td>"
<< "<td><input type=\"text\" name=\"lastname\"></td></tr>"
<< "<tr><td><label for=\"mail\">mail:</label></td>"
<< "<td><input type=\"text\" name=\"mail\"></td></tr>"
<< "<tr><td><label for=\"avatar\">ProfilBild:</label></td>"
<< "<td><input type=\"file\" name=\"avatar\"></td></tr>"
<< "<tr><td></td><td><input type=\"submit\"></td></tr>"
<< "</table>"
<< "</form";
libhtmlpp::HtmlElement *content=root.getElementbyID("content");
content->insertChild(form.parse());
libhtmlpp::print(&root,out,true);
rep.setContentType("text/html");
rep.setContentLength(out.size());
rep.send(curreq,out.c_str(),out.size());
}
void removeuser(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
char uid[255];
sscanf(curreq->getRequestURL(),"/admin/removeuser/%s",uid);
User user;
uuid_t uuid;
uuid_parse(uid,uuid);
_Backend.lock();
user.remove(_Backend,uuid);
_Backend.unlock();
libhttppp::HttpResponse rep;
rep.setState(HTTP307);
rep.setVersion(HTTPVERSION(1.1));
rep.setHeaderData("Location")->push_back("/admin/listusers");
rep.setContentType("text/html");
rep.send(curreq,nullptr,0);
void getAvatar(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
libhttppp::HttpResponse rep;
char cuid[255],ext[16];
sscanf(curreq->getRequestURL(),"/admin/getavatar/%[^.].%s",cuid,ext);
size_t rd=sizeof(authdb::AuthHeader),end=_Backend.end();
while(rd<end){
_Backend.read((unsigned char*)&cur,sizeof(AuthData::Record));
rd=_Backend.getPos()+cur.datasize;
if(uuid_compare(cur.uuid,uid)==0 && strcmp(cur.fieldname,"avatar")==0){
cur.data = new char[cur.datasize];
_Backend.read((unsigned char*)cur.data,cur.datasize);
char ctype[255];
snprintf(ctype,255,"image/%s",ext);
rep.setContentType(ctype);
}
}
if(end!=0){
rep.setState(HTTP404);
rep.send(curreq,nullptr,0);
}
_Backend.unlock();
};
void editUser(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
_Backend.lock();
size_t rd=sizeof(authdb::AuthHeader),end=_Backend.end();
char cuid[255];
sscanf(curreq->getRequestURL(),"/admin/edituser/%s",cuid);
uuid_t uid;
uuid_parse(cuid,uid);
AuthData editrec(uid);
bool data = false;
libhttppp::HttpForm curform;
curform.parse(curreq);
for (libhttppp::HttpForm::MultipartForm::Data* curformdat = curform.MultipartFormData.getFormData();
curformdat; curformdat = curformdat->nextData()) {
for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
curdispo; curdispo=curdispo->nextContentDisposition()
){
if(curformdat->Value.empty() || !curdispo->getValue())
continue;
data = true;
curec.Data->type=UserData;
curec.Data->storage=TextStorage;
for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
curdispo; curdispo=curdispo->nextContentDisposition()
){
std::string key;
if(curdispo->getKey())
key=curdispo->getKey();
std::transform(key.begin(), key.end(), key.begin(),
[](unsigned char c){ return std::tolower(c); });
if(key=="name"){
curec.Data->datasize=curformdat->Value.size();
curec.Data->data=new char[curec.Data->datasize];
memcpy(curec.Data->data,curformdat->Value.data(),curformdat->Value.size());
editrec.append(curec);
_Backend.unlock();
libhttppp::HttpResponse rep;
rep.setState(HTTP307);
rep.setVersion(HTTPVERSION(1.1));
rep.setHeaderData("Location")->push_back("/admin/listusers");
rep.setContentType("text/html");
rep.send(curreq,nullptr,0);
return;
}
libhtmlpp::HtmlPage page;
libhtmlpp::HtmlString form,out;
form << "<form method=\"post\" enctype=\"multipart/form-data\">"
<< "<table>";
while(rd<end){
_Backend.read((unsigned char*)&cur,sizeof(AuthData::Record));
rd=_Backend.getPos()+cur.datasize;
if(uuid_compare(cur.uuid,uid)==0 && cur.type==UserData && cur.storage==TextStorage){
cur.data = new char[cur.datasize];
_Backend.read((unsigned char*)cur.data,cur.datasize);
form << "<tr><td><label for=\"username\">" << cur.fieldname << "</label></td>"
<< "<td><input type=\"text\" name=\"" << cur.fieldname << "\" value=\""
<< cur.data <<"\"></td></tr>";
}catch(AuthBackendError &e){
std::cerr << e.what() << std::endl;
}
}
}
_Backend.unlock();
form << "<tr><td><label for=\"avatar\">ProfilBild:</label></td>"
<< "<td><input type=\"file\" name=\"avatar\"></td></tr>"
<< "<tr><td></td><td><input type=\"submit\"></td></tr>"
<< "</table>"
<< "</form";
libhtmlpp::HtmlElement root=_IndexElement;
libhtmlpp::HtmlElement *content=root.getElementbyID("content");
content->insertChild(form.parse());
libhtmlpp::print(&root,out,true);
libhttppp::HttpResponse rep;
rep.setContentType("text/html");
rep.setContentLength(out.size());
rep.send(curreq,out.c_str(),out.size());
}
void AdminController(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
if(strncmp(curreq->getRequestURL(),"/admin/listusers",16)==0){
listUsers(curreq,tid,args);
}else if(strncmp(curreq->getRequestURL(),"/admin/createuser",17)==0){
createUser(curreq,tid,args);
}else if(strncmp(curreq->getRequestURL(),"/admin/removeuser",17)==0){
removeuser(curreq,tid,args);
}else if(strncmp(curreq->getRequestURL(),"/admin/edituser",15)==0){
editUser(curreq,tid,args);
}else if(strncmp(curreq->getRequestURL(),"/admin/getavatar/",17)==0){
getAvatar(curreq,tid,args);
libhtmlpp::HtmlString out;
libhtmlpp::print(&root,out,true);
libhttppp::HttpResponse rep;
rep.setContentType("text/html");
rep.setContentLength(out.size());
rep.send(curreq,out.c_str(),out.size());
}
}
void RequestEvent(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
if(strncmp(curreq->getRequestURL(),"/admin",6)==0){
AdminController(curreq,tid,args);
}else if(strncmp(curreq->getRequestURL(),"/api",4)==0){
}else{
libhttppp::HttpResponse rep;
rep.setState(HTTP307);
rep.setVersion(HTTPVERSION(1.1));
rep.setHeaderData("Location")->push_back("/admin");
rep.setContentType("text/html");
rep.send(curreq,nullptr,0);
libhtmlpp::HtmlElement _IndexElement;
libhtmlpp::HtmlPage _Indexpage;
};
int searchValue(authdb::AuthBackend &backend,const char*fieldname,const char *value){
int rd=sizeof(authdb::AuthHeader),brd=rd;
while(rd>backend.end()){
backend.setPos(rd);
backend.read((unsigned char*)user,sizeof(AuthData::Record));
user->data = new char[user->datasize];
backend.read((unsigned char*)user->data,user->datasize);
Data->storage=EmptyStorage;
uuid_copy(Data->uuid,id);
AuthData::AuthData(const AuthData &src){
Data = new AuthData::Record;
AuthData *dest=this;
for(const AuthData *cursrc=&src; cursrc; cursrc=cursrc->next()){
memcpy(dest->Data,cursrc->Data,sizeof(AuthData::Record));
Data->data=new char[cursrc->Data->datasize];
memcpy(dest->Data->data,cursrc->Data->data,cursrc->Data->datasize);
if(cursrc->next()){
dest->_next=new AuthData(this->Data->uuid);
dest=dest->_next;
}
}
AuthData *AuthData::append(const AuthData &src){
AuthData *curec=this;
curec=curec->_next;
break;
}
curec=curec->_next;
for(const AuthData *cuxrcrec=&src; cuxrcrec; cuxrcrec=cuxrcrec->next()){
memcpy(curec->Data,cuxrcrec->Data,sizeof(AuthData::Record));
curec->Data->data=new char[curec->Data->datasize];
memcpy(curec->Data->data,cuxrcrec->Data->data,curec->Data->datasize);
curec->_next=nullptr;
if(cuxrcrec->next()){
curec->_next=new AuthData(src.Data->uuid);
}
return curec;
}
AuthData *AuthData::append(const AuthData::Record &src){
AuthData *curec=this;
curec=curec->_next;
break;
}
curec=curec->_next;
memcpy(curec->Data,&src,sizeof(AuthData::Record));
curec->Data->data=new char[curec->Data->datasize];
memcpy(curec->Data->data,src.data,curec->Data->datasize);
bool getRecord(authdb::AuthBackend &backend,AuthData &rec,int type){
bool found=false;
int rd=sizeof(authdb::AuthHeader),end=backend.end();
AuthData::Record cur;
memset(&cur,0,sizeof(AuthData::Record));
backend.setPos(rd);
backend.read((unsigned char*)&cur,sizeof(AuthData::Record));
rd=backend.getPos()+cur.datasize;
if(uuid_compare(cur.uuid,rec.Data->uuid) == 0 && cur.type == type){
cur.data=new char[cur.datasize];
backend.read((unsigned char*)cur.data,cur.datasize);
rec.append(cur);
delete[] cur.data;
bool editRecord(AuthBackend &backend,AuthData &rec,int type){
AuthData old(rec.Data->uuid);
std::vector<AuthData::Record*> changemap; //use fieldname;
std::vector<AuthData::Record*> newmap;
for(const AuthData *curdat=&rec; curdat; curdat=curdat->_next){
for(const AuthData *olddat=&old; olddat; olddat=olddat->_next){
if(uuid_compare(olddat->Data->uuid,curdat->Data->uuid)==0
&& strcmp(olddat->Data->fieldname,curdat->Data->fieldname)==0
){
size_t end = olddat->Data->datasize;
if(end!=curdat->Data->datasize){
changemap.push_back(curdat->Data);
}else{
for(size_t i=0; i<end; ++i){
if(olddat->Data->data[i]!=curdat->Data->data[i]){
changemap.push_back(curdat->Data);
break;
}
}
}
newentry=false;
}
}
if(newentry){
newmap.push_back(curdat->Data);
}
}
for(auto newel : newmap){
backend.setPos(backend.end());
backend.write((unsigned char*)newel,sizeof(AuthData::Record));;
backend.write((unsigned char*)newel->data,newel->datasize);
}
const unsigned char zero = 0;
for(auto chel : changemap){
size_t rd=sizeof(authdb::AuthHeader),end=backend.end();
while(rd<end){
authdb::AuthData::Record *rdrec=new AuthData::Record;
backend.setPos(rd);
backend.read((unsigned char*)rdrec,sizeof(AuthData::Record));
if(uuid_compare(rdrec->uuid,rec.Data->uuid)==0 && strcmp(rdrec->fieldname,chel->fieldname)==0){
backend.setPos(backend.end());
backend.write((const unsigned char*)chel,sizeof(AuthData::Record));
backend.write((const unsigned char*)chel->data,chel->datasize);
size_t dsize=rdrec->datasize;
backend.setPos(rd);
backend.write((const unsigned char*)rdrec,sizeof(AuthData::Record));
for(size_t i =0; i<rdrec->datasize; ++i){
backend.write(&zero,1);
}
rd=backend.getPos();
}else{
rd=backend.getPos()+rdrec->datasize;
}
delete rdrec;
}
}
if(!changemap.empty() || !newmap.empty())
return true;
return false;
}
void delRecord(AuthBackend &backend,const uuid_t uid){
size_t end=backend.end(),rd=sizeof(AuthHeader);
if(!uid)
throw AuthBackendError("user info uid required!");
while(rd<end){
authdb::AuthData::Record *cur=new AuthData::Record;
backend.setPos(rd);
backend.read((unsigned char*)cur,sizeof(AuthData::Record));
backend.setPos(wr);
backend.write((unsigned char*)cur,sizeof(AuthData::Record));
const unsigned char zero=0;
for(size_t i=0; i<dsize; ++i){
backend.write(&zero,1);
}
}
delete cur;
}
}
int main(int argc, char *argv[]){
cmdplus::CmdController &cmd=cmdplus::CmdController::getInstance();
if(!cmd.checkRequired()){
std::cerr << "Config Path required !" << std::endl;
cmd.printHelp();
return -1;
}
confplus::Config config(cmd.getCmdbyKey("config")->getValue());
authdb::AuthBackend backend(authdb::AuthBackendType::File,
config.getValue(config.getKey("/AUTHDB/ADMINDB/PATH"),0),
"admin.local"
);
libhttppp::HttpD httpd(
config.getValue(config.getKey("/AUTHDB/BIND"),0),
config.getIntValue(config.getKey("/AUTHDB/PORT"),0),
config.getIntValue(config.getKey("/AUTHDB/MAXCONN"),0),
nullptr,
nullptr
);
authdb::AuthDB authdb(backend,httpd.getServerSocket());
}catch(authdb::AuthBackendError &e){
std::cerr << e.what() << std::endl;
}