Skip to content
authdb.cpp 26.8 KiB
Newer Older
jan.koester's avatar
jan.koester committed
/*******************************************************************************
jan.koester's avatar
jan.koester committed
 * Copyright (c) 2025, Jan Koester jan.koester@gmx.net
jan.koester's avatar
jan.koester committed
 * 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.
 *******************************************************************************/

jan.koester's avatar
jan.koester committed
#include <algorithm>
jan.koester's avatar
jan.koester committed
#include <iostream>
jan.koester's avatar
jan.koester committed
#include <cstring>
jan.koester's avatar
jan.koester committed
#include <sstream>
jan.koester's avatar
jan.koester committed
#include <map>
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
#include <uuid/uuid.h>
jan.koester's avatar
jan.koester committed
#include <cmdplus/cmdplus.h>
#include <confplus/conf.h>
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
#include <httppp/httpd.h>
jan.koester's avatar
jan.koester committed
#include <htmlpp/html.h>
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
#include "backend.h"
jan.koester's avatar
jan.koester committed
#include "authdb.h"
jan.koester's avatar
jan.koester committed
#include "user.h"
jan.koester's avatar
jan.koester committed
#include "types.h"
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
namespace authdb {
jan.koester's avatar
jan.koester committed

    bool initalized=true;

jan.koester's avatar
jan.koester committed
    class AuthDB : public libhttppp::HttpEvent{
    public:
        AuthDB(authdb::AuthBackend &backend,netplus::socket *ssock) : HttpEvent(ssock), _Backend(backend){
jan.koester's avatar
jan.koester committed
            _Indexpage.loadFile(_IndexElement,"../data/index.html");
jan.koester's avatar
jan.koester committed
        };

jan.koester's avatar
jan.koester committed
        void listUsers(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
            _Backend.lock();

            size_t rd=sizeof(authdb::AuthHeader),end=_Backend.end();

jan.koester's avatar
jan.koester committed
            libhtmlpp::HtmlString userlist,out;

jan.koester's avatar
jan.koester committed
            libhtmlpp::HtmlElement root=_IndexElement;
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            libhtmlpp::HtmlElement *content=root.getElementbyID("content");
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            User user;
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            userlist <<"<div><p>UserList:</p><table class=\"userlist\">";
jan.koester's avatar
jan.koester committed

            while(rd<end){
                authdb::AuthData::Record cur;
jan.koester's avatar
jan.koester committed

                cur.type=EmptyData;
jan.koester's avatar
jan.koester committed

                _Backend.setPos(rd);
                _Backend.read((unsigned char*)&cur,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed

                rd=_Backend.getPos()+cur.datasize;
jan.koester's avatar
jan.koester committed

                if(cur.type == UserData && strcmp(cur.fieldname,"username")==0){
                    class UserData udat(cur.uuid);
jan.koester's avatar
jan.koester committed
                    try {
                        size_t upos=sizeof(authdb::AuthHeader);
                        user.info(_Backend,udat,upos);

                        char cruid[20];
                        uuid_unparse(cur.uuid,cruid);

jan.koester's avatar
jan.koester committed
                        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\">"
jan.koester's avatar
jan.koester committed
                        << "</td><td><ul><li>"
                        << "uid: " << cruid
jan.koester's avatar
jan.koester committed
                        << "</li>"
                        << "<li><span>Firstname:</span><span>" << udat.getFirstname() << "</span></li>"
jan.koester's avatar
jan.koester committed
                        << "<li><span>Lastname:</span><span>" << udat.getLastname() << "</span></li>"
jan.koester's avatar
jan.koester committed
                        << "<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>"
jan.koester's avatar
jan.koester committed
                        << "</ul></td></tr>";
                    }catch(AuthBackendError &e){
                        std::cerr << e.what() << std::endl;
jan.koester's avatar
jan.koester committed
                    }
                }
jan.koester's avatar
jan.koester committed
            }
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            _Backend.unlock();
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            userlist << "</table></div><div><ul class=\"usertoolbar\" ><li><a class=\"button\" href=\"/admin/createuser\">CreateUser</a></li></ul></div>";
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            content->insertChild(userlist.parse());

            libhtmlpp::print(&root,out,true);

jan.koester's avatar
jan.koester committed
            libhttppp::HttpResponse rep;
jan.koester's avatar
jan.koester committed
            rep.setContentType("text/html");
            rep.send(curreq,out.c_str(),out.size());
jan.koester's avatar
jan.koester committed
        }

        void createUser(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
            libhttppp::HttpResponse rep;

            libhttppp::HttpForm curform;
            curform.parse(curreq);
jan.koester's avatar
jan.koester committed
            if (curform.getBoundary()) {
                uuid_t uid;
                uuid_generate(uid);
jan.koester's avatar
jan.koester committed
                class UserData udat(uid);
jan.koester's avatar
jan.koester committed

                for (libhttppp::HttpForm::MultipartForm::Data* curformdat = curform.MultipartFormData.getFormData();
                     curformdat; curformdat = curformdat->nextData()) {

                    if(curformdat->Value.empty())
                        continue;

                    std::string name;
                    int stortype=TextStorage;

jan.koester's avatar
jan.koester committed
                    for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
                        curdispo; curdispo=curdispo->nextContentDisposition()
                    ){
jan.koester's avatar
jan.koester committed

                        std::string tmp=curdispo->getKey();

                        std::transform(tmp.begin(), tmp.end(), tmp.begin(),
                                       [](unsigned char c){ return std::tolower(c); });
jan.koester's avatar
jan.koester committed

                        if(tmp=="name")
                            name=curdispo->getValue();
jan.koester's avatar
jan.koester committed

                        if(tmp=="filename"){
                            stortype=BinaryStorage;
                        }
jan.koester's avatar
jan.koester committed
                    }

                    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;
                }
jan.koester's avatar
jan.koester committed
                _Backend.lock();
jan.koester's avatar
jan.koester committed
                User user;
                user.create(_Backend,&udat);
jan.koester's avatar
jan.koester committed
                _Backend.unlock();
jan.koester's avatar
jan.koester committed
                std::cout << "user created!" << std::endl;
            }


jan.koester's avatar
jan.koester committed
            libhtmlpp::HtmlPage page;
jan.koester's avatar
jan.koester committed

            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";

jan.koester's avatar
jan.koester committed
            libhtmlpp::HtmlElement root=_IndexElement;
jan.koester's avatar
jan.koester committed
            libhtmlpp::HtmlElement *content=root.getElementbyID("content");

            content->insertChild(form.parse());

            libhtmlpp::print(&root,out,true);
jan.koester's avatar
jan.koester committed

            rep.setContentType("text/html");
            rep.setContentLength(out.size());
            rep.send(curreq,out.c_str(),out.size());
jan.koester's avatar
jan.koester committed

        }

        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);
jan.koester's avatar
jan.koester committed
        }

