Skip to content
authdb.cpp 57.5 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
#include <fstream>
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 "domain.h"
jan.koester's avatar
jan.koester committed
#include "group.h"
jan.koester's avatar
jan.koester committed
#include "types.h"
jan.koester's avatar
jan.koester committed
#include "hash.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 DomainBackend {
    public:
        DomainBackend(authdb::AuthBackend &adminbck) : _adminbck(adminbck) {
            _domainbck=nullptr;
        }

        authdb::AuthBackend *data(uuid_t did){
            size_t rd=sizeof(authdb::AuthHeader),end=_adminbck.end();

            while(rd<end){
                authdb::AuthData::Record cur;

                _adminbck.setPos(rd);
                _adminbck.read((unsigned char*)&cur,sizeof(AuthData::Record));

                rd=_adminbck.getPos()+cur.datasize;

                if(uuid_compare(cur.uuid,did) == 0 && cur.type == DataType::DomainData &&
                    strcmp(cur.fieldname,"domainName")==0){

                    class DomainData ddat(cur.uuid);

                    size_t dpos=sizeof(authdb::AuthHeader);

                    Domain domain;
                    domain.info(_adminbck,ddat,dpos);

                    _domainbck = new AuthBackend(ddat.getStorageType(),ddat.getStorageOptions(),ddat.getDomainName());
                }
            }
            return _domainbck;
        }

        ~DomainBackend(){
            delete _domainbck;
        }

    private:
        authdb::AuthBackend &_adminbck;
        authdb::AuthBackend *_domainbck;
    };

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

            std::ifstream authfs("../data/authdb.js", std::ios::ate);

            size_t asize = authfs.tellg();
            _AuthJs.resize(asize);
            authfs.seekg(0);
            authfs.read(_AuthJs.data(),asize);

jan.koester's avatar
jan.koester committed
        void listUsers(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args,const char *url){
jan.koester's avatar
jan.koester committed
            libhtmlpp::HtmlString userlist,out,ddat;
jan.koester's avatar
jan.koester committed

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"),*domel=nullptr;
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
            domel=DomainChangeForm(curreq,url,_AdminBackend,ddat);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            if(!domel){
                throw AuthBackendError("listUsers: cannot load doamin's!");
            }

            char cdid[255];
            uuid_t did;

            if(sscanf(curreq->getRequestURL(),"/settings/%[^/]",cdid)<0){
                throw AuthBackendError("listUsers: wrong url!");
            }

            DomainBackend dbackend(_AdminBackend);

            AuthBackend *backend=nullptr;

            if(strcmp(cdid,"admin") == 0 ){
                backend=&_AdminBackend;
            }else if(uuid_parse(cdid,did) == 0 ){
                backend=dbackend.data(did);
            }else{
                throw AuthBackendError("listUsers: could not parse uuid!");
            }

            size_t rd=sizeof(authdb::AuthHeader),end=backend->end();
jan.koester's avatar
jan.koester committed

            content->appendChild(domel);

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;
                cur.type=EmptyData;
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));
jan.koester's avatar
jan.koester committed
                rd=backend->getPos()+cur.datasize;
                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);
jan.koester's avatar
jan.koester committed
                        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>"
jan.koester's avatar
jan.koester committed
                        << "<tr><td><img class=\"list_picture\" style=\"height:100px;\" src=\"" <<"/getavatar/" << cdid << "/" << 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\" >"
jan.koester's avatar
jan.koester committed
                        << "<li><a class=\"button\" href=\"/settings/"<< cdid << "/edituser/" << cruid << "\">EditUser</a></li>"
                        << "<li><a class=\"button\" href=\"/settings/" << cdid << "/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
            userlist << "</table></div><div><ul class=\"usertoolbar\" ><li><a class=\"button\" href=\"/settings/"<< cdid << "/createuser\">CreateUser</a></li></ul></div>";
jan.koester's avatar
jan.koester committed

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

            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
        }

