fixed conflicts with upstream/master

This commit is contained in:
csoler 2021-12-19 21:10:15 +01:00
commit 4a76fddaa9
186 changed files with 6793 additions and 5999 deletions

3
.gitmodules vendored
View File

@ -17,3 +17,6 @@
[submodule "supportlibs/libsam3"]
path = supportlibs/libsam3
url = https://github.com/i2p/libsam3.git
[submodule "supportlibs/jni.hpp"]
path = supportlibs/jni.hpp
url = https://github.com/RetroShare/jni.hpp.git

View File

@ -2,7 +2,7 @@
## image name must match gitlab repository name, you can play just with the tag
## the part after :
# export CI_IMAGE_NAME="registry.gitlab.com/retroshare/retroshare:android_arm_base"
# docker build --squash -t "${CI_REGISTRY_IMAGE}" \
# docker build --squash --tag "${CI_IMAGE_NAME}" \
# --build-arg QT_INSTALLER_JWT_TOKEN="your qt JWT token goes here" .
#
# To build Android ARMv8 (64 bit) package pass also
@ -25,14 +25,16 @@
FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
ENV APT_UNAT="--assume-yes --quiet"
RUN apt-get update && apt-get clean
RUN apt-get install -y -qq \
RUN apt-get update $APT_UNAT && apt-get upgrade --show-upgraded $APT_UNAT && \
apt-get clean $APT_UNAT
RUN apt-get install --no-install-recommends $APT_UNAT \
bash build-essential bzip2 cmake curl chrpath doxygen \
git p7zip python qt5-default qttools5-dev tclsh unzip wget zip
# Dependencies to create Android pkg
RUN apt-get install -y -qq \
RUN apt-get install --no-install-recommends $APT_UNAT \
openjdk-8-jre openjdk-8-jdk openjdk-8-jdk-headless gradle
ARG FRESHCLONE=0
@ -74,11 +76,11 @@ ARG QT_INSTALLER_JWT_TOKEN
RUN $PREPARE_TOOLCHAIN install_qt_android
# Avoid Qt account details leak into the image
RUN rm -f /root/.local/share/Qt/qtaccount.ini
# Shrink image by removing unneded Qt components
# Shrink image by removing unneeded Qt components
RUN rm -r \
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Docs/ \
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Examples/ \
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Tools/
$NATIVE_LIBS_TOOLCHAIN_PATH/Qt/Tools/
RUN mkdir /jsonapi-generator-build
WORKDIR /jsonapi-generator-build/

View File

@ -112,6 +112,9 @@ define_default_value MVPTREE_SOURCE_VERSION origin/master
define_default_value REPORT_DIR "$(pwd)/$(basename ${NATIVE_LIBS_TOOLCHAIN_PATH})_build_report/"
define_default_value RS_SRC_DIR "$(realpath $(dirname $BASH_SOURCE)/../../)"
cArch=""
eABI=""
cmakeABI=""
@ -829,6 +832,15 @@ build_phash()
popd
}
task_register fetch_jni_hpp
fetch_jni_hpp()
{
local rDir="supportlibs/jni.hpp/"
[ "$(ls "${RS_SRC_DIR}/${rDir}" | wc -l)" -gt "4" ] ||
git -C ${RS_SRC_DIR} submodule update --init ${rDir}
}
task_register build_mvptree
build_mvptree()
{
@ -862,6 +874,7 @@ build_default_toolchain()
task_run build_xapian || return $?
task_run build_miniupnpc || return $?
task_run build_phash || return $?
task_run fetch_jni_hpp || return $?
task_run deduplicate_includes || return $?
task_run get_native_libs_toolchain_path || return $?
}

View File

@ -1,7 +1,9 @@
ARG ANDROID_NDK_ARCH=arm
FROM registry.gitlab.com/retroshare/retroshare:android_${ANDROID_NDK_ARCH}_base
RUN apt-get update -y && apt-get upgrade -y
ENV APT_UNAT="--assume-yes --quiet"
RUN apt-get update $APT_UNAT && apt-get upgrade $APT_UNAT --show-upgraded
ARG REPO_URL=https://gitlab.com/RetroShare/RetroShare.git
ARG REPO_BRANCH=master

@ -1 +1 @@
Subproject commit b260e58346b1eec782bdf88a7e8f3c9d36fd3ecb
Subproject commit df16cb915465d058c75277678799ce4dadeae287

View File