jan.koester's avatar
jan.koester committed
        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);
            uuid_t uid;
            uuid_parse(cuid,uid);
            _Backend.lock();
jan.koester's avatar
jan.koester committed

            size_t rd=sizeof(authdb::AuthHeader),end=_Backend.end();

            while(rd<end){
                authdb::AuthData::Record cur;
jan.koester's avatar
jan.koester committed
                _Backend.setPos(rd);
                _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);
jan.koester's avatar
jan.koester committed
                    char ctype[255];
                    snprintf(ctype,255,"image/%s",ext);
                    rep.setContentType(ctype);
                    rep.send(curreq,cur.data,cur.datasize);
jan.koester's avatar
jan.koester committed
                    end=0;
                    delete[] cur.data;
jan.koester's avatar
jan.koester committed
                }
            }

            if(end!=0){
                rep.setState(HTTP404);
                rep.send(curreq,nullptr,0);
            }

            _Backend.unlock();
        };

jan.koester's avatar
jan.koester committed
        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);
jan.koester's avatar
jan.koester committed

            bool data = false;

            libhttppp::HttpForm curform;

            curform.parse(curreq);

jan.koester's avatar
jan.koester committed
            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()
                    ){
                        AuthData curec(uid);

jan.koester's avatar
jan.koester committed
                        if(curformdat->Value.empty() || !curdispo->getValue())
                            continue;

                        data = true;

jan.koester's avatar
jan.koester committed
                        curec.Data->type=UserData;
                        curec.Data->storage=TextStorage;
jan.koester's avatar
jan.koester committed

                        for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
                            curdispo; curdispo=curdispo->nextContentDisposition()
                        ){

                            std::string key;

                            if(curdispo->getKey())
                                key=curdispo->getKey();
                            else
                                continue;
jan.koester's avatar
jan.koester committed

                            std::transform(key.begin(), key.end(), key.begin(),
                                            [](unsigned char c){ return std::tolower(c); });

                            if(key=="name"){
jan.koester's avatar
jan.koester committed
                                strcpy(curec.Data->fieldname,curdispo->getValue());
                            }

                            if(key=="filename"){
jan.koester's avatar
jan.koester committed
                                curec.Data->storage=BinaryStorage;
jan.koester's avatar
jan.koester committed
                        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);
                        delete[] curec.Data->data;
jan.koester's avatar
jan.koester committed
                    }
            }

            if(data){
                editRecord(_Backend,editrec,UserData);
jan.koester's avatar
jan.koester committed
                _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){
                authdb::AuthData::Record cur;
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                _Backend.setPos(rd);
                _Backend.read((unsigned char*)&cur,sizeof(AuthData::Record));
                rd=_Backend.getPos()+cur.datasize;
jan.koester's avatar
jan.koester committed

                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);
