mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-25 15:39:27 -05:00
fixed merge with master
This commit is contained in:
commit
d8b193c10b
@ -6,12 +6,16 @@ TEMPLATE = subdirs
|
||||
SUBDIRS += openpgpsdk
|
||||
openpgpsdk.file = openpgpsdk/src/openpgpsdk.pro
|
||||
|
||||
SUBDIRS += libbitdht
|
||||
libbitdht.file = libbitdht/src/libbitdht.pro
|
||||
retrotor {
|
||||
libretroshare.depends = openpgpsdk
|
||||
} else {
|
||||
SUBDIRS += libbitdht
|
||||
libbitdht.file = libbitdht/src/libbitdht.pro
|
||||
libretroshare.depends = openpgpsdk libbitdht
|
||||
}
|
||||
|
||||
SUBDIRS += libretroshare
|
||||
libretroshare.file = libretroshare/src/libretroshare.pro
|
||||
libretroshare.depends = openpgpsdk libbitdht
|
||||
|
||||
SUBDIRS += libresapi
|
||||
libresapi.file = libresapi/src/libresapi.pro
|
||||
@ -24,12 +28,15 @@ retroshare_gui {
|
||||
retroshare_gui.target = retroshare_gui
|
||||
}
|
||||
|
||||
retrotor {
|
||||
} else {
|
||||
retroshare_nogui {
|
||||
SUBDIRS += retroshare_nogui
|
||||
retroshare_nogui.file = retroshare-nogui/src/retroshare-nogui.pro
|
||||
retroshare_nogui.depends = libretroshare libresapi
|
||||
retroshare_nogui.target = retroshare_nogui
|
||||
}
|
||||
}
|
||||
|
||||
retroshare_android_service {
|
||||
SUBDIRS += retroshare_android_service
|
||||
|
3
build_scripts/AppImage/makeAppImage_retrotor.sh
Executable file
3
build_scripts/AppImage/makeAppImage_retrotor.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
./Recipe retrotor.yml
|
||||
|
20
build_scripts/AppImage/retrotor.yml
Normal file
20
build_scripts/AppImage/retrotor.yml
Normal file
@ -0,0 +1,20 @@
|
||||
app: retroshare
|
||||
union: true
|
||||
|
||||
ingredients:
|
||||
dist: trusty
|
||||
sources:
|
||||
- deb http://archive.ubuntu.com/ubuntu trusty main restricted universe multiverse
|
||||
- deb http://archive.ubuntu.com/ubuntu trusty-updates main restricted universe multiverse
|
||||
- deb http://deb.torproject.org/torproject.org/ trusty main
|
||||
ppas:
|
||||
- retroshare/testing
|
||||
packages:
|
||||
- libqt5svg5
|
||||
- tor
|
||||
- retrotor
|
||||
|
||||
script:
|
||||
- rm -rf usr/share/glib-2.0/schemas/
|
||||
- sed -i -e 's|/usr/share/pixmaps/||g' retroshare.desktop
|
||||
- sed -i -e 's|/usr/bin/||g' retroshare.desktop
|
@ -1,5 +1,106 @@
|
||||
retroshare (0.6.3-1.XXXXXX~YYYYYY) YYYYYY; urgency=low
|
||||
|
||||
9352a7c csoler Thu, 8 Feb 2018 10:34:46 +0100 Merge pull request #1168 from PhenomRetroShare/Add_ConnFilterInFriendSel
|
||||
bf8bd4b Phenom Wed, 7 Feb 2018 19:00:08 +0100 Add Only Connected in FriendSelectionWidget.
|
||||
7bb8eb0 csoler Wed, 7 Feb 2018 16:06:54 +0100 Merge pull request #1166 from PhenomRetroShare/Add_ChatRoomRSLink
|
||||
02b61b2 csoler Wed, 7 Feb 2018 15:58:12 +0100 Merge pull request #1164 from aral/patch-1
|
||||
a496e6f Phenom Sun, 4 Feb 2018 17:51:26 +0100 Add Chat Room RSLink
|
||||
ed88b34 Aral B Sun, 4 Feb 2018 10:37:45 +0100 Fix typo in Mac install guide
|
||||
b662e66 Gioacc Fri, 2 Feb 2018 00:20:14 +0100 Qml app fix disappearing sidebar buttons
|
||||
6c85075 csoler Thu, 1 Feb 2018 21:35:54 +0100 lobby->room in Identities dialog
|
||||
36e20db Gioacc Thu, 1 Feb 2018 21:26:36 +0100 Fix some glitches in qml app menu
|
||||
6e093c7 Gioacc Thu, 1 Feb 2018 14:59:08 +0100 Qml token manager removed unuseful debug message
|
||||
2d00532 Gioacc Thu, 1 Feb 2018 14:42:46 +0100 Qml app fix sidebar buttons hiding behaviour
|
||||
1c698bf Gioacc Thu, 1 Feb 2018 14:31:07 +0100 Qml App add option to control DHT behaviour
|
||||
9a9fcca Gioacc Thu, 1 Feb 2018 14:22:33 +0100 Qml App token manager offer unregister token API
|
||||
1e3d2c2 csoler Tue, 30 Jan 2018 20:55:01 +0100 Merge pull request #1160 from G10h4ck/android_service_cleaning
|
||||
6f91b93 Gioacc Tue, 30 Jan 2018 20:07:51 +0100 Add some sanity check in libresapiclient
|
||||
4d60850 Gioacc Tue, 30 Jan 2018 18:25:04 +0100 More cleanup of .pro files
|
||||
0012586 Gioacc Tue, 30 Jan 2018 18:24:03 +0100 Add support for SQLCipher on Android
|
||||
ebfe50f Gioacc Tue, 30 Jan 2018 18:11:31 +0100 Make .pro files compiler agnostic on Android
|
||||
da2fc01 Gioacc Tue, 30 Jan 2018 18:04:24 +0100 Cleanup a bit libresapi.pro
|
||||
180a5b1 Gioacc Tue, 30 Jan 2018 18:02:55 +0100 Remove unnecessary dependencies in android-notify-service
|
||||
feae9f5 Gioacc Tue, 30 Jan 2018 00:36:19 +0100 Fix some compiler warnings
|
||||
fc5ed14 Gioacc Mon, 29 Jan 2018 22:44:04 +0100 Android toolchain builder libraries update
|
||||
fa71ed2 Gioacc Mon, 29 Jan 2018 13:26:43 +0100 Install bdboot.txt in Android
|
||||
2d8493f Gioacc Mon, 29 Jan 2018 10:56:12 +0100 Add link on how help confused gdb to give stacktrace
|
||||
efe78f5 csoler Sun, 28 Jan 2018 21:54:56 +0100 slight optimization to showEvent() and save/restore visible items in file lists
|
||||
d598a01 Gioacc Sun, 28 Jan 2018 11:38:14 +0100 ApiLocalListener do some sanity check on listen
|
||||
5a63ce8 Gioacc Sun, 28 Jan 2018 11:36:51 +0100 Android service avoid shouldexit timer using all CPU available
|
||||
3e5ed6a Gioacc Fri, 26 Jan 2018 00:18:31 +0100 Update Androig gdb debug instructions
|
||||
c39b3e5 Gioacc Thu, 25 Jan 2018 16:20:25 +0100 Better debug messages for Android app
|
||||
ac9a843 Gioacc Thu, 25 Jan 2018 15:50:12 +0100 Gracefully handle signals in retroshare-android-service
|
||||
8c21bfc Gioacc Thu, 25 Jan 2018 15:18:12 +0100 Avoid crash on stop in ApiServerLocal
|
||||
c1d8d6a Gioacc Thu, 25 Jan 2018 15:14:09 +0100 Properly run Qt event loop
|
||||
d80a806 csoler Thu, 25 Jan 2018 09:37:31 +0100 Merge pull request #1159 from csoler/v0.6-FileLists
|
||||
11eef05 csoler Wed, 24 Jan 2018 22:02:49 +0100 fixed bug causing hidden/expanded items to be reset by show() event in SharedFilesDialog
|
||||
1fbd9d1 csoler Wed, 24 Jan 2018 21:26:35 +0100 fixed hiding of top level items when searching
|
||||
f139685 csoler Wed, 24 Jan 2018 21:14:26 +0100 added a fair limit to search in FL in order to avoid crazy costs
|
||||
d93e259 csoler Wed, 24 Jan 2018 00:26:22 +0100 fixed expanding/collapsing of items on search
|
||||
1ee353c csoler Tue, 23 Jan 2018 22:18:35 +0100 improved efficiency of search in tree visualization mode. Re-enabled the search for testing purpose.
|
||||
725abad csoler Tue, 23 Jan 2018 22:18:02 +0100 fixed a bug in filterItems that caused searched files to generate an error in the console
|
||||
9b286c4 Gioacc Tue, 23 Jan 2018 11:13:03 +0100 add to README that DHT is not working on android
|
||||
000bbbd Gioacc Tue, 23 Jan 2018 10:33:00 +0100 Add link to Android debugging documentation
|
||||
7afa19e csoler Sun, 21 Jan 2018 22:23:08 +0100 removed search from tree view in file lists, until I find some way to do it more efficiently
|
||||
7448ff4 csoler Sun, 21 Jan 2018 19:07:37 +0100 re-enabled search in file lists tree view
|
||||
d21a5e5 csoler Sat, 20 Jan 2018 19:25:52 +0100 Merge pull request #1157 from PhenomRetroShare/Fix_IconCacheInFilesDefs
|
||||
f74ee5c Phenom Sat, 20 Jan 2018 17:21:37 +0100 Move File Icon Cache in FilesDefs
|
||||
7652821 Phenom Sat, 20 Jan 2018 17:18:50 +0100 Revert "patch from sss to cache TransfersDialog QIcons"
|
||||
4c626e0 csoler Mon, 15 Jan 2018 23:17:09 +0100 Merge pull request #1152 from csoler/v0.6-SecurityFixes
|
||||
841fee6 csoler Mon, 15 Jan 2018 23:13:42 +0100 fixed possible crash due to accessing deleted memory in database cache access
|
||||
7cac367 csoler Sun, 14 Jan 2018 22:39:50 +0100 removed warnign about bad service string when the service string is actually empty
|
||||
388b2c2 csoler Fri, 12 Jan 2018 22:47:42 +0100 patch from sss to cache TransfersDialog QIcons
|
||||
783e918 csoler Fri, 12 Jan 2018 22:19:52 +0100 Merge pull request #1151 from csoler/v0.6-SecurityFixes
|
||||
bbd8afe csoler Thu, 11 Jan 2018 18:14:20 +0100 Merge pull request #1150 from chelovechishko/unfocus_chat_text_edit
|
||||
173336e csoler Thu, 11 Jan 2018 18:12:22 +0100 Merge pull request #1148 from chelovechishko/qdarkstyle_fix
|
||||
b4ff14c csoler Thu, 11 Jan 2018 18:06:48 +0100 Merge pull request #1144 from PhenomRetroShare/Fix_DisableYesButtonOnInvite
|
||||
bb9dcbb Phenom Fri, 5 Jan 2018 14:45:29 +0100 Disable Yes button on chat room invitation if no Id selected.
|
||||
add9c1e chelov Wed, 10 Jan 2018 20:53:43 +0900 chatwidget: do not set focus to edit when it is not necessary
|
||||
4eea5a8 csoler Wed, 10 Jan 2018 00:10:08 +0100 removed consts in GrpMetaCache pointers, and made it possible to always re=use cache entries, possibly updating them
|
||||
553ab93 csoler Tue, 9 Jan 2018 22:18:01 +0100 Merge pull request #1149 from csoler/v0.6-SecurityFixes
|
||||
506190a csoler Tue, 9 Jan 2018 22:11:11 +0100 fixed bug causing failure of flag actions on groups
|
||||
ed81b4c csoler Tue, 9 Jan 2018 21:49:15 +0100 removed delete causing read of deleted memory
|
||||
51c7942 csoler Mon, 8 Jan 2018 19:08:10 +0100 Merge pull request #1146 from csoler/v0.6-SecurityFixes
|
||||
e261d45 chelov Mon, 8 Jan 2018 16:16:10 +0900 gui: fix networkdialog colors once more in qdarkstyle.qss
|
||||
f8f61cc chelov Mon, 8 Jan 2018 16:02:40 +0900 gui: fix colors for idtree of people in qdarkstyle.qss
|
||||
884bbb4 chelov Mon, 8 Jan 2018 15:58:04 +0900 gui: make friendlist more readable in some places in qdarkstyle.qss
|
||||
622316a chelov Mon, 8 Jan 2018 15:49:05 +0900 gui: improve readability of sharemanager for qdarkstyle.qss
|
||||
5e57cb4 csoler Sun, 7 Jan 2018 23:02:22 +0100 fixed gxs unit tests
|
||||
85b94d7 csoler Sun, 7 Jan 2018 22:36:49 +0100 fixed test compilation
|
||||
89c538d csoler Sun, 7 Jan 2018 22:36:38 +0100 fixed double deletion problem causing crashes
|
||||
b42b8e3 csoler Sun, 7 Jan 2018 21:41:41 +0100 moved memory ownership of RsGxsGrpMetaData down into RsGxsDataAccess. Avoids many copy-constructors of RsTlvSecurityKey. Will probably spare a lot of CPU on windows
|
||||
c3e300e Gioacc Sat, 6 Jan 2018 22:53:26 +0100 Merge pull request #1140 from Emotyco/libresapi_small_corrections
|
||||
67fc6a3 Konrad Sat, 6 Jan 2018 19:29:56 +0100 Fixed in Libresapi: Double declaration of StateToken in FileSharingHandler
|
||||
575a416 Konrad Sat, 6 Jan 2018 19:09:44 +0100 Changed in Libresapi: Used Doxigen style comments
|
||||
d53993c Konrad Sat, 6 Jan 2018 18:39:47 +0100 Changed in Libresapi: Pointer to RsNotify object into reference
|
||||
57f41d9 csoler Fri, 5 Jan 2018 21:27:18 +0100 Merge pull request #1145 from PhenomRetroShare/Fix_ClearPersonDetailIfNoSelection
|
||||
4026040 Konrad Fri, 5 Jan 2018 20:44:48 +0100 Libresapi: Extended ChatInfo class to contain own identity used in chat
|
||||
4f902bb Phenom Fri, 5 Jan 2018 17:48:18 +0100 Clear Person Detail when no selection
|
||||
0078b9c csoler Wed, 3 Jan 2018 20:33:25 +0100 Merge pull request #1143 from csoler/v0.6-SecurityFixes
|
||||
98d1d08 csoler Wed, 3 Jan 2018 20:32:37 +0100 removed extra links from chat widget, since normal links can be used now to DL through encrypted tunnels
|
||||
ee81eef csoler Wed, 3 Jan 2018 18:42:04 +0100 Merge pull request #1142 from csoler/v0.6-SecurityFixes
|
||||
ab60f49 csoler Wed, 3 Jan 2018 18:37:43 +0100 prevent sending/receiving of IP addresses to/at hidden nodes
|
||||
0a92710 csoler Wed, 3 Jan 2018 15:03:23 +0100 Merge pull request #1141 from csoler/v0.6-SecurityFixes
|
||||
0f6006d csoler Wed, 3 Jan 2018 15:01:04 +0100 prevent subscribing to a signed chat room without a signed identity
|
||||
eea0c64 csoler Wed, 3 Jan 2018 14:05:13 +0100 require signed identity to respond to a signed chat room invite. Avoids "god mode" bug.
|
||||
96e7507 Konrad Mon, 1 Jan 2018 23:38:07 +0100 Added in Libresapi: Short comment to FileSharingHandler
|
||||
9bb6adc Konrad Mon, 1 Jan 2018 23:27:46 +0100 Added in Libresapi: Missing mutex locking in TransfersHandler
|
||||
6a61e0a Konrad Mon, 1 Jan 2018 23:20:26 +0100 Changed in Libresapi: Locking mutex using macro instead of RsStackMutex object creation
|
||||
74a56f6 Konrad Fri, 29 Dec 2017 16:07:39 +0100 Changed in Libresapi: Closing distant connection (chat) requires now ChatId that is used in other functions, instead of DistantCharPeerId
|
||||
4b25684 Konrad Fri, 29 Dec 2017 16:03:45 +0100 Added in Libresapi: Functions to get and set default identity for lobby
|
||||
b24d772 Konrad Wed, 27 Dec 2017 22:38:04 +0100 Added in Libresapi: Getting node name in PeersHandler
|
||||
2db25d4 Konrad Wed, 27 Dec 2017 22:37:14 +0100 Added in Libresapi: StateToken refreshing to TransferHandler
|
||||
53118e5 Konrad Wed, 27 Dec 2017 22:35:51 +0100 Added in Libresapi: Missing bracket in ChatHandler
|
||||
92df847 Konrad Wed, 27 Dec 2017 22:33:23 +0100 Added in Libresapi: StateTokens to FileSharingHandler
|
||||
55385d7 Konrad Wed, 27 Dec 2017 22:31:17 +0100 Added in Libresapi: Marking particular message as read
|
||||
49cacc4 csoler Sun, 24 Dec 2017 12:04:15 +0100 fixed compilation on ubuntu precise
|
||||
122f6af csoler Sun, 24 Dec 2017 11:06:03 +0100 fixed compilation on ubuntu precise
|
||||
72d64c7 csoler Sun, 24 Dec 2017 10:36:08 +0100 updated changelog
|
||||
|
||||
-- Retroshare Dev Team <contact@retroshare.net> Sat, 10 Feb 2018 14:00:00 +0100
|
||||
|
||||
retroshare (0.6.3-1.20171224.72d64c7d~artful) precise; urgency=low
|
||||
|
||||
c2d5579 csoler Thu, 21 Dec 2017 17:06:32 +0100 storage of chat room icons in local variables to avoid re-reading them from qrc everytime (patch from sss)
|
||||
acd8355 Gioacc Wed, 20 Dec 2017 18:24:28 +0100 Add some documentation on how to debug retroshare on android
|
||||
c0d8333 csoler Mon, 18 Dec 2017 16:10:52 +0100 Merge pull request #1136 from csoler/v0.6-FT
|
||||
|
20
build_scripts/Debian+Ubuntu/control.trusty_retrotor
Normal file
20
build_scripts/Debian+Ubuntu/control.trusty_retrotor
Normal file
@ -0,0 +1,20 @@
|
||||
Source: retroshare
|
||||
Section: devel
|
||||
Priority: standard
|
||||
Maintainer: Cyril Soler <csoler@users.sourceforge.net>
|
||||
Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: http://retroshare.net
|
||||
|
||||
Package: retrotor
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor (>= 0.2.6)
|
||||
Conflicts: retroshare-nogui,retroshare06,retroshare
|
||||
Description: Secure communication with friends
|
||||
RetroShare is a Open Source cross-platform, private and secure decentralised
|
||||
commmunication platform. It lets you to securely chat and share files with your
|
||||
friends and family, using a web-of-trust to authenticate peers and OpenSSL to
|
||||
encrypt all communication. RetroShare provides filesharing, chat, messages,
|
||||
forums and channels.
|
||||
|
||||
|
20
build_scripts/Debian+Ubuntu/control.xenial_retrotor
Normal file
20
build_scripts/Debian+Ubuntu/control.xenial_retrotor
Normal file
@ -0,0 +1,20 @@
|
||||
Source: retroshare
|
||||
Section: devel
|
||||
Priority: standard
|
||||
Maintainer: Cyril Soler <csoler@users.sourceforge.net>
|
||||
Build-Depends: debhelper (>= 7), libglib2.0-dev, libupnp-dev, libssl-dev, libxss-dev, libgnome-keyring-dev, libbz2-dev, libspeex-dev, libspeexdsp-dev, libxslt1-dev, cmake, libcurl4-openssl-dev, libopencv-dev, tcl8.6, libsqlcipher-dev, libmicrohttpd-dev, libavcodec-dev, qtmultimedia5-dev, qttools5-dev, libqt5x11extras5-dev, qt5-default
|
||||
Standards-Version: 3.9.6
|
||||
Homepage: http://retroshare.sourceforge.net
|
||||
|
||||
Package: retrotor
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, gnome-keyring, tor (>= 0.2.6)
|
||||
Conflicts: retroshare-nogui,retroshare06,retroshare
|
||||
Description: Secure communication with friends
|
||||
RetroShare is a Open Source cross-platform, private and secure decentralised
|
||||
commmunication platform. It lets you to securely chat and share files with your
|
||||
friends and family, using a web-of-trust to authenticate peers and OpenSSL to
|
||||
encrypt all communication. RetroShare provides filesharing, chat, messages,
|
||||
forums and channels.
|
||||
|
||||
|
5
build_scripts/Debian+Ubuntu/debian/retrotor.install
Normal file
5
build_scripts/Debian+Ubuntu/debian/retrotor.install
Normal file
@ -0,0 +1,5 @@
|
||||
debian/tmp/usr/bin/retroshare
|
||||
debian/tmp/usr/share/applications/retroshare.desktop
|
||||
debian/tmp/usr/share/icons/hicolor/*
|
||||
debian/tmp/usr/share/pixmaps/retroshare.xpm
|
||||
debian/tmp/usr/share/retroshare/*
|
@ -27,6 +27,7 @@ time=`git log --pretty=format:"%aD" | head -1 | cut -d\ -f5 | sed -e s/://g`
|
||||
hhsh=`git log --pretty=format:"%H" | head -1 | cut -c1-8`
|
||||
|
||||
rev=${date}.${hhsh}
|
||||
useretrotor="false"
|
||||
|
||||
while [ ${#} -gt 0 ]; do
|
||||
case ${1} in
|
||||
@ -34,6 +35,9 @@ while [ ${#} -gt 0 ]; do
|
||||
rev=${1}
|
||||
shift
|
||||
;;
|
||||
"-retrotor") shift
|
||||
useretrotor="true"
|
||||
;;
|
||||
"-distribution") shift
|
||||
dist=${1}
|
||||
shift
|
||||
@ -54,6 +58,15 @@ while [ ${#} -gt 0 ]; do
|
||||
esac
|
||||
done
|
||||
|
||||
if test "${useretrotor}" = "true"; then
|
||||
if ! test "${dist}" = "trusty"; then
|
||||
echo ERROR: retro-tor can only be packaged for trusty for now.
|
||||
exit 1;
|
||||
fi
|
||||
gitpath="https://github.com/csoler/RetroShare.git"
|
||||
branch="v0.6-TorOnly"
|
||||
fi
|
||||
|
||||
if test "${dist}" = "" ; then
|
||||
dist="precise trusty xenial zesty artful"
|
||||
fi
|
||||
@ -71,6 +84,10 @@ echo " "Hash : ${hhsh}
|
||||
echo " "Using branch : ${branch}
|
||||
echo " "Using revision : ${rev}
|
||||
|
||||
if test ${useretrotor} = "true"; then
|
||||
echo " "Specific flags : retrotor
|
||||
fi
|
||||
|
||||
echo Done.
|
||||
version="${version}"."${rev}"
|
||||
echo Got version number ${version}.
|
||||
@ -83,7 +100,7 @@ echo Extracting base archive...
|
||||
mkdir -p ${workdir}/src
|
||||
echo Checking out latest snapshot...
|
||||
cd ${workdir}/src
|
||||
git clone --depth 1 https://github.com/RetroShare/RetroShare.git --single-branch --branch $branch .
|
||||
git clone --depth 1 ${gitpath} --single-branch --branch $branch .
|
||||
|
||||
# if ! test "$hhsh" = "" ; then
|
||||
# echo Checking out revision $hhsh
|
||||
@ -121,13 +138,16 @@ for i in ${dist}; do
|
||||
echo copying changelog for ${i}
|
||||
sed -e s/XXXXXX/"${rev}"/g -e s/YYYYYY/"${i}"/g ../changelog > debian/changelog
|
||||
|
||||
if test -f ../control."${i}" ; then
|
||||
if test ${useretrotor} = "true"; then
|
||||
cp ../rules.retrotor debian/rules
|
||||
cp ../control.trusty_retrotor debian/control
|
||||
elif test -f ../control."${i}" ; then
|
||||
echo \/\!\\ Using specific control file for distribution "${i}"
|
||||
cp ../control."${i}" debian/control
|
||||
cp ../control."${i}" debian/control
|
||||
else
|
||||
echo Using standard control file control."${i}" for distribution "${i}"
|
||||
cp ../debian/control debian/control
|
||||
fi
|
||||
cp ../debian/control debian/control
|
||||
fi
|
||||
|
||||
debuild -S -k${gpgkey}
|
||||
done
|
||||
|
61
build_scripts/Debian+Ubuntu/rules.retrotor
Executable file
61
build_scripts/Debian+Ubuntu/rules.retrotor
Executable file
@ -0,0 +1,61 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
configure: configure-stamp
|
||||
configure-stamp:
|
||||
dh_testdir
|
||||
cd src && qmake "CONFIG-=debug" "CONFIG+=release retrotor" "CONFIG+=rs_autologin" PREFIX=/usr LIB_DIR=/usr/lib RetroShare.pro
|
||||
touch $@
|
||||
|
||||
|
||||
build: build-stamp
|
||||
build-stamp: configure-stamp
|
||||
dh_testdir
|
||||
# Add here commands to compile the package.
|
||||
# cd libssh-0.6.4 && mkdir -p build && cd build && cmake -DWITH_STATIC_LIB=ON .. && make
|
||||
# cd sqlcipher && ./configure --disable-shared --enable-static --enable-tempstore=yes CFLAGS="-DSQLITE_HAS_CODEC" LDFLAGS="-lcrypto" && make
|
||||
# mkdir lib
|
||||
# cp -r libssh-0.6.4 lib/
|
||||
#cp -r sqlcipher lib/
|
||||
#cd src/rsctrl/src && make
|
||||
cd src && $(MAKE)
|
||||
touch $@
|
||||
|
||||
clean:
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
rm -f configure-stamp build-stamp
|
||||
# Add here commands to clean up after the build process.
|
||||
[ ! -f src/Makefile ] || (cd src && $(MAKE) distclean)
|
||||
dh_clean
|
||||
|
||||
install: build
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_clean -k
|
||||
#dh_installdirs
|
||||
cd src && $(MAKE) INSTALL_ROOT=$(CURDIR)/debian/tmp install
|
||||
|
||||
# Build architecture-independent files here.
|
||||
binary-indep: build install
|
||||
# We have nothing to do by default.
|
||||
|
||||
# Build architecture-dependent files here.
|
||||
binary-arch: build install
|
||||
dh_testdir
|
||||
dh_testroot
|
||||
dh_install --list-missing
|
||||
#dh_installdocs
|
||||
#dh_installexamples
|
||||
#dh_installman
|
||||
dh_link
|
||||
dh_strip
|
||||
dh_compress
|
||||
dh_fixperms
|
||||
dh_installdeb
|
||||
dh_shlibdeps
|
||||
dh_gencontrol
|
||||
dh_md5sums
|
||||
dh_builddeb
|
||||
|
||||
binary: binary-indep binary-arch
|
||||
.PHONY: build clean binary-indep binary-arch binary install configure
|
@ -38,7 +38,7 @@
|
||||
#include "crypto/chacha20.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rsrandom.h"
|
||||
#include "util/rsscopetimer.h"
|
||||
#include "util/rstime.h"
|
||||
|
||||
#define rotl(x,n) { x = (x << n) | (x >> (-n & 31)) ;}
|
||||
|
||||
@ -1385,27 +1385,27 @@ bool perform_tests()
|
||||
uint8_t received_tag[16] ;
|
||||
|
||||
{
|
||||
RsScopeTimer s("AEAD1") ;
|
||||
rstime::RsScopeTimer s("AEAD1") ;
|
||||
chacha20_encrypt_rs(key, 1, nonce, ten_megabyte_data,SIZE) ;
|
||||
|
||||
std::cerr << " Chacha20 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
{
|
||||
RsScopeTimer s("AEAD2") ;
|
||||
rstime::RsScopeTimer s("AEAD2") ;
|
||||
AEAD_chacha20_poly1305_rs(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD/poly1305 own encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x010100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
{
|
||||
RsScopeTimer s("AEAD3") ;
|
||||
rstime::RsScopeTimer s("AEAD3") ;
|
||||
AEAD_chacha20_poly1305_openssl(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD/poly1305 openssl encryption speed: " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
RsScopeTimer s("AEAD4") ;
|
||||
rstime::RsScopeTimer s("AEAD4") ;
|
||||
AEAD_chacha20_sha256(key,nonce,ten_megabyte_data,SIZE,aad,12,received_tag,true) ;
|
||||
|
||||
std::cerr << " AEAD/sha256 encryption speed : " << SIZE / (1024.0*1024.0) / s.duration() << " MB/s" << std::endl;
|
||||
|
@ -23,6 +23,7 @@
|
||||
*
|
||||
*/
|
||||
#include "util/folderiterator.h"
|
||||
#include "util/rstime.h"
|
||||
#include "rsserver/p3face.h"
|
||||
|
||||
#include "directory_storage.h"
|
||||
@ -92,7 +93,7 @@ void LocalDirectoryUpdater::data_tick()
|
||||
|
||||
for(uint32_t i=0;i<10;++i)
|
||||
{
|
||||
usleep(1*1000*1000);
|
||||
rstime::rs_usleep(1*1000*1000);
|
||||
|
||||
{
|
||||
if(mForceUpdate)
|
||||
|
@ -24,7 +24,7 @@
|
||||
*/
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rsscopetimer.h"
|
||||
#include "util/rstime.h"
|
||||
#include "rsserver/p3face.h"
|
||||
#include "pqi/authssl.h"
|
||||
#include "hash_cache.h"
|
||||
@ -125,7 +125,7 @@ void HashStorage::data_tick()
|
||||
std::cerr << "nothing to hash. Sleeping for " << st << " us" << std::endl;
|
||||
#endif
|
||||
|
||||
usleep(st); // when no files to hash, just wait for 2 secs. This avoids a dramatic loop.
|
||||
rstime::rs_usleep(st); // when no files to hash, just wait for 2 secs. This avoids a dramatic loop.
|
||||
|
||||
if(st > MAX_INACTIVITY_SLEEP_TIME)
|
||||
{
|
||||
@ -163,7 +163,7 @@ void HashStorage::data_tick()
|
||||
|
||||
if(paused) // we need to wait off mutex!!
|
||||
{
|
||||
usleep(MAX_INACTIVITY_SLEEP_TIME) ;
|
||||
rstime::rs_usleep(MAX_INACTIVITY_SLEEP_TIME) ;
|
||||
std::cerr << "Hashing process currently paused." << std::endl;
|
||||
return;
|
||||
}
|
||||
@ -190,7 +190,7 @@ void HashStorage::data_tick()
|
||||
|
||||
RsServer::notify()->notifyHashingInfo(NOTIFY_HASHTYPE_HASH_FILE, tmpout) ;
|
||||
|
||||
double seconds_origin = RsScopeTimer::currentTime() ;
|
||||
double seconds_origin = rstime::RsScopeTimer::currentTime() ;
|
||||
|
||||
if(RsDirUtil::getFileHash(job.full_path, hash,size, this))
|
||||
{
|
||||
@ -215,7 +215,7 @@ void HashStorage::data_tick()
|
||||
else
|
||||
std::cerr << "ERROR: cannot hash file " << job.full_path << std::endl;
|
||||
|
||||
mHashingTime += RsScopeTimer::currentTime() - seconds_origin ;
|
||||
mHashingTime += rstime::RsScopeTimer::currentTime() - seconds_origin ;
|
||||
mHashedBytes += size ;
|
||||
|
||||
if(mHashingTime > 3)
|
||||
|
@ -40,6 +40,7 @@
|
||||
#endif
|
||||
#include "util/rsdiscspace.h"
|
||||
#include "util/rsmemory.h"
|
||||
#include "util/rstime.h"
|
||||
|
||||
#include "ft/ftcontroller.h"
|
||||
|
||||
@ -219,7 +220,7 @@ void ftController::data_tick()
|
||||
/* check the queues */
|
||||
|
||||
//Waiting 1 sec before start
|
||||
usleep(1*1000*1000); // 1 sec
|
||||
rstime::rs_usleep(1*1000*1000); // 1 sec
|
||||
|
||||
#ifdef CONTROL_DEBUG
|
||||
//std::cerr << "ftController::run()";
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "ft/ftextralist.h"
|
||||
#include "rsitems/rsconfigitems.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rstime.h"
|
||||
#include <stdio.h>
|
||||
#include <unistd.h> /* for (u)sleep() */
|
||||
#include <time.h>
|
||||
@ -64,12 +65,8 @@ void ftExtraList::data_tick()
|
||||
/* Hash a file */
|
||||
hashAFile();
|
||||
|
||||
#ifdef WIN32
|
||||
Sleep(1);
|
||||
#else
|
||||
/* microsleep */
|
||||
usleep(10);
|
||||
#endif
|
||||
rstime::rs_usleep(10);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -513,16 +510,7 @@ bool ftExtraList::loadList(std::list<RsItem *>& load)
|
||||
delete (*it);
|
||||
|
||||
/* short sleep */
|
||||
#ifndef WINDOWS_SYS
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
usleep(1000); /* 1000 per second */
|
||||
|
||||
#else
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
Sleep(1);
|
||||
#endif
|
||||
/********************************** WINDOWS/UNIX SPECIFIC PART ******************/
|
||||
|
||||
rstime::rs_usleep(1000) ;
|
||||
}
|
||||
load.clear() ;
|
||||
return true;
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef RS_DATA_SERVICE_DEBUG_TIME
|
||||
#include <util/rsscopetimer.h>
|
||||
#include <util/rstime.h>
|
||||
#endif
|
||||
|
||||
#include "rsdataservice.h"
|
||||
@ -1066,7 +1066,7 @@ bool RsDataService::validSize(RsNxsGrp* grp) const
|
||||
int RsDataService::retrieveNxsGrps(std::map<RsGxsGroupId, RsNxsGrp *> &grp, bool withMeta, bool /* cache */)
|
||||
{
|
||||
#ifdef RS_DATA_SERVICE_DEBUG_TIME
|
||||
RsScopeTimer timer("");
|
||||
rstime::RsScopeTimer timer("");
|
||||
int resultCount = 0;
|
||||
int requestedGroups = grp.size();
|
||||
#endif
|
||||
@ -1166,7 +1166,7 @@ void RsDataService::locked_retrieveGroups(RetroCursor* c, std::vector<RsNxsGrp*>
|
||||
int RsDataService::retrieveNxsMsgs(const GxsMsgReq &reqIds, GxsMsgResult &msg, bool /* cache */, bool withMeta)
|
||||
{
|
||||
#ifdef RS_DATA_SERVICE_DEBUG_TIME
|
||||
RsScopeTimer timer("");
|
||||
rstime::RsScopeTimer timer("");
|
||||
int resultCount = 0;
|
||||
#endif
|
||||
|
||||
@ -1254,7 +1254,7 @@ int RsDataService::retrieveGxsMsgMetaData(const GxsMsgReq& reqIds, GxsMsgMetaRes
|
||||
RsStackMutex stack(mDbMutex);
|
||||
|
||||
#ifdef RS_DATA_SERVICE_DEBUG_TIME
|
||||
RsScopeTimer timer("");
|
||||
rstime::RsScopeTimer timer("");
|
||||
int resultCount = 0;
|
||||
#endif
|
||||
|
||||
@ -1341,7 +1341,7 @@ int RsDataService::retrieveGxsGrpMetaData(RsGxsGrpMetaTemporaryMap& grp)
|
||||
RsStackMutex stack(mDbMutex);
|
||||
|
||||
#ifdef RS_DATA_SERVICE_DEBUG_TIME
|
||||
RsScopeTimer timer("");
|
||||
rstime::RsScopeTimer timer("");
|
||||
int resultCount = 0;
|
||||
int requestedGroups = grp.size();
|
||||
#endif
|
||||
@ -1549,7 +1549,7 @@ int RsDataService::retrieveGroupIds(std::vector<RsGxsGroupId> &grpIds)
|
||||
RsStackMutex stack(mDbMutex);
|
||||
|
||||
#ifdef RS_DATA_SERVICE_DEBUG_TIME
|
||||
RsScopeTimer timer("");
|
||||
rstime::RsScopeTimer timer("");
|
||||
int resultCount = 0;
|
||||
#endif
|
||||
|
||||
@ -1586,7 +1586,7 @@ int RsDataService::retrieveGroupIds(std::vector<RsGxsGroupId> &grpIds)
|
||||
int RsDataService::retrieveMsgIds(const RsGxsGroupId& grpId, RsGxsMessageId::std_vector& msgIds)
|
||||
{
|
||||
#ifdef RS_DATA_SERVICE_DEBUG_TIME
|
||||
RsScopeTimer timer("");
|
||||
rstime::RsScopeTimer timer("");
|
||||
int resultCount = 0;
|
||||
#endif
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "gxssecurity.h"
|
||||
#include "util/contentvalue.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rstime.h"
|
||||
#include "retroshare/rsgxsflags.h"
|
||||
#include "retroshare/rsgxscircles.h"
|
||||
#include "retroshare/rsgrouter.h"
|
||||
@ -138,7 +139,7 @@ void RsGenExchange::data_tick()
|
||||
static const double timeDelta = 0.1; // slow tick in sec
|
||||
|
||||
tick();
|
||||
usleep((int) (timeDelta * 1000 *1000)); // timeDelta sec
|
||||
rstime::rs_usleep((int) (timeDelta * 1000 *1000)); // timeDelta sec
|
||||
}
|
||||
|
||||
void RsGenExchange::tick()
|
||||
|
@ -210,6 +210,7 @@
|
||||
#include "retroshare/rspeers.h"
|
||||
#include "pgp/pgpauxutils.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rstime.h"
|
||||
#include "util/rsmemory.h"
|
||||
#include "util/stacktrace.h"
|
||||
|
||||
@ -1787,7 +1788,7 @@ void RsGxsNetService::data_tick()
|
||||
static const double timeDelta = 0.5;
|
||||
|
||||
//Start waiting as nothing to do in runup
|
||||
usleep((int) (timeDelta * 1000 * 1000)); // timeDelta sec
|
||||
rstime::rs_usleep((int) (timeDelta * 1000 * 1000)); // timeDelta sec
|
||||
|
||||
if(mUpdateCounter >= 120) // 60 seconds
|
||||
{
|
||||
|
@ -1,7 +1,7 @@
|
||||
!include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri")
|
||||
|
||||
TEMPLATE = lib
|
||||
CONFIG += staticlib bitdht
|
||||
CONFIG += staticlib
|
||||
CONFIG += create_prl
|
||||
CONFIG -= qt
|
||||
TARGET = retroshare
|
||||
@ -10,7 +10,14 @@ DESTDIR = lib
|
||||
|
||||
#CONFIG += dsdv
|
||||
|
||||
# the dht stunner is used to obtain RS' external ip addr. when it is natted
|
||||
retrotor {
|
||||
DEFINES *= RETROTOR
|
||||
CONFIG -= bitdht
|
||||
} else {
|
||||
CONFIG += bitdht
|
||||
}
|
||||
|
||||
# the dht stunner is used to obtain RS external ip addr. when it is natted
|
||||
# this system is unreliable and rs supports a newer and better one (asking connected peers)
|
||||
# CONFIG += useDhtStunner
|
||||
|
||||
@ -90,6 +97,7 @@ HEADERS += tcponudp/udppeer.h \
|
||||
tcponudp/tcpstream.h \
|
||||
tcponudp/tou.h \
|
||||
tcponudp/udprelay.h \
|
||||
pqi/pqissludp.h \
|
||||
|
||||
SOURCES += tcponudp/udppeer.cc \
|
||||
tcponudp/tcppacket.cc \
|
||||
@ -97,6 +105,7 @@ SOURCES += tcponudp/udppeer.cc \
|
||||
tcponudp/tou.cc \
|
||||
tcponudp/bss_tou.c \
|
||||
tcponudp/udprelay.cc \
|
||||
pqi/pqissludp.cc \
|
||||
|
||||
useDhtStunner {
|
||||
HEADERS += dht/stunaddrassist.h \
|
||||
@ -434,7 +443,6 @@ HEADERS += pqi/authssl.h \
|
||||
pqi/pqissllistener.h \
|
||||
pqi/pqisslpersongrp.h \
|
||||
pqi/pqissli2pbob.h \
|
||||
pqi/pqissludp.h \
|
||||
pqi/pqisslproxy.h \
|
||||
pqi/pqistore.h \
|
||||
pqi/pqistreamer.h \
|
||||
@ -539,7 +547,7 @@ HEADERS += util/folderiterator.h \
|
||||
util/rsmemcache.h \
|
||||
util/rstickevent.h \
|
||||
util/rsrecogn.h \
|
||||
util/rsscopetimer.h \
|
||||
util/rstime.h \
|
||||
util/stacktrace.h \
|
||||
util/rsdeprecate.h \
|
||||
util/cxx11retrocompat.h
|
||||
@ -590,7 +598,6 @@ SOURCES += pqi/authgpg.cc \
|
||||
pqi/pqissllistener.cc \
|
||||
pqi/pqisslpersongrp.cc \
|
||||
pqi/pqissli2pbob.cpp \
|
||||
pqi/pqissludp.cc \
|
||||
pqi/pqisslproxy.cc \
|
||||
pqi/pqistore.cc \
|
||||
pqi/pqistreamer.cc \
|
||||
@ -688,7 +695,7 @@ SOURCES += util/folderiterator.cc \
|
||||
util/rsrandom.cc \
|
||||
util/rstickevent.cc \
|
||||
util/rsrecogn.cc \
|
||||
util/rsscopetimer.cc
|
||||
util/rstime.cc
|
||||
|
||||
|
||||
upnp_miniupnpc {
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "pgp/pgphandler.h"
|
||||
|
||||
#include <util/rsdir.h>
|
||||
#include <util/rstime.h>
|
||||
#include <pgp/pgpkeyutil.h>
|
||||
#include <unistd.h> /* for (u)sleep() */
|
||||
#include <iostream>
|
||||
@ -187,7 +188,7 @@ int AuthGPG::GPGInit(const RsPgpId &ownId)
|
||||
|
||||
void AuthGPG::data_tick()
|
||||
{
|
||||
usleep(100 * 1000); //100 msec
|
||||
rstime::rs_usleep(100 * 1000); //100 msec
|
||||
|
||||
/// every 100 milliseconds
|
||||
processServices();
|
||||
|
@ -718,7 +718,7 @@ void p3NetMgrIMPL::netExtCheck()
|
||||
#endif
|
||||
if(sockaddr_storage_isValidNet(tmpip))
|
||||
{
|
||||
if(rsBanList->isAddressAccepted(tmpip,RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
if( (rsBanList==NULL) || rsBanList->isAddressAccepted(tmpip,RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
{
|
||||
// must be stable???
|
||||
isStable = true;
|
||||
@ -761,7 +761,7 @@ void p3NetMgrIMPL::netExtCheck()
|
||||
/* input network bits */
|
||||
if (mDhtStunner->getExternalAddr(tmpaddr, isstable))
|
||||
{
|
||||
if(rsBanList->isAddressAccepted(tmpaddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
if((rsBanList == NULL) || rsBanList->isAddressAccepted(tmpaddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
{
|
||||
// must be stable???
|
||||
isStable = (isstable == 1);
|
||||
|
@ -1237,7 +1237,7 @@ bool p3PeerMgrIMPL::UpdateOwnAddress(const struct sockaddr_storage &localAddr,
|
||||
std::cerr << ")" << std::endl;
|
||||
#endif
|
||||
|
||||
if(!rsBanList->isAddressAccepted(localAddr, RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
if((rsBanList != NULL) && !rsBanList->isAddressAccepted(localAddr, RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
{
|
||||
std::cerr << "(SS) Trying to set own IP to a banned IP " << sockaddr_storage_iptostring(localAddr) << ". This probably means that a friend in under traffic re-routing attack." << std::endl;
|
||||
return false ;
|
||||
@ -1376,7 +1376,7 @@ bool p3PeerMgrIMPL::setExtAddress(const RsPeerId &id, const struct sockaddr_s
|
||||
bool changed = false;
|
||||
uint32_t check_res = 0 ;
|
||||
|
||||
if(!rsBanList->isAddressAccepted(addr,RSBANLIST_CHECKING_FLAGS_BLACKLIST,&check_res))
|
||||
if(rsBanList!=NULL && !rsBanList->isAddressAccepted(addr,RSBANLIST_CHECKING_FLAGS_BLACKLIST,&check_res))
|
||||
{
|
||||
std::cerr << "(SS) trying to set external contact address for peer " << id << " to a banned address " << sockaddr_storage_iptostring(addr )<< std::endl;
|
||||
return false ;
|
||||
@ -1550,7 +1550,7 @@ bool p3PeerMgrIMPL::addCandidateForOwnExternalAddress(const RsPeerId &from, cons
|
||||
|
||||
// Notify for every friend that has reported a wrong external address, except if that address is in the IP whitelist.
|
||||
|
||||
if((!rsBanList->isAddressAccepted(addr_filtered,RSBANLIST_CHECKING_FLAGS_WHITELIST)) && (!sockaddr_storage_sameip(own_addr,addr_filtered)))
|
||||
if((rsBanList!=NULL && !rsBanList->isAddressAccepted(addr_filtered,RSBANLIST_CHECKING_FLAGS_WHITELIST)) && (!sockaddr_storage_sameip(own_addr,addr_filtered)))
|
||||
{
|
||||
std::cerr << " Peer " << from << " reports a connection address (" << sockaddr_storage_iptostring(addr_filtered) <<") that is not your current external address (" << sockaddr_storage_iptostring(own_addr) << "). This is weird." << std::endl;
|
||||
|
||||
@ -2805,7 +2805,7 @@ bool p3PeerMgrIMPL::removeBannedIps()
|
||||
if(cleanIpList(it->second.ipAddrs.mExt.mAddrs,it->first,mLinkMgr)) changed = true ;
|
||||
if(cleanIpList(it->second.ipAddrs.mLocal.mAddrs,it->first,mLinkMgr)) changed = true ;
|
||||
|
||||
if(!rsBanList->isAddressAccepted(it->second.serveraddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
if(rsBanList!=NULL && !rsBanList->isAddressAccepted(it->second.serveraddr,RSBANLIST_CHECKING_FLAGS_BLACKLIST))
|
||||
{
|
||||
sockaddr_storage_clear(it->second.serveraddr) ;
|
||||
std::cerr << "(SS) Peer " << it->first << " has a banned server address. Wiping it out." << std::endl;
|
||||
|
@ -4,7 +4,9 @@
|
||||
#include "pqi/pqinetstatebox.h"
|
||||
#include "time.h"
|
||||
|
||||
#ifdef RS_USE_BITDHT
|
||||
#include "bitdht/bdiface.h"
|
||||
#endif
|
||||
|
||||
// External Interface.
|
||||
|
||||
|
@ -1321,14 +1321,14 @@ int pqissl::Authorise_SSL_Connection()
|
||||
if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL)
|
||||
checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST;
|
||||
|
||||
if(!rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result))
|
||||
if(rsBanList!=NULL && !rsBanList->isAddressAccepted(remote_addr,checking_flags,&check_result))
|
||||
{
|
||||
std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " <<
|
||||
std::cerr << "(SS) refusing connection attempt from IP address " << sockaddr_storage_iptostring(remote_addr) << ". Reason: " <<
|
||||
((check_result == RSBANLIST_CHECK_RESULT_NOT_WHITELISTED)?"not whitelisted (peer requires whitelist)":"blacklisted") << std::endl;
|
||||
|
||||
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(remote_addr), "", "", check_result);
|
||||
reset_locked();
|
||||
return 0 ;
|
||||
reset_locked();
|
||||
return 0 ;
|
||||
}
|
||||
// check it's the right one.
|
||||
if (certCorrect)
|
||||
@ -1371,12 +1371,12 @@ int pqissl::accept_locked(SSL *ssl, int fd, const struct sockaddr_storage &forei
|
||||
if (rsPeers->servicePermissionFlags(PeerId()) & RS_NODE_PERM_REQUIRE_WL)
|
||||
checking_flags |= RSBANLIST_CHECKING_FLAGS_WHITELIST;
|
||||
|
||||
if(!rsBanList->isAddressAccepted(foreign_addr,checking_flags,&check_result))
|
||||
if(rsBanList!=NULL && !rsBanList->isAddressAccepted(foreign_addr,checking_flags,&check_result))
|
||||
{
|
||||
std::cerr << "(SS) refusing incoming SSL connection from blacklisted foreign address " << sockaddr_storage_iptostring(foreign_addr)
|
||||
<< ". Reason: " << check_result << "." << std::endl;
|
||||
RsServer::notify()->AddFeedItem(RS_FEED_ITEM_SEC_IP_BLACKLISTED, PeerId().toStdString(), sockaddr_storage_iptostring(foreign_addr), "", "", check_result);
|
||||
reset_locked();
|
||||
reset_locked();
|
||||
return -1;
|
||||
}
|
||||
if (waiting != WAITING_NOT)
|
||||
|
@ -36,6 +36,9 @@ static struct RsLog::logInfo pqipersongrpzoneInfo = {RsLog::Default, "pqipersong
|
||||
/****
|
||||
* #define PQI_DISABLE_UDP 1
|
||||
***/
|
||||
#ifdef RETROTOR
|
||||
#define PQI_DISABLE_UDP 1
|
||||
#endif
|
||||
|
||||
/********************************** SSL Specific features ***************************/
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rsnet.h"
|
||||
#include "util/rstime.h"
|
||||
#include "util/rsstring.h"
|
||||
|
||||
#include "pqi/p3linkmgr.h"
|
||||
@ -571,7 +572,7 @@ bool pqissludp::moretoread(uint32_t usec)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
usleep(usec);
|
||||
rstime::rs_usleep(usec);
|
||||
}
|
||||
|
||||
/* check for more to read first ... if nothing... check error
|
||||
@ -655,7 +656,7 @@ bool pqissludp::cansend(uint32_t usec)
|
||||
return true;
|
||||
}
|
||||
|
||||
usleep(usec);
|
||||
rstime::rs_usleep(usec);
|
||||
}
|
||||
|
||||
rslog(RSL_DEBUG_ALL, pqissludpzone,
|
||||
|
@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "util/rstime.h"
|
||||
#include "pqi/pqithreadstreamer.h"
|
||||
#include <unistd.h>
|
||||
|
||||
@ -69,7 +70,7 @@ void pqithreadstreamer::data_tick()
|
||||
|
||||
if (!isactive)
|
||||
{
|
||||
usleep(DEFAULT_STREAMER_IDLE_SLEEP);
|
||||
rstime::rs_usleep(DEFAULT_STREAMER_IDLE_SLEEP);
|
||||
return ;
|
||||
}
|
||||
|
||||
@ -92,7 +93,7 @@ void pqithreadstreamer::data_tick()
|
||||
|
||||
if (sleep_period)
|
||||
{
|
||||
usleep(sleep_period);
|
||||
rstime::rs_usleep(sleep_period);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "util/rstime.h"
|
||||
#include "rsserver/p3face.h"
|
||||
#include "retroshare/rsplugin.h"
|
||||
|
||||
@ -134,11 +135,7 @@ RsServer::~RsServer()
|
||||
/* Thread Fn: Run the Core */
|
||||
void RsServer::data_tick()
|
||||
{
|
||||
#ifndef WINDOWS_SYS
|
||||
usleep((int) (mTimeDelta * 1000000));
|
||||
#else
|
||||
Sleep((int) (mTimeDelta * 1000));
|
||||
#endif
|
||||
rstime::rs_usleep(mTimeDelta * 1000000);
|
||||
|
||||
double ts = getCurrentTS();
|
||||
double delta = ts - mLastts;
|
||||
|
@ -71,8 +71,11 @@ RsAccountsDetail::RsAccountsDetail() : mAccountsLocked(false), mPreferredId("")
|
||||
bool RsAccountsDetail::loadAccounts()
|
||||
{
|
||||
int failing_accounts ;
|
||||
|
||||
getAvailableAccounts(mAccounts,failing_accounts,mUnsupportedKeys);
|
||||
#ifdef RETROTOR
|
||||
getAvailableAccounts(mAccounts,failing_accounts,mUnsupportedKeys,true);
|
||||
#else
|
||||
getAvailableAccounts(mAccounts,failing_accounts,mUnsupportedKeys,false);
|
||||
#endif
|
||||
|
||||
loadPreferredAccount();
|
||||
checkPreferredId();
|
||||
@ -512,7 +515,7 @@ bool RsAccountsDetail::getAccountOptions(bool &ishidden, bool &isFirstTimeRun)
|
||||
|
||||
|
||||
/* directories with valid certificates in the expected location */
|
||||
bool RsAccountsDetail::getAvailableAccounts(std::map<RsPeerId, AccountDetails> &accounts,int& failing_accounts,std::map<std::string,std::vector<std::string> >& unsupported_keys)
|
||||
bool RsAccountsDetail::getAvailableAccounts(std::map<RsPeerId, AccountDetails> &accounts,int& failing_accounts,std::map<std::string,std::vector<std::string> >& unsupported_keys,bool hidden_only)
|
||||
{
|
||||
failing_accounts = 0 ;
|
||||
/* get the directories */
|
||||
@ -615,6 +618,9 @@ bool RsAccountsDetail::getAvailableAccounts(std::map<RsPeerId, AccountDetails> &
|
||||
continue;
|
||||
}
|
||||
|
||||
if(hidden_only && !hidden_location)
|
||||
continue ;
|
||||
|
||||
if(valid_prefix && isHexaString(lochex) && (lochex).length() == 32)
|
||||
{
|
||||
std::string accountdir = mBaseDirectory + "/" + *it;
|
||||
|
@ -142,9 +142,9 @@ class RsAccountsDetail
|
||||
|
||||
static bool defaultBaseDirectory();
|
||||
|
||||
bool getAvailableAccounts(std::map<RsPeerId, AccountDetails> &accounts,
|
||||
bool getAvailableAccounts(std::map<RsPeerId, AccountDetails> &accounts,
|
||||
int& failing_accounts,
|
||||
std::map<std::string,std::vector<std::string> >& unsupported_keys);
|
||||
std::map<std::string,std::vector<std::string> >& unsupported_keys, bool hidden_only=false);
|
||||
|
||||
bool setupAccount(const std::string& accountdir);
|
||||
|
||||
|
@ -70,6 +70,11 @@
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
// This needs to be defined here, because when USE_BITDHT is unset, the variable, that is defined in libbitdht (not compiled!) will be missing.
|
||||
#ifndef RS_USE_BITDHT
|
||||
RsDht *rsDht = NULL ;
|
||||
#endif
|
||||
|
||||
// for blocking signals
|
||||
#include <signal.h>
|
||||
|
||||
@ -830,9 +835,10 @@ RsGRouter *rsGRouter = NULL ;
|
||||
#include "pqi/p3linkmgr.h"
|
||||
#include "pqi/p3netmgr.h"
|
||||
|
||||
|
||||
#ifndef RETROTOR
|
||||
#include "tcponudp/tou.h"
|
||||
#include "tcponudp/rsudpstack.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef RS_USE_BITDHT
|
||||
@ -1186,9 +1192,9 @@ int RsServer::StartupRetroShare()
|
||||
#ifdef RS_USE_DHT_STUNNER
|
||||
mNetMgr->setAddrAssist(new stunAddrAssist(mDhtStunner), new stunAddrAssist(mProxyStunner));
|
||||
#endif // RS_USE_DHT_STUNNER
|
||||
#else //RS_USE_BITDHT
|
||||
/* install NULL Pointer for rsDht Interface */
|
||||
rsDht = NULL;
|
||||
// #else //RS_USE_BITDHT
|
||||
// /* install NULL Pointer for rsDht Interface */
|
||||
// rsDht = NULL;
|
||||
#endif //RS_USE_BITDHT
|
||||
|
||||
|
||||
@ -1505,7 +1511,11 @@ int RsServer::StartupRetroShare()
|
||||
interfaces.mMsgs = rsMsgs;
|
||||
interfaces.mTurtle = rsTurtle;
|
||||
interfaces.mDisc = rsDisc;
|
||||
#ifdef RS_USE_BITDHT
|
||||
interfaces.mDht = rsDht;
|
||||
#else
|
||||
interfaces.mDht = NULL;
|
||||
#endif
|
||||
interfaces.mNotify = mNotify;
|
||||
interfaces.mServiceControl = serviceCtrl;
|
||||
interfaces.mPluginHandler = mPluginsManager;
|
||||
@ -1539,10 +1549,17 @@ int RsServer::StartupRetroShare()
|
||||
#endif
|
||||
|
||||
// new services to test.
|
||||
#ifndef RETROTOR
|
||||
p3BanList *mBanList = new p3BanList(serviceCtrl, mNetMgr);
|
||||
rsBanList = mBanList ;
|
||||
pqih -> addService(mBanList, true);
|
||||
#else
|
||||
rsBanList = NULL ;
|
||||
#endif
|
||||
|
||||
#ifdef RS_USE_BITDHT
|
||||
mBitDht->setupPeerSharer(mBanList);
|
||||
#endif
|
||||
|
||||
p3BandwidthControl *mBwCtrl = new p3BandwidthControl(pqih);
|
||||
pqih -> addService(mBwCtrl, true);
|
||||
@ -1608,7 +1625,9 @@ int RsServer::StartupRetroShare()
|
||||
mConfigMgr->addConfiguration("p3History.cfg", mHistoryMgr);
|
||||
mConfigMgr->addConfiguration("p3Status.cfg", mStatusSrv);
|
||||
mConfigMgr->addConfiguration("turtle.cfg", tr);
|
||||
#ifndef RETROTOR
|
||||
mConfigMgr->addConfiguration("banlist.cfg", mBanList);
|
||||
#endif
|
||||
mConfigMgr->addConfiguration("servicecontrol.cfg", serviceCtrl);
|
||||
mConfigMgr->addConfiguration("reputations.cfg", mReputations);
|
||||
#ifdef ENABLE_GROUTER
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "util/radix32.h"
|
||||
#include "util/radix64.h"
|
||||
#include "util/rsdebug.h"
|
||||
#include "util/rstime.h"
|
||||
#include "util/rsprint.h"
|
||||
#include "util/rsrandom.h"
|
||||
|
||||
@ -39,7 +40,7 @@ static struct RsLog::logInfo i2pBobLogInfo = {RsLog::Default, "p3I2pBob"};
|
||||
static const time_t selfCheckPeroid = 30;
|
||||
|
||||
void doSleep(useconds_t timeToSleepMS) {
|
||||
usleep((useconds_t) (timeToSleepMS * 1000));
|
||||
rstime::rs_usleep((useconds_t) (timeToSleepMS * 1000));
|
||||
}
|
||||
|
||||
p3I2pBob::p3I2pBob(p3PeerMgr *peerMgr)
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "rsautoproxymonitor.h"
|
||||
|
||||
#include <unistd.h> /* for usleep() */
|
||||
#include "util/rstime.h"
|
||||
|
||||
rsAutoProxyMonitor *rsAutoProxyMonitor::mInstance = NULL;
|
||||
|
||||
@ -93,7 +94,7 @@ void rsAutoProxyMonitor::stopAllRSShutdown()
|
||||
// wait for shutdown of all services
|
||||
uint32_t t = 0, timeout = 15;
|
||||
do {
|
||||
usleep(1000 * 1000);
|
||||
rstime::rs_usleep(1000 * 1000);
|
||||
RS_STACK_MUTEX(mLock);
|
||||
std::cout << "(II) waiting for auto proxy service(s) to shut down " << t << "/" << timeout << " (remaining: " << mProxies.size() << ")" << std::endl;
|
||||
if (mProxies.empty())
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "util/rsstring.h"
|
||||
#include "util/radix64.h"
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rstime.h"
|
||||
#include "crypto/hashstream.h"
|
||||
#include "gxs/gxssecurity.h"
|
||||
#include "retroshare/rspeers.h"
|
||||
@ -1071,7 +1072,7 @@ bool p3IdService::signData(const uint8_t *data,uint32_t data_size,const RsGxsId&
|
||||
#ifdef DEBUG_IDS
|
||||
std::cerr << " Cannot get key. Waiting for caching. try " << i << "/6" << std::endl;
|
||||
#endif
|
||||
usleep(500 * 1000) ; // sleep for 500 msec.
|
||||
rstime::rs_usleep(500 * 1000) ; // sleep for 500 msec.
|
||||
}
|
||||
else
|
||||
break ;
|
||||
@ -1110,7 +1111,7 @@ bool p3IdService::validateData(const uint8_t *data,uint32_t data_size,const RsTl
|
||||
#ifdef DEBUG_IDS
|
||||
std::cerr << " Cannot get key. Waiting for caching. try " << i << "/6" << std::endl;
|
||||
#endif
|
||||
if(force_load) usleep(500 * 1000) ; // sleep for 500 msec.
|
||||
if(force_load) rstime::rs_usleep(500 * 1000) ; // sleep for 500 msec.
|
||||
}
|
||||
else
|
||||
break ;
|
||||
@ -1151,7 +1152,7 @@ bool p3IdService::encryptData( const uint8_t *decrypted_data,
|
||||
if(getKey(encryption_key_id,encryption_key))
|
||||
break ;
|
||||
else
|
||||
usleep(500*1000) ; // sleep half a sec.
|
||||
rstime::rs_usleep(500*1000) ; // sleep half a sec.
|
||||
|
||||
if(encryption_key.keyId.isNull())
|
||||
{
|
||||
@ -1222,7 +1223,7 @@ bool p3IdService::encryptData( const uint8_t* decrypted_data,
|
||||
}
|
||||
|
||||
if(keyNotYetFoundIds.empty()) break;
|
||||
else usleep(500*1000);
|
||||
else rstime::rs_usleep(500*1000);
|
||||
}
|
||||
|
||||
if(!keyNotYetFoundIds.empty())
|
||||
@ -1279,7 +1280,7 @@ bool p3IdService::decryptData( const uint8_t *encrypted_data,
|
||||
int maxRounds = force_load ? 6 : 1;
|
||||
for(int i=0; i<maxRounds ;++i)
|
||||
if(getPrivateKey(key_id,encryption_key)) break;
|
||||
else usleep(500*1000) ; // sleep half a sec.
|
||||
else rstime::rs_usleep(500*1000) ; // sleep half a sec.
|
||||
|
||||
if(encryption_key.keyId.isNull())
|
||||
{
|
||||
@ -1356,7 +1357,7 @@ bool p3IdService::decryptData( const uint8_t* encrypted_data,
|
||||
}
|
||||
|
||||
if(keyNotYetFoundIds.empty()) break;
|
||||
else usleep(500*1000);
|
||||
else rstime::rs_usleep(500*1000);
|
||||
}
|
||||
|
||||
if(!keyNotYetFoundIds.empty())
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "util/rsdir.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/rsrandom.h"
|
||||
#include "util/rstime.h"
|
||||
#include "util/rsmemory.h"
|
||||
#include "util/folderiterator.h"
|
||||
#include "retroshare/rstypes.h"
|
||||
@ -711,7 +712,7 @@ bool RsDirUtil::renameFile(const std::string& from, const std::string& to)
|
||||
#endif
|
||||
/* set errno? */
|
||||
return false ;
|
||||
usleep(100 * 1000); // 100 msec
|
||||
rstime::rs_usleep(100 * 1000); // 100 msec
|
||||
|
||||
if (loops >= 30)
|
||||
return false ;
|
||||
@ -917,7 +918,7 @@ RsStackFileLock::RsStackFileLock(const std::string& file_path)
|
||||
while(RsDirUtil::createLockFile(file_path,_file_handle))
|
||||
{
|
||||
std::cerr << "Cannot acquire file lock " << file_path << ", waiting 1 sec." << std::endl;
|
||||
usleep(1 * 1000 * 1000) ; // 1 sec
|
||||
rstime::rs_usleep(1 * 1000 * 1000) ; // 1 sec
|
||||
}
|
||||
#ifdef RSDIR_DEBUG
|
||||
std::cerr << "Acquired file handle " << _file_handle << ", lock file:" << file_path << std::endl;
|
||||
@ -1321,7 +1322,7 @@ bool RsDirUtil::renameWideFile(const std::wstring& from, const std::wstring& to)
|
||||
#endif
|
||||
/* set errno? */
|
||||
return false ;
|
||||
usleep(100 * 1000); //100 msec
|
||||
rstime::rs_usleep(100 * 1000); //100 msec
|
||||
|
||||
if (loops >= 30)
|
||||
return false ;
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
#include "util/rstime.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
int __attribute__((weak)) pthread_setname_np(const char *__buf) ;
|
||||
int RS_pthread_setname_np(pthread_t /*__target_thread*/, const char *__buf) {
|
||||
@ -289,7 +291,7 @@ void RsQueueThread::data_tick()
|
||||
THREAD_DEBUG << "RsQueueThread::data_tick() no work: sleeping for: " << mLastSleep << " ms" << std::endl;
|
||||
#endif
|
||||
}
|
||||
usleep(mLastSleep * 1000); // mLastSleep msec
|
||||
rstime::rs_usleep(mLastSleep * 1000); // mLastSleep msec
|
||||
}
|
||||
|
||||
void RsMutex::unlock()
|
||||
|
@ -24,8 +24,29 @@
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <sys/time.h>
|
||||
#include "rsscopetimer.h"
|
||||
#include <sys/unistd.h>
|
||||
#include <unistd.h>
|
||||
#include "rstime.h"
|
||||
|
||||
namespace rstime {
|
||||
|
||||
int rs_usleep(uint32_t micro_seconds)
|
||||
{
|
||||
while(micro_seconds >= 1000000)
|
||||
{
|
||||
// usleep cannot be called with 1000000 or more.
|
||||
|
||||
usleep(500000) ;
|
||||
usleep(500000) ;
|
||||
|
||||
micro_seconds -= 1000000 ;
|
||||
}
|
||||
usleep(micro_seconds) ;
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
RsScopeTimer::RsScopeTimer(const std::string& name)
|
||||
{
|
||||
@ -57,3 +78,5 @@ double RsScopeTimer::duration()
|
||||
{
|
||||
return currentTime() - _seconds;
|
||||
}
|
||||
|
||||
}
|
@ -23,29 +23,40 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// Use this class to measure and display time duration of a given environment:
|
||||
//
|
||||
// {
|
||||
// RsScopeTimer timer("callToMeasure()") ;
|
||||
//
|
||||
// callToMeasure() ;
|
||||
// }
|
||||
//
|
||||
|
||||
#include <string>
|
||||
|
||||
class RsScopeTimer
|
||||
{
|
||||
public:
|
||||
RsScopeTimer(const std::string& name);
|
||||
~RsScopeTimer();
|
||||
namespace rstime {
|
||||
|
||||
void start();
|
||||
double duration();
|
||||
/*!
|
||||
* \brief This is a cross-system definition of usleep, which accepts any 32 bits number of micro-seconds.
|
||||
*/
|
||||
|
||||
static double currentTime();
|
||||
int rs_usleep(uint32_t micro_seconds);
|
||||
|
||||
private:
|
||||
std::string _name ;
|
||||
double _seconds ;
|
||||
};
|
||||
/* Use this class to measure and display time duration of a given environment:
|
||||
|
||||
{
|
||||
RsScopeTimer timer("callToMeasure()") ;
|
||||
|
||||
callToMeasure() ;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
class RsScopeTimer
|
||||
{
|
||||
public:
|
||||
RsScopeTimer(const std::string& name);
|
||||
~RsScopeTimer();
|
||||
|
||||
void start();
|
||||
double duration();
|
||||
|
||||
static double currentTime();
|
||||
|
||||
private:
|
||||
std::string _name ;
|
||||
double _seconds ;
|
||||
};
|
||||
|
||||
}
|
@ -26,6 +26,7 @@
|
||||
#include "retroshare/rsiface.h"
|
||||
#include "retroshare/rsgxsforums.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/rstime.h"
|
||||
#include "gxs/rsgenexchange.h"
|
||||
|
||||
#include <unistd.h>
|
||||
@ -2240,7 +2241,7 @@ bool p3FeedReader::waitForToken(uint32_t token)
|
||||
break;
|
||||
}
|
||||
|
||||
usleep(500 * 1000); // sleep for 500 msec
|
||||
rstime::rs_usleep(500 * 1000); // sleep for 500 msec
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "p3FeedReaderThread.h"
|
||||
#include "rsFeedReaderItems.h"
|
||||
#include "util/rsstring.h"
|
||||
#include "util/rstime.h"
|
||||
#include "util/CURLWrapper.h"
|
||||
#include "util/XMLWrapper.h"
|
||||
#include "util/HTMLWrapper.h"
|
||||
@ -51,11 +52,8 @@ p3FeedReaderThread::~p3FeedReaderThread()
|
||||
|
||||
void p3FeedReaderThread::data_tick()
|
||||
{
|
||||
#ifdef WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
usleep(1000000);
|
||||
#endif
|
||||
rstime::rs_usleep(1000000);
|
||||
|
||||
/* every second */
|
||||
|
||||
switch (mType) {
|
||||
|
105
retroshare-gui/src/TorControl/AddOnionCommand.cpp
Normal file
105
retroshare-gui/src/TorControl/AddOnionCommand.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2016, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "AddOnionCommand.h"
|
||||
#include "HiddenService.h"
|
||||
#include "CryptoKey.h"
|
||||
#include "StrUtil.h"
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
AddOnionCommand::AddOnionCommand(HiddenService *service)
|
||||
: m_service(service)
|
||||
{
|
||||
Q_ASSERT(m_service);
|
||||
}
|
||||
|
||||
bool AddOnionCommand::isSuccessful() const
|
||||
{
|
||||
return statusCode() == 250 && m_errorMessage.isEmpty();
|
||||
}
|
||||
|
||||
QByteArray AddOnionCommand::build()
|
||||
{
|
||||
QByteArray out("ADD_ONION");
|
||||
|
||||
if (m_service->privateKey().isLoaded()) {
|
||||
out += " RSA1024:";
|
||||
out += m_service->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64();
|
||||
} else {
|
||||
out += " NEW:RSA1024";
|
||||
}
|
||||
|
||||
foreach (const HiddenService::Target &target, m_service->targets()) {
|
||||
out += " Port=";
|
||||
out += QByteArray::number(target.servicePort);
|
||||
out += ",";
|
||||
out += target.targetAddress.toString().toLatin1();
|
||||
out += ":";
|
||||
out += QByteArray::number(target.targetPort);
|
||||
}
|
||||
|
||||
out.append("\r\n");
|
||||
return out;
|
||||
}
|
||||
|
||||
void AddOnionCommand::onReply(int statusCode, const QByteArray &data)
|
||||
{
|
||||
TorControlCommand::onReply(statusCode, data);
|
||||
if (statusCode != 250) {
|
||||
m_errorMessage = QString::fromLatin1(data);
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray keyPrefix("PrivateKey=RSA1024:");
|
||||
if (data.startsWith(keyPrefix)) {
|
||||
QByteArray keyData(QByteArray::fromBase64(data.mid(keyPrefix.size())));
|
||||
CryptoKey key;
|
||||
if (!key.loadFromData(keyData, CryptoKey::PrivateKey, CryptoKey::DER)) {
|
||||
m_errorMessage = QStringLiteral("Key decoding failed");
|
||||
return;
|
||||
}
|
||||
|
||||
m_service->setPrivateKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
void AddOnionCommand::onFinished(int statusCode)
|
||||
{
|
||||
TorControlCommand::onFinished(statusCode);
|
||||
if (isSuccessful())
|
||||
emit succeeded();
|
||||
else
|
||||
emit failed(statusCode);
|
||||
}
|
||||
|
||||
|
77
retroshare-gui/src/TorControl/AddOnionCommand.h
Normal file
77
retroshare-gui/src/TorControl/AddOnionCommand.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2016, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef ADDONIONCOMMAND_H
|
||||
#define ADDONIONCOMMAND_H
|
||||
|
||||
#include "TorControlCommand.h"
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QVariant>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class HiddenService;
|
||||
|
||||
class AddOnionCommand : public TorControlCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(AddOnionCommand)
|
||||
|
||||
Q_PROPERTY(QString errorMessage READ errorMessage CONSTANT)
|
||||
Q_PROPERTY(bool successful READ isSuccessful CONSTANT)
|
||||
|
||||
public:
|
||||
AddOnionCommand(HiddenService *service);
|
||||
|
||||
QByteArray build();
|
||||
|
||||
QString errorMessage() const { return m_errorMessage; }
|
||||
bool isSuccessful() const;
|
||||
|
||||
signals:
|
||||
void succeeded();
|
||||
void failed(int code);
|
||||
|
||||
protected:
|
||||
HiddenService *m_service;
|
||||
QString m_errorMessage;
|
||||
|
||||
virtual void onReply(int statusCode, const QByteArray &data);
|
||||
virtual void onFinished(int statusCode);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ADDONIONCOMMAND_H
|
||||
|
64
retroshare-gui/src/TorControl/AuthenticateCommand.cpp
Normal file
64
retroshare-gui/src/TorControl/AuthenticateCommand.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "AuthenticateCommand.h"
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
AuthenticateCommand::AuthenticateCommand()
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray AuthenticateCommand::build(const QByteArray &data)
|
||||
{
|
||||
if (data.isNull())
|
||||
return QByteArray("AUTHENTICATE\r\n");
|
||||
|
||||
return QByteArray("AUTHENTICATE ") + data.toHex() + "\r\n";
|
||||
}
|
||||
|
||||
void AuthenticateCommand::onReply(int statusCode, const QByteArray &data)
|
||||
{
|
||||
TorControlCommand::onReply(statusCode, data);
|
||||
m_statusMessage = QString::fromLatin1(data);
|
||||
}
|
||||
|
||||
void AuthenticateCommand::onFinished(int statusCode)
|
||||
{
|
||||
if (statusCode == 515) {
|
||||
m_statusMessage = QStringLiteral("Authentication failed - incorrect password");
|
||||
} else if (statusCode != 250) {
|
||||
if (m_statusMessage.isEmpty())
|
||||
m_statusMessage = QStringLiteral("Authentication failed (error %1").arg(statusCode);
|
||||
}
|
||||
TorControlCommand::onFinished(statusCode);
|
||||
}
|
63
retroshare-gui/src/TorControl/AuthenticateCommand.h
Normal file
63
retroshare-gui/src/TorControl/AuthenticateCommand.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef AUTHENTICATECOMMAND_H
|
||||
#define AUTHENTICATECOMMAND_H
|
||||
|
||||
#include "TorControlCommand.h"
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class AuthenticateCommand : public TorControlCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AuthenticateCommand();
|
||||
|
||||
QByteArray build(const QByteArray &data = QByteArray());
|
||||
|
||||
bool isSuccessful() const { return statusCode() == 250; }
|
||||
QString errorMessage() const { return m_statusMessage; }
|
||||
|
||||
protected:
|
||||
virtual void onReply(int statusCode, const QByteArray &data);
|
||||
virtual void onFinished(int statusCode);
|
||||
|
||||
private:
|
||||
QString m_statusMessage;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AUTHENTICATECOMMAND_H
|
477
retroshare-gui/src/TorControl/CryptoKey.cpp
Normal file
477
retroshare-gui/src/TorControl/CryptoKey.cpp
Normal file
@ -0,0 +1,477 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "CryptoKey.h"
|
||||
#include "SecureRNG.h"
|
||||
#include "Useful.h"
|
||||
#include <QtDebug>
|
||||
#include <QFile>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
|
||||
{
|
||||
*p = r->p;
|
||||
*q = r->q;
|
||||
}
|
||||
#define RSA_bits(o) (BN_num_bits((o)->n))
|
||||
#endif
|
||||
|
||||
void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen);
|
||||
bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen);
|
||||
|
||||
CryptoKey::CryptoKey()
|
||||
{
|
||||
}
|
||||
|
||||
CryptoKey::~CryptoKey()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
CryptoKey::Data::~Data()
|
||||
{
|
||||
if (key)
|
||||
{
|
||||
RSA_free(key);
|
||||
key = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CryptoKey::clear()
|
||||
{
|
||||
d = 0;
|
||||
}
|
||||
|
||||
bool CryptoKey::loadFromData(const QByteArray &data, KeyType type, KeyFormat format)
|
||||
{
|
||||
RSA *key = NULL;
|
||||
clear();
|
||||
|
||||
if (data.isEmpty())
|
||||
return false;
|
||||
|
||||
if (format == PEM) {
|
||||
BIO *b = BIO_new_mem_buf((void*)data.constData(), -1);
|
||||
|
||||
if (type == PrivateKey)
|
||||
key = PEM_read_bio_RSAPrivateKey(b, NULL, NULL, NULL);
|
||||
else
|
||||
key = PEM_read_bio_RSAPublicKey(b, NULL, NULL, NULL);
|
||||
|
||||
BIO_free(b);
|
||||
} else if (format == DER) {
|
||||
const uchar *dp = reinterpret_cast<const uchar*>(data.constData());
|
||||
|
||||
if (type == PrivateKey)
|
||||
key = d2i_RSAPrivateKey(NULL, &dp, data.size());
|
||||
else
|
||||
key = d2i_RSAPublicKey(NULL, &dp, data.size());
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
qWarning() << "Failed to parse" << (type == PrivateKey ? "private" : "public") << "key from data";
|
||||
return false;
|
||||
}
|
||||
|
||||
d = new Data(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoKey::loadFromFile(const QString &path, KeyType type, KeyFormat format)
|
||||
{
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
qWarning() << "Failed to open" << (type == PrivateKey ? "private" : "public") << "key from"
|
||||
<< path << "-" << file.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
|
||||
return loadFromData(data, type, format);
|
||||
}
|
||||
|
||||
bool CryptoKey::isPrivate() const
|
||||
{
|
||||
if (!isLoaded()) {
|
||||
return false;
|
||||
} else {
|
||||
const BIGNUM *p, *q;
|
||||
RSA_get0_factors(d->key, &p, &q);
|
||||
return (p != 0);
|
||||
}
|
||||
}
|
||||
|
||||
int CryptoKey::bits() const
|
||||
{
|
||||
return isLoaded() ? RSA_bits(d->key) : 0;
|
||||
}
|
||||
|
||||
QByteArray CryptoKey::publicKeyDigest() const
|
||||
{
|
||||
if (!isLoaded())
|
||||
return QByteArray();
|
||||
|
||||
QByteArray buf = encodedPublicKey(DER);
|
||||
|
||||
QByteArray re(20, 0);
|
||||
bool ok = SHA1(reinterpret_cast<const unsigned char*>(buf.constData()), buf.size(),
|
||||
reinterpret_cast<unsigned char*>(re.data())) != NULL;
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
qWarning() << "Failed to hash public key data for digest";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return re;
|
||||
}
|
||||
|
||||
QByteArray CryptoKey::encodedPublicKey(KeyFormat format) const
|
||||
{
|
||||
if (!isLoaded())
|
||||
return QByteArray();
|
||||
|
||||
if (format == PEM) {
|
||||
BIO *b = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!PEM_write_bio_RSAPublicKey(b, d->key)) {
|
||||
BUG() << "Failed to encode public key in PEM format";
|
||||
BIO_free(b);
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
BUF_MEM *buf;
|
||||
BIO_get_mem_ptr(b, &buf);
|
||||
|
||||
/* Close BIO, but don't free buf. */
|
||||
(void)BIO_set_close(b, BIO_NOCLOSE);
|
||||
BIO_free(b);
|
||||
|
||||
QByteArray re((const char *)buf->data, (int)buf->length);
|
||||
BUF_MEM_free(buf);
|
||||
return re;
|
||||
} else if (format == DER) {
|
||||
uchar *buf = NULL;
|
||||
int len = i2d_RSAPublicKey(d->key, &buf);
|
||||
if (len <= 0 || !buf) {
|
||||
BUG() << "Failed to encode public key in DER format";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray re((const char*)buf, len);
|
||||
OPENSSL_free(buf);
|
||||
return re;
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray CryptoKey::encodedPrivateKey(KeyFormat format) const
|
||||
{
|
||||
if (!isLoaded() || !isPrivate())
|
||||
return QByteArray();
|
||||
|
||||
if (format == PEM) {
|
||||
BIO *b = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!PEM_write_bio_RSAPrivateKey(b, d->key, NULL, NULL, 0, NULL, NULL)) {
|
||||
BUG() << "Failed to encode private key in PEM format";
|
||||
BIO_free(b);
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
BUF_MEM *buf;
|
||||
BIO_get_mem_ptr(b, &buf);
|
||||
|
||||
/* Close BIO, but don't free buf. */
|
||||
(void)BIO_set_close(b, BIO_NOCLOSE);
|
||||
BIO_free(b);
|
||||
|
||||
QByteArray re((const char *)buf->data, (int)buf->length);
|
||||
BUF_MEM_free(buf);
|
||||
return re;
|
||||
} else if (format == DER) {
|
||||
uchar *buf = NULL;
|
||||
int len = i2d_RSAPrivateKey(d->key, &buf);
|
||||
if (len <= 0 || !buf) {
|
||||
BUG() << "Failed to encode private key in DER format";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray re((const char*)buf, len);
|
||||
OPENSSL_free(buf);
|
||||
return re;
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QString CryptoKey::torServiceID() const
|
||||
{
|
||||
if (!isLoaded())
|
||||
return QString();
|
||||
|
||||
QByteArray digest = publicKeyDigest();
|
||||
if (digest.isNull())
|
||||
return QString();
|
||||
|
||||
static const int hostnameDigestSize = 10;
|
||||
static const int hostnameEncodedSize = 16;
|
||||
|
||||
QByteArray re(hostnameEncodedSize+1, 0);
|
||||
base32_encode(re.data(), re.size(), digest.constData(), hostnameDigestSize);
|
||||
|
||||
// Chop extra null byte
|
||||
re.chop(1);
|
||||
|
||||
return QString::fromLatin1(re);
|
||||
}
|
||||
|
||||
QByteArray CryptoKey::signData(const QByteArray &data) const
|
||||
{
|
||||
QByteArray digest(32, 0);
|
||||
bool ok = SHA256(reinterpret_cast<const unsigned char*>(data.constData()), data.size(),
|
||||
reinterpret_cast<unsigned char*>(digest.data())) != NULL;
|
||||
if (!ok) {
|
||||
qWarning() << "Digest for RSA signature failed";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
return signSHA256(digest);
|
||||
}
|
||||
|
||||
QByteArray CryptoKey::signSHA256(const QByteArray &digest) const
|
||||
{
|
||||
if (!isPrivate())
|
||||
return QByteArray();
|
||||
|
||||
QByteArray re(RSA_size(d->key), 0);
|
||||
unsigned sigsize = 0;
|
||||
int r = RSA_sign(NID_sha256, reinterpret_cast<const unsigned char*>(digest.constData()), digest.size(),
|
||||
reinterpret_cast<unsigned char*>(re.data()), &sigsize, d->key);
|
||||
|
||||
if (r != 1) {
|
||||
qWarning() << "RSA encryption failed when generating signature";
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
re.truncate(sigsize);
|
||||
return re;
|
||||
}
|
||||
|
||||
bool CryptoKey::verifyData(const QByteArray &data, QByteArray signature) const
|
||||
{
|
||||
QByteArray digest(32, 0);
|
||||
bool ok = SHA256(reinterpret_cast<const unsigned char*>(data.constData()), data.size(),
|
||||
reinterpret_cast<unsigned char*>(digest.data())) != NULL;
|
||||
|
||||
if (!ok) {
|
||||
qWarning() << "Digest for RSA verify failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
return verifySHA256(digest, signature);
|
||||
}
|
||||
|
||||
bool CryptoKey::verifySHA256(const QByteArray &digest, QByteArray signature) const
|
||||
{
|
||||
if (!isLoaded())
|
||||
return false;
|
||||
|
||||
int r = RSA_verify(NID_sha256, reinterpret_cast<const uchar*>(digest.constData()), digest.size(),
|
||||
reinterpret_cast<uchar*>(signature.data()), signature.size(), d->key);
|
||||
if (r != 1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Cryptographic hash of a password as expected by Tor's HashedControlPassword */
|
||||
QByteArray torControlHashedPassword(const QByteArray &password)
|
||||
{
|
||||
QByteArray salt = SecureRNG::random(8);
|
||||
if (salt.isNull())
|
||||
return QByteArray();
|
||||
|
||||
int count = ((quint32)16 + (96 & 15)) << ((96 >> 4) + 6);
|
||||
|
||||
SHA_CTX hash;
|
||||
SHA1_Init(&hash);
|
||||
|
||||
QByteArray tmp = salt + password;
|
||||
while (count)
|
||||
{
|
||||
int c = qMin(count, tmp.size());
|
||||
SHA1_Update(&hash, reinterpret_cast<const void*>(tmp.constData()), c);
|
||||
count -= c;
|
||||
}
|
||||
|
||||
unsigned char md[20];
|
||||
SHA1_Final(md, &hash);
|
||||
|
||||
/* 60 is the hex-encoded value of 96, which is a constant used by Tor's algorithm. */
|
||||
return QByteArray("16:") + salt.toHex().toUpper() + QByteArray("60") +
|
||||
QByteArray::fromRawData(reinterpret_cast<const char*>(md), 20).toHex().toUpper();
|
||||
}
|
||||
|
||||
/* Copyright (c) 2001-2004, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
|
||||
* Copyright (c) 2007-2010, The Tor Project, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define BASE32_CHARS "abcdefghijklmnopqrstuvwxyz234567"
|
||||
|
||||
/* Implements base32 encoding as in rfc3548. Requires that srclen*8 is a multiple of 5. */
|
||||
void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen)
|
||||
{
|
||||
unsigned i, bit, v, u;
|
||||
unsigned nbits = srclen * 8;
|
||||
|
||||
/* We need an even multiple of 5 bits, and enough space */
|
||||
if ((nbits%5) != 0 || destlen > (nbits/5)+1) {
|
||||
Q_ASSERT(false);
|
||||
memset(dest, 0, destlen);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0, bit = 0; bit < nbits; ++i, bit += 5)
|
||||
{
|
||||
/* set v to the 16-bit value starting at src[bits/8], 0-padded. */
|
||||
v = ((quint8) src[bit / 8]) << 8;
|
||||
if (bit + 5 < nbits)
|
||||
v += (quint8) src[(bit/8)+1];
|
||||
|
||||
/* set u to the 5-bit value at the bit'th bit of src. */
|
||||
u = (v >> (11 - (bit % 8))) & 0x1F;
|
||||
dest[i] = BASE32_CHARS[u];
|
||||
}
|
||||
|
||||
dest[i] = '\0';
|
||||
}
|
||||
|
||||
/* Implements base32 decoding as in rfc3548. Requires that srclen*5 is a multiple of 8. */
|
||||
bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen)
|
||||
{
|
||||
unsigned int i, j, bit;
|
||||
unsigned nbits = srclen * 5;
|
||||
|
||||
/* We need an even multiple of 8 bits, and enough space */
|
||||
if ((nbits%8) != 0 || (nbits/8)+1 > destlen) {
|
||||
Q_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
char *tmp = new char[srclen];
|
||||
|
||||
/* Convert base32 encoded chars to the 5-bit values that they represent. */
|
||||
for (j = 0; j < srclen; ++j)
|
||||
{
|
||||
if (src[j] > 0x60 && src[j] < 0x7B)
|
||||
tmp[j] = src[j] - 0x61;
|
||||
else if (src[j] > 0x31 && src[j] < 0x38)
|
||||
tmp[j] = src[j] - 0x18;
|
||||
else if (src[j] > 0x40 && src[j] < 0x5B)
|
||||
tmp[j] = src[j] - 0x41;
|
||||
else
|
||||
{
|
||||
delete[] tmp;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assemble result byte-wise by applying five possible cases. */
|
||||
for (i = 0, bit = 0; bit < nbits; ++i, bit += 8)
|
||||
{
|
||||
switch (bit % 40)
|
||||
{
|
||||
case 0:
|
||||
dest[i] = (((quint8)tmp[(bit/5)]) << 3) + (((quint8)tmp[(bit/5)+1]) >> 2);
|
||||
break;
|
||||
case 8:
|
||||
dest[i] = (((quint8)tmp[(bit/5)]) << 6) + (((quint8)tmp[(bit/5)+1]) << 1)
|
||||
+ (((quint8)tmp[(bit/5)+2]) >> 4);
|
||||
break;
|
||||
case 16:
|
||||
dest[i] = (((quint8)tmp[(bit/5)]) << 4) + (((quint8)tmp[(bit/5)+1]) >> 1);
|
||||
break;
|
||||
case 24:
|
||||
dest[i] = (((quint8)tmp[(bit/5)]) << 7) + (((quint8)tmp[(bit/5)+1]) << 2)
|
||||
+ (((quint8)tmp[(bit/5)+2]) >> 3);
|
||||
break;
|
||||
case 32:
|
||||
dest[i] = (((quint8)tmp[(bit/5)]) << 5) + ((quint8)tmp[(bit/5)+1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] tmp;
|
||||
return true;
|
||||
}
|
95
retroshare-gui/src/TorControl/CryptoKey.h
Normal file
95
retroshare-gui/src/TorControl/CryptoKey.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CRYPTOKEY_H
|
||||
#define CRYPTOKEY_H
|
||||
|
||||
#include <QString>
|
||||
#include <QSharedData>
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
|
||||
class CryptoKey
|
||||
{
|
||||
public:
|
||||
enum KeyType {
|
||||
PrivateKey,
|
||||
PublicKey
|
||||
};
|
||||
|
||||
enum KeyFormat {
|
||||
PEM,
|
||||
DER
|
||||
};
|
||||
|
||||
CryptoKey();
|
||||
CryptoKey(const CryptoKey &other) : d(other.d) { }
|
||||
~CryptoKey();
|
||||
|
||||
bool loadFromData(const QByteArray &data, KeyType type, KeyFormat format = PEM);
|
||||
bool loadFromFile(const QString &path, KeyType type, KeyFormat format = PEM);
|
||||
void clear();
|
||||
|
||||
bool isLoaded() const { return d.data() && d->key != 0; }
|
||||
bool isPrivate() const;
|
||||
|
||||
QByteArray publicKeyDigest() const;
|
||||
QByteArray encodedPublicKey(KeyFormat format) const;
|
||||
QByteArray encodedPrivateKey(KeyFormat format) const;
|
||||
QString torServiceID() const;
|
||||
int bits() const;
|
||||
|
||||
// Calculate and sign SHA-256 digest of data using this key and PKCS #1 v2.0 padding
|
||||
QByteArray signData(const QByteArray &data) const;
|
||||
// Verify a signature as per signData
|
||||
bool verifyData(const QByteArray &data, QByteArray signature) const;
|
||||
|
||||
// Sign the input SHA-256 digest using this key and PKCS #1 v2.0 padding
|
||||
QByteArray signSHA256(const QByteArray &digest) const;
|
||||
// Verify a signature as per signSHA256
|
||||
bool verifySHA256(const QByteArray &digest, QByteArray signature) const;
|
||||
|
||||
private:
|
||||
struct Data : public QSharedData
|
||||
{
|
||||
typedef struct rsa_st RSA;
|
||||
RSA *key;
|
||||
|
||||
Data(RSA *k = 0) : key(k) { }
|
||||
~Data();
|
||||
};
|
||||
|
||||
QExplicitlySharedDataPointer<Data> d;
|
||||
};
|
||||
|
||||
QByteArray torControlHashedPassword(const QByteArray &password);
|
||||
|
||||
#endif // CRYPTOKEY_H
|
124
retroshare-gui/src/TorControl/GetConfCommand.cpp
Normal file
124
retroshare-gui/src/TorControl/GetConfCommand.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "GetConfCommand.h"
|
||||
#include "StrUtil.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
GetConfCommand::GetConfCommand(Type t)
|
||||
: type(t)
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray GetConfCommand::build(const QByteArray &key)
|
||||
{
|
||||
return build(QList<QByteArray>() << key);
|
||||
}
|
||||
|
||||
QByteArray GetConfCommand::build(const QList<QByteArray> &keys)
|
||||
{
|
||||
QByteArray out;
|
||||
if (type == GetConf) {
|
||||
out = "GETCONF";
|
||||
} else if (type == GetInfo) {
|
||||
out = "GETINFO";
|
||||
} else {
|
||||
Q_ASSERT(false);
|
||||
return out;
|
||||
}
|
||||
|
||||
foreach (const QByteArray &key, keys) {
|
||||
out.append(' ');
|
||||
out.append(key);
|
||||
}
|
||||
|
||||
out.append("\r\n");
|
||||
return out;
|
||||
}
|
||||
|
||||
void GetConfCommand::onReply(int statusCode, const QByteArray &data)
|
||||
{
|
||||
TorControlCommand::onReply(statusCode, data);
|
||||
if (statusCode != 250)
|
||||
return;
|
||||
|
||||
int kep = data.indexOf('=');
|
||||
QString key = QString::fromLatin1(data.mid(0, kep));
|
||||
QVariant value;
|
||||
if (kep >= 0)
|
||||
value = QString::fromLatin1(unquotedString(data.mid(kep + 1)));
|
||||
|
||||
m_lastKey = key;
|
||||
QVariantMap::iterator it = m_results.find(key);
|
||||
if (it != m_results.end()) {
|
||||
// Make a list of values
|
||||
QVariantList results = it->toList();
|
||||
if (results.isEmpty())
|
||||
results.append(*it);
|
||||
results.append(value);
|
||||
*it = QVariant(results);
|
||||
} else {
|
||||
m_results.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
void GetConfCommand::onDataLine(const QByteArray &data)
|
||||
{
|
||||
if (m_lastKey.isEmpty()) {
|
||||
qWarning() << "torctrl: Unexpected data line in GetConf command";
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap::iterator it = m_results.find(m_lastKey);
|
||||
if (it != m_results.end()) {
|
||||
QVariantList results = it->toList();
|
||||
if (results.isEmpty() && !it->toByteArray().isEmpty())
|
||||
results.append(*it);
|
||||
results.append(data);
|
||||
*it = QVariant(results);
|
||||
} else {
|
||||
m_results.insert(m_lastKey, QVariantList() << data);
|
||||
}
|
||||
}
|
||||
|
||||
void GetConfCommand::onDataFinished()
|
||||
{
|
||||
m_lastKey.clear();
|
||||
}
|
||||
|
||||
QVariant GetConfCommand::get(const QByteArray &key) const
|
||||
{
|
||||
return m_results.value(QString::fromLatin1(key));
|
||||
}
|
||||
|
77
retroshare-gui/src/TorControl/GetConfCommand.h
Normal file
77
retroshare-gui/src/TorControl/GetConfCommand.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef GETCONFCOMMAND_H
|
||||
#define GETCONFCOMMAND_H
|
||||
|
||||
#include "TorControlCommand.h"
|
||||
#include <QList>
|
||||
#include <QVariantMap>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class GetConfCommand : public TorControlCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(GetConfCommand)
|
||||
|
||||
Q_PROPERTY(QVariantMap results READ results CONSTANT)
|
||||
|
||||
public:
|
||||
enum Type {
|
||||
GetConf,
|
||||
GetInfo
|
||||
};
|
||||
const Type type;
|
||||
|
||||
GetConfCommand(Type type);
|
||||
|
||||
QByteArray build(const QByteArray &key);
|
||||
QByteArray build(const QList<QByteArray> &keys);
|
||||
|
||||
const QVariantMap &results() const { return m_results; }
|
||||
QVariant get(const QByteArray &key) const;
|
||||
|
||||
protected:
|
||||
virtual void onReply(int statusCode, const QByteArray &data);
|
||||
virtual void onDataLine(const QByteArray &data);
|
||||
virtual void onDataFinished();
|
||||
|
||||
private:
|
||||
QVariantMap m_results;
|
||||
QString m_lastKey;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // GETCONFCOMMAND_H
|
137
retroshare-gui/src/TorControl/HiddenService.cpp
Normal file
137
retroshare-gui/src/TorControl/HiddenService.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "HiddenService.h"
|
||||
#include "TorControl.h"
|
||||
#include "TorSocket.h"
|
||||
#include "CryptoKey.h"
|
||||
#include "Useful.h"
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
HiddenService::HiddenService(QObject *parent)
|
||||
: QObject(parent), m_status(NotCreated)
|
||||
{
|
||||
}
|
||||
|
||||
HiddenService::HiddenService(const QString &path, QObject *parent)
|
||||
: QObject(parent), m_dataPath(path), m_status(NotCreated)
|
||||
{
|
||||
/* Set the initial status and, if possible, load the hostname */
|
||||
if (QDir(m_dataPath).exists(QLatin1String("private_key"))) {
|
||||
loadPrivateKey();
|
||||
if (!m_hostname.isEmpty())
|
||||
m_status = Offline;
|
||||
}
|
||||
}
|
||||
|
||||
HiddenService::HiddenService(const CryptoKey &privateKey, const QString &path, QObject *parent)
|
||||
: QObject(parent), m_dataPath(path), m_status(NotCreated)
|
||||
{
|
||||
setPrivateKey(privateKey);
|
||||
m_status = Offline;
|
||||
}
|
||||
|
||||
void HiddenService::setStatus(Status newStatus)
|
||||
{
|
||||
if (m_status == newStatus)
|
||||
return;
|
||||
|
||||
Status old = m_status;
|
||||
m_status = newStatus;
|
||||
|
||||
emit statusChanged(m_status, old);
|
||||
|
||||
if (m_status == Online)
|
||||
emit serviceOnline();
|
||||
}
|
||||
|
||||
void HiddenService::addTarget(const Target &target)
|
||||
{
|
||||
m_targets.append(target);
|
||||
}
|
||||
|
||||
void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort)
|
||||
{
|
||||
Target t = { targetAddress, servicePort, targetPort };
|
||||
m_targets.append(t);
|
||||
}
|
||||
|
||||
void HiddenService::setPrivateKey(const CryptoKey &key)
|
||||
{
|
||||
if (m_privateKey.isLoaded()) {
|
||||
BUG() << "Cannot change the private key on an existing HiddenService";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!key.isPrivate()) {
|
||||
BUG() << "Cannot create a hidden service with a public key";
|
||||
return;
|
||||
}
|
||||
|
||||
m_privateKey = key;
|
||||
m_hostname = m_privateKey.torServiceID() + QStringLiteral(".onion");
|
||||
emit privateKeyChanged();
|
||||
}
|
||||
|
||||
void HiddenService::loadPrivateKey()
|
||||
{
|
||||
if (m_privateKey.isLoaded() || m_dataPath.isEmpty())
|
||||
return;
|
||||
|
||||
bool ok = m_privateKey.loadFromFile(m_dataPath + QLatin1String("/private_key"), CryptoKey::PrivateKey);
|
||||
if (!ok) {
|
||||
qWarning() << "Failed to load hidden service key";
|
||||
return;
|
||||
}
|
||||
|
||||
m_hostname = m_privateKey.torServiceID();
|
||||
emit privateKeyChanged();
|
||||
}
|
||||
|
||||
void HiddenService::servicePublished()
|
||||
{
|
||||
loadPrivateKey();
|
||||
|
||||
if (m_hostname.isEmpty()) {
|
||||
std::cerr << "Failed to read hidden service hostname" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cerr << "Hidden service published successfully" << std::endl;
|
||||
setStatus(Online);
|
||||
}
|
||||
|
104
retroshare-gui/src/TorControl/HiddenService.h
Normal file
104
retroshare-gui/src/TorControl/HiddenService.h
Normal file
@ -0,0 +1,104 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef HIDDENSERVICE_H
|
||||
#define HIDDENSERVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
#include <QList>
|
||||
#include "CryptoKey.h"
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class TorSocket;
|
||||
|
||||
class HiddenService : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(HiddenService)
|
||||
|
||||
friend class TorControlPrivate;
|
||||
|
||||
public:
|
||||
struct Target
|
||||
{
|
||||
QHostAddress targetAddress;
|
||||
quint16 servicePort, targetPort;
|
||||
};
|
||||
|
||||
enum Status
|
||||
{
|
||||
NotCreated = -1, /* Service has not been created yet */
|
||||
Offline = 0, /* Data exists, but service is not published */
|
||||
Online /* Published */
|
||||
};
|
||||
|
||||
HiddenService(QObject *parent = 0);
|
||||
HiddenService(const QString &dataPath, QObject *parent = 0);
|
||||
HiddenService(const CryptoKey &privateKey, const QString &dataPath = QString(), QObject *parent = 0);
|
||||
|
||||
Status status() const { return m_status; }
|
||||
|
||||
const QString &hostname() const { return m_hostname; }
|
||||
const QString &dataPath() const { return m_dataPath; }
|
||||
|
||||
CryptoKey privateKey() { return m_privateKey; }
|
||||
void setPrivateKey(const CryptoKey &privateKey);
|
||||
|
||||
const QList<Target> &targets() const { return m_targets; }
|
||||
void addTarget(const Target &target);
|
||||
void addTarget(quint16 servicePort, QHostAddress targetAddress, quint16 targetPort);
|
||||
|
||||
signals:
|
||||
void statusChanged(int newStatus, int oldStatus);
|
||||
void serviceOnline();
|
||||
void privateKeyChanged();
|
||||
|
||||
private slots:
|
||||
void servicePublished();
|
||||
|
||||
private:
|
||||
QString m_dataPath;
|
||||
QList<Target> m_targets;
|
||||
QString m_hostname;
|
||||
Status m_status;
|
||||
CryptoKey m_privateKey;
|
||||
|
||||
void loadPrivateKey();
|
||||
void setStatus(Status newStatus);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HIDDENSERVICE_H
|
84
retroshare-gui/src/TorControl/PendingOperation.cpp
Normal file
84
retroshare-gui/src/TorControl/PendingOperation.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "PendingOperation.h"
|
||||
|
||||
PendingOperation::PendingOperation(QObject *parent)
|
||||
: QObject(parent), m_finished(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool PendingOperation::isFinished() const
|
||||
{
|
||||
return m_finished;
|
||||
}
|
||||
|
||||
bool PendingOperation::isSuccess() const
|
||||
{
|
||||
return m_finished && m_errorMessage.isNull();
|
||||
}
|
||||
|
||||
bool PendingOperation::isError() const
|
||||
{
|
||||
return m_finished && !m_errorMessage.isNull();
|
||||
}
|
||||
|
||||
QString PendingOperation::errorMessage() const
|
||||
{
|
||||
return m_errorMessage;
|
||||
}
|
||||
|
||||
void PendingOperation::finishWithError(const QString &message)
|
||||
{
|
||||
if (message.isEmpty())
|
||||
m_errorMessage = QStringLiteral("Unknown Error");
|
||||
m_errorMessage = message;
|
||||
|
||||
if (!m_finished) {
|
||||
m_finished = true;
|
||||
emit finished();
|
||||
emit error(m_errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void PendingOperation::finishWithSuccess()
|
||||
{
|
||||
Q_ASSERT(m_errorMessage.isNull());
|
||||
|
||||
if (!m_finished) {
|
||||
m_finished = true;
|
||||
emit finished();
|
||||
if (isSuccess())
|
||||
emit success();
|
||||
}
|
||||
}
|
||||
|
87
retroshare-gui/src/TorControl/PendingOperation.h
Normal file
87
retroshare-gui/src/TorControl/PendingOperation.h
Normal file
@ -0,0 +1,87 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PENDINGOPERATION_H
|
||||
#define PENDINGOPERATION_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
/* Represents an asynchronous operation for reporting status
|
||||
*
|
||||
* This class is used for asynchronous operations that report a
|
||||
* status and errors when finished, particularly for exposing them
|
||||
* to QML.
|
||||
*
|
||||
* Subclass PendingOperation to implement your operation's logic.
|
||||
* You also need to handle the object's lifetime, for example by
|
||||
* calling deleteLater() when finished() is emitted.
|
||||
*
|
||||
* PendingOperation will emit finished() and one of success() or
|
||||
* error() when completed.
|
||||
*/
|
||||
class PendingOperation : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool isFinished READ isFinished NOTIFY finished FINAL)
|
||||
Q_PROPERTY(bool isSuccess READ isSuccess NOTIFY success FINAL)
|
||||
Q_PROPERTY(bool isError READ isError NOTIFY error FINAL)
|
||||
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY finished FINAL)
|
||||
|
||||
public:
|
||||
PendingOperation(QObject *parent = 0);
|
||||
|
||||
bool isFinished() const;
|
||||
bool isSuccess() const;
|
||||
bool isError() const;
|
||||
QString errorMessage() const;
|
||||
|
||||
signals:
|
||||
// Always emitted once when finished, regardless of status
|
||||
void finished();
|
||||
|
||||
// One of error() or success() is emitted once
|
||||
void error(const QString &errorMessage);
|
||||
void success();
|
||||
|
||||
protected slots:
|
||||
void finishWithError(const QString &errorMessage);
|
||||
void finishWithSuccess();
|
||||
|
||||
private:
|
||||
bool m_finished;
|
||||
QString m_errorMessage;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(PendingOperation*)
|
||||
|
||||
#endif
|
85
retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp
Normal file
85
retroshare-gui/src/TorControl/ProtocolInfoCommand.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ProtocolInfoCommand.h"
|
||||
#include "TorControl.h"
|
||||
#include "StrUtil.h"
|
||||
#include <QList>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
ProtocolInfoCommand::ProtocolInfoCommand(TorControl *m)
|
||||
: manager(m)
|
||||
{
|
||||
}
|
||||
|
||||
QByteArray ProtocolInfoCommand::build()
|
||||
{
|
||||
return QByteArray("PROTOCOLINFO 1\r\n");
|
||||
}
|
||||
|
||||
void ProtocolInfoCommand::onReply(int statusCode, const QByteArray &data)
|
||||
{
|
||||
TorControlCommand::onReply(statusCode, data);
|
||||
if (statusCode != 250)
|
||||
return;
|
||||
|
||||
if (data.startsWith("AUTH "))
|
||||
{
|
||||
QList<QByteArray> tokens = splitQuotedStrings(data.mid(5), ' ');
|
||||
|
||||
foreach (QByteArray token, tokens)
|
||||
{
|
||||
if (token.startsWith("METHODS="))
|
||||
{
|
||||
QList<QByteArray> textMethods = unquotedString(token.mid(8)).split(',');
|
||||
for (QList<QByteArray>::Iterator it = textMethods.begin(); it != textMethods.end(); ++it)
|
||||
{
|
||||
if (*it == "NULL")
|
||||
m_authMethods |= AuthNull;
|
||||
else if (*it == "HASHEDPASSWORD")
|
||||
m_authMethods |= AuthHashedPassword;
|
||||
else if (*it == "COOKIE")
|
||||
m_authMethods |= AuthCookie;
|
||||
}
|
||||
}
|
||||
else if (token.startsWith("COOKIEFILE="))
|
||||
{
|
||||
m_cookieFile = QString::fromLatin1(unquotedString(token.mid(11)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.startsWith("VERSION Tor="))
|
||||
{
|
||||
m_torVersion = QString::fromLatin1(unquotedString(data.mid(12, data.indexOf(' ', 12))));
|
||||
}
|
||||
}
|
78
retroshare-gui/src/TorControl/ProtocolInfoCommand.h
Normal file
78
retroshare-gui/src/TorControl/ProtocolInfoCommand.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef PROTOCOLINFOCOMMAND_H
|
||||
#define PROTOCOLINFOCOMMAND_H
|
||||
|
||||
#include "TorControlCommand.h"
|
||||
#include <QFlags>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class TorControl;
|
||||
|
||||
class ProtocolInfoCommand : public TorControlCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(ProtocolInfoCommand)
|
||||
|
||||
public:
|
||||
enum AuthMethod
|
||||
{
|
||||
AuthUnknown = 0,
|
||||
AuthNull = 0x1,
|
||||
AuthHashedPassword = 0x2,
|
||||
AuthCookie = 0x4
|
||||
};
|
||||
Q_DECLARE_FLAGS(AuthMethods, AuthMethod)
|
||||
|
||||
ProtocolInfoCommand(TorControl *manager);
|
||||
QByteArray build();
|
||||
|
||||
AuthMethods authMethods() const { return m_authMethods; }
|
||||
QString torVersion() const { return m_torVersion; }
|
||||
QString cookieFile() const { return m_cookieFile; }
|
||||
|
||||
protected:
|
||||
virtual void onReply(int statusCode, const QByteArray &data);
|
||||
|
||||
private:
|
||||
TorControl *manager;
|
||||
AuthMethods m_authMethods;
|
||||
QString m_torVersion;
|
||||
QString m_cookieFile;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // PROTOCOLINFOCOMMAND_H
|
146
retroshare-gui/src/TorControl/SecureRNG.cpp
Normal file
146
retroshare-gui/src/TorControl/SecureRNG.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SecureRNG.h"
|
||||
#include <QtDebug>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
#if QT_VERSION >= 0x040700
|
||||
#include <QElapsedTimer>
|
||||
#endif
|
||||
|
||||
bool SecureRNG::seed()
|
||||
{
|
||||
#if QT_VERSION >= 0x040700
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
/* RAND_poll is very unreliable on windows; with older versions of OpenSSL,
|
||||
* it can take up to several minutes to run and has been known to crash.
|
||||
* Even newer versions seem to take around 400ms, which is far too long for
|
||||
* interactive startup. Random data from the windows CSP is used as a seed
|
||||
* instead, as it should be very high quality random and fast. */
|
||||
HCRYPTPROV provider = 0;
|
||||
if (!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
|
||||
{
|
||||
qWarning() << "Failed to acquire CSP context for RNG seed:" << hex << GetLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Same amount of entropy OpenSSL uses, apparently. */
|
||||
char buf[32];
|
||||
|
||||
if (!CryptGenRandom(provider, sizeof(buf), reinterpret_cast<BYTE*>(buf)))
|
||||
{
|
||||
qWarning() << "Failed to get entropy from CSP for RNG seed: " << hex << GetLastError();
|
||||
CryptReleaseContext(provider, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
CryptReleaseContext(provider, 0);
|
||||
|
||||
RAND_seed(buf, sizeof(buf));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
#else
|
||||
if (!RAND_poll())
|
||||
{
|
||||
qWarning() << "OpenSSL RNG seed failed:" << ERR_get_error();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if QT_VERSION >= 0x040700
|
||||
qDebug() << "RNG seed took" << timer.elapsed() << "ms";
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SecureRNG::random(char *buf, int size)
|
||||
{
|
||||
int r = RAND_bytes(reinterpret_cast<unsigned char*>(buf), size);
|
||||
if (r <= 0)
|
||||
qFatal("RNG failed: %lu", ERR_get_error());
|
||||
}
|
||||
|
||||
QByteArray SecureRNG::random(int size)
|
||||
{
|
||||
QByteArray re(size, 0);
|
||||
random(re.data(), size);
|
||||
return re;
|
||||
}
|
||||
|
||||
QByteArray SecureRNG::randomPrintable(int length)
|
||||
{
|
||||
QByteArray re(length, 0);
|
||||
for (int i = 0; i < re.size(); i++)
|
||||
re[i] = randomInt(95) + 32;
|
||||
return re;
|
||||
}
|
||||
|
||||
unsigned SecureRNG::randomInt(unsigned max)
|
||||
{
|
||||
unsigned cutoff = UINT_MAX - (UINT_MAX % max);
|
||||
unsigned value = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
random(reinterpret_cast<char*>(&value), sizeof(value));
|
||||
if (value < cutoff)
|
||||
return value % max;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef UINT64_MAX
|
||||
#define UINT64_MAX ((quint64)-1)
|
||||
#endif
|
||||
|
||||
quint64 SecureRNG::randomInt64(quint64 max)
|
||||
{
|
||||
quint64 cutoff = UINT64_MAX - (UINT64_MAX % max);
|
||||
quint64 value = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
random(reinterpret_cast<char*>(value), sizeof(value));
|
||||
if (value < cutoff)
|
||||
return value % max;
|
||||
}
|
||||
}
|
51
retroshare-gui/src/TorControl/SecureRNG.h
Normal file
51
retroshare-gui/src/TorControl/SecureRNG.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SECURERNG_H
|
||||
#define SECURERNG_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
class SecureRNG
|
||||
{
|
||||
public:
|
||||
static bool seed();
|
||||
|
||||
static void random(char *buf, int size);
|
||||
static QByteArray random(int size);
|
||||
|
||||
static QByteArray randomPrintable(int length);
|
||||
static unsigned randomInt(unsigned max);
|
||||
static quint64 randomInt64(quint64 max);
|
||||
};
|
||||
|
||||
#endif // SECURERNG_H
|
106
retroshare-gui/src/TorControl/SetConfCommand.cpp
Normal file
106
retroshare-gui/src/TorControl/SetConfCommand.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "SetConfCommand.h"
|
||||
#include "StrUtil.h"
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
SetConfCommand::SetConfCommand()
|
||||
: m_resetMode(false)
|
||||
{
|
||||
}
|
||||
|
||||
void SetConfCommand::setResetMode(bool enabled)
|
||||
{
|
||||
m_resetMode = enabled;
|
||||
}
|
||||
|
||||
bool SetConfCommand::isSuccessful() const
|
||||
{
|
||||
return statusCode() == 250;
|
||||
}
|
||||
|
||||
QByteArray SetConfCommand::build(const QByteArray &key, const QByteArray &value)
|
||||
{
|
||||
return build(QList<QPair<QByteArray, QByteArray> >() << qMakePair(key, value));
|
||||
}
|
||||
|
||||
QByteArray SetConfCommand::build(const QVariantMap &data)
|
||||
{
|
||||
QList<QPair<QByteArray, QByteArray> > out;
|
||||
|
||||
for (QVariantMap::ConstIterator it = data.begin(); it != data.end(); it++) {
|
||||
QByteArray key = it.key().toLatin1();
|
||||
|
||||
if (static_cast<QMetaType::Type>(it.value().type()) == QMetaType::QVariantList) {
|
||||
QVariantList values = it.value().value<QVariantList>();
|
||||
foreach (const QVariant &value, values)
|
||||
out.append(qMakePair(key, value.toString().toLatin1()));
|
||||
} else {
|
||||
out.append(qMakePair(key, it.value().toString().toLatin1()));
|
||||
}
|
||||
}
|
||||
|
||||
return build(out);
|
||||
}
|
||||
|
||||
QByteArray SetConfCommand::build(const QList<QPair<QByteArray, QByteArray> > &data)
|
||||
{
|
||||
QByteArray out(m_resetMode ? "RESETCONF" : "SETCONF");
|
||||
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
out += " " + data[i].first;
|
||||
if (!data[i].second.isEmpty())
|
||||
out += "=" + quotedString(data[i].second);
|
||||
}
|
||||
|
||||
out.append("\r\n");
|
||||
return out;
|
||||
}
|
||||
|
||||
void SetConfCommand::onReply(int statusCode, const QByteArray &data)
|
||||
{
|
||||
TorControlCommand::onReply(statusCode, data);
|
||||
if (statusCode != 250)
|
||||
m_errorMessage = QString::fromLatin1(data);
|
||||
}
|
||||
|
||||
void SetConfCommand::onFinished(int statusCode)
|
||||
{
|
||||
TorControlCommand::onFinished(statusCode);
|
||||
if (isSuccessful())
|
||||
emit setConfSucceeded();
|
||||
else
|
||||
emit setConfFailed(statusCode);
|
||||
}
|
||||
|
78
retroshare-gui/src/TorControl/SetConfCommand.h
Normal file
78
retroshare-gui/src/TorControl/SetConfCommand.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SETCONFCOMMAND_H
|
||||
#define SETCONFCOMMAND_H
|
||||
|
||||
#include "TorControlCommand.h"
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QVariant>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class SetConfCommand : public TorControlCommand
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(SetConfCommand)
|
||||
|
||||
Q_PROPERTY(QString errorMessage READ errorMessage CONSTANT)
|
||||
Q_PROPERTY(bool successful READ isSuccessful CONSTANT)
|
||||
|
||||
public:
|
||||
SetConfCommand();
|
||||
|
||||
void setResetMode(bool resetMode);
|
||||
|
||||
QByteArray build(const QByteArray &key, const QByteArray &value);
|
||||
QByteArray build(const QVariantMap &data);
|
||||
QByteArray build(const QList<QPair<QByteArray, QByteArray> > &data);
|
||||
|
||||
QString errorMessage() const { return m_errorMessage; }
|
||||
bool isSuccessful() const;
|
||||
|
||||
signals:
|
||||
void setConfSucceeded();
|
||||
void setConfFailed(int code);
|
||||
|
||||
protected:
|
||||
QString m_errorMessage;
|
||||
bool m_resetMode;
|
||||
|
||||
virtual void onReply(int statusCode, const QByteArray &data);
|
||||
virtual void onFinished(int statusCode);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // SETCONFCOMMAND_H
|
553
retroshare-gui/src/TorControl/Settings.cpp
Normal file
553
retroshare-gui/src/TorControl/Settings.cpp
Normal file
@ -0,0 +1,553 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "Settings.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonParseError>
|
||||
#include <QSaveFile>
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <QPointer>
|
||||
|
||||
class SettingsFilePrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SettingsFile *q;
|
||||
QString filePath;
|
||||
QString errorMessage;
|
||||
QTimer syncTimer;
|
||||
QJsonObject jsonRoot;
|
||||
SettingsObject *rootObject;
|
||||
|
||||
SettingsFilePrivate(SettingsFile *qp);
|
||||
virtual ~SettingsFilePrivate();
|
||||
|
||||
void reset();
|
||||
void setError(const QString &message);
|
||||
bool checkDirPermissions(const QString &path);
|
||||
bool readFile();
|
||||
bool writeFile();
|
||||
|
||||
static QStringList splitPath(const QString &input, bool &ok);
|
||||
QJsonValue read(const QJsonObject &base, const QStringList &path);
|
||||
bool write(const QStringList &path, const QJsonValue &value);
|
||||
|
||||
signals:
|
||||
void modified(const QStringList &path, const QJsonValue &value);
|
||||
|
||||
private slots:
|
||||
void sync();
|
||||
};
|
||||
|
||||
SettingsFile::SettingsFile(QObject *parent)
|
||||
: QObject(parent), d(new SettingsFilePrivate(this))
|
||||
{
|
||||
d->rootObject = new SettingsObject(this, QString());
|
||||
}
|
||||
|
||||
SettingsFile::~SettingsFile()
|
||||
{
|
||||
}
|
||||
|
||||
SettingsFilePrivate::SettingsFilePrivate(SettingsFile *qp)
|
||||
: QObject(qp)
|
||||
, q(qp)
|
||||
, rootObject(0)
|
||||
{
|
||||
syncTimer.setInterval(0);
|
||||
syncTimer.setSingleShot(true);
|
||||
connect(&syncTimer, &QTimer::timeout, this, &SettingsFilePrivate::sync);
|
||||
}
|
||||
|
||||
SettingsFilePrivate::~SettingsFilePrivate()
|
||||
{
|
||||
if (syncTimer.isActive())
|
||||
sync();
|
||||
delete rootObject;
|
||||
}
|
||||
|
||||
void SettingsFilePrivate::reset()
|
||||
{
|
||||
filePath.clear();
|
||||
errorMessage.clear();
|
||||
|
||||
jsonRoot = QJsonObject();
|
||||
emit modified(QStringList(), jsonRoot);
|
||||
}
|
||||
|
||||
QString SettingsFile::filePath() const
|
||||
{
|
||||
return d->filePath;
|
||||
}
|
||||
|
||||
bool SettingsFile::setFilePath(const QString &filePath)
|
||||
{
|
||||
if (d->filePath == filePath)
|
||||
return hasError();
|
||||
|
||||
d->reset();
|
||||
d->filePath = filePath;
|
||||
|
||||
QFileInfo fileInfo(filePath);
|
||||
QDir dir(fileInfo.path());
|
||||
if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
|
||||
d->setError(QStringLiteral("Cannot create directory: %1").arg(dir.path()));
|
||||
return false;
|
||||
}
|
||||
d->checkDirPermissions(fileInfo.path());
|
||||
|
||||
if (!d->readFile())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString SettingsFile::errorMessage() const
|
||||
{
|
||||
return d->errorMessage;
|
||||
}
|
||||
|
||||
bool SettingsFile::hasError() const
|
||||
{
|
||||
return !d->errorMessage.isEmpty();
|
||||
}
|
||||
|
||||
void SettingsFilePrivate::setError(const QString &message)
|
||||
{
|
||||
errorMessage = message;
|
||||
emit q->error();
|
||||
}
|
||||
|
||||
bool SettingsFilePrivate::checkDirPermissions(const QString &path)
|
||||
{
|
||||
static QFile::Permissions desired = QFileDevice::ReadUser | QFileDevice::WriteUser | QFileDevice::ExeUser;
|
||||
static QFile::Permissions ignored = QFileDevice::ReadOwner | QFileDevice::WriteOwner | QFileDevice::ExeOwner;
|
||||
|
||||
QFile file(path);
|
||||
if ((file.permissions() & ~ignored) != desired) {
|
||||
qDebug() << "Correcting permissions on configuration directory";
|
||||
if (!file.setPermissions(desired)) {
|
||||
qWarning() << "Correcting permissions on configuration directory failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SettingsObject *SettingsFile::root()
|
||||
{
|
||||
return d->rootObject;
|
||||
}
|
||||
|
||||
const SettingsObject *SettingsFile::root() const
|
||||
{
|
||||
return d->rootObject;
|
||||
}
|
||||
|
||||
void SettingsFilePrivate::sync()
|
||||
{
|
||||
if (filePath.isEmpty())
|
||||
return;
|
||||
|
||||
syncTimer.stop();
|
||||
writeFile();
|
||||
}
|
||||
|
||||
bool SettingsFilePrivate::readFile()
|
||||
{
|
||||
QFile file(filePath);
|
||||
if (!file.open(QIODevice::ReadWrite)) {
|
||||
setError(file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
if (data.isEmpty() && (file.error() != QFileDevice::NoError || file.size() > 0)) {
|
||||
setError(file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (data.isEmpty()) {
|
||||
jsonRoot = QJsonObject();
|
||||
return true;
|
||||
}
|
||||
|
||||
QJsonParseError parseError;
|
||||
QJsonDocument document = QJsonDocument::fromJson(data, &parseError);
|
||||
if (document.isNull()) {
|
||||
setError(parseError.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!document.isObject()) {
|
||||
setError(QStringLiteral("Invalid configuration file (expected object)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
jsonRoot = document.object();
|
||||
|
||||
emit modified(QStringList(), jsonRoot);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SettingsFilePrivate::writeFile()
|
||||
{
|
||||
QSaveFile file(filePath);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
setError(file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
QJsonDocument document(jsonRoot);
|
||||
QByteArray data = document.toJson();
|
||||
if (data.isEmpty() && !document.isEmpty()) {
|
||||
setError(QStringLiteral("Encoding failure"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file.write(data) < data.size() || !file.commit()) {
|
||||
setError(file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringList SettingsFilePrivate::splitPath(const QString &input, bool &ok)
|
||||
{
|
||||
QStringList components = input.split(QLatin1Char('.'));
|
||||
|
||||
// Allow a leading '.' to simplify concatenation
|
||||
if (!components.isEmpty() && components.first().isEmpty())
|
||||
components.takeFirst();
|
||||
|
||||
// No other empty components, including a trailing .
|
||||
foreach (const QString &word, components) {
|
||||
if (word.isEmpty()) {
|
||||
ok = false;
|
||||
return QStringList();
|
||||
}
|
||||
}
|
||||
|
||||
ok = true;
|
||||
return components;
|
||||
}
|
||||
|
||||
QJsonValue SettingsFilePrivate::read(const QJsonObject &base, const QStringList &path)
|
||||
{
|
||||
QJsonValue current = base;
|
||||
|
||||
foreach (const QString &key, path) {
|
||||
QJsonObject object = current.toObject();
|
||||
if (object.isEmpty() || (current = object.value(key)).isUndefined())
|
||||
return QJsonValue::Undefined;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
// Compare two QJsonValue to find keys that have changed,
|
||||
// recursing into objects and building paths as necessary.
|
||||
typedef QList<QPair<QStringList, QJsonValue> > ModifiedList;
|
||||
static void findModifiedRecursive(ModifiedList &modified, const QStringList &path, const QJsonValue &oldValue, const QJsonValue &newValue)
|
||||
{
|
||||
if (oldValue.isObject() || newValue.isObject()) {
|
||||
// If either is a non-object type, this returns an empty object
|
||||
QJsonObject oldObject = oldValue.toObject();
|
||||
QJsonObject newObject = newValue.toObject();
|
||||
|
||||
// Iterate keys of the original object and compare to new
|
||||
for (QJsonObject::iterator it = oldObject.begin(); it != oldObject.end(); it++) {
|
||||
QJsonValue newSubValue = newObject.value(it.key());
|
||||
if (*it == newSubValue)
|
||||
continue;
|
||||
|
||||
if ((*it).isObject() || newSubValue.isObject())
|
||||
findModifiedRecursive(modified, QStringList() << path << it.key(), *it, newSubValue);
|
||||
else
|
||||
modified.append(qMakePair(QStringList() << path << it.key(), newSubValue));
|
||||
}
|
||||
|
||||
// Iterate keys of the new object that may not be in original
|
||||
for (QJsonObject::iterator it = newObject.begin(); it != newObject.end(); it++) {
|
||||
if (oldObject.contains(it.key()))
|
||||
continue;
|
||||
|
||||
if ((*it).isObject())
|
||||
findModifiedRecursive(modified, QStringList() << path << it.key(), QJsonValue::Undefined, it.value());
|
||||
else
|
||||
modified.append(qMakePair(QStringList() << path << it.key(), it.value()));
|
||||
}
|
||||
} else
|
||||
modified.append(qMakePair(path, newValue));
|
||||
}
|
||||
|
||||
bool SettingsFilePrivate::write(const QStringList &path, const QJsonValue &value)
|
||||
{
|
||||
typedef QVarLengthArray<QPair<QString,QJsonObject> > ObjectStack;
|
||||
ObjectStack stack;
|
||||
QJsonValue current = jsonRoot;
|
||||
QJsonValue originalValue;
|
||||
QString currentKey;
|
||||
|
||||
foreach (const QString &key, path) {
|
||||
const QJsonObject &parent = current.toObject();
|
||||
stack.append(qMakePair(currentKey, parent));
|
||||
current = parent.value(key);
|
||||
currentKey = key;
|
||||
}
|
||||
|
||||
// Stack now contains parent objects starting with the root, and current
|
||||
// is the old value. Write back changes in reverse.
|
||||
if (current == value)
|
||||
return false;
|
||||
originalValue = current;
|
||||
current = value;
|
||||
|
||||
ObjectStack::const_iterator it = stack.end(), begin = stack.begin();
|
||||
while (it != begin) {
|
||||
--it;
|
||||
QJsonObject update = it->second;
|
||||
update.insert(currentKey, current);
|
||||
current = update;
|
||||
currentKey = it->first;
|
||||
}
|
||||
|
||||
// current is now the updated jsonRoot
|
||||
jsonRoot = current.toObject();
|
||||
syncTimer.start();
|
||||
|
||||
ModifiedList modified;
|
||||
findModifiedRecursive(modified, path, originalValue, value);
|
||||
|
||||
for (ModifiedList::iterator it = modified.begin(); it != modified.end(); it++)
|
||||
emit this->modified(it->first, it->second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class SettingsObjectPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SettingsObjectPrivate(SettingsObject *q);
|
||||
|
||||
SettingsObject *q;
|
||||
SettingsFile *file;
|
||||
QStringList path;
|
||||
QJsonObject object;
|
||||
bool invalid;
|
||||
|
||||
void setFile(SettingsFile *file);
|
||||
|
||||
public slots:
|
||||
void modified(const QStringList &absolutePath, const QJsonValue &value);
|
||||
};
|
||||
|
||||
SettingsObject::SettingsObject(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new SettingsObjectPrivate(this))
|
||||
{
|
||||
d->setFile(defaultFile());
|
||||
if (d->file)
|
||||
setPath(QString());
|
||||
}
|
||||
|
||||
SettingsObject::SettingsObject(const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new SettingsObjectPrivate(this))
|
||||
{
|
||||
d->setFile(defaultFile());
|
||||
setPath(path);
|
||||
}
|
||||
|
||||
SettingsObject::SettingsObject(SettingsFile *file, const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new SettingsObjectPrivate(this))
|
||||
{
|
||||
d->setFile(file);
|
||||
setPath(path);
|
||||
}
|
||||
|
||||
SettingsObject::SettingsObject(SettingsObject *base, const QString &path, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new SettingsObjectPrivate(this))
|
||||
{
|
||||
d->setFile(base->d->file);
|
||||
setPath(base->path() + QLatin1Char('.') + path);
|
||||
}
|
||||
|
||||
SettingsObjectPrivate::SettingsObjectPrivate(SettingsObject *qp)
|
||||
: QObject(qp)
|
||||
, q(qp)
|
||||
, file(0)
|
||||
, invalid(true)
|
||||
{
|
||||
}
|
||||
|
||||
void SettingsObjectPrivate::setFile(SettingsFile *value)
|
||||
{
|
||||
if (file == value)
|
||||
return;
|
||||
|
||||
if (file)
|
||||
disconnect(file, 0, this, 0);
|
||||
file = value;
|
||||
if (file)
|
||||
connect(file->d, &SettingsFilePrivate::modified, this, &SettingsObjectPrivate::modified);
|
||||
}
|
||||
|
||||
// Emit SettingsObject::modified with a relative path if path is matched
|
||||
void SettingsObjectPrivate::modified(const QStringList &key, const QJsonValue &value)
|
||||
{
|
||||
if (key.size() < path.size())
|
||||
return;
|
||||
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
if (path[i] != key[i])
|
||||
return;
|
||||
}
|
||||
|
||||
object = file->d->read(file->d->jsonRoot, path).toObject();
|
||||
emit q->modified(QStringList(key.mid(path.size())).join(QLatin1Char('.')), value);
|
||||
emit q->dataChanged();
|
||||
}
|
||||
|
||||
static QPointer<SettingsFile> defaultObjectFile;
|
||||
|
||||
SettingsFile *SettingsObject::defaultFile()
|
||||
{
|
||||
return defaultObjectFile;
|
||||
}
|
||||
|
||||
void SettingsObject::setDefaultFile(SettingsFile *file)
|
||||
{
|
||||
defaultObjectFile = file;
|
||||
}
|
||||
|
||||
QString SettingsObject::path() const
|
||||
{
|
||||
return d->path.join(QLatin1Char('.'));
|
||||
}
|
||||
|
||||
void SettingsObject::setPath(const QString &input)
|
||||
{
|
||||
bool ok = false;
|
||||
QStringList newPath = SettingsFilePrivate::splitPath(input, ok);
|
||||
if (!ok) {
|
||||
d->invalid = true;
|
||||
d->path.clear();
|
||||
d->object = QJsonObject();
|
||||
|
||||
emit pathChanged();
|
||||
emit dataChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->invalid && d->path == newPath)
|
||||
return;
|
||||
|
||||
d->path = newPath;
|
||||
if (d->file) {
|
||||
d->invalid = false;
|
||||
d->object = d->file->d->read(d->file->d->jsonRoot, d->path).toObject();
|
||||
emit dataChanged();
|
||||
}
|
||||
|
||||
emit pathChanged();
|
||||
}
|
||||
|
||||
QJsonObject SettingsObject::data() const
|
||||
{
|
||||
return d->object;
|
||||
}
|
||||
|
||||
void SettingsObject::setData(const QJsonObject &input)
|
||||
{
|
||||
if (d->invalid || d->object == input)
|
||||
return;
|
||||
|
||||
d->object = input;
|
||||
d->file->d->write(d->path, d->object);
|
||||
}
|
||||
|
||||
QJsonValue SettingsObject::read(const QString &key, const QJsonValue &defaultValue) const
|
||||
{
|
||||
bool ok = false;
|
||||
QStringList splitKey = SettingsFilePrivate::splitPath(key, ok);
|
||||
if (d->invalid || !ok || splitKey.isEmpty()) {
|
||||
qDebug() << "Invalid settings read of path" << key;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
QJsonValue ret = d->file->d->read(d->object, splitKey);
|
||||
if (ret.isUndefined())
|
||||
ret = defaultValue;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SettingsObject::write(const QString &key, const QJsonValue &value)
|
||||
{
|
||||
bool ok = false;
|
||||
QStringList splitKey = SettingsFilePrivate::splitPath(key, ok);
|
||||
if (d->invalid || !ok || splitKey.isEmpty()) {
|
||||
qDebug() << "Invalid settings write of path" << key;
|
||||
return;
|
||||
}
|
||||
|
||||
splitKey = d->path + splitKey;
|
||||
d->file->d->write(splitKey, value);
|
||||
}
|
||||
|
||||
void SettingsObject::unset(const QString &key)
|
||||
{
|
||||
write(key, QJsonValue());
|
||||
}
|
||||
|
||||
void SettingsObject::undefine()
|
||||
{
|
||||
if (d->invalid)
|
||||
return;
|
||||
|
||||
d->object = QJsonObject();
|
||||
d->file->d->write(d->path, QJsonValue::Undefined);
|
||||
}
|
||||
|
||||
#include "Settings.moc"
|
257
retroshare-gui/src/TorControl/Settings.h
Normal file
257
retroshare-gui/src/TorControl/Settings.h
Normal file
@ -0,0 +1,257 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SETTINGS_H
|
||||
#define SETTINGS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonValue>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QStringList>
|
||||
#include <QDateTime>
|
||||
|
||||
class SettingsObject;
|
||||
class SettingsFilePrivate;
|
||||
class SettingsObjectPrivate;
|
||||
|
||||
/* SettingsFile represents a JSON-encoded configuration file.
|
||||
*
|
||||
* SettingsFile is an API for reading, writing, and change notification
|
||||
* on JSON-encoded settings files.
|
||||
*
|
||||
* Data is accessed via SettingsObject, either using the root property
|
||||
* or by creating a SettingsObject, optionally using a base path.
|
||||
*/
|
||||
class SettingsFile : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(SettingsFile)
|
||||
|
||||
Q_PROPERTY(SettingsObject *root READ root CONSTANT)
|
||||
Q_PROPERTY(QString filePath READ filePath WRITE setFilePath NOTIFY filePathChanged)
|
||||
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY error)
|
||||
Q_PROPERTY(bool hasError READ hasError NOTIFY error)
|
||||
|
||||
public:
|
||||
explicit SettingsFile(QObject *parent = 0);
|
||||
virtual ~SettingsFile();
|
||||
|
||||
QString filePath() const;
|
||||
bool setFilePath(const QString &filePath);
|
||||
|
||||
QString errorMessage() const;
|
||||
bool hasError() const;
|
||||
|
||||
SettingsObject *root();
|
||||
const SettingsObject *root() const;
|
||||
|
||||
signals:
|
||||
void filePathChanged();
|
||||
void error();
|
||||
|
||||
private:
|
||||
SettingsFilePrivate *d;
|
||||
|
||||
friend class SettingsObject;
|
||||
friend class SettingsObjectPrivate;
|
||||
};
|
||||
|
||||
/* SettingsObject reads and writes data within a SettingsFile
|
||||
*
|
||||
* A SettingsObject is associated with a SettingsFile and represents an object
|
||||
* tree within that file. It refers to the JSON object tree using a path
|
||||
* notation with keys separated by '.'. For example:
|
||||
*
|
||||
* {
|
||||
* "one": {
|
||||
* "two": {
|
||||
* "three": "value"
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* With this data, a SettingsObject with an empty path can read with the path
|
||||
* "one.two.three", and a SettingsObject with a path of "one.two" can simply
|
||||
* read or write on "three".
|
||||
*
|
||||
* Multiple SettingsObjects may be created for the same path, and will be kept
|
||||
* synchronized with changes. The modified signal is emitted for all changes
|
||||
* affecting keys within a path, including writes of object trees and from other
|
||||
* instances.
|
||||
*/
|
||||
class SettingsObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(SettingsObject)
|
||||
|
||||
Q_PROPERTY(QString path READ path WRITE setPath NOTIFY pathChanged)
|
||||
Q_PROPERTY(QJsonObject data READ data WRITE setData NOTIFY dataChanged)
|
||||
|
||||
public:
|
||||
explicit SettingsObject(QObject *parent = 0);
|
||||
explicit SettingsObject(const QString &path, QObject *parent = 0);
|
||||
explicit SettingsObject(SettingsFile *file, const QString &path, QObject *parent = 0);
|
||||
explicit SettingsObject(SettingsObject *base, const QString &path, QObject *parent = 0);
|
||||
|
||||
/* Specify a SettingsFile to use by default on SettingsObject instances.
|
||||
*
|
||||
* After calling setDefaultFile, a SettingsObject created without any file, e.g.:
|
||||
*
|
||||
* SettingsObject settings;
|
||||
* SettingsObject animals(QStringLiteral("animals"));
|
||||
*
|
||||
* Will use the specified SettingsFile instance by default. This is a convenience
|
||||
* over passing around instances of SettingsFile in application use cases, and is
|
||||
* particularly useful for QML.
|
||||
*/
|
||||
static SettingsFile *defaultFile();
|
||||
static void setDefaultFile(SettingsFile *file);
|
||||
|
||||
QString path() const;
|
||||
void setPath(const QString &path);
|
||||
|
||||
QJsonObject data() const;
|
||||
void setData(const QJsonObject &data);
|
||||
|
||||
Q_INVOKABLE QJsonValue read(const QString &key, const QJsonValue &defaultValue = QJsonValue::Undefined) const;
|
||||
template<typename T> T read(const QString &key) const;
|
||||
Q_INVOKABLE void write(const QString &key, const QJsonValue &value);
|
||||
template<typename T> void write(const QString &key, const T &value);
|
||||
Q_INVOKABLE void unset(const QString &key);
|
||||
|
||||
// const char* key overloads
|
||||
QJsonValue read(const char *key, const QJsonValue &defaultValue = QJsonValue::Undefined) const
|
||||
{
|
||||
return read(QString::fromLatin1(key), defaultValue);
|
||||
}
|
||||
template<typename T> T read(const char *key) const
|
||||
{
|
||||
return read<T>(QString::fromLatin1(key));
|
||||
}
|
||||
void write(const char *key, const QJsonValue &value)
|
||||
{
|
||||
write(QString::fromLatin1(key), value);
|
||||
}
|
||||
template<typename T> void write(const char *key, const T &value)
|
||||
{
|
||||
write<T>(QString::fromLatin1(key), value);
|
||||
}
|
||||
void unset(const char *key)
|
||||
{
|
||||
unset(QString::fromLatin1(key));
|
||||
}
|
||||
|
||||
Q_INVOKABLE void undefine();
|
||||
|
||||
signals:
|
||||
void pathChanged();
|
||||
void dataChanged();
|
||||
|
||||
void modified(const QString &path, const QJsonValue &value);
|
||||
|
||||
private:
|
||||
SettingsObjectPrivate *d;
|
||||
};
|
||||
|
||||
template<typename T> inline void SettingsObject::write(const QString &key, const T &value)
|
||||
{
|
||||
write(key, QJsonValue(value));
|
||||
}
|
||||
|
||||
template<> inline QString SettingsObject::read<QString>(const QString &key) const
|
||||
{
|
||||
return read(key).toString();
|
||||
}
|
||||
|
||||
template<> inline QJsonArray SettingsObject::read<QJsonArray>(const QString &key) const
|
||||
{
|
||||
return read(key).toArray();
|
||||
}
|
||||
|
||||
template<> inline QJsonObject SettingsObject::read<QJsonObject>(const QString &key) const
|
||||
{
|
||||
return read(key).toObject();
|
||||
}
|
||||
|
||||
template<> inline double SettingsObject::read<double>(const QString &key) const
|
||||
{
|
||||
return read(key).toDouble();
|
||||
}
|
||||
|
||||
template<> inline int SettingsObject::read<int>(const QString &key) const
|
||||
{
|
||||
return read(key).toInt();
|
||||
}
|
||||
|
||||
template<> inline bool SettingsObject::read<bool>(const QString &key) const
|
||||
{
|
||||
return read(key).toBool();
|
||||
}
|
||||
|
||||
template<> inline QDateTime SettingsObject::read<QDateTime>(const QString &key) const
|
||||
{
|
||||
QString value = read(key).toString();
|
||||
if (value.isEmpty())
|
||||
return QDateTime();
|
||||
return QDateTime::fromString(value, Qt::ISODate).toLocalTime();
|
||||
}
|
||||
|
||||
template<> inline void SettingsObject::write<QDateTime>(const QString &key, const QDateTime &value)
|
||||
{
|
||||
write(key, QJsonValue(value.toUTC().toString(Qt::ISODate)));
|
||||
}
|
||||
|
||||
// Explicitly store value encoded as base64. Decodes and casts implicitly to QByteArray for reads.
|
||||
class Base64Encode
|
||||
{
|
||||
public:
|
||||
explicit Base64Encode(const QByteArray &value) : d(value) { }
|
||||
operator QByteArray() { return d; }
|
||||
QByteArray encoded() const { return d.toBase64(); }
|
||||
|
||||
private:
|
||||
QByteArray d;
|
||||
};
|
||||
|
||||
template<> inline Base64Encode SettingsObject::read<Base64Encode>(const QString &key) const
|
||||
{
|
||||
return Base64Encode(QByteArray::fromBase64(read(key).toString().toLatin1()));
|
||||
}
|
||||
|
||||
template<> inline void SettingsObject::write<Base64Encode>(const QString &key, const Base64Encode &value)
|
||||
{
|
||||
write(key, QJsonValue(QString::fromLatin1(value.encoded())));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
118
retroshare-gui/src/TorControl/StrUtil.cpp
Normal file
118
retroshare-gui/src/TorControl/StrUtil.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "StrUtil.h"
|
||||
|
||||
QByteArray quotedString(const QByteArray &string)
|
||||
{
|
||||
QByteArray out;
|
||||
out.reserve(string.size() * 2);
|
||||
|
||||
out.append('"');
|
||||
|
||||
for (int i = 0; i < string.size(); ++i)
|
||||
{
|
||||
switch (string[i])
|
||||
{
|
||||
case '"':
|
||||
out.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
out.append("\\\\");
|
||||
break;
|
||||
default:
|
||||
out.append(string[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out.append('"');
|
||||
return out;
|
||||
}
|
||||
|
||||
QByteArray unquotedString(const QByteArray &string)
|
||||
{
|
||||
if (string.size() < 2 || string[0] != '"')
|
||||
return string;
|
||||
|
||||
QByteArray out;
|
||||
out.reserve(string.size() - 2);
|
||||
|
||||
for (int i = 1; i < string.size(); ++i)
|
||||
{
|
||||
switch (string[i])
|
||||
{
|
||||
case '\\':
|
||||
if (++i < string.size())
|
||||
out.append(string[i]);
|
||||
break;
|
||||
case '"':
|
||||
return out;
|
||||
default:
|
||||
out.append(string[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator)
|
||||
{
|
||||
QList<QByteArray> out;
|
||||
bool inquote = false;
|
||||
int start = 0;
|
||||
|
||||
for (int i = 0; i < input.size(); ++i)
|
||||
{
|
||||
switch (input[i])
|
||||
{
|
||||
case '"':
|
||||
inquote = !inquote;
|
||||
break;
|
||||
case '\\':
|
||||
if (inquote)
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inquote && input[i] == separator)
|
||||
{
|
||||
out.append(input.mid(start, i - start));
|
||||
start = i+1;
|
||||
}
|
||||
}
|
||||
|
||||
if (start < input.size())
|
||||
out.append(input.mid(start));
|
||||
|
||||
return out;
|
||||
}
|
46
retroshare-gui/src/TorControl/StrUtil.h
Normal file
46
retroshare-gui/src/TorControl/StrUtil.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef STRINGUTIL_H
|
||||
#define STRINGUTIL_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QList>
|
||||
|
||||
QByteArray quotedString(const QByteArray &string);
|
||||
|
||||
/* Return the unquoted contents of a string, either until an end quote or an unescaped separator character. */
|
||||
QByteArray unquotedString(const QByteArray &string);
|
||||
|
||||
QList<QByteArray> splitQuotedStrings(const QByteArray &input, char separator);
|
||||
|
||||
#endif // STRINGUTIL_H
|
788
retroshare-gui/src/TorControl/TorControl.cpp
Normal file
788
retroshare-gui/src/TorControl/TorControl.cpp
Normal file
@ -0,0 +1,788 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "TorControl.h"
|
||||
#include "TorControlSocket.h"
|
||||
#include "HiddenService.h"
|
||||
#include "ProtocolInfoCommand.h"
|
||||
#include "AuthenticateCommand.h"
|
||||
#include "SetConfCommand.h"
|
||||
#include "GetConfCommand.h"
|
||||
#include "AddOnionCommand.h"
|
||||
#include "StrUtil.h"
|
||||
#include "Settings.h"
|
||||
#include "PendingOperation.h"
|
||||
#include <QHostAddress>
|
||||
#include <QDir>
|
||||
#include <QNetworkProxy>
|
||||
//#include <QQmlEngine>
|
||||
#include <QTimer>
|
||||
#include <QSaveFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
|
||||
Tor::TorControl *torControl = 0;
|
||||
|
||||
class nullstream: public std::ostream {};
|
||||
|
||||
static std::ostream& torctrldebug()
|
||||
{
|
||||
static nullstream null ;
|
||||
|
||||
if(true)
|
||||
return std::cerr << time(NULL) << ":TOR CONTROL: " ;
|
||||
else
|
||||
return null ;
|
||||
}
|
||||
|
||||
#define torCtrlDebug torctrldebug
|
||||
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
namespace Tor {
|
||||
|
||||
class TorControlPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorControl *q;
|
||||
|
||||
TorControlSocket *socket;
|
||||
QHostAddress torAddress;
|
||||
QString errorMessage;
|
||||
QString torVersion;
|
||||
QByteArray authPassword;
|
||||
QHostAddress socksAddress;
|
||||
QList<HiddenService*> services;
|
||||
quint16 controlPort, socksPort;
|
||||
TorControl::Status status;
|
||||
TorControl::TorStatus torStatus;
|
||||
QVariantMap bootstrapStatus;
|
||||
bool hasOwnership;
|
||||
|
||||
TorControlPrivate(TorControl *parent);
|
||||
|
||||
void setStatus(TorControl::Status status);
|
||||
void setTorStatus(TorControl::TorStatus status);
|
||||
|
||||
void getTorInfo();
|
||||
void publishServices();
|
||||
|
||||
public slots:
|
||||
void socketConnected();
|
||||
void socketDisconnected();
|
||||
void socketError();
|
||||
|
||||
void authenticateReply();
|
||||
void protocolInfoReply();
|
||||
void getTorInfoReply();
|
||||
void setError(const QString &message);
|
||||
|
||||
void statusEvent(int code, const QByteArray &data);
|
||||
void updateBootstrap(const QList<QByteArray> &data);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TorControl::TorControl(QObject *parent)
|
||||
: QObject(parent), d(new TorControlPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
TorControlPrivate::TorControlPrivate(TorControl *parent)
|
||||
: QObject(parent), q(parent), controlPort(0), socksPort(0),
|
||||
status(TorControl::NotConnected), torStatus(TorControl::TorUnknown),
|
||||
hasOwnership(false)
|
||||
{
|
||||
socket = new TorControlSocket(this);
|
||||
QObject::connect(socket, SIGNAL(connected()), this, SLOT(socketConnected()));
|
||||
QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
|
||||
QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError()));
|
||||
QObject::connect(socket, SIGNAL(error(QString)), this, SLOT(setError(QString)));
|
||||
}
|
||||
|
||||
QNetworkProxy TorControl::connectionProxy()
|
||||
{
|
||||
return QNetworkProxy(QNetworkProxy::Socks5Proxy, d->socksAddress.toString(), d->socksPort);
|
||||
}
|
||||
|
||||
void TorControlPrivate::setStatus(TorControl::Status n)
|
||||
{
|
||||
if (n == status)
|
||||
return;
|
||||
|
||||
TorControl::Status old = status;
|
||||
status = n;
|
||||
|
||||
if (old == TorControl::Error)
|
||||
errorMessage.clear();
|
||||
|
||||
emit q->statusChanged(status, old);
|
||||
|
||||
if (status == TorControl::Connected && old < TorControl::Connected)
|
||||
emit q->connected();
|
||||
else if (status < TorControl::Connected && old >= TorControl::Connected)
|
||||
emit q->disconnected();
|
||||
}
|
||||
|
||||
void TorControlPrivate::setTorStatus(TorControl::TorStatus n)
|
||||
{
|
||||
if (n == torStatus)
|
||||
return;
|
||||
|
||||
TorControl::TorStatus old = torStatus;
|
||||
torStatus = n;
|
||||
emit q->torStatusChanged(torStatus, old);
|
||||
emit q->connectivityChanged();
|
||||
|
||||
if (torStatus == TorControl::TorReady && socksAddress.isNull()) {
|
||||
// Request info again to read the SOCKS port
|
||||
getTorInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void TorControlPrivate::setError(const QString &message)
|
||||
{
|
||||
errorMessage = message;
|
||||
setStatus(TorControl::Error);
|
||||
|
||||
qWarning() << "torctrl: Error:" << errorMessage;
|
||||
|
||||
socket->abort();
|
||||
|
||||
QTimer::singleShot(15000, q, SLOT(reconnect()));
|
||||
}
|
||||
|
||||
TorControl::Status TorControl::status() const
|
||||
{
|
||||
return d->status;
|
||||
}
|
||||
|
||||
TorControl::TorStatus TorControl::torStatus() const
|
||||
{
|
||||
return d->torStatus;
|
||||
}
|
||||
|
||||
QString TorControl::torVersion() const
|
||||
{
|
||||
return d->torVersion;
|
||||
}
|
||||
|
||||
QString TorControl::errorMessage() const
|
||||
{
|
||||
return d->errorMessage;
|
||||
}
|
||||
|
||||
bool TorControl::hasConnectivity() const
|
||||
{
|
||||
return torStatus() == TorReady && !d->socksAddress.isNull();
|
||||
}
|
||||
|
||||
QHostAddress TorControl::socksAddress() const
|
||||
{
|
||||
return d->socksAddress;
|
||||
}
|
||||
|
||||
quint16 TorControl::socksPort() const
|
||||
{
|
||||
return d->socksPort;
|
||||
}
|
||||
|
||||
QList<HiddenService*> TorControl::hiddenServices() const
|
||||
{
|
||||
return d->services;
|
||||
}
|
||||
|
||||
QVariantMap TorControl::bootstrapStatus() const
|
||||
{
|
||||
return d->bootstrapStatus;
|
||||
}
|
||||
|
||||
void TorControl::setAuthPassword(const QByteArray &password)
|
||||
{
|
||||
d->authPassword = password;
|
||||
}
|
||||
|
||||
void TorControl::connect(const QHostAddress &address, quint16 port)
|
||||
{
|
||||
if (status() > Connecting)
|
||||
{
|
||||
torCtrlDebug() << "Ignoring TorControl::connect due to existing connection" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
d->torAddress = address;
|
||||
d->controlPort = port;
|
||||
d->setTorStatus(TorUnknown);
|
||||
|
||||
bool b = d->socket->blockSignals(true);
|
||||
d->socket->abort();
|
||||
d->socket->blockSignals(b);
|
||||
|
||||
d->setStatus(Connecting);
|
||||
d->socket->connectToHost(address, port);
|
||||
}
|
||||
|
||||
void TorControl::reconnect()
|
||||
{
|
||||
Q_ASSERT(!d->torAddress.isNull() && d->controlPort);
|
||||
if (d->torAddress.isNull() || !d->controlPort || status() >= Connecting)
|
||||
return;
|
||||
|
||||
d->setStatus(Connecting);
|
||||
d->socket->connectToHost(d->torAddress, d->controlPort);
|
||||
}
|
||||
|
||||
void TorControlPrivate::authenticateReply()
|
||||
{
|
||||
AuthenticateCommand *command = qobject_cast<AuthenticateCommand*>(sender());
|
||||
Q_ASSERT(command);
|
||||
Q_ASSERT(status == TorControl::Authenticating);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
if (!command->isSuccessful()) {
|
||||
setError(command->errorMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
torCtrlDebug() << "torctrl: Authentication successful" << std::endl;
|
||||
setStatus(TorControl::Connected);
|
||||
|
||||
setTorStatus(TorControl::TorUnknown);
|
||||
|
||||
TorControlCommand *clientEvents = new TorControlCommand;
|
||||
connect(clientEvents, &TorControlCommand::replyLine, this, &TorControlPrivate::statusEvent);
|
||||
socket->registerEvent("STATUS_CLIENT", clientEvents);
|
||||
|
||||
getTorInfo();
|
||||
publishServices();
|
||||
|
||||
// XXX Fix old configurations that would store unwanted options in torrc.
|
||||
// This can be removed some suitable amount of time after 1.0.4.
|
||||
if (hasOwnership)
|
||||
q->saveConfiguration();
|
||||
}
|
||||
|
||||
|
||||
void TorControlPrivate::socketConnected()
|
||||
{
|
||||
Q_ASSERT(status == TorControl::Connecting);
|
||||
|
||||
torCtrlDebug() << "torctrl: Connected socket; querying information" << std::endl;
|
||||
setStatus(TorControl::Authenticating);
|
||||
|
||||
ProtocolInfoCommand *command = new ProtocolInfoCommand(q);
|
||||
connect(command, &TorControlCommand::finished, this, &TorControlPrivate::protocolInfoReply);
|
||||
socket->sendCommand(command, command->build());
|
||||
}
|
||||
|
||||
void TorControlPrivate::socketDisconnected()
|
||||
{
|
||||
/* Clear some internal state */
|
||||
torVersion.clear();
|
||||
socksAddress.clear();
|
||||
socksPort = 0;
|
||||
setTorStatus(TorControl::TorUnknown);
|
||||
|
||||
/* This emits the disconnected() signal as well */
|
||||
setStatus(TorControl::NotConnected);
|
||||
}
|
||||
|
||||
void TorControlPrivate::socketError()
|
||||
{
|
||||
setError(QStringLiteral("Connection failed: %1").arg(socket->errorString()));
|
||||
}
|
||||
|
||||
void TorControlPrivate::protocolInfoReply()
|
||||
{
|
||||
ProtocolInfoCommand *info = qobject_cast<ProtocolInfoCommand*>(sender());
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
torVersion = info->torVersion();
|
||||
|
||||
if (status == TorControl::Authenticating)
|
||||
{
|
||||
AuthenticateCommand *auth = new AuthenticateCommand;
|
||||
connect(auth, &TorControlCommand::finished, this, &TorControlPrivate::authenticateReply);
|
||||
|
||||
QByteArray data;
|
||||
ProtocolInfoCommand::AuthMethods methods = info->authMethods();
|
||||
|
||||
if (methods.testFlag(ProtocolInfoCommand::AuthNull))
|
||||
{
|
||||
torCtrlDebug() << "torctrl: Using null authentication" << std::endl;
|
||||
data = auth->build();
|
||||
}
|
||||
else if (methods.testFlag(ProtocolInfoCommand::AuthCookie) && !info->cookieFile().isEmpty())
|
||||
{
|
||||
QString cookieFile = info->cookieFile();
|
||||
QString cookieError;
|
||||
torCtrlDebug() << "torctrl: Using cookie authentication with file" << cookieFile.toStdString() << std::endl;
|
||||
|
||||
QFile file(cookieFile);
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QByteArray cookie = file.readAll();
|
||||
file.close();
|
||||
|
||||
/* Simple test to avoid a vulnerability where any process listening on what we think is
|
||||
* the control port could trick us into sending the contents of an arbitrary file */
|
||||
if (cookie.size() == 32)
|
||||
data = auth->build(cookie);
|
||||
else
|
||||
cookieError = QStringLiteral("Unexpected file size");
|
||||
}
|
||||
else
|
||||
cookieError = file.errorString();
|
||||
|
||||
if (!cookieError.isNull() || data.isNull())
|
||||
{
|
||||
/* If we know a password and password authentication is allowed, try using that instead.
|
||||
* This is a strange corner case that will likely never happen in a normal configuration,
|
||||
* but it has happened. */
|
||||
if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty())
|
||||
{
|
||||
torCtrlDebug() << "torctrl: Unable to read authentication cookie file:" << cookieError.toStdString() << std::endl;
|
||||
goto usePasswordAuth;
|
||||
}
|
||||
|
||||
setError(QStringLiteral("Unable to read authentication cookie file: %1").arg(cookieError));
|
||||
delete auth;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword) && !authPassword.isEmpty())
|
||||
{
|
||||
usePasswordAuth:
|
||||
torCtrlDebug() << "torctrl: Using hashed password authentication" << std::endl;
|
||||
data = auth->build(authPassword);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (methods.testFlag(ProtocolInfoCommand::AuthHashedPassword))
|
||||
setError(QStringLiteral("Tor requires a control password to connect, but no password is configured."));
|
||||
else
|
||||
setError(QStringLiteral("Tor is not configured to accept any supported authentication methods."));
|
||||
delete auth;
|
||||
return;
|
||||
}
|
||||
|
||||
socket->sendCommand(auth, data);
|
||||
}
|
||||
}
|
||||
|
||||
void TorControlPrivate::getTorInfo()
|
||||
{
|
||||
Q_ASSERT(q->isConnected());
|
||||
|
||||
GetConfCommand *command = new GetConfCommand(GetConfCommand::GetInfo);
|
||||
connect(command, &TorControlCommand::finished, this, &TorControlPrivate::getTorInfoReply);
|
||||
|
||||
QList<QByteArray> keys;
|
||||
keys << QByteArray("status/circuit-established") << QByteArray("status/bootstrap-phase");
|
||||
|
||||
/* If these are set in the config, they override the automatic behavior. */
|
||||
SettingsObject settings(QStringLiteral("tor"));
|
||||
QHostAddress forceAddress(settings.read("socksAddress").toString());
|
||||
quint16 port = (quint16)settings.read("socksPort").toInt();
|
||||
|
||||
if (!forceAddress.isNull() && port) {
|
||||
torCtrlDebug() << "torctrl: Using manually specified SOCKS connection settings";
|
||||
socksAddress = forceAddress;
|
||||
socksPort = port;
|
||||
emit q->connectivityChanged();
|
||||
} else
|
||||
keys << QByteArray("net/listeners/socks");
|
||||
|
||||
socket->sendCommand(command, command->build(keys));
|
||||
}
|
||||
|
||||
void TorControlPrivate::getTorInfoReply()
|
||||
{
|
||||
GetConfCommand *command = qobject_cast<GetConfCommand*>(sender());
|
||||
if (!command || !q->isConnected())
|
||||
return;
|
||||
|
||||
QList<QByteArray> listenAddresses = splitQuotedStrings(command->get(QByteArray("net/listeners/socks")).toString().toLatin1(), ' ');
|
||||
for (QList<QByteArray>::Iterator it = listenAddresses.begin(); it != listenAddresses.end(); ++it) {
|
||||
QByteArray value = unquotedString(*it);
|
||||
int sepp = value.indexOf(':');
|
||||
QHostAddress address(QString::fromLatin1(value.mid(0, sepp)));
|
||||
quint16 port = (quint16)value.mid(sepp+1).toUInt();
|
||||
|
||||
/* Use the first address that matches the one used for this control connection. If none do,
|
||||
* just use the first address and rely on the user to reconfigure if necessary (not a problem;
|
||||
* their setup is already very customized) */
|
||||
if (socksAddress.isNull() || address == socket->peerAddress()) {
|
||||
socksAddress = address;
|
||||
socksPort = port;
|
||||
if (address == socket->peerAddress())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* It is not immediately an error to have no SOCKS address; when DisableNetwork is set there won't be a
|
||||
* listener yet. To handle that situation, we'll try to read the socks address again when TorReady state
|
||||
* is reached. */
|
||||
if (!socksAddress.isNull()) {
|
||||
torCtrlDebug() << "torctrl: SOCKS address is " << socksAddress.toString().toStdString() << ":" << socksPort << std::endl;
|
||||
emit q->connectivityChanged();
|
||||
}
|
||||
|
||||
if (command->get(QByteArray("status/circuit-established")).toInt() == 1) {
|
||||
torCtrlDebug() << "torctrl: Tor indicates that circuits have been established; state is TorReady" << std::endl;
|
||||
setTorStatus(TorControl::TorReady);
|
||||
} else {
|
||||
setTorStatus(TorControl::TorOffline);
|
||||
}
|
||||
|
||||
QByteArray bootstrap = command->get(QByteArray("status/bootstrap-phase")).toString().toLatin1();
|
||||
if (!bootstrap.isEmpty())
|
||||
updateBootstrap(splitQuotedStrings(bootstrap, ' '));
|
||||
}
|
||||
|
||||
void TorControl::addHiddenService(HiddenService *service)
|
||||
{
|
||||
if (d->services.contains(service))
|
||||
return;
|
||||
|
||||
d->services.append(service);
|
||||
}
|
||||
|
||||
void TorControlPrivate::publishServices()
|
||||
{
|
||||
torCtrlDebug() << "Publish Services... " ;
|
||||
|
||||
Q_ASSERT(q->isConnected());
|
||||
if (services.isEmpty())
|
||||
{
|
||||
std::cerr << "No service regstered!" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
SettingsObject settings(QStringLiteral("tor"));
|
||||
if (settings.read("neverPublishServices").toBool())
|
||||
{
|
||||
torCtrlDebug() << "torctrl: Skipping service publication because neverPublishService is enabled" << std::endl;
|
||||
|
||||
/* Call servicePublished under the assumption that they're published externally. */
|
||||
for (QList<HiddenService*>::Iterator it = services.begin(); it != services.end(); ++it)
|
||||
(*it)->servicePublished();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (q->torVersionAsNewAs(QStringLiteral("0.2.7"))) {
|
||||
foreach (HiddenService *service, services) {
|
||||
if (service->hostname().isEmpty())
|
||||
torCtrlDebug() << "torctrl: Creating a new hidden service" << std::endl;
|
||||
else
|
||||
torCtrlDebug() << "torctrl: Publishing hidden service: " << service->hostname().toStdString() << std::endl;
|
||||
AddOnionCommand *onionCommand = new AddOnionCommand(service);
|
||||
QObject::connect(onionCommand, &AddOnionCommand::succeeded, service, &HiddenService::servicePublished);
|
||||
socket->sendCommand(onionCommand, onionCommand->build());
|
||||
}
|
||||
} else {
|
||||
torCtrlDebug() << "torctrl: Using legacy SETCONF hidden service configuration for tor" << torVersion.toStdString() << std::endl;
|
||||
SetConfCommand *command = new SetConfCommand;
|
||||
QList<QPair<QByteArray,QByteArray> > torConfig;
|
||||
|
||||
foreach (HiddenService *service, services)
|
||||
{
|
||||
if (service->dataPath().isEmpty())
|
||||
continue;
|
||||
|
||||
if (service->privateKey().isLoaded() && !QFile::exists(service->dataPath() + QStringLiteral("/private_key"))) {
|
||||
// This case can happen if tor is downgraded after the profile is created
|
||||
qWarning() << "Cannot publish ephemeral hidden services with this version of tor; skipping";
|
||||
continue;
|
||||
}
|
||||
|
||||
torCtrlDebug() << "torctrl: Configuring hidden service at" << service->dataPath().toStdString() << std::endl;
|
||||
|
||||
QDir dir(service->dataPath());
|
||||
torConfig.append(qMakePair(QByteArray("HiddenServiceDir"), dir.absolutePath().toLocal8Bit()));
|
||||
|
||||
const QList<HiddenService::Target> &targets = service->targets();
|
||||
for (QList<HiddenService::Target>::ConstIterator tit = targets.begin(); tit != targets.end(); ++tit)
|
||||
{
|
||||
QString target = QString::fromLatin1("%1 %2:%3").arg(tit->servicePort)
|
||||
.arg(tit->targetAddress.toString())
|
||||
.arg(tit->targetPort);
|
||||
torConfig.append(qMakePair(QByteArray("HiddenServicePort"), target.toLatin1()));
|
||||
}
|
||||
|
||||
QObject::connect(command, &SetConfCommand::setConfSucceeded, service, &HiddenService::servicePublished);
|
||||
}
|
||||
|
||||
if (!torConfig.isEmpty())
|
||||
socket->sendCommand(command, command->build(torConfig));
|
||||
}
|
||||
}
|
||||
|
||||
void TorControl::shutdown()
|
||||
{
|
||||
if (!hasOwnership()) {
|
||||
qWarning() << "torctrl: Ignoring shutdown command for a tor instance I don't own";
|
||||
return;
|
||||
}
|
||||
|
||||
d->socket->sendCommand("SIGNAL SHUTDOWN\r\n");
|
||||
}
|
||||
|
||||
void TorControl::shutdownSync()
|
||||
{
|
||||
if (!hasOwnership()) {
|
||||
qWarning() << "torctrl: Ignoring shutdown command for a tor instance I don't own";
|
||||
return;
|
||||
}
|
||||
|
||||
shutdown();
|
||||
while (d->socket->bytesToWrite())
|
||||
{
|
||||
if (!d->socket->waitForBytesWritten(5000))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void TorControlPrivate::statusEvent(int code, const QByteArray &data)
|
||||
{
|
||||
Q_UNUSED(code);
|
||||
|
||||
QList<QByteArray> tokens = splitQuotedStrings(data.trimmed(), ' ');
|
||||
if (tokens.size() < 3)
|
||||
return;
|
||||
|
||||
torCtrlDebug() << "torctrl: status event:" << QString(data.trimmed()).toStdString() << std::endl;
|
||||
|
||||
if (tokens[2] == "CIRCUIT_ESTABLISHED") {
|
||||
setTorStatus(TorControl::TorReady);
|
||||
} else if (tokens[2] == "CIRCUIT_NOT_ESTABLISHED") {
|
||||
setTorStatus(TorControl::TorOffline);
|
||||
} else if (tokens[2] == "BOOTSTRAP") {
|
||||
tokens.takeFirst();
|
||||
updateBootstrap(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
void TorControlPrivate::updateBootstrap(const QList<QByteArray> &data)
|
||||
{
|
||||
bootstrapStatus.clear();
|
||||
// WARN or NOTICE
|
||||
bootstrapStatus[QStringLiteral("severity")] = data.value(0);
|
||||
for (int i = 1; i < data.size(); i++) {
|
||||
int equals = data[i].indexOf('=');
|
||||
QString key = QString::fromLatin1(data[i].mid(0, equals));
|
||||
QString value;
|
||||
if (equals >= 0)
|
||||
value = QString::fromLatin1(unquotedString(data[i].mid(equals + 1)));
|
||||
bootstrapStatus[key.toLower()] = value;
|
||||
}
|
||||
|
||||
//torCtrlDebug() << bootstrapStatus << std::endl;
|
||||
|
||||
emit q->bootstrapStatusChanged();
|
||||
}
|
||||
|
||||
QObject *TorControl::getConfiguration(const QString &options)
|
||||
{
|
||||
GetConfCommand *command = new GetConfCommand(GetConfCommand::GetConf);
|
||||
d->socket->sendCommand(command, command->build(options.toLatin1()));
|
||||
|
||||
//QQmlEngine::setObjectOwnership(command, QQmlEngine::CppOwnership);
|
||||
return command;
|
||||
}
|
||||
|
||||
QObject *TorControl::setConfiguration(const QVariantMap &options)
|
||||
{
|
||||
SetConfCommand *command = new SetConfCommand;
|
||||
command->setResetMode(true);
|
||||
d->socket->sendCommand(command, command->build(options));
|
||||
|
||||
//QQmlEngine::setObjectOwnership(command, QQmlEngine::CppOwnership);
|
||||
return command;
|
||||
}
|
||||
|
||||
namespace Tor {
|
||||
|
||||
class SaveConfigOperation : public PendingOperation
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SaveConfigOperation(QObject *parent)
|
||||
: PendingOperation(parent), command(0)
|
||||
{
|
||||
}
|
||||
|
||||
void start(TorControlSocket *socket)
|
||||
{
|
||||
Q_ASSERT(!command);
|
||||
command = new GetConfCommand(GetConfCommand::GetInfo);
|
||||
QObject::connect(command, &TorControlCommand::finished, this, &SaveConfigOperation::configTextReply);
|
||||
socket->sendCommand(command, command->build(QList<QByteArray>() << "config-text" << "config-file"));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void configTextReply()
|
||||
{
|
||||
Q_ASSERT(command);
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
QString path = QFile::decodeName(command->get("config-file").toByteArray());
|
||||
if (path.isEmpty()) {
|
||||
finishWithError(QStringLiteral("Cannot write torrc without knowing its path"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Out of paranoia, refuse to write any file not named 'torrc', or if the
|
||||
// file doesn't exist
|
||||
QFileInfo fileInfo(path);
|
||||
if (fileInfo.fileName() != QStringLiteral("torrc") || !fileInfo.exists()) {
|
||||
finishWithError(QStringLiteral("Refusing to write torrc to unacceptable path %1").arg(path));
|
||||
return;
|
||||
}
|
||||
|
||||
QSaveFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
finishWithError(QStringLiteral("Failed opening torrc file for writing: %1").arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove these keys when writing torrc; they are set at runtime and contain
|
||||
// absolute paths or port numbers
|
||||
static const char *bannedKeys[] = {
|
||||
"ControlPortWriteToFile",
|
||||
"DataDirectory",
|
||||
"HiddenServiceDir",
|
||||
"HiddenServicePort",
|
||||
0
|
||||
};
|
||||
|
||||
QVariantList configText = command->get("config-text").toList();
|
||||
foreach (const QVariant &value, configText) {
|
||||
QByteArray line = value.toByteArray();
|
||||
|
||||
bool skip = false;
|
||||
for (const char **key = bannedKeys; *key; key++) {
|
||||
if (line.startsWith(*key)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip)
|
||||
continue;
|
||||
|
||||
file.write(line);
|
||||
file.write("\n");
|
||||
}
|
||||
|
||||
if (!file.commit()) {
|
||||
finishWithError(QStringLiteral("Failed writing torrc: %1").arg(file.errorString()));
|
||||
return;
|
||||
}
|
||||
|
||||
torCtrlDebug() << "torctrl: Wrote torrc file" << std::endl;
|
||||
finishWithSuccess();
|
||||
}
|
||||
|
||||
private:
|
||||
GetConfCommand *command;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
PendingOperation *TorControl::saveConfiguration()
|
||||
{
|
||||
if (!hasOwnership()) {
|
||||
qWarning() << "torctrl: Ignoring save configuration command for a tor instance I don't own";
|
||||
return 0;
|
||||
}
|
||||
|
||||
SaveConfigOperation *operation = new SaveConfigOperation(this);
|
||||
QObject::connect(operation, &PendingOperation::finished, operation, &QObject::deleteLater);
|
||||
operation->start(d->socket);
|
||||
|
||||
//QQmlEngine::setObjectOwnership(operation, QQmlEngine::CppOwnership);
|
||||
return operation;
|
||||
}
|
||||
|
||||
bool TorControl::hasOwnership() const
|
||||
{
|
||||
return d->hasOwnership;
|
||||
}
|
||||
|
||||
void TorControl::takeOwnership()
|
||||
{
|
||||
d->hasOwnership = true;
|
||||
d->socket->sendCommand("TAKEOWNERSHIP\r\n");
|
||||
|
||||
// Reset PID-based polling
|
||||
QVariantMap options;
|
||||
options[QStringLiteral("__OwningControllerProcess")] = QVariant();
|
||||
setConfiguration(options);
|
||||
}
|
||||
|
||||
bool TorControl::torVersionAsNewAs(const QString &match) const
|
||||
{
|
||||
QRegularExpression r(QStringLiteral("[.-]"));
|
||||
QStringList split = torVersion().split(r);
|
||||
QStringList matchSplit = match.split(r);
|
||||
|
||||
for (int i = 0; i < matchSplit.size(); i++) {
|
||||
if (i >= split.size())
|
||||
return false;
|
||||
bool ok1 = false, ok2 = false;
|
||||
int currentVal = split[i].toInt(&ok1);
|
||||
int matchVal = matchSplit[i].toInt(&ok2);
|
||||
if (!ok1 || !ok2)
|
||||
return false;
|
||||
if (currentVal > matchVal)
|
||||
return true;
|
||||
if (currentVal < matchVal)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Versions are equal, up to the length of match
|
||||
return true;
|
||||
}
|
||||
|
||||
#include "TorControl.moc"
|
||||
|
144
retroshare-gui/src/TorControl/TorControl.h
Normal file
144
retroshare-gui/src/TorControl/TorControl.h
Normal file
@ -0,0 +1,144 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TORCONTROL_H
|
||||
#define TORCONTROL_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
#include "PendingOperation.h"
|
||||
|
||||
class QNetworkProxy;
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class HiddenService;
|
||||
class TorControlPrivate;
|
||||
|
||||
class TorControl : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(Status TorStatus)
|
||||
|
||||
// Status of the control connection
|
||||
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
|
||||
// Status of Tor (and whether it believes it can connect)
|
||||
Q_PROPERTY(TorStatus torStatus READ torStatus NOTIFY torStatusChanged)
|
||||
// Whether it's possible to make a SOCKS connection and connect
|
||||
Q_PROPERTY(bool hasConnectivity READ hasConnectivity NOTIFY connectivityChanged)
|
||||
Q_PROPERTY(QString torVersion READ torVersion NOTIFY connected)
|
||||
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY statusChanged)
|
||||
Q_PROPERTY(QVariantMap bootstrapStatus READ bootstrapStatus NOTIFY bootstrapStatusChanged)
|
||||
Q_PROPERTY(bool hasOwnership READ hasOwnership NOTIFY hasOwnershipChanged)
|
||||
|
||||
public:
|
||||
enum Status
|
||||
{
|
||||
Error = -1,
|
||||
NotConnected,
|
||||
Connecting,
|
||||
Authenticating,
|
||||
Connected
|
||||
};
|
||||
|
||||
enum TorStatus
|
||||
{
|
||||
TorUnknown,
|
||||
TorOffline,
|
||||
TorReady
|
||||
};
|
||||
|
||||
|
||||
explicit TorControl(QObject *parent = 0);
|
||||
|
||||
/* Information */
|
||||
Status status() const;
|
||||
TorStatus torStatus() const;
|
||||
QString torVersion() const;
|
||||
bool torVersionAsNewAs(const QString &version) const;
|
||||
QString errorMessage() const;
|
||||
|
||||
bool hasConnectivity() const;
|
||||
QHostAddress socksAddress() const;
|
||||
quint16 socksPort() const;
|
||||
QNetworkProxy connectionProxy();
|
||||
|
||||
/* Authentication */
|
||||
void setAuthPassword(const QByteArray &password);
|
||||
|
||||
/* Connection */
|
||||
bool isConnected() const { return status() == Connected; }
|
||||
void connect(const QHostAddress &address, quint16 port);
|
||||
|
||||
/* Ownership means that tor is managed by this socket, and we
|
||||
* can shut it down, own its configuration, etc. */
|
||||
bool hasOwnership() const;
|
||||
void takeOwnership();
|
||||
|
||||
/* Hidden Services */
|
||||
QList<HiddenService*> hiddenServices() const;
|
||||
void addHiddenService(HiddenService *service);
|
||||
|
||||
QVariantMap bootstrapStatus() const;
|
||||
Q_INVOKABLE QObject *getConfiguration(const QString &options);
|
||||
Q_INVOKABLE QObject *setConfiguration(const QVariantMap &options);
|
||||
Q_INVOKABLE PendingOperation *saveConfiguration();
|
||||
|
||||
signals:
|
||||
void statusChanged(int newStatus, int oldStatus);
|
||||
void torStatusChanged(int newStatus, int oldStatus);
|
||||
void connected();
|
||||
void disconnected();
|
||||
void connectivityChanged();
|
||||
void bootstrapStatusChanged();
|
||||
void hasOwnershipChanged();
|
||||
|
||||
public slots:
|
||||
/* Instruct Tor to shutdown */
|
||||
void shutdown();
|
||||
/* Call shutdown(), and wait synchronously for the command to be written */
|
||||
void shutdownSync();
|
||||
|
||||
void reconnect();
|
||||
|
||||
private:
|
||||
TorControlPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
extern Tor::TorControl *torControl;
|
||||
|
||||
#endif // TORCONTROLMANAGER_H
|
63
retroshare-gui/src/TorControl/TorControlCommand.cpp
Normal file
63
retroshare-gui/src/TorControl/TorControlCommand.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "TorControlCommand.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
TorControlCommand::TorControlCommand()
|
||||
: m_finalStatus(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TorControlCommand::onReply(int statusCode, const QByteArray &data)
|
||||
{
|
||||
emit replyLine(statusCode, data);
|
||||
}
|
||||
|
||||
void TorControlCommand::onFinished(int statusCode)
|
||||
{
|
||||
m_finalStatus = statusCode;
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void TorControlCommand::onDataLine(const QByteArray &data)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
}
|
||||
|
||||
void TorControlCommand::onDataFinished()
|
||||
{
|
||||
qWarning() << "torctrl: Unexpected data response for command";
|
||||
}
|
||||
|
70
retroshare-gui/src/TorControl/TorControlCommand.h
Normal file
70
retroshare-gui/src/TorControl/TorControlCommand.h
Normal file
@ -0,0 +1,70 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TORCONTROLCOMMAND_H
|
||||
#define TORCONTROLCOMMAND_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QByteArray>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class TorControlCommand : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(TorControlCommand)
|
||||
|
||||
friend class TorControlSocket;
|
||||
|
||||
public:
|
||||
TorControlCommand();
|
||||
|
||||
int statusCode() const { return m_finalStatus; }
|
||||
|
||||
signals:
|
||||
void replyLine(int statusCode, const QByteArray &data);
|
||||
void finished();
|
||||
|
||||
protected:
|
||||
virtual void onReply(int statusCode, const QByteArray &data);
|
||||
virtual void onFinished(int statusCode);
|
||||
virtual void onDataLine(const QByteArray &data);
|
||||
virtual void onDataFinished();
|
||||
|
||||
private:
|
||||
int m_finalStatus;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TORCONTROLCOMMAND_H
|
178
retroshare-gui/src/TorControl/TorControlSocket.cpp
Normal file
178
retroshare-gui/src/TorControl/TorControlSocket.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "TorControlSocket.h"
|
||||
#include "TorControlCommand.h"
|
||||
#include <QDebug>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
TorControlSocket::TorControlSocket(QObject *parent)
|
||||
: QTcpSocket(parent), currentCommand(0), inDataReply(false)
|
||||
{
|
||||
connect(this, SIGNAL(readyRead()), this, SLOT(process()));
|
||||
connect(this, SIGNAL(disconnected()), this, SLOT(clear()));
|
||||
}
|
||||
|
||||
TorControlSocket::~TorControlSocket()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void TorControlSocket::sendCommand(TorControlCommand *command, const QByteArray &data)
|
||||
{
|
||||
Q_ASSERT(data.endsWith("\r\n"));
|
||||
|
||||
commandQueue.append(command);
|
||||
write(data);
|
||||
|
||||
std::cerr << "[TOR CTRL] Sent: \"" << QString(data.trimmed()).toStdString() << "\"" << std::endl;
|
||||
}
|
||||
|
||||
void TorControlSocket::registerEvent(const QByteArray &event, TorControlCommand *command)
|
||||
{
|
||||
eventCommands.insert(event, command);
|
||||
|
||||
QByteArray data("SETEVENTS");
|
||||
foreach (const QByteArray &key, eventCommands.keys()) {
|
||||
data += ' ';
|
||||
data += key;
|
||||
}
|
||||
data += "\r\n";
|
||||
|
||||
sendCommand(data);
|
||||
}
|
||||
|
||||
void TorControlSocket::clear()
|
||||
{
|
||||
qDeleteAll(commandQueue);
|
||||
commandQueue.clear();
|
||||
qDeleteAll(eventCommands);
|
||||
eventCommands.clear();
|
||||
inDataReply = false;
|
||||
currentCommand = 0;
|
||||
}
|
||||
|
||||
void TorControlSocket::setError(const QString &message)
|
||||
{
|
||||
m_errorMessage = message;
|
||||
emit error(message);
|
||||
abort();
|
||||
}
|
||||
|
||||
void TorControlSocket::process()
|
||||
{
|
||||
for (;;) {
|
||||
if (!canReadLine())
|
||||
return;
|
||||
|
||||
QByteArray line = readLine(5120);
|
||||
if (!line.endsWith("\r\n")) {
|
||||
setError(QStringLiteral("Invalid control message syntax"));
|
||||
return;
|
||||
}
|
||||
line.chop(2);
|
||||
|
||||
if (inDataReply) {
|
||||
if (line == ".") {
|
||||
inDataReply = false;
|
||||
if (currentCommand)
|
||||
currentCommand->onDataFinished();
|
||||
currentCommand = 0;
|
||||
} else {
|
||||
if (currentCommand)
|
||||
currentCommand->onDataLine(line);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.size() < 4) {
|
||||
setError(QStringLiteral("Invalid control message syntax"));
|
||||
return;
|
||||
}
|
||||
|
||||
int statusCode = line.left(3).toInt();
|
||||
char type = line[3];
|
||||
bool isFinalReply = (type == ' ');
|
||||
inDataReply = (type == '+');
|
||||
|
||||
// Trim down to just data
|
||||
line = line.mid(4);
|
||||
|
||||
if (!isFinalReply && !inDataReply && type != '-') {
|
||||
setError(QStringLiteral("Invalid control message syntax"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 6xx replies are asynchronous responses
|
||||
if (statusCode >= 600 && statusCode < 700) {
|
||||
if (!currentCommand) {
|
||||
int space = line.indexOf(' ');
|
||||
if (space > 0)
|
||||
currentCommand = eventCommands.value(line.mid(0, space));
|
||||
|
||||
if (!currentCommand) {
|
||||
qWarning() << "torctrl: Ignoring unknown event";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
currentCommand->onReply(statusCode, line);
|
||||
if (isFinalReply) {
|
||||
currentCommand->onFinished(statusCode);
|
||||
currentCommand = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (commandQueue.isEmpty()) {
|
||||
qWarning() << "torctrl: Received unexpected data";
|
||||
continue;
|
||||
}
|
||||
|
||||
TorControlCommand *command = commandQueue.first();
|
||||
if (command)
|
||||
command->onReply(statusCode, line);
|
||||
|
||||
if (inDataReply) {
|
||||
currentCommand = command;
|
||||
} else if (isFinalReply) {
|
||||
commandQueue.takeFirst();
|
||||
if (command) {
|
||||
command->onFinished(statusCode);
|
||||
command->deleteLater();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
77
retroshare-gui/src/TorControl/TorControlSocket.h
Normal file
77
retroshare-gui/src/TorControl/TorControlSocket.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TORCONTROLSOCKET_H
|
||||
#define TORCONTROLSOCKET_H
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QQueue>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class TorControlCommand;
|
||||
|
||||
class TorControlSocket : public QTcpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TorControlSocket(QObject *parent = 0);
|
||||
virtual ~TorControlSocket();
|
||||
|
||||
QString errorMessage() const { return m_errorMessage; }
|
||||
|
||||
void registerEvent(const QByteArray &event, TorControlCommand *handler);
|
||||
|
||||
void sendCommand(const QByteArray &data) { sendCommand(0, data); }
|
||||
void sendCommand(TorControlCommand *command, const QByteArray &data);
|
||||
|
||||
signals:
|
||||
void error(const QString &message);
|
||||
|
||||
private slots:
|
||||
void process();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QQueue<TorControlCommand*> commandQueue;
|
||||
QHash<QByteArray,TorControlCommand*> eventCommands;
|
||||
QString m_errorMessage;
|
||||
TorControlCommand *currentCommand;
|
||||
bool inDataReply;
|
||||
|
||||
void setError(const QString &message);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TORCONTROLSOCKET_H
|
230
retroshare-gui/src/TorControl/TorControlWindow.cpp
Normal file
230
retroshare-gui/src/TorControl/TorControlWindow.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include <unistd.h>
|
||||
#include <set>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QFile>
|
||||
#include <QTcpServer>
|
||||
#include <QGraphicsDropShadowEffect>
|
||||
|
||||
#include <iostream>
|
||||
#include "util/rstime.h"
|
||||
|
||||
#include "TorControlWindow.h"
|
||||
#include "TorManager.h"
|
||||
#include "TorControl.h"
|
||||
#include "HiddenService.h"
|
||||
|
||||
TorControlDialog::TorControlDialog(Tor::TorManager *tm,QWidget *parent)
|
||||
: mTorManager(tm)
|
||||
{
|
||||
setupUi(this) ;
|
||||
|
||||
QObject::connect(tm->control(),SIGNAL(statusChanged(int,int)),this,SLOT(statusChanged())) ;
|
||||
QObject::connect(tm->control(),SIGNAL(connected()),this,SLOT(statusChanged()));
|
||||
QObject::connect(tm->control(),SIGNAL(disconnected()),this,SLOT(statusChanged()));
|
||||
QObject::connect(tm->control(),SIGNAL(bootstrapStatusChanged()),this,SLOT(statusChanged()));
|
||||
QObject::connect(tm->control(),SIGNAL(connectivityChanged()),this,SLOT(statusChanged()));
|
||||
QObject::connect(tm ,SIGNAL(errorChanged()),this,SLOT(statusChanged()));
|
||||
|
||||
//QTimer::singleShot(2000,this,SLOT(checkForHiddenService())) ;
|
||||
|
||||
mIncomingServer = new QTcpServer(this) ;
|
||||
mHiddenService = NULL ;
|
||||
mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_UNKNOWN;
|
||||
//mBootstrapPhaseFinished = false ;
|
||||
|
||||
connect(mIncomingServer, SIGNAL(QTcpServer::newConnection()), this, SLOT(onIncomingConnection()));
|
||||
|
||||
QTimer *timer = new QTimer ;
|
||||
|
||||
QObject::connect(timer,SIGNAL(timeout()),this,SLOT(showLog())) ;
|
||||
timer->start(500) ;
|
||||
|
||||
// Hide some debug output for the released version
|
||||
|
||||
setWindowFlags( Qt::Dialog | Qt::FramelessWindowHint );
|
||||
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void TorControlDialog::onIncomingConnection()
|
||||
{
|
||||
std::cerr << "Incoming connection !!" << std::endl;
|
||||
}
|
||||
|
||||
void TorControlDialog::statusChanged()
|
||||
{
|
||||
int tor_control_status = mTorManager->control()->status();
|
||||
int torstatus = mTorManager->control()->torStatus();
|
||||
|
||||
QString tor_control_status_str,torstatus_str ;
|
||||
|
||||
if(mTorManager->hasError())
|
||||
mErrorMsg = mTorManager->errorMessage() ;
|
||||
|
||||
switch(tor_control_status)
|
||||
{
|
||||
default:
|
||||
case Tor::TorControl::Error : tor_control_status_str = "Error" ; break ;
|
||||
case Tor::TorControl::NotConnected: tor_control_status_str = "Not connected" ; break ;
|
||||
case Tor::TorControl::Connecting: tor_control_status_str = "Connecting" ; break ;
|
||||
case Tor::TorControl::Authenticating: tor_control_status_str = "Authenticating" ; break ;
|
||||
case Tor::TorControl::Connected: tor_control_status_str = "Connected" ; break ;
|
||||
}
|
||||
|
||||
switch(torstatus)
|
||||
{
|
||||
default:
|
||||
case Tor::TorControl::TorUnknown: torstatus_str = "Unknown" ; break ;
|
||||
case Tor::TorControl::TorOffline: torstatus_str = "Tor offline" ; break ;
|
||||
case Tor::TorControl::TorReady: torstatus_str = "Tor ready" ; break ;
|
||||
}
|
||||
|
||||
torStatus_LB->setText(torstatus_str) ;
|
||||
|
||||
if(torstatus == Tor::TorControl::TorUnknown)
|
||||
torStatus_LB->setToolTip(tr("Check that Tor is accessible in your executable path")) ;
|
||||
else
|
||||
torStatus_LB->setToolTip("") ;
|
||||
|
||||
QVariantMap qvm = mTorManager->control()->bootstrapStatus();
|
||||
QString bootstrapstatus_str ;
|
||||
|
||||
std::cerr << "Tor control status: " << tor_control_status_str.toStdString() << std::endl;
|
||||
std::cerr << "Tor status: " << torstatus_str.toStdString() << std::endl;
|
||||
|
||||
std::cerr << "Bootstrap status map: " << std::endl;
|
||||
|
||||
for(auto it(qvm.begin());it!=qvm.end();++it)
|
||||
std::cerr << " " << it.key().toStdString() << " : " << it.value().toString().toStdString() << std::endl;
|
||||
|
||||
if(!qvm["progress"].toString().isNull())
|
||||
torBootstrapStatus_LB->setText(qvm["progress"].toString() + " % (" + qvm["summary"].toString() + ")") ;
|
||||
else
|
||||
torBootstrapStatus_LB->setText(tr("[Waiting for Tor...]")) ;
|
||||
|
||||
QString service_id ;
|
||||
QString onion_address ;
|
||||
QHostAddress service_target_address ;
|
||||
uint16_t service_port ;
|
||||
uint16_t target_port ;
|
||||
|
||||
if(mTorManager->getHiddenServiceInfo(service_id,onion_address,service_port, service_target_address,target_port))
|
||||
{
|
||||
hiddenServiceAddress_LB->setText(QString::number(service_port) + ":" + service_target_address.toString() + ":" + QString::number(target_port));
|
||||
onionAddress_LB->setText(onion_address);
|
||||
}
|
||||
else
|
||||
{
|
||||
hiddenServiceAddress_LB->setText(QString("[Not ready]")) ;
|
||||
onionAddress_LB->setText(QString("[Not ready]")) ;
|
||||
}
|
||||
|
||||
showLog();
|
||||
adjustSize();
|
||||
|
||||
QCoreApplication::processEvents(); // forces update
|
||||
}
|
||||
|
||||
void TorControlDialog::showLog()
|
||||
{
|
||||
static std::set<QString> already_seen ;
|
||||
|
||||
QString s ;
|
||||
QStringList logmsgs = mTorManager->logMessages() ;
|
||||
bool can_print = false ;
|
||||
|
||||
for(QStringList::const_iterator it(logmsgs.begin());it!=logmsgs.end();++it)
|
||||
{
|
||||
s += *it + "\n" ;
|
||||
|
||||
if(already_seen.find(*it) == already_seen.end())
|
||||
{
|
||||
can_print = true ;
|
||||
already_seen.insert(*it);
|
||||
}
|
||||
|
||||
if(can_print)
|
||||
std::cerr << "[TOR DEBUG LOG] " << (*it).toStdString() << std::endl;
|
||||
}
|
||||
|
||||
// torLog_TB->setText(s) ;:
|
||||
|
||||
std::cerr << "Connexion Proxy: " << mTorManager->control()->socksAddress().toString().toStdString() << ":" << mTorManager->control()->socksPort() << std::endl;
|
||||
}
|
||||
|
||||
TorControlDialog::TorStatus TorControlDialog::checkForTor(QString& error_msg)
|
||||
{
|
||||
if(!mErrorMsg.isNull())
|
||||
{
|
||||
error_msg = mErrorMsg ;
|
||||
return TorControlDialog::TOR_STATUS_FAIL ;
|
||||
}
|
||||
|
||||
switch(mTorManager->control()->torStatus())
|
||||
{
|
||||
case Tor::TorControl::TorReady: rstime::rs_usleep(1*1000*1000);return TOR_STATUS_OK ;
|
||||
default:
|
||||
return TOR_STATUS_UNKNOWN ;
|
||||
}
|
||||
}
|
||||
|
||||
TorControlDialog::HiddenServiceStatus TorControlDialog::checkForHiddenService()
|
||||
{
|
||||
std::cerr << "Checking for hidden services:" ;
|
||||
|
||||
switch(mHiddenServiceStatus)
|
||||
{
|
||||
default:
|
||||
case HIDDEN_SERVICE_STATUS_UNKNOWN: {
|
||||
|
||||
std::cerr << " trying to setup. " ;
|
||||
|
||||
if(!mTorManager->setupHiddenService())
|
||||
{
|
||||
mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_FAIL ;
|
||||
std::cerr << "Failed." << std::endl;
|
||||
return mHiddenServiceStatus ;
|
||||
}
|
||||
std::cerr << "Done." << std::endl;
|
||||
mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_REQUESTED ;
|
||||
return mHiddenServiceStatus ;
|
||||
}
|
||||
|
||||
case HIDDEN_SERVICE_STATUS_REQUESTED: {
|
||||
QList<Tor::HiddenService*> hidden_services = mTorManager->control()->hiddenServices();
|
||||
|
||||
if(hidden_services.empty())
|
||||
{
|
||||
std::cerr << "Not ready yet." << std::endl;
|
||||
return mHiddenServiceStatus ;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mHiddenService == NULL)
|
||||
mHiddenService = *(hidden_services.begin()) ;
|
||||
|
||||
Tor::HiddenService::Status hss = mHiddenService->status();
|
||||
|
||||
std::cerr << "New service acquired. Status is " << hss ;
|
||||
|
||||
if(hss == Tor::HiddenService::Online)
|
||||
{
|
||||
mHiddenServiceStatus = HIDDEN_SERVICE_STATUS_OK ;
|
||||
std::cerr << ": published and running!" << std::endl;
|
||||
|
||||
return mHiddenServiceStatus ;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << ": not ready yet." << std::endl;
|
||||
return mHiddenServiceStatus ;
|
||||
}
|
||||
}
|
||||
}
|
||||
case HIDDEN_SERVICE_STATUS_OK :
|
||||
std::cerr << "New service acquired." << std::endl;
|
||||
return mHiddenServiceStatus ;
|
||||
}
|
||||
}
|
||||
|
48
retroshare-gui/src/TorControl/TorControlWindow.h
Normal file
48
retroshare-gui/src/TorControl/TorControlWindow.h
Normal file
@ -0,0 +1,48 @@
|
||||
#include "ui_TorControlWindow.h"
|
||||
|
||||
class QTcpServer ;
|
||||
|
||||
namespace Tor {
|
||||
class HiddenService ;
|
||||
class TorManager ;
|
||||
}
|
||||
|
||||
class TorControlDialog: public QWidget, public Ui::TorControlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorControlDialog(Tor::TorManager *tm,QWidget *parent =NULL);
|
||||
|
||||
enum TorStatus {
|
||||
TOR_STATUS_UNKNOWN = 0x00,
|
||||
TOR_STATUS_OK = 0x01,
|
||||
TOR_STATUS_FAIL = 0x02
|
||||
};
|
||||
|
||||
enum HiddenServiceStatus {
|
||||
HIDDEN_SERVICE_STATUS_UNKNOWN = 0x00, // no information known.
|
||||
HIDDEN_SERVICE_STATUS_FAIL = 0x01, // some error occurred
|
||||
HIDDEN_SERVICE_STATUS_REQUESTED = 0x02, // one service at least has been requested. Still being tested.
|
||||
HIDDEN_SERVICE_STATUS_OK = 0x03 // one service responds and has been tested
|
||||
};
|
||||
|
||||
// Should be called multiple times in a loop until it returns something else than *_UNKNOWN
|
||||
|
||||
TorStatus checkForTor(QString& error_msg) ;
|
||||
HiddenServiceStatus checkForHiddenService() ;
|
||||
|
||||
protected slots:
|
||||
void showLog();
|
||||
void statusChanged();
|
||||
void onIncomingConnection();
|
||||
|
||||
private:
|
||||
QString mErrorMsg ;
|
||||
HiddenServiceStatus mHiddenServiceStatus ;
|
||||
|
||||
Tor::TorManager *mTorManager ;
|
||||
Tor::HiddenService *mHiddenService ;
|
||||
|
||||
QTcpServer *mIncomingServer ;
|
||||
};
|
134
retroshare-gui/src/TorControl/TorControlWindow.ui
Normal file
134
retroshare-gui/src/TorControl/TorControlWindow.ui
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TorControlDialog</class>
|
||||
<widget class="QWidget" name="TorControlDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>600</width>
|
||||
<height>228</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Setting up Tor...</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../gui/icons.qrc">:/icons/tor-logo.png</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="torStatusTxt_LB">
|
||||
<property name="text">
|
||||
<string>Tor status:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="torStatus_LB">
|
||||
<property name="text">
|
||||
<string>Unknown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="torBootstrapStatus_LB">
|
||||
<property name="text">
|
||||
<string>Not started</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="HiddenServiceAddressTxt_LB">
|
||||
<property name="text">
|
||||
<string>Hidden service address:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="torBootstrapStatusTxt_LB">
|
||||
<property name="text">
|
||||
<string>Tor bootstrap status:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="hiddenServiceAddress_LB">
|
||||
<property name="text">
|
||||
<string>Not set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="onionAddressTxt_LB">
|
||||
<property name="text">
|
||||
<string>Onion address:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="onionAddress_LB">
|
||||
<property name="text">
|
||||
<string>Not set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../gui/icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
501
retroshare-gui/src/TorControl/TorManager.cpp
Normal file
501
retroshare-gui/src/TorControl/TorManager.cpp
Normal file
@ -0,0 +1,501 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "TorManager.h"
|
||||
#include "TorProcess.h"
|
||||
#include "TorControl.h"
|
||||
#include "CryptoKey.h"
|
||||
#include "HiddenService.h"
|
||||
#include "GetConfCommand.h"
|
||||
#include "Settings.h"
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <QCoreApplication>
|
||||
#include <QTcpServer>
|
||||
#include <QTextStream>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class TorManagerPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorManager *q;
|
||||
TorProcess *process;
|
||||
TorControl *control;
|
||||
QString dataDir;
|
||||
QString hiddenServiceDir;
|
||||
QStringList logMessages;
|
||||
QString errorMessage;
|
||||
bool configNeeded;
|
||||
|
||||
HiddenService *hiddenService ;
|
||||
|
||||
explicit TorManagerPrivate(TorManager *parent = 0);
|
||||
|
||||
QString torExecutablePath() const;
|
||||
bool createDataDir(const QString &path);
|
||||
bool createDefaultTorrc(const QString &path);
|
||||
|
||||
void setError(const QString &errorMessage);
|
||||
|
||||
public slots:
|
||||
void processStateChanged(int state);
|
||||
void processErrorChanged(const QString &errorMessage);
|
||||
void processLogMessage(const QString &message);
|
||||
void controlStatusChanged(int status);
|
||||
void getConfFinished();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
TorManager::TorManager(QObject *parent)
|
||||
: QObject(parent), d(new TorManagerPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
TorManagerPrivate::TorManagerPrivate(TorManager *parent)
|
||||
: QObject(parent)
|
||||
, q(parent)
|
||||
, process(0)
|
||||
, control(new TorControl(this))
|
||||
, configNeeded(false)
|
||||
, hiddenService(NULL)
|
||||
{
|
||||
connect(control, SIGNAL(statusChanged(int,int)), SLOT(controlStatusChanged(int)));
|
||||
}
|
||||
|
||||
TorManager *TorManager::instance()
|
||||
{
|
||||
static TorManager *p = 0;
|
||||
if (!p)
|
||||
p = new TorManager(qApp);
|
||||
return p;
|
||||
}
|
||||
|
||||
TorControl *TorManager::control()
|
||||
{
|
||||
return d->control;
|
||||
}
|
||||
|
||||
TorProcess *TorManager::process()
|
||||
{
|
||||
return d->process;
|
||||
}
|
||||
|
||||
QString TorManager::dataDirectory() const
|
||||
{
|
||||
return d->dataDir;
|
||||
}
|
||||
|
||||
void TorManager::setDataDirectory(const QString &path)
|
||||
{
|
||||
d->dataDir = QDir::fromNativeSeparators(path);
|
||||
|
||||
if (!d->dataDir.isEmpty() && !d->dataDir.endsWith(QLatin1Char('/')))
|
||||
d->dataDir.append(QLatin1Char('/'));
|
||||
}
|
||||
|
||||
QString TorManager::hiddenServiceDirectory() const
|
||||
{
|
||||
return d->hiddenServiceDir;
|
||||
}
|
||||
void TorManager::setHiddenServiceDirectory(const QString &path)
|
||||
{
|
||||
d->hiddenServiceDir = QDir::fromNativeSeparators(path);
|
||||
|
||||
if (!d->hiddenServiceDir.isEmpty() && !d->hiddenServiceDir.endsWith(QLatin1Char('/')))
|
||||
d->hiddenServiceDir.append(QLatin1Char('/'));
|
||||
}
|
||||
|
||||
bool TorManager::setupHiddenService()
|
||||
{
|
||||
if(d->hiddenService != NULL)
|
||||
{
|
||||
std::cerr << "TorManager: setupHiddenService() called twice! Not doing anything this time." << std::endl;
|
||||
return true ;
|
||||
}
|
||||
|
||||
QString keyData ;//= m_settings->read("serviceKey").toString();
|
||||
QString legacyDir = d->hiddenServiceDir;
|
||||
|
||||
std::cerr << "TorManager: setting up hidden service." << std::endl;
|
||||
|
||||
if(legacyDir.isNull())
|
||||
{
|
||||
std::cerr << "legacy dir not set! Cannot proceed." << std::endl;
|
||||
return false ;
|
||||
}
|
||||
|
||||
std::cerr << "Using legacy dir: " << legacyDir.toStdString() << std::endl;
|
||||
|
||||
if (!legacyDir.isEmpty() && QFile::exists(legacyDir + QLatin1String("/private_key")))
|
||||
{
|
||||
std::cerr << "Attempting to load key from legacy filesystem format in " << legacyDir.toStdString() << std::endl;
|
||||
|
||||
CryptoKey key;
|
||||
if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey))
|
||||
{
|
||||
qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion";
|
||||
return false;
|
||||
}
|
||||
|
||||
keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64());
|
||||
d->hiddenService = new Tor::HiddenService(key, legacyDir, this);
|
||||
|
||||
std::cerr << "Got key from legacy dir: " << std::endl;
|
||||
std::cerr << keyData.toStdString() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->hiddenService = new Tor::HiddenService(legacyDir, this);
|
||||
|
||||
std::cerr << "Creating new hidden service." << std::endl;
|
||||
|
||||
connect(d->hiddenService, SIGNAL(privateKeyChanged()), this, SLOT(hiddenServicePrivateKeyChanged())) ;
|
||||
}
|
||||
|
||||
Q_ASSERT(d->hiddenService);
|
||||
connect(d->hiddenService, SIGNAL(statusChanged(int,int)), this, SLOT(hiddenServiceStatusChanged(int,int)));
|
||||
|
||||
// Generally, these are not used, and we bind to localhost and port 0
|
||||
// for an automatic (and portable) selection.
|
||||
|
||||
QHostAddress address = QHostAddress::LocalHost; // we only listen from localhost
|
||||
|
||||
quint16 port = 7934;//(quint16)m_settings->read("localListenPort").toInt();
|
||||
|
||||
std::cerr << "Testing host address: " << address.toString().toStdString() << ":" << port ;
|
||||
|
||||
if (!QTcpServer().listen(address, port))
|
||||
{
|
||||
// XXX error case
|
||||
std::cerr << " Failed to open incoming socket" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::cerr << " OK - Adding hidden service to TorControl." << std::endl;
|
||||
|
||||
//d->hiddenService->addTarget(9878, mIncomingServer->serverAddress(), mIncomingServer->serverPort());
|
||||
d->hiddenService->addTarget(9878, QHostAddress::LocalHost,7934);
|
||||
control()->addHiddenService(d->hiddenService);
|
||||
|
||||
return true ;
|
||||
}
|
||||
|
||||
void TorManager::hiddenServiceStatusChanged(int old_status,int new_status)
|
||||
{
|
||||
std::cerr << "Hidden service status changed from " << old_status << " to " << new_status << std::endl;
|
||||
}
|
||||
|
||||
void TorManager::hiddenServicePrivateKeyChanged()
|
||||
{
|
||||
QString key = QString::fromLatin1(d->hiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64());
|
||||
|
||||
QFile outfile(d->hiddenServiceDir + QLatin1String("/private_key")) ;
|
||||
outfile.open( QIODevice::WriteOnly | QIODevice::Text );
|
||||
QTextStream s(&outfile);
|
||||
|
||||
s << "-----BEGIN RSA PRIVATE KEY-----" << endl;
|
||||
|
||||
for(uint32_t i=0;i<key.length();i+=64)
|
||||
s << key.mid(i,64) << endl ;
|
||||
|
||||
s << "-----END RSA PRIVATE KEY-----" << endl;
|
||||
|
||||
outfile.close();
|
||||
|
||||
std::cerr << "Hidden service private key changed!" << std::endl;
|
||||
std::cerr << key.toStdString() << std::endl;
|
||||
|
||||
QFile outfile2(d->hiddenServiceDir + QLatin1String("/hostname")) ;
|
||||
outfile2.open( QIODevice::WriteOnly | QIODevice::Text );
|
||||
QTextStream t(&outfile2);
|
||||
|
||||
t << d->hiddenService->hostname() << endl;
|
||||
|
||||
outfile2.close();
|
||||
}
|
||||
|
||||
bool TorManager::configurationNeeded() const
|
||||
{
|
||||
return d->configNeeded;
|
||||
}
|
||||
|
||||
QStringList TorManager::logMessages() const
|
||||
{
|
||||
return d->logMessages;
|
||||
}
|
||||
|
||||
bool TorManager::hasError() const
|
||||
{
|
||||
return !d->errorMessage.isEmpty();
|
||||
}
|
||||
|
||||
QString TorManager::errorMessage() const
|
||||
{
|
||||
return d->errorMessage;
|
||||
}
|
||||
|
||||
bool TorManager::start()
|
||||
{
|
||||
if (!d->errorMessage.isEmpty()) {
|
||||
d->errorMessage.clear();
|
||||
emit errorChanged();
|
||||
}
|
||||
|
||||
SettingsObject settings(QStringLiteral("tor"));
|
||||
|
||||
// If a control port is defined by config or environment, skip launching tor
|
||||
if (!settings.read("controlPort").isUndefined() ||
|
||||
!qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT"))
|
||||
{
|
||||
QHostAddress address(settings.read("controlAddress").toString());
|
||||
quint16 port = (quint16)settings.read("controlPort").toInt();
|
||||
QByteArray password = settings.read("controlPassword").toString().toLatin1();
|
||||
|
||||
if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_HOST"))
|
||||
address = QHostAddress(QString::fromLatin1(qgetenv("TOR_CONTROL_HOST")));
|
||||
|
||||
if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PORT")) {
|
||||
bool ok = false;
|
||||
port = qgetenv("TOR_CONTROL_PORT").toUShort(&ok);
|
||||
if (!ok)
|
||||
port = 0;
|
||||
}
|
||||
|
||||
if (!qEnvironmentVariableIsEmpty("TOR_CONTROL_PASSWD"))
|
||||
password = qgetenv("TOR_CONTROL_PASSWD");
|
||||
|
||||
if (!port) {
|
||||
d->setError(QStringLiteral("Invalid control port settings from environment or configuration"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (address.isNull())
|
||||
address = QHostAddress::LocalHost;
|
||||
|
||||
d->control->setAuthPassword(password);
|
||||
d->control->connect(address, port);
|
||||
} else {
|
||||
// Launch a bundled Tor instance
|
||||
QString executable = d->torExecutablePath();
|
||||
|
||||
std::cerr << "Executable path: " << executable.toStdString() << std::endl;
|
||||
|
||||
if (executable.isEmpty()) {
|
||||
d->setError(QStringLiteral("Cannot find tor executable"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!d->process) {
|
||||
d->process = new TorProcess(this);
|
||||
connect(d->process, SIGNAL(stateChanged(int)), d, SLOT(processStateChanged(int)));
|
||||
connect(d->process, SIGNAL(errorMessageChanged(QString)), d,
|
||||
SLOT(processErrorChanged(QString)));
|
||||
connect(d->process, SIGNAL(logMessage(QString)), d, SLOT(processLogMessage(QString)));
|
||||
}
|
||||
|
||||
if (!QFile::exists(d->dataDir) && !d->createDataDir(d->dataDir)) {
|
||||
d->setError(QStringLiteral("Cannot write data location: %1").arg(d->dataDir));
|
||||
return false;
|
||||
}
|
||||
|
||||
QString defaultTorrc = d->dataDir + QStringLiteral("default_torrc");
|
||||
if (!QFile::exists(defaultTorrc) && !d->createDefaultTorrc(defaultTorrc)) {
|
||||
d->setError(QStringLiteral("Cannot write data files: %1").arg(defaultTorrc));
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile torrc(d->dataDir + QStringLiteral("torrc"));
|
||||
if (!torrc.exists() || torrc.size() == 0) {
|
||||
d->configNeeded = true;
|
||||
emit configurationNeededChanged();
|
||||
}
|
||||
|
||||
d->process->setExecutable(executable);
|
||||
d->process->setDataDir(d->dataDir);
|
||||
d->process->setDefaultTorrc(defaultTorrc);
|
||||
d->process->start();
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
bool TorManager::getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port)
|
||||
{
|
||||
proxy_server_adress = control()->socksAddress();
|
||||
proxy_server_port = control()->socksPort();
|
||||
|
||||
return proxy_server_port > 1023 ;
|
||||
}
|
||||
|
||||
bool TorManager::getHiddenServiceInfo(QString& service_id,QString& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port)
|
||||
{
|
||||
QList<Tor::HiddenService*> hidden_services = control()->hiddenServices();
|
||||
|
||||
if(hidden_services.empty())
|
||||
return false ;
|
||||
|
||||
// Only return the first one.
|
||||
|
||||
for(auto it(hidden_services.begin());it!=hidden_services.end();++it)
|
||||
{
|
||||
service_onion_address = (*it)->hostname();
|
||||
service_id = (*it)->privateKey().torServiceID();
|
||||
|
||||
for(auto it2((*it)->targets().begin());it2!=(*it)->targets().end();++it2)
|
||||
{
|
||||
service_port = (*it2).servicePort ;
|
||||
service_target_address = (*it2).targetAddress ;
|
||||
target_port = (*it2).targetPort;
|
||||
break ;
|
||||
}
|
||||
break ;
|
||||
}
|
||||
return true ;
|
||||
}
|
||||
|
||||
void TorManagerPrivate::processStateChanged(int state)
|
||||
{
|
||||
std::cerr << Q_FUNC_INFO << "state: " << state << " passwd=\"" << QString(process->controlPassword()).toStdString() << "\" " << process->controlHost().toString().toStdString()
|
||||
<< ":" << process->controlPort() << std::endl;
|
||||
if (state == TorProcess::Ready) {
|
||||
control->setAuthPassword(process->controlPassword());
|
||||
control->connect(process->controlHost(), process->controlPort());
|
||||
}
|
||||
}
|
||||
|
||||
void TorManagerPrivate::processErrorChanged(const QString &errorMessage)
|
||||
{
|
||||
std::cerr << "tor error:" << errorMessage.toStdString() << std::endl;
|
||||
setError(errorMessage);
|
||||
}
|
||||
|
||||
void TorManagerPrivate::processLogMessage(const QString &message)
|
||||
{
|
||||
std::cerr << "tor:" << message.toStdString() << std::endl;
|
||||
if (logMessages.size() >= 50)
|
||||
logMessages.takeFirst();
|
||||
logMessages.append(message);
|
||||
}
|
||||
|
||||
void TorManagerPrivate::controlStatusChanged(int status)
|
||||
{
|
||||
if (status == TorControl::Connected) {
|
||||
if (!configNeeded) {
|
||||
// If DisableNetwork is 1, trigger configurationNeeded
|
||||
connect(control->getConfiguration(QStringLiteral("DisableNetwork")),
|
||||
SIGNAL(finished()), SLOT(getConfFinished()));
|
||||
}
|
||||
|
||||
if (process) {
|
||||
// Take ownership via this control socket
|
||||
control->takeOwnership();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TorManagerPrivate::getConfFinished()
|
||||
{
|
||||
GetConfCommand *command = qobject_cast<GetConfCommand*>(sender());
|
||||
if (!command)
|
||||
return;
|
||||
|
||||
if (command->get("DisableNetwork").toInt() == 1 && !configNeeded) {
|
||||
configNeeded = true;
|
||||
emit q->configurationNeededChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString TorManagerPrivate::torExecutablePath() const
|
||||
{
|
||||
SettingsObject settings(QStringLiteral("tor"));
|
||||
QString path = settings.read("executablePath").toString();
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QString filename(QStringLiteral("/tor.exe"));
|
||||
#else
|
||||
QString filename(QStringLiteral("/tor"));
|
||||
#endif
|
||||
|
||||
path = qApp->applicationDirPath();
|
||||
if (QFile::exists(path + filename))
|
||||
return path + filename;
|
||||
|
||||
#ifdef BUNDLED_TOR_PATH
|
||||
path = QStringLiteral(BUNDLED_TOR_PATH);
|
||||
if (QFile::exists(path + filename))
|
||||
return path + filename;
|
||||
#endif
|
||||
|
||||
// Try $PATH
|
||||
return filename.mid(1);
|
||||
}
|
||||
|
||||
bool TorManagerPrivate::createDataDir(const QString &path)
|
||||
{
|
||||
QDir dir(path);
|
||||
return dir.mkpath(QStringLiteral("."));
|
||||
}
|
||||
|
||||
bool TorManagerPrivate::createDefaultTorrc(const QString &path)
|
||||
{
|
||||
static const char defaultTorrcContent[] =
|
||||
"SocksPort auto\n"
|
||||
"AvoidDiskWrites 1\n"
|
||||
// "DisableNetwork 1\n" // (cyril) I removed this because it prevents Tor to bootstrap.
|
||||
"__ReloadTorrcOnSIGHUP 0\n";
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::WriteOnly))
|
||||
return false;
|
||||
if (file.write(defaultTorrcContent) < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TorManagerPrivate::setError(const QString &message)
|
||||
{
|
||||
errorMessage = message;
|
||||
emit q->errorChanged();
|
||||
}
|
||||
|
||||
#include "TorManager.moc"
|
||||
|
109
retroshare-gui/src/TorControl/TorManager.h
Normal file
109
retroshare-gui/src/TorControl/TorManager.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// This code has been further modified to fit Retroshare context.
|
||||
|
||||
#ifndef TORMANAGER_H
|
||||
#define TORMANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QHostAddress>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class TorProcess;
|
||||
class TorControl;
|
||||
class TorManagerPrivate;
|
||||
|
||||
/* Run/connect to an instance of Tor according to configuration, and manage
|
||||
* UI interaction, first time configuration, etc. */
|
||||
class TorManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool configurationNeeded READ configurationNeeded NOTIFY configurationNeededChanged)
|
||||
Q_PROPERTY(QStringList logMessages READ logMessages CONSTANT)
|
||||
Q_PROPERTY(Tor::TorProcess* process READ process CONSTANT)
|
||||
Q_PROPERTY(Tor::TorControl* control READ control CONSTANT)
|
||||
Q_PROPERTY(bool hasError READ hasError NOTIFY errorChanged)
|
||||
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorChanged)
|
||||
Q_PROPERTY(QString dataDirectory READ dataDirectory WRITE setDataDirectory)
|
||||
|
||||
public:
|
||||
|
||||
explicit TorManager(QObject *parent = 0);
|
||||
static TorManager *instance();
|
||||
|
||||
TorProcess *process();
|
||||
TorControl *control();
|
||||
|
||||
QString dataDirectory() const;
|
||||
void setDataDirectory(const QString &path);
|
||||
|
||||
QString hiddenServiceDirectory() const;
|
||||
void setHiddenServiceDirectory(const QString &path);
|
||||
|
||||
// Starts a hidden service, loading it from the config directory that has been set earlier.
|
||||
bool setupHiddenService() ;
|
||||
|
||||
// True on first run or when the Tor configuration wizard needs to be shown
|
||||
bool configurationNeeded() const;
|
||||
|
||||
QStringList logMessages() const;
|
||||
|
||||
bool hasError() const;
|
||||
QString errorMessage() const;
|
||||
|
||||
bool getHiddenServiceInfo(QString& service_id,QString& service_onion_address,uint16_t& service_port, QHostAddress& service_target_address,uint16_t& target_port);
|
||||
bool getProxyServerInfo(QHostAddress& proxy_server_adress,uint16_t& proxy_server_port);
|
||||
|
||||
public slots:
|
||||
bool start();
|
||||
|
||||
private slots:
|
||||
void hiddenServicePrivateKeyChanged();
|
||||
void hiddenServiceStatusChanged(int old_status,int new_status);
|
||||
|
||||
signals:
|
||||
void configurationNeededChanged();
|
||||
void errorChanged();
|
||||
|
||||
private:
|
||||
TorManagerPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#
|
311
retroshare-gui/src/TorControl/TorProcess.cpp
Normal file
311
retroshare-gui/src/TorControl/TorProcess.cpp
Normal file
@ -0,0 +1,311 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "TorProcess_p.h"
|
||||
#include "CryptoKey.h"
|
||||
#include "SecureRNG.h"
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QCoreApplication>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
TorProcess::TorProcess(QObject *parent)
|
||||
: QObject(parent), d(new TorProcessPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
TorProcess::~TorProcess()
|
||||
{
|
||||
if (state() > NotStarted)
|
||||
stop();
|
||||
}
|
||||
|
||||
TorProcessPrivate::TorProcessPrivate(TorProcess *q)
|
||||
: QObject(q), q(q), state(TorProcess::NotStarted), controlPort(0), controlPortAttempts(0)
|
||||
{
|
||||
connect(&process, &QProcess::started, this, &TorProcessPrivate::processStarted);
|
||||
connect(&process, (void (QProcess::*)(int, QProcess::ExitStatus))&QProcess::finished,
|
||||
this, &TorProcessPrivate::processFinished);
|
||||
connect(&process, (void (QProcess::*)(QProcess::ProcessError))&QProcess::error,
|
||||
this, &TorProcessPrivate::processError);
|
||||
connect(&process, &QProcess::readyRead, this, &TorProcessPrivate::processReadable);
|
||||
|
||||
controlPortTimer.setInterval(500);
|
||||
connect(&controlPortTimer, &QTimer::timeout, this, &TorProcessPrivate::tryReadControlPort);
|
||||
}
|
||||
|
||||
QString TorProcess::executable() const
|
||||
{
|
||||
return d->executable;
|
||||
}
|
||||
|
||||
void TorProcess::setExecutable(const QString &path)
|
||||
{
|
||||
d->executable = path;
|
||||
}
|
||||
|
||||
QString TorProcess::dataDir() const
|
||||
{
|
||||
return d->dataDir;
|
||||
}
|
||||
|
||||
void TorProcess::setDataDir(const QString &path)
|
||||
{
|
||||
d->dataDir = path;
|
||||
}
|
||||
|
||||
QString TorProcess::defaultTorrc() const
|
||||
{
|
||||
return d->defaultTorrc;
|
||||
}
|
||||
|
||||
void TorProcess::setDefaultTorrc(const QString &path)
|
||||
{
|
||||
d->defaultTorrc = path;
|
||||
}
|
||||
|
||||
QStringList TorProcess::extraSettings() const
|
||||
{
|
||||
return d->extraSettings;
|
||||
}
|
||||
|
||||
void TorProcess::setExtraSettings(const QStringList &settings)
|
||||
{
|
||||
d->extraSettings = settings;
|
||||
}
|
||||
|
||||
TorProcess::State TorProcess::state() const
|
||||
{
|
||||
return d->state;
|
||||
}
|
||||
|
||||
QString TorProcess::errorMessage() const
|
||||
{
|
||||
return d->errorMessage;
|
||||
}
|
||||
|
||||
void TorProcess::start()
|
||||
{
|
||||
if (state() > NotStarted)
|
||||
return;
|
||||
|
||||
d->errorMessage.clear();
|
||||
|
||||
if (d->executable.isEmpty() || d->dataDir.isEmpty()) {
|
||||
d->errorMessage = QStringLiteral("Tor executable and data directory not specified");
|
||||
d->state = Failed;
|
||||
emit errorMessageChanged(d->errorMessage);
|
||||
emit stateChanged(d->state);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->ensureFilesExist()) {
|
||||
d->state = Failed;
|
||||
emit errorMessageChanged(d->errorMessage);
|
||||
emit stateChanged(d->state);
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray password = controlPassword();
|
||||
QByteArray hashedPassword = torControlHashedPassword(password);
|
||||
if (password.isEmpty() || hashedPassword.isEmpty()) {
|
||||
d->errorMessage = QStringLiteral("Random password generation failed");
|
||||
d->state = Failed;
|
||||
emit errorMessageChanged(d->errorMessage);
|
||||
emit stateChanged(d->state);
|
||||
}
|
||||
|
||||
QStringList args;
|
||||
if (!d->defaultTorrc.isEmpty())
|
||||
args << QStringLiteral("--defaults-torrc") << d->defaultTorrc;
|
||||
args << QStringLiteral("-f") << d->torrcPath();
|
||||
args << QStringLiteral("DataDirectory") << d->dataDir;
|
||||
args << QStringLiteral("HashedControlPassword") << QString::fromLatin1(hashedPassword);
|
||||
args << QStringLiteral("ControlPort") << QStringLiteral("auto");
|
||||
args << QStringLiteral("ControlPortWriteToFile") << d->controlPortFilePath();
|
||||
args << QStringLiteral("__OwningControllerProcess") << QString::number(qApp->applicationPid());
|
||||
args << d->extraSettings;
|
||||
|
||||
d->state = Starting;
|
||||
emit stateChanged(d->state);
|
||||
|
||||
if (QFile::exists(d->controlPortFilePath()))
|
||||
QFile::remove(d->controlPortFilePath());
|
||||
d->controlPort = 0;
|
||||
d->controlHost.clear();
|
||||
|
||||
d->process.setProcessChannelMode(QProcess::MergedChannels);
|
||||
d->process.start(d->executable, args, QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
void TorProcess::stop()
|
||||
{
|
||||
if (state() < Starting)
|
||||
return;
|
||||
|
||||
d->controlPortTimer.stop();
|
||||
|
||||
if (d->process.state() == QProcess::Starting)
|
||||
d->process.waitForStarted(2000);
|
||||
|
||||
d->state = NotStarted;
|
||||
|
||||
// Windows can't terminate the process well, but Tor will clean itself up
|
||||
#ifndef Q_OS_WIN
|
||||
if (d->process.state() == QProcess::Running) {
|
||||
d->process.terminate();
|
||||
if (!d->process.waitForFinished(5000)) {
|
||||
qWarning() << "Tor process" << d->process.pid() << "did not respond to terminate, killing...";
|
||||
d->process.kill();
|
||||
if (!d->process.waitForFinished(2000)) {
|
||||
qCritical() << "Tor process" << d->process.pid() << "did not respond to kill!";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
emit stateChanged(d->state);
|
||||
}
|
||||
|
||||
QByteArray TorProcess::controlPassword()
|
||||
{
|
||||
if (d->controlPassword.isEmpty())
|
||||
d->controlPassword = SecureRNG::randomPrintable(16);
|
||||
return d->controlPassword;
|
||||
}
|
||||
|
||||
QHostAddress TorProcess::controlHost()
|
||||
{
|
||||
return d->controlHost;
|
||||
}
|
||||
|
||||
quint16 TorProcess::controlPort()
|
||||
{
|
||||
return d->controlPort;
|
||||
}
|
||||
|
||||
bool TorProcessPrivate::ensureFilesExist()
|
||||
{
|
||||
QFile torrc(torrcPath());
|
||||
if (!torrc.exists()) {
|
||||
QDir dir(dataDir);
|
||||
if (!dir.exists() && !dir.mkpath(QStringLiteral("."))) {
|
||||
errorMessage = QStringLiteral("Cannot create Tor data directory: %1").arg(dataDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!torrc.open(QIODevice::ReadWrite)) {
|
||||
errorMessage = QStringLiteral("Cannot create Tor configuration file: %1").arg(torrcPath());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString TorProcessPrivate::torrcPath() const
|
||||
{
|
||||
return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("torrc");
|
||||
}
|
||||
|
||||
QString TorProcessPrivate::controlPortFilePath() const
|
||||
{
|
||||
return QDir::toNativeSeparators(dataDir) + QDir::separator() + QStringLiteral("control-port");
|
||||
}
|
||||
|
||||
void TorProcessPrivate::processStarted()
|
||||
{
|
||||
state = TorProcess::Connecting;
|
||||
emit q->stateChanged(state);
|
||||
|
||||
controlPortAttempts = 0;
|
||||
controlPortTimer.start();
|
||||
}
|
||||
|
||||
void TorProcessPrivate::processFinished()
|
||||
{
|
||||
if (state < TorProcess::Starting)
|
||||
return;
|
||||
|
||||
controlPortTimer.stop();
|
||||
errorMessage = process.errorString();
|
||||
if (errorMessage.isEmpty())
|
||||
errorMessage = QStringLiteral("Process exited unexpectedly (code %1)").arg(process.exitCode());
|
||||
state = TorProcess::Failed;
|
||||
emit q->errorMessageChanged(errorMessage);
|
||||
emit q->stateChanged(state);
|
||||
}
|
||||
|
||||
void TorProcessPrivate::processError(QProcess::ProcessError error)
|
||||
{
|
||||
if (error == QProcess::FailedToStart || error == QProcess::Crashed)
|
||||
processFinished();
|
||||
}
|
||||
|
||||
void TorProcessPrivate::processReadable()
|
||||
{
|
||||
while (process.bytesAvailable() > 0) {
|
||||
QByteArray line = process.readLine(2048).trimmed();
|
||||
if (!line.isEmpty())
|
||||
emit q->logMessage(QString::fromLatin1(line));
|
||||
}
|
||||
}
|
||||
|
||||
void TorProcessPrivate::tryReadControlPort()
|
||||
{
|
||||
QFile file(controlPortFilePath());
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QByteArray data = file.readLine().trimmed();
|
||||
|
||||
int p;
|
||||
if (data.startsWith("PORT=") && (p = data.lastIndexOf(':')) > 0) {
|
||||
controlHost = QHostAddress(QString::fromLatin1(data.mid(5, p - 5)));
|
||||
controlPort = data.mid(p+1).toUShort();
|
||||
|
||||
if (!controlHost.isNull() && controlPort > 0) {
|
||||
controlPortTimer.stop();
|
||||
state = TorProcess::Ready;
|
||||
emit q->stateChanged(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (++controlPortAttempts * controlPortTimer.interval() > 10000) {
|
||||
errorMessage = QStringLiteral("No control port available after launching process");
|
||||
state = TorProcess::Failed;
|
||||
emit q->errorMessageChanged(errorMessage);
|
||||
emit q->stateChanged(state);
|
||||
}
|
||||
}
|
||||
|
100
retroshare-gui/src/TorControl/TorProcess.h
Normal file
100
retroshare-gui/src/TorControl/TorProcess.h
Normal file
@ -0,0 +1,100 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TORPROCESS_H
|
||||
#define TORPROCESS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
|
||||
namespace Tor
|
||||
{
|
||||
|
||||
class TorProcessPrivate;
|
||||
|
||||
/* Launches and controls a Tor instance with behavior suitable for bundling
|
||||
* an instance with the application. */
|
||||
class TorProcess : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(State)
|
||||
|
||||
Q_PROPERTY(State state READ state NOTIFY stateChanged)
|
||||
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
|
||||
|
||||
public:
|
||||
enum State {
|
||||
Failed = -1,
|
||||
NotStarted,
|
||||
Starting,
|
||||
Connecting,
|
||||
Ready
|
||||
};
|
||||
|
||||
explicit TorProcess(QObject *parent = 0);
|
||||
virtual ~TorProcess();
|
||||
|
||||
QString executable() const;
|
||||
void setExecutable(const QString &path);
|
||||
|
||||
QString dataDir() const;
|
||||
void setDataDir(const QString &path);
|
||||
|
||||
QString defaultTorrc() const;
|
||||
void setDefaultTorrc(const QString &path);
|
||||
|
||||
QStringList extraSettings() const;
|
||||
void setExtraSettings(const QStringList &settings);
|
||||
|
||||
State state() const;
|
||||
QString errorMessage() const;
|
||||
QHostAddress controlHost();
|
||||
quint16 controlPort();
|
||||
QByteArray controlPassword();
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
void stateChanged(int newState);
|
||||
void errorMessageChanged(const QString &errorMessage);
|
||||
void logMessage(const QString &message);
|
||||
|
||||
private:
|
||||
TorProcessPrivate *d;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
79
retroshare-gui/src/TorControl/TorProcess_p.h
Normal file
79
retroshare-gui/src/TorControl/TorProcess_p.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TORPROCESS_P_H
|
||||
#define TORPROCESS_P_H
|
||||
|
||||
#include "TorProcess.h"
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Tor {
|
||||
|
||||
class TorProcessPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TorProcess *q;
|
||||
QProcess process;
|
||||
QString executable;
|
||||
QString dataDir;
|
||||
QString defaultTorrc;
|
||||
QStringList extraSettings;
|
||||
TorProcess::State state;
|
||||
QString errorMessage;
|
||||
QHostAddress controlHost;
|
||||
quint16 controlPort;
|
||||
QByteArray controlPassword;
|
||||
|
||||
QTimer controlPortTimer;
|
||||
int controlPortAttempts;
|
||||
|
||||
TorProcessPrivate(TorProcess *q);
|
||||
|
||||
QString torrcPath() const;
|
||||
QString controlPortFilePath() const;
|
||||
bool ensureFilesExist();
|
||||
|
||||
public slots:
|
||||
void processStarted();
|
||||
void processFinished();
|
||||
void processError(QProcess::ProcessError error);
|
||||
void processReadable();
|
||||
void tryReadControlPort();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
155
retroshare-gui/src/TorControl/TorSocket.cpp
Normal file
155
retroshare-gui/src/TorControl/TorSocket.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "TorSocket.h"
|
||||
#include "TorControl.h"
|
||||
#include <QNetworkProxy>
|
||||
|
||||
using namespace Tor;
|
||||
|
||||
TorSocket::TorSocket(QObject *parent)
|
||||
: QTcpSocket(parent)
|
||||
, m_port(0)
|
||||
, m_reconnectEnabled(true)
|
||||
, m_maxInterval(900)
|
||||
, m_connectAttempts(0)
|
||||
{
|
||||
connect(torControl, SIGNAL(connectivityChanged()), SLOT(connectivityChanged()));
|
||||
connect(&m_connectTimer, SIGNAL(timeout()), SLOT(reconnect()));
|
||||
connect(this, SIGNAL(disconnected()), SLOT(onFailed()));
|
||||
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(onFailed()));
|
||||
|
||||
m_connectTimer.setSingleShot(true);
|
||||
connectivityChanged();
|
||||
}
|
||||
|
||||
TorSocket::~TorSocket()
|
||||
{
|
||||
}
|
||||
|
||||
void TorSocket::setReconnectEnabled(bool enabled)
|
||||
{
|
||||
if (enabled == m_reconnectEnabled)
|
||||
return;
|
||||
|
||||
m_reconnectEnabled = enabled;
|
||||
if (m_reconnectEnabled) {
|
||||
m_connectAttempts = 0;
|
||||
reconnect();
|
||||
} else {
|
||||
m_connectTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void TorSocket::setMaxAttemptInterval(int interval)
|
||||
{
|
||||
m_maxInterval = interval;
|
||||
}
|
||||
|
||||
void TorSocket::resetAttempts()
|
||||
{
|
||||
m_connectAttempts = 0;
|
||||
if (m_connectTimer.isActive()) {
|
||||
m_connectTimer.stop();
|
||||
m_connectTimer.start(reconnectInterval() * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
int TorSocket::reconnectInterval()
|
||||
{
|
||||
int delay = 0;
|
||||
if (m_connectAttempts <= 4)
|
||||
delay = 30;
|
||||
else if (m_connectAttempts <= 6)
|
||||
delay = 120;
|
||||
else
|
||||
delay = m_maxInterval;
|
||||
|
||||
return qMin(delay, m_maxInterval);
|
||||
}
|
||||
|
||||
void TorSocket::reconnect()
|
||||
{
|
||||
if (!torControl->hasConnectivity() || !reconnectEnabled())
|
||||
return;
|
||||
|
||||
m_connectTimer.stop();
|
||||
if (!m_host.isEmpty() && m_port) {
|
||||
std::cerr << "Attempting reconnection of socket to" << m_host.toStdString() << ":" << m_port << std::endl;
|
||||
connectToHost(m_host, m_port);
|
||||
}
|
||||
}
|
||||
|
||||
void TorSocket::connectivityChanged()
|
||||
{
|
||||
if (torControl->hasConnectivity()) {
|
||||
setProxy(torControl->connectionProxy());
|
||||
if (state() == QAbstractSocket::UnconnectedState)
|
||||
reconnect();
|
||||
} else {
|
||||
m_connectTimer.stop();
|
||||
m_connectAttempts = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TorSocket::connectToHost(const QString &hostName, quint16 port, OpenMode openMode,
|
||||
NetworkLayerProtocol protocol)
|
||||
{
|
||||
m_host = hostName;
|
||||
m_port = port;
|
||||
|
||||
if (!torControl->hasConnectivity())
|
||||
return;
|
||||
|
||||
if (proxy() != torControl->connectionProxy())
|
||||
setProxy(torControl->connectionProxy());
|
||||
|
||||
QAbstractSocket::connectToHost(hostName, port, openMode, protocol);
|
||||
}
|
||||
|
||||
void TorSocket::connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode)
|
||||
{
|
||||
TorSocket::connectToHost(address.toString(), port, openMode);
|
||||
}
|
||||
|
||||
void TorSocket::onFailed()
|
||||
{
|
||||
// Make sure the internal connection to the SOCKS proxy is closed
|
||||
// Otherwise reconnect attempts will fail (#295)
|
||||
close();
|
||||
|
||||
if (reconnectEnabled() && !m_connectTimer.isActive()) {
|
||||
m_connectAttempts++;
|
||||
m_connectTimer.start(reconnectInterval() * 1000);
|
||||
std::cerr << "Reconnecting socket to" << m_host.toStdString() << ":" << m_port << "in" << m_connectTimer.interval() / 1000 << "seconds" << std::endl;
|
||||
}
|
||||
}
|
97
retroshare-gui/src/TorControl/TorSocket.h
Normal file
97
retroshare-gui/src/TorControl/TorSocket.h
Normal file
@ -0,0 +1,97 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TORSOCKET_H
|
||||
#define TORSOCKET_H
|
||||
|
||||
#include <QTcpSocket>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Tor {
|
||||
|
||||
/* Specialized QTcpSocket which makes connections over the SOCKS proxy
|
||||
* from a TorControl instance, automatically attempts reconnections, and
|
||||
* reacts to Tor's connectivity state.
|
||||
*
|
||||
* Use normal QTcpSocket/QAbstractSocket API. When a connection fails, it
|
||||
* will be retried automatically after the correct interval and when
|
||||
* connectivity is available.
|
||||
*
|
||||
* To fully disconnect, destroy the object, or call
|
||||
* setReconnectEnabled(false) and disconnect the socket with
|
||||
* disconnectFromHost or abort.
|
||||
*
|
||||
* The caller is responsible for resetting the attempt counter if a
|
||||
* connection was successful and reconnection will be used again.
|
||||
*/
|
||||
class TorSocket : public QTcpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TorSocket(QObject *parent = 0);
|
||||
virtual ~TorSocket();
|
||||
|
||||
bool reconnectEnabled() const { return m_reconnectEnabled; }
|
||||
void setReconnectEnabled(bool enabled);
|
||||
int maxAttemptInterval() { return m_maxInterval; }
|
||||
void setMaxAttemptInterval(int interval);
|
||||
void resetAttempts();
|
||||
|
||||
virtual void connectToHost(const QString &hostName, quint16 port, OpenMode openMode = ReadWrite, NetworkLayerProtocol protocol = AnyIPProtocol);
|
||||
virtual void connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode = ReadWrite);
|
||||
|
||||
QString hostName() const { return m_host; }
|
||||
quint16 port() const { return m_port; }
|
||||
|
||||
protected:
|
||||
virtual int reconnectInterval();
|
||||
|
||||
private slots:
|
||||
void reconnect();
|
||||
void connectivityChanged();
|
||||
void onFailed();
|
||||
|
||||
private:
|
||||
QString m_host;
|
||||
quint16 m_port;
|
||||
QTimer m_connectTimer;
|
||||
bool m_reconnectEnabled;
|
||||
int m_maxInterval;
|
||||
int m_connectAttempts;
|
||||
|
||||
using QAbstractSocket::connectToHost;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
71
retroshare-gui/src/TorControl/Useful.h
Normal file
71
retroshare-gui/src/TorControl/Useful.h
Normal file
@ -0,0 +1,71 @@
|
||||
/* Ricochet - https://ricochet.im/
|
||||
* Copyright (C) 2014, John Brooks <john.brooks@dereferenced.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* * Neither the names of the copyright owners nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef UTILS_USEFUL_H
|
||||
#define UTILS_USEFUL_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
|
||||
/* Print a warning for bug conditions, and assert on a debug build.
|
||||
*
|
||||
* This should be used in place of Q_ASSERT for bug conditions, along
|
||||
* with a proper error case for release-mode builds. For example:
|
||||
*
|
||||
* if (!connection || !user) {
|
||||
* BUG() << "Request" << request << "should have a connection and user";
|
||||
* return false;
|
||||
* }
|
||||
*
|
||||
* Do not confuse bugs with actual error cases; BUG() should never be
|
||||
* triggered unless the code or logic is wrong.
|
||||
*/
|
||||
#if !defined(QT_NO_DEBUG) || defined(QT_FORCE_ASSERTS)
|
||||
# define BUG() Explode(__FILE__,__LINE__), qWarning() << "BUG:"
|
||||
namespace {
|
||||
class Explode
|
||||
{
|
||||
public:
|
||||
const char *file;
|
||||
int line;
|
||||
Explode(const char *file, int line) : file(file), line(line) { }
|
||||
~Explode() {
|
||||
qt_assert("something broke!", file, line);
|
||||
}
|
||||
};
|
||||
}
|
||||
#else
|
||||
# define BUG() qWarning() << "BUG:"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -225,9 +225,10 @@ void AWidget::initImages()
|
||||
//p.drawPixmap(QRect(10, 10, width()-10, 60), image);
|
||||
|
||||
/* Draw RetroShare version */
|
||||
p.drawText(QPointF(10, 50), QString("%1 : %2").arg(tr("Retroshare version"), Rshare::retroshareVersion(true)));
|
||||
#ifdef RS_ONLYHIDDENNODE
|
||||
p.drawText(QPointF(10, 70), QString("Only Hidden Node"));
|
||||
p.drawText(QPointF(10, 50), QString("%1 : %2 (With embedded Tor)").arg(tr("Retroshare version"), Rshare::retroshareVersion(true)));
|
||||
#else
|
||||
p.drawText(QPointF(10, 50), QString("%1 : %2").arg(tr("Retroshare version"), Rshare::retroshareVersion(true)));
|
||||
#endif
|
||||
|
||||
/* Draw Qt's version number */
|
||||
|
@ -195,6 +195,10 @@ GenCertDialog::GenCertDialog(bool onlyGenerateIdentity, QWidget *parent)
|
||||
ui.nodeType_CB->setCurrentIndex(1);
|
||||
ui.nodeType_CB->setEnabled(false);
|
||||
#endif
|
||||
#ifdef RETROTOR
|
||||
ui.adv_checkbox->setChecked(false);
|
||||
ui.adv_checkbox->setVisible(true);
|
||||
#endif
|
||||
|
||||
initKeyList();
|
||||
setupState();
|
||||
@ -255,10 +259,16 @@ void GenCertDialog::setupState()
|
||||
{
|
||||
bool adv_state = ui.adv_checkbox->isChecked();
|
||||
|
||||
#ifdef RETROTOR
|
||||
bool retrotor = true ;
|
||||
#else
|
||||
bool retrotor = false ;
|
||||
#endif
|
||||
|
||||
if(!adv_state)
|
||||
{
|
||||
ui.reuse_existing_node_CB->setChecked(false) ;
|
||||
ui.nodeType_CB->setCurrentIndex(0) ;
|
||||
ui.nodeType_CB->setCurrentIndex(retrotor?1:0) ;
|
||||
ui.keylength_comboBox->setCurrentIndex(0) ;
|
||||
}
|
||||
bool hidden_state = ui.nodeType_CB->currentIndex()==1;
|
||||
@ -271,8 +281,8 @@ void GenCertDialog::setupState()
|
||||
setWindowTitle(generate_new?tr("Create new profile and new Retroshare node"):tr("Create new Retroshare node"));
|
||||
//ui.headerFrame->setHeaderText(generate_new?tr("Create a new profile and node"):tr("Create a new node"));
|
||||
|
||||
ui.label_nodeType->setVisible(adv_state) ;
|
||||
ui.nodeType_CB->setVisible(adv_state) ;
|
||||
ui.label_nodeType->setVisible(adv_state && !retrotor) ;
|
||||
ui.nodeType_CB->setVisible(adv_state && !retrotor) ;
|
||||
ui.reuse_existing_node_CB->setEnabled(adv_state) ;
|
||||
ui.importIdentity_PB->setVisible(adv_state && !generate_new) ;
|
||||
ui.exportIdentity_PB->setVisible(adv_state && !generate_new) ;
|
||||
@ -308,13 +318,13 @@ void GenCertDialog::setupState()
|
||||
ui.entropy_bar->setVisible(true);
|
||||
ui.genButton->setVisible(true);
|
||||
|
||||
ui.hiddenaddr_input->setVisible(hidden_state);
|
||||
ui.hiddenaddr_label->setVisible(hidden_state);
|
||||
ui.hiddenaddr_input->setVisible(hidden_state && !retrotor);
|
||||
ui.hiddenaddr_label->setVisible(hidden_state && !retrotor);
|
||||
|
||||
ui.hiddenport_label->setVisible(hidden_state);
|
||||
ui.hiddenport_spinBox->setVisible(hidden_state);
|
||||
ui.hiddenport_label->setVisible(hidden_state && !retrotor);
|
||||
ui.hiddenport_spinBox->setVisible(hidden_state && !retrotor);
|
||||
|
||||
ui.cbUseBob->setVisible(hidden_state);
|
||||
ui.cbUseBob->setVisible(hidden_state && !retrotor);
|
||||
|
||||
if(!mAllFieldsOk)
|
||||
{
|
||||
|
@ -83,6 +83,7 @@
|
||||
#include "statusbar/SoundStatus.h"
|
||||
#include "statusbar/ToasterDisable.h"
|
||||
#include "statusbar/SysTrayStatus.h"
|
||||
#include "statusbar/torstatus.h"
|
||||
#include <retroshare/rsstatus.h>
|
||||
|
||||
#include <retroshare/rsiface.h>
|
||||
@ -244,18 +245,37 @@ MainWindow::MainWindow(QWidget* parent, Qt::WindowFlags flags)
|
||||
peerstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowPeer", QVariant(true)).toBool());
|
||||
statusBar()->addWidget(peerstatus);
|
||||
|
||||
natstatus = new NATStatus();
|
||||
if(hiddenmode) natstatus->setVisible(false);
|
||||
else natstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool());
|
||||
statusBar()->addWidget(natstatus);
|
||||
natstatus->getNATStatus();
|
||||
|
||||
dhtstatus = new DHTStatus();
|
||||
if(hiddenmode) dhtstatus->setVisible(false);
|
||||
else dhtstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool());
|
||||
statusBar()->addWidget(dhtstatus);
|
||||
dhtstatus->getDHTStatus();
|
||||
|
||||
if(hiddenmode)
|
||||
{
|
||||
#ifdef RETROTOR
|
||||
torstatus = new TorStatus();
|
||||
torstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowTor", QVariant(true)).toBool());
|
||||
statusBar()->addWidget(torstatus);
|
||||
torstatus->getTorStatus();
|
||||
#else
|
||||
torstatus = NULL ;
|
||||
#endif
|
||||
|
||||
natstatus = NULL ;
|
||||
dhtstatus = NULL ;
|
||||
}
|
||||
else
|
||||
{
|
||||
torstatus = NULL ;
|
||||
|
||||
natstatus = new NATStatus();
|
||||
if(hiddenmode) natstatus->setVisible(false);
|
||||
else natstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowNAT", QVariant(true)).toBool());
|
||||
statusBar()->addWidget(natstatus);
|
||||
natstatus->getNATStatus();
|
||||
|
||||
dhtstatus = new DHTStatus();
|
||||
if(hiddenmode) dhtstatus->setVisible(false);
|
||||
else dhtstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowDHT", QVariant(true)).toBool());
|
||||
statusBar()->addWidget(dhtstatus);
|
||||
dhtstatus->getDHTStatus();
|
||||
}
|
||||
|
||||
hashingstatus = new HashingStatus();
|
||||
hashingstatus->setVisible(Settings->valueFromGroup("StatusBar", "ShowHashing", QVariant(true)).toBool());
|
||||
statusBar()->addPermanentWidget(hashingstatus, 1);
|
||||
@ -710,6 +730,9 @@ void MainWindow::updateStatus()
|
||||
if (ratesstatus)
|
||||
ratesstatus->getRatesStatus(downKb, upKb);
|
||||
|
||||
if(torstatus)
|
||||
torstatus->getTorStatus();
|
||||
|
||||
if(!hiddenmode)
|
||||
{
|
||||
if (natstatus)
|
||||
@ -1594,6 +1617,10 @@ void MainWindow::setCompactStatusMode(bool compact)
|
||||
dhtstatus->setCompactMode(compact);
|
||||
dhtstatus->getDHTStatus();
|
||||
}
|
||||
|
||||
if(torstatus)
|
||||
torstatus->setCompactMode(compact) ;
|
||||
|
||||
hashingstatus->setCompactMode(compact);
|
||||
ratesstatus->setCompactMode(compact);
|
||||
//opModeStatus: TODO Show only ???
|
||||
|
@ -46,6 +46,7 @@ class OpModeStatus;
|
||||
class SoundStatus;
|
||||
class ToasterDisable;
|
||||
class SysTrayStatus;
|
||||
class TorStatus ;
|
||||
//class ForumsDialog;
|
||||
class GxsChannelDialog ;
|
||||
class GxsForumsDialog ;
|
||||
@ -293,6 +294,7 @@ private:
|
||||
SoundStatus *soundStatus;
|
||||
ToasterDisable *toasterDisable;
|
||||
SysTrayStatus *sysTrayStatus;
|
||||
TorStatus *torstatus;
|
||||
|
||||
/* Status */
|
||||
std::set <QObject*> m_apStatusObjects; // added objects for status
|
||||
|
@ -1,6 +1,8 @@
|
||||
#ifndef PGPID_ITEM_PROXY_H
|
||||
#define PGPID_ITEM_PROXY_H
|
||||
|
||||
#include "util/cxx11retrocompat.h"
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class pgpid_item_proxy :
|
||||
|
@ -46,7 +46,8 @@
|
||||
#include "util/HandleRichText.h"
|
||||
#include "util/QtVersion.h"
|
||||
|
||||
#include <retroshare/rsnotify.h>
|
||||
#include "retroshare/rsnotify.h"
|
||||
#include "util/rstime.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
@ -339,7 +340,7 @@ void ChatLobbyDialog::init(const ChatId &/*id*/, const QString &/*title*/)
|
||||
if(rsIdentity->getIdDetails(gxs_id,details))
|
||||
break ;
|
||||
else
|
||||
usleep(1000*300) ;
|
||||
rstime::rs_usleep(1000*300) ;
|
||||
|
||||
ui.chatWidget->setName(QString::fromUtf8(details.mNickname.c_str()));
|
||||
//ui.chatWidget->addToolsAction(ui.actionChangeNickname);
|
||||
|
@ -342,7 +342,8 @@ void FriendList::peerTreeWidgetCustomPopupMenu()
|
||||
|
||||
// QMenu *lobbyMenu = NULL;
|
||||
|
||||
switch (type) {
|
||||
switch (type)
|
||||
{
|
||||
case TYPE_GROUP:
|
||||
{
|
||||
bool standard = c->data(COLUMN_DATA, ROLE_STANDARD).toBool();
|
||||
@ -448,11 +449,11 @@ void FriendList::peerTreeWidgetCustomPopupMenu()
|
||||
contextMenu->addAction(QIcon(IMAGE_EXPORTFRIEND), tr("Recommend this node to..."), this, SLOT(recommendfriend()));
|
||||
}
|
||||
|
||||
contextMenu->addAction(QIcon(IMAGE_CONNECT), tr("Attempt to connect"), this, SLOT(connectfriend()));
|
||||
if(!rsPeers->isHiddenNode(rsPeers->getOwnId()) || rsPeers->isHiddenNode( RsPeerId(getRsId(c)) ))
|
||||
contextMenu->addAction(QIcon(IMAGE_CONNECT), tr("Attempt to connect"), this, SLOT(connectfriend()));
|
||||
|
||||
contextMenu->addAction(QIcon(IMAGE_COPYLINK), tr("Copy certificate link"), this, SLOT(copyFullCertificate()));
|
||||
|
||||
|
||||
//this is a SSL key
|
||||
contextMenu->addAction(QIcon(IMAGE_REMOVEFRIEND), tr("Remove Friend Node"), this, SLOT(removefriend()));
|
||||
|
||||
|
@ -45,11 +45,12 @@
|
||||
|
||||
#define IDDIALOG_IDLIST 1
|
||||
|
||||
#define ROLE_ID Qt::UserRole
|
||||
#define ROLE_SORT_GROUP Qt::UserRole + 1
|
||||
#define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 2
|
||||
#define ROLE_SORT_NAME Qt::UserRole + 3
|
||||
#define ROLE_SORT_STATE Qt::UserRole + 4
|
||||
#define ROLE_ID Qt::UserRole
|
||||
#define ROLE_SORT_GROUP Qt::UserRole + 1
|
||||
#define ROLE_SORT_STANDARD_GROUP Qt::UserRole + 2
|
||||
#define ROLE_SORT_NAME Qt::UserRole + 3
|
||||
#define ROLE_SORT_STATE Qt::UserRole + 4
|
||||
#define ROLE_FILTER_REASON Qt::UserRole + 5
|
||||
|
||||
#define IMAGE_GROUP16 ":/images/user/group16.png"
|
||||
#define IMAGE_FRIENDINFO ":/images/peerdetails_16x16.png"
|
||||
@ -109,10 +110,15 @@ FriendSelectionWidget::FriendSelectionWidget(QWidget *parent)
|
||||
mActionSortByState->setCheckable(true);
|
||||
connect(mActionSortByState, SIGNAL(toggled(bool)), this, SLOT(sortByState(bool)));
|
||||
ui->friendList->addContextMenuAction(mActionSortByState);
|
||||
mActionFilterConnected = new QAction(tr("Filter only connected"), this);
|
||||
mActionFilterConnected->setCheckable(true);
|
||||
connect(mActionFilterConnected, SIGNAL(toggled(bool)), this, SLOT(filterConnected(bool)));
|
||||
ui->friendList->addContextMenuAction(mActionFilterConnected);
|
||||
|
||||
/* initialize list */
|
||||
ui->friendList->setColumnCount(COLUMN_COUNT);
|
||||
ui->friendList->headerItem()->setText(COLUMN_NAME, tr("Name"));
|
||||
ui->friendList->setFilterReasonRole(ROLE_FILTER_REASON);
|
||||
|
||||
/* sort list by name ascending */
|
||||
ui->friendList->sortItems(COLUMN_NAME, Qt::AscendingOrder);
|
||||
@ -216,8 +222,8 @@ static void initSslItem(QTreeWidgetItem *item, const RsPeerDetails &detail, cons
|
||||
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1);
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0);
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_STATE, (state != (int) RS_STATUS_OFFLINE) ? 0 : 1);
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_NAME, name);
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_STATE, state);
|
||||
}
|
||||
|
||||
void FriendSelectionWidget::fillList()
|
||||
@ -359,8 +365,8 @@ void FriendSelectionWidget::secured_fillList()
|
||||
|
||||
groupItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 0);
|
||||
groupItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, (groupInfo->flag & RS_GROUP_FLAG_STANDARD) ? 0 : 1);
|
||||
groupItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 0);
|
||||
groupItem->setData(COLUMN_NAME, ROLE_SORT_NAME, groupName);
|
||||
groupItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 0);
|
||||
|
||||
if (mListModus == MODUS_CHECK) {
|
||||
groupItem->setCheckState(0, Qt::Unchecked);
|
||||
@ -426,8 +432,8 @@ void FriendSelectionWidget::secured_fillList()
|
||||
|
||||
gpgItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1);
|
||||
gpgItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0);
|
||||
gpgItem->setData(COLUMN_NAME, ROLE_SORT_STATE, (state != (int) RS_STATUS_OFFLINE) ? 0 : 1);
|
||||
gpgItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name);
|
||||
gpgItem->setData(COLUMN_NAME, ROLE_SORT_STATE, state);
|
||||
|
||||
if (mListModus == MODUS_CHECK) {
|
||||
gpgItem->setCheckState(0, Qt::Unchecked);
|
||||
@ -561,9 +567,9 @@ void FriendSelectionWidget::secured_fillList()
|
||||
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1);
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0);
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name);
|
||||
//TODO: online state for gxs items
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 1);
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name);
|
||||
|
||||
if (mListModus == MODUS_CHECK)
|
||||
gxsItem->setCheckState(0, Qt::Unchecked);
|
||||
@ -615,9 +621,9 @@ void FriendSelectionWidget::secured_fillList()
|
||||
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_GROUP, 1);
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_STANDARD_GROUP, 0);
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name);
|
||||
//TODO: online state for gxs items
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_STATE, 1);
|
||||
gxsItem->setData(COLUMN_NAME, ROLE_SORT_NAME, name);
|
||||
|
||||
if (mListModus == MODUS_CHECK)
|
||||
gxsItem->setCheckState(0, Qt::Unchecked);
|
||||
@ -650,6 +656,7 @@ void FriendSelectionWidget::secured_fillList()
|
||||
mInFillList = false;
|
||||
|
||||
ui->friendList->resort();
|
||||
filterConnected(isFilterConnected());
|
||||
|
||||
emit contentChanged();
|
||||
}
|
||||
@ -751,7 +758,7 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status)
|
||||
item->setTextColor(COLUMN_NAME, color);
|
||||
item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(gpgStatus)));
|
||||
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_STATE, (gpgStatus != (int) RS_STATUS_OFFLINE) ? 0 : 1);
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_STATE, gpgStatus);
|
||||
|
||||
bFoundGPG = true;
|
||||
}
|
||||
@ -770,7 +777,7 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status)
|
||||
item->setTextColor(COLUMN_NAME, color);
|
||||
item->setIcon(COLUMN_NAME, QIcon(StatusDefs::imageUser(status)));
|
||||
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_STATE, (status != (int) RS_STATUS_OFFLINE) ? 0 : 1);
|
||||
item->setData(COLUMN_NAME, ROLE_SORT_STATE, status);
|
||||
|
||||
bFoundSSL = true;
|
||||
}
|
||||
@ -799,6 +806,7 @@ void FriendSelectionWidget::peerStatusChanged(const QString& peerId, int status)
|
||||
}
|
||||
|
||||
ui->friendList->resort();
|
||||
filterConnected(isFilterConnected());
|
||||
}
|
||||
|
||||
void FriendSelectionWidget::addContextMenuAction(QAction *action)
|
||||
@ -810,7 +818,7 @@ void FriendSelectionWidget::contextMenuRequested(const QPoint &/*pos*/)
|
||||
{
|
||||
QMenu *contextMenu = new QMenu(this);
|
||||
|
||||
if (mListModus == MODUS_CHECK) {
|
||||
if (mListModus == MODUS_MULTI) {
|
||||
contextMenu->addAction(QIcon(), tr("Mark all"), this, SLOT(selectAll()));
|
||||
contextMenu->addAction(QIcon(), tr("Mark none"), this, SLOT(deselectAll()));
|
||||
}
|
||||
@ -953,37 +961,9 @@ void FriendSelectionWidget::itemChanged(QTreeWidgetItem *item, int column)
|
||||
|
||||
void FriendSelectionWidget::filterItems(const QString& text)
|
||||
{
|
||||
int count = ui->friendList->topLevelItemCount();
|
||||
for (int index = 0; index < count; ++index) {
|
||||
filterItem(ui->friendList->topLevelItem(index), text);
|
||||
}
|
||||
}
|
||||
|
||||
bool FriendSelectionWidget::filterItem(QTreeWidgetItem *item, const QString &text)
|
||||
{
|
||||
bool visible = true;
|
||||
|
||||
if (text.isEmpty() == false) {
|
||||
if (item->text(0).contains(text, Qt::CaseInsensitive) == false) {
|
||||
visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
int visibleChildCount = 0;
|
||||
int count = item->childCount();
|
||||
for (int index = 0; index < count; ++index) {
|
||||
if (filterItem(item->child(index), text)) {
|
||||
++visibleChildCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (visible || visibleChildCount) {
|
||||
item->setHidden(false);
|
||||
} else {
|
||||
item->setHidden(true);
|
||||
}
|
||||
|
||||
return (visible || visibleChildCount);
|
||||
ui->friendList->filterItems(COLUMN_NAME, text);
|
||||
ui->friendList->resort();
|
||||
filterConnected(isFilterConnected());
|
||||
}
|
||||
|
||||
int FriendSelectionWidget::selectedItemCount()
|
||||
@ -1168,9 +1148,24 @@ void FriendSelectionWidget::sortByState(bool sort)
|
||||
mActionSortByState->setChecked(sort);
|
||||
|
||||
ui->friendList->resort();
|
||||
filterConnected(isFilterConnected());
|
||||
}
|
||||
|
||||
bool FriendSelectionWidget::isSortByState()
|
||||
{
|
||||
return mActionSortByState->isChecked();
|
||||
}
|
||||
|
||||
void FriendSelectionWidget::filterConnected(bool filter)
|
||||
{
|
||||
ui->friendList->filterMinValItems(COLUMN_NAME, filter ? RS_STATUS_AWAY : RS_STATUS_OFFLINE, ROLE_SORT_STATE);
|
||||
|
||||
mActionFilterConnected->setChecked(filter);
|
||||
|
||||
ui->friendList->resort();
|
||||
}
|
||||
|
||||
bool FriendSelectionWidget::isFilterConnected()
|
||||
{
|
||||
return mActionFilterConnected->isChecked();
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
void start();
|
||||
|
||||
bool isSortByState();
|
||||
bool isFilterConnected();
|
||||
|
||||
int selectedItemCount();
|
||||
std::string selectedId(IdType &idType);
|
||||
@ -130,6 +131,7 @@ signals:
|
||||
|
||||
public slots:
|
||||
void sortByState(bool sort);
|
||||
void filterConnected(bool filter);
|
||||
|
||||
private slots:
|
||||
void groupsChanged(int type);
|
||||
@ -144,7 +146,6 @@ private slots:
|
||||
private:
|
||||
void fillList();
|
||||
void secured_fillList();
|
||||
bool filterItem(QTreeWidgetItem *item, const QString &text);
|
||||
|
||||
void selectedIds(IdType idType, std::set<std::string> &ids, bool onlyDirectSelected);
|
||||
void setSelectedIds(IdType idType, const std::set<std::string> &ids, bool add);
|
||||
@ -161,6 +162,7 @@ private:
|
||||
bool mInSslItemChanged;
|
||||
bool mInFillList;
|
||||
QAction *mActionSortByState;
|
||||
QAction *mActionFilterConnected;
|
||||
|
||||
/* Color definitions (for standard see qss.default) */
|
||||
QColor mTextColorOnline;
|
||||
|
@ -34,6 +34,7 @@ RSTreeWidget::RSTreeWidget(QWidget *parent) : QTreeWidget(parent)
|
||||
{
|
||||
mEnableColumnCustomize = false;
|
||||
mSettingsVersion = 0; // disabled
|
||||
mFilterReasonRole = -1; // disabled
|
||||
|
||||
QHeaderView *h = header();
|
||||
h->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
@ -84,6 +85,12 @@ void RSTreeWidget::mousePressEvent(QMouseEvent *event)
|
||||
QTreeWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void RSTreeWidget::setFilterReasonRole(int role /*=-1*/)
|
||||
{
|
||||
if (role > Qt::UserRole)
|
||||
mFilterReasonRole = role;
|
||||
}
|
||||
|
||||
void RSTreeWidget::filterItems(int filterColumn, const QString &text, int role)
|
||||
{
|
||||
int count = topLevelItemCount();
|
||||
@ -101,6 +108,13 @@ void RSTreeWidget::filterItems(int filterColumn, const QString &text, int role)
|
||||
bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text, int role)
|
||||
{
|
||||
bool itemVisible = true;
|
||||
//Get who hide this item
|
||||
int filterReason = 0;
|
||||
if (mFilterReasonRole >= Qt::UserRole)
|
||||
filterReason = item->data(filterColumn, mFilterReasonRole).toInt();
|
||||
//Remove this filter for last test
|
||||
if (filterReason & FILTER_REASON_TEXT)
|
||||
filterReason -= FILTER_REASON_TEXT;
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
if (!item->data(filterColumn, role).toString().contains(text, Qt::CaseInsensitive)) {
|
||||
@ -116,11 +130,62 @@ bool RSTreeWidget::filterItem(QTreeWidgetItem *item, int filterColumn, const QSt
|
||||
}
|
||||
}
|
||||
|
||||
if (itemVisible || visibleChildCount) {
|
||||
item->setHidden(false);
|
||||
} else {
|
||||
item->setHidden(true);
|
||||
if (!itemVisible && !visibleChildCount) {
|
||||
filterReason |= FILTER_REASON_TEXT;
|
||||
}
|
||||
item->setHidden(filterReason != 0);
|
||||
//Update hiding reason
|
||||
if (mFilterReasonRole >= Qt::UserRole)
|
||||
item->setData(filterColumn, mFilterReasonRole, filterReason);
|
||||
|
||||
return (itemVisible || visibleChildCount);
|
||||
}
|
||||
|
||||
void RSTreeWidget::filterMinValItems(int filterColumn, const double &value, int role)
|
||||
{
|
||||
int count = topLevelItemCount();
|
||||
for (int index = 0; index < count; ++index) {
|
||||
filterMinValItem(topLevelItem(index), filterColumn, value, role);
|
||||
}
|
||||
|
||||
QTreeWidgetItem *item = currentItem();
|
||||
if (item && item->isHidden()) {
|
||||
// active item is hidden, deselect it
|
||||
setCurrentItem(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool RSTreeWidget::filterMinValItem(QTreeWidgetItem *item, int filterColumn, const double &value, int role)
|
||||
{
|
||||
bool itemVisible = true;
|
||||
//Get who hide this item
|
||||
int filterReason = 0;
|
||||
if (mFilterReasonRole >= Qt::UserRole)
|
||||
filterReason = item->data(filterColumn, mFilterReasonRole).toInt();
|
||||
//Remove this filter for last test
|
||||
if (filterReason & FILTER_REASON_MINVAL)
|
||||
filterReason -= FILTER_REASON_MINVAL;
|
||||
|
||||
bool ok = false;
|
||||
if ((item->data(filterColumn, role).toDouble(&ok) < value) && ok ) {
|
||||
itemVisible = false;
|
||||
}
|
||||
|
||||
int visibleChildCount = 0;
|
||||
int count = item->childCount();
|
||||
for (int index = 0; index < count; ++index) {
|
||||
if (filterMinValItem(item->child(index), filterColumn, value, role)) {
|
||||
++visibleChildCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemVisible && !visibleChildCount) {
|
||||
filterReason |= FILTER_REASON_MINVAL;
|
||||
}
|
||||
item->setHidden(filterReason != 0);
|
||||
//Update hiding reason
|
||||
if (mFilterReasonRole >= Qt::UserRole)
|
||||
item->setData(filterColumn, mFilterReasonRole, filterReason);
|
||||
|
||||
return (itemVisible || visibleChildCount);
|
||||
}
|
||||
@ -294,6 +359,6 @@ void RSTreeWidget::columnVisible()
|
||||
void RSTreeWidget::resort()
|
||||
{
|
||||
if (isSortingEnabled()) {
|
||||
sortByColumn(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
|
||||
sortItems(header()->sortIndicatorSection(), header()->sortIndicatorOrder());
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,9 @@
|
||||
|
||||
#include <QTreeWidget>
|
||||
|
||||
#define FILTER_REASON_TEXT 0x0001
|
||||
#define FILTER_REASON_MINVAL 0x0002
|
||||
|
||||
/* Subclassing QTreeWidget */
|
||||
class RSTreeWidget : public QTreeWidget
|
||||
{
|
||||
@ -35,7 +38,9 @@ public:
|
||||
QString placeholderText() { return mPlaceholderText; }
|
||||
void setPlaceholderText(const QString &text);
|
||||
|
||||
void setFilterReasonRole(int role = -1);
|
||||
void filterItems(int filterColumn, const QString &text, int role = Qt::DisplayRole);
|
||||
void filterMinValItems(int filterColumn, const double &value, int role = Qt::DisplayRole);
|
||||
|
||||
void setSettingsVersion(qint32 version);
|
||||
void processSettings(bool load);
|
||||
@ -58,6 +63,7 @@ signals:
|
||||
|
||||
private:
|
||||
bool filterItem(QTreeWidgetItem *item, int filterColumn, const QString &text, int role);
|
||||
bool filterMinValItem(QTreeWidgetItem *item, int filterColumn, const double &value, int role);
|
||||
|
||||
private slots:
|
||||
void headerContextMenuRequested(const QPoint &pos);
|
||||
@ -74,6 +80,7 @@ private:
|
||||
QMap<int, bool> mColumnCustomizable;
|
||||
QList<QAction*> mContextMenuActions;
|
||||
QList<QMenu*> mContextMenuMenus;
|
||||
int mFilterReasonRole;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -435,15 +435,29 @@ void ConnectFriendWizard::initializePage(int id)
|
||||
break;
|
||||
case Page_Conclusion:
|
||||
{
|
||||
bool peerIsHiddenNode = peerDetails.isHiddenNode ;
|
||||
bool amIHiddenNode = rsPeers->isHiddenNode(rsPeers->getOwnId()) ;
|
||||
|
||||
std::cerr << "Conclusion page id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
|
||||
|
||||
ui->_direct_transfer_CB_2 ->setChecked(false) ; //peerDetails.service_perm_flags & RS_NODE_PERM_DIRECT_DL) ;
|
||||
ui->_allow_push_CB_2 ->setChecked(peerDetails.service_perm_flags & RS_NODE_PERM_ALLOW_PUSH) ;
|
||||
ui->_require_WL_CB_2 ->setChecked(peerDetails.service_perm_flags & RS_NODE_PERM_REQUIRE_WL) ;
|
||||
|
||||
if(!peerIsHiddenNode && !amIHiddenNode)
|
||||
ui->_require_WL_CB_2 ->setChecked(peerDetails.service_perm_flags & RS_NODE_PERM_REQUIRE_WL) ;
|
||||
else
|
||||
{
|
||||
ui->_require_WL_CB_2 ->setChecked(false) ;
|
||||
ui->_require_WL_CB_2 ->hide() ;
|
||||
|
||||
ui->_addIPToWhiteList_CB_2->hide();
|
||||
ui->_addIPToWhiteList_ComboBox_2->hide();
|
||||
}
|
||||
|
||||
sockaddr_storage addr ;
|
||||
|
||||
std::cerr << "Cert IP = " << peerDetails.extAddr << std::endl;
|
||||
std::cerr << "Cert IP = " << peerDetails.extAddr << std::endl;
|
||||
|
||||
if(sockaddr_storage_ipv4_aton(addr,peerDetails.extAddr.c_str()) && sockaddr_storage_isValidNet(addr))
|
||||
{
|
||||
QString ipstring0 = QString::fromStdString(sockaddr_storage_iptostring(addr));
|
||||
@ -577,29 +591,28 @@ void ConnectFriendWizard::initializePage(int id)
|
||||
ui->fr_avatar->setFrameType(AvatarWidget::NORMAL_FRAME);
|
||||
setPixmap(QWizard::LogoPixmap, QPixmap(":/images/user/user_request48.png"));
|
||||
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
|
||||
//set the radio button to sign the GPG key
|
||||
if (peerDetails.accept_connection && !peerDetails.ownsign) {
|
||||
//gpg key connection is already accepted, don't propose to accept it again
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
ui->fr_acceptNoSignGPGCheckBox->hide();
|
||||
ui->fr_signGPGCheckBox->show();
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(false);
|
||||
}
|
||||
if (!peerDetails.accept_connection && peerDetails.ownsign) {
|
||||
//gpg key is already signed, don't propose to sign it again
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(true);
|
||||
ui->fr_signGPGCheckBox->hide();
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
}
|
||||
if (!peerDetails.accept_connection && !peerDetails.ownsign) {
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(true);
|
||||
ui->fr_signGPGCheckBox->show();
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
ui->fr_acceptNoSignGPGCheckBox->show();
|
||||
}
|
||||
if (peerDetails.accept_connection && peerDetails.ownsign) {
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(false);
|
||||
ui->fr_acceptNoSignGPGCheckBox->hide();
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
ui->fr_signGPGCheckBox->hide();
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>760</width>
|
||||
<height>538</height>
|
||||
<width>1161</width>
|
||||
<height>1223</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -64,6 +64,9 @@ ConnectProgressDialog::ConnectProgressDialog(const RsPeerId& id, QWidget *parent
|
||||
ui->headerFrame->setHeaderText(tr("Connection Assistant"));
|
||||
|
||||
connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(stopAndClose()));
|
||||
|
||||
mAmIHiddenNode = rsPeers->isHiddenNode(rsPeers->getOwnId()) ;
|
||||
mIsPeerHiddenNode = rsPeers->isHiddenNode(id) ;
|
||||
}
|
||||
|
||||
ConnectProgressDialog::~ConnectProgressDialog()
|
||||
@ -165,15 +168,35 @@ void ConnectProgressDialog::initDialog()
|
||||
ui->NetResult->setText(tr("N/A"));
|
||||
ui->ContactResult->setText(tr("N/A"));
|
||||
|
||||
#ifdef RS_USE_BITDHT
|
||||
if(!mIsPeerHiddenNode && !mAmIHiddenNode)
|
||||
{
|
||||
ui->DhtResult->setText(tr("DHT Startup"));
|
||||
ui->DhtProgressBar->setValue(0);
|
||||
}
|
||||
#else
|
||||
if(mIsPeerHiddenNode || mAmIHiddenNode)
|
||||
{
|
||||
ui->DhtResult->hide();
|
||||
ui->DhtLabel->hide();
|
||||
ui->DhtProgressBar->hide();
|
||||
}
|
||||
#endif
|
||||
if(mIsPeerHiddenNode || mAmIHiddenNode)
|
||||
{
|
||||
ui->UdpResult->hide();
|
||||
ui->UdpProgressBar->hide();
|
||||
ui->UdpLabel->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->UdpResult->setText(tr("N/A"));
|
||||
ui->UdpProgressBar->setValue(0);
|
||||
}
|
||||
|
||||
ui->LookupResult->setText(tr("N/A"));
|
||||
ui->LookupProgressBar->setValue(0);
|
||||
|
||||
ui->UdpResult->setText(tr("N/A"));
|
||||
ui->UdpProgressBar->setValue(0);
|
||||
|
||||
sayInProgress();
|
||||
|
||||
if (rsPeers->isFriend(mId))
|
||||
@ -219,7 +242,9 @@ void ConnectProgressDialog::updateStatus()
|
||||
|
||||
updateNetworkStatus();
|
||||
updateContactStatus();
|
||||
#ifdef RS_USE_BITDHT
|
||||
updateDhtStatus();
|
||||
#endif
|
||||
updateLookupStatus();
|
||||
updateUdpStatus();
|
||||
|
||||
@ -443,6 +468,7 @@ void ConnectProgressDialog::updateLookupStatus()
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef RS_USE_BITDHT
|
||||
time_t now = time(NULL);
|
||||
switch(mDhtStatus)
|
||||
{
|
||||
@ -520,6 +546,7 @@ void ConnectProgressDialog::updateLookupStatus()
|
||||
mLookupStatus = CONNECT_LOOKUP_ONLINE;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -572,6 +599,7 @@ void ConnectProgressDialog::updateUdpStatus()
|
||||
|
||||
ui->UdpProgressBar->setValue(calcProgress(now, mUdpTS, CONNECT_UDP_TYPICAL, CONNECT_UDP_SLOW, CONNECT_UDP_PERIOD));
|
||||
|
||||
#ifdef RS_USE_BITDHT
|
||||
/* now lookup details from Dht */
|
||||
RsDhtNetPeer status;
|
||||
rsDht->getNetPeerStatus(mId, status);
|
||||
@ -599,6 +627,7 @@ void ConnectProgressDialog::updateUdpStatus()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -97,6 +97,9 @@ private:
|
||||
time_t mUdpTS;
|
||||
uint32_t mUdpStatus;
|
||||
|
||||
bool mAmIHiddenNode ;
|
||||
bool mIsPeerHiddenNode ;
|
||||
|
||||
/** Qt Designer generated object */
|
||||
Ui::ConnectProgressDialog *ui;
|
||||
};
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>553</width>
|
||||
<height>489</height>
|
||||
<width>623</width>
|
||||
<height>608</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -21,7 +21,16 @@
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<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>
|
||||
@ -97,7 +106,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<widget class="QLabel" name="DhtLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -117,7 +126,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<widget class="QLabel" name="LookupLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -137,7 +146,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<widget class="QLabel" name="UdpLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
@ -283,10 +292,10 @@
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
</style></head><body style=" font-family:'Sans'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">This Widget shows the progress of your connection to your new peer.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">It is helpful for problem-solving.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:13pt;"></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:13pt;"><br /></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">If you are an expert RS user, or trust that RS will do the right thing</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Lucida Grande'; font-size:13pt;">you can close it.</span></p></body></html></string>
|
||||
</property>
|
||||
@ -331,7 +340,6 @@ p, li { white-space: pre-wrap; }
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../images.qrc"/>
|
||||
<include location="../images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/onion.png</file>
|
||||
<file>icons/svg/hidden.svg</file>
|
||||
<file>icons/svg/randomness.svg</file>
|
||||
<file>icons/svg/password.svg</file>
|
||||
@ -227,6 +228,7 @@
|
||||
<file>icons/tor-logo.png</file>
|
||||
<file>icons/tor-off.png</file>
|
||||
<file>icons/tor-on.png</file>
|
||||
<file>icons/no-tor.png</file>
|
||||
<file>icons/tor-starting.png</file>
|
||||
<file>icons/tor-stopping.png</file>
|
||||
<file>icons/user-away_64.png</file>
|
||||
|
BIN
retroshare-gui/src/gui/icons/no-tor.png
Normal file
BIN
retroshare-gui/src/gui/icons/no-tor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
retroshare-gui/src/gui/icons/onion.png
Normal file
BIN
retroshare-gui/src/gui/icons/onion.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
@ -366,13 +366,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxShowDHTStatus">
|
||||
<property name="text">
|
||||
<string>Show DHT Status</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxShowHashingStatus">
|
||||
<property name="text">
|
||||
@ -380,13 +373,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="checkBoxShowNATStatus">
|
||||
<property name="text">
|
||||
<string>Show NAT Status</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxShowPeerStatus">
|
||||
<property name="text">
|
||||
@ -418,17 +404,31 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QCheckBox" name="checkBoxShowSystrayOnStatus">
|
||||
<item row="2" column="2">
|
||||
<widget class="QCheckBox" name="checkBoxShowNATStatus">
|
||||
<property name="text">
|
||||
<string>Show SysTray on Status Bar</string>
|
||||
<string>Show NAT Status</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="checkBoxShowOpModeStatus">
|
||||
<property name="text">
|
||||
<string>Show Operating Mode Status</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QCheckBox" name="checkBoxShowOpModeStatus">
|
||||
<widget class="QCheckBox" name="checkBoxShowDHTStatus">
|
||||
<property name="text">
|
||||
<string>Show Operating Mode Status</string>
|
||||
<string>Show DHT Status</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxShowSystrayOnStatus">
|
||||
<property name="text">
|
||||
<string>Show SysTray on Status Bar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -59,7 +59,26 @@
|
||||
///
|
||||
/// \brief hiddenServiceIncomingTab index of hidden serice incoming tab
|
||||
///
|
||||
const static uint32_t hiddenServiceIncomingTab = 2;
|
||||
///
|
||||
|
||||
// Tabs numbers *after* non relevant tabs are removed. So do not use them to add/remove tabs!!
|
||||
#ifdef RETROTOR
|
||||
static const uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0;
|
||||
static const uint32_t TAB_HIDDEN_SERVICE_INCOMING = 1;
|
||||
|
||||
static const uint32_t TAB_NETWORK = 0;
|
||||
static const uint32_t TAB_HIDDEN_SERVICE = 1;
|
||||
static const uint32_t TAB_IP_FILTERS = 99; // This is a trick: these tabs do not exist, so enabling/disabling them has no effect
|
||||
static const uint32_t TAB_RELAYS = 99;
|
||||
#else
|
||||
const static uint32_t TAB_HIDDEN_SERVICE_OUTGOING = 0;
|
||||
const static uint32_t TAB_HIDDEN_SERVICE_INCOMING = 2;
|
||||
|
||||
const static uint32_t TAB_NETWORK = 0;
|
||||
const static uint32_t TAB_IP_FILTERS = 1;
|
||||
const static uint32_t TAB_HIDDEN_SERVICE = 2;
|
||||
const static uint32_t TAB_RELAYS = 3;
|
||||
#endif
|
||||
|
||||
//#define SERVER_DEBUG 1
|
||||
|
||||
@ -71,6 +90,26 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
|
||||
|
||||
manager = NULL ;
|
||||
|
||||
#ifdef RETROTOR
|
||||
// Here we use absolute numbers instead of consts defined above, because the consts correspond to the tab number *after* this tab removal.
|
||||
|
||||
ui.tabWidget->removeTab(3) ; // remove relays. Not useful in Tor mode.
|
||||
ui.tabWidget->removeTab(1) ; // remove IP filters. Not useful in Tor mode.
|
||||
|
||||
ui.hiddenServiceTab->removeTab(1) ; // remove the Automatic I2P/BOB tab
|
||||
ui.hiddenpage_proxyAddress_i2p->hide() ;
|
||||
ui.hiddenpage_proxyLabel_i2p->hide() ;
|
||||
ui.hiddenpage_proxyPort_i2p->hide() ;
|
||||
ui.label_i2p_outgoing->hide() ;
|
||||
ui.iconlabel_i2p_outgoing->hide() ;
|
||||
ui.plainTextEdit->hide() ;
|
||||
ui.hiddenpage_configuration->hide() ;
|
||||
ui.l_hiddenpage_configuration->hide() ;
|
||||
ui.hiddenpageInHelpPlainTextEdit->hide() ;
|
||||
|
||||
ui.hiddenpage_outHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ;
|
||||
ui.hiddenpage_inHeader->setText(tr("Tor has been automatically configured by Retroshare. You shouldn't need to change anything here.")) ;
|
||||
#endif
|
||||
ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_RANGE,new QTableWidgetItem(tr("IP Range"))) ;
|
||||
ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_STATUS,new QTableWidgetItem(tr("Status"))) ;
|
||||
ui.filteredIpsTable->setHorizontalHeaderItem(COLUMN_ORIGIN,new QTableWidgetItem(tr("Origin"))) ;
|
||||
@ -98,7 +137,7 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
|
||||
for(std::list<std::string>::const_iterator it(ip_servers.begin());it!=ip_servers.end();++it)
|
||||
ui.IPServersLV->addItem(QString::fromStdString(*it)) ;
|
||||
|
||||
ui.hiddenServiceTab->setTabEnabled(hiddenServiceIncomingTab, false);
|
||||
ui.hiddenServiceTab->setTabEnabled(TAB_HIDDEN_SERVICE_INCOMING, false);
|
||||
ui.gbBob->setEnabled(false);
|
||||
ui.swBobAdvanced->setCurrentIndex(0);
|
||||
|
||||
@ -196,7 +235,6 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
|
||||
|
||||
QObject::connect(ui.enableCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateRelayMode()));
|
||||
QObject::connect(ui.serverCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateRelayMode()));
|
||||
|
||||
}
|
||||
|
||||
void ServerPage::saveAndTestInProxy()
|
||||
@ -300,8 +338,8 @@ void ServerPage::load()
|
||||
if (mIsHiddenNode)
|
||||
{
|
||||
mHiddenType = detail.hiddenType;
|
||||
ui.tabWidget->setTabEnabled(1,false) ; // ip filter
|
||||
ui.tabWidget->setTabEnabled(3,false) ; // relay
|
||||
ui.tabWidget->setTabEnabled(TAB_IP_FILTERS,false) ; // ip filter
|
||||
ui.tabWidget->setTabEnabled(TAB_RELAYS,false) ; // relay
|
||||
loadHiddenNode();
|
||||
return;
|
||||
}
|
||||
@ -460,6 +498,9 @@ void ServerPage::toggleIpFiltering(bool b)
|
||||
|
||||
void ServerPage::loadFilteredIps()
|
||||
{
|
||||
if(rsBanList == NULL)
|
||||
return ;
|
||||
|
||||
if(rsBanList->ipFilteringEnabled())
|
||||
{
|
||||
whileBlocking(ui.denyAll_CB)->setChecked(true) ;
|
||||
@ -854,6 +895,8 @@ void ServerPage::toggleUPnP()
|
||||
settingChangeable = true;
|
||||
}
|
||||
|
||||
// Shouldn't we use readOnly instead of enabled??
|
||||
|
||||
if (settingChangeable)
|
||||
{
|
||||
ui.localAddress->setEnabled(false);
|
||||
@ -876,7 +919,7 @@ void ServerPage::saveAddresses()
|
||||
|
||||
saveCommon();
|
||||
|
||||
if(ui.tabWidget->currentIndex() == 2) // hidden services tab
|
||||
if(ui.tabWidget->currentIndex() == TAB_HIDDEN_SERVICE) // hidden services tab
|
||||
updateOutProxyIndicator();
|
||||
|
||||
if (mIsHiddenNode) {
|
||||
@ -1055,7 +1098,7 @@ void ServerPage::loadHiddenNode()
|
||||
ui.label_dynDNS->setVisible(false);
|
||||
ui.dynDNS ->setVisible(false);
|
||||
|
||||
ui.hiddenServiceTab->setTabEnabled(hiddenServiceIncomingTab, true);
|
||||
ui.hiddenServiceTab->setTabEnabled(TAB_HIDDEN_SERVICE_INCOMING, true);
|
||||
|
||||
/* Addresses must be set here - otherwise can't edit it */
|
||||
/* set local address */
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1220</width>
|
||||
<height>896</height>
|
||||
<width>1283</width>
|
||||
<height>917</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="ServerPageVLayout">
|
||||
@ -26,7 +26,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabNetConf">
|
||||
<attribute name="title">
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user