jan.koester's avatar
jan.koester committed
        void createUser(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args,const char *baseurl){
jan.koester's avatar
jan.koester committed
            libhttppp::HttpResponse rep;

            libhttppp::HttpForm curform;
            curform.parse(curreq);
jan.koester's avatar
jan.koester committed
            char cdid[255];
jan.koester's avatar
jan.koester committed
            uuid_t did;

            if(sscanf(curreq->getRequestURL(),"/settings/%[^/]/*",cdid)<0){
                throw AuthBackendError("createUser: wrong url!");
            }

            DomainBackend dbackend(_AdminBackend);

            AuthBackend *backend=nullptr;

            if(strcmp(cdid,"admin") == 0 ){
                backend=&_AdminBackend;
            }else if(uuid_parse(cdid,did) == 0 ){
                backend=dbackend.data(did);
            }else{
                throw AuthBackendError("createUser: could not parse uuid!");
            }
jan.koester's avatar
jan.koester committed

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;
jan.koester's avatar
jan.koester committed
                    int stortype=EmptyStorage;
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

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

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

jan.koester's avatar
jan.koester committed
                    if(stortype==EmptyStorage){
                        bool numeric=true;
                        for(auto i : curformdat->Value){
                            if(!std::isdigit(i)){
                                numeric=false;
                                break;
                            }
                        }

                        if(!numeric)
                            stortype=TextStorage;
                        else
                            stortype=IntStorage;
                    }

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

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

                        udat.Data->append(cudat);
                        delete[] cudat.data;
                    }else if(cudat.storage==TextStorage){
jan.koester's avatar
jan.koester committed
                        if(strcmp(cudat.fieldname,"pwhash")==0){
                            Hash hash;
                            std::string pwhash,inpw;
                            std::copy(curformdat->Value.begin(),curformdat->Value.end(),
                                      std::back_inserter(inpw));
                            hash.hash(inpw,pwhash);
                            cudat.datasize=pwhash.length()+1;
                            cudat.data=new char[cudat.datasize];
                            memcpy(cudat.data,pwhash.c_str(),pwhash.length());
                            cudat.data[pwhash.length()]='\0';
jan.koester's avatar
jan.koester committed

                            udat.Data->append(cudat);
                            delete[] cudat.data;
jan.koester's avatar
jan.koester committed
                        }else{
jan.koester's avatar
jan.koester committed
                            curformdat->Value.push_back('\0');

                            cudat.datasize=curformdat->Value.size();
jan.koester's avatar
jan.koester committed
                            cudat.data=new char[cudat.datasize];
                            memcpy(cudat.data,curformdat->Value.data(),
                                    curformdat->Value.size());
jan.koester's avatar
jan.koester committed

                            udat.Data->append(cudat);
                            delete[] cudat.data;
jan.koester's avatar
jan.koester committed
                        }
jan.koester's avatar
jan.koester committed
                    }else if(cudat.storage==IntStorage){
                            curformdat->Value.push_back('\0');
                            int val=atoi(curformdat->Value.data());
                            cudat.datasize=sizeof(int);
                            cudat.data=(char*)new int;
                            memcpy(cudat.data,&val,
                                    curformdat->Value.size());

                            udat.Data->append(cudat);
                            delete[] cudat.data;
jan.koester's avatar
jan.koester committed
                User user;
jan.koester's avatar
jan.koester committed
                user.create(*backend,&udat);
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>"
jan.koester's avatar
jan.koester committed
                  << "<tr><td><label for=\"pwhash\">password:</label></td>"
                  << "<td><input type=\"text\" name=\"pwhash\"></td></tr>"
jan.koester's avatar
jan.koester committed
                  << "<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){
jan.koester's avatar
jan.koester committed
            char cdid[255],uid[255];
            uuid_t did;

            if(sscanf(curreq->getRequestURL(),"/settings/%[^/]/removeuser/%s",cdid,uid)<0){
                throw AuthBackendError("listUsers: wrong url!");
            }

            DomainBackend dbackend(_AdminBackend);

            AuthBackend *backend=nullptr;

            if(strcmp(cdid,"admin") == 0 ){
                backend=&_AdminBackend;
            }else if(uuid_parse(cdid,did) == 0 ){
                backend=dbackend.data(did);
            }else{
                throw AuthBackendError("listUsers: could not parse uuid!");
            }
jan.koester's avatar
jan.koester committed

            User user;

            uuid_t uuid;

            uuid_parse(uid,uuid);

jan.koester's avatar
jan.koester committed
            user.remove(*backend,uuid);
jan.koester's avatar
jan.koester committed

            libhttppp::HttpResponse rep;
            rep.setState(HTTP307);
            rep.setVersion(HTTPVERSION(1.1));
jan.koester's avatar
jan.koester committed
            char rurl[255];
            snprintf(rurl,255,"/settings/%s/listusers",cdid);
            rep.setHeaderData("Location")->push_back(rurl);
jan.koester's avatar
jan.koester committed
            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;
jan.koester's avatar
jan.koester committed

            DomainBackend dbackend(_AdminBackend);
            AuthBackend *backend=nullptr;
jan.koester's avatar
jan.koester committed

            char domain[255],cuid[255],ext[16];
jan.koester's avatar
jan.koester committed
            if(sscanf(curreq->getRequestURL(),"/getavatar/%[^/]/%[^.].%s",domain,cuid,ext)<0)
jan.koester's avatar
jan.koester committed
                return;

jan.koester's avatar
jan.koester committed
            uuid_t did;

            if(strcmp(domain,"admin") == 0 ){
jan.koester's avatar
jan.koester committed
                backend=&_AdminBackend;
jan.koester's avatar
jan.koester committed
            }else if(uuid_parse(domain,did) == 0 ){
                backend=dbackend.data(did);
jan.koester's avatar
jan.koester committed
            }else{
jan.koester's avatar
jan.koester committed
                throw AuthBackendError("createUser: could not parse uuid!");
jan.koester's avatar
jan.koester committed
            }
            uuid_t uid;
            uuid_parse(cuid,uid);
jan.koester's avatar
jan.koester committed
            size_t rd=sizeof(authdb::AuthHeader),end=backend->end();
jan.koester's avatar
jan.koester committed

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

        };