jan.koester's avatar
jan.koester committed
                    try {
                        form  << "<tr><td><label for=\"username\">" << cur.fieldname << "</label></td>"
                              << "<td><input type=\"text\" name=\"" << cur.fieldname << "\" value=\""
                              << cur.data <<"\"></td></tr>";
jan.koester's avatar
jan.koester committed
                    }catch(AuthBackendError &e){
                        std::cerr << e.what() << std::endl;
                    }
                    delete[] cur.data;
jan.koester's avatar
jan.koester committed
                }
            }
            _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());
        }

jan.koester's avatar
jan.koester committed
        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);
jan.koester's avatar
jan.koester committed
            }else if(strncmp(curreq->getRequestURL(),"/admin/removeuser",17)==0){
                removeuser(curreq,tid,args);
jan.koester's avatar
jan.koester committed
            }else if(strncmp(curreq->getRequestURL(),"/admin/edituser",15)==0){
                editUser(curreq,tid,args);
jan.koester's avatar
jan.koester committed
            }else if(strncmp(curreq->getRequestURL(),"/admin/getavatar/",17)==0){
                getAvatar(curreq,tid,args);
jan.koester's avatar
jan.koester committed
            }else{
jan.koester's avatar
jan.koester committed
                libhtmlpp::HtmlElement root=_IndexElement;
jan.koester's avatar
jan.koester committed
                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());
jan.koester's avatar
jan.koester committed
            }
        }

        void RequestEvent(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
            if(strncmp(curreq->getRequestURL(),"/admin",6)==0){
                AdminController(curreq,tid,args);
jan.koester's avatar
jan.koester committed
            }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);
jan.koester's avatar
jan.koester committed
            }
jan.koester's avatar
jan.koester committed
        };
    private:
jan.koester's avatar
jan.koester committed
        authdb::AuthBackend     _Backend;
jan.koester's avatar
jan.koester committed
        libhtmlpp::HtmlElement  _IndexElement;
        libhtmlpp::HtmlPage     _Indexpage;
