Files
aqhomecontrol/apps/aqhome-cgi/modules/common/mservice.c
2025-09-15 19:34:56 +02:00

486 lines
12 KiB
C

/****************************************************************************
* This file is part of the project AqHome.
* AqHome (c) by 2025 Martin Preuss, all rights reserved.
*
* The license for this file can be found in the file COPYING which you
* should have received along with this file.
****************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "./mservice_p.h"
#include "aqhome-cgi/service/module.h"
#include <gwenhywfar/debug.h>
/* ------------------------------------------------------------------------------------------------
* defs and enums
* ------------------------------------------------------------------------------------------------
*/
#define AQH_MOD_SERVICE_HEADERFILE "header.html"
#define AQH_MOD_SERVICE_FOOTERFILE "footer.html"
/* ------------------------------------------------------------------------------------------------
* global vars
* ------------------------------------------------------------------------------------------------
*/
GWEN_INHERIT(AQH_MODULE, AQH_MOD_SERVICE)
/* ------------------------------------------------------------------------------------------------
* forward declarations
* ------------------------------------------------------------------------------------------------
*/
static void GWENHYWFAR_CB _freeData(void *bp, void *p);
static void _calcUserModPerms(AQH_MODULE *m, const AQH_USER *user);
static uint32_t _calcRolePerms(const AQH_MODULE *m, const AQH_MODULE_PERMS *modPerms);
/* ------------------------------------------------------------------------------------------------
* code
* ------------------------------------------------------------------------------------------------
*/
void AQH_ModService_Extend(AQH_MODULE *m, AQH_SERVICE *sv, const char *baseFolder)
{
AQH_MOD_SERVICE *xm;
GWEN_NEW_OBJECT(AQH_MOD_SERVICE, xm);
GWEN_INHERIT_SETDATA(AQH_MODULE, AQH_MOD_SERVICE, m, xm, _freeData);
xm->service=sv;
xm->baseFolder=(baseFolder && *baseFolder)?strdup(baseFolder):NULL;
}
void _freeData(GWEN_UNUSED void *bp, void *p)
{
AQH_MOD_SERVICE *xm;
xm=(AQH_MOD_SERVICE*) p;
free(xm->baseFolder);
GWEN_FREE_OBJECT(xm);
}
AQH_SERVICE *AQH_ModService_GetService(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->service;
}
}
return NULL;
}
const char *AQH_ModService_GetBaseFolder(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->baseFolder;
}
}
return NULL;
}
uint32_t AQH_ModService_GetUserPerms(const AQH_MODULE *m)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
return xm->userPerms;
}
}
return 0;
}
void AQH_ModService_SetHandleRequestFn(AQH_MODULE *m, AQH_MODSERVICE_HANDLEREQUEST_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->handleRequestFn=fn;
}
}
}
void AQH_ModService_SetLoadSubModuleFn(AQH_MODULE *m, AQH_MODSERVICE_LOADSUBMODULE_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->loadSubModuleFn=fn;
}
}
}
void AQH_ModService_SetAddHeaderFn(AQH_MODULE *m, AQH_MODSERVICE_ADDHEADER_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->addHeaderFn=fn;
}
}
}
void AQH_ModService_SetAddFooterFn(AQH_MODULE *m, AQH_MODSERVICE_ADDFOOTER_FN fn)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
xm->addFooterFn=fn;
}
}
}
void AQH_ModService_AddHeader(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
{
if (m && dbuf) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
if (xm->addHeaderFn)
xm->addHeaderFn(m, lang, dbuf);
else {
AQH_MODULE *mParent;
mParent=AQH_Module_Tree2_GetParent(m);
if (mParent)
AQH_ModService_AddHeader(mParent, lang, dbuf);
AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_HEADERFILE, dbuf);
}
}
}
}
void AQH_ModService_AddFooter(AQH_MODULE *m, const char *lang, GWEN_BUFFER *dbuf)
{
if (m && dbuf) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
if (xm->addFooterFn)
xm->addFooterFn(m, lang, dbuf);
else {
AQH_MODULE *mParent;
AQH_ModService_ReadStaticFile(m, lang, AQH_MOD_SERVICE_FOOTERFILE, dbuf);
mParent=AQH_Module_Tree2_GetParent(m);
if (mParent)
AQH_ModService_AddFooter(mParent, lang, dbuf);
}
}
}
}
int AQH_ModService_RespondWithFile(AQH_MODULE *m, AQCGI_REQUEST *rq, const char *lang, const char *sFilename)
{
GWEN_BUFFER *buf;
int rv;
buf=GWEN_Buffer_new(0, 256, 0, 1);
AQH_ModService_AddHeader(m, lang, buf);
rv=AQH_ModService_ReadStaticFile(m, lang, sFilename, buf);
if (rv<0) {
AQCGI_SendResponseWithStatus(rq, 500, "Internal error");
GWEN_Buffer_free(buf);
return GWEN_ERROR_INTERNAL;
}
AQH_ModService_AddFooter(m, lang, buf);
AQCGI_Request_SetBufferResponseBody(rq, buf);
AQCGI_Request_AddResponseHeaderData(rq, "Content-type: text/html");
AQCGI_SendResponseWithStatus(rq, 200, "Ok");
return 0;
}
int AQH_ModService_HandleRequest(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sLastPathElem)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm && xm->handleRequestFn)
return xm->handleRequestFn(m, rq, session, sLastPathElem);
}
return GWEN_ERROR_NOT_IMPLEMENTED;
}
AQH_MODULE *AQH_ModService_LoadSubModule(AQH_MODULE *m, AQCGI_REQUEST *rq, AQH_SESSION *session, const char *sModuleName)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm && xm->loadSubModuleFn) {
AQH_MODULE *mReturn;
mReturn=xm->loadSubModuleFn(m, rq, session, sModuleName);
if (mReturn)
AQH_ModService_CalcSessionModPerms(mReturn, session);
return mReturn;
}
}
return NULL;
}
int AQH_ModService_ReadStaticFile(AQH_MODULE *m, const char *lang, const char *filename, GWEN_BUFFER *dbuf)
{
if (m && filename && dbuf) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
GWEN_BUFFER *fbuf;
int rv;
fbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendString(fbuf, xm->baseFolder);
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(fbuf, (lang && *lang)?lang:"en");
GWEN_Buffer_AppendString(fbuf, GWEN_DIR_SEPARATOR_S);
GWEN_Buffer_AppendString(fbuf, filename);
DBG_ERROR(NULL, "Reading file \"%s\"", GWEN_Buffer_GetStart(fbuf));
rv=GWEN_SyncIo_Helper_ReadFile(GWEN_Buffer_GetStart(fbuf), dbuf);
if (rv<0) {
DBG_ERROR(NULL, "Read(%s): %d", GWEN_Buffer_GetStart(fbuf), rv);
GWEN_Buffer_free(fbuf);
return rv;
}
GWEN_Buffer_free(fbuf);
return 0;
}
}
DBG_ERROR(NULL, "Any arg is missing (or is not a AQH_MOD_SERVICE object)");
return GWEN_ERROR_INTERNAL;
}
AQH_SESSION *AQH_ModService_ReadSession(AQH_MODULE *m, AQCGI_REQUEST *rq)
{
AQH_SERVICE *sv;
GWEN_DB_NODE *db;
const char *s;
sv=AQH_ModService_GetService(m);
db=AQCGI_Request_GetDbRequestHeader(rq);
s=GWEN_DB_GetCharValue(db, "cookies/session", 0, NULL);
if (s && *s) {
AQH_SESSION *session;
session=AQH_Service_LoadSession(sv, s);
if (session==NULL) {
DBG_ERROR(NULL, "Session \"%s\" not found", s);
return NULL;
}
else {
const char *sUserName;
GWEN_BUFFER *tbuf;
sUserName=AQH_Session_GetUserAlias(session);
if (sUserName && *sUserName) {
AQH_USER *user;
user=AQH_Service_LoadUser(sv, sUserName);
if (user==NULL) {
DBG_ERROR(NULL, "User \"%s\" not found", sUserName);
AQH_Session_free(session);
return NULL;
}
else {
DBG_ERROR(NULL, "User is \"%s\"", sUserName);
}
AQH_Session_SetUser(session, user);
}
/* renew session cookie */
tbuf=GWEN_Buffer_new(0, 256, 0, 1);
GWEN_Buffer_AppendArgs(tbuf, "Set-Cookie: session=%s; max-age=3600", AQH_Session_GetUid(session));
AQCGI_Request_AddResponseHeaderData(rq, GWEN_Buffer_GetStart(tbuf));
DBG_ERROR(NULL, "Renew session cookie");
GWEN_Buffer_free(tbuf);
return session;
}
}
else {
DBG_ERROR(NULL, "No session cookie");
}
return NULL;
}
void AQH_ModService_CalcSessionModPerms(AQH_MODULE *m, const AQH_SESSION *session)
{
const AQH_USER *user;
user=session?AQH_Session_GetUser(session):NULL;
_calcUserModPerms(m, user);
}
void _calcUserModPerms(AQH_MODULE *m, const AQH_USER *user)
{
if (m) {
AQH_MOD_SERVICE *xm;
xm=GWEN_INHERIT_GETDATA(AQH_MODULE, AQH_MOD_SERVICE, m);
if (xm) {
uint32_t perms=0;
if (user) {
if (AQH_User_GetFlags(user) & AQH_USER_FLAGS_ADMIN)
perms=0xffffffff;
else {
const char *sModName;
const AQH_MODULE_PERMS_LIST *modPermsList;
AQH_MODULE_PERMS *modPerms;
sModName=AQH_Module_GetName(m);
modPermsList=AQH_User_GetModulePermList(user);
modPerms=(sModName && modPermsList)?AQH_ModulePerms_List_GetByModuleId(modPermsList, sModName):NULL;
if (modPerms)
perms=_calcRolePerms(m, modPerms);
else
perms=AQH_Module_GetGuestPerms(m);
}
} /* if (user) */
else
perms=AQH_Module_GetGuestPerms(m);
xm->userPerms=perms;
}
} /* if (m) */
}
uint32_t _calcRolePerms(const AQH_MODULE *m, const AQH_MODULE_PERMS *modPerms)
{
uint32_t perms=0;
const AQH_ROLE_LIST *roleList;
roleList=AQH_Module_GetRoleList(m);
if (roleList) {
int roleArraySize;
int i;
uint32_t explAddPerms=0;
uint32_t explDelPerms=0;
roleArraySize=AQH_ModulePerms_GetRoleArrayArraySize();
for (i=0; i<roleArraySize; i++) {
int roleId;
roleId=AQH_ModulePerms_GetRoleArrayAt(modPerms, i);
if (roleId) {
const AQH_ROLE *role;
role=AQH_Role_List_GetById(roleList, roleId);
if (role) {
perms|=AQH_Role_GetPerms(role);
explAddPerms|=AQH_Role_GetExplAddPerms(role);
explAddPerms|=AQH_Role_GetExplDelPerms(role);
}
}
} /* for */
/* collate permissions */
perms|=explAddPerms;
perms|=AQH_ModulePerms_GetExplAddPerms(modPerms);
perms&=~explDelPerms;
perms&=~AQH_ModulePerms_GetExplDelPerms(modPerms);
}
return perms;
}
void AQH_ModService_AddPermDef(AQH_PERMDEF_LIST *permDefList, const char *id, uint32_t mask, const char *descr)
{
AQH_PERMDEF *permDef;
permDef=AQH_PermDef_new();
AQH_PermDef_SetId(permDef, id);
AQH_PermDef_SetMask(permDef, mask);
AQH_PermDef_SetDescr(permDef, descr);
AQH_PermDef_List_Add(permDef, permDefList);
}
void AQH_ModService_AddRole(AQH_ROLE_LIST *roleList, int id, const char *name, uint32_t perms, const char *descr)
{
AQH_ROLE *role;
role=AQH_Role_new();
AQH_Role_SetId(role, id);
AQH_Role_SetName(role, name);
AQH_Role_SetPerms(role, perms);
AQH_Role_SetDescr(role, descr);
AQH_Role_List_Add(role, roleList);
}