jan.koester's avatar
jan.koester committed
        void editUser(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
jan.koester's avatar
jan.koester committed
            char cdid[255],cuid[255];
            uuid_t did;

            if(sscanf(curreq->getRequestURL(),"/settings/%[^/]/edituser/%s",cdid,cuid)<0){
                throw AuthBackendError("listUsers: wrong url!");
            }
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            DomainBackend dbackend(_AdminBackend);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            AuthBackend *backend=nullptr;

            if(strcmp(cdid,"admin") == 0 ){
                backend=&_AdminBackend;
            }else if(uuid_parse(cdid,did) == 0 ){
                backend=dbackend.data(did);
            }else{
                throw AuthBackendError("listUsers: could not parse uuid!");
            }


            size_t rd=sizeof(authdb::AuthHeader),end=backend->end();

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

                    AuthData curec(uid);

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

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

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

                        data = true;

jan.koester's avatar
jan.koester committed
                        std::string key;
jan.koester's avatar
jan.koester committed

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

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

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

jan.koester's avatar
jan.koester committed
                        if(key=="filename"){
                            curec.Data->storage=BinaryStorage;
                        }
                    }
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                    if(curec.Data->storage==EmptyStorage){
                        bool numeric=true;
jan.koester's avatar
jan.koester committed
                        for(auto t : curformdat->Value){
                            if(!std::isdigit(t)){
                                numeric=false;
                                break;
jan.koester's avatar
jan.koester committed
                        if(numeric)
                            curec.Data->storage=IntStorage;
                        else
                            curec.Data->storage=TextStorage;
                    }
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed


jan.koester's avatar
jan.koester committed
                    if(curec.Data->storage==TextStorage) {
                        curformdat->Value.push_back('\0');
                        if(strcmp(curec.Data->fieldname,"pwhash")==0){
                            Hash hash;
                            std::string pwhash,inpw;
                            std::copy(curformdat->Value.begin(),curformdat->Value.end(),
                                      std::back_inserter(inpw));
                            hash.hash(inpw,pwhash);
                            curec.Data->datasize=pwhash.length()+1;
                            curec.Data->data=new char[curec.Data->datasize];
                            std::copy(pwhash.begin(),pwhash.end(),curec.Data->data);
                            curec.Data->data[pwhash.length()]='\0';
jan.koester's avatar
jan.koester committed
                            editrec.append(curec);
                            delete[] curec.Data->data;
jan.koester's avatar
jan.koester committed
                        }else{
jan.koester's avatar
jan.koester committed
                            curec.Data->datasize=curformdat->Value.size();
jan.koester's avatar
jan.koester committed
                            curec.Data->data=new char[curec.Data->datasize];
jan.koester's avatar
jan.koester committed
                            std::copy(curformdat->Value.begin(),
                                        curformdat->Value.end(),curec.Data->data);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                            editrec.append(curec);
                            delete[] curec.Data->data;
jan.koester's avatar
jan.koester committed
                        }
                    }else if(curec.Data->storage==BinaryStorage){
                        curec.Data->datasize=curformdat->Value.size();
                        curec.Data->data=new char[curec.Data->datasize];
                        memcpy(curec.Data->data,curformdat->Value.data(),
                               curformdat->Value.size());
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                        editrec.append(curec);
                        delete[] curec.Data->data;
                    }else if(curec.Data->storage==IntStorage){
                        curformdat->Value.push_back('\0');
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                        curec.Data->datasize=sizeof(int);
                        curec.Data->data=(char*)new int;
                        int val=atoi(curformdat->Value.data());
                        memcpy(curec.Data->data,&val,
                               curec.Data->datasize);

                        editrec.append(curec);
                        delete[] (int*)curec.Data->data;
jan.koester's avatar
jan.koester committed
                    }
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            }

            if(data){
jan.koester's avatar
jan.koester committed
                editRecord(*backend,editrec,UserData);
jan.koester's avatar
jan.koester committed
                libhttppp::HttpResponse rep;
                rep.setState(HTTP307);
                rep.setVersion(HTTPVERSION(1.1));
jan.koester's avatar
jan.koester committed
                char rurl[255];
                snprintf(rurl,255,"/settings/%s/listusers",cdid);
                rep.setHeaderData("Location")->push_back(rurl);
jan.koester's avatar
jan.koester committed
                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];
jan.koester's avatar
jan.koester committed
                    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
                }
            }

            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
        libhtmlpp::HtmlElement *DomainChangeForm(libhttppp::HttpRequest *curreq,const char *url,AuthBackend &backend,libhtmlpp::HtmlString &dest){
jan.koester's avatar
jan.koester committed
            libhttppp::HttpForm form;
            form.parse(curreq);

            char cdid[255];
jan.koester's avatar
jan.koester committed
            if(sscanf(curreq->getRequestURL(),"/settings/%[^/]",cdid)<0)
jan.koester's avatar
jan.koester committed
                cdid[0]='\0';

            for (libhttppp::HttpForm::UrlcodedForm::Data* cururlform = form.UrlFormData.getFormData(); cururlform;
                    cururlform = cururlform->nextData()) {
                if( strcmp(cururlform->getKey(),"domaindid")==0){
                    if(strcmp(cdid,cururlform->getValue())!=0){
                        char rurl[255];
jan.koester's avatar
jan.koester committed
                        snprintf(rurl,255,"/settings/%s/%s",cururlform->getValue(),url);
jan.koester's avatar
jan.koester committed
                        libhttppp::HttpResponse rep;
                        rep.setState(HTTP307);
                        rep.setVersion(HTTPVERSION(1.1));
                        rep.setHeaderData("Location")->push_back(rurl);
                        rep.setContentType("text/html");
                        rep.send(curreq,nullptr,0);
                        return nullptr;
                    }
                }
            }

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

            Domain domain;

            dest.clear();
            dest << "<form method=\"post\" ><select name=\"domaindid\" onchange=\"this.form.submit()\">";

jan.koester's avatar
jan.koester committed
            dest << "<option value=\"admin\" >admin.local</option>";
jan.koester's avatar
jan.koester committed

            while(rd<end){
                authdb::AuthData::Record cur;

                cur.type=EmptyData;

                backend.setPos(rd);
                backend.read((unsigned char*)&cur,sizeof(AuthData::Record));

                rd=backend.getPos()+cur.datasize;
                if(cur.type == DataType::DomainData && strcmp(cur.fieldname,"domainName")==0){
                    size_t dpos=sizeof(authdb::AuthHeader);

                    cur.data = new char[cur.datasize];
                    backend.read((unsigned char*)cur.data,cur.datasize);

                    char did[255];
                    uuid_unparse(cur.uuid,did);

                    dest << "<option value=\"" << did << "\" ";
                    if ( strcmp(cdid,did)==0 ){
                        dest << "selected";
                    }
                    dest << ">"
                         << cur.data << "</option>";

                    delete [] cur.data;
                }
            }
            dest << "</select></form>";

            return (libhtmlpp::HtmlElement*)dest.parse();
        }