jan.koester's avatar
jan.koester committed
    };

    int searchValue(authdb::AuthBackend &backend,const char*fieldname,const char *value){
jan.koester's avatar
jan.koester committed
        authdb::AuthData::Record *user=new AuthData::Record;
jan.koester's avatar
jan.koester committed
        int rd=sizeof(authdb::AuthHeader),brd=rd;
        while(rd>backend.end()){
jan.koester's avatar
jan.koester committed
            backend.setPos(rd);
            backend.read((unsigned char*)user,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            rd=backend.getPos();
jan.koester's avatar
jan.koester committed
            if(strcmp(user->fieldname,fieldname) == 0){
jan.koester's avatar
jan.koester committed
                user->data = new char[user->datasize];
                backend.read((unsigned char*)user->data,user->datasize);
jan.koester's avatar
jan.koester committed
                if(strcmp(user->data,value) == 0){
                    delete[] user->data;
jan.koester's avatar
jan.koester committed
                    goto VALUEFOUND;
jan.koester's avatar
jan.koester committed
                }
jan.koester's avatar
jan.koester committed
                delete[] user->data;
jan.koester's avatar
jan.koester committed
            }
            brd=rd;
        }
jan.koester's avatar
jan.koester committed
VALUEFOUND:
jan.koester's avatar
jan.koester committed
        delete user;
jan.koester's avatar
jan.koester committed
        return brd;
    AuthData::AuthData(const uuid_t id){
jan.koester's avatar
jan.koester committed
         Data = new AuthData::Record;
jan.koester's avatar
jan.koester committed
         memset((void*)Data,0,sizeof(AuthData));
jan.koester's avatar
jan.koester committed
         Data->start=0xFE;
         Data->storage=EmptyStorage;
         uuid_copy(Data->uuid,id);
jan.koester's avatar
jan.koester committed
        _next=nullptr;
    }

jan.koester's avatar
jan.koester committed
    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;
            }
        }