@ -1,447 +1,10 @@
// SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team <contact@retroshare.cc>
// SPDX-FileCopyrightText: (C) 2021 Retroshare Team <contact@retroshare.cc>
// SPDX-License-Identifier: CC0-1.0
RetroShare JSON API
===================
= Moved
:Cxx: C&#43;&#43;
JSON API generator is now part of `libretroshare` look under `src/jsonapi/`
directory in `libretroshare` repository.
== How to use RetroShare JSON API
Look for methods marked with +@jsonapi+ doxygen custom command into
+libretroshare/src/retroshare+. The method path is composed by service instance
pointer name like +rsGxsChannels+ for +RsGxsChannels+, and the method name like
+createGroup+ and pass the input paramethers as a JSON object.
.Service instance pointer in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* Pointer to global instance of RsGxsChannels service implementation
* @jsonapi{development}
*/
extern RsGxsChannels* rsGxsChannels;
--------------------------------------------------------------------------------
.Method declaration in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* @brief Request channel creation.
* The action is performed asyncronously, so it could fail in a subsequent
* phase even after returning true.
* @jsonapi{development}
* @param[out] token Storage for RsTokenService token to track request
* status.
* @param[in] group Channel data (name, description...)
* @return false on error, true otherwise
*/
virtual bool createGroup(uint32_t& token, RsGxsChannelGroup& group) = 0;
--------------------------------------------------------------------------------
.paramethers.json
[source,json]
--------------------------------------------------------------------------------
{
"group":{
"mMeta":{
"mGroupName":"JSON test group",
"mGroupFlags":4,
"mSignFlags":520
},
"mDescription":"JSON test group description"
},
"caller_data":"Here can go any kind of JSON data (even objects) that the caller want to get back together with the response"
}
--------------------------------------------------------------------------------
.Calling the JSON API with curl on the terminal
[source,bash]
--------------------------------------------------------------------------------
curl -u $API_USER --data @paramethers.json http://127.0.0.1:9092/rsGxsChannels/createGroup
--------------------------------------------------------------------------------
.JSON API call result
[source,json]
--------------------------------------------------------------------------------
{
"caller_data": "Here can go any kind of JSON data (even objects) that the caller want to get back together with the response",
"retval": true,
"token": 3
}
--------------------------------------------------------------------------------
Even if it is less efficient because of URL encoding HTTP +GET+ method is
supported too, so in cases where the client cannot use +POST+ she can still use
+GET+ taking care of encoding the JSON data. With +curl+ this can be done at
least in two different ways.
.Calling the JSON API with GET method with curl on the terminal
[source,bash]
--------------------------------------------------------------------------------
curl -u $API_USER --get --data-urlencode jsonData@paramethers.json \
http://127.0.0.1:9092/rsGxsChannels/createGroup
--------------------------------------------------------------------------------
Letting +curl+ do the encoding is much more elegant but it is semantically
equivalent to the following.
.Calling the JSON API with GET method and pre-encoded data with curl on the terminal
--------------------------------------------------------------------------------
curl -u $API_USER http://127.0.0.1:9092/rsGxsChannels/createGroup?jsonData=%7B%0A%20%20%20%20%22group%22%3A%7B%0A%20%20%20%20%20%20%20%20%22mMeta%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupName%22%3A%22JSON%20test%20group%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupFlags%22%3A4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mSignFlags%22%3A520%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22mDescription%22%3A%22JSON%20test%20group%20description%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22caller_data%22%3A%22Here%20can%20go%20any%20kind%20of%20JSON%20data%20%28even%20objects%29%20that%20the%20caller%20want%20to%20get%20back%20together%20with%20the%20response%22%0A%7D
--------------------------------------------------------------------------------
Note that using +GET+ method +?jsonData=+ and then the JSON data URL encoded are
added after the path in the HTTP request.
== JSON API authentication
Most of JSON API methods require authentication as they give access to
RetroShare user data, and we don't want any application running on the system
eventually by other users be able to access private data indiscriminately.
JSON API support HTTP Basic as authentication scheme, this is enough as JSON API
server is intented for usage on the same system (127.0.0.1) not over an
untrusted network.
If you need to use JSON API over an untrusted network consider using a reverse
proxy with HTTPS such as NGINX in front of JSON API server.
If RetroShare login has been effectuated through the JSON API you can use your
location SSLID as username and your PGP password as credential for the JSON API,
but we suggests you use specific meaningful and human readable credentials for
each JSON API client so the human user can have better control over which client
can access the JSON API.
.NewToken.json
[source,json]
--------------------------------------------------------------------------------
{
"token": "myNewUser:myNewPassword"
}
--------------------------------------------------------------------------------
.An authenticated client can authorize new tokens like this
--------------------------------------------------------------------------------
curl -u $API_USER --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/authorizeToken
--------------------------------------------------------------------------------
.An unauthenticated JSON API client can request access with
--------------------------------------------------------------------------------
curl --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/requestNewTokenAutorization
--------------------------------------------------------------------------------
When an unauthenticated client request his token to be authorized, JSON API
server will try to ask confirmation to the human user if possible through
+mNewAccessRequestCallback+, if it is not possible or the user didn't authorized
the token +false+ is returned.
== Offer new RetroShare services through JSON API
To offer a retroshare service through the JSON API, first of all one need find
the global pointer to the service instance and document it in doxygen syntax,
plus marking with the custom doxygen command +@jsonapi{RS_VERSION}+ where
+RS_VERSION+ is the retroshare version in which this service became available
with the current semantic (major changes to the service semantic, changes the
meaning of the service itself, so the version should be updated in the
documentation in that case).
.Service instance pointer in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* Pointer to global instance of RsGxsChannels service implementation
* @jsonapi{development}
*/
extern RsGxsChannels* rsGxsChannels;
--------------------------------------------------------------------------------
Once the service instance itself is known to the JSON API you need to document
in doxygen syntax and mark with the custom doxygen command
+@jsonapi{RS_VERSION}+ the methods of the service that you want to make
available through JSON API.
.Offering RsGxsChannels::getChannelDownloadDirectory in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* Get download directory for the given channel
* @jsonapi{development}
* @param[in] channelId id of the channel
* @param[out] directory reference to string where to store the path
* @return false on error, true otherwise
*/
virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId,
std::string& directory ) = 0;
--------------------------------------------------------------------------------
For each paramether you must specify if it is used as input +@param[in]+ as
output +@param[out]+ or both +@param[inout]+. Paramethers and return value
types must be of a type supported by +RsTypeSerializer+ which already support
most basic types (+bool+, +std::string+...), +RsSerializable+ and containers of
them like +std::vector<std::string>+. Paramethers passed by value and by
reference of those types are both supported, while passing by pointer is not
supported. If your paramether or return +class+/+struct+ type is not supported
yet by +RsTypeSerializer+ most convenient approach is to make it derive from
+RsSerializable+ and implement +serial_process+ method like I did with
+RsGxsChannelGroup+.
.Deriving RsGxsChannelGroup from RsSerializable in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
struct RsGxsChannelGroup : RsSerializable
{
RsGroupMetaData mMeta;
std::string mDescription;
RsGxsImage mImage;
bool mAutoDownload;
/// @see RsSerializable
virtual void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx )
{
RS_SERIAL_PROCESS(mMeta);
RS_SERIAL_PROCESS(mDescription);
RS_SERIAL_PROCESS(mImage);
RS_SERIAL_PROCESS(mAutoDownload);
}
};
--------------------------------------------------------------------------------
You can do the same recursively for any member of your +struct+ that is not yet
supported by +RsTypeSerializer+.
Some Retroshare {Cxx} API functions are asyncronous, historically RetroShare
didn't follow a policy on how to expose asyncronous API so differents services
and some times even differents method of the same service follow differents
asyncronous patterns, thus making automatic generation of JSON API wrappers for
those methods impractical. Instead of dealing with all those differents patterns
I have chosed to support only one new pattern taking advantage of modern {Cxx}11
and restbed features. On the {Cxx}11 side lambdas and +std::function+s are used,
on the restbed side Server Side Events are used to send asyncronous results.
Lets see an example so it will be much esier to understand.
.RsGxsChannels::turtleSearchRequest asyncronous API
[source,cpp]
--------------------------------------------------------------------------------
/**
* @brief Request remote channels search
* @jsonapi{development}
* @param[in] matchString string to look for in the search
* @param multiCallback function that will be called each time a search
* result is received
* @param[in] maxWait maximum wait time in seconds for search results
* @return false on error, true otherwise
*/
virtual bool turtleSearchRequest(
const std::string& matchString,
const std::function<void (const RsGxsGroupSummary& result)>& multiCallback,
std::time_t maxWait = 300 ) = 0;
--------------------------------------------------------------------------------
+RsGxsChannels::turtleSearchRequest(...)+ is an asyncronous method because it
send a channel search request on turtle network and then everytime a result is
received from the network +multiCallback+ is called and the result is passed as
parameter. To be supported by the automatic JSON API wrappers generator an
asyncronous method need a parameter of type +std::function<void (...)>+ called
+callback+ if the callback will be called only once or +multiCallback+ if the
callback is expected to be called more then once like in this case.
A second mandatory parameter is +maxWait+ of type +std::time_t+ it indicates the
maximum amount of time in seconds for which the caller is willing to wait for
results, in case the timeout is reached the callback will not be called anymore.
[IMPORTANT]
================================================================================
+callback+ and +multiCallback+ parameters documentation must *not* specify
+[in]+, +[out]+, +[inout]+, in Doxygen documentation as this would fool the
automatic wrapper generator, and ultimately break the compilation.
================================================================================
.RsFiles::turtleSearchRequest asyncronous JSON API usage example
[source,bash]
--------------------------------------------------------------------------------
$ cat turtle_search.json
{
"matchString":"linux"
}
$ curl --data @turtle_search.json http://127.0.0.1:9092/rsFiles/turtleSearchRequest
data: {"retval":true}
data: {"results":[{"size":157631,"hash":"69709b4d01025584a8def5cd78ebbd1a3cf3fd05","name":"kill_bill_linux_1024x768.jpg"},{"size":192560,"hash":"000000000000000000009a93e5be8486c496f46c","name":"coffee_box_linux2.jpg"},{"size":455087,"hash":"9a93e5be8486c496f46c00000000000000000000","name":"Linux.png"},{"size":182004,"hash":"e8845280912ebf3779e400000000000000000000","name":"Linux_2_6.png"}]}
data: {"results":[{"size":668,"hash":"e8845280912ebf3779e400000000000000000000","name":"linux.png"},{"size":70,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.txt.sha1sum"},{"size":3076767744,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.iso"},{"size":2780872,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.bin"},{"size":917504,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.lzma"},{"size":2278404096,"hash":"e8845280912ebf3779e400000000000000000000","name":"gentoo-linux-livedvd-amd64-multilib-20160704.iso"},{"size":151770333,"hash":"e8845280912ebf3779e400000000000000000000","name":"flashtool-0.9.23.0-linux.tar.7z"},{"size":2847372,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.elf"},{"size":1310720,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.gz"},{"size":987809,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux-lzma.elf"}]}
--------------------------------------------------------------------------------
By default JSON API methods requires client authentication and their wrappers
are automatically generated by +json-api-generator+.
In some cases methods need do be accessible without authentication such as
+rsLoginHelper/getLocations+ so in the doxygen documentaion they have the custom
command +@jsonapi{RS_VERSION,unauthenticated}+.
Other methods such as +/rsControl/rsGlobalShutDown+ need special care so they
are marked with the custom doxygen command +@jsonapi{RS_VERSION,manualwrapper}+
and their wrappers are not automatically generated but written manually into
+JsonApiServer::JsonApiServer(...)+.
== Quirks
=== 64 bits integers handling
While JSON doesn't have problems representing 64 bits integers JavaScript, Dart
and other languages are not capable to handle those numbers natively.
To overcome this limitation JSON API output 64 bit integers as an object with
two keys, one as proper integer and one as string representation.
.JSON API 64 bit integer output example
[source,json]
--------------------------------------------------------------------------------
"lobby_id": { "xint64": 6215642878098695544, "xstr64": "6215642878098695544" }
--------------------------------------------------------------------------------
So from languages that have proper 64bit integers support like Python or C++ one
better read from `xint64` which is represented as a JSON integer, from languages
where there is no proper 64bit integers support like JavaScript one can read from
`xstr64` which is represented as JSON string (note that the first is not wrapped
in "" while the latter is).
When one input a 64bit integer into the JSON API it first try to parse it as if
it was sent the old way for retrocompatibility.
.JSON API 64 bit integer deprecated format input example
[source,json]
--------------------------------------------------------------------------------
"lobby_id":6215642878098695544
--------------------------------------------------------------------------------
This way is *DEPRECATED* and may disappear in the future, it is TEMPORALLY kept
only for retrocompatibiliy with old clients.
If retrocompatible parsing attempt fail then it try to parse with the new way
with proper JSON integer format.
.JSON API 64 bit integer new proper integer format input example
[source,json]
--------------------------------------------------------------------------------
lobby_id": { "xint64": 6215642878098695544 }
--------------------------------------------------------------------------------
If this fails then it try to parse with the new way with JSON string format.
.JSON API 64 bit integer new string format input example
[source,json]
--------------------------------------------------------------------------------
"lobby_id": { "xstr64": "6215642878098695544" }
--------------------------------------------------------------------------------
[WARNING]
================================================================================
Clients written in languages without proper 64bit integers support must
use *ONLY* the string format otherwise they will send approximated values and
get unexpected results from the JSON API, because parsing will success but the
value will not be exactly the one you believe you sent.
================================================================================
== A bit of history
=== First writings about this
The previous attempt of exposing a RetroShare JSON API is called +libresapi+ and
unfortunatley it requires a bunch of boilerplate code when we want to expose
something present in the {Cxx} API in the JSON API.
As an example here you can see the libresapi that exposes part of the retroshare
chat {Cxx} API and lot of boilerplate code just to convert {Cxx} objects to JSON
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L44
To avoid the {Cxx} to JSON and back conversion boilerplate code I have worked out
an extension to our {Cxx} serialization code so it is capable to serialize and
deserialize to JSON you can see it in this pull request
https://github.com/RetroShare/RetroShare/pull/1155
So first step toward having a good API is to take advantage of the fact that RS
is now capable of converting C++ objects from and to JSON.
The current API is accessible via HTTP and unix socket, there is no
authentication in both of them, so anyone having access to the HTTP server or to
the unix socket can access the API without extra restrictions.
Expecially for the HTTP API this is a big risk because also if the http server
listen on 127.0.0.1 every application on the machine (even rogue javascript
running on your web browser) can access that and for example on android it is
not safe at all (because of that I implemented the unix socket access so at
least in android API was reasonably safe) because of this.
A second step to improve the API would be to implement some kind of API
authentication mechanism (it would be nice that the mechanism is handled at API
level and not at transport level so we can use it for any API trasport not just
HTTP for example)
The HTTP server used by libresapi is libmicrohttpd server that is very minimal,
it doesn't provide HTTPS nor modern HTTP goodies, like server notifications,
websockets etc. because the lack of support we have a token polling mechanism in
libresapi to avoid polling for every thing but it is still ugly, so if we can
completely get rid of polling in the API that would be really nice.
I have done a crawl to look for a replacement and briefly looked at
- https://www.gnu.org/software/libmicrohttpd/
- http://wolkykim.github.io/libasyncd/
- https://github.com/corvusoft/restbed
- https://code.facebook.com/posts/1503205539947302/introducing-proxygen-facebook-s-c-http-framework/
- https://github.com/cmouse/yahttp
taking in account a few metrics like modern HTTP goodies support, license,
platform support, external dependencies and documentation it seemed to me that
restbed is the more appropriate.
Another source of boilerplate code into libresapi is the mapping between JSON
API requests and C++ API methods as an example you can look at this
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L158
and this
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ApiServer.cpp#L253
The abstract logic of this thing is, when libreasapi get a request like
+/chat/initiate_distant_chat+ then call
+ChatHandler::handleInitiateDistantChatConnexion+ which in turn is just a
wrapper of +RsMsgs::initiateDistantChatConnexion+ all this process is basically
implemented as boilerplate code and would be unnecessary in a smarter design of
the API because almost all the information needed is already present in the
C++ API +libretroshare/src/retroshare+.
So a third step to improve the JSON API would be to remove this source of
boilerplate code by automatizing the mapping between C++ and JSON API call.
This may result a little tricky as language parsing or other adevanced things
may be required.
Hope this dive is useful for you +
Cheers +
G10h4ck
=== Second writings about this
I have been investigating a bit more about:
[verse, G10h4ck]
________________________________________________________________________________
So a third step to improve the JSON API would be to remove this source of
boilerplate code by automatizing the mapping between C++ and JSON API call
________________________________________________________________________________
After spending some hours investigating this topic the most reasonable approach
seems to:
1. Properly document headers in +libretroshare/src/retroshare/+ in doxygen syntax
specifying wihich params are input and/or output (doxygen sysntax for this is
+@param[in/out/inout]+) this will be the API documentation too.
2. At compile time use doxygen to generate XML description of the headers and use
the XML to generate the JSON api server stub.
http://www.stack.nl/~dimitri/doxygen/manual/customize.html#xmlgenerator
3. Enjoy
This directory and all it's content is kept as is only for retro-compatibility
with the old, deprecated `qmake` build system.

View File

@ -1,80 +0,0 @@
/*******************************************************************************
* RetroShare JSON API *
* *
* Copyright (C) 2018-2019 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 version 3 as *
* published by the Free Software Foundation. *
* *
* 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
registerHandler( "$%apiPath%$",
[this](const std::shared_ptr<rb::Session> session)
{
const std::multimap<std::string, std::string> headers
{
{ "Connection", "keep-alive" },
{ "Content-Type", "text/event-stream" }
};
session->yield(rb::OK, headers);
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
session->fetch( reqSize, [this](
const std::shared_ptr<rb::Session> session,
const rb::Bytes& body )
{
INITIALIZE_API_CALL_JSON_CONTEXT;
if( !checkRsServicePtrReady(
$%instanceName%$, "$%instanceName%$", cAns, session ) )
return;
$%paramsDeclaration%$
$%inputParamsDeserialization%$
const std::weak_ptr<rb::Service> weakService(mService);
const std::weak_ptr<rb::Session> weakSession(session);
$%callbackName%$ = [weakService, weakSession]($%callbackParams%$)
{
auto session = weakSession.lock();
if(!session || session->is_closed()) return;
auto lService = weakService.lock();
if(!lService || lService->is_down()) return;
$%callbackParamsSerialization%$
std::stringstream sStream;
sStream << "data: " << compactJSON << ctx.mJson << "\n\n";
const std::string message = sStream.str();
lService->schedule( [weakSession, message]()
{
auto session = weakSession.lock();
if(!session || session->is_closed()) return;
session->yield(message);
$%sessionEarlyClose%$
} );
};
$%functionCall%$
$%outputParamsSerialization%$
// return them to the API caller
std::stringstream message;
message << "data: " << compactJSON << cAns.mJson << "\n\n";
session->yield(message.str());
$%sessionDelayedClose%$
} );
}, $%requiresAuth%$ );

View File

@ -0,0 +1 @@
../../libretroshare/src/jsonapi/async-method-wrapper-template.cpp.tmpl

View File

@ -1,230 +0,0 @@
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libretroshare"
ALIASES += jsonapi{1}="\xmlonly<jsonapi minversion=\"\1\"/>\endxmlonly"
ALIASES += jsonapi{2}="\xmlonly<jsonapi minversion=\"\1\" access=\"\2\"/>\endxmlonly"
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
INHERIT_DOCS = YES
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
# The default value is: YES.
MARKDOWN_SUPPORT = YES
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
# Note: This will also disable the warnings about undocumented members that are
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
# section is generated. This option has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
#INPUT =
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f \
*.for \
*.tcl \
*.vhd \
*.vhdl \
*.ucf \
*.qsf
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
#
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
# The default value is: NO.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories.
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = NO
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
GENERATE_XML = YES
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
# EXPAND_AS_DEFINED tags.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_ONLY_PREDEF = NO

View File

@ -0,0 +1 @@
../../libretroshare/src/jsonapi/jsonapi-generator-doxygen.conf

View File

@ -1,50 +0,0 @@
/*******************************************************************************
* RetroShare JSON API *
* *
* Copyright (C) 2018-2019 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
registerHandler( "$%apiPath%$",
[](const std::shared_ptr<rb::Session> session)
{
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
session->fetch( reqSize, [](
const std::shared_ptr<rb::Session> session,
const rb::Bytes& body )
{
INITIALIZE_API_CALL_JSON_CONTEXT;
if( !checkRsServicePtrReady(
$%instanceName%$, "$%instanceName%$", cAns, session ) )
return;
$%paramsDeclaration%$
// deserialize input parameters from JSON
$%inputParamsDeserialization%$
// call retroshare C++ API
$%functionCall%$
// serialize out parameters and return value to JSON
$%outputParamsSerialization%$
// return them to the API caller
DEFAULT_API_CALL_JSON_RETURN(rb::OK);
} );
}, $%requiresAuth%$ );

View File

@ -0,0 +1 @@
../../libretroshare/src/jsonapi/method-wrapper-template.cpp.tmpl

19
libbitdht/CMakeLists.txt Normal file
View File

@ -0,0 +1,19 @@
# RetroShare decentralized communication platform
#
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
#
# SPDX-License-Identifier: CC0-1.0
cmake_minimum_required (VERSION 2.8.12)
project(bitdht)
file(
GLOB BITDHT_SOURCES
src/bitdht/*.c src/bitdht/*.cc src/udp/*.cc src/util/*.cc )
add_library(${PROJECT_NAME} ${BITDHT_SOURCES})
target_include_directories(
${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src )

View File

@ -0,0 +1,411 @@
# RetroShare decentralized communication platform
#
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
#
# SPDX-License-Identifier: CC0-1.0
cmake_minimum_required (VERSION 3.18.0)
project(retroshare)
include(CMakeDependentOption)
set(FETCHCONTENT_QUIET OFF)
include(FetchContent)
# sqlcipher
option(
RS_SQLCIPHER
"SQLCipher encryption for GXS database"
ON )
# rs_gxs_send_all
option(
RS_GXS_SEND_ALL
"GXS distribute all available messages on request, indipendently from \
local sync timer"
ON )
# bitdht
option(
RS_BITDHT
"Use bitdht (BitTorrent DHT own implementation) to look for online peers"
ON )
# use_dht_stunner
cmake_dependent_option(
RS_BITDHT_STUNNER
"Use bitdht (BitTorrent DHT own implementation) for NAT type discovery and \
attempt the STUN (Session Traversal Utilities for NAT)"
ON
"RS_BITDHT"
OFF )
# use_dht_stunner_ext_ip
cmake_dependent_option(
RS_BITDHT_STUNNER_EXT_IP
"Use bitdht (BitTorrent DHT own implementation) stunner to figure out our \
external IP. As this purely relying on random DHT peers that answer our \
request, it can easily be abused. Therefore, it is turned off by default."
OFF
"RS_BITDHT_STUNNER"
OFF )
# rs_jsonapi
option(
RS_JSON_API
"Use restbed to expose libretroshare as JSON API via HTTP"
OFF )
# rs_deep_forums_index
option(
RS_FORUM_DEEP_INDEX
"Xapian based full text index and search of GXS forums"
OFF )
# rs_broadcast_discovery
option(
RS_BRODCAST_DISCOVERY
"Local area network peer discovery via udp-discovery-cpp"
ON )
# rs_dh_init_check
option(
RS_DH_PRIME_INIT_CHECK
"Check Diffie Hellman prime at each startup. This is not necessary and on \
all Android mobile phones tested this take at least one minute at startup \
which is untolerable for most phone users."
ON )
option(
RS_MINIUPNPC
"Forward ports in NAT router via miniupnpc"
ON )
cmake_dependent_option(
RS_LIBUPNP
"Forward ports in NAT router via libupnp (unstable)"
OFF
"NOT RS_MINIUPNPC"
OFF )
option(
RS_LIBRETROSHARE_STATIC
"Build RetroShare static library"
ON )
cmake_dependent_option(
RS_LIBRETROSHARE_SHARED
"Build RetroShare shared library"
OFF
"NOT RS_LIBRETROSHARE_STATIC"
OFF )
# rs_deprecatedwarning
option(
RS_WARN_DEPRECATED
"Print warning about RetroShare deprecated components usage during build"
ON )
# rs_cppwarning
option(
RS_WARN_LESS
"Silence a few at the moment very common warnings about RetroShare \
components during build"
OFF )
# rs_v07_changes
option(
RS_V07_BREAKING_CHANGES
"Enable retro-compatibility breaking changes planned for RetroShare 0.7.0"
OFF )
set(
RS_DATA_DIR
"${CMAKE_INSTALL_PREFIX}/share/retroshare"
CACHE STRING
"Path where to install RetroShare system wide data" )
################################################################################
find_package(Git REQUIRED)
#function(check_submodule sPath)
# if(NOT EXISTS "${sPath}/.git" )
# message("Initializing submodule ${sPath}")
# execute_process(
# COMMAND "${GIT_EXECUTABLE}" submodule update --init
# WORKING_DIRECTORY "${sPath}"
# COMMAND_ECHO STDERR
# COMMAND_ERROR_IS_FATAL ANY)
# endif()
#endfunction()
################################################################################
include(src/CMakeLists.txt)
list(TRANSFORM RS_SOURCES PREPEND src/)
list(TRANSFORM RS_PUBLIC_HEADERS PREPEND src/)
if(RS_LIBRETROSHARE_STATIC)
add_library(${PROJECT_NAME} STATIC ${RS_SOURCES})
endif(RS_LIBRETROSHARE_STATIC)
if(RS_LIBRETROSHARE_SHARED)
add_library(${PROJECT_NAME} SHARED ${RS_SOURCES})
## Ensure statically linked libraries such as openpgpsdk are compiled with
## PIC Which is needed for shared library
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif(RS_LIBRETROSHARE_SHARED)
target_include_directories(
${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src )
find_package(OpenSSL REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL OpenSSL::Crypto)
################################################################################
set(OPENPGPSDK_DEVEL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../openpgpsdk/")
if(EXISTS "${OPENPGPSDK_DEVEL_DIR}/.git" )
message(
CHECK_PASS
"openpgpsdk submodule found at ${OPENPGPSDK_DEVEL_DIR} using it" )
add_subdirectory(${OPENPGPSDK_DEVEL_DIR} ${CMAKE_BINARY_DIR}/openpgpsdk)
else()
FetchContent_Declare(
openpgpsdk
GIT_REPOSITORY "https://gitlab.com/RetroShare/openpgpsdk.git"
GIT_TAG "origin/master"
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
TIMEOUT 10
)
FetchContent_MakeAvailable(openpgpsdk)
endif()
target_link_libraries(${PROJECT_NAME} PRIVATE openpgpsdk)
################################################################################
if(RS_BITDHT)
set(BITDHT_DEVEL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../libbitdht/")
if(EXISTS "${BITDHT_DEVEL_DIR}/.git" )
message(
CHECK_PASS
"BitDHT submodule found at ${BITDHT_DEVEL_DIR} using it" )
add_subdirectory(${BITDHT_DEVEL_DIR} ${CMAKE_BINARY_DIR}/bitdht)
else()
FetchContent_Declare(
bitdht
GIT_REPOSITORY "https://gitlab.com/RetroShare/bitdht.git"
GIT_TAG "origin/master"
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
TIMEOUT 10
)
FetchContent_MakeAvailable(bitdht)
endif()
add_compile_definitions(RS_USE_BITDHT)
target_link_libraries(${PROJECT_NAME} PRIVATE bitdht)
if(RS_BITDHT_STUNNER)
add_compile_definitions(RS_USE_DHT_STUNNER)
if(RS_BITDHT_STUNNER_EXT_IP)
# TODO: Refactor this define to use proper naming
add_compile_definitions(ALLOW_DHT_STUNNER)
endif(RS_BITDHT_STUNNER_EXT_IP)
endif(RS_BITDHT_STUNNER)
endif(RS_BITDHT)
################################################################################
if(RS_JSON_API)
find_package(Doxygen REQUIRED)
find_package(Python3 REQUIRED)
## TODO: execute at build time instead that at cofiguration time see
## add_custom_command or add_custom_target
set(
JSON_API_GENERATOR_WORK_DIR
"${CMAKE_BINARY_DIR}/jsonapi-generator.workdir/" )
set(
JSON_API_GENERATOR_DOXYFILE
"${JSON_API_GENERATOR_WORK_DIR}/jsonapi-generator-doxygen.conf" )
set(
JSONAPI_GENERATOR_OUTPUT_DIR
"${JSON_API_GENERATOR_WORK_DIR}/src/" )
set(
JSONAPI_GENERATOR_SOURCE_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/src/jsonapi/" )
set(
JSONAPI_GENERATOR_EXECUTABLE
"${JSONAPI_GENERATOR_SOURCE_DIR}/jsonapi-generator.py" )
file(
COPY "src/jsonapi/jsonapi-generator-doxygen.conf"
DESTINATION "${JSON_API_GENERATOR_WORK_DIR}" )
file(
APPEND
"${JSON_API_GENERATOR_DOXYFILE}"
"OUTPUT_DIRECTORY=${JSONAPI_GENERATOR_OUTPUT_DIR}\n"
"INPUT=${CMAKE_CURRENT_SOURCE_DIR}" )
add_custom_command(
OUTPUT
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-includes.inl"
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-wrappers.inl"
COMMAND ${DOXYGEN_EXECUTABLE} ${JSON_API_GENERATOR_DOXYFILE}
COMMAND
${Python3_EXECUTABLE} ${JSONAPI_GENERATOR_EXECUTABLE}
${JSONAPI_GENERATOR_SOURCE_DIR} ${JSONAPI_GENERATOR_OUTPUT_DIR}
MAIN_DEPENDENCY "${JSONAPI_GENERATOR_EXECUTABLE}"
DEPENDS ${JSON_API_GENERATOR_DOXYFILE} ${RS_PUBLIC_HEADERS} )
target_sources(
${PROJECT_NAME} PRIVATE
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-includes.inl"
"${JSONAPI_GENERATOR_OUTPUT_DIR}/jsonapi-wrappers.inl" )
include_directories(${JSONAPI_GENERATOR_OUTPUT_DIR})
set(BUILD_TESTS OFF CACHE BOOL "Do not build restbed tests")
set(BUILD_SSL OFF CACHE BOOL "Do not build restbed SSL support")
FetchContent_Declare(
restbed
GIT_REPOSITORY "https://github.com/Corvusoft/restbed.git"
GIT_TAG "4.8"
GIT_SUBMODULES dependency/asio dependency/catch
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
TIMEOUT 10
)
FetchContent_MakeAvailable(restbed)
target_link_libraries(${PROJECT_NAME} PRIVATE restbed)
## TODO: work around target_include_directories should be added upstream
include_directories(${restbed_SOURCE_DIR}/source/)
add_compile_definitions(RS_JSONAPI)
endif(RS_JSON_API)
################################################################################
if(RS_FORUM_DEEP_INDEX)
find_package(Xapian REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE ${XAPIAN_LIBRARIES})
add_compile_definitions(RS_DEEP_FORUMS_INDEX)
endif(RS_FORUM_DEEP_INDEX)
################################################################################
## TODO: Check if https://github.com/rbock/sqlpp11 or
## https://github.com/rbock/sqlpp17 may improve GXS code
if(RS_SQLCIPHER)
find_library(RS_SQL_LIB "sqlcipher" REQUIRED)
find_path(
RS_SQL_LIB_INCLUDE "sqlcipher/sqlite3.h"
PATH_SUFFIXES "include" "includes"
REQUIRED )
target_include_directories(
${PROJECT_NAME}
PRIVATE "${RS_SQL_LIB_INCLUDE}/sqlcipher" )
target_link_libraries(${PROJECT_NAME} PRIVATE ${RS_SQL_LIB})
else()
add_compile_definitions(NO_SQLCIPHER)
find_package(SQLite3 REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE SQLite::SQLite3)
endif()
add_compile_definitions(
SQLITE_HAS_CODEC
RS_ENABLE_GXS
GXS_ENABLE_SYNC_MSGS
RS_USE_GXS_DISTANT_SYNC
RS_GXS_TRANS
V07_NON_BACKWARD_COMPATIBLE_CHANGE_001
V07_NON_BACKWARD_COMPATIBLE_CHANGE_002
V07_NON_BACKWARD_COMPATIBLE_CHANGE_003 )
if(RS_V07_BREAKING_CHANGES)
add_compile_definitions(
V07_NON_BACKWARD_COMPATIBLE_CHANGE_004
V07_NON_BACKWARD_COMPATIBLE_CHANGE_UNNAMED )
endif()
if(RS_DH_PRIME_INIT_CHECK)
add_compile_definitions(RS_DISABLE_DIFFIE_HELLMAN_INIT_CHECK)
endif(RS_DH_PRIME_INIT_CHECK)
if(RS_MINIUPNPC)
add_compile_definitions(RS_USE_LIBMINIUPNPC)
endif(RS_MINIUPNPC)
if(RS_LIBUPNP)
message(FATAL_ERROR "UPnP support via libupnp is currently not supported")
#add_compile_definitions(RS_USE_LIBUPNP)
endif(RS_LIBUPNP)
if(RS_GXS_SEND_ALL)
add_compile_definitions(RS_GXS_SEND_ALL)
endif(RS_GXS_SEND_ALL)
if(RS_BRODCAST_DISCOVERY)
## TODO: upstream option to disable tests building
set(BUILD_EXAMPLE OFF CACHE BOOL "Do not build udp-discovery-cpp examples")
set(BUILD_TOOL OFF CACHE BOOL "Do not build udp-discovery-tool application")
FetchContent_Declare(
udp-discovery-cpp
GIT_REPOSITORY "https://github.com/truvorskameikin/udp-discovery-cpp.git"
GIT_TAG "origin/master"
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
TIMEOUT 10
)
FetchContent_MakeAvailable(udp-discovery-cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE udp-discovery-cpp)
## TODO: Temporary work around target_include_directories should be added
## upstream
include_directories(${udp-discovery-cpp_SOURCE_DIR})
endif(RS_BRODCAST_DISCOVERY)
if(NOT RS_WARN_DEPRECATED)
add_compile_definitions(RS_NO_WARN_DEPRECATED)
target_compile_options(
${PROJECT_NAME} PRIVATE
-Wno-deprecated -Wno-deprecated-declarations )
endif(NOT RS_WARN_DEPRECATED)
if(RS_WARN_LESS)
add_compile_definitions(RS_NO_WARN_CPP)
target_compile_options(
${PROJECT_NAME} PRIVATE
-Wno-cpp -Wno-inconsistent-missing-override )
endif(RS_WARN_LESS)
################################################################################
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_compile_definitions(RS_DATA_DIR="${RS_DATA_DIR}")
endif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
## Useful to debug CMake
#set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

View File

@ -0,0 +1,408 @@
# RetroShare decentralized communication platform
#
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
#
# SPDX-License-Identifier: CC0-1.0
list(
APPEND RS_PUBLIC_HEADERS
retroshare/rsexpr.h
retroshare/rsgxsdistsync.h
retroshare/rsiface.h
retroshare/rsrtt.h
retroshare/rsbanlist.h
retroshare/rsconfig.h
retroshare/rsdisc.h
retroshare/rsflags.h
retroshare/rsgrouter.h
retroshare/rsgxsflags.h
retroshare/rsgxsservice.h
retroshare/rsgxstrans.h
retroshare/rsgxstunnel.h
retroshare/rsids.h
retroshare/rsnotify.h
retroshare/rsphoto.h
retroshare/rsplugin.h
retroshare/rsreputations.h
retroshare/rsservicecontrol.h
retroshare/rstokenservice.h
retroshare/rsturtle.h
retroshare/rsgossipdiscovery.h
retroshare/rsgxscommon.h
retroshare/rsposted.h
retroshare/rsstatus.h
retroshare/rsversion.h
retroshare/rsgxsifacehelper.h
retroshare/rshistory.h
retroshare/rsidentity.h
retroshare/rsmsgs.h
retroshare/rsgxschannels.h
retroshare/rsgxscircles.h
retroshare/rsgxsiface.h
retroshare/rsgxsifacetypes.h
retroshare/rstypes.h
retroshare/rsgxsforums.h
retroshare/rsevents.h
retroshare/rsfiles.h
retroshare/rsinit.h
retroshare/rspeers.h )
list(
APPEND RS_SOURCES
chat/distantchat.cc
chat/p3chatservice.cc
chat/rschatitems.cc
chat/distributedchat.cc
crypto/chacha20.cpp
crypto/hashstream.cc
crypto/rsaes.cc
crypto/rscrypto.cpp )
if(RS_BITDHT)
list(
APPEND RS_PUBLIC_HEADERS
retroshare/rsdht.h )
list(
APPEND RS_SOURCES
dht/connectstatebox.cc
dht/p3bitdht.cc
dht/p3bitdht_interface.cc
dht/p3bitdht_peernet.cc
dht/p3bitdht_peers.cc
dht/p3bitdht_relay.cc )
endif(RS_BITDHT)
list(
APPEND RS_SOURCES
file_sharing/filelist_io.cc
file_sharing/rsfilelistitems.cc
file_sharing/file_tree.cc
file_sharing/directory_updater.cc
file_sharing/p3filelists.cc
file_sharing/hash_cache.cc
file_sharing/dir_hierarchy.cc
file_sharing/directory_storage.cc
ft/ftchunkmap.cc
ft/ftfilecreator.cc
ft/ftfileprovider.cc
ft/ftfilesearch.cc
ft/ftturtlefiletransferitem.cc
ft/fttransfermodule.cc
ft/ftcontroller.cc
ft/ftdatamultiplex.cc
ft/ftextralist.cc
ft/ftserver.cc )
list(
APPEND RS_SOURCES
grouter/groutermatrix.cc
grouter/grouteritems.cc
grouter/p3grouter.cc )
list(
APPEND RS_SOURCES
gxs/rsgxsdata.cc
gxs/rsgxsrequesttypes.cc
gxs/gxssecurity.cc
gxs/gxstokenqueue.cc
gxs/rsdataservice.cc
gxs/rsgxsdataaccess.cc
gxs/rsgxsnetutils.cc
gxs/rsgxsnettunnel.cc
gxs/rsgxsutil.cc
gxs/rsnxsobserver.cpp
gxs/rsgenexchange.cc
gxs/rsgxsnetservice.cc )
list(
APPEND RS_SOURCES
gxstrans/p3gxstransitems.cc
gxstrans/p3gxstrans.cc )
list(
APPEND RS_SOURCES
gxstunnel/rsgxstunnelitems.cc
gxstunnel/p3gxstunnel.cc )
if(RS_JSON_API)
list(
APPEND RS_PUBLIC_HEADERS
retroshare/rsjsonapi.h )
list(
APPEND RS_SOURCES
jsonapi/jsonapi.cpp )
endif(RS_JSON_API)
list(
APPEND RS_SOURCES
pgp/pgpkeyutil.cc
pgp/pgpauxutils.cc
pgp/pgphandler.cc
pgp/rscertificate.cc )
#./plugins/dlfcn_win32.cc
#./plugins/dlfcn_win32.h
#./plugins/pluginmanager.h
#./plugins/rscacheservice.h
#./plugins/rspqiservice.h
#./plugins/pluginmanager.cc
list(
APPEND RS_SOURCES
pqi/pqibin.cc
pqi/pqiipset.cc
pqi/pqiloopback.cc
pqi/pqimonitor.cc
pqi/pqipersongrp.cc
pqi/pqiqos.cc
pqi/pqiqosstreamer.cc
pqi/pqisslproxy.cc
pqi/pqistore.cc
pqi/authgpg.cc
pqi/p3cfgmgr.cc
pqi/p3notify.cc
pqi/p3servicecontrol.cc
pqi/pqinetstatebox.cc
pqi/pqiperson.cc
pqi/pqiservice.cc
pqi/pqissllistener.cc
pqi/pqissludp.cc
pqi/pqithreadstreamer.cc
pqi/sslfns.cc
pqi/authssl.cc
pqi/p3historymgr.cc
pqi/p3linkmgr.cc
pqi/pqihandler.cc
pqi/pqistreamer.cc
pqi/p3netmgr.cc
pqi/p3peermgr.cc
pqi/pqinetwork.cc
pqi/pqissl.cc
pqi/pqisslpersongrp.cc )
#./pqi/pqissli2psam3.cpp
#./pqi/pqissli2psam3.h
list(
APPEND RS_SOURCES
rsitems/rsbanlistitems.cc
rsitems/rsbwctrlitems.cc
rsitems/rsconfigitems.cc
rsitems/rsfiletransferitems.cc
rsitems/rsgxscommentitems.cc
rsitems/rsgxsforumitems.cc
rsitems/rsgxsiditems.cc
rsitems/rsgxsrecognitems.cc
rsitems/rsgxsreputationitems.cc
rsitems/rsgxsupdateitems.cc
rsitems/rshistoryitems.cc
rsitems/rsrttitems.cc
rsitems/rsserviceinfoitems.cc )
#retroshare/rswiki.h
#./rsitems/rswikiitems.cc
#./rsitems/rswikiitems.h
#./rsitems/rswireitems.h
list(
APPEND RS_SOURCES
rsitems/rsgxschannelitems.cc
rsitems/rsgxscircleitems.cc
rsitems/rsgxsitems.cc
rsitems/rsmsgitems.cc )
#./rsitems/rsphotoitems.cc
#./rsitems/rsphotoitems.h
#./rsitems/rsposteditems.cc
#./rsitems/rsposteditems.h
#./rsitems/rswireitems.cc
#retroshare/rswire.h
list(
APPEND RS_SOURCES
rsitems/rsnxsitems.cc )
list(
APPEND RS_SOURCES
rsserver/p3status.cc
rsserver/p3face-config.cc
rsserver/p3face-info.cc
rsserver/p3history.cc
rsserver/p3serverconfig.cc
rsserver/rsloginhandler.cc
rsserver/p3face-server.cc
rsserver/p3msgs.cc
rsserver/p3peers.cc
rsserver/rsaccounts.cc
rsserver/rsinit.cc )
list(
APPEND RS_SOURCES
serialiser/rsbaseserial.cc
serialiser/rsserializable.cc
serialiser/rstlvaddrs.cc
serialiser/rstlvbanlist.cc
serialiser/rstlvbase.cc
serialiser/rstlvbinary.cc
serialiser/rstlvfileitem.cc
serialiser/rstlvgenericmap.inl
serialiser/rstlvgenericparam.cc
serialiser/rstlvidset.cc
serialiser/rstlvimage.cc
serialiser/rstlvitem.cc
serialiser/rstlvkeys.cc
serialiser/rstlvkeyvalue.cc
serialiser/rstlvstring.cc
serialiser/rsserializer.cc
serialiser/rstypeserializer.cc
serialiser/rsserial.cc )
# ./services/autoproxy
#./services/autoproxy/p3i2psam3.cpp
#./services/autoproxy/p3i2psam3.h
list(
APPEND RS_SOURCES
services/autoproxy/rsautoproxymonitor.cc
services/p3bwctrl.cc
services/p3heartbeat.cc
services/p3service.cc
services/p3serviceinfo.cc
services/p3statusservice.cc
services/p3banlist.cc
services/p3rtt.cc
services/rseventsservice.cc
services/p3gxscircles.cc
services/p3gxscommon.cc
services/p3gxsreputation.cc
services/p3msgservice.cc
services/p3idservice.cc
services/p3gxschannels.cc
services/p3gxsforums.cc )
#./services/p3wiki.cc
#./services/p3wiki.h
#./services/p3wire.cc
#./services/p3wire.h
#./services/p3photoservice.cc
#./services/p3photoservice.h
#./services/p3postbase.cc
#./services/p3postbase.h
#./services/p3posted.cc
#./services/p3posted.h
if(RS_BRODCAST_DISCOVERY)
list(
APPEND RS_PUBLIC_HEADERS
retroshare/rsbroadcastdiscovery.h )
list(
APPEND RS_SOURCES
services/broadcastdiscoveryservice.cc )
endif(RS_BRODCAST_DISCOVERY)
list(
APPEND RS_SOURCES
tcponudp/tcppacket.cc
tcponudp/tcpstream.cc
tcponudp/tou.cc
tcponudp/udppeer.cc
tcponudp/bss_tou.cc
tcponudp/udprelay.cc )
if(RS_BITDHT_STUNNER)
list(
APPEND RS_SOURCES
tcponudp/udpstunner.cc )
endif(RS_BITDHT_STUNNER)
list(
APPEND RS_SOURCES
turtle/rsturtleitem.cc
turtle/p3turtle.cc )
list(
APPEND RS_SOURCES
# util/contentvalue.cc
# util/exampletst.c
# util/rsdbbind.cc
# util/rsdiscspace.cc
util/rsexpr.cc
util/rsprint.cc
# util/rsrecogn.cc
# util/rssharedptr.h
# util/rstickevent.cc
util/rstime.cc
util/smallobject.cc
# util/retrodb.cc
util/rsbase64.cc
util/rsjson.cc
# util/rskbdinput.cc
util/rsrandom.cc
util/rsstring.cc
util/rsurl.cc
util/folderiterator.cc
util/rsdir.cc
util/dnsresolver.cc
util/extaddrfinder.cc
util/rsdebug.cc
util/rsdnsutils.cc
util/rsnet.cc
util/rsnet_ss.cc
util/rsthreads.cc )
# util/i2pcommon.cpp
# util/i2pcommon.h
if(RS_FORUM_DEEP_INDEX)
list(
APPEND RS_SOURCES
deep_search/commonutils.cpp
deep_search/forumsindex.cpp )
endif(RS_FORUM_DEEP_INDEX)
#./deep_search/filesflacindexer.hpp
#./deep_search/filesoggindexer.hpp
#./deep_search/filestaglibindexer.hpp
#./deep_search/filesindex.cpp
#./deep_search/filesindex.hpp
#./deep_search/channelsindex.cpp
#./deep_search/channelsindex.hpp
list(
APPEND RS_SOURCES
gossipdiscovery/gossipdiscoveryitems.cc
gossipdiscovery/p3gossipdiscovery.cc )
if(RS_MINIUPNPC)
list(
APPEND RS_SOURCES
rs_upnp/upnphandler_miniupnp.cc )
endif(RS_MINIUPNPC)
#./rs_upnp/UPnPBase.cpp
#./rs_upnp/upnphandler_libupnp.cc
#./rs_upnp/upnptest.cc
#./rs_upnp/upnputil.cc
#./rs_android/LocalArray.h
#./rs_android/README-ifaddrs-android.adoc
#./rs_android/ScopedFd.h
#./rs_android/androidcoutcerrcatcher.hpp
#./rs_android/errorconditionwrap.cpp
#./rs_android/ifaddrs-android.h
#./rs_android/org
#./rs_android/org/retroshare
#./rs_android/org/retroshare/service
#./rs_android/org/retroshare/service/AssetHelper.java
#./rs_android/org/retroshare/service/ErrorConditionWrap.java
#./rs_android/org/retroshare/service/RetroShareServiceAndroid.java
#./rs_android/retroshareserviceandroid.cpp
#./rs_android/retroshareserviceandroid.hpp
#./rs_android/rsjni.cpp
#./rs_android/rsjni.hpp

View File

@ -46,7 +46,9 @@ std::error_condition DeepForumsIndex::search(
// End of prefix configuration.
// And parse the query.
Xapian::Query query = queryparser.parse_query(queryStr);
using XQP = Xapian::QueryParser;
Xapian::Query query = queryparser.parse_query(
queryStr, XQP::FLAG_WILDCARD | XQP::FLAG_DEFAULT );
// Use an Enquire object on the database to run the query.
Xapian::Enquire enquire(db);

View File

@ -107,7 +107,7 @@ p3discovery2::p3discovery2(
addSerialType(new RsDiscSerialiser());
// Add self into PGP FriendList.
mFriendList[AuthGPG::getAuthGPG()->getGPGOwnId()] = DiscPgpInfo();
mFriendList[AuthPGP::getPgpOwnId()] = DiscPgpInfo();
}
@ -219,7 +219,7 @@ void p3discovery2::removeFriend(const RsPeerId &sslId)
std::cerr << std::endl;
#endif
/* pgp peer without any ssl entries -> check if they are still a real friend */
if (!(AuthGPG::getAuthGPG()->isGPGAccepted(pgpId)))
if (!(AuthPGP::isPGPAccepted(pgpId)))
{
#ifdef P3DISC_DEBUG
std::cerr << "p3discovery2::addFriend() pgpId is no longer a friend, removing";
@ -604,8 +604,8 @@ void p3discovery2::updatePgpFriendList()
std::list<RsPgpId>::iterator lit;
std::map<RsPgpId, DiscPgpInfo>::iterator it;
RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId();
AuthGPG::getAuthGPG()->getGPGAcceptedList(pgpList);
RsPgpId ownPgpId = AuthPGP::getPgpOwnId();
AuthPGP::getPgpAcceptedList(pgpList);
pgpList.push_back(ownPgpId);
// convert to set for ordering.
@ -723,7 +723,7 @@ void p3discovery2::processPGPList(const RsPeerId &fromId, const RsDiscPgpListIte
std::set<RsPgpId>::const_iterator fit;
for(fit = item->pgpIdSet.ids.begin(); fit != item->pgpIdSet.ids.end(); ++fit)
{
if (!AuthGPG::getAuthGPG()->isGPGId(*fit))
if (!AuthPGP::isPGPId(*fit))
{
#ifdef P3DISC_DEBUG
std::cerr << "p3discovery2::processPGPList() requesting certificate for PgpId: " << *fit;
@ -1058,11 +1058,11 @@ void p3discovery2::recvPGPCertificateRequest( const RsPeerId& fromId, const RsDi
return;
}
RsPgpId ownPgpId = AuthGPG::getAuthGPG()->getGPGOwnId();
RsPgpId ownPgpId = AuthPGP::getPgpOwnId();
for(const RsPgpId& pgpId : item->pgpIdSet.ids)
if (pgpId == ownPgpId)
sendPGPCertificate(pgpId, fromId);
else if(ps.vs_disc != RS_VS_DISC_OFF && AuthGPG::getAuthGPG()->isGPGAccepted(pgpId))
else if(ps.vs_disc != RS_VS_DISC_OFF && AuthPGP::isPGPAccepted(pgpId))
sendPGPCertificate(pgpId, fromId);
else
std::cerr << "(WW) not sending certificate " << pgpId << " asked by friend " << fromId << " because this either this cert is not a friend, or discovery is off" << std::endl;
@ -1078,7 +1078,7 @@ void p3discovery2::sendPGPCertificate(const RsPgpId &aboutId, const RsPeerId &to
unsigned char *bin_data;
size_t bin_len;
if(!AuthGPG::getAuthGPG()->exportPublicKey(aboutId,bin_data,bin_len,false,true))
if(!AuthPGP::exportPublicKey(aboutId,bin_data,bin_len,false,true))
{
std::cerr << "(EE) cannot export public key " << aboutId << " requested by peer " << toId << std::endl;
return ;
@ -1098,7 +1098,7 @@ void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem*
std::string cert_name;
std::list<RsPgpId> cert_signers;
if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock( (unsigned char*)item->bin_data,item->bin_len, cert_pgp_id, cert_name, cert_signers ))
if(!AuthPGP::getPgpDetailsFromBinaryBlock( (unsigned char*)item->bin_data,item->bin_len, cert_pgp_id, cert_name, cert_signers ))
{
std::cerr << "(EE) cannot parse own PGP key sent by " << fromId << std::endl;
return;
@ -1147,7 +1147,7 @@ void p3discovery2::recvPGPCertificate(const RsPeerId& fromId, RsDiscPgpKeyItem*
// otherwise the connection should already be accepted. This only happens when the short invite peer sends its own PGP key.
if(det.skip_pgp_signature_validation)
AuthGPG::getAuthGPG()->AllowConnection(det.gpg_id,true);
AuthPGP::AllowConnection(det.gpg_id,true);
}
/************* from pqiServiceMonitor *******************/

View File

@ -41,6 +41,7 @@
#include "rsserver/p3face.h"
#include "retroshare/rsevents.h"
#include "util/radix64.h"
#include "util/cxx17retrocompat.h"
#define PUB_GRP_MASK 0x000f
#define RESTR_GRP_MASK 0x00f0
@ -2285,8 +2286,9 @@ bool RsGenExchange::processGrpMask(const RsGxsGroupId& grpId, ContentValue &grpC
void RsGenExchange::publishMsgs()
{
bool atLeastOneMessageCreatedSuccessfully = false;
RS_STACK_MUTEX(mGenMtx) ;
RS_STACK_MUTEX(mGenMtx);
rstime_t now = time(NULL);
@ -2463,6 +2465,8 @@ void RsGenExchange::publishMsgs()
// add to published to allow acknowledgement
mMsgNotify.insert(std::make_pair(mit->first, std::make_pair(grpId, msgId)));
mDataAccess->updatePublicRequestStatus(mit->first, RsTokenService::COMPLETE);
atLeastOneMessageCreatedSuccessfully = true;
}
else
{
@ -2496,6 +2500,8 @@ void RsGenExchange::publishMsgs()
mNotifications.push_back(ch);
}
if(atLeastOneMessageCreatedSuccessfully) mNetService->requestPull();
}
RsGenExchange::ServiceCreate_Return RsGenExchange::service_CreateGroup(RsGxsGrpItem* /* grpItem */,
@ -2723,7 +2729,8 @@ bool RsGenExchange::checkKeys(const RsTlvSecurityKeySet& keySet)
void RsGenExchange::publishGrps()
{
std::list<RsGxsGroupId> groups_to_subscribe ;
bool atLeastOneGroupCreatedSuccessfully = false;
std::list<RsGxsGroupId> groups_to_subscribe;
{
RS_STACK_MUTEX(mGenMtx) ;
@ -2954,6 +2961,8 @@ void RsGenExchange::publishGrps()
// add to published to allow acknowledgement
toNotify.insert(std::make_pair(token, GrpNote(true,ggps.mIsUpdate,grpId)));
atLeastOneGroupCreatedSuccessfully = true;
}
}
@ -2972,9 +2981,14 @@ void RsGenExchange::publishGrps()
// This is done off-mutex to avoid possible cross deadlocks with the net service.
if(mNetService!=NULL)
for(std::list<RsGxsGroupId>::const_iterator it(groups_to_subscribe.begin());it!=groups_to_subscribe.end();++it)
mNetService->subscribeStatusChanged((*it),true) ;
if(mNetService != nullptr)
{
for(auto& grpId : std::as_const(groups_to_subscribe))
mNetService->subscribeStatusChanged(grpId, true);
if(atLeastOneGroupCreatedSuccessfully)
mNetService->requestPull();
}
}
uint32_t RsGenExchange::generatePublicToken()

View File

@ -35,7 +35,7 @@
// |
// +----------- sharePublishKeys()
// |
// +----------- syncWithPeers()
// +----------- checkUpdatesFromPeers()
// | |
// | +--if AutoSync--- send global UpdateTS of each peer to itself => the peer knows the last
// | | time current peer has received an updated from himself
@ -127,14 +127,14 @@
// (Set at server side to be mGrpServerUpdateItem->grpUpdateTS)
//
// Only updated in processCompletedIncomingTransaction() from Grp list transaction.
// Used in syncWithPeers() sending in RsNxsSyncGrp once to all peers: peer will send data if
// Used in checkUpdatesFromPeers() sending in RsNxsSyncGrp once to all peers: peer will send data if
// has something new. All time comparisons are in the friends' clock time.
//
// mClientMsgUpdateMap: map< RsPeerId, map<grpId,TimeStamp > >
//
// Last msg list modification time sent by that peer Id
// Updated in processCompletedIncomingTransaction() from Grp list trans.
// Used in syncWithPeers() sending in RsNxsSyncGrp once to all peers.
// Used in checkUpdatesFromPeers() sending in RsNxsSyncGrp once to all peers.
// Set at server to be mServerMsgUpdateMap[grpId]->msgUpdateTS
//
// mGrpServerUpdateItem: TimeStamp Last group local modification timestamp over all groups
@ -150,7 +150,7 @@
//
// tick() tick()
// | |
// +---- SyncWithPeers +-- recvNxsItemQueue()
// +---- checkUpdatesFromPeers() +-- recvNxsItemQueue()
// | |
// +---------------- Send global UpdateTS of each peer to itself => the peer knows +---------> +------ handleRecvSyncGroup( RsNxsSyncGrp*)
// | the last msg sent (stored in mClientGrpUpdateMap[peer_id]), | | - parse all subscribed groups. For each, send a RsNxsSyncGrpItem with publish TS
@ -457,7 +457,7 @@ int RsGxsNetService::tick()
if((elapsed) < now)
{
syncWithPeers();
checkUpdatesFromPeers();
syncGrpStatistics();
checkDistantSyncState();
@ -570,39 +570,40 @@ RsGxsGroupId RsGxsNetService::hashGrpId(const RsGxsGroupId& gid,const RsPeerId&
return RsGxsGroupId( RsDirUtil::sha1sum(tmpmem,SIZE).toByteArray() );
}
void RsGxsNetService::syncWithPeers()
std::error_condition RsGxsNetService::checkUpdatesFromPeers(
std::set<RsPeerId> peers )
{
#ifdef NXS_NET_DEBUG_0
GXSNETDEBUG___ << "RsGxsNetService::syncWithPeers() this=" << (void*)this << ". serviceInfo=" << mServiceInfo << std::endl;
RS_DBG("this=", (void*)this, ". serviceInfo=", mServiceInfo);
#endif
static RsNxsSerialiser ser(mServType) ; // this is used to estimate bandwidth.
RS_STACK_MUTEX(mNxsMutex) ;
std::set<RsPeerId> peers;
mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers);
if(mAllowDistSync && mGxsNetTunnel != NULL)
/* If specific peers are passed as paramether ask only to them */
if(peers.empty())
{
// Grab all online virtual peers of distant tunnels for the current service.
mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers);
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
mGxsNetTunnel->getVirtualPeers(vpids);
if(mAllowDistSync && mGxsNetTunnel != nullptr)
{
/* Grab all online virtual peers of distant tunnels for the current
* service. */
for(auto it(vpids.begin());it!=vpids.end();++it)
peers.insert(RsPeerId(*it)) ;
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
mGxsNetTunnel->getVirtualPeers(vpids);
for(auto it(vpids.begin());it!=vpids.end();++it)
peers.insert(RsPeerId(*it)) ;
}
}
if (peers.empty()) {
// nothing to do
return;
}
// Still empty? Reports there are no available peers
if (peers.empty()) return std::errc::network_down;
RS_STACK_MUTEX(mNxsMutex);
// for now just grps
for(auto sit = peers.begin(); sit != peers.end(); ++sit)
{
const RsPeerId peerId = *sit;
ClientGrpMap::const_iterator cit = mClientGrpUpdateMap.find(peerId);
@ -624,8 +625,7 @@ void RsGxsNetService::syncWithPeers()
generic_sendItem(grp);
}
if(!mAllowMsgSync)
return ;
if(!mAllowMsgSync) return std::error_condition();
#ifndef GXS_DISABLE_SYNC_MSGS
@ -743,10 +743,12 @@ void RsGxsNetService::syncWithPeers()
}
}
#endif
#endif // ndef GXS_DISABLE_SYNC_MSGS
return std::error_condition();
}
void RsGxsNetService::generic_sendItem(RsNxsItem *si)
void RsGxsNetService::generic_sendItem(rs_owner_ptr<RsItem> si)
{
// check if the item is to be sent to a distant peer or not
@ -1022,32 +1024,32 @@ void RsGxsNetService::locked_resetClientTS(const RsGxsGroupId& grpId)
it->second.msgUpdateInfos.erase(grpId) ;
}
void RsGxsNetService::subscribeStatusChanged(const RsGxsGroupId& grpId,bool subscribed)
void RsGxsNetService::subscribeStatusChanged(
const RsGxsGroupId& grpId, bool subscribed )
{
RS_STACK_MUTEX(mNxsMutex) ;
if(!subscribed)
return ;
if(!subscribed) return;
// When we subscribe, we reset the time stamps, so that the entire group list
// gets requested once again, for a proper update.
RS_STACK_MUTEX(mNxsMutex);
#ifdef NXS_NET_DEBUG_0
GXSNETDEBUG__G(grpId) << "Changing subscribe status for grp " << grpId << " to " << subscribed << ": reseting all server msg time stamps for this group, and server global TS." << std::endl;
std::map<RsGxsGroupId,RsGxsServerMsgUpdate>::iterator it = mServerMsgUpdateMap.find(grpId) ;
RS_DBG( "Changing subscribe status for grp", grpId, " to ", subscribed,
": reseting all server msg time stamps for this group, and "
"server global TS." );
#endif
RsGxsServerMsgUpdate& item(mServerMsgUpdateMap[grpId]) ;
RsGxsServerMsgUpdate& item(mServerMsgUpdateMap[grpId]);
item.msgUpdateTS = static_cast<uint32_t>(time(nullptr));
item.msgUpdateTS = time(NULL) ;
/* We also update mGrpServerUpdateItem so as to trigger a new grp list
* exchange with friends (friends will send their known ClientTS which
* will be lower than our own grpUpdateTS, triggering our sending of the
* new subscribed grp list. */
mGrpServerUpdate.grpUpdateTS = static_cast<uint32_t>(time(nullptr));
// We also update mGrpServerUpdateItem so as to trigger a new grp list exchange with friends (friends will send their known ClientTS which
// will be lower than our own grpUpdateTS, triggering our sending of the new subscribed grp list.
mGrpServerUpdate.grpUpdateTS = time(NULL) ;
if(subscribed)
locked_resetClientTS(grpId) ;
locked_resetClientTS(grpId);
}
bool RsGxsNetService::fragmentMsg(RsNxsMsg& msg, MsgFragments& msgFragments) const
@ -1718,13 +1720,25 @@ RsItem *RsGxsNetService::generic_recvItem()
void RsGxsNetService::recvNxsItemQueue()
{
RsItem *item ;
RsItem* item;
while(NULL != (item=generic_recvItem()))
{
while(nullptr != (item=generic_recvItem()))
{
#ifdef NXS_NET_DEBUG_1
GXSNETDEBUG_P_(item->PeerId()) << "Received RsGxsNetService Item:" << (void*)item << " type=" << std::hex << item->PacketId() << std::dec << std::endl ;
RS_DBG( "Received RsGxsNetService Item: ", (void*)item, " type=",
item->PacketId() );
#endif
/* Handle pull request and other new items here to not mess with all the
* old nested code and items hell */
switch(static_cast<RsNxsSubtype>(item->PacketSubType()))
{
case RsNxsSubtype::PULL_REQUEST:
std::unique_ptr<RsNxsPullRequestItem> pullItem(
static_cast<RsNxsPullRequestItem*>(item) );
handlePullRequest(std::move(pullItem));
continue;
}
// RsNxsItem needs dynamic_cast, since they have derived siblings.
//
RsNxsItem *ni = dynamic_cast<RsNxsItem*>(item) ;
@ -4690,7 +4704,7 @@ bool RsGxsNetService::checkPermissionsForFriendGroup(const RsPeerId& sslId,const
if(!grpMeta.mInternalCircle.isNull())
{
RsGroupInfo ginfo ;
RsPgpId pgpId = mPgpUtils->getPGPId(sslId) ;
RsPgpId pgpId = mPgpUtils->getPgpId(sslId) ;
#ifdef NXS_NET_DEBUG_4
GXSNETDEBUG_PG(sslId,grpMeta.mGroupId) << " Group internal circle: " << grpMeta.mInternalCircle << ", We're owner. Sending to everyone in the group." << std::endl;
@ -5075,6 +5089,46 @@ void RsGxsNetService::handleRecvPublishKeys(RsNxsGroupPublishKeyItem *item)
}
}
std::error_condition RsGxsNetService::requestPull(std::set<RsPeerId> peers)
{
/* If specific peers are passed as paramether ask only to them */
if(peers.empty())
{
mNetMgr->getOnlineList(mServiceInfo.mServiceType, peers);
if(mAllowDistSync && mGxsNetTunnel != nullptr)
{
/* Grab all online virtual peers of distant tunnels for the current
* service. */
std::list<RsGxsNetTunnelVirtualPeerId> vpids ;
mGxsNetTunnel->getVirtualPeers(vpids);
for(auto it(vpids.begin());it!=vpids.end();++it)
peers.insert(RsPeerId(*it)) ;
}
}
// Still empty? Reports there are no available peers
if (peers.empty()) return std::errc::network_down;
for(auto& peerId: std::as_const(peers))
{
auto item = new RsNxsPullRequestItem(
static_cast<RsServiceType>(mServType) );
item->PeerId(peerId);
generic_sendItem(item);
}
return std::error_condition();
}
void RsGxsNetService::handlePullRequest(
std::unique_ptr<RsNxsPullRequestItem> item )
{
checkUpdatesFromPeers(std::set<RsPeerId>{item->PeerId()});
}
bool RsGxsNetService::getGroupServerUpdateTS(const RsGxsGroupId& gid,rstime_t& group_server_update_TS, rstime_t& msg_server_update_TS)
{
RS_STACK_MUTEX(mNxsMutex) ;

View File

@ -250,6 +250,15 @@ public:
void threadTick() override; /// @see RsTickingThread
/// @see RsNetworkExchangeService
std::error_condition checkUpdatesFromPeers(
std::set<RsPeerId> peers = std::set<RsPeerId>() ) override;
/// @see RsNetworkExchangeService
std::error_condition requestPull(
std::set<RsPeerId> peers = std::set<RsPeerId>() ) override;
private:
/*!
@ -423,6 +432,8 @@ private:
*/
void handleRecvPublishKeys(RsNxsGroupPublishKeyItem*) ;
void handlePullRequest(std::unique_ptr<RsNxsPullRequestItem> item);
/** E: item handlers **/
@ -459,7 +470,7 @@ private:
void locked_pushMsgRespFromList(std::list<RsNxsItem*>& itemL, const RsPeerId& sslId, const RsGxsGroupId &grp_id, const uint32_t& transN);
void checkDistantSyncState();
void syncWithPeers();
void syncGrpStatistics();
void addGroupItemToList(NxsTransaction*& tr,
const RsGxsGroupId& grpId, uint32_t& transN,
@ -559,7 +570,7 @@ private:
void cleanRejectedMessages();
void processObserverNotifications();
void generic_sendItem(RsNxsItem *si);
void generic_sendItem(rs_owner_ptr<RsItem> si);
RsItem *generic_recvItem();
private:

View File

@ -223,7 +223,7 @@ bool GrpCircleVetting::canSend(
{
if(mCircles->isLoaded(circleId))
{
const RsPgpId& pgpId = mPgpUtils->getPGPId(peerId);
const RsPgpId& pgpId = mPgpUtils->getPgpId(peerId);
return mCircles->canSend(circleId, pgpId,should_encrypt);
}
@ -302,7 +302,7 @@ bool MsgCircleIdsRequestVetting::cleared()
if(filtered_out_msgs>0)
std::cerr << "(WW) " << filtered_out_msgs << " messages not sent because they are signed by author(s) not member of that circle " << mCircleId << std::endl;
RsPgpId pgpId = mPgpUtils->getPGPId(mPeerId);
RsPgpId pgpId = mPgpUtils->getPgpId(mPeerId);
bool can_send_res = mCircles->canSend(mCircleId, pgpId,mShouldEncrypt);
if(mShouldEncrypt) // that means the circle is external

View File

@ -26,7 +26,7 @@
#include <set>
#include <string>
#include <stdlib.h>
#include <cstdlib>
#include <list>
#include <map>
@ -325,4 +325,20 @@ public:
return RsReputationLevel::NEUTRAL;
}
}
/**
* @brief Check if new stuff is available from peers
* @param peers peers to check, if empty all available peers are checked
*/
virtual std::error_condition checkUpdatesFromPeers(
std::set<RsPeerId> peers = std::set<RsPeerId>() ) = 0;
/**
* @brief request online peers to pull updates from our node ASAP
* @param peers peers to which request pull from, if empty all available
* peers are requested to pull
* @return success or error details
*/
virtual std::error_condition requestPull(
std::set<RsPeerId> peers = std::set<RsPeerId>() ) = 0;
};

View File

@ -0,0 +1,447 @@
// SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team <contact@retroshare.cc>
// SPDX-License-Identifier: CC0-1.0
RetroShare JSON API
===================
:Cxx: C&#43;&#43;
== How to use RetroShare JSON API
Look for methods marked with +@jsonapi+ doxygen custom command into
+libretroshare/src/retroshare+. The method path is composed by service instance
pointer name like +rsGxsChannels+ for +RsGxsChannels+, and the method name like
+createGroup+ and pass the input paramethers as a JSON object.
.Service instance pointer in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* Pointer to global instance of RsGxsChannels service implementation
* @jsonapi{development}
*/
extern RsGxsChannels* rsGxsChannels;
--------------------------------------------------------------------------------
.Method declaration in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* @brief Request channel creation.
* The action is performed asyncronously, so it could fail in a subsequent
* phase even after returning true.
* @jsonapi{development}
* @param[out] token Storage for RsTokenService token to track request
* status.
* @param[in] group Channel data (name, description...)
* @return false on error, true otherwise
*/
virtual bool createGroup(uint32_t& token, RsGxsChannelGroup& group) = 0;
--------------------------------------------------------------------------------
.paramethers.json
[source,json]
--------------------------------------------------------------------------------
{
"group":{
"mMeta":{
"mGroupName":"JSON test group",
"mGroupFlags":4,
"mSignFlags":520
},
"mDescription":"JSON test group description"
},
"caller_data":"Here can go any kind of JSON data (even objects) that the caller want to get back together with the response"
}
--------------------------------------------------------------------------------
.Calling the JSON API with curl on the terminal
[source,bash]
--------------------------------------------------------------------------------
curl -u $API_USER --data @paramethers.json http://127.0.0.1:9092/rsGxsChannels/createGroup
--------------------------------------------------------------------------------
.JSON API call result
[source,json]
--------------------------------------------------------------------------------
{
"caller_data": "Here can go any kind of JSON data (even objects) that the caller want to get back together with the response",
"retval": true,
"token": 3
}
--------------------------------------------------------------------------------
Even if it is less efficient because of URL encoding HTTP +GET+ method is
supported too, so in cases where the client cannot use +POST+ she can still use
+GET+ taking care of encoding the JSON data. With +curl+ this can be done at
least in two different ways.
.Calling the JSON API with GET method with curl on the terminal
[source,bash]
--------------------------------------------------------------------------------
curl -u $API_USER --get --data-urlencode jsonData@paramethers.json \
http://127.0.0.1:9092/rsGxsChannels/createGroup
--------------------------------------------------------------------------------
Letting +curl+ do the encoding is much more elegant but it is semantically
equivalent to the following.
.Calling the JSON API with GET method and pre-encoded data with curl on the terminal
--------------------------------------------------------------------------------
curl -u $API_USER http://127.0.0.1:9092/rsGxsChannels/createGroup?jsonData=%7B%0A%20%20%20%20%22group%22%3A%7B%0A%20%20%20%20%20%20%20%20%22mMeta%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupName%22%3A%22JSON%20test%20group%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mGroupFlags%22%3A4%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22mSignFlags%22%3A520%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22mDescription%22%3A%22JSON%20test%20group%20description%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22caller_data%22%3A%22Here%20can%20go%20any%20kind%20of%20JSON%20data%20%28even%20objects%29%20that%20the%20caller%20want%20to%20get%20back%20together%20with%20the%20response%22%0A%7D
--------------------------------------------------------------------------------
Note that using +GET+ method +?jsonData=+ and then the JSON data URL encoded are
added after the path in the HTTP request.
== JSON API authentication
Most of JSON API methods require authentication as they give access to
RetroShare user data, and we don't want any application running on the system
eventually by other users be able to access private data indiscriminately.
JSON API support HTTP Basic as authentication scheme, this is enough as JSON API
server is intented for usage on the same system (127.0.0.1) not over an
untrusted network.
If you need to use JSON API over an untrusted network consider using a reverse
proxy with HTTPS such as NGINX in front of JSON API server.
If RetroShare login has been effectuated through the JSON API you can use your
location SSLID as username and your PGP password as credential for the JSON API,
but we suggests you use specific meaningful and human readable credentials for
each JSON API client so the human user can have better control over which client
can access the JSON API.
.NewToken.json
[source,json]
--------------------------------------------------------------------------------
{
"token": "myNewUser:myNewPassword"
}
--------------------------------------------------------------------------------
.An authenticated client can authorize new tokens like this
--------------------------------------------------------------------------------
curl -u $API_USER --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/authorizeToken
--------------------------------------------------------------------------------
.An unauthenticated JSON API client can request access with
--------------------------------------------------------------------------------
curl --data @NewToken.json http://127.0.0.1:9092/jsonApiServer/requestNewTokenAutorization
--------------------------------------------------------------------------------
When an unauthenticated client request his token to be authorized, JSON API
server will try to ask confirmation to the human user if possible through
+mNewAccessRequestCallback+, if it is not possible or the user didn't authorized
the token +false+ is returned.
== Offer new RetroShare services through JSON API
To offer a retroshare service through the JSON API, first of all one need find
the global pointer to the service instance and document it in doxygen syntax,
plus marking with the custom doxygen command +@jsonapi{RS_VERSION}+ where
+RS_VERSION+ is the retroshare version in which this service became available
with the current semantic (major changes to the service semantic, changes the
meaning of the service itself, so the version should be updated in the
documentation in that case).
.Service instance pointer in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* Pointer to global instance of RsGxsChannels service implementation
* @jsonapi{development}
*/
extern RsGxsChannels* rsGxsChannels;
--------------------------------------------------------------------------------
Once the service instance itself is known to the JSON API you need to document
in doxygen syntax and mark with the custom doxygen command
+@jsonapi{RS_VERSION}+ the methods of the service that you want to make
available through JSON API.
.Offering RsGxsChannels::getChannelDownloadDirectory in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
/**
* Get download directory for the given channel
* @jsonapi{development}
* @param[in] channelId id of the channel
* @param[out] directory reference to string where to store the path
* @return false on error, true otherwise
*/
virtual bool getChannelDownloadDirectory( const RsGxsGroupId& channelId,
std::string& directory ) = 0;
--------------------------------------------------------------------------------
For each paramether you must specify if it is used as input +@param[in]+ as
output +@param[out]+ or both +@param[inout]+. Paramethers and return value
types must be of a type supported by +RsTypeSerializer+ which already support
most basic types (+bool+, +std::string+...), +RsSerializable+ and containers of
them like +std::vector<std::string>+. Paramethers passed by value and by
reference of those types are both supported, while passing by pointer is not
supported. If your paramether or return +class+/+struct+ type is not supported
yet by +RsTypeSerializer+ most convenient approach is to make it derive from
+RsSerializable+ and implement +serial_process+ method like I did with
+RsGxsChannelGroup+.
.Deriving RsGxsChannelGroup from RsSerializable in rsgxschannels.h
[source,cpp]
--------------------------------------------------------------------------------
struct RsGxsChannelGroup : RsSerializable
{
RsGroupMetaData mMeta;
std::string mDescription;
RsGxsImage mImage;
bool mAutoDownload;
/// @see RsSerializable
virtual void serial_process( RsGenericSerializer::SerializeJob j,
RsGenericSerializer::SerializeContext& ctx )
{
RS_SERIAL_PROCESS(mMeta);
RS_SERIAL_PROCESS(mDescription);
RS_SERIAL_PROCESS(mImage);
RS_SERIAL_PROCESS(mAutoDownload);
}
};
--------------------------------------------------------------------------------
You can do the same recursively for any member of your +struct+ that is not yet
supported by +RsTypeSerializer+.
Some Retroshare {Cxx} API functions are asyncronous, historically RetroShare
didn't follow a policy on how to expose asyncronous API so differents services
and some times even differents method of the same service follow differents
asyncronous patterns, thus making automatic generation of JSON API wrappers for
those methods impractical. Instead of dealing with all those differents patterns
I have chosed to support only one new pattern taking advantage of modern {Cxx}11
and restbed features. On the {Cxx}11 side lambdas and +std::function+s are used,
on the restbed side Server Side Events are used to send asyncronous results.
Lets see an example so it will be much esier to understand.
.RsGxsChannels::turtleSearchRequest asyncronous API
[source,cpp]
--------------------------------------------------------------------------------
/**
* @brief Request remote channels search
* @jsonapi{development}
* @param[in] matchString string to look for in the search
* @param multiCallback function that will be called each time a search
* result is received
* @param[in] maxWait maximum wait time in seconds for search results
* @return false on error, true otherwise
*/
virtual bool turtleSearchRequest(
const std::string& matchString,
const std::function<void (const RsGxsGroupSummary& result)>& multiCallback,
std::time_t maxWait = 300 ) = 0;
--------------------------------------------------------------------------------
+RsGxsChannels::turtleSearchRequest(...)+ is an asyncronous method because it
send a channel search request on turtle network and then everytime a result is
received from the network +multiCallback+ is called and the result is passed as
parameter. To be supported by the automatic JSON API wrappers generator an
asyncronous method need a parameter of type +std::function<void (...)>+ called
+callback+ if the callback will be called only once or +multiCallback+ if the
callback is expected to be called more then once like in this case.
A second mandatory parameter is +maxWait+ of type +std::time_t+ it indicates the
maximum amount of time in seconds for which the caller is willing to wait for
results, in case the timeout is reached the callback will not be called anymore.
[IMPORTANT]
================================================================================
+callback+ and +multiCallback+ parameters documentation must *not* specify
+[in]+, +[out]+, +[inout]+, in Doxygen documentation as this would fool the
automatic wrapper generator, and ultimately break the compilation.
================================================================================
.RsFiles::turtleSearchRequest asyncronous JSON API usage example
[source,bash]
--------------------------------------------------------------------------------
$ cat turtle_search.json
{
"matchString":"linux"
}
$ curl --data @turtle_search.json http://127.0.0.1:9092/rsFiles/turtleSearchRequest
data: {"retval":true}
data: {"results":[{"size":157631,"hash":"69709b4d01025584a8def5cd78ebbd1a3cf3fd05","name":"kill_bill_linux_1024x768.jpg"},{"size":192560,"hash":"000000000000000000009a93e5be8486c496f46c","name":"coffee_box_linux2.jpg"},{"size":455087,"hash":"9a93e5be8486c496f46c00000000000000000000","name":"Linux.png"},{"size":182004,"hash":"e8845280912ebf3779e400000000000000000000","name":"Linux_2_6.png"}]}
data: {"results":[{"size":668,"hash":"e8845280912ebf3779e400000000000000000000","name":"linux.png"},{"size":70,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.txt.sha1sum"},{"size":3076767744,"hash":"e8845280912ebf3779e400000000000000000000","name":"kali-linux-2016.2-amd64.iso"},{"size":2780872,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.bin"},{"size":917504,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.lzma"},{"size":2278404096,"hash":"e8845280912ebf3779e400000000000000000000","name":"gentoo-linux-livedvd-amd64-multilib-20160704.iso"},{"size":151770333,"hash":"e8845280912ebf3779e400000000000000000000","name":"flashtool-0.9.23.0-linux.tar.7z"},{"size":2847372,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.elf"},{"size":1310720,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux.gz"},{"size":987809,"hash":"e8845280912ebf3779e400000000000000000000","name":"openwrt-ar71xx-generic-vmlinux-lzma.elf"}]}
--------------------------------------------------------------------------------
By default JSON API methods requires client authentication and their wrappers
are automatically generated by +json-api-generator+.
In some cases methods need do be accessible without authentication such as
+rsLoginHelper/getLocations+ so in the doxygen documentaion they have the custom
command +@jsonapi{RS_VERSION,unauthenticated}+.
Other methods such as +/rsControl/rsGlobalShutDown+ need special care so they
are marked with the custom doxygen command +@jsonapi{RS_VERSION,manualwrapper}+
and their wrappers are not automatically generated but written manually into
+JsonApiServer::JsonApiServer(...)+.
== Quirks
=== 64 bits integers handling
While JSON doesn't have problems representing 64 bits integers JavaScript, Dart
and other languages are not capable to handle those numbers natively.
To overcome this limitation JSON API output 64 bit integers as an object with
two keys, one as proper integer and one as string representation.
.JSON API 64 bit integer output example
[source,json]
--------------------------------------------------------------------------------
"lobby_id": { "xint64": 6215642878098695544, "xstr64": "6215642878098695544" }
--------------------------------------------------------------------------------
So from languages that have proper 64bit integers support like Python or C++ one
better read from `xint64` which is represented as a JSON integer, from languages
where there is no proper 64bit integers support like JavaScript one can read from
`xstr64` which is represented as JSON string (note that the first is not wrapped
in "" while the latter is).
When one input a 64bit integer into the JSON API it first try to parse it as if
it was sent the old way for retrocompatibility.
.JSON API 64 bit integer deprecated format input example
[source,json]
--------------------------------------------------------------------------------
"lobby_id":6215642878098695544
--------------------------------------------------------------------------------
This way is *DEPRECATED* and may disappear in the future, it is TEMPORALLY kept
only for retrocompatibiliy with old clients.
If retrocompatible parsing attempt fail then it try to parse with the new way
with proper JSON integer format.
.JSON API 64 bit integer new proper integer format input example
[source,json]
--------------------------------------------------------------------------------
lobby_id": { "xint64": 6215642878098695544 }
--------------------------------------------------------------------------------
If this fails then it try to parse with the new way with JSON string format.
.JSON API 64 bit integer new string format input example
[source,json]
--------------------------------------------------------------------------------
"lobby_id": { "xstr64": "6215642878098695544" }
--------------------------------------------------------------------------------
[WARNING]
================================================================================
Clients written in languages without proper 64bit integers support must
use *ONLY* the string format otherwise they will send approximated values and
get unexpected results from the JSON API, because parsing will success but the
value will not be exactly the one you believe you sent.
================================================================================
== A bit of history
=== First writings about this
The previous attempt of exposing a RetroShare JSON API is called +libresapi+ and
unfortunatley it requires a bunch of boilerplate code when we want to expose
something present in the {Cxx} API in the JSON API.
As an example here you can see the libresapi that exposes part of the retroshare
chat {Cxx} API and lot of boilerplate code just to convert {Cxx} objects to JSON
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L44
To avoid the {Cxx} to JSON and back conversion boilerplate code I have worked out
an extension to our {Cxx} serialization code so it is capable to serialize and
deserialize to JSON you can see it in this pull request
https://github.com/RetroShare/RetroShare/pull/1155
So first step toward having a good API is to take advantage of the fact that RS
is now capable of converting C++ objects from and to JSON.
The current API is accessible via HTTP and unix socket, there is no
authentication in both of them, so anyone having access to the HTTP server or to
the unix socket can access the API without extra restrictions.
Expecially for the HTTP API this is a big risk because also if the http server
listen on 127.0.0.1 every application on the machine (even rogue javascript
running on your web browser) can access that and for example on android it is
not safe at all (because of that I implemented the unix socket access so at
least in android API was reasonably safe) because of this.
A second step to improve the API would be to implement some kind of API
authentication mechanism (it would be nice that the mechanism is handled at API
level and not at transport level so we can use it for any API trasport not just
HTTP for example)
The HTTP server used by libresapi is libmicrohttpd server that is very minimal,
it doesn't provide HTTPS nor modern HTTP goodies, like server notifications,
websockets etc. because the lack of support we have a token polling mechanism in
libresapi to avoid polling for every thing but it is still ugly, so if we can
completely get rid of polling in the API that would be really nice.
I have done a crawl to look for a replacement and briefly looked at
- https://www.gnu.org/software/libmicrohttpd/
- http://wolkykim.github.io/libasyncd/
- https://github.com/corvusoft/restbed
- https://code.facebook.com/posts/1503205539947302/introducing-proxygen-facebook-s-c-http-framework/
- https://github.com/cmouse/yahttp
taking in account a few metrics like modern HTTP goodies support, license,
platform support, external dependencies and documentation it seemed to me that
restbed is the more appropriate.
Another source of boilerplate code into libresapi is the mapping between JSON
API requests and C++ API methods as an example you can look at this
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ChatHandler.cpp#L158
and this
https://github.com/RetroShare/RetroShare/blob/v0.6.4/libresapi/src/api/ApiServer.cpp#L253
The abstract logic of this thing is, when libreasapi get a request like
+/chat/initiate_distant_chat+ then call
+ChatHandler::handleInitiateDistantChatConnexion+ which in turn is just a
wrapper of +RsMsgs::initiateDistantChatConnexion+ all this process is basically
implemented as boilerplate code and would be unnecessary in a smarter design of
the API because almost all the information needed is already present in the
C++ API +libretroshare/src/retroshare+.
So a third step to improve the JSON API would be to remove this source of
boilerplate code by automatizing the mapping between C++ and JSON API call.
This may result a little tricky as language parsing or other adevanced things
may be required.
Hope this dive is useful for you +
Cheers +
G10h4ck
=== Second writings about this
I have been investigating a bit more about:
[verse, G10h4ck]
________________________________________________________________________________
So a third step to improve the JSON API would be to remove this source of
boilerplate code by automatizing the mapping between C++ and JSON API call
________________________________________________________________________________
After spending some hours investigating this topic the most reasonable approach
seems to:
1. Properly document headers in +libretroshare/src/retroshare/+ in doxygen syntax
specifying wihich params are input and/or output (doxygen sysntax for this is
+@param[in/out/inout]+) this will be the API documentation too.
2. At compile time use doxygen to generate XML description of the headers and use
the XML to generate the JSON api server stub.
http://www.stack.nl/~dimitri/doxygen/manual/customize.html#xmlgenerator
3. Enjoy

View File

@ -0,0 +1,80 @@
/*******************************************************************************
* RetroShare JSON API *
* *
* Copyright (C) 2018-2019 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 version 3 as *
* published by the Free Software Foundation. *
* *
* 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
registerHandler( "$%apiPath%$",
[this](const std::shared_ptr<rb::Session> session)
{
const std::multimap<std::string, std::string> headers
{
{ "Connection", "keep-alive" },
{ "Content-Type", "text/event-stream" }
};
session->yield(rb::OK, headers);
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
session->fetch( reqSize, [this](
const std::shared_ptr<rb::Session> session,
const rb::Bytes& body )
{
INITIALIZE_API_CALL_JSON_CONTEXT;
if( !checkRsServicePtrReady(
$%instanceName%$, "$%instanceName%$", cAns, session ) )
return;
$%paramsDeclaration%$
$%inputParamsDeserialization%$
const std::weak_ptr<rb::Service> weakService(mService);
const std::weak_ptr<rb::Session> weakSession(session);
$%callbackName%$ = [weakService, weakSession]($%callbackParams%$)
{
auto session = weakSession.lock();
if(!session || session->is_closed()) return;
auto lService = weakService.lock();
if(!lService || lService->is_down()) return;
$%callbackParamsSerialization%$
std::stringstream sStream;
sStream << "data: " << compactJSON << ctx.mJson << "\n\n";
const std::string message = sStream.str();
lService->schedule( [weakSession, message]()
{
auto session = weakSession.lock();
if(!session || session->is_closed()) return;
session->yield(message);
$%sessionEarlyClose%$
} );
};
$%functionCall%$
$%outputParamsSerialization%$
// return them to the API caller
std::stringstream message;
message << "data: " << compactJSON << cAns.mJson << "\n\n";
session->yield(message.str());
$%sessionDelayedClose%$
} );
}, $%requiresAuth%$ );

View File

@ -0,0 +1,230 @@
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "libretroshare"
ALIASES += jsonapi{1}="\xmlonly<jsonapi minversion=\"\1\"/>\endxmlonly"
ALIASES += jsonapi{2}="\xmlonly<jsonapi minversion=\"\1\" access=\"\2\"/>\endxmlonly"
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
INHERIT_DOCS = YES
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
# The default value is: YES.
MARKDOWN_SUPPORT = YES
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
AUTOLINK_SUPPORT = YES
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
# Note: This will also disable the warnings about undocumented members that are
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
# section is generated. This option has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
#INPUT =
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
FILE_PATTERNS = *.c \
*.cc \
*.cxx \
*.cpp \
*.c++ \
*.java \
*.ii \
*.ixx \
*.ipp \
*.i++ \
*.inl \
*.idl \
*.ddl \
*.odl \
*.h \
*.hh \
*.hxx \
*.hpp \
*.h++ \
*.cs \
*.d \
*.php \
*.php4 \
*.php5 \
*.phtml \
*.inc \
*.m \
*.markdown \
*.md \
*.mm \
*.dox \
*.py \
*.pyw \
*.f90 \
*.f95 \
*.f03 \
*.f08 \
*.f \
*.for \
*.tcl \
*.vhd \
*.vhdl \
*.ucf \
*.qsf
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
#
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
# The default value is: NO.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories.
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = NO
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
GENERATE_LATEX = NO
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
GENERATE_XML = YES
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
ENABLE_PREPROCESSING = YES
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
# EXPAND_AS_DEFINED tags.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_ONLY_PREDEF = NO

View File

@ -0,0 +1,365 @@
#!/usr/bin/python3
# RetroShare JSON API generator
#
# Copyright (C) 2019 selankon <selankon@selankon.xyz>
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
#
# 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, version 3.
#
# 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 <https://www.gnu.org/licenses/>
#
# SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
# SPDX-License-Identifier: AGPL-3.0-only
# Original idea and implementation by G10h4ck (jsonapi-generator.cpp)
# Initial python reimplementation by Sehraf
#
# This python 3 script has superseded the original C++/Qt implementation this
# and is now used at build time in without depending on Qt.
import os
import sys
import xml.etree.ElementTree as ET
from string import Template
class MethodParam:
_type = ''
_name = ''
_defval = ''
_in = False
_out = False
_isMultiCallback = False
_isSingleCallback = False
class TemplateOwn(Template):
delimiter = '$%'
pattern = '''
\$%(?:
(?P<escaped>\$\%) | # Escape sequence of two delimiters
(?P<named>[_a-z][_a-z0-9]*)%\$ | # delimiter and a Python identifier
{(?P<braced>[_a-z][_a-z0-9]*)} | # delimiter and a braced identifier
(?P<invalid>) # Other ill-formed delimiter exprs
)
'''
def getText(e):
return "".join(e.itertext())
def processFile(file):
try:
dom1 = ET.parse(file).getroot()
except FileNotFoundError:
print('Can\'t open:', file)
headerFileInfo = dom1[0].findall('location')[0].attrib['file']
headerRelPath = os.path.dirname(headerFileInfo).split('/')[-1] + '/' + os.path.basename(headerFileInfo)
for sectDef in dom1.findall('.//memberdef'):
if sectDef.attrib['kind'] != 'variable' or sectDef.find('.//jsonapi') == None:
continue
instanceName = sectDef.find('name').text
typeName = sectDef.find('type/ref').text
typeFilePath = sectDef.find('type/ref').attrib['refid']
try:
dom2 = ET.parse(doxPrefix + typeFilePath + '.xml').getroot()
except FileNotFoundError:
print('Can\'t open:', doxPrefix + typeFilePath + '.xml')
for member in dom2.findall('.//member'):
refid = member.attrib['refid']
methodName = member.find('name').text
requiresAuth = True
defFilePath = refid.split('_')[0] + '.xml'
defFile = defFilePath
print('Looking for', typeName, methodName, 'into', typeFilePath)
try:
defDoc = ET.parse(doxPrefix + defFilePath).getroot()
except FileNotFoundError:
print('Can\'t open:', doxPrefix + defFilePath)
memberdef = None
for tmpMBD in defDoc.findall('.//memberdef'):
tmpId = tmpMBD.attrib['id']
tmpKind = tmpMBD.attrib['kind']
tmpJsonApiTagList = tmpMBD.findall('.//jsonapi')
if len(tmpJsonApiTagList) != 0 and tmpId == refid and tmpKind == 'function':
tmpJsonApiTag = tmpJsonApiTagList[0]
tmpAccessValue = None
if 'access' in tmpJsonApiTag.attrib:
tmpAccessValue = tmpJsonApiTag.attrib['access']
requiresAuth = 'unauthenticated' != tmpAccessValue;
if 'manualwrapper' != tmpAccessValue:
memberdef = tmpMBD
break
if memberdef == None:
continue
apiPath = '/' + instanceName + '/' + methodName
retvalType = getText(memberdef.find('type'))
# Apparently some xml declarations include new lines ('\n') and/or multiple spaces
# Strip them using python magic
retvalType = ' '.join(retvalType.split())
paramsMap = {}
orderedParamNames = []
hasInput = False
hasOutput = False
hasSingleCallback = False
hasMultiCallback = False
callbackName = ''
callbackParams = ''
for tmpPE in memberdef.findall('param'):
mp = MethodParam()
pName = getText(tmpPE.find('declname'))
tmpDefval = tmpPE.find('defval')
mp._defval = getText(tmpDefval) if tmpDefval != None else ''
pType = getText(tmpPE.find('type'))
if pType.startswith('const '): pType = pType[6:]
if pType.startswith('std::function'):
if pType.endswith('&'): pType = pType[:-1]
if pName.startswith('multiCallback'):
mp._isMultiCallback = True
hasMultiCallback = True
elif pName.startswith('callback'):
mp._isSingleCallback = True
hasSingleCallback = True
callbackName = pName
callbackParams = pType
else:
pType = pType.replace('&', '').replace(' ', '')
# Apparently some xml declarations include new lines ('\n') and/or multiple spaces
# Strip them using python magic
pType = ' '.join(pType.split())
mp._defval = ' '.join(mp._defval.split())
mp._type = pType
mp._name = pName
paramsMap[pName] = mp
orderedParamNames.append(pName)
for tmpPN in memberdef.findall('.//parametername'):
tmpParam = paramsMap[tmpPN.text]
tmpD = tmpPN.attrib['direction'] if 'direction' in tmpPN.attrib else ''
if 'in' in tmpD:
tmpParam._in = True
hasInput = True
if 'out' in tmpD:
tmpParam._out = True
hasOutput = True
# Params sanity check
for pmKey in paramsMap:
pm = paramsMap[pmKey]
if not (pm._isMultiCallback or pm._isSingleCallback or pm._in or pm._out):
print('ERROR', 'Parameter:', pm._name, 'of:', apiPath,
'declared in:', headerRelPath,
'miss doxygen parameter direction attribute!',
defFile)
sys.exit()
functionCall = '\t\t'
if retvalType != 'void':
functionCall += retvalType + ' retval = '
hasOutput = True
functionCall += instanceName + '->' + methodName + '('
functionCall += ', '.join(orderedParamNames) + ');\n'
print(instanceName, apiPath, retvalType, typeName, methodName)
for pn in orderedParamNames:
mp = paramsMap[pn]
print('\t', mp._type, mp._name, mp._in, mp._out)
inputParamsDeserialization = ''
if hasInput:
inputParamsDeserialization += '\t\t{\n'
inputParamsDeserialization += '\t\t\tRsGenericSerializer::SerializeContext& ctx(cReq);\n'
inputParamsDeserialization += '\t\t\tRsGenericSerializer::SerializeJob j(RsGenericSerializer::FROM_JSON);\n';
outputParamsSerialization = ''
if hasOutput:
outputParamsSerialization += '\t\t{\n'
outputParamsSerialization += '\t\t\tRsGenericSerializer::SerializeContext& ctx(cAns);\n'
outputParamsSerialization += '\t\t\tRsGenericSerializer::SerializeJob j(RsGenericSerializer::TO_JSON);\n';
paramsDeclaration = ''
for pn in orderedParamNames:
mp = paramsMap[pn]
paramsDeclaration += '\t\t' + mp._type + ' ' + mp._name
if mp._defval != '':
paramsDeclaration += ' = ' + mp._defval
paramsDeclaration += ';\n'
if mp._in:
inputParamsDeserialization += '\t\t\tRS_SERIAL_PROCESS('
inputParamsDeserialization += mp._name + ');\n'
if mp._out:
outputParamsSerialization += '\t\t\tRS_SERIAL_PROCESS('
outputParamsSerialization += mp._name + ');\n'
if hasInput:
inputParamsDeserialization += '\t\t}\n'
if retvalType != 'void':
outputParamsSerialization += '\t\t\tRS_SERIAL_PROCESS(retval);\n'
if hasOutput:
outputParamsSerialization += '\t\t}\n'
captureVars = ''
sessionEarlyClose = ''
if hasSingleCallback:
sessionEarlyClose = 'session->close();'
sessionDelayedClose = ''
if hasMultiCallback:
sessionDelayedClose = """
RsThread::async( [=]()
{
std::this_thread::sleep_for(
std::chrono::seconds(maxWait+120) );
auto lService = weakService.lock();
if(!lService || lService->is_down()) return;
lService->schedule( [=]()
{
auto session = weakSession.lock();
if(session && session->is_open())
session->close();
} );
} );
"""
captureVars = 'this'
callbackParamsSerialization = ''
if hasSingleCallback or hasMultiCallback or (callbackParams.find('(') + 2 < callbackParams.find(')')):
cbs = ''
callbackParams = callbackParams.split('(')[1]
callbackParams = callbackParams.split(')')[0]
cbs += '\t\t\tRsGenericSerializer::SerializeContext ctx;\n'
for cbPar in callbackParams.split(','):
isConst = cbPar.startswith('const ')
pSep = ' '
isRef = '&' in cbPar
if isRef: pSep = '&'
sepIndex = cbPar.rfind(pSep) + 1
cpt = cbPar[0:sepIndex][6:]
cpn = cbPar[sepIndex:]
cbs += '\t\t\tRsTypeSerializer::serial_process('
cbs += 'RsGenericSerializer::TO_JSON, ctx, '
if isConst:
cbs += 'const_cast<'
cbs += cpt
cbs += '>('
cbs += cpn
if isConst: cbs += ')'
cbs += ', "'
cbs += cpn
cbs += '" );\n'
callbackParamsSerialization += cbs
substitutionsMap = dict()
substitutionsMap['paramsDeclaration'] = paramsDeclaration
substitutionsMap['inputParamsDeserialization'] = inputParamsDeserialization
substitutionsMap['outputParamsSerialization'] = outputParamsSerialization
substitutionsMap['instanceName'] = instanceName
substitutionsMap['functionCall'] = functionCall
substitutionsMap['apiPath'] = apiPath
substitutionsMap['sessionEarlyClose'] = sessionEarlyClose
substitutionsMap['sessionDelayedClose'] = sessionDelayedClose
substitutionsMap['captureVars'] = captureVars
substitutionsMap['callbackName'] = callbackName
substitutionsMap['callbackParams'] = callbackParams
substitutionsMap['callbackParamsSerialization'] = callbackParamsSerialization
substitutionsMap['requiresAuth'] = 'true' if requiresAuth else 'false'
# print(substitutionsMap)
templFilePath = sourcePath
if hasMultiCallback or hasSingleCallback:
templFilePath += '/async-method-wrapper-template.cpp.tmpl'
else:
templFilePath += '/method-wrapper-template.cpp.tmpl'
templFile = open(templFilePath, 'r')
wrapperDef = TemplateOwn(templFile.read())
tmp = wrapperDef.substitute(substitutionsMap)
wrappersDefFile.write(tmp)
cppApiIncludesSet.add('#include "' + headerRelPath + '"\n')
if len(sys.argv) != 3:
print('Usage:', sys.argv[0], 'SOURCE_PATH OUTPUT_PATH Got:', sys.argv[:])
sys.exit(-1)
sourcePath = str(sys.argv[1])
outputPath = str(sys.argv[2])
doxPrefix = outputPath + '/xml/'
try:
wrappersDefFile = open(outputPath + '/jsonapi-wrappers.inl', 'w')
except FileNotFoundError:
print('Can\'t open:', outputPath + '/jsonapi-wrappers.inl')
try:
cppApiIncludesFile = open(outputPath + '/jsonapi-includes.inl', 'w');
except FileNotFoundError:
print('Can\'t open:', outputPath + '/jsonapi-includes.inl')
cppApiIncludesSet = set()
filesIterator = None
try:
filesIterator = os.listdir(doxPrefix)
except FileNotFoundError:
print("Doxygen xml output dir not found: ", doxPrefix)
os.exit(-1)
for file in filesIterator:
if file.endswith("8h.xml"):
processFile(os.path.join(doxPrefix, file))
for incl in cppApiIncludesSet:
cppApiIncludesFile.write(incl)

View File

@ -796,8 +796,9 @@ void JsonApiServer::run()
}
catch(std::exception& e)
{
RsErr() << __PRETTY_FUNCTION__ << " Failure starting JSON API server: "
<< e.what() << std::endl;
/* TODO: find a way to report back programmatically if failed listening
* port */
RS_ERR("Failure starting JSON API server: ", e.what());
print_stacktrace();
return;
}

View File

@ -0,0 +1,50 @@
/*******************************************************************************
* RetroShare JSON API *
* *
* Copyright (C) 2018-2019 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 <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
registerHandler( "$%apiPath%$",
[](const std::shared_ptr<rb::Session> session)
{
size_t reqSize = session->get_request()->get_header("Content-Length", 0);
session->fetch( reqSize, [](
const std::shared_ptr<rb::Session> session,
const rb::Bytes& body )
{
INITIALIZE_API_CALL_JSON_CONTEXT;
if( !checkRsServicePtrReady(
$%instanceName%$, "$%instanceName%$", cAns, session ) )
return;
$%paramsDeclaration%$
// deserialize input parameters from JSON
$%inputParamsDeserialization%$
// call retroshare C++ API
$%functionCall%$
// serialize out parameters and return value to JSON
$%outputParamsSerialization%$
// return them to the API caller
DEFAULT_API_CALL_JSON_RETURN(rb::OK);
} );
}, $%requiresAuth%$ );

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: (C) 2004-2019 Retroshare Team <contact@retroshare.cc>
# SPDX-FileCopyrightText: (C) 2004-2021 Retroshare Team <contact@retroshare.cc>
# SPDX-License-Identifier: CC0-1.0
!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri")
@ -207,7 +207,7 @@ linux-* {
LIBS *= -ldl
DEFINES *= PLUGIN_DIR=\"\\\"$${PLUGIN_DIR}\\\"\"
DEFINES *= DATA_DIR=\"\\\"$${DATA_DIR}\\\"\"
DEFINES *= RS_DATA_DIR=\"\\\"$${RS_DATA_DIR}\\\"\"
}
linux-g++ {
@ -291,7 +291,7 @@ mac {
#LIBS += -lsqlite3
DEFINES *= PLUGIN_DIR=\"\\\"$${PLUGIN_DIR}\\\"\"
DEFINES *= DATA_DIR=\"\\\"$${DATA_DIR}\\\"\"
DEFINES *= RS_DATA_DIR=\"\\\"$${RS_DATA_DIR}\\\"\"
}
################################# FreeBSD ##########################################
@ -365,6 +365,7 @@ HEADERS += chat/distantchat.h \
HEADERS += pqi/authssl.h \
pqi/authgpg.h \
pgp/pgphandler.h \
pgp/openpgpsdkhandler.h \
pgp/pgpkeyutil.h \
pqi/pqifdbin.h \
pqi/rstcpsocket.h \
@ -511,7 +512,8 @@ HEADERS += util/folderiterator.h \
util/cxx11retrocompat.h \
util/cxx14retrocompat.h \
util/cxx17retrocompat.h \
util/rsurl.h
util/cxx23retrocompat.h \
util/rsurl.h
SOURCES += ft/ftchunkmap.cc \
ft/ftcontroller.cc \
@ -538,6 +540,7 @@ SOURCES += chat/distantchat.cc \
SOURCES += pqi/authgpg.cc \
pqi/authssl.cc \
pgp/pgphandler.cc \
pgp/openpgpsdkhandler.cc \
pgp/pgpkeyutil.cc \
pgp/rscertificate.cc \
pgp/pgpauxutils.cc \
@ -1132,6 +1135,8 @@ test_bitdht {
################################# Android #####################################
android-* {
lessThan(ANDROID_API_VERSION, 24) {
## TODO: This probably disable largefile support and maybe is not necessary with
## __ANDROID_API__ >= 24 hence should be made conditional or moved to a
## compatibility header
@ -1139,12 +1144,26 @@ android-* {
DEFINES *= "fseeko64=fseeko"
DEFINES *= "ftello64=ftello"
## @See: rs_android/README-ifaddrs-android.adoc
HEADERS += \
rs_android/ifaddrs-android.h \
rs_android/LocalArray.h \
rs_android/ScopedFd.h
}
## Static library are very susceptible to order in command line
sLibs = bz2 $$RS_UPNP_LIB $$RS_SQL_LIB ssl crypto
LIBS += $$linkStaticLibs(sLibs)
PRE_TARGETDEPS += $$pretargetStaticLibs(sLibs)
HEADERS += util/androiddebug.h
HEADERS += \
rs_android/androidcoutcerrcatcher.hpp \
rs_android/retroshareserviceandroid.hpp \
rs_android/rsjni.hpp
SOURCES += rs_android/rsjni.cpp \
rs_android/retroshareserviceandroid.cpp \
rs_android/errorconditionwrap.cpp
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,116 @@
/*******************************************************************************
* libretroshare/src/pgp: pgphandler.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright 2018 Cyril Soler <csoler@users.sourceforge.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <stdint.h>
#include <string>
#include <list>
#include <map>
#include <set>
#include "util/rsthreads.h"
#include "pgp/pgphandler.h"
#include "retroshare/rstypes.h"
extern "C" {
// we should make sure later on to get rid of these structures in the .h
#include "openpgpsdk/keyring.h"
}
/// This class offer an abstract pgp handler to be used in RetroShare.
class OpenPGPSDKHandler: public PGPHandler
{
public:
OpenPGPSDKHandler( const std::string& path_to_public_keyring,
const std::string& path_to_secret_keyring,
const std::string& path_to_trust_database,
const std::string& pgp_lock_file) ;
virtual ~OpenPGPSDKHandler() ;
//================================================================================================//
// Implemented API from PGPHandler //
//================================================================================================//
//virtual std::string makeRadixEncodedPGPKey(uint32_t key_index,bool include_signatures) override;
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) override;
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids) override;
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passphrase, RsPgpId& pgpId, const int keynumbits, std::string& errString) override;
virtual std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const override;
virtual bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures ) const override;
virtual bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const override;
virtual bool exportGPGKeyPairToString( std::string& data, const RsPgpId& exportedKeyId, bool includeSignatures, std::string& errorMsg ) const override;
virtual bool getGPGDetailsFromBinaryBlock(const unsigned char *mem_block,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const override;
virtual bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_key_id,std::string& import_error) override;
virtual bool importGPGKeyPairFromString(const std::string &data, RsPgpId &imported_key_id, std::string &import_error) override;
virtual bool LoadCertificateFromBinaryData(const unsigned char *data,uint32_t data_len,RsPgpId& id,std::string& error_string) override;
virtual bool LoadCertificateFromString(const std::string& pgp_cert,RsPgpId& id,std::string& error_string) override;
virtual bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) override;
virtual bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len, unsigned char *encrypted_data, unsigned int *encrypted_data_len) override;
virtual bool decryptDataBin(const RsPgpId& /*key_id*/,const void *encrypted_data, const uint32_t encrypted_len, unsigned char *data, unsigned int *data_len) override;
virtual bool decryptTextFromFile(const RsPgpId&,std::string& text,const std::string& inputfile) override;
virtual bool SignDataBin(const RsPgpId& id,const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen,bool use_raw_signature, std::string reason /* = "" */) override;
virtual bool privateSignCertificate(const RsPgpId& ownId,const RsPgpId& id_of_key_to_sign) override;
virtual bool VerifySignBin(const void *literal_data, uint32_t literal_data_length, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& key_fingerprint) override;
virtual bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const override;
virtual bool haveSecretKey(const RsPgpId& id) const override;
virtual bool syncDatabase() override;
private:
bool locked_syncPublicKeyring() ;
void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ;
bool LoadCertificate(const unsigned char *data,uint32_t data_len,bool armoured,RsPgpId& id,std::string& error_string) ;
// Returns true if the signatures have been updated
//
bool validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) ;
/** Check public/private key and import them into the keyring
* @param keyring keyring with the new public/private key pair. Will be freed by the function.
* @param imported_key_id PGP id of the imported key
* @param import_error human readbale error message
* @returns true on success
* */
bool checkAndImportKeyPair(ops_keyring_t *keyring, RsPgpId& imported_key_id,std::string& import_error);
const ops_keydata_t *locked_getPublicKey(const RsPgpId&,bool stamp_the_key) const;
const ops_keydata_t *locked_getSecretKey(const RsPgpId&) const ;
void locked_mergeKeyringFromDisk(ops_keyring_t *keyring, std::map<RsPgpId,PGPCertificateInfo>& kmap, const std::string& keyring_file) ;
bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map<RsPgpId,PGPCertificateInfo>& kmap,const ops_keydata_t *keydata) ;
// Members.
//
ops_keyring_t *_pubring ;
ops_keyring_t *_secring ;
void printOPSKeys() const;
// Helper functions.
//
static std::string makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) ;
static ops_keyring_t *allocateOPSKeyring() ;
static void addNewKeyToOPSKeyring(ops_keyring_t*, const ops_keydata_t&) ;
static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different
};

View File

@ -34,17 +34,17 @@ PgpAuxUtilsImpl::PgpAuxUtilsImpl()
const RsPgpId& PgpAuxUtilsImpl::getPGPOwnId()
{
return AuthGPG::getAuthGPG()->getGPGOwnId();
return AuthPGP::getPgpOwnId();
}
RsPgpId PgpAuxUtilsImpl::getPGPId(const RsPeerId& sslid)
RsPgpId PgpAuxUtilsImpl::getPgpId(const RsPeerId& sslid)
{
return rsPeers->getGPGId(sslid);
}
bool PgpAuxUtilsImpl::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const
{
return AuthGPG::getAuthGPG()->getKeyFingerprint(id, fp);
return AuthPGP::getKeyFingerprint(id, fp);
}
bool PgpAuxUtilsImpl::VerifySignBin(const void *data,
@ -54,17 +54,17 @@ bool PgpAuxUtilsImpl::VerifySignBin(const void *data,
const PGPFingerprintType& withfingerprint)
{
return AuthGPG::getAuthGPG()->VerifySignBin(data, len, sign, signlen, withfingerprint);
return AuthPGP::VerifySignBin(data, len, sign, signlen, withfingerprint);
}
bool PgpAuxUtilsImpl::getGPGAllList(std::list<RsPgpId> &ids)
bool PgpAuxUtilsImpl::getPgpAllList(std::list<RsPgpId> &ids)
{
return AuthGPG::getAuthGPG()->getGPGAllList(ids);
return AuthPGP::getPgpAllList(ids);
}
bool PgpAuxUtilsImpl::parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const
{
return AuthGPG::getAuthGPG()->parseSignature(sign,signlen,issuer);
return AuthPGP::parseSignature(sign,signlen,issuer);
}

View File

@ -35,8 +35,8 @@ class PgpAuxUtils
virtual ~PgpAuxUtils(){}
virtual const RsPgpId &getPGPOwnId() = 0;
virtual RsPgpId getPGPId(const RsPeerId& sslid) = 0;
virtual bool getGPGAllList(std::list<RsPgpId> &ids) = 0;
virtual RsPgpId getPgpId(const RsPeerId& sslid) = 0;
virtual bool getPgpAllList(std::list<RsPgpId> &ids) = 0;
virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const = 0;
virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const =0;
@ -49,12 +49,12 @@ public:
PgpAuxUtilsImpl();
virtual const RsPgpId &getPGPOwnId();
virtual RsPgpId getPGPId(const RsPeerId& sslid);
virtual RsPgpId getPgpId(const RsPeerId& sslid);
virtual bool parseSignature(unsigned char *sign, unsigned int signlen, RsPgpId& issuer) const ;
virtual bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) const;
virtual bool VerifySignBin(const void *data, uint32_t len, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint);
virtual bool getGPGAllList(std::list<RsPgpId> &ids);
virtual bool getPgpAllList(std::list<RsPgpId> &ids);
};

File diff suppressed because it is too large Load Diff

View File

@ -29,12 +29,6 @@
#include <util/rsthreads.h>
#include <retroshare/rstypes.h>
extern "C" {
#include <openpgpsdk/types.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/keyring_local.h>
}
typedef std::string (*PassphraseCallback)(void *data, const char *uid_title, const char *uid_hint, const char *passphrase_info, int prev_was_bad,bool *cancelled) ;
class PGPCertificateInfo
@ -56,9 +50,11 @@ class PGPCertificateInfo
mutable rstime_t _time_stamp ; // last time the key was used (received, used for signature verification, etc)
PGPFingerprintType _fpr; /* fingerprint */
// RsPgpId _key_id ;
uint32_t _key_index ; // index to array of keys in the public keyring
// Index to array of keys in the public keyring. Dependign on the specific implementation
// of how the keyring is stored, this may be used differently.
uint32_t _key_index ;
static const uint32_t PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION = 0x0001 ;
static const uint32_t PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE = 0x0002 ;
@ -80,53 +76,87 @@ class PGPCertificateInfo
class PGPHandler
{
public:
PGPHandler( const std::string& path_to_public_keyring,
PGPHandler( const std::string& path_to_public_keyring,
const std::string& path_to_secret_keyring,
const std::string& path_to_trust_database,
const std::string& pgp_lock_file) ;
virtual ~PGPHandler() ;
/**
//=======================================================================================//
// Methods that needs to be derived depending on how PGP is implemented //
//=======================================================================================//
// Removes the given keys from the keyring. Also backup the keyring to a file which name is automatically generated
// and given pack for proper display.
//
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) =0;
//virtual std::string makeRadixEncodedPGPKey(uint32_t key_index,bool include_signatures) =0;
virtual bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids)=0;
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) =0;
virtual std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const=0;
/** The caller is in charge of freeing `mem` once finished */
virtual bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures ) const =0;
virtual bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_key_id) const=0;
virtual bool exportGPGKeyPairToString( std::string& data, const RsPgpId& exportedKeyId, bool includeSignatures, std::string& errorMsg ) const =0;
// Gets info about the key. Who are the signers, what's the owner's name, etc.
//
virtual bool getGPGDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const =0;
virtual bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_id,std::string& import_error) =0;
/**
* @param ids list of gpg certificate ids (note, not the actual certificates)
*/
virtual bool importGPGKeyPairFromString(const std::string& data,RsPgpId& imported_id,std::string& import_error) =0;
virtual bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string)=0;
virtual bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string)=0;
virtual bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) =0;
virtual bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) =0;
// The client should supply a memory chunk to store the data. The length will be updated to the real length of the data.
//
virtual bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len , unsigned char *encrypted_data, unsigned int *encrypted_data_len) =0;
virtual bool decryptDataBin(const RsPgpId& key_id,const void *encrypted_data, const uint32_t encrypted_len , unsigned char *data, unsigned int *data_len) =0;
virtual bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") =0;
virtual bool privateSignCertificate(const RsPgpId& own_id,const RsPgpId& id_of_key_to_sign) =0;
virtual bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) =0;
/**
* @brief Get PGP fingerprint for the given key
* @param id PGP 64bit key id
* @param fp storage for the retrived key fingerpring, the contained value
* is meaningfull only if true is returned
* @return true if the key was found, false if not
*/
virtual bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const=0;
virtual bool haveSecretKey(const RsPgpId& id) const =0;
// Syncs the keyrings and trust database between memory and disk. The algorithm is:
// 1 - lock the keyrings
// 2 - compare file modification dates with last writing date
// - if file is modified, load it, and merge with memory
// 3 - look into memory modification flags
// - if flag says keyring has changed, write to disk
//
virtual bool syncDatabase() =0;
//=======================================================================================//
// Common methods to PGPHandler //
//=======================================================================================//
bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) const ;
bool haveSecretKey(const RsPgpId& id) const ;
bool importGPGKeyPair(const std::string& filename,RsPgpId& imported_id,std::string& import_error) ;
bool importGPGKeyPairFromString(const std::string& data,RsPgpId& imported_id,std::string& import_error) ;
bool exportGPGKeyPair(const std::string& filename,const RsPgpId& exported_id) const ;
bool exportGPGKeyPairToString(
std::string& data, const RsPgpId& exportedKeyId,
bool includeSignatures, std::string& errorMsg ) const;
bool availableGPGCertificatesWithPrivateKeys(std::list<RsPgpId>& ids);
bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString) ;
bool LoadCertificateFromString(const std::string& pem, RsPgpId& gpg_id, std::string& error_string);
bool LoadCertificateFromBinaryData(const unsigned char *bin_data,uint32_t bin_data_len, RsPgpId& gpg_id, std::string& error_string);
std::string SaveCertificateToString(const RsPgpId& id,bool include_signatures) const ;
/** The caller is in charge of freeing `mem` once finished */
bool exportPublicKey( const RsPgpId& id,
unsigned char*& mem, size_t& mem_size,
bool armoured, bool include_signatures) const;
bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ;
bool SignDataBin(const RsPgpId& id, const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, bool make_raw_signature=false, std::string reason = "") ;
bool VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& withfingerprint) ;
bool privateSignCertificate(const RsPgpId& own_id,const RsPgpId& id_of_key_to_sign) ;
// The client should supply a memory chunk to store the data. The length will be updated to the real length of the data.
//
bool encryptDataBin(const RsPgpId& key_id,const void *data, const uint32_t len
, unsigned char *encrypted_data, unsigned int *encrypted_data_len) ;
bool decryptDataBin(const RsPgpId& key_id,const void *encrypted_data, const uint32_t encrypted_len
, unsigned char *data, unsigned int *data_len) ;
bool encryptTextToFile(const RsPgpId& key_id,const std::string& text,const std::string& outfile) ;
bool decryptTextFromFile(const RsPgpId& key_id,std::string& text,const std::string& encrypted_inputfile) ;
bool parseSignature(unsigned char *sign, unsigned int signlen,RsPgpId& issuer_id) ;
void setAcceptConnexion(const RsPgpId&,bool) ;
@ -135,11 +165,6 @@ public:
void locked_updateOwnSignatureFlag(PGPCertificateInfo&, const RsPgpId&, PGPCertificateInfo&, const RsPgpId&) ;
// Removes the given keys from the keyring. Also backup the keyring to a file which name is automatically generated
// and given pack for proper display.
//
bool removeKeysFromPGPKeyring(const std::set<RsPgpId>& key_ids,std::string& backup_file,uint32_t& error_code) ;
//bool isKeySupported(const RsPgpId& id) const ;
bool privateTrustCertificate(const RsPgpId& id,int valid_level) ;
@ -174,66 +199,18 @@ public:
*/
static RsPgpId pgpIdFromFingerprint(const RsPgpFingerprint& f);
/**
* @brief Get PGP fingerprint for the given key
* @param id PGP 64bit key id
* @param fp storage for the retrived key fingerpring, the contained value
* is meaningfull only if true is returned
* @return true if the key was found, false if not
*/
bool getKeyFingerprint(const RsPgpId& id, RsPgpFingerprint& fp) const;
// Gets info about the key. Who are the signers, what's the owner's name, etc.
//
bool getGPGDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) const ;
// Debug stuff.
virtual bool printKeys() const ;
// Syncs the keyrings and trust database between memory and disk. The algorithm is:
// 1 - lock the keyrings
// 2 - compare file modification dates with last writing date
// - if file is modified, load it, and merge with memory
// 3 - look into memory modification flags
// - if flag says keyring has changed, write to disk
//
bool syncDatabase() ;
private:
bool LoadCertificate(const unsigned char *bin_data,uint32_t bin_data_len, bool armoured, RsPgpId& gpg_id, std::string& error_string);
void initCertificateInfo(PGPCertificateInfo& cert,const ops_keydata_t *keydata,uint32_t i) ;
// Returns true if the signatures have been updated
//
bool validateAndUpdateSignatures(PGPCertificateInfo& cert,const ops_keydata_t *keydata) ;
/** Check public/private key and import them into the keyring
* @param keyring keyring with the new public/private key pair. Will be freed by the function.
* @param imported_key_id PGP id of the imported key
* @param import_error human readbale error message
* @returns true on success
* */
bool checkAndImportKeyPair(ops_keyring_t *keyring, RsPgpId& imported_key_id,std::string& import_error);
const ops_keydata_t *locked_getPublicKey(const RsPgpId&,bool stamp_the_key) const;
const ops_keydata_t *locked_getSecretKey(const RsPgpId&) const ;
protected:
void locked_readPrivateTrustDatabase() ;
bool locked_writePrivateTrustDatabase() ;
bool locked_syncPublicKeyring() ;
bool locked_syncTrustDatabase() ;
void locked_mergeKeyringFromDisk(ops_keyring_t *keyring, std::map<RsPgpId,PGPCertificateInfo>& kmap, const std::string& keyring_file) ;
bool locked_addOrMergeKey(ops_keyring_t *keyring,std::map<RsPgpId,PGPCertificateInfo>& kmap,const ops_keydata_t *keydata) ;
bool locked_syncTrustDatabase() ;
// Members.
//
mutable RsMutex pgphandlerMtx ;
ops_keyring_t *_pubring ;
ops_keyring_t *_secring ;
std::map<RsPgpId,PGPCertificateInfo> _public_keyring_map ; // used for fast access to keys. Gives the index in the keyring.
std::map<RsPgpId,PGPCertificateInfo> _secret_keyring_map ;
@ -249,11 +226,5 @@ public:
rstime_t _secring_last_update_time ;
rstime_t _trustdb_last_update_time ;
// Helper functions.
//
static std::string makeRadixEncodedPGPKey(const ops_keydata_t *key,bool include_signatures) ;
static ops_keyring_t *allocateOPSKeyring() ;
static void addNewKeyToOPSKeyring(ops_keyring_t*, const ops_keydata_t&) ;
static PassphraseCallback _passphrase_callback ;
static bool mergeKeySignatures(ops_keydata_t *dst,const ops_keydata_t *src) ; // returns true if signature lists are different
};