jan.koester's avatar
jan.koester committed
        void listDomains(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
jan.koester's avatar
jan.koester committed
            size_t rd=sizeof(authdb::AuthHeader),end=_AdminBackend.end();
jan.koester's avatar
jan.koester committed

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

            libhtmlpp::HtmlElement root=_IndexElement;
            libhtmlpp::HtmlElement *content=root.getElementbyID("content");

jan.koester's avatar
jan.koester committed
            Domain domain;

            list <<"<div><p>DomainList:</p><table class=\"domainlist\">";

            while(rd<end){
                authdb::AuthData::Record cur;

                cur.type=EmptyData;

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

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

                if(cur.type == DataType::DomainData && strcmp(cur.fieldname,"domainName")==0){
                    class DomainData ddat(cur.uuid);

                    try {
                        size_t dpos=sizeof(authdb::AuthHeader);
jan.koester's avatar
jan.koester committed
                        domain.info(_AdminBackend,ddat,dpos);
jan.koester's avatar
jan.koester committed

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

                        list << "<tr><td>"
                        <<  ddat.getDomainName()
                        << "</td><td><ul><li>"
                        << "Domainid: " << crdid
                        << "</li>"
                        << "<li><span>Storagetype: </span><span>" << ddat.getStorageType() << "</span></li>"
                        << "<li><span>Storageoptions: </span><span>" << ddat.getStorageOptions() << "</span></li>"
                        << "</ul></td><td><ul class=\"usertoolbar\" >"
jan.koester's avatar
jan.koester committed
                        << "<li><a class=\"button\" href=\"/settings/" << crdid << "/removedomain\">RemoveDomain</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
            list  << "</table></div><div><ul class=\"domaintoolbar\" >"
jan.koester's avatar
jan.koester committed
                  << "<li><a class=\"button\" href=\"/settings/admin/createdomain\">CreateDomain</a>"
jan.koester's avatar
jan.koester committed
                  << "</li></ul></div>";

jan.koester's avatar
jan.koester committed
            content->appendChild(list.parse());
jan.koester's avatar
jan.koester committed

            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 createDomain(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
jan.koester's avatar
jan.koester committed
            libhttppp::HttpForm curform;
            curform.parse(curreq);

            if (curform.getBoundary()) {
                uuid_t uid;
                uuid_generate(uid);
                class DomainData ddat(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;
jan.koester's avatar
jan.koester committed
                            continue;
jan.koester's avatar
jan.koester committed
                        }

                        bool numeric=true;

jan.koester's avatar
jan.koester committed
                        for(auto t=curformdat->Value.begin(); t!=curformdat->Value.end();
                            ++t){
jan.koester's avatar
jan.koester committed
                            if(!std::isdigit(*t)){
                                numeric=false;
                                break;
                            }
                        }

                        if(numeric){
                            stortype=StorageType::IntStorage;
                        }

                    }

                    if(name.empty() || stortype == EmptyStorage)
                        continue;

                    struct AuthData::Record dodat;
                    memset(&dodat,0,sizeof(AuthData::Record));

                    dodat.start=0xFE;
                    uuid_copy(dodat.uuid,uid);

                    dodat.type=UserData;
                    dodat.storage=stortype;
                    strcpy(dodat.fieldname,name.c_str());

                    if(dodat.storage==TextStorage){
jan.koester's avatar
jan.koester committed
                        curformdat->Value.push_back('\0');
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                        dodat.datasize=curformdat->Value.size();
jan.koester's avatar
jan.koester committed
                        dodat.data=new char[dodat.datasize];
                        memcpy(dodat.data,curformdat->Value.data(),
                               curformdat->Value.size());
jan.koester's avatar
jan.koester committed

                        ddat.Data->append(dodat);
                        delete[] dodat.data;
jan.koester's avatar
jan.koester committed
                    }else if(dodat.storage==IntStorage){
jan.koester's avatar
jan.koester committed
                        curformdat->Value.push_back('\0');

jan.koester's avatar
jan.koester committed
                        dodat.datasize=sizeof(int);
                        dodat.data=(char*)new int;
jan.koester's avatar
jan.koester committed
                        int val=atoi(curformdat->Value.data());
jan.koester's avatar
jan.koester committed
                        memcpy(dodat.data,&val,
jan.koester's avatar
jan.koester committed
                               dodat.datasize);
jan.koester's avatar
jan.koester committed

                        ddat.Data->append(dodat);
                        delete (int*)dodat.data;
jan.koester's avatar
jan.koester committed
                    }else {
                        dodat.datasize=curformdat->Value.size();
                        dodat.data=new char[dodat.datasize];
                        memcpy(dodat.data,curformdat->Value.data(),
                               dodat.datasize);

jan.koester's avatar
jan.koester committed
                        ddat.Data->append(dodat);
                        delete[] dodat.data;
                    }
jan.koester's avatar
jan.koester committed
                }
                Domain domain;
jan.koester's avatar
jan.koester committed
                domain.create(_AdminBackend,&ddat);
jan.koester's avatar
jan.koester committed
                std::cout << "domain created!" << std::endl;
            }

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

            libhtmlpp::HtmlElement root=_IndexElement;
            libhtmlpp::HtmlElement *content=root.getElementbyID("content");

            form  << "<form method=\"post\" enctype=\"multipart/form-data\">"
                  << "<table>"

jan.koester's avatar
jan.koester committed
                  << "<tr><td><label for=\"domainName\">Domain Name:</label></td>"
                  << "<td><input class=\"domaintext\" type=\"text\" name=\"domainName\" value=\"tuxist.de\"></td></tr>"
jan.koester's avatar
jan.koester committed
                  << "<tr><td><label for=\"domainStorage\">Domain Storage:</label></td>"
                  << "<td><select name=\"domainStorage\">"
jan.koester's avatar
jan.koester committed
                  << "<option value=\""<< AuthBackendType::File << "\">File</option>"
jan.koester's avatar
jan.koester committed
                  << "</select></td></tr>"

jan.koester's avatar
jan.koester committed
                  << "<tr><td><label for=\"domainOptions\">Domain Options:</label></td>"
jan.koester's avatar
jan.koester committed
                  << "<td><input class=\"domaintext\" type=\"text\" name=\"domainOptions\" value=\"tuxist.de.db\"></td></tr>"
jan.koester's avatar
jan.koester committed

                  << "<tr><td></td><td><input type=\"submit\" value=\"save\" ></td></tr>"
                  << "</table>";

            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 removeDomain(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
jan.koester's avatar
jan.koester committed
            char did[255];
            sscanf(curreq->getRequestURL(),"/settings/%[^/]/removedomain",did);
jan.koester's avatar
jan.koester committed

            Domain domain;

            uuid_t uuid;

jan.koester's avatar
jan.koester committed
            uuid_parse(did,uuid);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
            domain.remove(_AdminBackend,uuid);
jan.koester's avatar
jan.koester committed

            libhttppp::HttpResponse rep;
            rep.setState(HTTP307);
            rep.setVersion(HTTPVERSION(1.1));
jan.koester's avatar
jan.koester committed
            rep.setHeaderData("Location")->push_back("/settings/index");
jan.koester's avatar
jan.koester committed
            rep.setContentType("text/html");
            rep.send(curreq,nullptr,0);
        }

jan.koester's avatar
jan.koester committed
        void listGroups(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args,const char *url){
            libhtmlpp::HtmlString grouplist,out,ddat;

            libhtmlpp::HtmlElement root=_IndexElement;

            libhtmlpp::HtmlElement *content=root.getElementbyID("content"),*domel=nullptr;

            Group group;

            domel=DomainChangeForm(curreq,url,_AdminBackend,ddat);

            if(!domel){
                throw AuthBackendError("listGroups: cannot load doamin's!");
            }

            char cdid[255];
            uuid_t did;

            if(sscanf(curreq->getRequestURL(),"/settings/%[^/]",cdid)<0){
                throw AuthBackendError("listGroups: wrong url!");
            }

            DomainBackend dbackend(_AdminBackend);

            AuthBackend *backend=nullptr;

            if(strcmp(cdid,"admin") == 0 ){
                backend=&_AdminBackend;
            }else if(uuid_parse(cdid,did) == 0 ){
                backend=dbackend.data(did);
            }else{
                throw AuthBackendError("listGroups: could not parse uuid!");
            }

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

jan.koester's avatar
jan.koester committed
            size_t rd=sizeof(authdb::AuthHeader),end=backend->end();
jan.koester's avatar
jan.koester committed
            while(rd<end){
                authdb::AuthData::Record cur;

                cur.type=EmptyData;

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

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

                if(cur.type == GroupData && strcmp(cur.fieldname,"groupname")==0){
                    class GroupData gdat(cur.uuid);
                    try {
                        size_t upos=sizeof(authdb::AuthHeader);
                        group.info(*backend,gdat,upos);

                        char cruid[20];
                        uuid_unparse(cur.uuid,cruid);
                        grouplist << "<tr><td class=\"list_groupname\">" << gdat.getName()
                        << "</td><td>"
                        << "<ul><li>"
                        << "uid: " << cruid
                        << "</li>"
                        << "</ul></td><td><a class=\"button\" href=\"/settings/"
                        << cdid
                        << "/removegroup/" << cruid << "\">Remove group</a></td></tr>";
                    }catch(AuthBackendError &e){
                        std::cerr << e.what() << std::endl;