jan.koester's avatar
jan.koester committed
    AuthData::~AuthData(){
jan.koester's avatar
jan.koester committed
        delete Data;
jan.koester's avatar
jan.koester committed
    AuthData *AuthData::next() const{
jan.koester's avatar
jan.koester committed
        return _next;
jan.koester's avatar
jan.koester committed
    AuthData *AuthData::append(const AuthData &src){
        AuthData *curec=this;

        while(curec->Data->datasize!=0){
jan.koester's avatar
jan.koester committed
            if(!curec->_next){
                curec->_next=new AuthData(Data->uuid);
jan.koester's avatar
jan.koester committed
                curec=curec->_next;
                break;
            }
            curec=curec->_next;
jan.koester's avatar
jan.koester committed

        for(const AuthData *cuxrcrec=&src; cuxrcrec; cuxrcrec=cuxrcrec->next()){
            memcpy(curec->Data,cuxrcrec->Data,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            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);
jan.koester's avatar
jan.koester committed
                curec=curec->_next;
            }
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        }
        return curec;
    }

    AuthData *AuthData::append(const AuthData::Record &src){
        AuthData *curec=this;

        while(curec->Data->datasize!=0){
jan.koester's avatar
jan.koester committed
            if(!curec->_next){
                curec->_next=new AuthData(Data->uuid);
jan.koester's avatar
jan.koester committed
                curec=curec->_next;
                break;
            }
            curec=curec->_next;
jan.koester's avatar
jan.koester committed

        memcpy(curec->Data,&src,sizeof(AuthData::Record));
        curec->Data->data=new char[curec->Data->datasize];
        memcpy(curec->Data->data,src.data,curec->Data->datasize);
jan.koester's avatar
jan.koester committed
        return curec;
    }

    bool getRecord(authdb::AuthBackend &backend,AuthData &rec,int type){
jan.koester's avatar
jan.koester committed
        bool found=false;
        int rd=sizeof(authdb::AuthHeader),end=backend.end();
jan.koester's avatar
jan.koester committed
        AuthData *curec=&rec;
jan.koester's avatar
jan.koester committed

        while(rd<end){
            AuthData::Record cur;
            memset(&cur,0,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            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;
jan.koester's avatar
jan.koester committed
            }
        }
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        return found;
    }
    bool editRecord(AuthBackend &backend,AuthData &rec,int type){
        AuthData old(rec.Data->uuid);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        std::vector<AuthData::Record*> changemap; //use fieldname;
        std::vector<AuthData::Record*> newmap;
jan.koester's avatar
jan.koester committed

        getRecord(backend,old,type);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        for(const AuthData *curdat=&rec; curdat; curdat=curdat->_next){
jan.koester's avatar
jan.koester committed
            bool newentry=true;
jan.koester's avatar
jan.koester committed
            for(const AuthData *olddat=&old; olddat; olddat=olddat->_next){
                if(uuid_compare(olddat->Data->uuid,curdat->Data->uuid)==0
jan.koester's avatar
jan.koester committed
                    && 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());
jan.koester's avatar
jan.koester committed
            backend.write((unsigned char*)newel,sizeof(AuthData::Record));;
            backend.write((unsigned char*)newel->data,newel->datasize);
jan.koester's avatar
jan.koester committed
        }

        const unsigned char zero = 0;


        for(auto chel : changemap){
            size_t rd=sizeof(authdb::AuthHeader),end=backend.end();
            while(rd<end){
jan.koester's avatar
jan.koester committed
                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){
jan.koester's avatar
jan.koester committed
                    backend.setPos(backend.end());
                    backend.write((const unsigned char*)chel,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                    backend.write((const unsigned char*)chel->data,chel->datasize);
                    size_t dsize=rdrec->datasize;
jan.koester's avatar
jan.koester committed
                    memset(rdrec,0,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                    rdrec->start = 0xFE;
jan.koester's avatar
jan.koester committed
                    rdrec->datasize=dsize;
jan.koester's avatar
jan.koester committed
                    backend.setPos(rd);
                    backend.write((const unsigned char*)rdrec,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                    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;
    }

jan.koester's avatar
jan.koester committed
    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){
jan.koester's avatar
jan.koester committed
            authdb::AuthData::Record *cur=new AuthData::Record;
            backend.setPos(rd);
            size_t wr=backend.getPos();
jan.koester's avatar
jan.koester committed
            backend.read((unsigned char*)cur,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            rd=backend.getPos()+cur->datasize;
            if(uuid_compare(uid,cur->uuid) == 0){
jan.koester's avatar
jan.koester committed
                size_t dsize=cur->datasize;
                memset(cur,0,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                cur->start = 0xFE;
jan.koester's avatar
jan.koester committed
                cur->datasize=dsize;
jan.koester's avatar
jan.koester committed
                backend.setPos(wr);
                backend.write((unsigned char*)cur,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                const unsigned char zero=0;
                for(size_t i=0; i<dsize; ++i){
                    backend.write(&zero,1);
                }
            }
            delete cur;
        }
    }

jan.koester's avatar
jan.koester committed
int main(int argc, char *argv[]){
    cmdplus::CmdController &cmd=cmdplus::CmdController::getInstance();
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
    cmd.registerCmd("config",'c',true,nullptr,"Config Path");
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
    cmd.parseCmd(argc,argv);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
    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"
                                );
jan.koester's avatar
jan.koester committed
    try {
jan.koester's avatar
jan.koester committed
        if(backend.end()<=sizeof(authdb::AuthHeader)){
jan.koester's avatar
jan.koester committed
            authdb::initalized=false;
jan.koester's avatar
jan.koester committed
        }

jan.koester's avatar
jan.koester committed
        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
        );
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        authdb::AuthDB authdb(backend,httpd.getServerSocket());
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        authdb.runEventloop();
jan.koester's avatar
jan.koester committed
    }catch(authdb::AuthBackendError &e){
        std::cerr << e.what() << std::endl;
    }
jan.koester's avatar
jan.koester committed
}