View File

@ -552,26 +552,24 @@ unsigned short RsCertificate::loc_port_us() const
return (int)ipv4_internal_ip_and_port[4]*256 + (int)ipv4_internal_ip_and_port[5] ;
}
bool RsCertificate::cleanCertificate( const std::string& input, std::string& output, Format& format, uint32_t& error_code, bool check_content )
bool RsCertificate::cleanCertificate( const std::string& input, std::string& output, Format& format, uint32_t& error_code, bool check_content, RsPeerDetails& details)
{
if(cleanRadix64(input,output,error_code))
{
RsPeerDetails details;
if(rsPeers->parseShortInvite(output,details,error_code))
{
format = RS_CERTIFICATE_SHORT_RADIX;
return true;
}
if(rsPeers->parseShortInvite(output,details,error_code))
{
format = RS_CERTIFICATE_SHORT_RADIX;
return true;
}
//Clear details. As parseShortInvite may make it dirty.
details = RsPeerDetails();
format = RS_CERTIFICATE_RADIX;
if(!check_content) return true;
uint32_t errCode;
auto crt = RsCertificate::fromString(input, errCode);
error_code = static_cast<int>(errCode);
return crt != nullptr;
return rsPeers->loadDetailsFromStringCert(input,details,error_code);
}
return false;

View File

@ -84,7 +84,7 @@ public:
static bool cleanCertificate(
const std::string& input, std::string& output,
RsCertificate::Format& format, uint32_t& error_code, bool check_content);
RsCertificate::Format& format, uint32_t& error_code, bool check_content, RsPeerDetails& details);
const std::set<RsUrl>& locators() const { return mLocators; }

