mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-02 22:25:04 -04:00
Merge branch 'master' into extra_locators_merge
This commit is contained in:
commit
1dd707710b
241 changed files with 20454 additions and 3066 deletions
|
@ -17,7 +17,7 @@
|
|||
#include "ChannelsHandler.h"
|
||||
#include "StatsHandler.h"
|
||||
|
||||
#ifdef LIBRESAPI_QT
|
||||
#ifdef LIBRESAPI_SETTINGS
|
||||
#include "SettingsHandler.h"
|
||||
#endif
|
||||
|
||||
|
@ -240,9 +240,9 @@ public:
|
|||
mTransfersHandler(sts, ifaces.mFiles, ifaces.mPeers, *ifaces.mNotify),
|
||||
mChatHandler(sts, ifaces.mNotify, ifaces.mMsgs, ifaces.mPeers, ifaces.mIdentity, &mPeersHandler),
|
||||
mApiPluginHandler(sts, ifaces),
|
||||
mChannelsHandler(ifaces.mGxsChannels),
|
||||
mChannelsHandler(*ifaces.mGxsChannels),
|
||||
mStatsHandler()
|
||||
#ifdef LIBRESAPI_QT
|
||||
#ifdef LIBRESAPI_SETTINGS
|
||||
,mSettingsHandler(sts)
|
||||
#endif
|
||||
{
|
||||
|
@ -272,7 +272,7 @@ public:
|
|||
&ChannelsHandler::handleRequest);
|
||||
router.addResourceHandler("stats", dynamic_cast<ResourceRouter*>(&mStatsHandler),
|
||||
&StatsHandler::handleRequest);
|
||||
#ifdef LIBRESAPI_QT
|
||||
#ifdef LIBRESAPI_SETTINGS
|
||||
router.addResourceHandler("settings", dynamic_cast<ResourceRouter*>(&mSettingsHandler),
|
||||
&SettingsHandler::handleRequest);
|
||||
#endif
|
||||
|
@ -290,7 +290,7 @@ public:
|
|||
ChannelsHandler mChannelsHandler;
|
||||
StatsHandler mStatsHandler;
|
||||
|
||||
#ifdef LIBRESAPI_QT
|
||||
#ifdef LIBRESAPI_SETTINGS
|
||||
SettingsHandler mSettingsHandler;
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -369,6 +369,9 @@ static void secure_queue_response(MHD_Connection *connection, unsigned int statu
|
|||
// tell Internet Explorer to not do content sniffing
|
||||
MHD_add_response_header(response, "X-Content-Type-Options", "nosniff");
|
||||
|
||||
// Prevent clickjacking attacks (also prevented by CSP, but not in all browsers, including FireFox)
|
||||
MHD_add_response_header(response, "X-Frame-Options", "SAMEORIGIN");
|
||||
|
||||
// Content security policy header, its a new technology and not implemented everywhere
|
||||
|
||||
// get own host name as the browser sees it
|
||||
|
|
|
@ -1,8 +1,29 @@
|
|||
/*
|
||||
* RetroShare JSON API
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ChannelsHandler.h"
|
||||
|
||||
#include <retroshare/rsgxschannels.h>
|
||||
#include <util/radix64.h>
|
||||
#include <util/rstime.h>
|
||||
#include <algorithm>
|
||||
#include <time.h>
|
||||
|
||||
#include "Operators.h"
|
||||
|
||||
namespace resource_api
|
||||
|
@ -21,22 +42,414 @@ StreamBase& operator << (StreamBase& left, RsGxsFile& file)
|
|||
{
|
||||
double size = 0;
|
||||
left << makeKeyValueReference("size", size);
|
||||
file.mSize = size;
|
||||
file.mSize = size;
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
ChannelsHandler::ChannelsHandler(RsGxsChannels *channels):
|
||||
mChannels(channels)
|
||||
ChannelsHandler::ChannelsHandler(RsGxsChannels& channels): mChannels(channels)
|
||||
{
|
||||
addResourceHandler("create_post", this, &ChannelsHandler::handleCreatePost);
|
||||
addResourceHandler("list_channels", this,
|
||||
&ChannelsHandler::handleListChannels);
|
||||
addResourceHandler("get_channel_info", this, &ChannelsHandler::handleGetChannelInfo);
|
||||
addResourceHandler("get_channel_content", this, &ChannelsHandler::handleGetChannelContent);
|
||||
addResourceHandler("toggle_subscribe", this, &ChannelsHandler::handleToggleSubscription);
|
||||
addResourceHandler("toggle_auto_download", this, &ChannelsHandler::handleToggleAutoDownload);
|
||||
addResourceHandler("toggle_read", this, &ChannelsHandler::handleTogglePostRead);
|
||||
addResourceHandler("create_channel", this, &ChannelsHandler::handleCreateChannel);
|
||||
addResourceHandler("create_post", this, &ChannelsHandler::handleCreatePost);
|
||||
}
|
||||
|
||||
ResponseTask* ChannelsHandler::handleCreatePost(Request &req, Response &resp)
|
||||
void ChannelsHandler::handleListChannels(Request& /*req*/, Response& resp)
|
||||
{
|
||||
RsTokReqOptions opts;
|
||||
opts.mReqType = GXS_REQUEST_TYPE_GROUP_META;
|
||||
uint32_t token;
|
||||
|
||||
RsTokenService& tChannels = *mChannels.getTokenService();
|
||||
|
||||
tChannels.requestGroupInfo(token, RS_DEPRECATED_TOKREQ_ANSTYPE, opts);
|
||||
|
||||
time_t start = time(NULL);
|
||||
while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
&&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED)
|
||||
&&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000);
|
||||
|
||||
std::list<RsGroupMetaData> grps;
|
||||
if( tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE
|
||||
&& mChannels.getGroupSummary(token, grps) )
|
||||
{
|
||||
for( RsGroupMetaData& grp : grps )
|
||||
{
|
||||
KeyValueReference<RsGxsGroupId> id("channel_id", grp.mGroupId);
|
||||
KeyValueReference<uint32_t> vis_msg("visible_msg_count", grp.mVisibleMsgCount);
|
||||
bool own = (grp.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN);
|
||||
bool subscribed = IS_GROUP_SUBSCRIBED(grp.mSubscribeFlags);
|
||||
std::string lastPostTsStr = std::to_string(grp.mLastPost);
|
||||
std::string publishTsStr = std::to_string(grp.mPublishTs);
|
||||
resp.mDataStream.getStreamToMember()
|
||||
<< id
|
||||
<< makeKeyValueReference("name", grp.mGroupName)
|
||||
<< makeKeyValueReference("last_post_ts", lastPostTsStr)
|
||||
<< makeKeyValueReference("popularity", grp.mPop)
|
||||
<< makeKeyValueReference("publish_ts", publishTsStr)
|
||||
<< vis_msg
|
||||
<< makeKeyValueReference("group_status", grp.mGroupStatus)
|
||||
<< makeKeyValueReference("author_id", grp.mAuthorId)
|
||||
<< makeKeyValueReference("parent_grp_id", grp.mParentGrpId)
|
||||
<< makeKeyValueReference("own", own)
|
||||
<< makeKeyValueReference("subscribed", subscribed);
|
||||
}
|
||||
|
||||
resp.setOk();
|
||||
}
|
||||
else resp.setFail("Cant get data from GXS!");
|
||||
}
|
||||
|
||||
void ChannelsHandler::handleGetChannelInfo(Request& req, Response& resp)
|
||||
{
|
||||
std::string chanIdStr;
|
||||
req.mStream << makeKeyValueReference("channel_id", chanIdStr);
|
||||
if(chanIdStr.empty())
|
||||
{
|
||||
resp.setFail("channel_id required!");
|
||||
return;
|
||||
}
|
||||
|
||||
RsGxsGroupId chanId(chanIdStr);
|
||||
if(chanId.isNull())
|
||||
{
|
||||
resp.setFail("Invalid channel_id:" + chanIdStr);
|
||||
return;
|
||||
}
|
||||
|
||||
bool wantThumbnail = true;
|
||||
req.mStream << makeKeyValueReference("want_thumbnail", wantThumbnail);
|
||||
|
||||
std::list<RsGxsGroupId> groupIds; groupIds.push_back(chanId);
|
||||
RsTokReqOptions opts;
|
||||
opts.mReqType = GXS_REQUEST_TYPE_GROUP_DATA;
|
||||
uint32_t token;
|
||||
|
||||
RsTokenService& tChannels = *mChannels.getTokenService();
|
||||
tChannels.requestGroupInfo( token, RS_DEPRECATED_TOKREQ_ANSTYPE,
|
||||
opts, groupIds );
|
||||
|
||||
time_t start = time(NULL);
|
||||
while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
&&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED)
|
||||
&&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000);
|
||||
|
||||
std::vector<RsGxsChannelGroup> grps;
|
||||
if( tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE
|
||||
&& mChannels.getGroupData(token, grps) )
|
||||
{
|
||||
for( RsGxsChannelGroup& grp : grps )
|
||||
{
|
||||
KeyValueReference<RsGxsGroupId> id("channel_id", grp.mMeta.mGroupId);
|
||||
KeyValueReference<uint32_t> vis_msg("visible_msg_count", grp.mMeta.mVisibleMsgCount);
|
||||
bool own = (grp.mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN);
|
||||
bool subscribed = IS_GROUP_SUBSCRIBED(grp.mMeta.mSubscribeFlags);
|
||||
std::string lastPostTsStr = std::to_string(grp.mMeta.mLastPost);
|
||||
std::string publishTsStr = std::to_string(grp.mMeta.mPublishTs);
|
||||
StreamBase& rgrp(resp.mDataStream.getStreamToMember());
|
||||
rgrp << id
|
||||
<< makeKeyValueReference("name", grp.mMeta.mGroupName)
|
||||
<< makeKeyValueReference("last_post_ts", lastPostTsStr)
|
||||
<< makeKeyValueReference("popularity", grp.mMeta.mPop)
|
||||
<< makeKeyValueReference("publish_ts", publishTsStr)
|
||||
<< vis_msg
|
||||
<< makeKeyValueReference("group_status", grp.mMeta.mGroupStatus)
|
||||
<< makeKeyValueReference("author_id", grp.mMeta.mAuthorId)
|
||||
<< makeKeyValueReference("parent_grp_id", grp.mMeta.mParentGrpId)
|
||||
<< makeKeyValueReference("description", grp.mDescription)
|
||||
<< makeKeyValueReference("own", own)
|
||||
<< makeKeyValueReference("subscribed", subscribed)
|
||||
<< makeKeyValueReference("auto_download", grp.mAutoDownload);
|
||||
|
||||
if(wantThumbnail)
|
||||
{
|
||||
std::string thumbnail_base64;
|
||||
Radix64::encode(grp.mImage.mData, grp.mImage.mSize, thumbnail_base64);
|
||||
rgrp << makeKeyValueReference("thumbnail_base64_png", thumbnail_base64);
|
||||
}
|
||||
}
|
||||
|
||||
resp.setOk();
|
||||
}
|
||||
else resp.setFail("Cant get data from GXS!");
|
||||
}
|
||||
|
||||
void ChannelsHandler::handleGetChannelContent(Request& req, Response& resp)
|
||||
{
|
||||
std::string chanIdStr;
|
||||
req.mStream << makeKeyValueReference("channel_id", chanIdStr);
|
||||
if(chanIdStr.empty())
|
||||
{
|
||||
resp.setFail("channel_id required!");
|
||||
return;
|
||||
}
|
||||
|
||||
RsGxsGroupId chanId(chanIdStr);
|
||||
if(chanId.isNull())
|
||||
{
|
||||
resp.setFail("Invalid channel_id:" + chanIdStr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::list<RsGxsGroupId> groupIds; groupIds.push_back(chanId);
|
||||
uint32_t token;
|
||||
RsTokReqOptions opts;
|
||||
opts.mReqType = GXS_REQUEST_TYPE_MSG_DATA;
|
||||
|
||||
if(! mChannels.getTokenService()->
|
||||
requestMsgInfo(token, RS_TOKREQ_ANSTYPE_DATA, opts, groupIds) )
|
||||
{
|
||||
resp.setFail("Unknown GXS error!");
|
||||
return;
|
||||
}
|
||||
|
||||
time_t start = time(NULL);
|
||||
while((mChannels.getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
&&(mChannels.getTokenService()->requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED)
|
||||
&&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000);
|
||||
|
||||
std::vector<RsGxsChannelPost> posts;
|
||||
std::vector<RsGxsComment> comments;
|
||||
if( mChannels.getTokenService()->requestStatus(token) ==
|
||||
RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE &&
|
||||
mChannels.getPostData(token, posts, comments) )
|
||||
{
|
||||
for( std::vector<RsGxsChannelPost>::iterator vit = posts.begin();
|
||||
vit != posts.end(); ++vit )
|
||||
{
|
||||
RsGxsChannelPost& post = *vit;
|
||||
RsMsgMetaData& pMeta = post.mMeta;
|
||||
resp.mDataStream.getStreamToMember()
|
||||
<< makeKeyValueReference("channel_id", pMeta.mGroupId)
|
||||
<< makeKeyValueReference("name", pMeta.mMsgName)
|
||||
<< makeKeyValueReference("post_id", pMeta.mMsgId)
|
||||
<< makeKeyValueReference("parent_id", pMeta.mParentId)
|
||||
<< makeKeyValueReference("author_id", pMeta.mAuthorId)
|
||||
<< makeKeyValueReference("orig_msg_id", pMeta.mOrigMsgId)
|
||||
<< makeKeyValueReference("thread_id", pMeta.mThreadId)
|
||||
<< makeKeyValueReference("message", post.mMsg);
|
||||
}
|
||||
|
||||
for( std::vector<RsGxsComment>::iterator vit = comments.begin();
|
||||
vit != comments.end(); ++vit )
|
||||
{
|
||||
RsGxsComment& comment = *vit;
|
||||
RsMsgMetaData& cMeta = comment.mMeta;
|
||||
std::string scoreStr = std::to_string(comment.mScore);
|
||||
resp.mDataStream.getStreamToMember()
|
||||
<< makeKeyValueReference("channel_id", cMeta.mGroupId)
|
||||
<< makeKeyValueReference("name", cMeta.mMsgName)
|
||||
<< makeKeyValueReference("comment_id", cMeta.mMsgId)
|
||||
<< makeKeyValueReference("parent_id", cMeta.mParentId)
|
||||
<< makeKeyValueReference("author_id", cMeta.mAuthorId)
|
||||
<< makeKeyValueReference("orig_msg_id", cMeta.mOrigMsgId)
|
||||
<< makeKeyValueReference("thread_id", cMeta.mThreadId)
|
||||
<< makeKeyValueReference("score", scoreStr)
|
||||
<< makeKeyValueReference("message", comment.mComment);
|
||||
}
|
||||
|
||||
resp.setOk();
|
||||
}
|
||||
else resp.setFail("Cant get data from GXS!");
|
||||
}
|
||||
|
||||
void ChannelsHandler::handleToggleSubscription(Request& req, Response& resp)
|
||||
{
|
||||
std::string chanIdStr;
|
||||
bool subscribe = true;
|
||||
|
||||
req.mStream << makeKeyValueReference("channel_id", chanIdStr)
|
||||
<< makeKeyValueReference("subscribe", subscribe);
|
||||
|
||||
if(chanIdStr.empty())
|
||||
{
|
||||
resp.setFail("channel_id required!");
|
||||
return;
|
||||
}
|
||||
|
||||
RsGxsGroupId chanId(chanIdStr);
|
||||
if(chanId.isNull())
|
||||
{
|
||||
resp.setFail("Invalid channel_id:" + chanIdStr);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t token;
|
||||
if(mChannels.subscribeToGroup(token, chanId, subscribe))
|
||||
{
|
||||
RsTokenService& tChannels = *mChannels.getTokenService();
|
||||
|
||||
time_t start = time(NULL);
|
||||
while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
&&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED)
|
||||
&&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000);
|
||||
|
||||
if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
resp.setOk();
|
||||
else resp.setFail("Unknown GXS error!");
|
||||
}
|
||||
else resp.setFail("Unknown GXS error!");
|
||||
}
|
||||
|
||||
void ChannelsHandler::handleCreateChannel(Request& req, Response& resp)
|
||||
{
|
||||
RsGxsChannelGroup chan;
|
||||
RsGroupMetaData& cMeta = chan.mMeta;
|
||||
std::string authorIdStr;
|
||||
std::string thumbnail_base64;
|
||||
|
||||
req.mStream << makeKeyValueReference("author_id", authorIdStr)
|
||||
<< makeKeyValueReference("name", cMeta.mGroupName)
|
||||
<< makeKeyValueReference("description", chan.mDescription)
|
||||
<< makeKeyValueReference("thumbnail_base64_png", thumbnail_base64);
|
||||
|
||||
if(cMeta.mGroupName.empty())
|
||||
{
|
||||
resp.setFail("Channel name required!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(thumbnail_base64.empty()) chan.mImage.clear();
|
||||
else
|
||||
{
|
||||
std::vector<uint8_t> png_data = Radix64::decode(thumbnail_base64);
|
||||
if(!png_data.empty())
|
||||
{
|
||||
if(png_data.size() < 8)
|
||||
{
|
||||
resp.setFail("Decoded thumbnail_base64_png is smaller than 8 byte. This can't be a valid png file!");
|
||||
return;
|
||||
}
|
||||
uint8_t png_magic_number[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
|
||||
if(!std::equal(&png_magic_number[0],&png_magic_number[8],png_data.begin()))
|
||||
{
|
||||
resp.setFail("Decoded thumbnail_base64_png does not seem to be a png file. (Header is missing magic number)");
|
||||
return;
|
||||
}
|
||||
chan.mImage.copy(png_data.data(), png_data.size());
|
||||
}
|
||||
}
|
||||
|
||||
if(!authorIdStr.empty()) cMeta.mAuthorId = RsGxsId(authorIdStr);
|
||||
|
||||
// ATM supports creating only public channels
|
||||
cMeta.mGroupFlags = GXS_SERV::FLAG_PRIVACY_PUBLIC;
|
||||
|
||||
// I am not sure about those flags I have reversed them with the debugger
|
||||
// that gives 520 as value of this member when a channel with default
|
||||
// options is created from Qt Gui
|
||||
cMeta.mSignFlags = GXS_SERV::MSG_AUTHEN_CHILD_AUTHOR_SIGN |
|
||||
GXS_SERV::FLAG_AUTHOR_AUTHENTICATION_REQUIRED;
|
||||
|
||||
uint32_t token;
|
||||
if(mChannels.createGroup(token, chan))
|
||||
{
|
||||
RsTokenService& tChannels = *mChannels.getTokenService();
|
||||
|
||||
time_t start = time(NULL);
|
||||
while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
&&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED)
|
||||
&&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000);
|
||||
|
||||
if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
resp.setOk();
|
||||
else resp.setFail("Unknown GXS error!");
|
||||
}
|
||||
else resp.setFail("Unkown GXS error!");
|
||||
}
|
||||
|
||||
void ChannelsHandler::handleToggleAutoDownload(Request& req, Response& resp)
|
||||
{
|
||||
|
||||
std::string chanIdStr;
|
||||
bool autoDownload = true;
|
||||
|
||||
req.mStream << makeKeyValueReference("channel_id", chanIdStr)
|
||||
<< makeKeyValueReference("auto_download", autoDownload);
|
||||
|
||||
if(chanIdStr.empty())
|
||||
{
|
||||
resp.setFail("channel_id required!");
|
||||
return;
|
||||
}
|
||||
|
||||
RsGxsGroupId chanId(chanIdStr);
|
||||
if(chanId.isNull())
|
||||
{
|
||||
resp.setFail("Invalid channel_id:" + chanIdStr);
|
||||
return;
|
||||
}
|
||||
|
||||
if(mChannels.setChannelAutoDownload(chanId, autoDownload))
|
||||
resp.setOk();
|
||||
else resp.setFail();
|
||||
}
|
||||
|
||||
void ChannelsHandler::handleTogglePostRead(Request& req, Response& resp)
|
||||
{
|
||||
std::string chanIdStr;
|
||||
std::string postIdStr;
|
||||
bool read = true;
|
||||
|
||||
req.mStream << makeKeyValueReference("channel_id", chanIdStr)
|
||||
<< makeKeyValueReference("post_id", postIdStr)
|
||||
<< makeKeyValueReference("read", read);
|
||||
|
||||
if(chanIdStr.empty())
|
||||
{
|
||||
resp.setFail("channel_id required!");
|
||||
return;
|
||||
}
|
||||
|
||||
RsGxsGroupId chanId(chanIdStr);
|
||||
if(chanId.isNull())
|
||||
{
|
||||
resp.setFail("Invalid channel_id:" + chanIdStr);
|
||||
return;
|
||||
}
|
||||
|
||||
if(postIdStr.empty())
|
||||
{
|
||||
resp.setFail("post_id required!");
|
||||
return;
|
||||
}
|
||||
|
||||
RsGxsMessageId postId(postIdStr);
|
||||
if(postId.isNull())
|
||||
{
|
||||
resp.setFail("Invalid post_id:" + postIdStr);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << __PRETTY_FUNCTION__ << " " << chanIdStr << " " << postIdStr
|
||||
<< " " << read << std::endl;
|
||||
|
||||
uint32_t token;
|
||||
mChannels.setMessageReadStatus(token, std::make_pair(chanId,postId), read);
|
||||
|
||||
RsTokenService& tChannels = *mChannels.getTokenService();
|
||||
|
||||
time_t start = time(NULL);
|
||||
while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
&&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED)
|
||||
&&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000);
|
||||
|
||||
if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
resp.setOk();
|
||||
else resp.setFail("Unknown GXS error!");
|
||||
}
|
||||
|
||||
void ChannelsHandler::handleCreatePost(Request &req, Response &resp)
|
||||
{
|
||||
RsGxsChannelPost post;
|
||||
|
||||
req.mStream << makeKeyValueReference("group_id", post.mMeta.mGroupId);
|
||||
req.mStream << makeKeyValueReference("channel_id", post.mMeta.mGroupId);
|
||||
req.mStream << makeKeyValueReference("subject", post.mMeta.mMsgName);
|
||||
req.mStream << makeKeyValueReference("message", post.mMsg);
|
||||
|
||||
|
@ -53,36 +466,36 @@ ResponseTask* ChannelsHandler::handleCreatePost(Request &req, Response &resp)
|
|||
|
||||
if(post.mMeta.mGroupId.isNull())
|
||||
{
|
||||
resp.setFail("groupd_id is null");
|
||||
return 0;
|
||||
resp.setFail("groupd_id is null");
|
||||
return;
|
||||
}
|
||||
if(post.mMeta.mMsgName.empty())
|
||||
{
|
||||
resp.setFail("subject is empty");
|
||||
return 0;
|
||||
resp.setFail("subject is empty");
|
||||
return;
|
||||
}
|
||||
if(post.mMsg.empty())
|
||||
{
|
||||
resp.setFail("msg text is empty");
|
||||
return 0;
|
||||
resp.setFail("msg text is empty");
|
||||
return;
|
||||
}
|
||||
// empty file list is ok, but files have to be valid
|
||||
for(std::list<RsGxsFile>::iterator lit = post.mFiles.begin(); lit != post.mFiles.end(); ++lit)
|
||||
{
|
||||
if(lit->mHash.isNull())
|
||||
{
|
||||
resp.setFail("at least one file hash is empty");
|
||||
return 0;
|
||||
resp.setFail("at least one file hash is empty");
|
||||
return;
|
||||
}
|
||||
if(lit->mName.empty())
|
||||
{
|
||||
resp.setFail("at leats one file name is empty");
|
||||
return 0;
|
||||
resp.setFail("at leats one file name is empty");
|
||||
return;
|
||||
}
|
||||
if(lit->mSize == 0)
|
||||
{
|
||||
resp.setFail("at least one file size is empty");
|
||||
return 0;
|
||||
resp.setFail("at least one file size is empty");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,22 +504,33 @@ ResponseTask* ChannelsHandler::handleCreatePost(Request &req, Response &resp)
|
|||
{
|
||||
if(png_data.size() < 8)
|
||||
{
|
||||
resp.setFail("Decoded thumbnail_base64_png is smaller than 8 byte. This can't be a valid png file!");
|
||||
return 0;
|
||||
resp.setFail("Decoded thumbnail_base64_png is smaller than 8 byte. This can't be a valid png file!");
|
||||
return;
|
||||
}
|
||||
uint8_t png_magic_number[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
|
||||
if(!std::equal(&png_magic_number[0],&png_magic_number[8],png_data.begin()))
|
||||
{
|
||||
resp.setFail("Decoded thumbnail_base64_png does not seem to be a png file. (Header is missing magic number)");
|
||||
return 0;
|
||||
resp.setFail("Decoded thumbnail_base64_png does not seem to be a png file. (Header is missing magic number)");
|
||||
return;
|
||||
}
|
||||
post.mThumbnail.copy(png_data.data(), png_data.size());
|
||||
}
|
||||
|
||||
uint32_t token;
|
||||
mChannels->createPost(token, post);
|
||||
// TODO: grp creation acknowledge
|
||||
return 0;
|
||||
if(mChannels.createPost(token, post))
|
||||
{
|
||||
RsTokenService& tChannels = *mChannels.getTokenService();
|
||||
|
||||
time_t start = time(NULL);
|
||||
while((tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
&&(tChannels.requestStatus(token) != RsTokenService::GXS_REQUEST_V2_STATUS_FAILED)
|
||||
&&((time(NULL) < (start+10)))) rstime::rs_usleep(500*1000);
|
||||
|
||||
if(tChannels.requestStatus(token) == RsTokenService::GXS_REQUEST_V2_STATUS_COMPLETE)
|
||||
resp.setOk();
|
||||
else resp.setFail("Unknown GXS error!");
|
||||
}
|
||||
else resp.setFail("Unknown GXS error!");
|
||||
}
|
||||
|
||||
} // namespace resource_api
|
||||
|
|
|
@ -1,4 +1,21 @@
|
|||
#pragma once
|
||||
/*
|
||||
* RetroShare JSON API
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ResourceRouter.h"
|
||||
|
||||
|
@ -7,15 +24,21 @@ class RsGxsChannels;
|
|||
namespace resource_api
|
||||
{
|
||||
|
||||
class ChannelsHandler : public ResourceRouter
|
||||
struct ChannelsHandler : ResourceRouter
|
||||
{
|
||||
public:
|
||||
ChannelsHandler(RsGxsChannels* channels);
|
||||
ChannelsHandler(RsGxsChannels& channels);
|
||||
|
||||
private:
|
||||
ResponseTask* handleCreatePost(Request& req, Response& resp);
|
||||
void handleListChannels(Request& req, Response& resp);
|
||||
void handleGetChannelInfo(Request& req, Response& resp);
|
||||
void handleGetChannelContent(Request& req, Response& resp);
|
||||
void handleToggleSubscription(Request& req, Response& resp);
|
||||
void handleCreateChannel(Request& req, Response& resp);
|
||||
void handleToggleAutoDownload(Request& req, Response& resp);
|
||||
void handleTogglePostRead(Request& req, Response& resp);
|
||||
void handleCreatePost(Request& req, Response& resp);
|
||||
|
||||
RsGxsChannels* mChannels;
|
||||
RsGxsChannels& mChannels;
|
||||
};
|
||||
|
||||
} // namespace resource_api
|
||||
|
|
|
@ -37,6 +37,16 @@ FileSharingHandler::FileSharingHandler(StateTokenServer *sts, RsFiles *files,
|
|||
addResourceHandler("get_dir_parent", this, &FileSharingHandler::handleGetDirectoryParent);
|
||||
addResourceHandler("get_dir_childs", this, &FileSharingHandler::handleGetDirectoryChilds);
|
||||
|
||||
addResourceHandler( "get_download_directory", this,
|
||||
&FileSharingHandler::handleGetDownloadDirectory );
|
||||
addResourceHandler( "set_download_directory", this,
|
||||
&FileSharingHandler::handleSetDownloadDirectory );
|
||||
|
||||
addResourceHandler( "get_partials_directory", this,
|
||||
&FileSharingHandler::handleGetPartialsDirectory );
|
||||
addResourceHandler( "set_partials_directory", this,
|
||||
&FileSharingHandler::handleSetPartialsDirectory );
|
||||
|
||||
addResourceHandler("is_dl_dir_shared", this, &FileSharingHandler::handleIsDownloadDirShared);
|
||||
addResourceHandler("share_dl_dir", this, &FileSharingHandler::handleShareDownloadDirectory);
|
||||
|
||||
|
@ -513,4 +523,48 @@ void FileSharingHandler::handleDownload(Request& req, Response& resp)
|
|||
resp.setFail("Couldn't download file");
|
||||
}
|
||||
|
||||
void FileSharingHandler::handleGetDownloadDirectory( Request& /*req*/,
|
||||
Response& resp )
|
||||
{
|
||||
std::string dlDir = mRsFiles->getDownloadDirectory();
|
||||
resp.mDataStream << makeKeyValueReference("download_directory", dlDir);
|
||||
resp.setOk();
|
||||
}
|
||||
|
||||
void FileSharingHandler::handleSetDownloadDirectory( Request& req,
|
||||
Response& resp )
|
||||
{
|
||||
std::string dlDir;
|
||||
req.mStream << makeKeyValueReference("download_directory", dlDir);
|
||||
|
||||
if(dlDir.empty()) resp.setFail("missing download_directory");
|
||||
else
|
||||
{
|
||||
mRsFiles->setDownloadDirectory(dlDir);
|
||||
resp.setOk();
|
||||
}
|
||||
}
|
||||
|
||||
void FileSharingHandler::handleGetPartialsDirectory( Request& /*req*/,
|
||||
Response& resp )
|
||||
{
|
||||
std::string partialsDir = mRsFiles->getPartialsDirectory();
|
||||
resp.mDataStream << makeKeyValueReference("partials_directory", partialsDir);
|
||||
resp.setOk();
|
||||
}
|
||||
|
||||
void FileSharingHandler::handleSetPartialsDirectory( Request& req,
|
||||
Response& resp )
|
||||
{
|
||||
std::string partialsDir;
|
||||
req.mStream << makeKeyValueReference("partials_directory", partialsDir);
|
||||
|
||||
if(partialsDir.empty()) resp.setFail("missing partials_directory");
|
||||
else
|
||||
{
|
||||
mRsFiles->setPartialsDirectory(partialsDir);
|
||||
resp.setOk();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace resource_api
|
||||
|
|
|
@ -57,6 +57,12 @@ private:
|
|||
|
||||
void handleDownload(Request& req, Response& resp);
|
||||
|
||||
void handleGetDownloadDirectory(Request& req, Response& resp);
|
||||
void handleSetDownloadDirectory(Request& req, Response& resp);
|
||||
|
||||
void handleGetPartialsDirectory(Request& req, Response& resp);
|
||||
void handleSetPartialsDirectory(Request& req, Response& resp);
|
||||
|
||||
/// Token indicating change in local shared files
|
||||
StateToken mLocalDirStateToken;
|
||||
|
||||
|
|
|
@ -15,6 +15,14 @@ TransfersHandler::TransfersHandler(StateTokenServer *sts, RsFiles *files, RsPeer
|
|||
addResourceHandler("downloads", this, &TransfersHandler::handleDownloads);
|
||||
addResourceHandler("uploads", this, &TransfersHandler::handleUploads);
|
||||
addResourceHandler("control_download", this, &TransfersHandler::handleControlDownload);
|
||||
|
||||
addResourceHandler( "set_file_destination_directory", this,
|
||||
&TransfersHandler::handleSetFileDestinationDirectory );
|
||||
addResourceHandler( "set_file_destination_name", this,
|
||||
&TransfersHandler::handleSetFileDestinationName );
|
||||
addResourceHandler( "set_file_chunk_strategy", this,
|
||||
&TransfersHandler::handleSetFileChunkStrategy );
|
||||
|
||||
mStateToken = mStateTokenServer->getNewToken();
|
||||
mStateTokenServer->registerTickClient(this);
|
||||
mNotify.registerNotifyClient(this);
|
||||
|
@ -288,4 +296,58 @@ void TransfersHandler::handleUploads(Request & /* req */, Response &resp)
|
|||
resp.setOk();
|
||||
}
|
||||
|
||||
void TransfersHandler::handleSetFileDestinationDirectory( Request& req,
|
||||
Response& resp )
|
||||
{
|
||||
mStateTokenServer->replaceToken(mStateToken);
|
||||
|
||||
std::string hashString;
|
||||
std::string newPath;
|
||||
req.mStream << makeKeyValueReference("path", newPath);
|
||||
req.mStream << makeKeyValueReference("hash", hashString);
|
||||
RsFileHash hash(hashString);
|
||||
|
||||
if (mFiles->setDestinationDirectory(hash, newPath)) resp.setOk();
|
||||
else resp.setFail();
|
||||
}
|
||||
|
||||
void TransfersHandler::handleSetFileDestinationName( Request& req,
|
||||
Response& resp )
|
||||
{
|
||||
mStateTokenServer->replaceToken(mStateToken);
|
||||
|
||||
std::string hashString;
|
||||
std::string newName;
|
||||
req.mStream << makeKeyValueReference("name", newName);
|
||||
req.mStream << makeKeyValueReference("hash", hashString);
|
||||
RsFileHash hash(hashString);
|
||||
|
||||
if (mFiles->setDestinationName(hash, newName)) resp.setOk();
|
||||
else resp.setFail();
|
||||
}
|
||||
|
||||
void TransfersHandler::handleSetFileChunkStrategy(Request& req, Response& resp)
|
||||
{
|
||||
mStateTokenServer->replaceToken(mStateToken);
|
||||
|
||||
std::string hashString;
|
||||
std::string newChunkStrategyStr;
|
||||
req.mStream << makeKeyValueReference("chuck_stategy", newChunkStrategyStr);
|
||||
req.mStream << makeKeyValueReference("hash", hashString);
|
||||
|
||||
RsFileHash hash(hashString);
|
||||
FileChunksInfo::ChunkStrategy newStrategy =
|
||||
FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE;
|
||||
|
||||
if ( newChunkStrategyStr == "streaming" )
|
||||
newStrategy = FileChunksInfo::CHUNK_STRATEGY_STREAMING;
|
||||
else if ( newChunkStrategyStr == "random" )
|
||||
newStrategy = FileChunksInfo::CHUNK_STRATEGY_RANDOM;
|
||||
else if ( newChunkStrategyStr == "progressive" )
|
||||
newStrategy = FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE;
|
||||
|
||||
if (mFiles->setChunkStrategy(hash, newStrategy)) resp.setOk();
|
||||
else resp.setFail();
|
||||
}
|
||||
|
||||
} // namespace resource_api
|
||||
|
|
|
@ -30,6 +30,9 @@ private:
|
|||
void handleControlDownload(Request& req, Response& resp);
|
||||
void handleDownloads(Request& req, Response& resp);
|
||||
void handleUploads(Request& req, Response& resp);
|
||||
void handleSetFileDestinationDirectory(Request& req, Response& resp);
|
||||
void handleSetFileDestinationName(Request& req, Response& resp);
|
||||
void handleSetFileChunkStrategy(Request& req, Response& resp);
|
||||
|
||||
StateTokenServer* mStateTokenServer;
|
||||
RsFiles* mFiles;
|
||||
|
|
|
@ -2,50 +2,26 @@
|
|||
|
||||
TEMPLATE = lib
|
||||
CONFIG += staticlib
|
||||
CONFIG += create_prl
|
||||
CONFIG -= qt
|
||||
TARGET = resapi
|
||||
TARGET_PRL = libresapi
|
||||
DESTDIR = lib
|
||||
|
||||
DEPENDPATH += ../../libretroshare/src/
|
||||
!include(use_libresapi.pri):error("Including")
|
||||
|
||||
INCLUDEPATH += ../../libretroshare/src
|
||||
|
||||
libresapilocalserver {
|
||||
SOURCES *= api/ApiServerLocal.cpp
|
||||
HEADERS *= api/ApiServerLocal.h
|
||||
}
|
||||
|
||||
retroshare_android_service {
|
||||
win32 {
|
||||
OBJECTS_DIR = temp/obj
|
||||
|
||||
LIBS_DIR = $$PWD/../../libs/lib
|
||||
LIBS += $$OUT_PWD/../../libretroshare/src/lib/libretroshare.a
|
||||
LIBS += $$OUT_PWD/../../openpgpsdk/src/lib/libops.a
|
||||
|
||||
for(lib, LIB_DIR):LIBS += -L"$$lib"
|
||||
for(bin, BIN_DIR):LIBS += -L"$$bin"
|
||||
|
||||
|
||||
LIBS += -lssl -lcrypto -lpthread -lminiupnpc -lz -lws2_32
|
||||
LIBS += -luuid -lole32 -liphlpapi -lcrypt32 -lgdi32
|
||||
LIBS += -lwinmm
|
||||
|
||||
DEFINES *= WINDOWS_SYS WIN32_LEAN_AND_MEAN _USE_32BIT_TIME_T
|
||||
|
||||
DEPENDPATH += . $$INC_DIR
|
||||
INCLUDEPATH += . $$INC_DIR
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
# Qt 5
|
||||
RC_INCLUDEPATH += $$_PRO_FILE_PWD_/../../libretroshare/src
|
||||
} else {
|
||||
# Qt 4
|
||||
QMAKE_RC += --include-dir=$$_PRO_FILE_PWD_/../../libretroshare/src
|
||||
}
|
||||
}
|
||||
libresapi_settings {
|
||||
SOURCES += api/SettingsHandler.cpp
|
||||
HEADERS += api/SettingsHandler.h
|
||||
}
|
||||
|
||||
libresapihttpserver {
|
||||
CONFIG += libmicrohttpd
|
||||
|
||||
unix {
|
||||
|
||||
webui_files.path = "$${DATA_DIR}/webui"
|
||||
|
@ -121,20 +97,13 @@ libresapihttpserver {
|
|||
DEFINES *= WINDOWS_SYS
|
||||
INCLUDEPATH += . $$INC_DIR
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
# Qt 5
|
||||
PRO_PATH=$$shell_path($$_PRO_FILE_PWD_)
|
||||
MAKE_SRC=$$shell_path($$PRO_PATH/webui-src/make-src)
|
||||
} else {
|
||||
# Qt 4
|
||||
PRO_PATH=$$replace(_PRO_FILE_PWD_, /, \\)
|
||||
MAKE_SRC=$$PRO_PATH\\webui-src\\make-src
|
||||
}
|
||||
PRO_PATH=$$shell_path($$_PRO_FILE_PWD_)
|
||||
MAKE_SRC=$$shell_path($$PRO_PATH/webui-src/make-src)
|
||||
|
||||
#create_webfiles.commands = $$MAKE_SRC\\build.bat $$PRO_PATH
|
||||
#QMAKE_EXTRA_TARGETS += create_webfiles
|
||||
#PRE_TARGETDEPS += create_webfiles
|
||||
QMAKE_POST_LINK=$$MAKE_SRC\\build.bat $$PRO_PATH
|
||||
#create_webfiles.commands = $$MAKE_SRC\\build.bat $$PRO_PATH
|
||||
#QMAKE_EXTRA_TARGETS += create_webfiles
|
||||
#PRE_TARGETDEPS += create_webfiles
|
||||
QMAKE_POST_LINK=$$MAKE_SRC\\build.bat $$PRO_PATH
|
||||
|
||||
# create dummy files
|
||||
system($$MAKE_SRC\\init.bat .)
|
||||
|
@ -211,18 +180,3 @@ HEADERS += \
|
|||
api/ChannelsHandler.h \
|
||||
api/StatsHandler.h \
|
||||
api/FileSharingHandler.h
|
||||
|
||||
libresapilocalserver {
|
||||
CONFIG *= qt
|
||||
QT *= network
|
||||
SOURCES *= api/ApiServerLocal.cpp
|
||||
HEADERS *= api/ApiServerLocal.h
|
||||
}
|
||||
|
||||
qt_dependencies {
|
||||
CONFIG *= qt
|
||||
QT *= core
|
||||
|
||||
SOURCES += api/SettingsHandler.cpp
|
||||
HEADERS += api/SettingsHandler.h
|
||||
}
|
||||
|
|
37
libresapi/src/use_libresapi.pri
Normal file
37
libresapi/src/use_libresapi.pri
Normal file
|
@ -0,0 +1,37 @@
|
|||
DEPENDPATH *= $$system_path($$clean_path($$PWD/../../libresapi/src))
|
||||
INCLUDEPATH *= $$system_path($$clean_path($${PWD}/../../libresapi/src))
|
||||
LIBS *= -L$$system_path($$clean_path($${OUT_PWD}/../../libresapi/src/lib/)) -lresapi
|
||||
|
||||
!equals(TARGET, resapi):PRE_TARGETDEPS *= $$system_path($$clean_path($${OUT_PWD}/../../libresapi/src/lib/libresapi.a))
|
||||
|
||||
!include("../../libretroshare/src/use_libretroshare.pri"):error("Including")
|
||||
|
||||
sLibs =
|
||||
mLibs =
|
||||
dLibs =
|
||||
|
||||
libresapilocalserver {
|
||||
CONFIG *= qt
|
||||
QT *= network
|
||||
}
|
||||
|
||||
libresapi_settings {
|
||||
CONFIG *= qt
|
||||
QT *= core
|
||||
}
|
||||
|
||||
libresapihttpserver {
|
||||
mLibs *= microhttpd
|
||||
}
|
||||
|
||||
static {
|
||||
sLibs *= $$mLibs
|
||||
} else {
|
||||
dLibs *= $$mLibs
|
||||
}
|
||||
|
||||
LIBS += $$linkStaticLibs(sLibs)
|
||||
PRE_TARGETDEPS += $$pretargetStaticLibs(sLibs)
|
||||
|
||||
LIBS += $$linkDynamicLibs(dLibs)
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue