diff --git a/BUILD.md b/BUILD.md index 7cb965f1..27547e12 100644 --- a/BUILD.md +++ b/BUILD.md @@ -11,9 +11,9 @@ cd onionshare Install the needed dependencies: -For Debian-like distros: `apt install -y build-essential fakeroot python3-all python3-stdeb dh-python python3-flask python3-stem python3-pyqt5 python-nautilus python3-pytest tor` +For Debian-like distros: `apt install -y build-essential fakeroot python3-all python3-stdeb dh-python python3-flask python3-stem python3-pyqt5 python-nautilus python3-pytest tor obfs4proxy` -For Fedora-like distros: `dnf install -y rpm-build python3-flask python3-stem python3-qt5 python3-pytest nautilus-python tor` +For Fedora-like distros: `dnf install -y rpm-build python3-flask python3-stem python3-qt5 python3-pytest nautilus-python tor obfs4` After that you can try both the CLI and the GUI version of OnionShare: @@ -98,11 +98,16 @@ These instructions include adding folders to the path in Windows. To do this, go Download and install the 32-bit [Visual C++ Redistributable for Visual Studio 2015](https://www.microsoft.com/en-US/download/details.aspx?id=48145). I downloaded `vc_redist.x86.exe`. -Download and install the standalone [Windows 10 SDK](https://dev.windows.com/en-us/downloads/windows-10-sdk). Note that you may not need this if you already have Visual Studio. Add the following directories to the path: +Download and install 7-Zip from http://70zip.org/download.html. I downloaded 7z1800.exe. + +Download and install the standalone [Windows 10 SDK](https://dev.windows.com/en-us/downloads/windows-10-sdk). Note that you may not need this if you already have Visual Studio. + +Add the following directories to the path: * `C:\Program Files (x86)\Windows Kits\10\bin\10.0.16299.0\x86` * `C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x86` * `C:\Users\user\AppData\Local\Programs\Python\Python36-32\Lib\site-packages\PyQt5\Qt\bin` +* `C:\Program Files (x86)\7-Zip` If you want to build the installer: diff --git a/install/build_rpm.sh b/install/build_rpm.sh index 98cd9c5b..c103262c 100755 --- a/install/build_rpm.sh +++ b/install/build_rpm.sh @@ -9,7 +9,7 @@ VERSION=`cat share/version.txt` rm -r build dist >/dev/null 2>&1 # build binary package -python3 setup.py bdist_rpm --requires="python3-flask, python3-stem, python3-qt5, nautilus-python, tor" +python3 setup.py bdist_rpm --requires="python3-flask, python3-stem, python3-qt5, nautilus-python, tor, obfs4" # install it echo "" diff --git a/install/get-tor-osx.py b/install/get-tor-osx.py index 76d8cb4f..f3ab48dc 100644 --- a/install/get-tor-osx.py +++ b/install/get-tor-osx.py @@ -84,6 +84,9 @@ def main(): shutil.copyfile(os.path.join(dmg_tor_path, 'MacOS', 'Tor', 'tor.real'), os.path.join(dist_path, 'MacOS', 'Tor', 'tor.real')) shutil.copyfile(os.path.join(dmg_tor_path, 'MacOS', 'Tor', 'libevent-2.0.5.dylib'), os.path.join(dist_path, 'MacOS', 'Tor', 'libevent-2.0.5.dylib')) os.chmod(os.path.join(dist_path, 'MacOS', 'Tor', 'tor.real'), 0o755) + # obfs4proxy binary + shutil.copyfile(os.path.join(dmg_tor_path, 'MacOS', 'Tor', 'PluggableTransports', 'obfs4proxy'), os.path.join(dist_path, 'Resources', 'Tor', 'obfs4proxy')) + os.chmod(os.path.join(dist_path, 'Resources', 'Tor', 'obfs4proxy'), 0o755) # Unmount dmg subprocess.call(['diskutil', 'unmount', '/Volumes/Tor Browser']) diff --git a/install/get-tor-windows.py b/install/get-tor-windows.py index 83b8f2b3..4945ce68 100644 --- a/install/get-tor-windows.py +++ b/install/get-tor-windows.py @@ -24,18 +24,17 @@ In order to avoid a Windows gnupg dependency, I manually verify the signature and hard-code the sha256 hash. """ -import inspect, os, sys, hashlib, zipfile, io, shutil +import inspect, os, sys, hashlib, shutil, subprocess import urllib.request def main(): - zip_url = 'https://archive.torproject.org/tor-package-archive/torbrowser/7.0.11/tor-win32-0.3.1.9.zip' - zip_filename = 'tor-win32-0.3.1.9.zip' - expected_zip_sha256 = 'faf28efb606455842bda66ca369287a116b6d6e5ad3720ebed9337da0717f1b4' - + exe_url = 'https://archive.torproject.org/tor-package-archive/torbrowser/7.0.11/torbrowser-install-7.0.11_en-US.exe' + exe_filename = 'torbrowser-install-7.0.11_en-US.exe' + expected_exe_sha256 = 'a033eb9b9ed2ad389169b36a90946a8af8f05bd0c7bbd3e37678041331096624' # Build paths root_path = os.path.dirname(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))) working_path = os.path.join(os.path.join(root_path, 'build'), 'tor') - zip_path = os.path.join(working_path, zip_filename) + exe_path = os.path.join(working_path, exe_filename) dist_path = os.path.join(os.path.join(os.path.join(root_path, 'dist'), 'onionshare'), 'tor') # Make sure the working folder exists @@ -43,36 +42,35 @@ def main(): os.makedirs(working_path) # Make sure the zip is downloaded - if not os.path.exists(zip_path): - print("Downloading {}".format(zip_url)) - response = urllib.request.urlopen(zip_url) - zip_data = response.read() - open(zip_path, 'wb').write(zip_data) - zip_sha256 = hashlib.sha256(zip_data).hexdigest() + if not os.path.exists(exe_path): + print("Downloading {}".format(exe_url)) + response = urllib.request.urlopen(exe_url) + exe_data = response.read() + open(exe_path, 'wb').write(exe_data) + exe_sha256 = hashlib.sha256(exe_data).hexdigest() else: - zip_data = open(zip_path, 'rb').read() - zip_sha256 = hashlib.sha256(zip_data).hexdigest() + exe_data = open(exe_path, 'rb').read() + exe_sha256 = hashlib.sha256(exe_data).hexdigest() # Compare the hash - if zip_sha256 != expected_zip_sha256: + if exe_sha256 != expected_exe_sha256: print("ERROR! The sha256 doesn't match:") - print("expected: {}".format(expected_zip_sha256)) - print(" actual: {}".format(zip_sha256)) + print("expected: {}".format(expected_exe_sha256)) + print(" actual: {}".format(exe_sha256)) sys.exit(-1) - # Extract the zip - z = zipfile.ZipFile(io.BytesIO(zip_data)) - z.extractall(working_path) - - # Delete un-used files - os.remove(os.path.join(os.path.join(working_path, 'Tor'), 'tor-gencert.exe')) + # Extract the bits we need from the exe + cmd = ['7z', 'e', exe_path, 'Browser\TorBrowser\Tor', '-o%s' % os.path.join(working_path, 'Tor')] + cmd2 = ['7z', 'e', exe_path, 'Browser\TorBrowser\Data\Tor\geoip*', '-o%s' % os.path.join(working_path, 'Data')] + subprocess.Popen(cmd).wait() + subprocess.Popen(cmd2).wait() # Copy into dist if os.path.exists(dist_path): shutil.rmtree(dist_path) os.makedirs(dist_path) shutil.copytree( os.path.join(working_path, 'Tor'), os.path.join(dist_path, 'Tor') ) - shutil.copytree( os.path.join(working_path, 'Data'), os.path.join(dist_path, 'Data') ) + shutil.copytree( os.path.join(working_path, 'Data'), os.path.join(dist_path, 'Data', 'Tor') ) if __name__ == '__main__': main() diff --git a/install/onionshare.nsi b/install/onionshare.nsi index 03830909..c0a39f35 100644 --- a/install/onionshare.nsi +++ b/install/onionshare.nsi @@ -1,466 +1,470 @@ -!define APPNAME "OnionShare" -!define BINPATH "..\dist\onionshare" -!define ABOUTURL "https:\\onionshare.org\" - -# change these with each release -!define INSTALLSIZE 54112 -!define VERSIONMAJOR 1 -!define VERSIONMINOR 1 -!define VERSIONSTRING "1.1" - -RequestExecutionLevel admin - -Name "OnionShare" -InstallDir "$PROGRAMFILES\${APPNAME}" -Icon "onionshare.ico" - -!include LogicLib.nsh - -Page directory -Page instfiles - -!macro VerifyUserIsAdmin -UserInfo::GetAccountType -pop $0 -${If} $0 != "admin" ;Require admin rights on NT4+ - messageBox mb_iconstop "Administrator rights required!" - setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED - quit -${EndIf} -!macroend - -# in order to code sign uninstall.exe, we need to do some hacky stuff outlined -# here: http:\\nsis.sourceforge.net\Signing_an_Uninstaller -!ifdef INNER - !echo "Creating uninstall.exe" - OutFile "$%TEMP%\tempinstaller.exe" - SetCompress off -!else - !echo "Creating normal installer" - !system "makensis.exe /DINNER onionshare.nsi" = 0 - !system "$%TEMP%\tempinstaller.exe" = 2 - !system "signtool.exe sign /v /d $\"Uninstall OnionShare$\" /a /tr http://time.certum.pl/ /fd sha256 $%TEMP%\uninstall.exe" = 0 - - # all done, now we can build the real installer - OutFile "..\dist\onionshare-setup.exe" - SetCompressor /FINAL /SOLID lzma -!endif - -Function .onInit - !ifdef INNER - WriteUninstaller "$%TEMP%\uninstall.exe" - Quit # bail out early - !endif - - setShellVarContext all - !insertmacro VerifyUserIsAdmin -FunctionEnd - -Section "install" - SetOutPath "$INSTDIR" - File "onionshare.ico" - File "${BINPATH}\api-ms-win-core-console-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-datetime-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-debug-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-errorhandling-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-file-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-file-l1-2-0.dll" - File "${BINPATH}\api-ms-win-core-file-l2-1-0.dll" - File "${BINPATH}\api-ms-win-core-handle-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-heap-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-interlocked-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-libraryloader-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-localization-l1-2-0.dll" - File "${BINPATH}\api-ms-win-core-memory-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-namedpipe-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-processenvironment-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-processthreads-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-processthreads-l1-1-1.dll" - File "${BINPATH}\api-ms-win-core-profile-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-rtlsupport-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-string-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-synch-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-synch-l1-2-0.dll" - File "${BINPATH}\api-ms-win-core-sysinfo-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-timezone-l1-1-0.dll" - File "${BINPATH}\api-ms-win-core-util-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-conio-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-convert-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-environment-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-filesystem-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-heap-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-locale-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-math-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-multibyte-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-process-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-runtime-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-stdio-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-string-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-time-l1-1-0.dll" - File "${BINPATH}\api-ms-win-crt-utility-l1-1-0.dll" - File "${BINPATH}\base_library.zip" - File "${BINPATH}\mfc140u.dll" - File "${BINPATH}\MSVCP140.dll" - File "${BINPATH}\onionshare-gui.exe" - File "${BINPATH}\onionshare-gui.exe.manifest" - File "${BINPATH}\pyexpat.pyd" - File "${BINPATH}\PyQt5.Qt.pyd" - File "${BINPATH}\PyQt5.QtCore.pyd" - File "${BINPATH}\PyQt5.QtGui.pyd" - File "${BINPATH}\PyQt5.QtPrintSupport.pyd" - File "${BINPATH}\PyQt5.QtWidgets.pyd" - File "${BINPATH}\python3.dll" - File "${BINPATH}\python36.dll" - File "${BINPATH}\pythoncom36.dll" - File "${BINPATH}\pywintypes36.dll" - File "${BINPATH}\Qt5Core.dll" - File "${BINPATH}\Qt5Gui.dll" - File "${BINPATH}\Qt5PrintSupport.dll" - File "${BINPATH}\Qt5Svg.dll" - File "${BINPATH}\Qt5Widgets.dll" - File "${BINPATH}\select.pyd" - File "${BINPATH}\sip.pyd" - File "${BINPATH}\ucrtbase.dll" - File "${BINPATH}\unicodedata.pyd" - File "${BINPATH}\VCRUNTIME140.dll" - File "${BINPATH}\win32api.pyd" - File "${BINPATH}\win32com.shell.shell.pyd" - File "${BINPATH}\win32trace.pyd" - File "${BINPATH}\win32ui.pyd" - File "${BINPATH}\win32wnet.pyd" - File "${BINPATH}\_asyncio.pyd" - File "${BINPATH}\_bz2.pyd" - File "${BINPATH}\_ctypes.pyd" - File "${BINPATH}\_decimal.pyd" - File "${BINPATH}\_hashlib.pyd" - File "${BINPATH}\_lzma.pyd" - File "${BINPATH}\_multiprocessing.pyd" - File "${BINPATH}\_overlapped.pyd" - File "${BINPATH}\_socket.pyd" - File "${BINPATH}\_ssl.pyd" - File "${BINPATH}\_win32sysloader.pyd" - - SetOutPath "$INSTDIR\Include" - File "${BINPATH}\Include\pyconfig.h" - - SetOutPath "$INSTDIR\lib2to3" - File "${BINPATH}\lib2to3\Grammar.txt" - File "${BINPATH}\lib2to3\Grammar3.6.2.candidate.2.pickle" - File "${BINPATH}\lib2to3\Grammar3.6.2.final.0.pickle" - File "${BINPATH}\lib2to3\Grammar3.6.3.candidate.1.pickle" - File "${BINPATH}\lib2to3\Grammar3.6.3.final.0.pickle" - File "${BINPATH}\lib2to3\Grammar3.6.4.candidate.1.pickle" - File "${BINPATH}\lib2to3\Grammar3.6.4.final.0.pickle" - File "${BINPATH}\lib2to3\PatternGrammar.txt" - File "${BINPATH}\lib2to3\PatternGrammar3.6.2.candidate.2.pickle" - File "${BINPATH}\lib2to3\PatternGrammar3.6.2.final.0.pickle" - File "${BINPATH}\lib2to3\PatternGrammar3.6.3.candidate.1.pickle" - File "${BINPATH}\lib2to3\PatternGrammar3.6.3.final.0.pickle" - File "${BINPATH}\lib2to3\PatternGrammar3.6.4.candidate.1.pickle" - File "${BINPATH}\lib2to3\PatternGrammar3.6.4.final.0.pickle" - - SetOutPath "$INSTDIR\lib2to3\tests\data" - File "${BINPATH}\lib2to3\tests\data\README" - - SetOutPath "$INSTDIR\PyQt5\Qt\bin" - File "${BINPATH}\PyQt5\Qt\bin\qt.conf" - - SetOutPath "$INSTDIR\PyQt5\Qt\plugins\iconengines" - File "${BINPATH}\PyQt5\Qt\plugins\iconengines\qsvgicon.dll" - - SetOutPath "$INSTDIR\PyQt5\Qt\plugins\imageformats" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qgif.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qicns.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qico.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qjpeg.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qsvg.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qtga.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qtiff.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qwbmp.dll" - File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qwebp.dll" - - SetOutPath "$INSTDIR\PyQt5\Qt\plugins\platforms" - File "${BINPATH}\PyQt5\Qt\plugins\platforms\qminimal.dll" - File "${BINPATH}\PyQt5\Qt\plugins\platforms\qoffscreen.dll" - File "${BINPATH}\PyQt5\Qt\plugins\platforms\qwindows.dll" - - SetOutPath "$INSTDIR\PyQt5\Qt\plugins\printsupport" - File "${BINPATH}\PyQt5\Qt\plugins\printsupport\windowsprintersupport.dll" - - SetOutPath "$INSTDIR\share" - File "${BINPATH}\share\license.txt" - File "${BINPATH}\share\torrc_template" - File "${BINPATH}\share\torrc_template-windows" - File "${BINPATH}\share\version.txt" - File "${BINPATH}\share\wordlist.txt" - - SetOutPath "$INSTDIR\share\html" - File "${BINPATH}\share\html\404.html" - File "${BINPATH}\share\html\denied.html" - File "${BINPATH}\share\html\index.html" - - SetOutPath "$INSTDIR\share\images" - File "${BINPATH}\share\images\drop_files.png" - File "${BINPATH}\share\images\logo.png" - File "${BINPATH}\share\images\logo_grayscale.png" - File "${BINPATH}\share\images\server_started.png" - File "${BINPATH}\share\images\server_stopped.png" - File "${BINPATH}\share\images\server_working.png" - File "${BINPATH}\share\images\settings.png" - File "${BINPATH}\share\images\settings_inactive.png" - - SetOutPath "$INSTDIR\share\locale" - File "${BINPATH}\share\locale\cs.json" - File "${BINPATH}\share\locale\de.json" - File "${BINPATH}\share\locale\en.json" - File "${BINPATH}\share\locale\eo.json" - File "${BINPATH}\share\locale\es.json" - File "${BINPATH}\share\locale\fi.json" - File "${BINPATH}\share\locale\fr.json" - File "${BINPATH}\share\locale\it.json" - File "${BINPATH}\share\locale\nl.json" - File "${BINPATH}\share\locale\no.json" - File "${BINPATH}\share\locale\pt.json" - File "${BINPATH}\share\locale\ru.json" - File "${BINPATH}\share\locale\tr.json" - - SetOutPath "$INSTDIR\tor\Data\Tor" - File "${BINPATH}\tor\Data\Tor\geoip" - File "${BINPATH}\tor\Data\Tor\geoip6" - - SetOutPath "$INSTDIR\tor\Tor" - File "${BINPATH}\tor\Tor\libeay32.dll" - File "${BINPATH}\tor\Tor\libevent-2-0-5.dll" - File "${BINPATH}\tor\Tor\libevent_core-2-0-5.dll" - File "${BINPATH}\tor\Tor\libevent_extra-2-0-5.dll" - File "${BINPATH}\tor\Tor\libgcc_s_sjlj-1.dll" - File "${BINPATH}\tor\Tor\libssp-0.dll" - File "${BINPATH}\tor\Tor\ssleay32.dll" - File "${BINPATH}\tor\Tor\tor.exe" - File "${BINPATH}\tor\Tor\zlib1.dll" - - # uninstaller - !ifndef INNER - SetOutPath $INSTDIR - File $%TEMP%\uninstall.exe - !endif - - # start menu - CreateShortCut "$SMPROGRAMS\${APPNAME}.lnk" "$INSTDIR\onionshare-gui.exe" "" "$INSTDIR\onionshare.ico" - - # registry information for add\remove programs - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" \S" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayIcon" "$\"$INSTDIR\onionshare.ico$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" - WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayVersion" ${VERSIONSTRING} - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMajor" ${VERSIONMAJOR} - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMinor" ${VERSIONMINOR} - # there is no option for modifying or repairing the install - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoModify" 1 - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoRepair" 1 - # set the INSTALLSIZE constant (!defined at the top of this script) so Add\Remove Programs can accurately report the size - WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "EstimatedSize" ${INSTALLSIZE} -SectionEnd - -# uninstaller -Function un.onInit - SetShellVarContext all - - #Verify the uninstaller - last chance to back out - MessageBox MB_OKCANCEL "Uninstall ${APPNAME}?" IDOK next - Abort - next: - !insertmacro VerifyUserIsAdmin -FunctionEnd - -!ifdef INNER - Section "uninstall" - Delete "$SMPROGRAMS\${APPNAME}.lnk" - - # remove files - Delete "$INSTDIR\api-ms-win-core-console-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-datetime-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-debug-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-errorhandling-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-file-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-file-l1-2-0.dll" - Delete "$INSTDIR\api-ms-win-core-file-l2-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-handle-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-heap-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-interlocked-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-libraryloader-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-localization-l1-2-0.dll" - Delete "$INSTDIR\api-ms-win-core-memory-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-namedpipe-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-processenvironment-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-processthreads-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-processthreads-l1-1-1.dll" - Delete "$INSTDIR\api-ms-win-core-profile-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-rtlsupport-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-string-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-synch-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-synch-l1-2-0.dll" - Delete "$INSTDIR\api-ms-win-core-sysinfo-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-timezone-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-core-util-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-conio-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-convert-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-environment-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-filesystem-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-heap-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-locale-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-math-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-multibyte-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-process-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-runtime-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-stdio-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-string-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-time-l1-1-0.dll" - Delete "$INSTDIR\api-ms-win-crt-utility-l1-1-0.dll" - Delete "$INSTDIR\base_library.zip" - Delete "$INSTDIR\Include\pyconfig.h" - Delete "$INSTDIR\lib2to3\Grammar.txt" - Delete "$INSTDIR\lib2to3\Grammar3.6.2.candidate.2.pickle" - Delete "$INSTDIR\lib2to3\Grammar3.6.2.final.0.pickle" - Delete "$INSTDIR\lib2to3\Grammar3.6.3.candidate.1.pickle" - Delete "$INSTDIR\lib2to3\Grammar3.6.3.final.0.pickle" - Delete "$INSTDIR\lib2to3\Grammar3.6.4.candidate.1.pickle" - Delete "$INSTDIR\lib2to3\Grammar3.6.4.final.0.pickle" - Delete "$INSTDIR\lib2to3\PatternGrammar.txt" - Delete "$INSTDIR\lib2to3\PatternGrammar3.6.2.candidate.2.pickle" - Delete "$INSTDIR\lib2to3\PatternGrammar3.6.2.final.0.pickle" - Delete "$INSTDIR\lib2to3\PatternGrammar3.6.3.candidate.1.pickle" - Delete "$INSTDIR\lib2to3\PatternGrammar3.6.3.final.0.pickle" - Delete "$INSTDIR\lib2to3\PatternGrammar3.6.4.candidate.1.pickle" - Delete "$INSTDIR\lib2to3\PatternGrammar3.6.4.final.0.pickle" - Delete "$INSTDIR\lib2to3\tests" - Delete "$INSTDIR\lib2to3\tests\data" - Delete "$INSTDIR\lib2to3\tests\data\README" - Delete "$INSTDIR\mfc140u.dll" - Delete "$INSTDIR\MSVCP140.dll" - Delete "$INSTDIR\onionshare-gui.exe" - Delete "$INSTDIR\onionshare-gui.exe.manifest" - Delete "$INSTDIR\pyexpat.pyd" - Delete "$INSTDIR\PyQt5\Qt\bin\qt.conf" - Delete "$INSTDIR\PyQt5\Qt\plugins\iconengines\qsvgicon.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qgif.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qicns.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qico.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qjpeg.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qsvg.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qtga.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qtiff.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qwbmp.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qwebp.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\platforms\qminimal.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\platforms\qoffscreen.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\platforms\qwindows.dll" - Delete "$INSTDIR\PyQt5\Qt\plugins\printsupport\windowsprintersupport.dll" - Delete "$INSTDIR\PyQt5.Qt.pyd" - Delete "$INSTDIR\PyQt5.QtCore.pyd" - Delete "$INSTDIR\PyQt5.QtGui.pyd" - Delete "$INSTDIR\PyQt5.QtPrintSupport.pyd" - Delete "$INSTDIR\PyQt5.QtWidgets.pyd" - Delete "$INSTDIR\python3.dll" - Delete "$INSTDIR\python36.dll" - Delete "$INSTDIR\pythoncom36.dll" - Delete "$INSTDIR\pywintypes36.dll" - Delete "$INSTDIR\Qt5Core.dll" - Delete "$INSTDIR\Qt5Gui.dll" - Delete "$INSTDIR\Qt5PrintSupport.dll" - Delete "$INSTDIR\Qt5Svg.dll" - Delete "$INSTDIR\Qt5Widgets.dll" - Delete "$INSTDIR\select.pyd" - Delete "$INSTDIR\share\html\404.html" - Delete "$INSTDIR\share\html\denied.html" - Delete "$INSTDIR\share\html\index.html" - Delete "$INSTDIR\share\images\drop_files.png" - Delete "$INSTDIR\share\images\logo.png" - Delete "$INSTDIR\share\images\logo_grayscale.png" - Delete "$INSTDIR\share\images\server_started.png" - Delete "$INSTDIR\share\images\server_stopped.png" - Delete "$INSTDIR\share\images\server_working.png" - Delete "$INSTDIR\share\images\settings.png" - Delete "$INSTDIR\share\images\settings_inactive.png" - Delete "$INSTDIR\share\license.txt" - Delete "$INSTDIR\share\locale\cs.json" - Delete "$INSTDIR\share\locale\de.json" - Delete "$INSTDIR\share\locale\en.json" - Delete "$INSTDIR\share\locale\eo.json" - Delete "$INSTDIR\share\locale\es.json" - Delete "$INSTDIR\share\locale\fi.json" - Delete "$INSTDIR\share\locale\fr.json" - Delete "$INSTDIR\share\locale\it.json" - Delete "$INSTDIR\share\locale\nl.json" - Delete "$INSTDIR\share\locale\no.json" - Delete "$INSTDIR\share\locale\pt.json" - Delete "$INSTDIR\share\locale\ru.json" - Delete "$INSTDIR\share\locale\tr.json" - Delete "$INSTDIR\share\torrc_template" - Delete "$INSTDIR\share\torrc_template-windows" - Delete "$INSTDIR\share\version.txt" - Delete "$INSTDIR\share\wordlist.txt" - Delete "$INSTDIR\sip.pyd" - Delete "$INSTDIR\tor\Data\Tor\geoip" - Delete "$INSTDIR\tor\Data\Tor\geoip6" - Delete "$INSTDIR\tor\Tor\libeay32.dll" - Delete "$INSTDIR\tor\Tor\libevent-2-0-5.dll" - Delete "$INSTDIR\tor\Tor\libevent_core-2-0-5.dll" - Delete "$INSTDIR\tor\Tor\libevent_extra-2-0-5.dll" - Delete "$INSTDIR\tor\Tor\libgcc_s_sjlj-1.dll" - Delete "$INSTDIR\tor\Tor\libssp-0.dll" - Delete "$INSTDIR\tor\Tor\ssleay32.dll" - Delete "$INSTDIR\tor\Tor\tor.exe" - Delete "$INSTDIR\tor\Tor\zlib1.dll" - Delete "$INSTDIR\ucrtbase.dll" - Delete "$INSTDIR\unicodedata.pyd" - Delete "$INSTDIR\VCRUNTIME140.dll" - Delete "$INSTDIR\win32api.pyd" - Delete "$INSTDIR\win32com.shell.shell.pyd" - Delete "$INSTDIR\win32trace.pyd" - Delete "$INSTDIR\win32ui.pyd" - Delete "$INSTDIR\win32wnet.pyd" - Delete "$INSTDIR\_asyncio.pyd" - Delete "$INSTDIR\_bz2.pyd" - Delete "$INSTDIR\_ctypes.pyd" - Delete "$INSTDIR\_decimal.pyd" - Delete "$INSTDIR\_hashlib.pyd" - Delete "$INSTDIR\_lzma.pyd" - Delete "$INSTDIR\_multiprocessing.pyd" - Delete "$INSTDIR\_overlapped.pyd" - Delete "$INSTDIR\_socket.pyd" - Delete "$INSTDIR\_ssl.pyd" - Delete "$INSTDIR\_win32sysloader.pyd" - - Delete "$INSTDIR\onionshare.ico" - Delete "$INSTDIR\uninstall.exe" - - rmDir "$INSTDIR\Include" - rmDir "$INSTDIR\lib2to3\tests\data" - rmDir "$INSTDIR\lib2to3\tests" - rmDir "$INSTDIR\lib2to3" - rmDir "$INSTDIR\PyQt5\Qt\bin" - rmDir "$INSTDIR\PyQt5\Qt\plugins\iconengines" - rmDir "$INSTDIR\PyQt5\Qt\plugins\imageformats" - rmDir "$INSTDIR\PyQt5\Qt\plugins\platforms" - rmDir "$INSTDIR\PyQt5\Qt\plugins\printsupport" - rmDir "$INSTDIR\PyQt5\Qt\plugins" - rmDir "$INSTDIR\PyQt5\Qt" - rmDir "$INSTDIR\PyQt5" - rmDir "$INSTDIR\share\html" - rmDir "$INSTDIR\share\images" - rmDir "$INSTDIR\share\locale" - rmDir "$INSTDIR\share" - rmDir "$INSTDIR\tor\Data\Tor" - rmDir "$INSTDIR\tor\Data" - rmDir "$INSTDIR\tor\Tor" - rmDir "$INSTDIR\tor" - rmDir "$INSTDIR" - - # remove uninstaller information from the registry - DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" - SectionEnd -!endif +!define APPNAME "OnionShare" +!define BINPATH "..\dist\onionshare" +!define ABOUTURL "https:\\onionshare.org\" + +# change these with each release +!define INSTALLSIZE 54112 +!define VERSIONMAJOR 1 +!define VERSIONMINOR 1 +!define VERSIONSTRING "1.1" + +RequestExecutionLevel admin + +Name "OnionShare" +InstallDir "$PROGRAMFILES\${APPNAME}" +Icon "onionshare.ico" + +!include LogicLib.nsh + +Page directory +Page instfiles + +!macro VerifyUserIsAdmin +UserInfo::GetAccountType +pop $0 +${If} $0 != "admin" ;Require admin rights on NT4+ + messageBox mb_iconstop "Administrator rights required!" + setErrorLevel 740 ;ERROR_ELEVATION_REQUIRED + quit +${EndIf} +!macroend + +# in order to code sign uninstall.exe, we need to do some hacky stuff outlined +# here: http:\\nsis.sourceforge.net\Signing_an_Uninstaller +!ifdef INNER + !echo "Creating uninstall.exe" + OutFile "$%TEMP%\tempinstaller.exe" + SetCompress off +!else + !echo "Creating normal installer" + !system "makensis.exe /DINNER onionshare.nsi" = 0 + !system "$%TEMP%\tempinstaller.exe" = 2 + !system "signtool.exe sign /v /d $\"Uninstall OnionShare$\" /a /tr http://time.certum.pl/ /fd sha256 $%TEMP%\uninstall.exe" = 0 + + # all done, now we can build the real installer + OutFile "..\dist\onionshare-setup.exe" + SetCompressor /FINAL /SOLID lzma +!endif + +Function .onInit + !ifdef INNER + WriteUninstaller "$%TEMP%\uninstall.exe" + Quit # bail out early + !endif + + setShellVarContext all + !insertmacro VerifyUserIsAdmin +FunctionEnd + +Section "install" + SetOutPath "$INSTDIR" + File "onionshare.ico" + File "${BINPATH}\api-ms-win-core-console-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-datetime-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-debug-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-errorhandling-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-file-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-file-l1-2-0.dll" + File "${BINPATH}\api-ms-win-core-file-l2-1-0.dll" + File "${BINPATH}\api-ms-win-core-handle-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-heap-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-interlocked-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-libraryloader-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-localization-l1-2-0.dll" + File "${BINPATH}\api-ms-win-core-memory-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-namedpipe-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-processenvironment-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-processthreads-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-processthreads-l1-1-1.dll" + File "${BINPATH}\api-ms-win-core-profile-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-rtlsupport-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-string-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-synch-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-synch-l1-2-0.dll" + File "${BINPATH}\api-ms-win-core-sysinfo-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-timezone-l1-1-0.dll" + File "${BINPATH}\api-ms-win-core-util-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-conio-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-convert-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-environment-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-filesystem-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-heap-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-locale-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-math-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-multibyte-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-process-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-runtime-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-stdio-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-string-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-time-l1-1-0.dll" + File "${BINPATH}\api-ms-win-crt-utility-l1-1-0.dll" + File "${BINPATH}\base_library.zip" + File "${BINPATH}\mfc140u.dll" + File "${BINPATH}\MSVCP140.dll" + File "${BINPATH}\onionshare-gui.exe" + File "${BINPATH}\onionshare-gui.exe.manifest" + File "${BINPATH}\pyexpat.pyd" + File "${BINPATH}\PyQt5.Qt.pyd" + File "${BINPATH}\PyQt5.QtCore.pyd" + File "${BINPATH}\PyQt5.QtGui.pyd" + File "${BINPATH}\PyQt5.QtPrintSupport.pyd" + File "${BINPATH}\PyQt5.QtWidgets.pyd" + File "${BINPATH}\python3.dll" + File "${BINPATH}\python36.dll" + File "${BINPATH}\pythoncom36.dll" + File "${BINPATH}\pywintypes36.dll" + File "${BINPATH}\Qt5Core.dll" + File "${BINPATH}\Qt5Gui.dll" + File "${BINPATH}\Qt5PrintSupport.dll" + File "${BINPATH}\Qt5Svg.dll" + File "${BINPATH}\Qt5Widgets.dll" + File "${BINPATH}\select.pyd" + File "${BINPATH}\sip.pyd" + File "${BINPATH}\ucrtbase.dll" + File "${BINPATH}\unicodedata.pyd" + File "${BINPATH}\VCRUNTIME140.dll" + File "${BINPATH}\win32api.pyd" + File "${BINPATH}\win32com.shell.shell.pyd" + File "${BINPATH}\win32trace.pyd" + File "${BINPATH}\win32ui.pyd" + File "${BINPATH}\win32wnet.pyd" + File "${BINPATH}\_asyncio.pyd" + File "${BINPATH}\_bz2.pyd" + File "${BINPATH}\_ctypes.pyd" + File "${BINPATH}\_decimal.pyd" + File "${BINPATH}\_hashlib.pyd" + File "${BINPATH}\_lzma.pyd" + File "${BINPATH}\_multiprocessing.pyd" + File "${BINPATH}\_overlapped.pyd" + File "${BINPATH}\_socket.pyd" + File "${BINPATH}\_ssl.pyd" + File "${BINPATH}\_win32sysloader.pyd" + + SetOutPath "$INSTDIR\Include" + File "${BINPATH}\Include\pyconfig.h" + + SetOutPath "$INSTDIR\lib2to3" + File "${BINPATH}\lib2to3\Grammar.txt" + File "${BINPATH}\lib2to3\Grammar3.6.2.candidate.2.pickle" + File "${BINPATH}\lib2to3\Grammar3.6.2.final.0.pickle" + File "${BINPATH}\lib2to3\Grammar3.6.3.candidate.1.pickle" + File "${BINPATH}\lib2to3\Grammar3.6.3.final.0.pickle" + File "${BINPATH}\lib2to3\Grammar3.6.4.candidate.1.pickle" + File "${BINPATH}\lib2to3\Grammar3.6.4.final.0.pickle" + File "${BINPATH}\lib2to3\PatternGrammar.txt" + File "${BINPATH}\lib2to3\PatternGrammar3.6.2.candidate.2.pickle" + File "${BINPATH}\lib2to3\PatternGrammar3.6.2.final.0.pickle" + File "${BINPATH}\lib2to3\PatternGrammar3.6.3.candidate.1.pickle" + File "${BINPATH}\lib2to3\PatternGrammar3.6.3.final.0.pickle" + File "${BINPATH}\lib2to3\PatternGrammar3.6.4.candidate.1.pickle" + File "${BINPATH}\lib2to3\PatternGrammar3.6.4.final.0.pickle" + + SetOutPath "$INSTDIR\lib2to3\tests\data" + File "${BINPATH}\lib2to3\tests\data\README" + + SetOutPath "$INSTDIR\PyQt5\Qt\bin" + File "${BINPATH}\PyQt5\Qt\bin\qt.conf" + + SetOutPath "$INSTDIR\PyQt5\Qt\plugins\iconengines" + File "${BINPATH}\PyQt5\Qt\plugins\iconengines\qsvgicon.dll" + + SetOutPath "$INSTDIR\PyQt5\Qt\plugins\imageformats" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qgif.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qicns.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qico.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qjpeg.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qsvg.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qtga.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qtiff.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qwbmp.dll" + File "${BINPATH}\PyQt5\Qt\plugins\imageformats\qwebp.dll" + + SetOutPath "$INSTDIR\PyQt5\Qt\plugins\platforms" + File "${BINPATH}\PyQt5\Qt\plugins\platforms\qminimal.dll" + File "${BINPATH}\PyQt5\Qt\plugins\platforms\qoffscreen.dll" + File "${BINPATH}\PyQt5\Qt\plugins\platforms\qwindows.dll" + + SetOutPath "$INSTDIR\PyQt5\Qt\plugins\printsupport" + File "${BINPATH}\PyQt5\Qt\plugins\printsupport\windowsprintersupport.dll" + + SetOutPath "$INSTDIR\share" + File "${BINPATH}\share\license.txt" + File "${BINPATH}\share\torrc_template" + File "${BINPATH}\share\torrc_template-windows" + File "${BINPATH}\share\torrc_template-obfs4" + File "${BINPATH}\share\version.txt" + File "${BINPATH}\share\wordlist.txt" + + SetOutPath "$INSTDIR\share\html" + File "${BINPATH}\share\html\404.html" + File "${BINPATH}\share\html\denied.html" + File "${BINPATH}\share\html\index.html" + + SetOutPath "$INSTDIR\share\images" + File "${BINPATH}\share\images\drop_files.png" + File "${BINPATH}\share\images\logo.png" + File "${BINPATH}\share\images\logo_grayscale.png" + File "${BINPATH}\share\images\server_started.png" + File "${BINPATH}\share\images\server_stopped.png" + File "${BINPATH}\share\images\server_working.png" + File "${BINPATH}\share\images\settings.png" + File "${BINPATH}\share\images\settings_inactive.png" + + SetOutPath "$INSTDIR\share\locale" + File "${BINPATH}\share\locale\cs.json" + File "${BINPATH}\share\locale\de.json" + File "${BINPATH}\share\locale\en.json" + File "${BINPATH}\share\locale\eo.json" + File "${BINPATH}\share\locale\es.json" + File "${BINPATH}\share\locale\fi.json" + File "${BINPATH}\share\locale\fr.json" + File "${BINPATH}\share\locale\it.json" + File "${BINPATH}\share\locale\nl.json" + File "${BINPATH}\share\locale\no.json" + File "${BINPATH}\share\locale\pt.json" + File "${BINPATH}\share\locale\ru.json" + File "${BINPATH}\share\locale\tr.json" + + SetOutPath "$INSTDIR\tor\Data\Tor" + File "${BINPATH}\tor\Data\Tor\geoip" + File "${BINPATH}\tor\Data\Tor\geoip6" + + SetOutPath "$INSTDIR\tor\Tor" + File "${BINPATH}\tor\Tor\libeay32.dll" + File "${BINPATH}\tor\Tor\libevent-2-0-5.dll" + File "${BINPATH}\tor\Tor\libevent_core-2-0-5.dll" + File "${BINPATH}\tor\Tor\libevent_extra-2-0-5.dll" + File "${BINPATH}\tor\Tor\libgcc_s_sjlj-1.dll" + File "${BINPATH}\tor\Tor\libssp-0.dll" + File "${BINPATH}\tor\Tor\obfs4proxy.exe" + File "${BINPATH}\tor\Tor\ssleay32.dll" + File "${BINPATH}\tor\Tor\tor.exe" + File "${BINPATH}\tor\Tor\zlib1.dll" + + # uninstaller + !ifndef INNER + SetOutPath $INSTDIR + File $%TEMP%\uninstall.exe + !endif + + # start menu + CreateShortCut "$SMPROGRAMS\${APPNAME}.lnk" "$INSTDIR\onionshare-gui.exe" "" "$INSTDIR\onionshare.ico" + + # registry information for add\remove programs + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayName" "${APPNAME}" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" \S" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "InstallLocation" "$\"$INSTDIR$\"" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayIcon" "$\"$INSTDIR\onionshare.ico$\"" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "URLInfoAbout" "$\"${ABOUTURL}$\"" + WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "DisplayVersion" ${VERSIONSTRING} + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMajor" ${VERSIONMAJOR} + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "VersionMinor" ${VERSIONMINOR} + # there is no option for modifying or repairing the install + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoModify" 1 + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "NoRepair" 1 + # set the INSTALLSIZE constant (!defined at the top of this script) so Add\Remove Programs can accurately report the size + WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" "EstimatedSize" ${INSTALLSIZE} +SectionEnd + +# uninstaller +Function un.onInit + SetShellVarContext all + + #Verify the uninstaller - last chance to back out + MessageBox MB_OKCANCEL "Uninstall ${APPNAME}?" IDOK next + Abort + next: + !insertmacro VerifyUserIsAdmin +FunctionEnd + +!ifdef INNER + Section "uninstall" + Delete "$SMPROGRAMS\${APPNAME}.lnk" + + # remove files + Delete "$INSTDIR\api-ms-win-core-console-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-datetime-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-debug-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-errorhandling-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-file-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-file-l1-2-0.dll" + Delete "$INSTDIR\api-ms-win-core-file-l2-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-handle-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-heap-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-interlocked-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-libraryloader-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-localization-l1-2-0.dll" + Delete "$INSTDIR\api-ms-win-core-memory-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-namedpipe-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-processenvironment-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-processthreads-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-processthreads-l1-1-1.dll" + Delete "$INSTDIR\api-ms-win-core-profile-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-rtlsupport-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-string-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-synch-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-synch-l1-2-0.dll" + Delete "$INSTDIR\api-ms-win-core-sysinfo-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-timezone-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-core-util-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-conio-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-convert-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-environment-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-filesystem-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-heap-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-locale-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-math-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-multibyte-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-process-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-runtime-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-stdio-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-string-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-time-l1-1-0.dll" + Delete "$INSTDIR\api-ms-win-crt-utility-l1-1-0.dll" + Delete "$INSTDIR\base_library.zip" + Delete "$INSTDIR\Include\pyconfig.h" + Delete "$INSTDIR\lib2to3\Grammar.txt" + Delete "$INSTDIR\lib2to3\Grammar3.6.2.candidate.2.pickle" + Delete "$INSTDIR\lib2to3\Grammar3.6.2.final.0.pickle" + Delete "$INSTDIR\lib2to3\Grammar3.6.3.candidate.1.pickle" + Delete "$INSTDIR\lib2to3\Grammar3.6.3.final.0.pickle" + Delete "$INSTDIR\lib2to3\Grammar3.6.4.candidate.1.pickle" + Delete "$INSTDIR\lib2to3\Grammar3.6.4.final.0.pickle" + Delete "$INSTDIR\lib2to3\PatternGrammar.txt" + Delete "$INSTDIR\lib2to3\PatternGrammar3.6.2.candidate.2.pickle" + Delete "$INSTDIR\lib2to3\PatternGrammar3.6.2.final.0.pickle" + Delete "$INSTDIR\lib2to3\PatternGrammar3.6.3.candidate.1.pickle" + Delete "$INSTDIR\lib2to3\PatternGrammar3.6.3.final.0.pickle" + Delete "$INSTDIR\lib2to3\PatternGrammar3.6.4.candidate.1.pickle" + Delete "$INSTDIR\lib2to3\PatternGrammar3.6.4.final.0.pickle" + Delete "$INSTDIR\lib2to3\tests" + Delete "$INSTDIR\lib2to3\tests\data" + Delete "$INSTDIR\lib2to3\tests\data\README" + Delete "$INSTDIR\mfc140u.dll" + Delete "$INSTDIR\MSVCP140.dll" + Delete "$INSTDIR\onionshare-gui.exe" + Delete "$INSTDIR\onionshare-gui.exe.manifest" + Delete "$INSTDIR\pyexpat.pyd" + Delete "$INSTDIR\PyQt5\Qt\bin\qt.conf" + Delete "$INSTDIR\PyQt5\Qt\plugins\iconengines\qsvgicon.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qgif.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qicns.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qico.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qjpeg.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qsvg.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qtga.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qtiff.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qwbmp.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\imageformats\qwebp.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\platforms\qminimal.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\platforms\qoffscreen.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\platforms\qwindows.dll" + Delete "$INSTDIR\PyQt5\Qt\plugins\printsupport\windowsprintersupport.dll" + Delete "$INSTDIR\PyQt5.Qt.pyd" + Delete "$INSTDIR\PyQt5.QtCore.pyd" + Delete "$INSTDIR\PyQt5.QtGui.pyd" + Delete "$INSTDIR\PyQt5.QtPrintSupport.pyd" + Delete "$INSTDIR\PyQt5.QtWidgets.pyd" + Delete "$INSTDIR\python3.dll" + Delete "$INSTDIR\python36.dll" + Delete "$INSTDIR\pythoncom36.dll" + Delete "$INSTDIR\pywintypes36.dll" + Delete "$INSTDIR\Qt5Core.dll" + Delete "$INSTDIR\Qt5Gui.dll" + Delete "$INSTDIR\Qt5PrintSupport.dll" + Delete "$INSTDIR\Qt5Svg.dll" + Delete "$INSTDIR\Qt5Widgets.dll" + Delete "$INSTDIR\select.pyd" + Delete "$INSTDIR\share\html\404.html" + Delete "$INSTDIR\share\html\denied.html" + Delete "$INSTDIR\share\html\index.html" + Delete "$INSTDIR\share\images\drop_files.png" + Delete "$INSTDIR\share\images\logo.png" + Delete "$INSTDIR\share\images\logo_grayscale.png" + Delete "$INSTDIR\share\images\server_started.png" + Delete "$INSTDIR\share\images\server_stopped.png" + Delete "$INSTDIR\share\images\server_working.png" + Delete "$INSTDIR\share\images\settings.png" + Delete "$INSTDIR\share\images\settings_inactive.png" + Delete "$INSTDIR\share\license.txt" + Delete "$INSTDIR\share\locale\cs.json" + Delete "$INSTDIR\share\locale\de.json" + Delete "$INSTDIR\share\locale\en.json" + Delete "$INSTDIR\share\locale\eo.json" + Delete "$INSTDIR\share\locale\es.json" + Delete "$INSTDIR\share\locale\fi.json" + Delete "$INSTDIR\share\locale\fr.json" + Delete "$INSTDIR\share\locale\it.json" + Delete "$INSTDIR\share\locale\nl.json" + Delete "$INSTDIR\share\locale\no.json" + Delete "$INSTDIR\share\locale\pt.json" + Delete "$INSTDIR\share\locale\ru.json" + Delete "$INSTDIR\share\locale\tr.json" + Delete "$INSTDIR\share\torrc_template" + Delete "$INSTDIR\share\torrc_template-windows" + Delete "$INSTDIR\share\torrc_template-obfs4" + Delete "$INSTDIR\share\version.txt" + Delete "$INSTDIR\share\wordlist.txt" + Delete "$INSTDIR\sip.pyd" + Delete "$INSTDIR\tor\Data\Tor\geoip" + Delete "$INSTDIR\tor\Data\Tor\geoip6" + Delete "$INSTDIR\tor\Tor\libeay32.dll" + Delete "$INSTDIR\tor\Tor\libevent-2-0-5.dll" + Delete "$INSTDIR\tor\Tor\libevent_core-2-0-5.dll" + Delete "$INSTDIR\tor\Tor\libevent_extra-2-0-5.dll" + Delete "$INSTDIR\tor\Tor\libgcc_s_sjlj-1.dll" + Delete "$INSTDIR\tor\Tor\libssp-0.dll" + Delete "$INSTDIR\tor\Tor\obfs4proxy.exe" + Delete "$INSTDIR\tor\Tor\ssleay32.dll" + Delete "$INSTDIR\tor\Tor\tor.exe" + Delete "$INSTDIR\tor\Tor\zlib1.dll" + Delete "$INSTDIR\ucrtbase.dll" + Delete "$INSTDIR\unicodedata.pyd" + Delete "$INSTDIR\VCRUNTIME140.dll" + Delete "$INSTDIR\win32api.pyd" + Delete "$INSTDIR\win32com.shell.shell.pyd" + Delete "$INSTDIR\win32trace.pyd" + Delete "$INSTDIR\win32ui.pyd" + Delete "$INSTDIR\win32wnet.pyd" + Delete "$INSTDIR\_asyncio.pyd" + Delete "$INSTDIR\_bz2.pyd" + Delete "$INSTDIR\_ctypes.pyd" + Delete "$INSTDIR\_decimal.pyd" + Delete "$INSTDIR\_hashlib.pyd" + Delete "$INSTDIR\_lzma.pyd" + Delete "$INSTDIR\_multiprocessing.pyd" + Delete "$INSTDIR\_overlapped.pyd" + Delete "$INSTDIR\_socket.pyd" + Delete "$INSTDIR\_ssl.pyd" + Delete "$INSTDIR\_win32sysloader.pyd" + + Delete "$INSTDIR\onionshare.ico" + Delete "$INSTDIR\uninstall.exe" + + rmDir "$INSTDIR\Include" + rmDir "$INSTDIR\lib2to3\tests\data" + rmDir "$INSTDIR\lib2to3\tests" + rmDir "$INSTDIR\lib2to3" + rmDir "$INSTDIR\PyQt5\Qt\bin" + rmDir "$INSTDIR\PyQt5\Qt\plugins\iconengines" + rmDir "$INSTDIR\PyQt5\Qt\plugins\imageformats" + rmDir "$INSTDIR\PyQt5\Qt\plugins\platforms" + rmDir "$INSTDIR\PyQt5\Qt\plugins\printsupport" + rmDir "$INSTDIR\PyQt5\Qt\plugins" + rmDir "$INSTDIR\PyQt5\Qt" + rmDir "$INSTDIR\PyQt5" + rmDir "$INSTDIR\share\html" + rmDir "$INSTDIR\share\images" + rmDir "$INSTDIR\share\locale" + rmDir "$INSTDIR\share" + rmDir "$INSTDIR\tor\Data\Tor" + rmDir "$INSTDIR\tor\Data" + rmDir "$INSTDIR\tor\Tor" + rmDir "$INSTDIR\tor" + rmDir "$INSTDIR" + + # remove uninstaller information from the registry + DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APPNAME}" + SectionEnd +!endif diff --git a/install/pyinstaller.spec b/install/pyinstaller.spec index 9ef4c0df..a38aaf6e 100644 --- a/install/pyinstaller.spec +++ b/install/pyinstaller.spec @@ -14,6 +14,7 @@ a = Analysis( ('../share/version.txt', 'share'), ('../share/wordlist.txt', 'share'), ('../share/torrc_template', 'share'), + ('../share/torrc_template-obfs4', 'share'), ('../share/torrc_template-windows', 'share'), ('../share/images/*', 'share/images'), ('../share/locale/*', 'share/locale'), diff --git a/onionshare/common.py b/onionshare/common.py index 562c71f2..25b901ee 100644 --- a/onionshare/common.py +++ b/onionshare/common.py @@ -94,9 +94,11 @@ def get_tor_paths(): tor_path = '/usr/bin/tor' tor_geo_ip_file_path = '/usr/share/tor/geoip' tor_geo_ipv6_file_path = '/usr/share/tor/geoip6' + obfs4proxy_file_path = '/usr/bin/obfs4proxy' elif p == 'Windows': base_path = os.path.join(os.path.dirname(os.path.dirname(get_resource_path(''))), 'tor') - tor_path = os.path.join(os.path.join(base_path, 'Tor'), "tor.exe") + tor_path = os.path.join(os.path.join(base_path, 'Tor'), 'tor.exe') + obfs4proxy_file_path = os.path.join(os.path.join(base_path, 'Tor'), 'obfs4proxy.exe') tor_geo_ip_file_path = os.path.join(os.path.join(os.path.join(base_path, 'Data'), 'Tor'), 'geoip') tor_geo_ipv6_file_path = os.path.join(os.path.join(os.path.join(base_path, 'Data'), 'Tor'), 'geoip6') elif p == 'Darwin': @@ -104,12 +106,14 @@ def get_tor_paths(): tor_path = os.path.join(base_path, 'Resources', 'Tor', 'tor') tor_geo_ip_file_path = os.path.join(base_path, 'Resources', 'Tor', 'geoip') tor_geo_ipv6_file_path = os.path.join(base_path, 'Resources', 'Tor', 'geoip6') + obfs4proxy_file_path = os.path.join(base_path, 'Resources', 'Tor', 'obfs4proxy') elif p == 'OpenBSD' or p == 'FreeBSD': tor_path = '/usr/local/bin/tor' tor_geo_ip_file_path = '/usr/local/share/tor/geoip' tor_geo_ipv6_file_path = '/usr/local/share/tor/geoip6' + obfs4proxy_file_path = '/usr/local/bin/obfs4proxy' - return (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path) + return (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path, obfs4proxy_file_path) def get_version(): diff --git a/onionshare/onion.py b/onionshare/onion.py index db1dfeaf..013a9177 100644 --- a/onionshare/onion.py +++ b/onionshare/onion.py @@ -140,7 +140,7 @@ class Onion(object): self.bundle_tor_supported = True # Set the path of the tor binary, for bundled tor - (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path) = common.get_tor_paths() + (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths() # The tor process self.tor_proc = None @@ -205,6 +205,16 @@ class Onion(object): with open(self.tor_torrc, 'w') as f: f.write(torrc_template) + # Bridge support + if self.settings.get('tor_bridges_use_obfs4'): + f.write('ClientTransportPlugin obfs4 exec {}\n'.format(self.obfs4proxy_file_path)) + with open(common.get_resource_path('torrc_template-obfs4')) as o: + for line in o: + f.write(line) + if self.settings.get('tor_bridges_use_custom_bridges'): + f.write(self.settings.get('tor_bridges_use_custom_bridges')) + f.write('\nUseBridges 1') + # Execute a tor subprocess start_ts = time.time() if self.system == 'Windows': @@ -254,8 +264,13 @@ class Onion(object): break time.sleep(0.2) - # Timeout after 90 seconds - if time.time() - start_ts > 90: + # If using bridges, it might take a bit longer to connect to Tor + if self.settings.get('tor_bridges_use_custom_bridges') or self.settings.get('tor_bridges_use_obfs4'): + connect_timeout = 150 + else: + # Timeout after 120 seconds + connect_timeout = 120 + if time.time() - start_ts > connect_timeout: print("") self.tor_proc.terminate() raise BundledTorTimeout(strings._('settings_error_bundled_tor_timeout')) diff --git a/onionshare/settings.py b/onionshare/settings.py index e8103757..94b5dde5 100644 --- a/onionshare/settings.py +++ b/onionshare/settings.py @@ -61,6 +61,9 @@ class Settings(object): 'use_stealth': False, 'use_autoupdate': True, 'autoupdate_timestamp': None, + 'no_bridges': True, + 'tor_bridges_use_obfs4': False, + 'tor_bridges_use_custom_bridges': '', 'save_private_key': False, 'private_key': '', 'slug': '', diff --git a/onionshare_gui/settings_dialog.py b/onionshare_gui/settings_dialog.py index 92555700..18372a47 100644 --- a/onionshare_gui/settings_dialog.py +++ b/onionshare_gui/settings_dialog.py @@ -18,7 +18,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ from PyQt5 import QtCore, QtWidgets, QtGui -import sys, platform, datetime +import sys, platform, datetime, re from onionshare import strings, common from onionshare.settings import Settings @@ -140,6 +140,51 @@ class SettingsDialog(QtWidgets.QDialog): if (system == 'Windows' or system == 'Darwin') and getattr(sys, 'onionshare_dev_mode', False): self.connection_type_bundled_radio.setEnabled(False) + # Bridge options for bundled tor + + # No bridges option radio + self.tor_bridges_no_bridges_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_no_bridges_radio_option', True)) + self.tor_bridges_no_bridges_radio.toggled.connect(self.tor_bridges_no_bridges_radio_toggled) + + # obfs4 option radio + # if the obfs4proxy binary is missing, we can't use obfs4 transports + (self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = common.get_tor_paths() + if not os.path.isfile(self.obfs4proxy_file_path): + self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy', True)) + self.tor_bridges_use_obfs4_radio.setEnabled(False) + else: + self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option', True)) + self.tor_bridges_use_obfs4_radio.toggled.connect(self.tor_bridges_use_obfs4_radio_toggled) + + # Custom bridges radio and textbox + self.tor_bridges_use_custom_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_custom_radio_option', True)) + self.tor_bridges_use_custom_radio.toggled.connect(self.tor_bridges_use_custom_radio_toggled) + + self.tor_bridges_use_custom_label = QtWidgets.QLabel(strings._('gui_settings_tor_bridges_custom_label', True)) + self.tor_bridges_use_custom_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction) + self.tor_bridges_use_custom_label.setOpenExternalLinks(True) + self.tor_bridges_use_custom_textbox = QtWidgets.QPlainTextEdit() + self.tor_bridges_use_custom_textbox.setMaximumHeight(200) + self.tor_bridges_use_custom_textbox.setPlaceholderText('[address:port] [identifier]') + + tor_bridges_use_custom_textbox_options_layout = QtWidgets.QVBoxLayout() + tor_bridges_use_custom_textbox_options_layout.addWidget(self.tor_bridges_use_custom_label) + tor_bridges_use_custom_textbox_options_layout.addWidget(self.tor_bridges_use_custom_textbox) + + self.tor_bridges_use_custom_textbox_options = QtWidgets.QWidget() + self.tor_bridges_use_custom_textbox_options.setLayout(tor_bridges_use_custom_textbox_options_layout) + self.tor_bridges_use_custom_textbox_options.hide() + + # Bridges layout/widget + bridges_layout = QtWidgets.QVBoxLayout() + bridges_layout.addWidget(self.tor_bridges_no_bridges_radio) + bridges_layout.addWidget(self.tor_bridges_use_obfs4_radio) + bridges_layout.addWidget(self.tor_bridges_use_custom_radio) + bridges_layout.addWidget(self.tor_bridges_use_custom_textbox_options) + + self.bridges = QtWidgets.QWidget() + self.bridges.setLayout(bridges_layout) + # Automatic self.connection_type_automatic_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_automatic_option', True)) self.connection_type_automatic_radio.toggled.connect(self.connection_type_automatic_toggled) @@ -238,6 +283,13 @@ class SettingsDialog(QtWidgets.QDialog): connection_type_group = QtWidgets.QGroupBox() connection_type_group.setLayout(connection_type_group_layout) + # The Bridges options are not exclusive (enabling Bridges offers obfs4 or custom bridges) + connection_type_bridges_radio_group_layout = QtWidgets.QVBoxLayout() + connection_type_bridges_radio_group_layout.addWidget(self.bridges) + self.connection_type_bridges_radio_group = QtWidgets.QGroupBox(strings._("gui_settings_tor_bridges", True)) + self.connection_type_bridges_radio_group.setLayout(connection_type_bridges_radio_group_layout) + self.connection_type_bridges_radio_group.hide() + # Buttons self.save_button = QtWidgets.QPushButton(strings._('gui_settings_button_save', True)) self.save_button.clicked.connect(self.save_clicked) @@ -266,6 +318,7 @@ class SettingsDialog(QtWidgets.QDialog): right_col_layout = QtWidgets.QVBoxLayout() right_col_layout.addWidget(connection_type_radio_group) right_col_layout.addWidget(connection_type_group) + right_col_layout.addWidget(self.connection_type_bridges_radio_group) right_col_layout.addWidget(self.tor_status) right_col_layout.addStretch() @@ -345,6 +398,25 @@ class SettingsDialog(QtWidgets.QDialog): self.authenticate_password_radio.setChecked(True) self.authenticate_password_extras_password.setText(self.old_settings.get('auth_password')) + if self.old_settings.get('no_bridges'): + self.tor_bridges_no_bridges_radio.setChecked(True) + self.tor_bridges_use_obfs4_radio.setChecked(False) + self.tor_bridges_use_custom_radio.setChecked(False) + else: + self.tor_bridges_no_bridges_radio.setChecked(False) + self.tor_bridges_use_obfs4_radio.setChecked(self.old_settings.get('tor_bridges_use_obfs4')) + if self.old_settings.get('tor_bridges_use_custom_bridges'): + self.tor_bridges_use_custom_radio.setChecked(True) + # Remove the 'Bridge' lines at the start of each bridge. + # They are added automatically to provide compatibility with + # copying/pasting bridges provided from https://bridges.torproject.org + new_bridges = [] + bridges = self.old_settings.get('tor_bridges_use_custom_bridges').split('Bridge ') + for bridge in bridges: + new_bridges.append(bridge) + new_bridges = ''.join(new_bridges) + self.tor_bridges_use_custom_textbox.setPlainText(new_bridges) + def connection_type_bundled_toggled(self, checked): """ Connection type bundled was toggled. If checked, hide authentication fields. @@ -353,6 +425,28 @@ class SettingsDialog(QtWidgets.QDialog): if checked: self.authenticate_group.hide() self.connection_type_socks.hide() + self.connection_type_bridges_radio_group.show() + + def tor_bridges_no_bridges_radio_toggled(self, checked): + """ + 'No bridges' option was toggled. If checked, enable other bridge options. + """ + if checked: + self.tor_bridges_use_custom_textbox_options.hide() + + def tor_bridges_use_obfs4_radio_toggled(self, checked): + """ + obfs4 bridges option was toggled. If checked, disable custom bridge options. + """ + if checked: + self.tor_bridges_use_custom_textbox_options.hide() + + def tor_bridges_use_custom_radio_toggled(self, checked): + """ + Custom bridges option was toggled. If checked, show custom bridge options. + """ + if checked: + self.tor_bridges_use_custom_textbox_options.show() def connection_type_automatic_toggled(self, checked): """ @@ -362,6 +456,7 @@ class SettingsDialog(QtWidgets.QDialog): if checked: self.authenticate_group.hide() self.connection_type_socks.hide() + self.connection_type_bridges_radio_group.hide() def connection_type_control_port_toggled(self, checked): """ @@ -373,6 +468,7 @@ class SettingsDialog(QtWidgets.QDialog): self.authenticate_group.show() self.connection_type_control_port_extras.show() self.connection_type_socks.show() + self.connection_type_bridges_radio_group.hide() else: self.connection_type_control_port_extras.hide() @@ -387,6 +483,7 @@ class SettingsDialog(QtWidgets.QDialog): self.authenticate_group.show() self.connection_type_socket_file_extras.show() self.connection_type_socks.show() + self.connection_type_bridges_radio_group.hide() else: self.connection_type_socket_file_extras.hide() @@ -513,7 +610,9 @@ class SettingsDialog(QtWidgets.QDialog): if changed(settings, self.old_settings, [ 'connection_type', 'control_port_address', 'control_port_port', 'socks_address', 'socks_port', - 'socket_file_path', 'auth_type', 'auth_password']): + 'socket_file_path', 'auth_type', 'auth_password', + 'no_bridges', 'tor_bridges_use_obfs4', + 'tor_bridges_use_custom_bridges']): reboot_onion = True @@ -614,6 +713,38 @@ class SettingsDialog(QtWidgets.QDialog): settings.set('auth_password', self.authenticate_password_extras_password.text()) + # Whether we use bridges + if self.tor_bridges_no_bridges_radio.isChecked(): + settings.set('no_bridges', True) + settings.set('tor_bridges_use_obfs4', False) + settings.set('tor_bridges_use_custom_bridges', '') + if self.tor_bridges_use_obfs4_radio.isChecked(): + settings.set('no_bridges', False) + settings.set('tor_bridges_use_obfs4', True) + settings.set('tor_bridges_use_custom_bridges', '') + if self.tor_bridges_use_custom_radio.isChecked(): + settings.set('no_bridges', False) + settings.set('tor_bridges_use_obfs4', False) + # Insert a 'Bridge' line at the start of each bridge. + # This makes it easier to copy/paste a set of bridges + # provided from https://bridges.torproject.org + new_bridges = [] + bridges = self.tor_bridges_use_custom_textbox.toPlainText().split('\n') + bridges_valid = False + for bridge in bridges: + if bridge != '': + # Check the syntax of the custom bridge to make sure it looks legitimate + pattern = re.compile("[0-9.]+:[0-9]+\s[A-Z0-9]+$") + if pattern.match(bridge): + new_bridges.append(''.join(['Bridge ', bridge, '\n'])) + bridges_valid = True + if bridges_valid: + new_bridges = ''.join(new_bridges) + settings.set('tor_bridges_use_custom_bridges', new_bridges) + else: + Alert(strings._('gui_settings_tor_bridges_invalid', True)) + settings.set('no_bridges', True) + return settings def closeEvent(self, e): diff --git a/share/locale/en.json b/share/locale/en.json index 05873e26..cdd89c1e 100644 --- a/share/locale/en.json +++ b/share/locale/en.json @@ -91,6 +91,13 @@ "gui_settings_authenticate_cookie_option": "Cookie", "gui_settings_password_label": "Password", "gui_settings_cookie_label": "Cookie path", + "gui_settings_tor_bridges": "Tor Bridge support", + "gui_settings_tor_bridges_no_bridges_radio_option": "Don't use bridges", + "gui_settings_tor_bridges_obfs4_radio_option": "Use obfs4 pluggable transports", + "gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy": "Use obfs4 pluggable transports (requires obfs4proxy)", + "gui_settings_tor_bridges_custom_radio_option": "Use custom bridges (non-pluggable transports)", + "gui_settings_tor_bridges_custom_label": "You can get bridges from https://bridges.torproject.org", + "gui_settings_tor_bridges_invalid": "None of the bridges you supplied seem to be valid, so they've been ignored.\nPlease try again with valid bridges.", "gui_settings_button_save": "Save", "gui_settings_button_cancel": "Cancel", "gui_settings_button_help": "Help", diff --git a/share/torrc_template-obfs4 b/share/torrc_template-obfs4 new file mode 100644 index 00000000..306c456c --- /dev/null +++ b/share/torrc_template-obfs4 @@ -0,0 +1,27 @@ +Bridge obfs4 154.35.22.10:80 8FB9F4319E89E5C6223052AA525A192AFBC85D55 cert=GGGS1TX4R81m3r0HBl79wKy1OtPPNR2CZUIrHjkRg65Vc2VR8fOyo64f9kmT1UAFG7j0HQ iat-mode=0 +Bridge obfs4 83.212.101.3:50002 A09D536DD1752D542E1FBB3C9CE4449D51298239 cert=lPRQ/MXdD1t5SRZ9MquYQNT9m5DV757jtdXdlePmRCudUU9CFUOX1Tm7/meFSyPOsud7Cw iat-mode=0 +Bridge obfs4 109.105.109.165:10527 8DFCD8FB3285E855F5A55EDDA35696C743ABFC4E cert=Bvg/itxeL4TWKLP6N1MaQzSOC6tcRIBv6q57DYAZc3b2AzuM+/TfB7mqTFEfXILCjEwzVA iat-mode=1 +Bridge obfs4 154.35.22.11:80 A832D176ECD5C7C6B58825AE22FC4C90FA249637 cert=YPbQqXPiqTUBfjGFLpm9JYEFTBvnzEJDKJxXG5Sxzrr/v2qrhGU4Jls9lHjLAhqpXaEfZw iat-mode=0 +Bridge obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0 +Bridge obfs4 154.35.22.9:443 C73ADBAC8ADFDBF0FC0F3F4E8091C0107D093716 cert=gEGKc5WN/bSjFa6UkG9hOcft1tuK+cV8hbZ0H6cqXiMPLqSbCh2Q3PHe5OOr6oMVORhoJA iat-mode=0 +Bridge obfs4 154.35.22.11:443 A832D176ECD5C7C6B58825AE22FC4C90FA249637 cert=YPbQqXPiqTUBfjGFLpm9JYEFTBvnzEJDKJxXG5Sxzrr/v2qrhGU4Jls9lHjLAhqpXaEfZw iat-mode=0 +Bridge obfs4 154.35.22.13:443 FE7840FE1E21FE0A0639ED176EDA00A3ECA1E34D cert=fKnzxr+m+jWXXQGCaXe4f2gGoPXMzbL+bTBbXMYXuK0tMotd+nXyS33y2mONZWU29l81CA iat-mode=0 +Bridge obfs4 154.35.22.10:443 8FB9F4319E89E5C6223052AA525A192AFBC85D55 cert=GGGS1TX4R81m3r0HBl79wKy1OtPPNR2CZUIrHjkRg65Vc2VR8fOyo64f9kmT1UAFG7j0HQ iat-mode=0 +Bridge obfs4 154.35.22.9:80 C73ADBAC8ADFDBF0FC0F3F4E8091C0107D093716 cert=gEGKc5WN/bSjFa6UkG9hOcft1tuK+cV8hbZ0H6cqXiMPLqSbCh2Q3PHe5OOr6oMVORhoJA iat-mode=0 +Bridge obfs4 192.99.11.54:443 7B126FAB960E5AC6A629C729434FF84FB5074EC2 cert=VW5f8+IBUWpPFxF+rsiVy2wXkyTQG7vEd+rHeN2jV5LIDNu8wMNEOqZXPwHdwMVEBdqXEw iat-mode=0 +Bridge obfs4 154.35.22.13:16815 FE7840FE1E21FE0A0639ED176EDA00A3ECA1E34D cert=fKnzxr+m+jWXXQGCaXe4f2gGoPXMzbL+bTBbXMYXuK0tMotd+nXyS33y2mONZWU29l81CA iat-mode=0 +Bridge obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0 +Bridge obfs4 38.229.33.83:80 0BAC39417268B96B9F514E7F63FA6FBA1A788955 cert=VwEFpk9F/UN9JED7XpG1XOjm/O8ZCXK80oPecgWnNDZDv5pdkhq1OpbAH0wNqOT6H6BmRQ iat-mode=1 +Bridge obfs4 154.35.22.11:16488 A832D176ECD5C7C6B58825AE22FC4C90FA249637 cert=YPbQqXPiqTUBfjGFLpm9JYEFTBvnzEJDKJxXG5Sxzrr/v2qrhGU4Jls9lHjLAhqpXaEfZw iat-mode=0 +Bridge obfs4 154.35.22.9:12166 C73ADBAC8ADFDBF0FC0F3F4E8091C0107D093716 cert=gEGKc5WN/bSjFa6UkG9hOcft1tuK+cV8hbZ0H6cqXiMPLqSbCh2Q3PHe5OOr6oMVORhoJA iat-mode=0 +Bridge obfs4 109.105.109.147:13764 BBB28DF0F201E706BE564EFE690FE9577DD8386D cert=KfMQN/tNMFdda61hMgpiMI7pbwU1T+wxjTulYnfw+4sgvG0zSH7N7fwT10BI8MUdAD7iJA iat-mode=2 +Bridge obfs4 38.229.1.78:80 C8CBDB2464FC9804A69531437BCF2BE31FDD2EE4 cert=Hmyfd2ev46gGY7NoVxA9ngrPF2zCZtzskRTzoWXbxNkzeVnGFPWmrTtILRyqCTjHR+s9dg iat-mode=1 +Bridge obfs4 [2001:470:b381:bfff:216:3eff:fe23:d6c3]:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1 +Bridge obfs4 85.17.30.79:443 FC259A04A328A07FED1413E9FC6526530D9FD87A cert=RutxZlu8BtyP+y0NX7bAVD41+J/qXNhHUrKjFkRSdiBAhIHIQLhKQ2HxESAKZprn/lR3KA iat-mode=0 +Bridge obfs4 154.35.22.10:15937 8FB9F4319E89E5C6223052AA525A192AFBC85D55 cert=GGGS1TX4R81m3r0HBl79wKy1OtPPNR2CZUIrHjkRg65Vc2VR8fOyo64f9kmT1UAFG7j0HQ iat-mode=0 +Bridge obfs4 37.218.240.34:40035 88CD36D45A35271963EF82E511C8827A24730913 cert=eGXYfWODcgqIdPJ+rRupg4GGvVGfh25FWaIXZkit206OSngsp7GAIiGIXOJJROMxEqFKJg iat-mode=1 +Bridge obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1 +Bridge obfs4 154.35.22.12:80 00DC6C4FA49A65BD1472993CF6730D54F11E0DBB cert=N86E9hKXXXVz6G7w2z8wFfhIDztDAzZ/3poxVePHEYjbKDWzjkRDccFMAnhK75fc65pYSg iat-mode=0 +Bridge obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0 +Bridge obfs4 154.35.22.12:4304 00DC6C4FA49A65BD1472993CF6730D54F11E0DBB cert=N86E9hKXXXVz6G7w2z8wFfhIDztDAzZ/3poxVePHEYjbKDWzjkRDccFMAnhK75fc65pYSg iat-mode=0 +UseBridges 1 diff --git a/stdeb.cfg b/stdeb.cfg index cc811197..334502c0 100644 --- a/stdeb.cfg +++ b/stdeb.cfg @@ -1,6 +1,6 @@ [DEFAULT] Package3: onionshare -Depends3: python3-flask, python3-stem, python3-pyqt5, python-nautilus, tor +Depends3: python3-flask, python3-stem, python3-pyqt5, python-nautilus, tor, obfs4proxy Build-Depends: python3-pytest, python3-flask, python3-stem, python3-pyqt5 Suite: xenial X-Python3-Version: >= 3.4 diff --git a/test/test_onionshare_common.py b/test/test_onionshare_common.py index 8d0eb0ea..f574ad7f 100644 --- a/test/test_onionshare_common.py +++ b/test/test_onionshare_common.py @@ -213,13 +213,15 @@ class TestGetTorPaths: base_path, 'Resources', 'Tor', 'geoip') tor_geo_ipv6_file_path = os.path.join( base_path, 'Resources', 'Tor', 'geoip6') + obfs4proxy_file_path = os.path.join( + base_path, 'Resources', 'Tor', 'obfs4proxy') assert (common.get_tor_paths() == - (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path)) + (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path, obfs4proxy_file_path)) # @pytest.mark.skipif(sys.platform != 'Linux', reason='requires Linux') ? def test_get_tor_paths_linux(self, platform_linux): assert (common.get_tor_paths() == - ('/usr/bin/tor', '/usr/share/tor/geoip', '/usr/share/tor/geoip6')) + ('/usr/bin/tor', '/usr/share/tor/geoip', '/usr/share/tor/geoip6', '/usr/bin/obfs4proxy')) # @pytest.mark.skipif(sys.platform != 'Windows', reason='requires Windows') ? def test_get_tor_paths_windows(self, platform_windows, sys_frozen): @@ -228,7 +230,9 @@ class TestGetTorPaths: os.path.dirname( common.get_resource_path(''))), 'tor') tor_path = os.path.join( - os.path.join(base_path, 'Tor'), "tor.exe") + os.path.join(base_path, 'Tor'), 'tor.exe') + obfs4proxy_file_path = os.path.join( + os.path.join(base_path, 'Tor'), 'obfs4proxy.exe') tor_geo_ip_file_path = os.path.join( os.path.join( os.path.join(base_path, 'Data'), 'Tor'), 'geoip') @@ -236,7 +240,7 @@ class TestGetTorPaths: os.path.join( os.path.join(base_path, 'Data'), 'Tor'), 'geoip6') assert (common.get_tor_paths() == - (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path)) + (tor_path, tor_geo_ip_file_path, tor_geo_ipv6_file_path, obfs4proxy_file_path)) class TestGetVersion: diff --git a/test/test_onionshare_settings.py b/test/test_onionshare_settings.py index ba45ef5e..b17ce30a 100644 --- a/test/test_onionshare_settings.py +++ b/test/test_onionshare_settings.py @@ -58,6 +58,9 @@ class TestSettings: 'use_stealth': False, 'use_autoupdate': True, 'autoupdate_timestamp': None, + 'no_bridges': True, + 'tor_bridges_use_obfs4': False, + 'tor_bridges_use_custom_bridges': '', 'save_private_key': False, 'private_key': '', 'slug': '', @@ -119,6 +122,11 @@ class TestSettings: assert settings_obj.get('use_stealth') is False assert settings_obj.get('use_autoupdate') is True assert settings_obj.get('autoupdate_timestamp') is None + assert settings_obj.get('autoupdate_timestamp') is None + assert settings_obj.get('no_bridges') is True + assert settings_obj.get('tor_bridges_use_obfs4') is False + assert settings_obj.get('tor_bridges_use_custom_bridges') == '' + def test_set_version(self, settings_obj): settings_obj.set('version', 'CUSTOM_VERSION') @@ -165,3 +173,7 @@ class TestSettings: monkeypatch.setenv('APPDATA', 'C:') obj = settings.Settings() assert obj.filename == 'C:\\OnionShare\\onionshare.json' + + def test_set_custom_bridge(self, settings_obj): + settings_obj.set('tor_bridges_use_custom_bridges', 'Bridge 45.3.20.65:9050 21300AD88890A49C429A6CB9959CFD44490A8F6E') + assert settings_obj._settings['tor_bridges_use_custom_bridges'] == 'Bridge 45.3.20.65:9050 21300AD88890A49C429A6CB9959CFD44490A8F6E'