View File

@ -46,7 +46,7 @@
//const rstime_t STORE_KEY_TIMEOUT = 1 * 60 * 60; //store key is call around every hour
AuthGPG *AuthGPG::_instance = NULL ;
AuthPGP *AuthPGP::_instance = NULL ;
void cleanupZombies(int numkill); // function to cleanup zombies under OSX.
@ -54,34 +54,46 @@ void cleanupZombies(int numkill); // function to cleanup zombies under OSX.
/* Function to sign X509_REQ via GPGme. */
bool AuthGPG::decryptTextFromFile(std::string& text,const std::string& inputfile)
int AuthPGP::availablePgpCertificatesWithPrivateKeys(std::list<RsPgpId>& pgpIds)
{
return PGPHandler::decryptTextFromFile(mOwnGpgId,text,inputfile) ;
return instance()->mPgpHandler->availableGPGCertificatesWithPrivateKeys(pgpIds);
}
bool AuthPGP::getPgpDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers)
{
return instance()->mPgpHandler->getGPGDetailsFromBinaryBlock(mem,mem_size,key_id,name,signers);
}
void AuthPGP::registerToConfigMgr(const std::string& fname,p3ConfigMgr *CfgMgr)
{
CfgMgr->addConfiguration(fname, instance());
}
bool AuthPGP::decryptTextFromFile(std::string& text,const std::string& inputfile)
{
return instance()->mPgpHandler->decryptTextFromFile(instance()->mOwnGpgId,text,inputfile) ;
}
bool AuthGPG::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
bool AuthPGP::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
{
// std::list<RsPgpId> pids ;
//
// for(std::list<RsPgpId>::const_iterator it(pgp_ids.begin());it!=pgp_ids.end();++it)
// pids.push_back(RsPgpId(*it)) ;
return PGPHandler::removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
return instance()->mPgpHandler->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
}
// bool AuthGPG::decryptTextFromString(std::string& encrypted_text,std::string& output)
// {
// return PGPHandler::decryptTextFromString(mOwnGpgId,encrypted_text,output) ;
// return instance()->mPgpHandler->decryptTextFromString(mOwnGpgId,encrypted_text,output) ;
// }
bool AuthGPG::encryptTextToFile(const std::string& text,const std::string& outfile)
bool AuthPGP::encryptTextToFile(const std::string& text,const std::string& outfile)
{
return PGPHandler::encryptTextToFile(mOwnGpgId,text,outfile) ;
return instance()->mPgpHandler->encryptTextToFile(instance()->mOwnGpgId,text,outfile) ;
}
// bool AuthGPG::encryptTextToString(const std::string& pgp_id,const std::string& text,std::string& outstr)
// {
// return PGPHandler::encryptTextToString(RsPgpId(pgp_id),text,outstr) ;
// return instance()->mPgpHandler->encryptTextToString(RsPgpId(pgp_id),text,outstr) ;
// }
std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char *uid_hint, const char * /*passphrase_info*/, int prev_was_bad,bool *cancelled)
@ -95,7 +107,7 @@ std::string pgp_pwd_callback(void * /*hook*/, const char *uid_title, const char
return password ;
}
void AuthGPG::init(
void AuthPGP::init(
const std::string& path_to_public_keyring,
const std::string& path_to_secret_keyring,
const std::string& path_to_trustdb,
@ -107,14 +119,14 @@ void AuthGPG::init(
std::cerr << "AuthGPG::init() called twice!" << std::endl ;
}
// if(cb) PGPHandler::setPassphraseCallback(cb);else
PGPHandler::setPassphraseCallback(pgp_pwd_callback);
_instance = new AuthGPG( path_to_public_keyring,
// if(cb) instance()->mPgpHandler->setPassphraseCallback(cb);else
instance()->mPgpHandler->setPassphraseCallback(pgp_pwd_callback);
_instance = new AuthPGP( path_to_public_keyring,
path_to_secret_keyring,
path_to_trustdb, pgp_lock_file );
}
void AuthGPG::exit()
void AuthPGP::exit()
{
if(_instance)
{
@ -124,9 +136,8 @@ void AuthGPG::exit()
}
}
AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& path_to_secret_keyring,const std::string& path_to_trustdb,const std::string& pgp_lock_file)
AuthPGP::AuthPGP(const std::string& path_to_public_keyring,const std::string& path_to_secret_keyring,const std::string& path_to_trustdb,const std::string& pgp_lock_file)
:p3Config(),
PGPHandler(path_to_public_keyring,path_to_secret_keyring,path_to_trustdb,pgp_lock_file),
gpgMtxService("AuthGPG-service"),
gpgMtxEngine("AuthGPG-engine"),
gpgMtxData("AuthGPG-data"),
@ -135,7 +146,9 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
_force_sync_database(false),
mCount(0)
{
start("AuthGPG");
mPgpHandler = new OpenPGPSDKHandler(path_to_public_keyring,path_to_secret_keyring,path_to_trustdb,pgp_lock_file);
start("AuthGPG");
}
/* This function is called when retroshare is first started
@ -149,7 +162,7 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
//{
// std::list<RsPgpId> pids ;
//
// PGPHandler::availableGPGCertificatesWithPrivateKeys(pids) ;
// mPgpHandler->availableGPGCertificatesWithPrivateKeys(pids) ;
//
// for(std::list<RsPgpId>::const_iterator it(pids.begin());it!=pids.end();++it)
// ids.push_back( (*it).toStdString() ) ;
@ -165,17 +178,17 @@ AuthGPG::AuthGPG(const std::string& path_to_public_keyring,const std::string& pa
* This function must be called successfully (return == 1)
* before anything else can be done. (except above fn).
*/
int AuthGPG::GPGInit(const RsPgpId &ownId)
int AuthPGP::PgpInit(const RsPgpId &ownId)
{
#ifdef DEBUG_AUTHGPG
std::cerr << "AuthGPG::GPGInit() called with own gpg id : " << ownId.toStdString() << std::endl;
#endif
mOwnGpgId = RsPgpId(ownId);
instance()->mOwnGpgId = ownId;
//force the validity of the private key. When set to unknown, it caused signature and text encryptions bugs
privateTrustCertificate(ownId, 5);
updateOwnSignatureFlag(mOwnGpgId) ;
instance()->privateTrustCertificate(ownId, 5);
instance()->mPgpHandler->updateOwnSignatureFlag(ownId) ;
#ifdef DEBUG_AUTHGPG
std::cerr << "AuthGPG::GPGInit finished." << std::endl;
@ -184,11 +197,11 @@ int AuthGPG::GPGInit(const RsPgpId &ownId)
return 1;
}
AuthGPG::~AuthGPG()
AuthPGP::~AuthPGP()
{
}
void AuthGPG::threadTick()
void AuthPGP::threadTick()
{
rstime::rs_usleep(100 * 1000); //100 msec
@ -204,13 +217,13 @@ void AuthGPG::threadTick()
/// - checks whether the keyring has changed on disk.
/// - merges/updates according to status.
///
PGPHandler::syncDatabase() ;
mPgpHandler->syncDatabase() ;
mCount = 0;
_force_sync_database = false ;
}//if (++count >= 100 || _force_sync_database)
}
void AuthGPG::processServices()
void AuthPGP::processServices()
{
AuthGPGOperation *operation = NULL;
AuthGPGService *service = NULL;
@ -251,7 +264,7 @@ void AuthGPG::processServices()
/* don't bother loading - if we already have the certificate */
if (isGPGId(loadOrSave->m_certGpgId))
if (mPgpHandler->isGPGId(loadOrSave->m_certGpgId))
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPGimpl::processServices() Skipping load - already have it" << std::endl;
@ -305,66 +318,66 @@ void AuthGPG::processServices()
delete operation;
}
bool AuthGPG::DoOwnSignature(const void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl, std::string reason /* = "" */)
bool AuthPGP::DoOwnSignature(const void *data, unsigned int datalen, void *buf_sigout, unsigned int *outl, std::string reason /* = "" */)
{
return PGPHandler::SignDataBin(mOwnGpgId,data,datalen,(unsigned char *)buf_sigout,outl,false,reason) ;
return instance()->mPgpHandler->SignDataBin(mOwnGpgId,data,datalen,(unsigned char *)buf_sigout,outl,false,reason) ;
}
/* import to GnuPG and other Certificates */
bool AuthGPG::VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const PGPFingerprintType& withfingerprint)
bool AuthPGP::VerifySignature(const void *data, int datalen, const void *sig, unsigned int siglen, const PGPFingerprintType& withfingerprint)
{
return PGPHandler::VerifySignBin((unsigned char*)data,datalen,(unsigned char*)sig,siglen,withfingerprint) ;
return instance()->mPgpHandler->VerifySignBin((unsigned char*)data,datalen,(unsigned char*)sig,siglen,withfingerprint) ;
}
bool AuthGPG::parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id)
bool AuthPGP::parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id)
{
return PGPHandler::parseSignature((unsigned char*)sig,siglen,issuer_id) ;
return instance()->mPgpHandler->parseSignature((unsigned char*)sig,siglen,issuer_id) ;
}
bool AuthGPG::exportProfile(const std::string& fname,const RsPgpId& exported_id)
bool AuthPGP::exportProfile(const std::string& fname,const RsPgpId& exported_id)
{
return PGPHandler::exportGPGKeyPair(fname,exported_id) ;
return instance()->mPgpHandler->exportGPGKeyPair(fname,exported_id) ;
}
bool AuthGPG::exportIdentityToString(
bool AuthPGP::exportIdentityToString(
std::string& data, const RsPgpId& pgpId, bool includeSignatures,
std::string& errorMsg )
{
return PGPHandler::exportGPGKeyPairToString(
return instance()->mPgpHandler->exportGPGKeyPairToString(
data, pgpId, includeSignatures, errorMsg);
}
bool AuthGPG::importProfile(const std::string& fname,RsPgpId& imported_id,std::string& import_error)
bool AuthPGP::importProfile(const std::string& fname,RsPgpId& imported_id,std::string& import_error)
{
return PGPHandler::importGPGKeyPair(fname,imported_id,import_error) ;
return instance()->mPgpHandler->importGPGKeyPair(fname,imported_id,import_error) ;
}
bool AuthGPG::importProfileFromString(const std::string &data, RsPgpId &gpg_id, std::string &import_error)
bool AuthPGP::importProfileFromString(const std::string &data, RsPgpId &gpg_id, std::string &import_error)
{
return PGPHandler::importGPGKeyPairFromString(data, gpg_id, import_error);
return instance()->mPgpHandler->importGPGKeyPairFromString(data, gpg_id, import_error);
}
bool AuthGPG::active()
bool AuthPGP::active()
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
return gpgKeySelected;
return instance()->gpgKeySelected;
}
bool AuthGPG::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString)
bool AuthPGP::GeneratePgpCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId& pgpId, const int keynumbits, std::string& errString)
{
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
return PGPHandler::GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString) ;
return instance()->mPgpHandler->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString) ;
}
/**** These Two are common */
std::string AuthGPG::getGPGName(const RsPgpId& id,bool *success)
std::string AuthPGP::getPgpName(const RsPgpId& id,bool *success)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
const PGPCertificateInfo *info = getCertificateInfo(id) ;
const PGPCertificateInfo *info = instance()->mPgpHandler->getCertificateInfo(id) ;
if(info != NULL)
{
@ -378,11 +391,25 @@ std::string AuthGPG::getGPGName(const RsPgpId& id,bool *success)
}
}
/**** These Two are common */
std::string AuthGPG::getGPGEmail(const RsPgpId& id,bool *success)
AuthPGP *AuthPGP::instance()
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
const PGPCertificateInfo *info = getCertificateInfo(id) ;
if(!_instance)
{
RsFatal() << "AuthGPG::instance() called before AuthGPG::init()! This should not happen." << std::endl;
return nullptr;
}
return _instance;
}
bool AuthPGP::isPGPId(const RsPgpId& id)
{
return instance()->mPgpHandler->isGPGId(id);
}
/**** These Two are common */
std::string AuthPGP::getPgpEmail(const RsPgpId& id,bool *success)
{
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
const PGPCertificateInfo *info = instance()->mPgpHandler->getCertificateInfo(id) ;
if(info != NULL)
{
@ -398,30 +425,30 @@ std::string AuthGPG::getGPGEmail(const RsPgpId& id,bool *success)
/**** GPG versions ***/
const RsPgpId& AuthGPG::getGPGOwnId()
const RsPgpId& AuthPGP::getPgpOwnId()
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
return mOwnGpgId ;
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
return instance()->mOwnGpgId ;
}
std::string AuthGPG::getGPGOwnName()
std::string AuthPGP::getPgpOwnName()
{
return getGPGName(mOwnGpgId) ;
return getPgpName(instance()->mOwnGpgId) ;
}
bool AuthGPG::getGPGAllList(std::list<RsPgpId> &ids)
bool AuthPGP::getPgpAllList(std::list<RsPgpId> &ids)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
PGPHandler::getGPGFilteredList(ids) ;
instance()->mPgpHandler->getGPGFilteredList(ids) ;
return true;
}
const PGPCertificateInfo *AuthGPG::getCertInfoFromStdString(const std::string& pgp_id) const
const PGPCertificateInfo *AuthPGP::getCertInfoFromStdString(const std::string& pgp_id) const
{
try
{
return PGPHandler::getCertificateInfo(RsPgpId(pgp_id)) ;
return instance()->mPgpHandler->getCertificateInfo(RsPgpId(pgp_id)) ;
}
catch(std::exception& e)
{
@ -429,13 +456,13 @@ const PGPCertificateInfo *AuthGPG::getCertInfoFromStdString(const std::string& p
return NULL ;
}
}
bool AuthGPG::haveSecretKey(const RsPgpId& id) const
bool AuthPGP::haveSecretKey(const RsPgpId& id)
{
return PGPHandler::haveSecretKey(id) ;
return instance()->mPgpHandler->haveSecretKey(id) ;
}
bool AuthGPG::isKeySupported(const RsPgpId& id) const
bool AuthPGP::isKeySupported(const RsPgpId& id)
{
const PGPCertificateInfo *pc = getCertificateInfo(id) ;
const PGPCertificateInfo *pc = instance()->mPgpHandler->getCertificateInfo(id) ;
if(pc == NULL)
return false ;
@ -443,11 +470,11 @@ bool AuthGPG::isKeySupported(const RsPgpId& id) const
return !(pc->_flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_UNSUPPORTED_ALGORITHM) ;
}
bool AuthGPG::getGPGDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
bool AuthPGP::getPgpDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxData); /******* LOCKED ******/
const PGPCertificateInfo *pc = PGPHandler::getCertificateInfo(pgp_id) ;
const PGPCertificateInfo *pc = instance()->mPgpHandler->getCertificateInfo(pgp_id) ;
if(pc == NULL)
return false ;
@ -474,28 +501,26 @@ bool AuthGPG::getGPGDetails(const RsPgpId& pgp_id, RsPeerDetails &d)
return true;
}
bool AuthGPG::getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&))
bool AuthPGP::getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&))
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
return PGPHandler::getGPGFilteredList(list,filter) ;
return instance()->mPgpHandler->getGPGFilteredList(list,filter) ;
}
static bool filter_Validity(const PGPCertificateInfo& /*info*/) { return true ; } //{ return info._validLvl >= PGPCertificateInfo::GPGME_VALIDITY_MARGINAL ; }
static bool filter_Accepted(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_ACCEPT_CONNEXION ; }
static bool filter_OwnSigned(const PGPCertificateInfo& info) { return info._flags & PGPCertificateInfo::PGP_CERTIFICATE_FLAG_HAS_OWN_SIGNATURE ; }
bool AuthGPG::getGPGValidList(std::list<RsPgpId> &ids)
bool AuthPGP::getPgpValidList(std::list<RsPgpId> &ids)
{
return getGPGFilteredList(ids,&filter_Validity);
}
bool AuthGPG::getGPGAcceptedList(std::list<RsPgpId> &ids)
bool AuthPGP::getPgpAcceptedList(std::list<RsPgpId> &ids)
{
return getGPGFilteredList(ids,&filter_Accepted);
}
bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
bool AuthPGP::getPgpSignedList(std::list<RsPgpId> &ids)
{
return getGPGFilteredList(ids,&filter_OwnSigned);
}
@ -504,9 +529,9 @@ bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
// {
// RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
// #ifdef LIMIT_CERTIFICATE_SIZE
// certificate = PGPHandler::SaveCertificateToString(RsPgpId(id),false) ;
// certificate = instance()->mPgpHandler->SaveCertificateToString(RsPgpId(id),false) ;
// #else
// certificate = PGPHandler::SaveCertificateToString(RsPgpId(id),true) ;
// certificate = instance()->mPgpHandler->SaveCertificateToString(RsPgpId(id),true) ;
// #endif
//
// // #ifdef LIMIT_CERTIFICATE_SIZE
@ -528,20 +553,20 @@ bool AuthGPG::getGPGSignedList(std::list<RsPgpId> &ids)
/* SKTAN : do not know how to use std::string id */
std::string AuthGPG::SaveCertificateToString(const RsPgpId &id,bool include_signatures)
std::string AuthPGP::SaveCertificateToString(const RsPgpId &id,bool include_signatures)
{
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
return PGPHandler::SaveCertificateToString(id,include_signatures) ;
return instance()->mPgpHandler->SaveCertificateToString(id,include_signatures) ;
}
/* import to GnuPG and other Certificates */
bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string)
bool AuthPGP::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string)
{
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
if(PGPHandler::LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string))
if(instance()->mPgpHandler->LoadCertificateFromBinaryData(data,data_len,gpg_id,error_string))
{
updateOwnSignatureFlag(gpg_id,mOwnGpgId) ;
instance()->mPgpHandler->updateOwnSignatureFlag(gpg_id,instance()->mOwnGpgId) ;
return true ;
}
@ -549,13 +574,13 @@ bool AuthGPG::LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_l
}
/* import to GnuPG and other Certificates */
bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string)
bool AuthPGP::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,std::string& error_string)
{
RsStackMutex stack(gpgMtxEngine); /******* LOCKED ******/
RsStackMutex stack(instance()->gpgMtxEngine); /******* LOCKED ******/
if(PGPHandler::LoadCertificateFromString(str,gpg_id,error_string))
if(instance()->mPgpHandler->LoadCertificateFromString(str,gpg_id,error_string))
{
updateOwnSignatureFlag(gpg_id,mOwnGpgId) ;
instance()->mPgpHandler->updateOwnSignatureFlag(gpg_id,instance()->mOwnGpgId) ;
return true ;
}
@ -576,7 +601,7 @@ bool AuthGPG::LoadCertificateFromString(const std::string &str, RsPgpId& gpg_id,
/*************************************/
/* These take PGP Ids */
bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
bool AuthPGP::AllowConnection(const RsPgpId& gpg_id, bool accept)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPG::AllowConnection(" << gpg_id << ")" << std::endl;
@ -584,11 +609,11 @@ bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
/* Was a "Reload Certificates" here -> be shouldn't be needed -> and very expensive, try without. */
{
RsStackMutex stack(gpgMtxData);
PGPHandler::setAcceptConnexion(gpg_id,accept) ;
RsStackMutex stack(instance()->gpgMtxData);
instance()->mPgpHandler->setAcceptConnexion(gpg_id,accept) ;
}
IndicateConfigChanged();
instance()->IndicateConfigChanged();
RsServer::notify()->notifyListChange(NOTIFY_LIST_FRIENDS, accept ? NOTIFY_TYPE_ADD : NOTIFY_TYPE_DEL);
@ -596,16 +621,16 @@ bool AuthGPG::AllowConnection(const RsPgpId& gpg_id, bool accept)
}
/* These take PGP Ids */
bool AuthGPG::SignCertificateLevel0(const RsPgpId &id)
bool AuthPGP::SignCertificateLevel0(const RsPgpId &id)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPG::SignCertificat(" << id << ")" << std::endl;
#endif
return privateSignCertificate(id) ;
return instance()->privateSignCertificate(id) ;
}
bool AuthGPG::RevokeCertificate(const RsPgpId &id)
bool AuthPGP::RevokeCertificate(const RsPgpId &id)
{
/* remove unused parameter warnings */
(void) id;
@ -617,46 +642,59 @@ bool AuthGPG::RevokeCertificate(const RsPgpId &id)
return false;
}
bool AuthGPG::TrustCertificate(const RsPgpId& id, int trustlvl)
bool AuthPGP::TrustCertificate(const RsPgpId& id, int trustlvl)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPG::TrustCertificate(" << id << ", " << trustlvl << ")" << std::endl;
#endif
return privateTrustCertificate(id, trustlvl) ;
return instance()->privateTrustCertificate(id, trustlvl) ;
}
bool AuthGPG::encryptDataBin(const RsPgpId& pgp_id,const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
bool AuthPGP::encryptDataBin(const RsPgpId& pgp_id,const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
{
return PGPHandler::encryptDataBin(RsPgpId(pgp_id),data,datalen,sign,signlen) ;
return instance()->mPgpHandler->encryptDataBin(RsPgpId(pgp_id),data,datalen,sign,signlen) ;
}
bool AuthGPG::decryptDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
bool AuthPGP::decryptDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen)
{
return PGPHandler::decryptDataBin(mOwnGpgId,data,datalen,sign,signlen) ;
return instance()->mPgpHandler->decryptDataBin(instance()->mOwnGpgId,data,datalen,sign,signlen) ;
}
bool AuthGPG::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen, std::string reason /*= ""*/)
bool AuthPGP::SignDataBin(const void *data, unsigned int datalen, unsigned char *sign, unsigned int *signlen, std::string reason /*= ""*/)
{
return DoOwnSignature(data, datalen, sign, signlen, reason);
return instance()->DoOwnSignature(data, datalen, sign, signlen, reason);
}
bool AuthGPG::VerifySignBin(const void *data, uint32_t datalen, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint)
bool AuthPGP::exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures )
{
return VerifySignature(data, datalen, sign, signlen, withfingerprint);
return instance()->mPgpHandler->exportPublicKey(id,mem_block,mem_size,armoured,include_signatures);
}
bool AuthPGP::isPgpPubKeyAvailable(const RsPgpId& pgp_id)
{
return instance()->mPgpHandler->isPgpPubKeyAvailable(pgp_id);
}
bool AuthPGP::getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp)
{
return instance()->mPgpHandler->getKeyFingerprint(id,fp);
}
bool AuthPGP::VerifySignBin(const void *data, uint32_t datalen, unsigned char *sign, unsigned int signlen, const PGPFingerprintType& withfingerprint)
{
return instance()->VerifySignature(data, datalen, sign, signlen, withfingerprint);
}
/* Sign/Trust stuff */
int AuthGPG::privateSignCertificate(const RsPgpId &id)
int AuthPGP::privateSignCertificate(const RsPgpId &id)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
int ret = PGPHandler::privateSignCertificate(mOwnGpgId,id) ;
int ret = mPgpHandler->privateSignCertificate(mOwnGpgId,id) ;
_force_sync_database = true ;
return ret ;
}
/* revoke the signature on Certificate */
int AuthGPG::privateRevokeCertificate(const RsPgpId &/*id*/)
int AuthPGP::privateRevokeCertificate(const RsPgpId &/*id*/)
{
//RsStackMutex stack(gpgMtx); /******* LOCKED ******/
std::cerr << __PRETTY_FUNCTION__ << ": not implemented!" << std::endl;
@ -664,7 +702,7 @@ int AuthGPG::privateRevokeCertificate(const RsPgpId &/*id*/)
return 0;
}
int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
int AuthPGP::privateTrustCertificate(const RsPgpId& id, int trustlvl)
{
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
@ -672,10 +710,10 @@ int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
// The trust level is only a user-defined property that has nothing to
// do with the fact that we allow connections or not.
if(!isGPGAccepted(id))
if(!isPGPAccepted(id))
return 0;
int res = PGPHandler::privateTrustCertificate(id,trustlvl) ;
int res = instance()->mPgpHandler->privateTrustCertificate(id,trustlvl) ;
_force_sync_database = true ;
return res ;
}
@ -684,20 +722,24 @@ int AuthGPG::privateTrustCertificate(const RsPgpId& id, int trustlvl)
// -------------------------------- Config functions ------------------------------ //
// -----------------------------------------------------------------------------------//
//
RsSerialiser *AuthGPG::setupSerialiser()
RsSerialiser *AuthPGP::setupSerialiser()
{
RsSerialiser *rss = new RsSerialiser ;
rss->addSerialType(new RsGeneralConfigSerialiser());
return rss ;
}
bool AuthPGP::isPGPAccepted(const RsPgpId& id)
{
return instance()->mPgpHandler->isGPGAccepted(id);
}
bool AuthGPG::saveList(bool& cleanup, std::list<RsItem*>& lst)
bool AuthPGP::saveList(bool& cleanup, std::list<RsItem*>& lst)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPG::saveList() called" << std::endl ;
#endif
std::list<RsPgpId> ids ;
getGPGAcceptedList(ids) ; // needs to be done before the lock
getPgpAcceptedList(ids) ; // needs to be done before the lock
RsStackMutex stack(gpgMtxData); /******* LOCKED ******/
@ -722,7 +764,7 @@ bool AuthGPG::saveList(bool& cleanup, std::list<RsItem*>& lst)
return true;
}
bool AuthGPG::loadList(std::list<RsItem*>& load)
bool AuthPGP::loadList(std::list<RsItem*>& load)
{
#ifdef GPG_DEBUG
std::cerr << "AuthGPG::loadList() Item Count: " << load.size() << std::endl;
@ -745,7 +787,7 @@ bool AuthGPG::loadList(std::list<RsItem*>& load)
std::list<RsTlvKeyValue>::iterator kit;
for(kit = vitem->tlvkvs.pairs.begin(); kit != vitem->tlvkvs.pairs.end(); ++kit)
if (kit->key != mOwnGpgId.toStdString())
PGPHandler::setAcceptConnexion(RsPgpId(kit->key), (kit->value == "TRUE"));
instance()->mPgpHandler->setAcceptConnexion(RsPgpId(kit->key), (kit->value == "TRUE"));
}
delete (*it);
}
@ -753,16 +795,16 @@ bool AuthGPG::loadList(std::list<RsItem*>& load)
return true;
}
bool AuthGPG::addService(AuthGPGService *service)
bool AuthPGP::addService(AuthGPGService *service)
{
RsStackMutex stack(gpgMtxService); /********* LOCKED *********/
RsStackMutex stack(instance()->gpgMtxService); /********* LOCKED *********/
if (std::find(services.begin(), services.end(), service) != services.end()) {
if (std::find(instance()->services.begin(), instance()->services.end(), service) != instance()->services.end()) {
/* it exists already! */
return false;
}
services.push_back(service);
instance()->services.push_back(service);
return true;
}

View File

@ -34,7 +34,7 @@
#include "util/rsthreads.h"
#include "pqi/p3cfgmgr.h"
#include "pgp/pgphandler.h"
#include "pgp/openpgpsdkhandler.h"
#define MAX_GPG_SIGNATURE_SIZE 4096
@ -89,16 +89,19 @@ public:
virtual void setGPGOperation(AuthGPGOperation *operation) = 0;
};
class AuthGPG: public p3Config, public RsTickingThread, public PGPHandler
class AuthPGP: public p3Config, public RsTickingThread
{
public:
static void init(const std::string& path_to_pubring,
const std::string& path_to_secring,
const std::string& path_to_trustdb,
const std::string& pgp_lock_file);
static void init(const std::string& path_to_pubring,
const std::string& path_to_secring,
const std::string& path_to_trustdb,
const std::string& pgp_lock_file);
static void exit();
static AuthGPG *getAuthGPG() { return _instance ; }
static void registerToConfigMgr(const std::string& fname,p3ConfigMgr *CfgMgr);
static void exit();
static bool isPGPId(const RsPgpId& id) ;
static bool isPGPAccepted(const RsPgpId& id) ;
/**
* @param ids list of gpg certificate ids (note, not the actual certificates)
@ -118,7 +121,7 @@ public:
* (see storage at the end of the class)
*
****/
virtual bool active();
static bool active();
// /* Initialize */
// virtual bool InitAuth ();
@ -126,10 +129,13 @@ public:
/* Init by generating new Own PGP Cert, or selecting existing PGP Cert */
virtual int GPGInit(const RsPgpId &ownId);
virtual bool GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString);
static int PgpInit(const RsPgpId &ownId);
static bool GeneratePgpCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString);
/*********************************************************************************/
static bool getPgpDetailsFromBinaryBlock(const unsigned char *mem,size_t mem_size,RsPgpId& key_id, std::string& name, std::list<RsPgpId>& signers) ;
static int availablePgpCertificatesWithPrivateKeys(std::list<RsPgpId>& pgpIds);
/*********************************************************************************/
/************************* STAGE 3 ***********************************************/
/*********************************************************************************/
/*****
@ -140,29 +146,33 @@ public:
* provide access to details in cache list.
*
****/
virtual std::string getGPGName(const RsPgpId &pgp_id,bool *success = NULL);
virtual std::string getGPGEmail(const RsPgpId &pgp_id,bool *success = NULL);
static std::string getPgpName(const RsPgpId &pgp_id,bool *success = NULL);
static std::string getPgpEmail(const RsPgpId &pgp_id,bool *success = NULL);
/* PGP web of trust management */
virtual const RsPgpId& getGPGOwnId();
virtual std::string getGPGOwnName();
static bool exportPublicKey( const RsPgpId& id, unsigned char*& mem_block, size_t& mem_size, bool armoured, bool include_signatures );
//virtual std::string getGPGOwnEmail();
virtual bool isKeySupported(const RsPgpId &id) const ;
virtual bool haveSecretKey(const RsPgpId &id) const ;
virtual bool getGPGDetails(const RsPgpId& id, RsPeerDetails &d);
virtual bool getGPGAllList(std::list<RsPgpId> &ids);
virtual bool getGPGValidList(std::list<RsPgpId> &ids);
virtual bool getGPGAcceptedList(std::list<RsPgpId> &ids);
virtual bool getGPGSignedList(std::list<RsPgpId> &ids);
virtual bool importProfile(const std::string& filename,RsPgpId& gpg_id,std::string& import_error) ;
virtual bool importProfileFromString(const std::string& data,RsPgpId& gpg_id,std::string& import_error) ;
virtual bool exportProfile(const std::string& filename,const RsPgpId& gpg_id) ;
virtual bool exportIdentityToString(
/* PGP web of trust management */
static const RsPgpId& getPgpOwnId();
static std::string getPgpOwnName();
//virtual std::string getGPGOwnEmail();
static bool getKeyFingerprint(const RsPgpId& id,PGPFingerprintType& fp) ;
static bool isKeySupported(const RsPgpId &id) ;
static bool isPgpPubKeyAvailable(const RsPgpId& pgp_id);
static bool haveSecretKey(const RsPgpId &id) ;
static bool getPgpDetails(const RsPgpId& id, RsPeerDetails &d);
static bool getPgpAllList(std::list<RsPgpId> &ids);
static bool getPgpValidList(std::list<RsPgpId> &ids);
static bool getPgpAcceptedList(std::list<RsPgpId> &ids);
static bool getPgpSignedList(std::list<RsPgpId> &ids);
static bool importProfile(const std::string& filename,RsPgpId& gpg_id,std::string& import_error) ;
static bool importProfileFromString(const std::string& data,RsPgpId& gpg_id,std::string& import_error) ;
static bool exportProfile(const std::string& filename,const RsPgpId& gpg_id) ;
static bool exportIdentityToString(
std::string& data, const RsPgpId& pgpId, bool includeSignatures,
std::string& errorMsg );
virtual bool removeKeysFromPGPKeyring(const std::set<RsPgpId> &pgp_ids,std::string& backup_file,uint32_t& error_code) ;
static bool removeKeysFromPGPKeyring(const std::set<RsPgpId> &pgp_ids,std::string& backup_file,uint32_t& error_code) ;
/*********************************************************************************/
/************************* STAGE 4 ***********************************************/
@ -171,9 +181,9 @@ public:
* STAGE 4: Loading and Saving Certificates. (Strings and Files)
*
****/
virtual bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string);
virtual bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string);
virtual std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ;
static bool LoadCertificateFromString(const std::string &pem, RsPgpId& gpg_id,std::string& error_string);
static bool LoadPGPKeyFromBinaryData(const unsigned char *data,uint32_t data_len, RsPgpId& gpg_id,std::string& error_string);
static std::string SaveCertificateToString(const RsPgpId &id,bool include_signatures) ;
// Cached certificates.
//bool getCachedGPGCertificate(const RsPgpId &id, std::string &certificate);
@ -188,12 +198,12 @@ public:
* done in gpgroot already.
*
****/
virtual bool AllowConnection(const RsPgpId &gpg_id, bool accept);
static bool AllowConnection(const RsPgpId &gpg_id, bool accept);
virtual bool SignCertificateLevel0(const RsPgpId &id);
virtual bool RevokeCertificate(const RsPgpId &id); /* Particularly hard - leave for later */
static bool SignCertificateLevel0(const RsPgpId &id);
static bool RevokeCertificate(const RsPgpId &id); /* Particularly hard - leave for later */
virtual bool TrustCertificate(const RsPgpId& id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust
static bool TrustCertificate(const RsPgpId& id, int trustlvl); //trustlvl is 2 for none, 3 for marginal and 4 for full trust
/*********************************************************************************/
/************************* STAGE 7 ***********************************************/
@ -204,39 +214,39 @@ public:
* There should also be Encryption Functions... (do later).
*
****/
virtual bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "");
virtual bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const PGPFingerprintType& withfingerprint);
virtual bool parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id);
static bool SignDataBin(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason = "");
static bool VerifySignBin(const void*, uint32_t, unsigned char*, unsigned int, const PGPFingerprintType& withfingerprint);
static bool parseSignature(const void *sig, unsigned int siglen, RsPgpId& issuer_id);
virtual bool encryptDataBin(const RsPgpId& pgp_id,const void *data, const uint32_t len, unsigned char *encr, unsigned int *encrlen);
virtual bool decryptDataBin(const void *data, const uint32_t len, unsigned char *decr, unsigned int *decrlen);
static bool encryptDataBin(const RsPgpId& pgp_id,const void *data, const uint32_t len, unsigned char *encr, unsigned int *encrlen);
static bool decryptDataBin(const void *data, const uint32_t len, unsigned char *decr, unsigned int *decrlen);
virtual bool decryptTextFromFile( std::string& text,const std::string& filename);
virtual bool encryptTextToFile (const std::string& text,const std::string& filename);
static bool decryptTextFromFile( std::string& text,const std::string& filename);
static bool encryptTextToFile (const std::string& text,const std::string& filename);
// virtual bool decryptTextFromString( std::string& encrypted_text,std::string& clear_string);
// virtual bool encryptTextToString (const std::string& pgp_id,const std::string& clear_text,std::string& encrypted_string);
bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ;
static bool getGPGFilteredList(std::list<RsPgpId>& list,bool (*filter)(const PGPCertificateInfo&) = NULL) ;
//END of PGP public functions
/* GPG service */
virtual bool addService(AuthGPGService *service) ;
static bool addService(AuthGPGService *service) ;
// This is for debug purpose only. Don't use it !!
static void setAuthGPG_debug(AuthGPG *auth_gpg) { _instance = auth_gpg ; }
static void setAuthGPG_debug(AuthPGP *auth_gpg) { _instance = auth_gpg ; }
protected:
AuthGPG(const std::string& path_to_pubring, const std::string& path_to_secring,const std::string& path_to_trustdb,const std::string& pgp_lock_file);
virtual ~AuthGPG();
AuthPGP(const std::string& path_to_pubring, const std::string& path_to_secring,const std::string& path_to_trustdb,const std::string& pgp_lock_file);
virtual ~AuthPGP();
/*****************************************************************/
/*********************** p3config ******************************/
/* Key Functions to be overloaded for Full Configuration */
virtual RsSerialiser *setupSerialiser();
virtual bool saveList(bool &cleanup, std::list<RsItem *>&);
virtual bool loadList(std::list<RsItem *>& load);
virtual RsSerialiser *setupSerialiser() override;
virtual bool saveList(bool &cleanup, std::list<RsItem *>&) override;
virtual bool loadList(std::list<RsItem *>& load) override;
/*****************************************************************/
private:
@ -274,8 +284,7 @@ private:
void threadTick() override; /// @see RsTickingThread
private:
static AuthGPG *instance_gpg; // pointeur vers le singleton
static AuthPGP *instance();
RsMutex gpgMtxService;
RsMutex gpgMtxEngine;
@ -290,6 +299,8 @@ private:
rstime_t mStoreKeyTime;
PGPHandler *mPgpHandler;
RsPgpId mOwnGpgId;
bool gpgKeySelected;
bool _force_sync_database ;
@ -297,7 +308,7 @@ private:
std::list<AuthGPGService*> services ;
static AuthGPG *_instance ;
static AuthPGP *_instance ;
};
#endif

View File

@ -759,8 +759,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
//long version = 0x00;
unsigned long chtype = MBSTRING_UTF8;
X509_NAME *issuer_name = X509_NAME_new();
X509_NAME_add_entry_by_txt(issuer_name, "CN", chtype,
(unsigned char *) AuthGPG::getAuthGPG()->getGPGOwnId().toStdString().c_str(), -1, -1, 0);
X509_NAME_add_entry_by_txt(issuer_name, "CN", chtype, (unsigned char *) AuthPGP::getPgpOwnId().toStdString().c_str(), -1, -1, 0);
/****
X509_NAME_add_entry_by_NID(issuer_name, 48, 0,
(unsigned char *) "email@email.com", -1, -1, 0);
@ -770,7 +769,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
(unsigned char *) "loc", -1, -1, 0);
****/
std::cerr << "AuthSSLimpl::SignX509Req() Issuer name: " << AuthGPG::getAuthGPG()->getGPGOwnId().toStdString() << std::endl;
std::cerr << "AuthSSLimpl::SignX509Req() Issuer name: " << AuthPGP::getPgpOwnId().toStdString() << std::endl;
#ifdef V07_NON_BACKWARD_COMPATIBLE_CHANGE_002
static const uint64_t CERTIFICATE_SERIAL_NUMBER = RS_CERTIFICATE_VERSION_NUMBER_07_0001 ;
@ -945,7 +944,7 @@ X509 *AuthSSLimpl::SignX509ReqWithGPG(X509_REQ *req, long /*days*/)
std::cerr << "Buffers Allocated" << std::endl;
/* NOW Sign via GPG Functions */
if (!AuthGPG::getAuthGPG()->SignDataBin(buf_in, inl, buf_sigout, (unsigned int *) &sigoutl,"AuthSSLimpl::SignX509ReqWithGPG()"))
if (!AuthPGP::SignDataBin(buf_in, inl, buf_sigout, (unsigned int *) &sigoutl,"AuthSSLimpl::SignX509ReqWithGPG()"))
{
sigoutl = 0;
goto err;
@ -1040,7 +1039,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic)
{
RsPgpId issuer = RsX509Cert::getCertIssuer(*x509);
RsPeerDetails pd;
if (!AuthGPG::getAuthGPG()->getGPGDetails(issuer, pd))
if (!AuthPGP::getPgpDetails(issuer, pd))
{
RsInfo() << __PRETTY_FUNCTION__ << " X509 NOT authenticated : "
<< "AuthGPG::getAuthGPG()->getGPGDetails(" << issuer
@ -1185,9 +1184,7 @@ bool AuthSSLimpl::AuthX509WithGPG(X509 *x509,bool verbose, uint32_t& diagnostic)
// passed, verify the signature itself
if (!AuthGPG::getAuthGPG()->VerifySignBin(
signed_data, signed_data_length, signature->data,
static_cast<unsigned int>(signature->length), pd.fpr ))
if (!AuthPGP::VerifySignBin( signed_data, signed_data_length, signature->data, static_cast<unsigned int>(signature->length), pd.fpr ))
{
diagnostic = RS_SSL_HANDSHAKE_DIAGNOSTIC_WRONG_SIGNATURE;
goto err;
@ -1383,7 +1380,7 @@ int AuthSSLimpl::VerifyX509Callback(int /*preverify_ok*/, X509_STORE_CTX* ctx)
std::cerr << "******* VerifyX509Callback cert: " << std::hex << ctx->cert <<std::dec << std::endl;
#endif
if ( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() && !AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
if ( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
{
std::string errMsg = "Connection attempt signed by PGP key id: " +
pgpId.toStdString() + " not accepted because it is not"

View File

@ -812,11 +812,11 @@ int p3PeerMgrIMPL::getFriendCount(bool ssl, bool online)
// count all gpg id's
std::list<RsPgpId> gpgIds;
AuthGPG::getAuthGPG()->getGPGAcceptedList(gpgIds);
AuthPGP::getPgpAcceptedList(gpgIds);
// add own gpg id, if we have more than one location
std::list<RsPeerId> ownSslIds;
getAssociatedPeers(AuthGPG::getAuthGPG()->getGPGOwnId(), ownSslIds);
getAssociatedPeers(AuthPGP::getPgpOwnId(), ownSslIds);
return gpgIds.size() + ((ownSslIds.size() > 0) ? 1 : 0);
}
@ -962,7 +962,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
// check that the PGP key is known
if(!AuthGPG::getAuthGPG()->isGPGId(gpg_id))
if(!AuthPGP::isPGPId(gpg_id))
{
RsErr() << "Trying to add SSL id (" << id << ") to be validated with unknown PGP key (" << gpg_id << ". This is a bug!" << std::endl;
return false;
@ -970,7 +970,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
//Authentication is now tested at connection time, we don't store the ssl cert anymore
//
if (!AuthGPG::getAuthGPG()->isGPGAccepted(gpg_id) && gpg_id != AuthGPG::getAuthGPG()->getGPGOwnId())
if (!AuthPGP::isPGPAccepted(gpg_id) && gpg_id != AuthPGP::getPgpOwnId())
{
#ifdef PEER_DEBUG
std::cerr << "p3PeerMgrIMPL::addFriend() gpg is not accepted" << std::endl;
@ -1024,7 +1024,7 @@ bool p3PeerMgrIMPL::addFriend(const RsPeerId& input_id, const RsPgpId& input_gpg
pstate.id = id;
pstate.gpg_id = gpg_id;
pstate.name = AuthGPG::getAuthGPG()->getGPGName(gpg_id);
pstate.name = AuthPGP::getPgpName(gpg_id);
pstate.vs_disc = vs_disc;
pstate.vs_dht = vs_dht;
@ -1126,8 +1126,8 @@ bool p3PeerMgrIMPL::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_
* superficially set to true the PGP signature verification would have been
* skipped and the attacker connection would be accepted.
* If the PGP key is available add it as full friend. */
if(AuthGPG::getAuthGPG()->isPgpPubKeyAvailable(pgp_id))
AuthGPG::getAuthGPG()->AllowConnection(pgp_id, true);
if(AuthPGP::isPgpPubKeyAvailable(pgp_id))
AuthPGP::AllowConnection(pgp_id, true);
else
pstate.skip_pgp_signature_validation = true;
@ -1398,11 +1398,11 @@ bool p3PeerMgrIMPL::UpdateOwnAddress( const sockaddr_storage& pLocalAddr,
sockaddr_storage_copy(pExtAddr, extAddr);
sockaddr_storage_ipv6_to_ipv4(extAddr);
//#ifdef PEER_DEBUG
#ifdef PEER_DEBUG
std::cerr << "p3PeerMgrIMPL::UpdateOwnAddress("
<< sockaddr_storage_tostring(localAddr) << ", "
<< sockaddr_storage_tostring(extAddr) << ")" << std::endl;
//#endif
#endif
if( rsBanList &&
!rsBanList->isAddressAccepted(localAddr,
@ -2470,7 +2470,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
setOwnNetworkMode(pitem->netMode);
setOwnVisState(pitem->vs_disc, pitem->vs_dht);
mOwnState.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId();
mOwnState.gpg_id = AuthPGP::getPgpOwnId();
mOwnState.location = AuthSSL::getAuthSSL()->getOwnLocation();
}
else
@ -2642,7 +2642,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
#endif
for(uint32_t i=0;i<sitem->pgp_ids.size();++i)
if(AuthGPG::getAuthGPG()->isGPGAccepted(sitem->pgp_ids[i]) || sitem->pgp_ids[i] == AuthGPG::getAuthGPG()->getGPGOwnId())
if(AuthPGP::isPGPAccepted(sitem->pgp_ids[i]) || sitem->pgp_ids[i] == AuthPGP::getPgpOwnId())
{
mFriendsPermissionFlags[sitem->pgp_ids[i]] = sitem->service_flags[i] ;
#ifdef PEER_DEBUG
@ -2684,7 +2684,7 @@ bool p3PeerMgrIMPL::loadList(std::list<RsItem *>& load)
for(auto group_pair:groupList)
{
for(auto profileIdIt(group_pair.second.peerIds.begin());profileIdIt!=group_pair.second.peerIds.end();)
if(AuthGPG::getAuthGPG()->isGPGAccepted(*profileIdIt) || *profileIdIt == AuthGPG::getAuthGPG()->getGPGOwnId())
if(AuthPGP::isPGPAccepted(*profileIdIt) || *profileIdIt == AuthPGP::getPgpOwnId())
++profileIdIt;
else
{

View File

@ -46,9 +46,13 @@ void RsFdBinInterface::setSocket(int s)
int flags = fcntl(s,F_GETFL);
if(!(flags & O_NONBLOCK))
throw std::runtime_error("Trying to use a blocking file descriptor in RsFdBinInterface. This is not going to work!");
{
RsWarn() << "Trying to use a blocking file descriptor in RsFdBinInterface. This is not going to work! Setting the socket to be non blocking.";
unix_fcntl_nonblock(s);
}
#else
// On windows, there is no way to determine whether a socket is blobking or not, so we set it to non blocking whatsoever.
// On windows, there is no way to determine whether a socket is blocking or not, so we set it to non blocking whatsoever.
unsigned long int on = 1;
ioctlsocket(s, FIONBIO, &on);
#endif

View File

@ -21,15 +21,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifdef WINDOWS_SYS
# include "util/rswin.h"
# include "util/rsmemory.h"
# include <ws2tcpip.h>
#endif // WINDOWS_SYS
#ifdef __ANDROID__
# include <android/api-level.h>
#endif // def __ANDROID__
#include <cerrno>
#include <iostream>
@ -43,6 +34,28 @@
#include "util/rsnet.h"
#include "util/stacktrace.h"
#ifdef WINDOWS_SYS
# include "util/rswin.h"
# include "util/rsmemory.h"
# include <ws2tcpip.h>
#endif // WINDOWS_SYS
/// @See: android_ifaddrs/README.adoc
#ifdef __ANDROID__
# include <android/api-level.h>
#endif // def __ANDROID__
#ifdef WINDOWS_SYS /* Windows - define errno */
int errno;
#else /* Windows - define errno */
#include <netdb.h>
#endif
#ifdef __HAIKU__
# include <sys/sockio.h>
# define IFF_RUNNING 0x0001
#endif
static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"};
#define pqinetzone &pqinetzoneInfo
@ -50,21 +63,6 @@ static struct RsLog::logInfo pqinetzoneInfo = {RsLog::Default, "pqinet"};
* #define NET_DEBUG 1
****/
#ifdef WINDOWS_SYS /* Windows - define errno */
int errno;
#else /* Windows - define errno */
#include <netdb.h>
#endif
#ifdef __HAIKU__
#include <sys/sockio.h>
#define IFF_RUNNING 0x0001
#endif
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
@ -270,18 +268,16 @@ int inet_aton(const char *name, struct in_addr *addr)
#endif
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
#include "util/cxx17retrocompat.h"
#include <sys/types.h>
#ifdef WINDOWS_SYS
# include <winsock2.h>
# include <iphlpapi.h>
# pragma comment(lib, "IPHLPAPI.lib")
#elif defined(__ANDROID__) && __ANDROID_API__ < 24
# include <string>
# include <QString>
# include <QHostAddress>
# include <QNetworkInterface>
#else // not __ANDROID__ nor WINDOWS => Linux and other unixes
/// @See: android_ifaddrs/README.adoc
# include "rs_android/ifaddrs-android.h"
#else // not WINDOWS => Linux and other unixes
# include <ifaddrs.h>
# include <net/if.h>
#endif // WINDOWS_SYS
@ -324,20 +320,12 @@ bool getLocalAddresses(std::vector<sockaddr_storage>& addrs)
}
}
free(adapter_addresses);
#elif defined(__ANDROID__) && __ANDROID_API__ < 24
for(auto& qAddr: QNetworkInterface::allAddresses())
{
sockaddr_storage tmpAddr;
sockaddr_storage_clear(tmpAddr);
if(sockaddr_storage_ipv4_aton(tmpAddr, qAddr.toString().toStdString().c_str()))
addrs.push_back(tmpAddr);
}
#else // not WINDOWS_SYS not ANDROID => Linux and other unixes
#else // not WINDOWS_SYS => Linux and other unixes
struct ifaddrs *ifsaddrs, *ifa;
if(getifaddrs(&ifsaddrs) != 0)
{
std::cerr << __PRETTY_FUNCTION__ << " FATAL ERROR: " << errno << " "
<< strerror(errno) << std::endl;
RS_ERR( "getifaddrs failed with: ", errno, " ",
rs_errno_to_condition(errno) );
print_stacktrace();
return false;
}
@ -346,18 +334,19 @@ bool getLocalAddresses(std::vector<sockaddr_storage>& addrs)
{
sockaddr_storage tmp;
sockaddr_storage_clear(tmp);
if (sockaddr_storage_copyip(tmp, *reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr)))
if(sockaddr_storage_copyip(
tmp,
*reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr) ))
addrs.push_back(tmp);
}
freeifaddrs(ifsaddrs);
#endif // WINDOWS_SYS
#ifdef NET_DEBUG
std::list<sockaddr_storage>::iterator it;
std::cout << "getLocalAddresses(...) returning: <" ;
for(it = addrs.begin(); it != addrs.end(); ++it)
std::cout << sockaddr_storage_iptostring(*it) << ", ";
std::cout << ">" << std::endl;
auto&& dbg = RS_DBG("returning: [");
for(auto& addr: std::as_const(addrs))
dbg << sockaddr_storage_iptostring(addr) << ", ";
dbg << "]" << std::endl;
#endif
return !addrs.empty();

View File

@ -4,7 +4,8 @@
* libretroshare: retroshare core library *
* *
* Copyright (C) 2004-2006 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2015-2018 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2015-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -20,8 +21,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef MRK_PQI_NETWORKING_HEADER
#define MRK_PQI_NETWORKING_HEADER
#pragma once
#include <vector>
@ -86,9 +86,13 @@ extern int errno; /* Define extern errno, to duplicate unix behaviour */
#include <string>
#include <list>
#include "util/rsdeprecate.h"
// Same def - different functions...
RS_DEPRECATED_FOR("use std::error_condition instead")
void showSocketError(std::string &out);
RS_DEPRECATED_FOR("use std::error_condition instead")
std::string socket_errorType(int err);
bool getLocalAddresses(std::vector<sockaddr_storage> & addrs);
@ -103,10 +107,6 @@ int unix_getsockopt_error(int sockfd, int *err);
#ifdef WINDOWS_SYS // WINDOWS
/******************* WINDOWS SPECIFIC PART ******************/
RS_DEPRECATED_FOR("use std::error_condition instead")
int WinToUnixError(int error);
#endif
#endif

View File

@ -1213,8 +1213,7 @@ int pqissl::Authorise_SSL_Connection()
}
RsPgpId pgpId = RsX509Cert::getCertIssuer(*peercert);
if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() &&
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
if( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
{
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
<< " is not friend. It is very unlikely to happen at this "

View File

@ -797,8 +797,7 @@ int pqissllistener::completeConnection(int fd, IncomingSSLInfo& info)
exit(failure);
}
if( !isSslOnlyFriend && pgpId != AuthGPG::getAuthGPG()->getGPGOwnId() &&
!AuthGPG::getAuthGPG()->isGPGAccepted(pgpId) )
if( !isSslOnlyFriend && pgpId != AuthPGP::getPgpOwnId() && !AuthPGP::isPGPAccepted(pgpId) )
{
RsFatal() << __PRETTY_FUNCTION__ << " pgpId: " << pgpId
<< " is not friend. It is very unlikely to happen at this "

View File

@ -450,6 +450,17 @@ public:
const std::string& matchString,
std::vector<RsGxsSearchResult>& searchResults ) = 0;
/**
* @brief Request Synchronization with available peers
* Usually syncronization already happen automatically so be carefull
* to call this method only if necessary.
* It has been thinked for use cases like mobile phone where internet
* connection is intermittent and calling this may be useful when a system
* event about connection being available or about to go offline is received
* @jsonapi{development}
* @return Success or error details
*/
virtual std::error_condition requestSynchronization() = 0;
////////////////////////////////////////////////////////////////////////////
/* Following functions are deprecated and should not be considered a stable

View File

@ -887,7 +887,7 @@ public:
// Certificate utils
virtual bool cleanCertificate(
const std::string& certstr, std::string& cleanCert,
bool& is_short_format, uint32_t& error_code ) = 0;
bool& is_short_format, uint32_t& error_code, RsPeerDetails& details) = 0;
virtual std::string saveCertificateToString(const RsPeerId &id) = 0;
virtual bool signGPGCertificate(const RsPgpId &gpg_id,const std::string& gpg_passphrase) = 0;

View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LOCAL_ARRAY_H_included
#define LOCAL_ARRAY_H_included
#include <cstddef>
#include <new>
/**
* A fixed-size array with a size hint. That number of bytes will be allocated
* on the stack, and used if possible, but if more bytes are requested at
* construction time, a buffer will be allocated on the heap (and deallocated
* by the destructor).
*
* The API is intended to be a compatible subset of C++0x's std::array.
*/
template <size_t STACK_BYTE_COUNT>
class LocalArray {
public:
/**
* Allocates a new fixed-size array of the given size. If this size is
* less than or equal to the template parameter STACK_BYTE_COUNT, an
* internal on-stack buffer will be used. Otherwise a heap buffer will
* be allocated.
*/
LocalArray(size_t desiredByteCount) : mSize(desiredByteCount) {
if (desiredByteCount > STACK_BYTE_COUNT) {
mPtr = new char[mSize];
} else {
mPtr = &mOnStackBuffer[0];
}
}
/**
* Frees the heap-allocated buffer, if there was one.
*/
~LocalArray() {
if (mPtr != &mOnStackBuffer[0]) {
delete[] mPtr;
}
}
// Capacity.
size_t size() { return mSize; }
bool empty() { return mSize == 0; }
// Element access.
char& operator[](size_t n) { return mPtr[n]; }
const char& operator[](size_t n) const { return mPtr[n]; }
private:
char mOnStackBuffer[STACK_BYTE_COUNT];
char* mPtr;
size_t mSize;
// Disallow copy and assignment.
LocalArray(const LocalArray&);
void operator=(const LocalArray&);
};
#endif // LOCAL_ARRAY_H_included

View File

@ -0,0 +1,49 @@
= README Android ifaddrs
Android API level < 24 doesn't provide `getifaddrs` and related functions, we
have tested multiple ways to overcome this issue.
== Non Weorking alternative implementations
https://github.com/kmackay/android-ifaddrs
https://github.com/morristech/android-ifaddrs
https://www.openhub.net/p/android-ifaddrs/
Compiles but then segfault at runtime.
== Qt implementation
Using `QNetworkInterface::allAddresses()` provided by Qt works but at time of
writing (Q4 2021) on newer Android the log is flooded by warnings as we reported
here
https://bugreports.qt.io/browse/QTBUG-78659
plus depending on Qt networking module just for this is frustrating.
Update: the warning flood seems have been fixed in later Qt versions
https://bugreports.qt.io/browse/QTBUG-86394
This solution was the first working we implemented in our code it has been
removed to avoid dependency on Qt, as lighter alternatives are possible.
== Code copied from Android Gingerbread release
As explained here
https://stackoverflow.com/a/57112520
even older Android have `getifaddrs` implementations but doesn't make them
accessible in the API, in particular the one included in Android Gingerbread
https://android.googlesource.com/platform/libcore/+/refs/heads/gingerbread-release/luni/src/main/native/ifaddrs-android.h
https://android.googlesource.com/platform/libcore/+/refs/heads/gingerbread-release/
is particularly easy to include in our code base and compile.
This solution seems the best fitting and doesn't introduce dependency on Qt.
Newer Android releases (expecially 11) have introduced multiple restrictions
on network information access so we suggest you to prepare different APK for
different API level in order to use the `getifaddrs` provided by Android NDK
which deal gracefully with those restrictions as soon as available.

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SCOPED_FD_H_included
#define SCOPED_FD_H_included
#include <unistd.h>
// A smart pointer that closes the given fd on going out of scope.
// Use this when the fd is incidental to the purpose of your function,
// but needs to be cleaned up on exit.
class ScopedFd {
public:
explicit ScopedFd(int fd) : fd(fd) {
}
~ScopedFd() {
close(fd);
}
int get() const {
return fd;
}
private:
int fd;
// Disallow copy and assignment.
ScopedFd(const ScopedFd&);
void operator=(const ScopedFd&);
};
#endif // SCOPED_FD_H_included

View File

@ -1,9 +1,9 @@
/*******************************************************************************
* libretroshare/src/util: androiddebug.h *
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2016 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -36,10 +36,10 @@
* class at the beginning of the main of your program to get them (stdout and
* stderr) on logcat output.
*/
class AndroidStdIOCatcher
class AndroidCoutCerrCatcher
{
public:
AndroidStdIOCatcher(const std::string& dTag = "RetroShare",
AndroidCoutCerrCatcher(const std::string& dTag = "RetroShare",
android_LogPriority stdout_pri = ANDROID_LOG_INFO,
android_LogPriority stderr_pri = ANDROID_LOG_ERROR) :
tag(dTag), cout_pri(stdout_pri), cerr_pri(stderr_pri), should_stop(false)
@ -63,10 +63,10 @@ public:
pthread_detach(thr);
}
~AndroidStdIOCatcher()
~AndroidCoutCerrCatcher()
{
should_stop = true;
pthread_join(thr, NULL);
pthread_join(thr, nullptr);
}
private:
@ -79,11 +79,13 @@ private:
pthread_t thr;
std::atomic<bool> should_stop;
static void *thread_func(void* instance)
static void* thread_func(void* instance)
{
__android_log_write(ANDROID_LOG_INFO, "RetroShare", "Android debugging start");
__android_log_write(
ANDROID_LOG_INFO, "RetroShare",
"Android standard I/O catcher start" );
AndroidStdIOCatcher &i = *static_cast<AndroidStdIOCatcher*>(instance);
AndroidCoutCerrCatcher &i = *static_cast<AndroidCoutCerrCatcher*>(instance);
std::string out_buf;
std::string err_buf;
@ -113,9 +115,11 @@ private:
usleep(10000);
}
__android_log_write(ANDROID_LOG_INFO, "RetroShare", "Android debugging stop");
__android_log_write(
ANDROID_LOG_INFO, "RetroShare",
"Android standard I/O catcher stop" );
return NULL;
return nullptr;
}
};

View File

@ -0,0 +1,42 @@
/*******************************************************************************
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "rs_android/rsjni.hpp"
namespace jni
{
Local<Object<RsJni::ErrorConditionWrap>> MakeAnything(
ThingToMake<RsJni::ErrorConditionWrap>, JNIEnv& env,
const std::error_condition& ec )
{
auto& clazz = jni::Class<RsJni::ErrorConditionWrap>::Singleton(env);
static auto method =
clazz.GetConstructor<jni::jint, jni::String, jni::String>(env);
jni::jint value = ec.value();
auto message = jni::Make<jni::String>(env, ec.message());
auto category = jni::Make<jni::String>(env, ec.category().name());
return clazz.New(env, method, value, message, category);
}
}

View File

@ -0,0 +1,228 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IFADDRS_ANDROID_H_included
#define IFADDRS_ANDROID_H_included
#include <arpa/inet.h>
#include <cstring>
#include <errno.h>
#include <net/if.h>
#include <netinet/in.h>
#include <new>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include "LocalArray.h"
#include "ScopedFd.h"
// Android (bionic) doesn't have getifaddrs(3)/freeifaddrs(3).
// We fake it here, so java_net_NetworkInterface.cpp can use that API
// with all the non-portable code being in this file.
// Source-compatible subset of the BSD struct.
struct ifaddrs {
// Pointer to next struct in list, or NULL at end.
ifaddrs* ifa_next;
// Interface name.
char* ifa_name;
// Interface flags.
unsigned int ifa_flags;
// Interface network address.
sockaddr* ifa_addr;
// Interface netmask.
sockaddr* ifa_netmask;
ifaddrs(ifaddrs* next)
: ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL), ifa_netmask(NULL)
{
}
~ifaddrs() {
delete ifa_next;
delete[] ifa_name;
delete ifa_addr;
delete ifa_netmask;
}
// Sadly, we can't keep the interface index for portability with BSD.
// We'll have to keep the name instead, and re-query the index when
// we need it later.
bool setNameAndFlagsByIndex(int interfaceIndex) {
// Get the name.
char buf[IFNAMSIZ];
char* name = if_indextoname(interfaceIndex, buf);
if (name == NULL) {
return false;
}
ifa_name = new char[strlen(name) + 1];
strcpy(ifa_name, name);
// Get the flags.
ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0));
if (fd.get() == -1) {
return false;
}
ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, name);
int rc = ioctl(fd.get(), SIOCGIFFLAGS, &ifr);
if (rc == -1) {
return false;
}
ifa_flags = ifr.ifr_flags;
return true;
}
// Netlink gives us the address family in the header, and the
// sockaddr_in or sockaddr_in6 bytes as the payload. We need to
// stitch the two bits together into the sockaddr that's part of
// our portable interface.
void setAddress(int family, void* data, size_t byteCount) {
// Set the address proper...
sockaddr_storage* ss = new sockaddr_storage;
memset(ss, 0, sizeof(*ss));
ifa_addr = reinterpret_cast<sockaddr*>(ss);
ss->ss_family = family;
uint8_t* dst = sockaddrBytes(family, ss);
memcpy(dst, data, byteCount);
}
// Netlink gives us the prefix length as a bit count. We need to turn
// that into a BSD-compatible netmask represented by a sockaddr*.
void setNetmask(int family, size_t prefixLength) {
// ...and work out the netmask from the prefix length.
sockaddr_storage* ss = new sockaddr_storage;
memset(ss, 0, sizeof(*ss));
ifa_netmask = reinterpret_cast<sockaddr*>(ss);
ss->ss_family = family;
uint8_t* dst = sockaddrBytes(family, ss);
memset(dst, 0xff, prefixLength / 8);
if ((prefixLength % 8) != 0) {
dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8)));
}
}
// Returns a pointer to the first byte in the address data (which is
// stored in network byte order).
uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) {
if (family == AF_INET) {
sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss);
return reinterpret_cast<uint8_t*>(&ss4->sin_addr);
} else if (family == AF_INET6) {
sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss);
return reinterpret_cast<uint8_t*>(&ss6->sin6_addr);
}
return NULL;
}
private:
// Disallow copy and assignment.
ifaddrs(const ifaddrs&);
void operator=(const ifaddrs&);
};
// FIXME: use iovec instead.
struct addrReq_struct {
nlmsghdr netlinkHeader;
ifaddrmsg msg;
};
inline bool sendNetlinkMessage(int fd, const void* data, size_t byteCount) {
ssize_t sentByteCount = TEMP_FAILURE_RETRY(send(fd, data, byteCount, 0));
return (sentByteCount == static_cast<ssize_t>(byteCount));
}
inline ssize_t recvNetlinkMessage(int fd, char* buf, size_t byteCount) {
return TEMP_FAILURE_RETRY(recv(fd, buf, byteCount, 0));
}
// Source-compatible with the BSD function.
inline int getifaddrs(ifaddrs** result) {
// Simplify cleanup for callers.
*result = NULL;
// Create a netlink socket.
ScopedFd fd(socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE));
if (fd.get() < 0) {
return -1;
}
// Ask for the address information.
addrReq_struct addrRequest;
memset(&addrRequest, 0, sizeof(addrRequest));
addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_MATCH;
addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;
addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));
addrRequest.msg.ifa_family = AF_UNSPEC; // All families.
addrRequest.msg.ifa_index = 0; // All interfaces.
if (!sendNetlinkMessage(fd.get(), &addrRequest, addrRequest.netlinkHeader.nlmsg_len)) {
return -1;
}
// Read the responses.
LocalArray<0> buf(65536); // We don't necessarily have std::vector.
ssize_t bytesRead;
while ((bytesRead = recvNetlinkMessage(fd.get(), &buf[0], buf.size())) > 0) {
nlmsghdr* hdr = reinterpret_cast<nlmsghdr*>(&buf[0]);
for (; NLMSG_OK(hdr, (size_t)bytesRead); hdr = NLMSG_NEXT(hdr, bytesRead)) {
switch (hdr->nlmsg_type) {
case NLMSG_DONE:
return 0;
case NLMSG_ERROR:
return -1;
case RTM_NEWADDR:
{
ifaddrmsg* address = reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(hdr));
rtattr* rta = IFA_RTA(address);
size_t ifaPayloadLength = IFA_PAYLOAD(hdr);
while (RTA_OK(rta, ifaPayloadLength)) {
if (rta->rta_type == IFA_LOCAL) {
int family = address->ifa_family;
if (family == AF_INET || family == AF_INET6) {
*result = new ifaddrs(*result);
if (!(*result)->setNameAndFlagsByIndex(address->ifa_index)) {
return -1;
}
(*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta));
(*result)->setNetmask(family, address->ifa_prefixlen);
}
}
rta = RTA_NEXT(rta, ifaPayloadLength);
}
}
break;
}
}
}
// We only get here if recv fails before we see a NLMSG_DONE.
return -1;
}
// Source-compatible with the BSD function.
inline void freeifaddrs(ifaddrs* addresses) {
delete addresses;
}
#endif // IFADDRS_ANDROID_H_included

View File

@ -0,0 +1,98 @@
/*
* RetroShare
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
*
* 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/>.
*
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package org.retroshare.service;
import android.util.Log;
import android.content.Context;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
public class AssetHelper
{
public static boolean copyAsset(
Context ctx, String assetPath, String destinationFilePath )
{
Log.d(TAG, "copyAsset " + assetPath + " -> " + destinationFilePath);
InputStream in;
OutputStream out;
try { in = ctx.getAssets().open(assetPath); }
catch(Exception e)
{
Log.e(
TAG,
"Failure opening asset: " + assetPath + " " + e.getMessage() );
return false;
}
try { out = new FileOutputStream(destinationFilePath); }
catch(Exception e)
{
Log.e(
TAG,
"Failure opening destination: " + destinationFilePath + " " +
e.getMessage() );
return false;
}
try
{
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) out.write(buf, 0, len);
}
catch(IOException e)
{
Log.e(
TAG,
"Failure coping: " + assetPath + " -> " + destinationFilePath +
" " + e.getMessage() );
return false;
}
try { in.close(); }
catch(IOException e)
{
Log.e(TAG, "Failure closing: " + assetPath + " " + e.getMessage() );
return false;
}
try { out.close(); }
catch(IOException e)
{
Log.e(
TAG,
"Failure closing: " + destinationFilePath + " " +
e.getMessage() );
return false;
}
return true;
}
private static final String TAG = "RetroShare AssetHelper.java";
}

View File

@ -0,0 +1,48 @@
/*
* RetroShare
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
*
* 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/>.
*
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package org.retroshare.service;
public class ErrorConditionWrap
{
public ErrorConditionWrap(
int value, String message, String categoryName )
{
mValue = value;
mMessage = message;
mCategoryName = categoryName;
}
public int value() { return mValue; }
public String message() { return mMessage; }
public String categoryName() { return mCategoryName; }
public boolean toBool() { return mValue != 0; }
@Override
public String toString()
{ return String.format("%d", mValue)+" "+mMessage+" [" + mCategoryName+ "]"; }
private int mValue = 0;
private String mMessage;
private String mCategoryName;
}

View File

@ -0,0 +1,141 @@
/*
* RetroShare
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org>
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
*
* 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/>.
*
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package org.retroshare.service;
import android.app.Service;
import android.os.IBinder;
import android.os.Bundle;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.app.ActivityManager;
public class RetroShareServiceAndroid extends Service
{
public static final int DEFAULT_JSON_API_PORT = 9092;
public static final String DEFAULT_JSON_API_BINDING_ADDRESS = "127.0.0.1";
static { System.loadLibrary("retroshare-service"); }
public static void start(
Context ctx, int jsonApiPort, String jsonApiBindAddress )
{
Log.d(TAG, "start");
Intent intent = new Intent(ctx, RetroShareServiceAndroid.class);
intent.putExtra(JSON_API_PORT_KEY, jsonApiPort);
intent.putExtra(JSON_API_BIND_ADDRESS_KEY, jsonApiBindAddress);
ctx.startService(intent);
}
public static void stop(Context ctx)
{
Log.d(TAG, "stop");
ctx.stopService(new Intent(ctx, RetroShareServiceAndroid.class));
}
public static boolean isRunning(Context ctx)
{
Log.d(TAG, "isRunning");
ActivityManager manager =
(ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
for( ActivityManager.RunningServiceInfo service :
manager.getRunningServices(Integer.MAX_VALUE) )
if( RetroShareServiceAndroid.class.getName()
.equals(service.service.getClassName()) )
return true;
return false;
}
public static Context getServiceContext()
{
if(sServiceContext == null)
{
Log.e(TAG, "getServiceContext() called before onCreate");
throw new NullPointerException();
}
return sServiceContext;
}
@Override
public int onStartCommand(
Intent intent, int flags, int startId )
{
if(intent == null)
{
Log.i(TAG, "onStartCommand called without intent");
return Service.START_REDELIVER_INTENT;
}
int jsonApiPort = DEFAULT_JSON_API_PORT;
String jsonApiBindAddress = DEFAULT_JSON_API_BINDING_ADDRESS;
Bundle args = intent.getExtras();
if(args.containsKey(JSON_API_PORT_KEY))
jsonApiPort = args.getInt(JSON_API_PORT_KEY);
if(args.containsKey(JSON_API_BIND_ADDRESS_KEY))
jsonApiBindAddress =
args.getString(JSON_API_BIND_ADDRESS_KEY);
ErrorConditionWrap ec = nativeStart(jsonApiPort, jsonApiBindAddress);
if(ec.toBool()) Log.e(TAG, "onStartCommand(...) " + ec.toString());
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate ()
{
super.onCreate();
sServiceContext = this;
}
@Override
public void onDestroy()
{
ErrorConditionWrap ec = nativeStop();
if(ec.toBool()) Log.e(TAG, "onDestroy() " + ec.toString());
sServiceContext = null;
super.onDestroy();
}
@Override
public IBinder onBind(Intent arg0) { return null; }
private static final String JSON_API_PORT_KEY =
RetroShareServiceAndroid.class.getCanonicalName() +
"/JSON_API_PORT_KEY";
private static final String JSON_API_BIND_ADDRESS_KEY =
RetroShareServiceAndroid.class.getCanonicalName() +
"/JSON_API_BIND_ADDRESS_KEY" ;
private static final String TAG = "RetroShareServiceAndroid.java";
private static Context sServiceContext;
protected static native ErrorConditionWrap nativeStart(
int jsonApiPort, String jsonApiBindAddress );
protected static native ErrorConditionWrap nativeStop();
}

View File

@ -0,0 +1,103 @@
/*
* RetroShare Service Android
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org>
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
*
* 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/>.
*
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include <limits>
#include <cstdint>
#include "util/stacktrace.h"
#include "retroshare/rsinit.h"
#include "retroshare/rsiface.h"
#include "util/rsdebug.h"
#include "rs_android/retroshareserviceandroid.hpp"
#include "rs_android/rsjni.hpp"
/*static*/ std::unique_ptr<AndroidCoutCerrCatcher>
RetroShareServiceAndroid::sAndroidCoutCerrCatcher = nullptr;
using ErrorConditionWrap = RsJni::ErrorConditionWrap;
/*static*/ jni::Local<jni::Object<ErrorConditionWrap>>
RetroShareServiceAndroid::start(
JNIEnv& env, jni::Class<RetroShareServiceAndroid>&,
jni::jint jsonApiPort, const jni::String& jsonApiBindAddress )
{
if(jsonApiPort < 0 || jsonApiPort > std::numeric_limits<uint16_t>::max())
{
RS_ERR("Got invalid JSON API port: ", jsonApiPort);
return jni::Make<ErrorConditionWrap>(env, std::errc::invalid_argument);
}
RsInfo() << "\n" <<
"+================================================================+\n"
"| o---o o |\n"
"| \\ / - Retroshare Service Android - / \\ |\n"
"| o o---o |\n"
"+================================================================+"
<< std::endl << std::endl;
sAndroidCoutCerrCatcher = std::make_unique<AndroidCoutCerrCatcher>();
RsInit::InitRsConfig();
RsControl::earlyInitNotificationSystem();
RsConfigOptions conf;
conf.jsonApiPort = static_cast<uint16_t>(jsonApiPort);
conf.jsonApiBindAddress = jni::Make<std::string>(env, jsonApiBindAddress);
// Dirty workaround plugins not supported on Android ATM
conf.main_executable_path = " ";
int initResult = RsInit::InitRetroShare(conf);
if(initResult != RS_INIT_OK)
{
RS_ERR("Retroshare core initalization failed with: ", initResult);
return jni::Make<ErrorConditionWrap>(env, std::errc::no_child_process);
}
return jni::Make<ErrorConditionWrap>(env, std::error_condition());
}
jni::Local<jni::Object<ErrorConditionWrap>> RetroShareServiceAndroid::stop(
JNIEnv& env, jni::Class<RetroShareServiceAndroid>& )
{
if(RsControl::instance()->isReady())
{
RsControl::instance()->rsGlobalShutDown();
return jni::Make<ErrorConditionWrap>(env, std::error_condition());
}
sAndroidCoutCerrCatcher.reset();
return jni::Make<ErrorConditionWrap>(env, std::errc::no_such_process);
}
jni::Local<jni::Object<RetroShareServiceAndroid::Context> >
RetroShareServiceAndroid::getAndroidContext(JNIEnv& env)
{
auto& clazz = jni::Class<RetroShareServiceAndroid>::Singleton(env);
static auto method =
clazz.GetStaticMethod<jni::Object<RetroShareServiceAndroid::Context>()>(
env, "getServiceContext" );
return clazz.Call(env, method);
}

View File

@ -0,0 +1,84 @@
/*
* RetroShare Service Android
* Copyright (C) 2016-2021 Gioacchino Mazzurco <gio@eigenlab.org>
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
*
* 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/>.
*
* SPDX-FileCopyrightText: Retroshare Team <contact@retroshare.cc>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#pragma once
#include <system_error>
#include <memory>
#include <jni/jni.hpp>
#include "rs_android/rsjni.hpp"
#include "rs_android/androidcoutcerrcatcher.hpp"
#include "util/stacktrace.h"
/** Provide native methods that are registered into corresponding Java class
* to start/stop RetroShare with reasonable comfort on Android platform */
struct RetroShareServiceAndroid
{
static constexpr auto Name()
{ return "org/retroshare/service/RetroShareServiceAndroid"; }
using ErrorConditionWrap = RsJni::ErrorConditionWrap;
/**
* Called from RetroShareServiceAndroid Java to init libretroshare
* @param[in] env the usual JNI parafernalia
* @param[in] jclass the usual JNI parafernalia
* @param[in] jsonApiPort port on which JSON API server will listen
* @param[in] jsonApiBindAddress binding address of the JSON API server
* @note Yeah you read it well we use a full 32 bit signed integer for JSON
* API port. This is because Java lack even the minimum decency to implement
* unsigned integral types so we need to wrap the port (16 bit unsigned
* integer everywhere reasonable) into a full integer and then check at
* runtime the value.
*/
static jni::Local<jni::Object<ErrorConditionWrap>> start(
JNIEnv& env, jni::Class<RetroShareServiceAndroid>& jclass,
jni::jint jsonApiPort, const jni::String& jsonApiBindAddress );
/**
* Called from RetroShareServiceAndroid Java to shutdown libretroshare
* @param[in] env the usual JNI parafernalia
* @param[in] jclass the usual JNI parafernalia
*/
static jni::Local<jni::Object<ErrorConditionWrap>> stop(
JNIEnv& env, jni::Class<RetroShareServiceAndroid>& );
struct Context
{
/// JNI parafernalia
static constexpr auto Name() { return "android/content/Context"; }
};
/// Return RetroShare Service Android Context
static jni::Local<jni::Object<Context>> getAndroidContext(JNIEnv& env);
private:
/** Doesn't involve complex liftime handling stuff better let the runtime
* handle costruction (ASAP)/destruction for us */
static CrashStackTrace CrashStackTrace;
/** Involve threads, file descriptors etc. better handle lifetime
* explicitely */
static std::unique_ptr<AndroidCoutCerrCatcher> sAndroidCoutCerrCatcher;
};

View File

@ -0,0 +1,70 @@
/*******************************************************************************
* RetroShare JNI utilities *
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "rs_android/rsjni.hpp"
#include "rs_android/retroshareserviceandroid.hpp"
rs_view_ptr<JavaVM> RsJni::mJvm = nullptr;
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad_retroshare(JavaVM* vm, void*)
{
RS_DBG(vm);
RsJni::mJvm = vm;
jni::JNIEnv& env { jni::GetEnv(*vm) };
/** Ensure singleton refereces to our own Java classes are inizialized here
* because default Java class loader which is the one accessible by native
* threads which is not main even if attached, is not capable to find them.
* https://stackoverflow.com/questions/20752352/classnotfoundexception-when-finding-a-class-in-jni-background-thread
* https://groups.google.com/g/android-ndk/c/2gkr1mXKn_E */
jni::Class<RsJni::AssetHelper>::Singleton(env);
jni::Class<RsJni::ErrorConditionWrap>::Singleton(env);
jni::RegisterNatives(
env, *jni::Class<RetroShareServiceAndroid>::Singleton(env),
jni::MakeNativeMethod<
decltype(&RetroShareServiceAndroid::start),
&RetroShareServiceAndroid::start >("nativeStart"),
jni::MakeNativeMethod<
decltype(&RetroShareServiceAndroid::stop),
&RetroShareServiceAndroid::stop >("nativeStop")
);
return jni::Unwrap(jni::jni_version_1_2);
}
#ifdef RS_LIBRETROSHARE_EXPORT_JNI_ONLOAD
/** If libretroshare is linked statically to other components which already
* export JNI_OnLoad then a symbol clash may happen
* if RS_LIBRETROSHARE_EXPORT_JNI_ONLOAD is defined.
* @see JNI_OnLoad_retroshare should instead be called from the exported
* JNI_OnLoad */
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* _reserved)
{
RS_DBG(vm);
return JNI_OnLoad_retroshare(vm, _reserved);
}
#endif // def RS_LIBRETROSHARE_EXPORT_JNI_ONLOAD

View File

@ -0,0 +1,90 @@
/*******************************************************************************
* RetroShare JNI utilities *
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <system_error>
#include <cstdlib>
#include <jni/jni.hpp>
#include "util/rsmemory.h"
#include "util/cxx23retrocompat.h"
/** Store JVM pointer safely and register native methods */
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad_retroshare(JavaVM* vm, void*);
/** Provide library wide JVM access with some safe measures
* The JVM pointer is set properly by @see JNI_OnLoad_retroshare
*/
class RsJni
{
public:
static inline JavaVM& getVM()
{
if(!mJvm) // [[unlikely]]
{
RS_FATAL( "Attempt to access JVM before JNI_OnLoad_retroshare ",
std::errc::bad_address );
print_stacktrace();
std::exit(std::to_underlying(std::errc::bad_address));
}
return *mJvm;
}
friend jint JNI_OnLoad_retroshare(JavaVM* vm, void*);
/** Provide a comfortable way to access Android package assets like
* bdboot.txt from C++ */
struct AssetHelper
{
static constexpr auto Name()
{ return "org/retroshare/service/AssetHelper"; }
};
/** Provide a comfortable way to propagate C++ error_conditions to Java
* callers */
struct ErrorConditionWrap
{
static constexpr auto Name()
{ return "org/retroshare/service/ErrorConditionWrap"; }
};
private:
static rs_view_ptr<JavaVM> mJvm;
};
namespace jni
{
/** Provides idiomatic way of creating instances via
@code{.cpp}
jni::Make<ErrorConditionWrap>(env, std::error_condition());
@endcode */
jni::Local<jni::Object<RsJni::ErrorConditionWrap>>
MakeAnything(
jni::ThingToMake<RsJni::ErrorConditionWrap>, JNIEnv& env,
const std::error_condition& ec );
}

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2011-2011 by Cyril Soler <csoler@users.sourceforge.net> *
* Copyright (C) 2011-2018 Cyril Soler <csoler@users.sourceforge.net> *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -21,7 +23,9 @@
*******************************************************************************/
#pragma once
#include <stdint.h>
#include <cstdint>
using RsItemPriority = uint8_t;
// This file centralises QoS priorities for all transfer RsItems
//

View File

@ -3,7 +3,8 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2018-2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -28,6 +29,9 @@
#include "serialiser/rsserializer.h"
#include "serialiser/rsserializable.h"
#include "util/stacktrace.h"
#include "rsitems/itempriorities.h"
#include "rsitems/rsserviceids.h"
#include <typeinfo>
@ -42,8 +46,13 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable
virtual ~RsItem();
/// TODO: Do this make sense with the new serialization system?
virtual void clear() = 0;
/** TODO: Does the existence of this method make sense with the new
* serialization system? **/
virtual void clear()
{
RS_ERR("Called without being overridden, report to developers");
print_stacktrace();
}
/// @deprecated use << ostream operator instead
RS_DEPRECATED_FOR("<< ostream operator")
@ -70,14 +79,21 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable
uint8_t PacketType();
uint8_t PacketSubType() const;
/** For Service Packets, @deprecated use the costructor with priority
* paramether instead */
RS_DEPRECATED RsItem(uint8_t ver, uint16_t service, uint8_t subtype);
/// For Service Packets
RsItem(uint8_t ver, uint16_t service, uint8_t subtype);
RsItem( uint8_t ver, RsServiceType service, uint8_t subtype,
RsItemPriority prio );
uint16_t PacketService() const; /* combined Packet class/type (mid 16bits) */
void setPacketService(uint16_t service);
inline uint8_t priority_level() const { return _priority_level ;}
inline void setPriorityLevel(uint8_t l) { _priority_level = l ;}
#ifdef RS_DEAD_CODE
/*
* TODO: This default implementation should be removed and childs structs
* implement ::serial_process(...) as soon as all the codebase is ported to
@ -90,11 +106,12 @@ struct RsItem : RsMemoryManagement::SmallObject, RsSerializable
"overriding Class is: ", typeid(*this).name() );
print_stacktrace();
}
#endif //def RS_DEAD_CODE
protected:
uint32_t type;
RsPeerId peerId;
uint8_t _priority_level;
RsItemPriority _priority_level;
};
/// TODO: Do this make sense with the new serialization system?
@ -108,9 +125,17 @@ public:
uint32_t getRawLength() { return len; }
void * getRawData() { return data; }
virtual void clear() {}
// virtual void clear() override {}
virtual std::ostream &print(std::ostream &out, uint16_t indent = 0);
virtual void serial_process(RsGenericSerializer::SerializeJob,
RsGenericSerializer::SerializeContext&) override
{
RS_ERR( "called by an item using new serialization system ",
typeid(*this).name() );
print_stacktrace();
}
private:
void *data;
uint32_t len;

View File

@ -64,6 +64,12 @@ RsItem *RsNxsSerialiser::create_item(uint16_t service_id,uint8_t item_subtype) c
if(service_id != SERVICE_TYPE)
return NULL ;
switch(static_cast<RsNxsSubtype>(item_subtype))
{
case RsNxsSubtype::PULL_REQUEST:
return new RsNxsPullRequestItem(static_cast<RsServiceType>(service_id));
}
switch(item_subtype)
{
case RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM: return new RsNxsSyncGrpReqItem(SERVICE_TYPE) ;

View File

@ -3,7 +3,10 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2012 Christopher Evi-Parker,Robert Fernie<retroshare@lunamutt.com>*
* Copyright (C) 2012 Christopher Evi-Parker *
* Copyright (C) 2012 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@altermundi.net> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -19,8 +22,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef RSNXSITEMS_H
#define RSNXSITEMS_H
#pragma once
#include <map>
#include <openssl/ssl.h>
@ -33,8 +35,13 @@
#include "serialiser/rstlvkeys.h"
#include "gxs/rsgxsdata.h"
// These items have "flag type" numbers, but this is not used.
enum class RsNxsSubtype : uint8_t
{
PULL_REQUEST = 0x90 /// @see RsNxsPullRequestItem
};
// These items have "flag type" numbers, but this is not used.
// TODO: refactor as C++11 enum class
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_REQ_ITEM = 0x01;
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_ITEM = 0x02;
const uint8_t RS_PKT_SUBTYPE_NXS_SYNC_GRP_STATS_ITEM = 0x03;
@ -47,14 +54,15 @@ const uint8_t RS_PKT_SUBTYPE_NXS_MSG_ITEM = 0x20;
const uint8_t RS_PKT_SUBTYPE_NXS_TRANSAC_ITEM = 0x40;
const uint8_t RS_PKT_SUBTYPE_NXS_GRP_PUBLISH_KEY_ITEM = 0x80;
// possibility create second service to deal with this functionality
#ifdef RS_DEAD_CODE
// possibility create second service to deal with this functionality
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_GRP = 0x0001;
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_MSG = 0x0002;
const uint8_t RS_PKT_SUBTYPE_EXT_DELETE_GRP = 0x0004;
const uint8_t RS_PKT_SUBTYPE_EXT_DELETE_MSG = 0x0008;
const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_REQ = 0x0010;
#endif // def RS_DEAD_CODE
/*!
* Base class for Network exchange service
@ -65,17 +73,14 @@ const uint8_t RS_PKT_SUBTYPE_EXT_SEARCH_REQ = 0x0010;
*/
class RsNxsItem : public RsItem
{
public:
RsNxsItem(uint16_t servtype, uint8_t subtype) : RsItem(RS_PKT_VERSION_SERVICE, servtype, subtype), transactionNumber(0)
{
setPriorityLevel(QOS_PRIORITY_RS_GXS_NET);
return;
}
virtual ~RsNxsItem(){}
virtual void clear() = 0;
RsNxsItem(uint16_t servtype, uint8_t subtype):
RsItem(RS_PKT_VERSION_SERVICE, servtype, subtype), transactionNumber(0)
{ setPriorityLevel(QOS_PRIORITY_RS_GXS_NET); }
uint32_t transactionNumber; // set to zero if this is not a transaction item
virtual ~RsNxsItem() = default;
uint32_t transactionNumber; // set to zero if this is not a transaction item
};
@ -362,6 +367,22 @@ public:
};
/*!
* Used to request to a peer pull updates from us ASAP without waiting GXS sync
* timer */
struct RsNxsPullRequestItem: RsItem
{
explicit RsNxsPullRequestItem(RsServiceType servtype):
RsItem( RS_PKT_VERSION_SERVICE,
servtype,
static_cast<uint8_t>(RsNxsSubtype::PULL_REQUEST),
QOS_PRIORITY_RS_GXS_NET ) {}
/// @see RsSerializable
void serial_process( RsGenericSerializer::SerializeJob,
RsGenericSerializer::SerializeContext& ) override {}
};
/*!
* Used to respond to a RsGrpMsgsReq
@ -401,6 +422,7 @@ struct RsNxsMsg : RsNxsItem
RsGxsMsgMetaData* metaData;
};
#ifdef RS_DEAD_CODE
/*!
* Used to request a search of user data
*/
@ -422,7 +444,7 @@ public:
RsTlvBinaryData serviceSearchItem; // service aware of item class
uint32_t expiration; // expiration date
};
#endif //def RS_DEAD_CODE
#ifdef UNUSED_CODE
@ -503,14 +525,12 @@ class RsNxsSerialiser : public RsServiceSerializer
{
public:
explicit RsNxsSerialiser(uint16_t servtype) : RsServiceSerializer(servtype), SERVICE_TYPE(servtype) {}
virtual ~RsNxsSerialiser() {}
explicit RsNxsSerialiser(uint16_t servtype):
RsServiceSerializer(servtype), SERVICE_TYPE(servtype) {}
virtual ~RsNxsSerialiser() = default;
virtual RsItem *create_item(uint16_t service_id,uint8_t item_subtype) const ;
protected:
const uint16_t SERVICE_TYPE;
};
#endif // RSNXSITEMS_H

View File

@ -118,7 +118,7 @@ void RsServer::rsGlobalShutDown()
// if(mWire) mWire->join();
// #endif
AuthGPG::exit();
AuthPGP::exit();
mShutdownCallback(0);
}

View File

@ -254,7 +254,7 @@ bool p3Peers::setPeerMaximumRates(const RsPgpId& pid,uint32_t maxUploadRate,uint
bool p3Peers::haveSecretKey(const RsPgpId& id)
{
return AuthGPG::getAuthGPG()->haveSecretKey(id);
return AuthPGP::haveSecretKey(id);
}
/* There are too many dependancies of this function
@ -273,7 +273,7 @@ bool p3Peers::getPeerDetails(const RsPeerId& id, RsPeerDetails &d)
if (id == sOwnId)
{
mPeerMgr->getOwnNetStatus(ps);
ps.gpg_id = AuthGPG::getAuthGPG()->getGPGOwnId();
ps.gpg_id = AuthPGP::getPgpOwnId();
}
else if (!mPeerMgr->getFriendNetStatus(id, ps))
{
@ -559,17 +559,17 @@ bool p3Peers::isProxyAddress(const uint32_t type, const sockaddr_storage& addr)
bool p3Peers::isKeySupported(const RsPgpId& id)
{
return AuthGPG::getAuthGPG()->isKeySupported(id);
return AuthPGP::isKeySupported(id);
}
std::string p3Peers::getGPGName(const RsPgpId &gpg_id)
{
/* get from mAuthMgr as it should have more peers? */
return AuthGPG::getAuthGPG()->getGPGName(gpg_id);
return AuthPGP::getPgpName(gpg_id);
}
bool p3Peers::isPgpFriend(const RsPgpId& pgpId)
{ return AuthGPG::getAuthGPG()->isGPGAccepted(pgpId); }
{ return AuthPGP::isPGPAccepted(pgpId); }
bool p3Peers::isSslOnlyFriend(const RsPeerId& sslId)
{
@ -597,7 +597,7 @@ std::string p3Peers::getPeerName(const RsPeerId& ssl)
#endif
std::string name;
if (ssl == AuthSSL::getAuthSSL()->OwnId())
return AuthGPG::getAuthGPG()->getGPGOwnName();
return AuthPGP::getPgpOwnName();
if (mPeerMgr->getPeerName(ssl, name))
{
@ -617,7 +617,7 @@ bool p3Peers::getGPGAllList(std::list<RsPgpId> &ids)
#endif
/* get from mAuthMgr */
AuthGPG::getAuthGPG()->getGPGAllList(ids);
AuthPGP::getPgpAllList(ids);
return true;
}
@ -628,7 +628,7 @@ bool p3Peers::getGPGValidList(std::list<RsPgpId> &ids)
#endif
/* get from mAuthMgr */
AuthGPG::getAuthGPG()->getGPGValidList(ids);
AuthPGP::getPgpValidList(ids);
return true;
}
@ -639,14 +639,14 @@ bool p3Peers::getGPGSignedList(std::list<RsPgpId> &ids)
#endif
/* get from mAuthMgr */
AuthGPG::getAuthGPG()->getGPGSignedList(ids);
AuthPGP::getPgpSignedList(ids);
return true;
}
bool p3Peers::getPgpFriendList(std::vector<RsPgpId>& pgpIds)
{
std::list<RsPgpId> ids;
if(AuthGPG::getAuthGPG()->getGPGAcceptedList(ids))
if(AuthPGP::getPgpAcceptedList(ids))
{
pgpIds.clear();
std::copy(ids.begin(), ids.end(), std::back_inserter(pgpIds));
@ -660,7 +660,7 @@ bool p3Peers::getGPGAcceptedList(std::list<RsPgpId> &ids)
#ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::getGPGAcceptedList()" << std::endl;
#endif
AuthGPG::getAuthGPG()->getGPGAcceptedList(ids);
AuthPGP::getPgpAcceptedList(ids);
return true;
}
@ -676,7 +676,7 @@ bool p3Peers::getAssociatedSSLIds(const RsPgpId &gpg_id, std::list<RsPeerId> &id
bool p3Peers::gpgSignData(const void *data, const uint32_t len, unsigned char *sign, unsigned int *signlen, std::string reason /* = "" */)
{
return AuthGPG::getAuthGPG()->SignDataBin(data,len,sign,signlen, reason);
return AuthPGP::SignDataBin(data,len,sign,signlen, reason);
}
RsPgpId p3Peers::pgpIdFromFingerprint(const RsPgpFingerprint& fpr)
@ -691,7 +691,7 @@ bool p3Peers::getGPGDetails(const RsPgpId &pgp_id, RsPeerDetails &d)
#endif
/* get from mAuthMgr */
bool res = AuthGPG::getAuthGPG()->getGPGDetails(pgp_id, d);
bool res = AuthPGP::getPgpDetails(pgp_id, d);
d.isOnlyGPGdetail = true ;
d.service_perm_flags = mPeerMgr->servicePermissionFlags(pgp_id) ;
@ -706,7 +706,7 @@ const RsPgpId& p3Peers::getGPGOwnId()
#endif
/* get from mAuthMgr */
return AuthGPG::getAuthGPG()->getGPGOwnId();
return AuthPGP::getPgpOwnId();
}
RsPgpId p3Peers::getGPGId(const RsPeerId& sslid)
@ -718,7 +718,7 @@ RsPgpId p3Peers::getGPGId(const RsPeerId& sslid)
/* get from mAuthMgr */
if (sslid == AuthSSL::getAuthSSL()->OwnId())
{
return AuthGPG::getAuthGPG()->getGPGOwnId();
return AuthPGP::getPgpOwnId();
}
peerState pcs;
if (mPeerMgr->getFriendNetStatus(sslid, pcs))
@ -739,12 +739,12 @@ bool p3Peers::addFriend(const RsPeerId &ssl_id, const RsPgpId &gpg_id,ServicePe
#ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::addFriend() with : id : " << id << "; gpg_id : " << gpg_id << std::endl;
#endif
if(AuthGPG::getAuthGPG()->isGPGId(gpg_id))
if(AuthPGP::isPGPId(gpg_id))
{
#ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::addFriend() Authorising GPG Id: " << gpg_id << std::endl;
#endif
if (AuthGPG::getAuthGPG()->AllowConnection(gpg_id, true))
if (AuthPGP::AllowConnection(gpg_id, true))
{
#ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::addFriend() Authorization OK." << std::endl;
@ -797,7 +797,7 @@ bool p3Peers::addSslOnlyFriend( const RsPeerId& sslId, const RsPgpId& pgp_id,con
bool p3Peers::removeKeysFromPGPKeyring(const std::set<RsPgpId>& pgp_ids,std::string& backup_file,uint32_t& error_code)
{
return AuthGPG::getAuthGPG()->removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
return AuthPGP::removeKeysFromPGPKeyring(pgp_ids,backup_file,error_code) ;
}
bool p3Peers::removeFriendLocation(const RsPeerId &sslId)
@ -817,7 +817,7 @@ bool p3Peers::removeFriend(const RsPgpId& gpgId)
#ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::removeFriend() " << gpgId << std::endl;
#endif
if (gpgId == AuthGPG::getAuthGPG()->getGPGOwnId()) {
if (gpgId == AuthPGP::getPgpOwnId()) {
std::cerr << "p3Peers::removeFriend() ERROR we're not going to remove our own GPG id." << std::endl;
return false;
}
@ -825,7 +825,7 @@ bool p3Peers::removeFriend(const RsPgpId& gpgId)
#ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::removeFriend() Removing GPG Id: " << gpgId << std::endl;
#endif
if (AuthGPG::getAuthGPG()->AllowConnection(gpgId, false))
if (AuthPGP::AllowConnection(gpgId, false))
{
#ifdef P3PEERS_DEBUG
std::cerr << "p3Peers::removeFriend() OK." << std::endl;
@ -1113,9 +1113,7 @@ std::string p3Peers::getPGPKey(const RsPgpId& pgp_id,bool include_signatures)
rs_owner_ptr<unsigned char> mem_block = nullptr;
size_t mem_block_size = 0;
if( !AuthGPG::getAuthGPG()->exportPublicKey(
RsPgpId(pgp_id), mem_block, mem_block_size,
false, include_signatures ) )
if( !AuthPGP::exportPublicKey( RsPgpId(pgp_id), mem_block, mem_block_size, false, include_signatures ) )
{
RsErr() << __PRETTY_FUNCTION__
<< " Failure retriving certificate for id " << pgp_id
@ -1146,8 +1144,7 @@ bool p3Peers::GetPGPBase64StringAndCheckSum(
rs_owner_ptr<unsigned char> mem_block = nullptr;
size_t mem_block_size = 0;
if(!AuthGPG::getAuthGPG()->exportPublicKey(
gpg_id,mem_block,mem_block_size,false,false ))
if(!AuthPGP::exportPublicKey( gpg_id,mem_block,mem_block_size,false,false ))
return false;
RsBase64::encode(mem_block, mem_block_size, gpg_base64_string, true, false);
@ -1644,7 +1641,7 @@ std::string p3Peers::GetRetroshareInvite( const RsPeerId& sslId, RetroshareInvit
unsigned char *mem_block = nullptr;
size_t mem_block_size = 0;
if(!AuthGPG::getAuthGPG()->exportPublicKey( RsPgpId(detail.gpg_id), mem_block, mem_block_size, false, !!(invite_flags & RetroshareInviteFlags::PGP_SIGNATURES) ))
if(!AuthPGP::exportPublicKey( RsPgpId(detail.gpg_id), mem_block, mem_block_size, false, !!(invite_flags & RetroshareInviteFlags::PGP_SIGNATURES) ))
{
std::cerr << "Cannot output certificate for id \"" << detail.gpg_id
<< "\". Sorry." << std::endl;
@ -1680,7 +1677,7 @@ bool p3Peers::loadCertificateFromString(
}
RsPgpId gpgid;
bool res = AuthGPG::getAuthGPG()->LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string );
bool res = AuthPGP::LoadCertificateFromString( crt->armouredPGPKey(), gpgid, error_string );
gpg_id = gpgid;
ssl_id = crt->sslid();
@ -1697,7 +1694,7 @@ bool p3Peers::loadCertificateFromString(
}
bool p3Peers::loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string )
{
bool res = AuthGPG::getAuthGPG()->LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string );
bool res = AuthPGP::LoadPGPKeyFromBinaryData( bin_key_data,bin_key_len, gpg_id, error_string );
if(res)
mPeerMgr->notifyPgpKeyReceived(gpg_id);
@ -1716,9 +1713,7 @@ bool p3Peers::loadDetailsFromStringCert( const std::string &certstr,
RsCertificate& cert = *certPtr;
if(!AuthGPG::getAuthGPG()->getGPGDetailsFromBinaryBlock(
cert.pgp_key(), cert.pgp_key_size(),
pd.gpg_id, pd.name, pd.gpgSigners ))
if(!AuthPGP::getPgpDetailsFromBinaryBlock( cert.pgp_key(), cert.pgp_key_size(), pd.gpg_id, pd.name, pd.gpgSigners ))
return false;
Dbg4() << __PRETTY_FUNCTION__ << " Parsing cert for sslid, location, ext "
@ -1758,11 +1753,11 @@ bool p3Peers::loadDetailsFromStringCert( const std::string &certstr,
return true;
}
bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code)
bool p3Peers::cleanCertificate(const std::string &certstr, std::string &cleanCert,bool& is_short_format,uint32_t& error_code,RsPeerDetails& details)
{
RsCertificate::Format format ;
bool res = RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true) ;
bool res = RsCertificate::cleanCertificate(certstr,cleanCert,format,error_code,true,details) ;
if(format == RsCertificate::RS_CERTIFICATE_RADIX)
is_short_format = false;
@ -1796,7 +1791,7 @@ bool p3Peers::signGPGCertificate(const RsPgpId &id, const std::string &gpg_pass
rsNotify->cachePgpPassphrase(gpg_passphrase);
rsNotify->setDisableAskPassword(true);
bool res = AuthGPG::getAuthGPG()->SignCertificateLevel0(id);
bool res = AuthPGP::SignCertificateLevel0(id);
rsNotify->clearPgpPassphrase();
rsNotify->setDisableAskPassword(false);
@ -1810,7 +1805,7 @@ bool p3Peers::trustGPGCertificate(const RsPgpId &id, uint32_t trustlvl)
std::cerr << "p3Peers::TrustCertificate() " << id;
std::cerr << std::endl;
#endif
return AuthGPG::getAuthGPG()->TrustCertificate(id, trustlvl);
return AuthPGP::TrustCertificate(id, trustlvl);
}
/* Group Stuff */

View File

@ -163,7 +163,7 @@ public:
virtual bool loadPgpKeyFromBinaryData( const unsigned char *bin_key_data,uint32_t bin_key_len, RsPgpId& gpg_id, std::string& error_string ) override;
virtual bool loadDetailsFromStringCert(const std::string &cert, RsPeerDetails &pd, uint32_t& error_code) override;
virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert, bool &is_short_format, uint32_t& error_code) override;
virtual bool cleanCertificate(const std::string &certstr, std::string &cleanCert, bool &is_short_format, uint32_t& error_code, RsPeerDetails& details) override;
virtual std::string saveCertificateToString(const RsPeerId &id) override;
virtual bool signGPGCertificate(const RsPgpId &id,const std::string& gpg_passphrase) override;

View File

@ -140,7 +140,7 @@ bool p3ServerConfig::setConfigurationOption(uint32_t key, const std::string &opt
int p3ServerConfig::getConfigNetStatus(RsConfigNetStatus &status)
{
status.ownId = AuthSSL::getAuthSSL()->OwnId();
status.ownName = AuthGPG::getAuthGPG()->getGPGOwnName();
status.ownName = AuthPGP::getPgpOwnName();
// Details from PeerMgr.
peerState pstate;

View File

@ -32,12 +32,12 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <system_error>
#include <iostream>
#include "retroshare/rsinit.h"
#include "rsaccounts.h"
#include "util/rsdebug.h"
#include "util/rsdir.h"
#include "util/rsstring.h"
#include "util/folderiterator.h"
@ -48,6 +48,11 @@
#include <openssl/ssl.h>
#ifdef __ANDROID__
# include "rs_android/rsjni.hpp"
# include "rs_android/retroshareserviceandroid.hpp"
#endif
// Global singleton declaration of data.
RsAccountsDetail* RsAccounts::rsAccountsDetails = nullptr;
@ -328,22 +333,7 @@ bool RsAccountsDetail::defaultBaseDirectory()
{
std::string basedir;
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
#ifndef WINDOWS_SYS
// unix: homedir + /.retroshare
char *h = getenv("HOME");
if (h == NULL)
{
std::cerr << "defaultBaseDirectory() Error: cannot determine $HOME dir"
<< std::endl;
return false ;
}
basedir = h;
basedir += "/.retroshare";
#else
#ifdef WINDOWS_SYS
if (RsInit::isPortable())
{
// use directory "Data" in portable version
@ -375,13 +365,53 @@ bool RsAccountsDetail::defaultBaseDirectory()
}
basedir += "\\RetroShare";
}
#endif
/******************************** WINDOWS/UNIX SPECIFIC PART ******************/
#elif defined (__ANDROID__) // def WINDOWS_SYS
struct ApplicationInfo
{
static constexpr auto Name()
{ return "android/content/pm/ApplicationInfo"; }
};
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
JNIEnv& env = *uenv;
auto androidContext = RetroShareServiceAndroid::getAndroidContext(env);
auto& contextClass =
jni::Class<RetroShareServiceAndroid::Context>::Singleton(env);
auto& applicationInfoClass = jni::Class<ApplicationInfo>::Singleton(env);
auto getApplicationInfo =
contextClass.GetMethod<jni::Object<ApplicationInfo> ()>(
env, "getApplicationInfo" );
auto applicationInfo = androidContext.Call(env, getApplicationInfo);
auto dataDirField = jni::Field<ApplicationInfo, jni::String>(
env, applicationInfoClass, "dataDir" );
jni::Local<jni::String> dataDir = applicationInfo.Get<jni::String>(
env, dataDirField );
basedir = jni::Make<std::string>(env, dataDir) + "/.retroshare/";
#else // def WINDOWS_SYS, if defined (__ANDROID__)
// unix: homedir + /.retroshare
char* h = getenv("HOME");
if(h == nullptr)
{
RS_ERR("cannot determine $HOME dir");
return false ;
}
basedir = h;
basedir += "/.retroshare";
#endif // def WINDOWS_SYS
/* store to class variable */
mBaseDirectory = basedir;
std::cerr << "defaultBaseDirectory() = " << mBaseDirectory;
std::cerr << std::endl;
RS_INFO(mBaseDirectory);
return true;
}
@ -701,10 +731,10 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
if(! RsAccounts::GetPGPLoginDetails(account.mPgpId, account.mPgpName, account.mPgpEmail))
return false ;
if(!AuthGPG::getAuthGPG()->haveSecretKey(account.mPgpId))
if(!AuthPGP::haveSecretKey(account.mPgpId))
return false ;
if(!AuthGPG::getAuthGPG()->isKeySupported(account.mPgpId))
if(!AuthPGP::isKeySupported(account.mPgpId))
{
std::string keystring = account.mPgpId.toStdString() + " " + account.mPgpName + "&#60;" + account.mPgpEmail ;
unsupported_keys[keystring].push_back("Location: " + account.mLocation + "&nbsp;&nbsp;(" + account.mSslId.toStdString() + ")") ;
@ -811,14 +841,15 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
/* Use RetroShare's exe dir */
dataDirectory = ".";
#elif defined(ANDROID)
#elif defined(__ANDROID__)
// TODO: This is probably not really used on Android
dataDirectory = PathBaseDirectory()+"/usr/share/retroshare";
#elif defined(DATA_DIR)
#elif defined(RS_DATA_DIR)
// cppcheck-suppress ConfigurationNotChecked
dataDirectory = DATA_DIR;
dataDirectory = RS_DATA_DIR;
// For all other OS the data directory must be set in libretroshare.pro
#else
# error "For your target OS automatic data dir discovery is not supported, cannot compile if DATA_DIR variable not set."
# error "For your target OS automatic data dir discovery is not supported, cannot compile if RS_DATA_DIR variable not set."
#endif
if (!check)
@ -851,9 +882,10 @@ static bool checkAccount(const std::string &accountdir, AccountDetails &account,
/* Generating GPGme Account */
int RsAccountsDetail::GetPGPLogins(std::list<RsPgpId> &pgpIds) {
AuthGPG::getAuthGPG()->availableGPGCertificatesWithPrivateKeys(pgpIds);
return 1;
int RsAccountsDetail::GetPGPLogins(std::list<RsPgpId>& pgpIds)
{
AuthPGP::availablePgpCertificatesWithPrivateKeys(pgpIds);
return 1;
}
int RsAccountsDetail::GetPGPLoginDetails(const RsPgpId& id, std::string &name, std::string &email)
@ -863,10 +895,10 @@ int RsAccountsDetail::GetPGPLoginDetails(const RsPgpId& id, std::string &na
#endif
bool ok = true ;
name = AuthGPG::getAuthGPG()->getGPGName(id,&ok);
name = AuthPGP::getPgpName(id,&ok);
if(!ok)
return 0 ;
email = AuthGPG::getAuthGPG()->getGPGEmail(id,&ok);
email = AuthPGP::getPgpEmail(id,&ok);
if(!ok)
return 0 ;
@ -886,7 +918,7 @@ bool RsAccountsDetail::SelectPGPAccount(const RsPgpId& pgpId)
{
bool retVal = false;
if (0 < AuthGPG::getAuthGPG() -> GPGInit(pgpId))
if (0 < AuthPGP::PgpInit(pgpId))
{
retVal = true;
#ifdef DEBUG_ACCOUNTS
@ -906,7 +938,7 @@ bool RsAccountsDetail::SelectPGPAccount(const RsPgpId& pgpId)
bool RsAccountsDetail::GeneratePGPCertificate(const std::string& name, const std::string& email, const std::string& passwd, RsPgpId &pgpId, const int keynumbits, std::string &errString)
{
return AuthGPG::getAuthGPG()->GeneratePGPCertificate(name, email, passwd, pgpId, keynumbits, errString);
return AuthPGP::GeneratePgpCertificate(name, email, passwd, pgpId, keynumbits, errString);
}
// PGP Support Functions.
@ -918,29 +950,34 @@ void RsAccountsDetail::getUnsupportedKeys(std::map<std::string,std::vector<std::
bool RsAccountsDetail::exportIdentity(const std::string& fname,const RsPgpId& id)
{
return AuthGPG::getAuthGPG()->exportProfile(fname,id);
return AuthPGP::exportProfile(fname,id);
}
bool RsAccountsDetail::importIdentity(const std::string& fname,RsPgpId& id,std::string& import_error)
{
return AuthGPG::getAuthGPG()->importProfile(fname,id,import_error);
return AuthPGP::importProfile(fname,id,import_error);
}
bool RsAccountsDetail::importIdentityFromString(const std::string &data, RsPgpId &imported_pgp_id, std::string &import_error)
{
return AuthGPG::getAuthGPG()->importProfileFromString(data, imported_pgp_id, import_error);
return AuthPGP::importProfileFromString(data, imported_pgp_id, import_error);
}
bool RsAccountsDetail::exportIdentityToString(
std::string& data, const RsPgpId& pgpId, bool includeSignatures,
std::string& errorMsg )
{
return AuthGPG::getAuthGPG()->exportIdentityToString(
return AuthPGP::exportIdentityToString(
data, pgpId, includeSignatures, errorMsg );
}
bool RsAccountsDetail::copyGnuPGKeyrings()
{
#ifdef __ANDROID__
RS_ERR(std::errc::not_supported);
print_stacktrace();
return false;
#else
std::string pgp_dir = PathPGPDirectory() ;
if(!RsDirUtil::checkCreateDirectory(pgp_dir))
@ -992,6 +1029,7 @@ bool RsAccountsDetail::copyGnuPGKeyrings()
}
return true ;
#endif // def __ANDROID__
}
@ -1020,7 +1058,7 @@ bool RsAccountsDetail::GenerateSSLCertificate(const RsPgpId& pgp_id, const s
int nbits = 4096;
//std::string pgp_name = AuthGPG::getAuthGPG()->getGPGName(pgp_id);
//std::string pgp_name = AuthGPG::getGPGName(pgp_id);
// Create the filename .....
// Temporary Directory for creating files....
@ -1295,7 +1333,7 @@ bool RsAccounts::init(const std::string& opt_base_dir,int& error_code)
if(!RsDirUtil::checkCreateDirectory(pgp_dir))
throw std::runtime_error("Cannot create pgp directory " + pgp_dir) ;
AuthGPG::init( pgp_dir + "/retroshare_public_keyring.gpg",
AuthPGP::init( pgp_dir + "/retroshare_public_keyring.gpg",
pgp_dir + "/retroshare_secret_keyring.gpg",
pgp_dir + "/retroshare_trustdb.gpg",
pgp_dir + "/lock");

View File

@ -32,8 +32,9 @@
#endif
#ifdef __ANDROID__
# include <QFile> // To install bdboot.txt
# include <QString> // for QString::fromStdString(...)
# include <jni/jni.hpp>
# include "rs_android/rsjni.hpp"
# include "rs_android/retroshareserviceandroid.hpp"
#endif
#include "util/argstream.h"
@ -196,7 +197,7 @@ static const int SSLPWD_LEN = 64;
void RsInit::InitRsConfig()
{
RsInfo() << " libretroshare version: " << RS_HUMAN_READABLE_VERSION
RsInfo() << "libretroshare version: " << RS_HUMAN_READABLE_VERSION
<< std::endl;
rsInitConfig = new RsInitConfig;
@ -514,7 +515,7 @@ RsInit::LoadCertificateStatus RsInit::LockAndLoadCertificates(
if(!RsAccounts::GetAccountDetails(accountId, pgpId, pgpName, pgpEmail, location))
throw RsInit::ERR_UNKNOWN; // invalid PreferredAccount;
if(0 == AuthGPG::getAuthGPG() -> GPGInit(pgpId))
if(0 == AuthPGP::PgpInit(pgpId))
throw RsInit::ERR_UNKNOWN; // PGP Error.
LoadCertificateStatus retVal =
@ -914,8 +915,8 @@ int RsServer::StartupRetroShare()
/* History Manager */
mHistoryMgr = new p3HistoryMgr();
mPeerMgr = new p3PeerMgrIMPL( AuthSSL::getAuthSSL()->OwnId(),
AuthGPG::getAuthGPG()->getGPGOwnId(),
AuthGPG::getAuthGPG()->getGPGOwnName(),
AuthPGP::getPgpOwnId(),
AuthPGP::getPgpOwnName(),
AuthSSL::getAuthSSL()->getOwnLocation());
mNetMgr = new p3NetMgrIMPL();
mLinkMgr = new p3LinkMgrIMPL(mPeerMgr, mNetMgr);
@ -1014,32 +1015,32 @@ int RsServer::StartupRetroShare()
uint64_t tmp_size ;
if (!RsDirUtil::checkFile(bootstrapfile,tmp_size,true))
{
std::cerr << "DHT bootstrap file not in ConfigDir: " << bootstrapfile
<< std::endl;
#ifdef __ANDROID__
QFile bdbootRF("assets:/values/bdboot.txt");
if(!bdbootRF.open(QIODevice::ReadOnly | QIODevice::Text))
std::cerr << __PRETTY_FUNCTION__
<< " bdbootRF(assets:/values/bdboot.txt).open(...) fail: "
<< bdbootRF.errorString().toStdString() << std::endl;
else
{
QFile bdbootCF(QString::fromStdString(bootstrapfile));
if(!bdbootCF.open(QIODevice::WriteOnly | QIODevice::Text))
std::cerr << __PRETTY_FUNCTION__ << " bdbootCF("
<< bootstrapfile << ").open(...) fail: "
<< bdbootRF.errorString().toStdString() << std::endl;
else
{
bdbootCF.write(bdbootRF.readAll());
bdbootCF.close();
std::cerr << "Installed DHT bootstrap file not in ConfigDir: "
<< bootstrapfile << std::endl;
}
RS_INFO("DHT bootstrap file not in ConfigDir: ", bootstrapfile);
bdbootRF.close();
}
#else
#ifdef __ANDROID__
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
JNIEnv& env = *uenv;
using AContext = RetroShareServiceAndroid::Context;
auto& assetHelperClass = jni::Class<RsJni::AssetHelper>::Singleton(env);
static auto copyAsset =
assetHelperClass.GetStaticMethod<
jni::jboolean(jni::Object<AContext>, jni::String, jni::String)>(
env, "copyAsset" );
auto androidContext = RetroShareServiceAndroid::getAndroidContext(env);
jni::jboolean result = assetHelperClass.Call(
env, copyAsset,
androidContext,
jni::Make<jni::String>(env, "values/bdboot.txt"),
jni::Make<jni::String>(env, bootstrapfile) );
if(!result) RS_ERR("Failure installing ", bootstrapfile);
#else // def __ANDROID__
std::cerr << "Checking for Installation DHT bootstrap file " << installfile << std::endl;
if ((installfile != "") && (RsDirUtil::checkFile(installfile,tmp_size)))
{
@ -1615,7 +1616,8 @@ int RsServer::StartupRetroShare()
//mConfigMgr->addConfiguration("ftserver.cfg", ftserver);
//
mConfigMgr->addConfiguration("gpg_prefs.cfg" , AuthGPG::getAuthGPG());
AuthPGP::registerToConfigMgr(std::string("gpg_prefs.cfg"),mConfigMgr);
mConfigMgr->addConfiguration("gxsnettunnel.cfg", mGxsNetTunnel);
mConfigMgr->addConfiguration("peers.cfg" , mPeerMgr);
mConfigMgr->addConfiguration("general.cfg" , mGeneralConfig);
@ -1801,7 +1803,7 @@ int RsServer::StartupRetroShare()
/* Add AuthGPG services */
/**************************************************************************/
//AuthGPG::getAuthGPG()->addService(mDisc);
//AuthGPG::addService(mDisc);
/**************************************************************************/
/* Force Any Last Configuration Options */

View File

@ -60,8 +60,7 @@ bool RsLoginHandler::checkAndStoreSSLPasswdIntoGPGFile(
return true ;
}
bool ok = AuthGPG::getAuthGPG()->encryptTextToFile(
ssl_passwd, getSSLPasswdFileName(ssl_id));
bool ok = AuthPGP::encryptTextToFile( ssl_passwd, getSSLPasswdFileName(ssl_id));
if (!ok) std::cerr << "Encrypting went wrong !" << std::endl;
@ -90,7 +89,7 @@ bool RsLoginHandler::getSSLPasswdFromGPGFile(const RsPeerId& ssl_id,std::string&
#endif
std::string plain;
if ( AuthGPG::getAuthGPG()->decryptTextFromFile( plain, getSSLPasswdFileName(ssl_id)) )
if ( AuthPGP::decryptTextFromFile( plain, getSSLPasswdFileName(ssl_id)) )
{
sslPassword = plain;
#ifdef DEBUG_RSLOGINHANDLER

View File

@ -3,7 +3,9 @@
* *
* libretroshare: retroshare core library *
* *
* Copyright 2007-2008 by Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2007-2008 Robert Fernie <retroshare@lunamutt.com> *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -20,21 +22,20 @@
* *
*******************************************************************************/
#include "serialiser/rsbaseserial.h"
#include "util/rsthreads.h"
#include "util/rsstring.h"
#include "util/rsprint.h"
#include "rsitems/rsitem.h"
#include "rsitems/itempriorities.h"
#include <math.h>
#include <cmath>
#include <map>
#include <vector>
#include <iostream>
#include <typeinfo>
#include "serialiser/rsbaseserial.h"
#include "util/cxx23retrocompat.h"
#include "util/rsthreads.h"
#include "util/rsstring.h"
#include "util/rsprint.h"
#include "rsitems/rsitem.h"
#include "rsitems/itempriorities.h"
/***
* #define RSSERIAL_DEBUG 1
@ -166,11 +167,17 @@ uint8_t RsItem::PacketSubType() const
/* For Service Packets */
RsItem::RsItem(uint8_t ver, uint16_t service, uint8_t subtype)
{
_priority_level = QOS_PRIORITY_UNKNOWN ; // This value triggers PQIInterface to complain about undefined priorities
// This value triggers PQIInterface to complain about undefined priorities
_priority_level = QOS_PRIORITY_UNKNOWN;
type = (ver << 24) + (service << 8) + subtype;
return;
}
RsItem::RsItem( uint8_t ver, RsServiceType service, uint8_t subtype,
RsItemPriority prio ):
type(static_cast<uint32_t>(
(ver << 24) + (std::to_underlying(service) << 8) + subtype )),
_priority_level(prio) {}
uint16_t RsItem::PacketService() const
{
return (type >> 8) & 0xFFFF;

View File

@ -1,7 +1,8 @@
/*******************************************************************************
* RetroShare Broadcast Domain Discovery *
* *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
* Copyright (C) 2019-2021 Gioacchino Mazzurco <gio@altermundi.net> *
* Copyright (C) 2019-2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -25,16 +26,17 @@
#include <vector>
#include <iostream>
#ifdef __ANDROID__
# include <QtAndroid>
#endif // def __ANDROID__
#include "services/broadcastdiscoveryservice.h"
#include "retroshare/rspeers.h"
#include "serialiser/rsserializable.h"
#include "serialiser/rsserializer.h"
#include "retroshare/rsevents.h"
#ifdef __ANDROID__
# include "rs_android/retroshareserviceandroid.hpp"
#endif // def __ANDROID__
/*extern*/ RsBroadcastDiscovery* rsBroadcastDiscovery = nullptr;
struct BroadcastDiscoveryPack : RsSerializable
@ -99,7 +101,7 @@ BroadcastDiscoveryService::BroadcastDiscoveryService(
if(mRsPeers.isHiddenNode(mRsPeers.getOwnId())) return;
#ifdef __ANDROID__
createMulticastLock();
createAndroidMulticastLock();
#endif // def __ANDROID__
enableMulticastListening();
@ -228,19 +230,47 @@ RsBroadcastDiscoveryResult BroadcastDiscoveryService::createResult(
bool BroadcastDiscoveryService::isMulticastListeningEnabled()
{
#ifdef __ANDROID__
return assertMulticastLockIsvalid() &&
mWifiMulticastLock.callMethod<jboolean>("isHeld");
#endif // def __ANDROID__
if(!mAndroidWifiMulticastLock)
{
RS_ERR("Android multicast lock not initialized!");
return false;
}
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
JNIEnv& env = *uenv;
auto& multicastLockClass = jni::Class<AndroidMulticastLock>::Singleton(env);
auto isHeld =
multicastLockClass.GetMethod<jni::jboolean()>(
env, "isHeld" );
return mAndroidWifiMulticastLock.Call(env, isHeld);
#else // def __ANDROID__
return true;
#endif // def __ANDROID__
}
bool BroadcastDiscoveryService::enableMulticastListening()
{
#ifdef __ANDROID__
if(assertMulticastLockIsvalid() && !isMulticastListeningEnabled())
if(!mAndroidWifiMulticastLock)
{
mWifiMulticastLock.callMethod<void>("acquire");
RS_ERR("Android multicast lock not initialized!");
return false;
}
if(!isMulticastListeningEnabled())
{
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
JNIEnv& env = *uenv;
auto& multicastLockClass = jni::Class<AndroidMulticastLock>::Singleton(env);
auto acquire =
multicastLockClass.GetMethod<void()>(
env, "acquire" );
mAndroidWifiMulticastLock.Call(env, acquire);
return true;
}
#endif // def __ANDROID__
@ -251,9 +281,24 @@ bool BroadcastDiscoveryService::enableMulticastListening()
bool BroadcastDiscoveryService::disableMulticastListening()
{
#ifdef __ANDROID__
if(assertMulticastLockIsvalid() && isMulticastListeningEnabled())
if(!mAndroidWifiMulticastLock)
{
mWifiMulticastLock.callMethod<void>("release");
RS_ERR("Android multicast lock not initialized!");
return false;
}
if(isMulticastListeningEnabled())
{
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
JNIEnv& env = *uenv;
auto& multicastLockClass = jni::Class<AndroidMulticastLock>::Singleton(env);
auto release =
multicastLockClass.GetMethod<void()>(
env, "release" );
mAndroidWifiMulticastLock.Call(env, release);
return true;
}
#endif // def __ANDROID__
@ -262,56 +307,57 @@ bool BroadcastDiscoveryService::disableMulticastListening()
}
#ifdef __ANDROID__
bool BroadcastDiscoveryService::createMulticastLock()
bool BroadcastDiscoveryService::createAndroidMulticastLock()
{
Dbg2() << __PRETTY_FUNCTION__ << std::endl;
constexpr auto fname = __PRETTY_FUNCTION__;
const auto failure = [&](const std::string& err)
if(mAndroidWifiMulticastLock)
{
RsErr() << fname << " " << err << std::endl;
return false;
};
if(mWifiMulticastLock.isValid())
return failure("mWifiMulticastLock is already initialized");
QAndroidJniObject context = QtAndroid::androidContext();
if(!context.isValid())
return failure("Cannot retrieve Android context");
QAndroidJniObject WIFI_SERVICE = QAndroidJniObject::getStaticObjectField(
"android.content.Context", "WIFI_SERVICE", "Ljava/lang/String;");
if(!WIFI_SERVICE.isValid())
return failure("Cannot retrieve Context.WIFI_SERVICE value");
QAndroidJniObject wifiManager = context.callObjectMethod(
"getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;",
WIFI_SERVICE.object<jstring>() );
if(!wifiManager.isValid())
return failure("Cannot retrieve Android Wifi Manager");
mWifiMulticastLock = wifiManager.callObjectMethod(
"createMulticastLock",
"(Ljava/lang/String;)Landroid/net/wifi/WifiManager$MulticastLock;",
QAndroidJniObject::fromString(fname).object<jstring>() );
if(!mWifiMulticastLock.isValid())
return failure("Cannot create WifiManager.MulticastLock");
return true;
}
bool BroadcastDiscoveryService::assertMulticastLockIsvalid()
{
if(!mWifiMulticastLock.isValid())
{
RsErr() << __PRETTY_FUNCTION__ << " mWifiMulticastLock is invalid!"
<< std::endl;
RS_ERR("Android multicast lock is already initialized");
print_stacktrace();
return false;
}
auto uenv = jni::GetAttachedEnv(RsJni::getVM());
JNIEnv& env = *uenv;
using AContextTag = RetroShareServiceAndroid::Context;
using AContext = jni::Class<AContextTag>;
static auto& contextClass = AContext::Singleton(env);
auto wifiServiceField = jni::StaticField<AContextTag, jni::String>(
env, contextClass, "WIFI_SERVICE");
jni::Local<jni::String> WIFI_SERVICE = contextClass.Get(
env, wifiServiceField );
auto androidContext = RetroShareServiceAndroid::getAndroidContext(env);
auto getSystemService =
contextClass.GetMethod<jni::Object<jni::ObjectTag> (jni::String)>(
env, "getSystemService" );
struct WifiManager
{ static constexpr auto Name() { return "android/net/wifi/WifiManager"; } };
auto& wifiManagerClass = jni::Class<WifiManager>::Singleton(env);
auto wifiManager = jni::Cast<WifiManager>(
env, wifiManagerClass,
androidContext.Call(env, getSystemService, WIFI_SERVICE) );
auto createMulticastLock =
wifiManagerClass.GetMethod<jni::Object<AndroidMulticastLock>(jni::String)>(
env, "createMulticastLock" );
mAndroidWifiMulticastLock = jni::NewGlobal(
env, wifiManager.Call(
env, createMulticastLock,
jni::Make<jni::String>(
env, "RetroShare BroadcastDiscoveryService" ) ) );
return true;
}
#endif // def __ANDROID__
RsBroadcastDiscovery::~RsBroadcastDiscovery() = default;

View File

@ -1,7 +1,8 @@
/*******************************************************************************
* RetroShare Broadcast Domain Discovery *
* *
* Copyright (C) 2019 Gioacchino Mazzurco <gio@altermundi.net> *
* Copyright (C) 2019-2021 Gioacchino Mazzurco <gio@altermundi.net> *
* Copyright (C) 2019-2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
@ -27,14 +28,16 @@
#include <udp_discovery_peer.hpp>
#ifdef __ANDROID__
# include <QtAndroidExtras/QAndroidJniObject>
#endif // def __ANDROID__
#include "retroshare/rsbroadcastdiscovery.h"
#include "util/rsthreads.h"
#include "util/rsdebug.h"
#ifdef __ANDROID__
# include <jni/jni.hpp>
# include "rs_android/rsjni.hpp"
#endif // def __ANDROID__
namespace UDC = udpdiscovery;
class RsPeers;
@ -42,7 +45,7 @@ class BroadcastDiscoveryService :
public RsBroadcastDiscovery, public RsTickingThread
{
public:
BroadcastDiscoveryService(RsPeers& pRsPeers);
explicit BroadcastDiscoveryService(RsPeers& pRsPeers);
~BroadcastDiscoveryService() override;
/// @see RsBroadcastDiscovery
@ -71,26 +74,27 @@ protected:
std::map<UDC::IpPort, std::string> mDiscoveredData;
RsMutex mDiscoveredDataMutex;
RsPeers& mRsPeers; // TODO: std::shared_ptr<RsPeers> mRsPeers;
RsPeers& mRsPeers;
RsBroadcastDiscoveryResult createResult(
const UDC::IpPort& ipp, const std::string& uData );
#ifdef __ANDROID__
/** Android WifiManager.MulticastLock */
QAndroidJniObject mWifiMulticastLock;
struct AndroidMulticastLock
{
static constexpr auto Name()
{ return "android/net/wifi/WifiManager$MulticastLock"; }
};
jni::Global<jni::Object<AndroidMulticastLock>> mAndroidWifiMulticastLock;
/** Initialize the wifi multicast lock without acquiring it
* Needed to enable multicast listening in Android, for RetroShare broadcast
* discovery inspired by:
* https://github.com/flutter/flutter/issues/16335#issuecomment-420547860
*/
bool createMulticastLock();
/** Return false if mWifiMulticastLock is invalid and print error messages */
bool assertMulticastLockIsvalid();
#endif // def __ANDROID__
bool createAndroidMulticastLock();
#endif
RS_SET_CONTEXT_DEBUG_LEVEL(3)
};

View File

@ -900,10 +900,19 @@ bool p3GxsForums::markRead(const RsGxsGrpMsgIdPair& msgId, bool read)
bool p3GxsForums::subscribeToForum(const RsGxsGroupId& groupId, bool subscribe )
{
uint32_t token;
if( !RsGenExchange::subscribeToGroup(token, groupId, subscribe) || waitToken(token) != RsTokenService::COMPLETE ) return false;
if( !RsGenExchange::subscribeToGroup(token, groupId, subscribe) ||
waitToken(token) != RsTokenService::COMPLETE ) return false;
RsGxsGroupId grp;
acknowledgeGrp(token,grp);
RsGxsGroupId grp;
acknowledgeGrp(token, grp);
/* Since subscribe has been requested, the caller is most probably
* interested in getting the group messages ASAP so check updates from peers
* without waiting GXS sync timer.
* Do it here as this is meaningful or not depending on the service.
* Do it only after the token has been completed otherwise the pull have no
* effect. */
if(subscribe) RsGenExchange::netService()->checkUpdatesFromPeers();
return true;
}
@ -1150,6 +1159,13 @@ std::error_condition p3GxsForums::setPostKeepForever(
}
}
std::error_condition p3GxsForums::requestSynchronization()
{
auto errc = RsGenExchange::netService()->checkUpdatesFromPeers();
if(errc) return errc;
return RsGenExchange::netService()->requestPull();
}
/* so we need the same tick idea as wiki for generating dummy forums
*/

View File

@ -175,6 +175,8 @@ public:
rs_owner_ptr<uint8_t>& resultData, uint32_t& resultSize ) override;
#endif
std::error_condition requestSynchronization() override;
/// implementation of rsGxsGorums
///
bool getGroupData(const uint32_t &token, std::vector<RsGxsForumGroup> &groups) override;

View File

@ -1067,7 +1067,7 @@ bool p3IdService::createIdentity(uint32_t& token, RsIdentityParameters &params)
if(params.isPgpLinked)
{
ssdata.pgp.pgpId = AuthGPG::getAuthGPG()->getGPGOwnId();
ssdata.pgp.pgpId = AuthPGP::getPgpOwnId();
ssdata.pgp.lastCheckTs = time(nullptr);
}
@ -3619,7 +3619,7 @@ RsGenExchange::ServiceCreate_Return p3IdService::service_CreateGroup(
unsigned int sign_size = MAX_SIGN_SIZE;
memset(signarray,0,MAX_SIGN_SIZE) ; // just in case.
int result = AuthGPG::getAuthGPG()->SignDataBin(
int result = AuthPGP::SignDataBin(
static_cast<const void*>(hash.toByteArray()),
hash.SIZE_IN_BYTES, signarray, &sign_size,
__PRETTY_FUNCTION__ )
@ -4096,7 +4096,7 @@ void p3IdService::getPgpIdList()
#endif // DEBUG_IDS
std::list<RsPgpId> list;
mPgpUtils->getGPGAllList(list);
mPgpUtils->getPgpAllList(list);
RsStackMutex stack(mIdMtx); /********** STACK LOCKED MTX ******/
@ -4593,7 +4593,7 @@ void p3IdService::generateDummy_FriendPGP()
// Now Generate for friends.
std::list<RsPgpId> gpgids;
std::list<RsPgpId>::const_iterator it;
mPgpUtils->getGPGAllList(gpgids);
mPgpUtils->getPgpAllList(gpgids);
RsGxsIdGroup id;

View File

@ -111,11 +111,7 @@ PRE_TARGETDEPS += $$pretargetStaticLibs(sLibs)
LIBS += $$linkDynamicLibs(dLibs)
android-* {
## ifaddrs is missing on Android to add them don't use the one from
## https://github.com/morristech/android-ifaddrs
## because it crash, use QNetworkInterface from Qt instead
CONFIG *= qt
QT *= network
INCLUDEPATH *= $$clean_path($${RS_SRC_PATH}/supportlibs/jni.hpp/include/)
}
################################### Pkg-Config Stuff #############################

View File

@ -0,0 +1,34 @@
/*******************************************************************************
* RetroShare C++23 backwards compatibility utilities *
* *
* libretroshare: retroshare core library *
* *
* Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org> *
* Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#pragma once
#include <utility>
#if ! defined(__cpp_lib_to_underlying)
namespace std
{
template <class Enum>
constexpr underlying_type_t<Enum> to_underlying(Enum e) noexcept
{ return static_cast<std::underlying_type_t<Enum>>(e); }
}
#endif // ! defined(__cpp_lib_to_underlying)

27
openpgpsdk/CMakeLists.txt Normal file
View File

@ -0,0 +1,27 @@
# RetroShare decentralized communication platform
#
# Copyright (C) 2021 Gioacchino Mazzurco <gio@eigenlab.org>
# Copyright (C) 2021 Asociación Civil Altermundi <info@altermundi.net>
#
# SPDX-License-Identifier: CC0-1.0
cmake_minimum_required (VERSION 3.12.0)
project(openpgpsdk)
find_package(ZLIB REQUIRED)
find_package(BZip2 REQUIRED)
find_package(OpenSSL REQUIRED)
file(GLOB SOURCES src/openpgpsdk/*.c)
add_library(${PROJECT_NAME} ${SOURCES})
target_include_directories(
${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src
PRIVATE ${OPENSSL_INCLUDE_DIR}
PRIVATE ${BZIP2_INCLUDE_DIRS}
PRIVATE ${ZLIB_INCLUDE_DIRS} )
target_link_libraries(
${PROJECT_NAME}
OpenSSL::SSL OpenSSL::Crypto BZip2::BZip2 ZLIB::ZLIB )

View File

@ -104,8 +104,8 @@ AudioWizard::AudioWizard(QWidget *p) : QWizard(p) {
iMaxPeak = 0;
iTicks = 0;
qpTalkingOn = QPixmap::fromImage(QImage(QLatin1String("skin:talking_on.svg")).scaled(64,64));
qpTalkingOff = QPixmap::fromImage(QImage(QLatin1String("skin:talking_off.svg")).scaled(64,64));
qpTalkingOn = QPixmap::fromImage(QImage(QLatin1String(":/images/talking_on.svg")).scaled(64,64));
qpTalkingOff = QPixmap::fromImage(QImage(QLatin1String(":/images/talking_off.svg")).scaled(64,64));
bInit = false;

View File

@ -21,6 +21,7 @@
#include <QColorDialog>
#include <QDesktopServices>
#include <QIcon>
#include <QInputDialog>
#include <QMessageBox>
#include <QPixmap>
#include <QStatusBar>
@ -1689,3 +1690,19 @@ void MainWindow::setCompactStatusMode(bool compact)
ratesstatus->setCompactMode(compact);
//opModeStatus: TODO Show only ???
}
Gui_InputDialogReturn MainWindow::guiInputDialog(const QString& windowTitle, const QString& labelText, QLineEdit::EchoMode textEchoMode, bool modal)
{
QInputDialog dialog(this);
dialog.setWindowTitle(windowTitle);
dialog.setLabelText(labelText);
dialog.setTextEchoMode(textEchoMode);
dialog.setModal(modal);
Gui_InputDialogReturn ret;
ret.execReturn = dialog.exec();
ret.textValue = dialog.textValue();
return ret;
}

View File

@ -21,6 +21,7 @@
#ifndef _MainWindow_H
#define _MainWindow_H
#include <QLineEdit>
#include <QSystemTrayIcon>
#include <set>
@ -74,6 +75,14 @@ class MessengerWindow;
class ApplicationWindow;
#endif
struct Gui_InputDialogReturn
{
int execReturn;
QString textValue;
};
Q_DECLARE_METATYPE(Gui_InputDialogReturn);
class MainWindow : public RWindow
{
Q_OBJECT
@ -192,7 +201,7 @@ public:
}
static bool hiddenmode;
public slots:
void receiveNewArgs(QStringList args);
void displayErrorMessage(int,int,const QString&) ;
@ -210,9 +219,35 @@ public slots:
void showBandwidthGraph();
void toggleStatusToolTip(bool toggle);
/**
* @brief Create a QInputDialog. This must be called in MainWindow thread because Widgets must be created in the GUI thread.
* Here an exemple how to call it:
*
* bool sameThread = QThread::currentThread() == qApp->thread();
* Gui_InputDialogReturn ret;
* qRegisterMetaType<Gui_InputDialogReturn>("Gui_InputDialogReturn");
* QMetaObject::invokeMethod( MainWindow::getInstance()
* , "guiInputDialog"
* , sameThread ? Qt::DirectConnection : Qt::BlockingQueuedConnection
* , Q_RETURN_ARG(Gui_InputDialogReturn, ret)
* , Q_ARG(QString, windowTitle)
* , Q_ARG(QString, labelText)
* , Q_ARG(QLineEdit::EchoMode, textEchoMode)
* , Q_ARG(bool, modal)
* );
*
* @param windowTitle: the window title (caption).
* @param labelText: label's text which describes what needs to be input.
* @param textEchoMode: the echo mode for the text value.
* @param modal: pop up the dialog as modal or modeless.
* @return Gui_InputDialogReturn ( Accepted(1)|Rejected(0), text value for the input dialog)
*/
Gui_InputDialogReturn guiInputDialog(const QString& windowTitle, const QString& labelText, QLineEdit::EchoMode textEchoMode, bool modal);
protected:
/** Default Constructor */
MainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
MainWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
void closeEvent(QCloseEvent *);

View File

@ -122,14 +122,14 @@ void BoardPostDisplayWidgetBase::setReadStatus(bool isNew, bool isUnread)
void BoardPostDisplayWidget_compact::doExpand(bool e)
{
#ifdef DEBUG_BOARDPOSTDISPLAYWIDGET
std::cerr << "Expanding" << std::endl;
std::cerr << "Expanding" << std::endl;
#endif
if(e)
ui->frame_notes->show();
else
ui->frame_notes->hide();
if(e)
ui->frame_notes->show();
else
ui->frame_notes->hide();
emit expand(mPost.mMeta.mMsgId,e);
emit expand(mPost.mMeta.mMsgId,e);
}
void BoardPostDisplayWidgetBase::loadComments(bool e)
@ -144,7 +144,7 @@ void BoardPostDisplayWidgetBase::readToggled()
emit changeReadStatusRequested(mPost.mMeta.mMsgId,s);
}
void BoardPostDisplayWidgetBase::setup()
void BoardPostDisplayWidgetBase::baseSetup()
{
// show/hide things based on the view type
@ -166,8 +166,6 @@ void BoardPostDisplayWidgetBase::setup()
QAction *CopyLinkAction = new QAction(QIcon(""),tr("Copy RetroShare Link"), this);
connect(CopyLinkAction, SIGNAL(triggered()), this, SLOT(handleCopyLinkClicked()));
int S = QFontMetricsF(font()).height() ;
readButton()->setChecked(false);
QMenu *menu = new QMenu();
@ -184,6 +182,7 @@ void BoardPostDisplayWidgetBase::setup()
if(redacted)
{
commentButton()->setDisabled(true);
shareButton()->setDisabled(true);
voteUpButton()->setDisabled(true);
voteDownButton()->setDisabled(true);
fromLabel()->setId(mPost.mMeta.mAuthorId);
@ -196,8 +195,6 @@ void BoardPostDisplayWidgetBase::setup()
}
else
{
QPixmap sqpixmap2 = FilesDefs::getPixmapFromQtResourcePath(":/images/thumb-default.png");
QDateTime qtime;
qtime.setTime_t(mPost.mMeta.mPublishTs);
QString timestamp = qtime.toString("hh:mm dd-MMM-yyyy");
@ -295,16 +292,7 @@ BoardPostDisplayWidget_compact::BoardPostDisplayWidget_compact(const RsPostedPos
: BoardPostDisplayWidgetBase(post,display_flags,parent), ui(new Ui::BoardPostDisplayWidget_compact())
{
ui->setupUi(this);
setup();
ui->right_VL->addStretch();
ui->right_VL->setAlignment(Qt::AlignTop);
ui->topLayout->setAlignment(Qt::AlignTop);
ui->arrowsLayout->addStretch();
ui->arrowsLayout->setAlignment(Qt::AlignTop);
ui->feedFrame_VL->addStretch();
adjustSize();
BoardPostDisplayWidget_compact::setup();
}
BoardPostDisplayWidget_compact::~BoardPostDisplayWidget_compact()
@ -314,7 +302,7 @@ BoardPostDisplayWidget_compact::~BoardPostDisplayWidget_compact()
void BoardPostDisplayWidget_compact::setup()
{
BoardPostDisplayWidgetBase::setup();
baseSetup();
// show/hide things based on the view type
@ -356,7 +344,7 @@ void BoardPostDisplayWidget_compact::setup()
QObject::connect(ui->expandButton, SIGNAL(toggled(bool)), this, SLOT(doExpand(bool)));
QTextDocument doc;
doc.setHtml(notes()->text());
doc.setHtml(BoardPostDisplayWidget_compact::notes()->text());
if(mDisplayFlags & SHOW_NOTES)
{
@ -427,16 +415,7 @@ BoardPostDisplayWidget_card::BoardPostDisplayWidget_card(const RsPostedPost& pos
: BoardPostDisplayWidgetBase(post,display_flags,parent), ui(new Ui::BoardPostDisplayWidget_card())
{
ui->setupUi(this);
setup();
ui->right_VL->addStretch();
ui->right_VL->setAlignment(Qt::AlignTop);
ui->topLayout->setAlignment(Qt::AlignTop);
ui->arrowsLayout->addStretch();
ui->arrowsLayout->setAlignment(Qt::AlignTop);
ui->feedFrame_VL->addStretch();
adjustSize();
BoardPostDisplayWidget_card::setup();
}
BoardPostDisplayWidget_card::~BoardPostDisplayWidget_card()
@ -446,7 +425,7 @@ BoardPostDisplayWidget_card::~BoardPostDisplayWidget_card()
void BoardPostDisplayWidget_card::setup()
{
BoardPostDisplayWidgetBase::setup();
baseSetup();
RsReputationLevel overall_reputation = rsReputations->overallReputationLevel(mPost.mMeta.mAuthorId);
bool redacted = (overall_reputation == RsReputationLevel::LOCALLY_NEGATIVE);
@ -463,7 +442,6 @@ void BoardPostDisplayWidget_card::setup()
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
// Wiping data - as its been passed to thumbnail.
QPixmap scaledpixmap;
if(pixmap.width() > 800){
QPixmap scaledpixmap = pixmap.scaledToWidth(800, Qt::SmoothTransformation);
ui->pictureLabel->setPixmap(scaledpixmap);
@ -478,10 +456,10 @@ void BoardPostDisplayWidget_card::setup()
}
QTextDocument doc;
doc.setHtml(notes()->text());
doc.setHtml(BoardPostDisplayWidget_card::notes()->text());
if(doc.toPlainText().trimmed().isEmpty())
notes()->hide();
BoardPostDisplayWidget_card::notes()->hide();
}
QToolButton *BoardPostDisplayWidget_card::voteUpButton() { return ui->voteUpButton; }

View File

@ -62,10 +62,11 @@ public:
static const char *DEFAULT_BOARD_IMAGE;
protected slots:
protected:
/* GxsGroupFeedItem */
virtual void setup(); // to be overloaded by the different views
void baseSetup();
virtual void setup() =0; // to be overloaded by the different views
virtual QToolButton *voteUpButton() =0;
virtual QToolButton *commentButton() =0;
@ -81,6 +82,7 @@ protected slots:
virtual QToolButton *shareButton() =0;
virtual QFrame *feedFrame() =0;
protected slots:
void loadComments(bool e);
void readToggled();
void setReadStatus(bool isNew, bool isUnread) ;

View File

@ -90,7 +90,10 @@
</property>
<item>
<widget class="QFrame" name="voteFrame">
<layout class="QVBoxLayout" name="arrowsLayout">
<layout class="QVBoxLayout" name="voteFrame_VL">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
@ -173,6 +176,13 @@
</property>
</widget>
</item>
<item>
<spacer name="voteFrame_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -277,7 +287,7 @@
</widget>
</item>
<item>
<spacer name="from_HSpacer">
<spacer name="from_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -340,7 +350,7 @@
</widget>
</item>
<item>
<spacer name="pictureLabel_HSpacer">
<spacer name="pictureLabel_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -401,16 +411,16 @@
<iconset resource="Posted_images.qrc">
<normaloff>:/images/share.png</normaloff>:/images/share.png</iconset>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="buttons_HSpacer">
<spacer name="buttons_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -424,10 +434,30 @@
</item>
</layout>
</item>
<item>
<spacer name="right_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="feedFrame_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
</item>

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>542</width>
<height>150</height>
<height>151</height>
</rect>
</property>
<property name="sizePolicy">
@ -90,7 +90,22 @@
</property>
<item>
<widget class="QFrame" name="voteFrame">
<layout class="QVBoxLayout" name="arrowsLayout">
<layout class="QVBoxLayout" name="voteFrame_VL">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="voteUpButton">
<property name="sizePolicy">
@ -161,6 +176,13 @@
</property>
</widget>
</item>
<item>
<spacer name="voteFrame_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@ -287,7 +309,7 @@
</widget>
</item>
<item>
<spacer name="from_HSpacer">
<spacer name="from_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -305,7 +327,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="buttons_HM">
<layout class="QHBoxLayout" name="buttons_HL">
<item>
<widget class="QToolButton" name="commentButton">
<property name="text">
@ -400,7 +422,7 @@
</widget>
</item>
<item>
<spacer name="buttons_HSpacer">
<spacer name="buttons_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -414,6 +436,13 @@
</item>
</layout>
</item>
<item>
<spacer name="right_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
@ -473,6 +502,13 @@
</layout>
</widget>
</item>
<item>
<spacer name="feedFrame_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
</item>

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>614</width>
<height>182</height>
<height>198</height>
</rect>
</property>
<property name="windowTitle">
@ -16,7 +16,7 @@
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="PostedCardView_GL">
<property name="leftMargin">
<number>0</number>
</property>
@ -118,7 +118,7 @@
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="from_HL">
<property name="spacing">
<number>5</number>
</property>
@ -216,7 +216,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<spacer name="from_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -241,30 +241,27 @@
<height>0</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="voteFrame_VL">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>3</number>
<number>0</number>
</property>
<property name="topMargin">
<number>3</number>
<number>0</number>
</property>
<property name="rightMargin">
<number>3</number>
<number>0</number>
</property>
<property name="bottomMargin">
<number>3</number>
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="voteUpButton">
@ -337,26 +334,20 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<spacer name="voteFrame_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="5" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="buttons_HL">
<item>
<widget class="QToolButton" name="commentButton">
<property name="text">
@ -389,7 +380,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<spacer name="buttons_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -461,7 +452,7 @@
</item>
<item row="4" column="1">
<widget class="QFrame" name="picture_frame">
<layout class="QHBoxLayout" name="horizontalPictureLayout">
<layout class="QHBoxLayout" name="picture_frame_HL">
<property name="leftMargin">
<number>0</number>
</property>
@ -485,7 +476,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<spacer name="picture_frame_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -513,9 +504,9 @@
</customwidget>
</customwidgets>
<resources>
<include location="../images.qrc"/>
<include location="../icons.qrc"/>
<include location="Posted_images.qrc"/>
<include location="../icons.qrc"/>
<include location="../images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -41,9 +41,12 @@
#include "gui/common/FilesDefs.h"
/* View Page */
#define VIEW_POST 1
#define VIEW_IMAGE 2
#define VIEW_LINK 3
#define VIEW_POST 0
#define VIEW_IMAGE 1
#define VIEW_LINK 2
/* View Image */
#define IMG_ATTACH 0
#define IMG_PICTURE 1
PostedCreatePostDialog::PostedCreatePostDialog(RsPosted *posted, const RsGxsGroupId& grpId, const RsGxsId& default_author, QWidget *parent):
QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint),
@ -54,7 +57,6 @@ PostedCreatePostDialog::PostedCreatePostDialog(RsPosted *posted, const RsGxsGrou
Settings->loadWidgetInformation(this);
connect(ui->postButton, SIGNAL(clicked()), this, SLOT(createPost()));
connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(ui->addPicButton, SIGNAL(clicked() ), this , SLOT(addPicture()));
connect(ui->RichTextEditWidget, SIGNAL(textSizeOk(bool)),ui->postButton, SLOT(setEnabled(bool)));
@ -84,6 +86,7 @@ PostedCreatePostDialog::PostedCreatePostDialog(RsPosted *posted, const RsGxsGrou
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setPage(int)));
ui->removeButton->hide();
ui->stackedWidgetPicture->setCurrentIndex(IMG_ATTACH);
/* load settings */
processSettings(true);
@ -202,7 +205,6 @@ void PostedCreatePostDialog::addPicture()
// select a picture file
if (misc::getOpenFileName(window(), RshareSettings::LASTDIR_IMAGES, tr("Load Picture File"), "Pictures (*.png *.xpm *.jpg *.jpeg *.gif *.webp )", imagefilename)) {
QString encodedImage;
QImage image;
if (image.load(imagefilename) == false) {
fprintf (stderr, "RsHtml::makeEmbeddedImage() - image \"%s\" can't be load\n", imagefilename.toLatin1().constData());
@ -213,7 +215,7 @@ void PostedCreatePostDialog::addPicture()
QImage opt;
if(ImageUtil::optimizeSizeBytes(imagebytes, image, opt, 640*480, MAXMESSAGESIZE - 2000)) { //Leave space for other stuff
ui->imageLabel->setPixmap(QPixmap::fromImage(opt));
ui->stackedWidgetPicture->setCurrentIndex(1);
ui->stackedWidgetPicture->setCurrentIndex(IMG_PICTURE);
ui->removeButton->show();
} else {
imagefilename = "";
@ -259,45 +261,24 @@ int PostedCreatePostDialog::viewMode()
void PostedCreatePostDialog::setPage(int viewMode)
{
switch (viewMode) {
case VIEW_POST:
ui->stackedWidget->setCurrentIndex(0);
if( (viewMode < 0) || (viewMode > ui->stackedWidget->count()-1) )
viewMode = VIEW_POST;
ui->viewPostButton->setChecked(true);
ui->viewImageButton->setChecked(false);
ui->viewLinkButton->setChecked(false);
ui->stackedWidget->setCurrentIndex(viewMode);
break;
case VIEW_IMAGE:
ui->stackedWidget->setCurrentIndex(1);
ui->viewPostButton ->setChecked(viewMode==VIEW_POST);
ui->viewImageButton->setChecked(viewMode==VIEW_IMAGE);
ui->viewLinkButton ->setChecked(viewMode==VIEW_LINK);
ui->viewImageButton->setChecked(true);
ui->viewPostButton->setChecked(false);
ui->viewLinkButton->setChecked(false);
break;
case VIEW_LINK:
ui->stackedWidget->setCurrentIndex(2);
ui->viewLinkButton->setChecked(true);
ui->viewPostButton->setChecked(false);
ui->viewImageButton->setChecked(false);
break;
default:
setPage(VIEW_POST);
return;
}
}
void PostedCreatePostDialog::on_removeButton_clicked()
{
imagefilename = "";
imagebytes.clear();
QPixmap empty;
ui->imageLabel->setPixmap(empty);
ui->imageLabel->setPixmap(QPixmap());
ui->removeButton->hide();
ui->stackedWidgetPicture->setCurrentIndex(0);
ui->stackedWidgetPicture->setCurrentIndex(IMG_ATTACH);
}
void PostedCreatePostDialog::reject()

View File

@ -52,7 +52,7 @@ private slots:
void addPicture();
void on_removeButton_clicked();
void fileHashingFinished(QList<HashedFile> hashedFiles);
void reject();
void reject() override; //QDialog
void setPage(int viewMode);
private:

View File

@ -143,7 +143,7 @@
<item row="0" column="1">
<widget class="QStackedWidget" name="stackedWidgetPicture">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="PageAttach">
<layout class="QGridLayout" name="PageAttach_GL">

View File

@ -16,7 +16,7 @@
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<layout class="QGridLayout" name="PostedItem_GL">
<property name="leftMargin">
<number>1</number>
</property>
@ -82,21 +82,21 @@
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<layout class="QVBoxLayout" name="voteFrame_VL">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>3</number>
<number>0</number>
</property>
<property name="topMargin">
<number>3</number>
<number>0</number>
</property>
<property name="rightMargin">
<number>3</number>
<number>0</number>
</property>
<property name="bottomMargin">
<number>3</number>
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="voteUpButton">
@ -169,26 +169,20 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<spacer name="voteFrame_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="1" rowspan="2">
<layout class="QVBoxLayout" name="verticalLayout_3">
<layout class="QVBoxLayout" name="thumbnail_VL">
<property name="leftMargin">
<number>9</number>
</property>
@ -233,7 +227,7 @@
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<spacer name="thumbnail_VS">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -248,7 +242,7 @@
</layout>
</item>
<item row="0" column="2">
<layout class="QVBoxLayout" name="verticalLayout_4">
<layout class="QVBoxLayout" name="title_VL">
<property name="topMargin">
<number>6</number>
</property>
@ -286,7 +280,7 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="newCommHLayout">
<layout class="QHBoxLayout" name="newComm_HL">
<property name="topMargin">
<number>0</number>
</property>
@ -312,7 +306,7 @@
</layout>
</item>
<item row="1" column="2">
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QVBoxLayout" name="from_VL">
<property name="spacing">
<number>0</number>
</property>
@ -320,7 +314,7 @@
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QHBoxLayout" name="from_HL">
<property name="spacing">
<number>5</number>
</property>
@ -416,7 +410,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<spacer name="from_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -434,7 +428,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="buttonHLayout">
<layout class="QHBoxLayout" name="buttons_HL">
<property name="spacing">
<number>6</number>
</property>
@ -567,7 +561,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<spacer name="buttons_HS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -631,9 +625,9 @@
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="frame_picture_HL">
<item>
<spacer name="horizontalSpacer_2">
<spacer name="frame_picture_LHS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -659,7 +653,7 @@
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<spacer name="frame_picture_RHS">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -685,7 +679,7 @@
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<layout class="QGridLayout" name="frame_notes_GL">
<property name="leftMargin">
<number>3</number>
</property>
@ -726,17 +720,17 @@
</layout>
</widget>
<customwidgets>
<customwidget>
<class>GxsIdLabel</class>
<extends>QLabel</extends>
<header>gui/gxs/GxsIdLabel.h</header>
</customwidget>
<customwidget>
<class>ElidedLabel</class>
<extends>QLabel</extends>
<header>gui/common/ElidedLabel.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GxsIdLabel</class>
<extends>QLabel</extends>
<header>gui/gxs/GxsIdLabel.h</header>
</customwidget>
<customwidget>
<class>ClickableLabel</class>
<extends>QLabel</extends>

View File

@ -58,9 +58,7 @@
// number of posts to show at once.
#define POSTS_CHUNK_SIZE 25
/****
* #define DEBUG_POSTED
***/
//#define DEBUG_POSTED
static const int POSTED_TABS_POSTS = 1;
@ -87,8 +85,12 @@ std::ostream& operator<<(std::ostream& o,const QSize& s) { return o << s.width()
void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
#ifdef DEBUG_POSTED
if(option.state & QStyle::State_Selected) RS_DBG("Selected");
#endif
if((option.state & QStyle::State_Selected)) // Avoids double display. The selected widget is never exactly the size of the rendered one,
return; // so when selected, we only draw the selected one.
return; // so when selected, we only draw the selected one.
// prepare
painter->save();
@ -98,7 +100,7 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
painter->save();
painter->fillRect( option.rect, option.palette.background());
painter->fillRect( option.rect, option.palette.window());
painter->restore();
QPixmap pixmap(option.rect.size());
@ -109,9 +111,9 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
BoardPostDisplayWidget_compact w(post,displayFlags(post.mMeta.mMsgId),nullptr);
w.setFixedSize(option.rect.size());
w.updateGeometry();
w.adjustSize();
w.render(&pixmap,QPoint(0,0),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
}
else
@ -121,6 +123,7 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
w.setFixedSize(option.rect.size());
w.updateGeometry();
w.adjustSize();
w.render(&pixmap,QPoint(0,0),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
}
@ -145,6 +148,10 @@ void PostedPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem &
painter->save();
painter->drawPixmap(option.rect.topLeft(), pixmap /*,.scaled(option.rect.width(),option.rect.width()*w.height()/(float)w.width(),Qt::KeepAspectRatio,Qt::SmoothTransformation)*/);
#ifdef DEBUG_POSTED
painter->drawText(option.rect.bottomLeft(),QString::number(time(nullptr)));
RS_DBG("DisplayMode=", mDisplayMode == BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT? "Compact":"Card", " Title:", post.mMeta.mMsgName.c_str());
#endif
painter->restore();
}
@ -193,40 +200,46 @@ uint8_t PostedPostDelegate::displayFlags(const RsGxsMessageId &id) const
QWidget *PostedPostDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const
{
RsPostedPost post = index.data(Qt::UserRole).value<RsPostedPost>() ;
if(index.column() == RsPostedPostsModel::COLUMN_POSTS)
{
QWidget *w ;
if (!index.isValid())
return nullptr;
if(mDisplayMode==BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT)
w = new BoardPostDisplayWidget_compact(post,displayFlags(post.mMeta.mMsgId),parent);
else
w = new BoardPostDisplayWidget_card(post,displayFlags(post.mMeta.mMsgId),parent);
if(index.column() != RsPostedPostsModel::COLUMN_POSTS)
return nullptr;
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(voteMsg(RsGxsGrpMsgIdPair,bool)));
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(expandItem(RsGxsMessageId,bool)));
QObject::connect(w,SIGNAL(commentsRequested(const RsGxsMessageId&,bool)),mPostListWidget,SLOT(openComments(const RsGxsMessageId&)));
QObject::connect(w,SIGNAL(changeReadStatusRequested(const RsGxsMessageId&,bool)),mPostListWidget,SLOT(changeReadStatus(const RsGxsMessageId&,bool)));
QWidget *w ;
RsPostedPost post = index.data(Qt::UserRole).value<RsPostedPost>() ;
// All other interactions with the widget should cause the msg to be set as read.
QObject::connect(w,SIGNAL(thumbnailOpenned()),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(commentsRequested(const RsGxsMessageId&,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(shareButtonClicked()),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(copylinkClicked()),mPostListWidget,SLOT(copyMessageLink()));
#ifdef DEBUG_POSTED
RS_DBG("Title:", post.mMeta.mMsgName.c_str());
#endif
w->setFixedSize(option.rect.size());
w->adjustSize();
w->updateGeometry();
w->adjustSize();
if(mDisplayMode==BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT)
w = new BoardPostDisplayWidget_compact(post,displayFlags(post.mMeta.mMsgId),parent);
else
w = new BoardPostDisplayWidget_card(post,displayFlags(post.mMeta.mMsgId),parent);
return w;
}
else
return NULL;
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(voteMsg(RsGxsGrpMsgIdPair,bool)));
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(expandItem(RsGxsMessageId,bool)));
QObject::connect(w,SIGNAL(commentsRequested(RsGxsMessageId,bool)),mPostListWidget,SLOT(openComments(RsGxsMessageId)));
QObject::connect(w,SIGNAL(changeReadStatusRequested(RsGxsMessageId,bool)),mPostListWidget,SLOT(changeReadStatus(RsGxsMessageId,bool)));
// All other interactions with the widget should cause the msg to be set as read.
QObject::connect(w,SIGNAL(thumbnailOpenned()),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(commentsRequested(RsGxsMessageId,bool)),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(shareButtonClicked()),mPostListWidget,SLOT(markCurrentPostAsRead()));
QObject::connect(w,SIGNAL(copylinkClicked()),mPostListWidget,SLOT(copyMessageLink()));
w->setGeometry(option.rect);
w->adjustSize();
w->updateGeometry();
w->adjustSize();
return w;
}
void PostedPostDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
@ -264,13 +277,11 @@ PostedListWidgetWithModel::PostedListWidgetWithModel(const RsGxsGroupId& postedI
connect(ui->nextButton,SIGNAL(clicked()),this,SLOT(nextPosts()));
connect(ui->prevButton,SIGNAL(clicked()),this,SLOT(prevPosts()));
connect(ui->postsTree,SIGNAL(customContextMenuRequested(const QPoint&)),this,SLOT(postContextMenu(const QPoint&)));
connect(ui->postsTree,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(postContextMenu(QPoint)));
connect(ui->viewModeButton,SIGNAL(clicked()),this,SLOT(switchDisplayMode()));
connect(mPostedPostsModel,SIGNAL(boardPostsLoaded()),this,SLOT(postPostLoad()));
QFontMetricsF fm(font());
/* Setup UI helper */
/* Connect signals */
@ -374,23 +385,20 @@ void PostedListWidgetWithModel::filterItems(QString text)
void PostedListWidgetWithModel::nextPosts()
{
ui->postsTree->selectionModel()->clear();
if(mPostedPostsModel->displayedStartPostIndex() + POSTS_CHUNK_SIZE < mPostedPostsModel->filteredPostsCount())
{
mPostedPostsModel->setPostsInterval(POSTS_CHUNK_SIZE+mPostedPostsModel->displayedStartPostIndex(),POSTS_CHUNK_SIZE);
if(mPostedPostsModel->displayedStartPostIndex() + POSTS_CHUNK_SIZE < mPostedPostsModel->filteredPostsCount())
{
mPostedPostsModel->setPostsInterval(POSTS_CHUNK_SIZE+mPostedPostsModel->displayedStartPostIndex(),POSTS_CHUNK_SIZE);
updateShowLabel();
}
}
}
void PostedListWidgetWithModel::prevPosts()
{
ui->postsTree->selectionModel()->clear();
if((int)mPostedPostsModel->displayedStartPostIndex() > 0)
{
mPostedPostsModel->setPostsInterval((int)mPostedPostsModel->displayedStartPostIndex()-POSTS_CHUNK_SIZE,POSTS_CHUNK_SIZE);
updateShowLabel();
}
if((int)mPostedPostsModel->displayedStartPostIndex() > 0)
{
mPostedPostsModel->setPostsInterval((int)mPostedPostsModel->displayedStartPostIndex()-POSTS_CHUNK_SIZE,POSTS_CHUNK_SIZE);
updateShowLabel();
}
}
void PostedListWidgetWithModel::showAuthorInPeople()
@ -490,29 +498,30 @@ void PostedListWidgetWithModel::handleEvent_main_thread(std::shared_ptr<const Rs
switch(e->mPostedEventCode)
{
case RsPostedEventCode::NEW_COMMENT: // [[fallthrough]];
case RsPostedEventCode::NEW_VOTE: // [[fallthrough]];
{
// special treatment here because the message might be a comment, so we need to refresh the comment tab if openned
case RsPostedEventCode::NEW_COMMENT: [[fallthrough]];
case RsPostedEventCode::NEW_VOTE:
{
// special treatment here because the message might be a comment, so we need to refresh the comment tab if openned
for(int i=2;i<ui->tabWidget->count();++i)
{
auto *t = dynamic_cast<GxsCommentDialog*>(ui->tabWidget->widget(i));
for(int i=2;i<ui->tabWidget->count();++i)
{
auto *t = dynamic_cast<GxsCommentDialog*>(ui->tabWidget->widget(i));
if(t->groupId() == e->mPostedGroupId)
t->refresh();
}
}
case RsPostedEventCode::NEW_MESSAGE: // [[fallthrough]];
case RsPostedEventCode::NEW_POSTED_GROUP: // [[fallthrough]];
case RsPostedEventCode::UPDATED_POSTED_GROUP: // [[fallthrough]];
case RsPostedEventCode::UPDATED_MESSAGE:
case RsPostedEventCode::BOARD_DELETED:
case RsPostedEventCode::SYNC_PARAMETERS_UPDATED:
{
if(t->groupId() == e->mPostedGroupId)
t->refresh();
}
}
[[clang::fallthrough]];
case RsPostedEventCode::NEW_MESSAGE: [[fallthrough]];
case RsPostedEventCode::NEW_POSTED_GROUP: [[fallthrough]];
case RsPostedEventCode::UPDATED_POSTED_GROUP: [[fallthrough]];
case RsPostedEventCode::UPDATED_MESSAGE: [[fallthrough]];
case RsPostedEventCode::BOARD_DELETED: [[fallthrough]];
case RsPostedEventCode::SYNC_PARAMETERS_UPDATED:
{
if(e->mPostedGroupId == groupId())
updateDisplay(true);
}
}
default:
break;

View File

@ -251,7 +251,7 @@ p, li { white-space: pre-wrap; }
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -310,7 +310,7 @@ p, li { white-space: pre-wrap; }
</property>
<property name="font">
<font>
<pointsize>11</pointsize>
<pointsize>25</pointsize>
<weight>75</weight>
<italic>true</italic>
<bold>true</bold>

View File

@ -381,7 +381,7 @@ void ChatWidget::init(const ChatId &chat_id, const QString &title)
hist_chat_type = RS_HISTORY_TYPE_PUBLIC;
messageCount = Settings->getPublicChatHistoryCount();
ui->titleBarFrame->setVisible(false);
ui->headerBFrame->setVisible(false);
}
if (rsHistory->getEnable(hist_chat_type))

View File

@ -32,7 +32,7 @@
<enum>QLayout::SetMaximumSize</enum>
</property>
<item>
<widget class="QFrame" name="titleBarFrame">
<widget class="QFrame" name="headerBFrame">
<property name="minimumSize">
<size>
<width>0</width>
@ -51,7 +51,7 @@
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<layout class="QHBoxLayout" name="titleBarFrameHLayout">
<layout class="QHBoxLayout" name="headerBFrameHLayout">
<property name="leftMargin">
<number>2</number>
</property>

View File

@ -18,42 +18,73 @@
* *
*******************************************************************************/
#include <QPainter>
#include <QResizeEvent>
#include "RSTreeView.h"
RSTreeView::RSTreeView(QWidget *parent) : QTreeView(parent)
#include "util/rsdebug.h"
#include <QPainter>
#include <QResizeEvent>
//#define DEBUG_RSTREEVIEW
RSTreeView::RSTreeView(QWidget *parent)
: QTreeView(parent), autoSelect(false)
{
setMouseTracking(false); // normally the default, but who knows if it's not goign to change in the future.
setMouseTracking(false); // normally the default, but who knows if it's not going to change in the future.
}
void RSTreeView::wheelEvent(QWheelEvent *e)
{
if(e->modifiers() == Qt::ControlModifier)
{
emit zoomRequested(e->delta() > 0);
return;
}
else
QTreeView::wheelEvent(e);
if(e->modifiers() == Qt::ControlModifier)
{
emit zoomRequested(e->angleDelta().y() > 0);
return;
}
else
QTreeView::wheelEvent(e);
}
void RSTreeView::mouseMoveEvent(QMouseEvent *e)
{
QModelIndex idx = indexAt(e->pos());
#ifdef DEBUG_RSTREEVIEW
RS_DBG(e->localPos().x(), ":", e->localPos().y());
#endif
if (autoSelect)
{
QModelIndex idx = indexAt(e->pos());
if(idx.isValid() && idx != selectionModel()->currentIndex())
selectionModel()->setCurrentIndex(idx,QItemSelectionModel::ClearAndSelect);
if(idx.isValid() && idx != selectionModel()->currentIndex())
{
#ifdef DEBUG_RSTREEVIEW
RS_DBG("Selection changed");
#endif
selectionModel()->setCurrentIndex(idx,QItemSelectionModel::ClearAndSelect);
}
}
QTreeView::mouseMoveEvent(e);
QTreeView::mouseMoveEvent(e);
}
void RSTreeView::leaveEvent(QEvent *e)
{
#ifdef DEBUG_RSTREEVIEW
RS_DBG("");
#endif
if (autoSelect)
{
auto fp = focusPolicy();
setFocusPolicy(Qt::NoFocus); // To not select first index when resetting current index.
selectionModel()->setCurrentIndex(QModelIndex(),QItemSelectionModel::Clear); // Close editor
setFocusPolicy(fp);
}
QTreeView::leaveEvent(e);
}
void RSTreeView::setAutoSelect(bool b)
{
if(b)
setMouseTracking(true);
else
setMouseTracking(false);
autoSelect = b; // Keep this because setMouseTracking can be called outside.
setMouseTracking(b);
}
void RSTreeView::resizeEvent(QResizeEvent *e)

View File

@ -29,26 +29,34 @@ class RSTreeView : public QTreeView
Q_OBJECT
public:
RSTreeView(QWidget *parent = 0);
RSTreeView(QWidget *parent = nullptr);
/**
* @brief set Placeholder Text
* @param text
*/
void setPlaceholderText(const QString &text);
// Use this to make selection automatic based on mouse position. This is useful to trigger selection and therefore editing mode
// in trees that show editing widgets using a QStyledItemDelegate
void setAutoSelect(bool b);
/**
* @brief Use this to make selection automatic based on mouse position.
* This is useful to trigger selection and therefore editing mode in trees that show editing widgets using a QStyledItemDelegate.
* @param b
*/
void setAutoSelect(bool b);
signals:
void sizeChanged(QSize);
void zoomRequested(bool zoom_or_unzoom);
void sizeChanged(QSize);
void zoomRequested(bool zoom_or_unzoom);
protected:
virtual void mouseMoveEvent(QMouseEvent *e) override; // overriding so as to manage auto-selection
virtual void leaveEvent(QEvent *e) override; // overriding so as to manage auto-selection clear
virtual void wheelEvent(QWheelEvent *e) override; // overriding so as to manage zoom
virtual void resizeEvent(QResizeEvent *e) override;
virtual void resizeEvent(QResizeEvent *e) override;
virtual void paintEvent(QPaintEvent *event) override;
QString placeholderText;
bool autoSelect;
};
#endif

View File

@ -39,6 +39,7 @@
#include "ConnectFriendWizard.h"
#include "ui_ConnectFriendWizard.h"
#include "gui/common/PeerDefs.h"
#include "gui/connect/ConfCertDialog.h"
#include "gui/notifyqt.h"
#include "gui/common/GroupDefs.h"
#include "gui/msgs/MessageComposer.h"
@ -572,6 +573,16 @@ void ConnectFriendWizard::initializePage(int id)
ui->ipEdit->setText(s);
ui->signersEdit->setPlainText(ts);
ui->knownIpLabel->setHidden(peerDetails.ipAddressList.empty());
ui->knownIpEdit->setHidden(peerDetails.ipAddressList.empty());
{
QString ipList;
for(auto& it : peerDetails.ipAddressList)
ipList.append(QString::fromStdString(it) + "\n");
ui->knownIpEdit->setPlainText(ipList);
}
fillGroups(this, ui->groupComboBox, groupId);
if(peerDetails.isHiddenNode)
@ -587,15 +598,16 @@ void ConnectFriendWizard::initializePage(int id)
}
if(mIsShortInvite)
{
ui->nameEdit->setText(tr("[Unknown]"));
ui->addKeyToKeyring_CB->setChecked(false);
ui->addKeyToKeyring_CB->setEnabled(false);
if(ui->nameEdit->text().isEmpty())
ui->nameEdit->setText(tr("[Unknown]"));
ui->addKeyToKeyring_CB->setChecked(false);
ui->addKeyToKeyring_CB->setEnabled(false);
ui->signersEdit->hide();
ui->signersLabel->hide();
ui->signGPGCheckBox->setChecked(false);
ui->signGPGCheckBox->setEnabled(false);
ui->acceptNoSignGPGCheckBox->setChecked(true);
ui->acceptNoSignGPGCheckBox->setEnabled(false);
ui->signGPGCheckBox->setChecked(false);
ui->signGPGCheckBox->setEnabled(false);
ui->acceptNoSignGPGCheckBox->setChecked(true);
ui->acceptNoSignGPGCheckBox->setEnabled(false);
}
ui->ipEdit->setTextInteractionFlags(Qt::TextSelectableByMouse);
@ -856,30 +868,30 @@ void ConnectFriendWizard::cleanFriendCert()
{
bool certValid = false;
QString errorMsg ;
QString certDetail;
std::string cert = ui->friendCertEdit->toPlainText().toUtf8().constData();
if (cert.empty()) {
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
ui->friendCertCleanLabel->setToolTip("");
ui->friendCertCleanLabel->setStyleSheet("");
errorMsg = tr("");
} else {
std::string cleanCert;
uint32_t error_code;
RsPeerDetails details;
if (rsPeers->cleanCertificate(cert, cleanCert, mIsShortInvite, error_code))
{
if (rsPeers->cleanCertificate(cert, cleanCert, mIsShortInvite, error_code, details))
{
certValid = true;
if (cert != cleanCert)
{
{
QTextCursor textCursor = ui->friendCertEdit->textCursor();
whileBlocking(ui->friendCertEdit)->setPlainText(QString::fromUtf8(cleanCert.c_str()));
whileBlocking(ui->friendCertEdit)->setTextCursor(textCursor);
ui->friendCertCleanLabel->setStyleSheet("");
certDetail = ConfCertDialog::getCertificateDescription(details,false,mIsShortInvite,!details.ipAddressList.empty());
}
if (mIsShortInvite)
@ -887,7 +899,7 @@ void ConnectFriendWizard::cleanFriendCert()
else
errorMsg = tr("Valid certificate") ;
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png"));
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png"));
} else {
if (error_code > 0) {
switch (error_code) {
@ -903,16 +915,17 @@ void ConnectFriendWizard::cleanFriendCert()
default:
errorMsg = tr("Not a valid Retroshare certificate!") ;
ui->friendCertCleanLabel->setStyleSheet("QLabel#friendCertCleanLabel {border: 1px solid #DCDC41; border-radius: 6px; background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #FFFFD7, stop:1 #FFFFB2);}");
}
}
ui->friendCertCleanLabel->setPixmap(FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
}
}
ui->friendCertCleanLabel->setPixmap(certValid ? FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png") : FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
ui->friendCertCleanLabel->setToolTip(errorMsg);
ui->friendCertCleanLabel->setPixmap(certValid ? FilesDefs::getPixmapFromQtResourcePath(":/images/accepted16.png") : FilesDefs::getPixmapFromQtResourcePath(":/images/delete.png"));
ui->friendCertCleanLabel->setToolTip("<p>" + errorMsg + (certValid ? "\n" + certDetail : "") + "</p>");
ui->friendCertCleanLabel->setText(errorMsg);
ui->friendCertCleanLabel->setProperty("WrongValue", !certValid && !errorMsg.isEmpty());
ui->friendCertCleanLabel->style()->unpolish(ui->friendCertCleanLabel);
ui->friendCertCleanLabel->style()->polish( ui->friendCertCleanLabel);
ui->TextPage->setComplete(certValid);
}

Some files were not shown because too many files have changed in this diff Show More