Merge feather 2.7.0

This commit is contained in:
twiddle 2024-10-11 18:19:34 -04:00
commit 5f26201cdf
191 changed files with 1623 additions and 1300 deletions

View file

@ -80,7 +80,18 @@ jobs:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4
with: with:
merge-multiple: true merge-multiple: true
- name: print hashes
run: |
echo '```' >> $GITHUB_STEP_SUMMARY
uname --machine && find **/output/ -type f -print0 | env LC_ALL=C sort -z | xargs -r0 sha256sum >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v4 - uses: actions/upload-artifact@v4
with: with:
name: "logs" name: "logs"
path: '**/logs/**' path: '**/logs/**'
- uses: ncipollo/release-action@v1
if: startsWith(github.ref, 'refs/tags/')
with:
artifacts: "**/*.AppImage,**/*-linux-arm.zip,**/*-linux-arm64.zip,**/*-linux-riscv64.zip,**/*-linux.zip,**/*-mac-arm64.zip,**/*-mac.zip,**/*-win.zip,**/FeatherWalletSetup-*.exe,**/feather-{{github.ref_name}}.tar.gz"
draft: true
name: v${{github.ref_name}}

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
.DS_Store .DS_Store
lib/* lib/*
cmake-build-debug/* cmake-build-debug/*
cmake-build-release/*
.idea .idea
*.user *.user
*.stash *.stash

3
.gitmodules vendored
View file

@ -1,9 +1,6 @@
[submodule "monero"] [submodule "monero"]
path = monero path = monero
url = https://github.com/feather-wallet/monero.git url = https://github.com/feather-wallet/monero.git
[submodule "src/third-party/singleapplication"]
path = src/third-party/singleapplication
url = https://github.com/itay-grudev/SingleApplication.git
[submodule "src/third-party/polyseed"] [submodule "src/third-party/polyseed"]
path = src/third-party/polyseed path = src/third-party/polyseed
url = https://github.com/tevador/polyseed.git url = https://github.com/tevador/polyseed.git

View file

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.18) cmake_minimum_required(VERSION 3.18)
project(feather project(feather
VERSION "2.6.8" VERSION "2.7.0"
DESCRIPTION "A free Monero desktop wallet" DESCRIPTION "A free Monero desktop wallet"
LANGUAGES CXX C ASM LANGUAGES CXX C ASM
) )
@ -15,6 +15,8 @@ set(PACKAGE_URL "https://featherwallet.org/")
set(COPYRIGHT_YEAR "2024") set(COPYRIGHT_YEAR "2024")
set(COPYRIGHT_HOLDERS "The Monero Project") set(COPYRIGHT_HOLDERS "The Monero Project")
cmake_policy(SET CMP0074 NEW)
# Configurable options # Configurable options
option(STATIC "Link libraries statically, requires static Qt" OFF) option(STATIC "Link libraries statically, requires static Qt" OFF)
option(SELF_CONTAINED "Disable when building Feather for packages" OFF) option(SELF_CONTAINED "Disable when building Feather for packages" OFF)
@ -71,9 +73,7 @@ if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/monero/CMakeLists.txt")
message(FATAL_ERROR "'monero/CMakeLists.txt' does not exist, did you forget to:\ngit submodule update --init --recursive --progress") message(FATAL_ERROR "'monero/CMakeLists.txt' does not exist, did you forget to:\ngit submodule update --init --recursive --progress")
endif() endif()
add_subdirectory(monero EXCLUDE_FROM_ALL) add_subdirectory(monero EXCLUDE_FROM_ALL)
set_property(TARGET wallet_merged PROPERTY FOLDER "monero")
get_directory_property(ARCH_WIDTH DIRECTORY "monero" DEFINITION ARCH_WIDTH) get_directory_property(ARCH_WIDTH DIRECTORY "monero" DEFINITION ARCH_WIDTH)
get_directory_property(UNBOUND_LIBRARY DIRECTORY "monero" DEFINITION UNBOUND_LIBRARY)
get_directory_property(DEVICE_TREZOR_READY DIRECTORY "monero" DEFINITION DEVICE_TREZOR_READY) get_directory_property(DEVICE_TREZOR_READY DIRECTORY "monero" DEFINITION DEVICE_TREZOR_READY)
get_directory_property(TREZOR_DEP_LIBS DIRECTORY "monero" DEFINITION TREZOR_DEP_LIBS) get_directory_property(TREZOR_DEP_LIBS DIRECTORY "monero" DEFINITION TREZOR_DEP_LIBS)
get_directory_property(OPENBSD DIRECTORY "monero" DEFINITION OPENBSD) get_directory_property(OPENBSD DIRECTORY "monero" DEFINITION OPENBSD)
@ -90,10 +90,6 @@ endif()
# pthread # pthread
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
# Sodium
find_library(SODIUM_LIBRARY sodium)
message(STATUS "libsodium: libraries at ${SODIUM_LIBRARY}")
# QrEncode # QrEncode
find_package(QREncode REQUIRED) find_package(QREncode REQUIRED)
@ -136,27 +132,12 @@ if(MINGW)
set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN") set(MINGW_FLAG "${MINGW_FLAG} -DWIN32_LEAN_AND_MEAN")
set(Boost_THREADAPI win32) set(Boost_THREADAPI win32)
endif() endif()
set(Boost_USE_MULTITHREADED ON)
set(BOOST_COMPONENTS
system
filesystem
thread
date_time
chrono
regex
serialization
program_options
locale
)
if(STACK_TRACE AND UNIX AND NOT APPLE) if(STACK_TRACE AND UNIX AND NOT APPLE)
list(APPEND BOOST_COMPONENTS find_package(Boost 1.58 REQUIRED COMPONENTS stacktrace_basic)
stacktrace_basic)
endif() endif()
set(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.58 REQUIRED COMPONENTS ${BOOST_COMPONENTS})
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446 # https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446
@ -250,13 +231,6 @@ if (NOT WIN32 AND NOT OPENBSD AND NOT "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang"
add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS) add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS)
endif() endif()
# -mmitigate-rop
# removed in GCC 9.1 (or before ?), but still accepted, so spams the output
if (NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))
add_c_flag_if_supported(-mmitigate-rop C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-mmitigate-rop CXX_SECURITY_FLAGS)
endif()
# linker # linker
if (APPLE) if (APPLE)
add_linker_flag_if_supported(-Wl,-bind_at_load LD_SECURITY_FLAGS) add_linker_flag_if_supported(-Wl,-bind_at_load LD_SECURITY_FLAGS)

View file

@ -1,29 +1,26 @@
# Documentation for developers # Documentation for developers
Feather is developed primarily on Linux, but can also be built and debugged on macOS. Development on Windows is not Feather is developed primarily on Linux, but can also be built on macOS. Development on Windows is not currently supported.
currently supported.
We support development on rolling release distributions and the latest version of Ubuntu. Building on older stable distributions is not guaranteed to work.
## Setting up a development environment ## Setting up a development environment
### Dependencies ### Dependencies
Note: Feather requires Qt 6.3 or later. Make sure your distro's package manager provides this version.
If not, it is recommended that you install Qt manually using the online installer, which can be found here:
https://www.qt.io/download (under open-source).
#### Arch Linux #### Arch Linux
```bash ```bash
pacman -S git cmake base-devel ccache unbound boost qrencode qt6-base qt6-svg qt6-websockets qt6-multimedia libzip hidapi protobuf zxing-cpp pacman -S git cmake base-devel ccache unbound boost qrencode qt6-base qt6-svg qt6-websockets qt6-multimedia libzip hidapi protobuf zxing-cpp
``` ```
#### Ubuntu 22.04 #### Ubuntu 24.04
```bash ```bash
apt update apt update
apt install git cmake build-essential ccache libssl-dev libunbound-dev libboost-all-dev libqrencode-dev \ apt install git cmake build-essential ccache libssl-dev libunbound-dev libboost-all-dev libqrencode-dev \
qt6-base-dev libgl1-mesa-dev libqt6svg6-dev libqt6websockets6-dev libzip-dev libsodium-dev libgcrypt-dev \ qt6-base-dev qt6-multimedia-dev libgl1-mesa-dev libqt6svg6-dev libqt6websockets6-dev libzip-dev libsodium-dev libgcrypt-dev \
libx11-xcb-dev libprotobuf-dev libhidapi-dev libzxing-dev libx11-xcb-dev libprotobuf-dev protobuf-compiler libhidapi-dev libzxing-dev
``` ```
#### Void Linux #### Void Linux
@ -92,9 +89,8 @@ git submodule update --init --recursive
We recommend using Jetbrains Clion for Feather development. It integrates nicely with CMake and comes with a built-in We recommend using Jetbrains Clion for Feather development. It integrates nicely with CMake and comes with a built-in
debugger. debugger.
To pass CMake flags to CLion, go to `File->Settings->Build->CMake`, set Build Type to `Debug` and set your To pass CMake flags to CLion, go to `File -> Settings -> Build -> CMake`, set Build Type to `Debug` and set your
preferred CMake options. If you installed Qt using the online installer you may have to add preferred CMake options. More CMake options are documented below.
`-DCMAKE_PREFIX_PATH=/path/to/qt/installation` in the CMake options. More CMake options are documented below.
Run CMake (`View -> Tool Windows -> CMake`). Click on the 🔃 (`Reload CMake Project`) button. Run CMake (`View -> Tool Windows -> CMake`). Click on the 🔃 (`Reload CMake Project`) button.

View file

@ -13,20 +13,36 @@ This document is written for developers and users interested in learning how Fea
- Review the diff of any altered package to mitigate the risk of supply chain attacks - Review the diff of any altered package to mitigate the risk of supply chain attacks
- Update compilers and security flags for better binary security - Update compilers and security flags for better binary security
- Reduce the number of third-party dependencies - Reduce the number of third-party dependencies
- Keep the website VPS up-to-date and secure - Keep the [website](https://github.com/feather-wallet/feather-site/blob/master/mirrors.txt) VPS up-to-date and secure
- Further harden the [release process](RELEASE.md) - Contact relevant authorities to take [phishing sites](https://gist.github.com/tobtoht/4039fa3cf922d4fe8bca2f8e3ddac63b) offline
- Make improvements to the [release process](RELEASE.md)
Goals: Goals:
- Set up a bug bounty program for issues that affect privacy or security - Set up a bug bounty program for issues that affect privacy or security
- Set up a status page with information about project health - Set up a status page with information about project health
- Set up a feed for security bulletins - Set up a feed for security bulletins
- Sandbox components that handle untrusted input (e.g. QR code scanner)
- Create a package manager for secure distribution of portable binaries
- `-static-pie` release binaries for Linux targets
Security issues that affect Feather always warrant a new release as soon as possible. Security issues that affect Feather always warrant a new release as soon as possible.
### 2. Reproducibility ### 2. Continuity
- Improve and maintain tools to check for reproducibility defects - Keep the website and services online
- Keep source repositories accessible
- Make sure that running release builds is easy to set up and reproducible in time
Goals:
- Make sure the project is transmissible
- Make sure that setting up release infrastructure, release engineering, and maintenance are extensively documented
- Make the websocket server repository public
### 3. Reproducibility
- Improve and maintain tools to check for non-determinism
- Ensure releases are reproducible and stay that way - Ensure releases are reproducible and stay that way
- Upload source archives to the fallback mirror - Upload source archives to the fallback mirror
@ -36,31 +52,32 @@ To learn more about Feather's build system, see: [`contrib/guix/README.md`](http
Our Guix time-machine is currently pinned at a commit which implements the Our Guix time-machine is currently pinned at a commit which implements the
[Full-Source Bootstrap](https://guix.gnu.org/en/blog/2023/the-full-source-bootstrap-building-from-source-all-the-way-down/). [Full-Source Bootstrap](https://guix.gnu.org/en/blog/2023/the-full-source-bootstrap-building-from-source-all-the-way-down/).
### 3. Bugs ### 4. Bugs
- Fix reproducible bugs and crashes - Fix bugs and crashes
To report a bug, please see: https://docs.featherwallet.org/guides/report-an-issue To report a bug, please see: https://docs.featherwallet.org/guides/report-an-issue
### 4. Tests ### 5. Tests
- Improve test coverage - Improve test coverage
- Write more test cases - Write more test cases
Feather does not currently have a test suite (apart from the tests in the Monero submodule), this is a WIP. Feather does not currently have a test suite (apart from the tests in the Monero submodule), this is a WIP.
### 5. Documentation ### 6. Documentation
- Make sure the documentation accurately reflects the latest release - Make sure the documentation accurately reflects the latest release
- Add troubleshooting guides for common problems - Add troubleshooting guides for common problems
- Ideally, most support questions can be answered with a link to the documentation
Goals: Goals:
- Most support questions can be answered with a link to the documentation
- Reconsider and document default settings - Reconsider and document default settings
- Write a document on threat modeling
Documentation is available at https://docs.featherwallet.org Documentation is available at https://docs.featherwallet.org
### 6. Improvements ### 7. Improvements
- Improve existing features - Improve existing features
- Improve UI/UX - Improve UI/UX
@ -68,19 +85,15 @@ Documentation is available at https://docs.featherwallet.org
Feather should first and foremost be a good __wallet__. Feather should first and foremost be a good __wallet__.
Improving features that are closer to this end should have priority. Improving features that are closer to this end should have priority.
### 7. Packaging ### 8. Platform Support
- Add support for more architectures and operating systems - Add support for more architectures and operating systems
- Drop support for End-of-Life distributions - Drop support for End-of-Life distributions
- Add support for new hardware wallets
Goals:
- Debian and Guix packages
- Create a document with guidelines for packagers
See: https://docs.featherwallet.org/guides/supported-operating-systems See: https://docs.featherwallet.org/guides/supported-operating-systems
### 8. Optimization, cleanup and continuity ### 9. Optimization
Miscellaneous maintenance tasks. Miscellaneous maintenance tasks.
@ -98,9 +111,9 @@ Miscellaneous maintenance tasks.
Goals: Goals:
- Make sure Feather is ready for the migration to [Seraphis](https://github.com/seraphis-migration/wallet3) - Make sure Feather is ready for the migration to [FCMP++](https://www.getmonero.org/2024/04/27/fcmps.html)
### 9. Features ### 10. Features
- Implement new features - Implement new features
- Allow Feather to be used or configured for higher, esoteric or new threat models - Allow Feather to be used or configured for higher, esoteric or new threat models
@ -112,7 +125,7 @@ compared to its expected maintenance and support burden.
For a non-exhaustive list of potentially new features, see: https://featherwallet.org/ideas For a non-exhaustive list of potentially new features, see: https://featherwallet.org/ideas
### 10. Upstreaming ### 11. Upstreaming
- Upstream tried and tested features, bugfixes and useful patches - Upstream tried and tested features, bugfixes and useful patches
- Bugfixes should be upstreamed without delay - Bugfixes should be upstreamed without delay

View file

@ -37,27 +37,29 @@ If for some reason the swap isn't able to be completed when ran, one party goes
https://github.com/user-attachments/assets/b7871a2f-21d0-46e2-b575-b9ba885a810d https://github.com/user-attachments/assets/b7871a2f-21d0-46e2-b575-b9ba885a810d
#### This video has been speed up in multiple sections time on the top right is accurate to real life time. For release policy, see: [RELEASE.md](https://github.com/feather-wallet/feather/blob/master/RELEASE.md)
## Resources
* Web: [featherwallet.org](https://featherwallet.org)
* Docs: [docs.featherwallet.org](https://docs.featherwallet.org)
* Git: [github.com/feather-wallet/feather](https://github.com/feather-wallet/feather)
* Reddit: [/r/FeatherWallet](https://old.reddit.com/r/FeatherWallet)
* Lemmy: [monero.town/c/featherwallet](https://monero.town/c/featherwallet)
* Mail: dev@featherwallet.org
* IRC: `#feather` on [OFTC](https://www.oftc.net/)
* Matrix: [matrix.to/#/#feather:monero.social](https://matrix.to/#/#feather:monero.social)
## Deterministic builds
See [contrib/guix/README.md](https://github.com/feather-wallet/feather/blob/master/contrib/guix/README.md) for more information.
## Development ## Development
If you are looking to set up a development environment for Feather, see [HACKING.md](https://github.com/feather-wallet/feather/blob/master/HACKING.md). If you are looking to set up a development environment for Feather, see [HACKING.md](https://github.com/feather-wallet/feather/blob/master/HACKING.md).
It is highly recommended that you join the `#feather` IRC channel on [OFTC](https://www.oftc.net/) or [`#feather:monero.social`](https://matrix.to/#/#feather:monero.social) on Matrix if you It is highly recommended that you join our Matrix or IRC channel if you are hacking on Feather.
are hacking on Feather. Due to the nature of this open source software project, idling in this channel is the best Idling in this channel is the best way to stay updated on best practices and new developments.
way to stay updated on best practices and new developments.
For information on how Feather is maintained, see: [MAINTENANCE.md](https://github.com/feather-wallet/feather/blob/master/MAINTENANCE.md)
To report a security vulnerability, see: [SECURITY.md](https://github.com/feather-wallet/feather/blob/master/SECURITY.md)
## Support
Feather is funded entirely through donations. We don't take a cut from transaction fees and make no money from exchange integrations.
Donations help pay for hosting, build servers, domain names, e-mail and other recurring costs. Any amount helps.
`47ntfT2Z5384zku39pTM6hGcnLnvpRYW2Azm87GiAAH2bcTidtq278TL6HmwyL8yjMeERqGEBs3cqC8vvHPJd1cWQrGC65f`
## License
Feather is free and open-source software, [licensed under BSD-3](https://raw.githubusercontent.com/feather-wallet/feather/master/LICENSE).
Copyright (c) 2020-2024, The Monero Project

View file

@ -13,3 +13,32 @@ The following keys may be used to communicate sensitive information to developer
| tobtoht | E87B D921 CDD8 85C9 D78A 38C5 E45B 10DD 027D 2472 | | tobtoht | E87B D921 CDD8 85C9 D78A 38C5 E45B 10DD 027D 2472 |
Public keys can be found in [`utils/pubkeys`](utils/pubkeys). Public keys can be found in [`utils/pubkeys`](utils/pubkeys).
## Bug Bounty Program
A bounty may be rewarded to a vulnerability report **if and only if** the issue can result in **a loss of funds**.
You must describe a **plausible scenario** in which a loss of funds can occur (or has occurred) that **isn't solely attributable to user error**.
Only **the code** of the **latest tagged release** of **[this repository](https://github.com/feather-wallet/feather/)** is in scope.
**The bounty can only be rewarded in XMR**. The bounty amount for your report is determined by the maintainers and ranges from USD 150 to USD 3000 (in terms of XMR) and depends on the severity of the issue and other factors.
Clarifications on scope:
- The issue **must be present in a [signed](https://docs.featherwallet.org/guides/release-signing-key) [release build](https://github.com/feather-wallet/feather/blob/master/contrib/guix/README.md)**. Custom builds, including distribution packages, are out of scope.
- The developers **must be able to reproduce and fix the issue**. If the issue cannot be fixed **in our code** for any reason, it is out of scope.
- The live [websites](https://github.com/feather-wallet/feather-site/blob/master/mirrors.txt) and their repositories are out of scope.
- Loss of funds due to malware on the user's machine is out of scope.
- Memory imaging, including cold boot attacks, is out of scope.
- Social engineering against users is out of scope. This includes messages received from the [websocket server](https://docs.featherwallet.org/guides/websocket).
- Any form of coercion, physical or psychological, is out of scope.
- Vulnerabilities that are attributable to hardware are out of scope.
- If the issue was fixed in the `master` branch before we receive your report, it is invalid and not eligible for a bounty from this program.
- If the vulnerability involves binary exploitation, we may ask you to provide a proof of concept of secret key exfiltration.
- Vulnerabilities that are present in the monero submodule but were not introduced in patches made by the Feather developers must
be reported [upstream](https://github.com/monero-project/meta/blob/master/VULNERABILITY_RESPONSE_PROCESS.md) and are not eligible for a bounty from this program.
- Vulnerabilities that are present in any of our third-party dependencies must be reported upstream and are not eligible for a bounty from this program.
- Vulnerabilities that are present in [supported hardware wallets](https://docs.featherwallet.org/guides/hardware-wallet-support) must be reported upstream and are not eligible for a bounty from this program.
- A bounty will not be awarded if the reported vulnerability was already known. We may make an exception if you demonstrate that the severity of the issue was underestimated and no immediate fix was planned.
- If, during your research, you disrupt Feather's release infrastructure or services, or attempt to coerce its developers, you will not be awarded a bounty.

View file

@ -1,291 +0,0 @@
# Written in 2016 by Henrik Steffen Gaßmann <henrik@gassmann.onl>
#
# To the extent possible under law, the author(s) have dedicated all copyright
# and related and neighboring rights to this software to the public domain
# worldwide. This software is distributed without any warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication along with
# this software. If not, see
#
# http://creativecommons.org/publicdomain/zero/1.0/
#
# ##############################################################################
# Tries to find the local libsodium installation.
#
# On Windows the sodium_DIR environment variable is used as a default hint which
# can be overridden by setting the corresponding cmake variable.
#
# Once done the following variables will be defined:
#
# sodium_FOUND sodium_INCLUDE_DIR sodium_LIBRARY_DEBUG sodium_LIBRARY_RELEASE
# sodium_VERSION_STRING
#
# Furthermore an imported "sodium" target is created.
#
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
set(_GCC_COMPATIBLE 1)
endif()
# static library option
if(NOT DEFINED sodium_USE_STATIC_LIBS)
option(sodium_USE_STATIC_LIBS "enable to statically link against sodium" OFF)
endif()
if(NOT (sodium_USE_STATIC_LIBS EQUAL sodium_USE_STATIC_LIBS_LAST))
unset(sodium_LIBRARY CACHE)
unset(sodium_LIBRARY_DEBUG CACHE)
unset(sodium_LIBRARY_RELEASE CACHE)
unset(sodium_DLL_DEBUG CACHE)
unset(sodium_DLL_RELEASE CACHE)
set(sodium_USE_STATIC_LIBS_LAST
${sodium_USE_STATIC_LIBS}
CACHE INTERNAL "internal change tracking variable")
endif()
# ##############################################################################
# UNIX
if(UNIX)
# import pkg-config
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_check_modules(sodium_PKG QUIET libsodium)
endif()
if(sodium_USE_STATIC_LIBS)
if(sodium_PKG_STATIC_LIBRARIES)
foreach(_libname ${sodium_PKG_STATIC_LIBRARIES})
if(NOT _libname MATCHES "^lib.*\\.a$") # ignore strings already ending
# with .a
list(INSERT sodium_PKG_STATIC_LIBRARIES 0 "lib${_libname}.a")
endif()
endforeach()
list(REMOVE_DUPLICATES sodium_PKG_STATIC_LIBRARIES)
else()
# if pkgconfig for libsodium doesn't provide static lib info, then
# override PKG_STATIC here..
set(sodium_PKG_STATIC_LIBRARIES libsodium.a)
endif()
set(XPREFIX sodium_PKG_STATIC)
else()
if(sodium_PKG_LIBRARIES STREQUAL "")
set(sodium_PKG_LIBRARIES sodium)
endif()
set(XPREFIX sodium_PKG)
endif()
find_path(sodium_INCLUDE_DIR sodium.h HINTS ${${XPREFIX}_INCLUDE_DIRS})
find_library(sodium_LIBRARY_DEBUG
NAMES ${${XPREFIX}_LIBRARIES}
HINTS ${${XPREFIX}_LIBRARY_DIRS})
find_library(sodium_LIBRARY_RELEASE
NAMES ${${XPREFIX}_LIBRARIES}
HINTS ${${XPREFIX}_LIBRARY_DIRS})
# ############################################################################
# Windows
elseif(WIN32)
set(sodium_DIR "$ENV{sodium_DIR}" CACHE FILEPATH "sodium install directory")
mark_as_advanced(sodium_DIR)
find_path(sodium_INCLUDE_DIR sodium.h
HINTS ${sodium_DIR}
PATH_SUFFIXES include)
if(MSVC)
# detect target architecture
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/arch.c" [=[
#if defined _M_IX86
#error ARCH_VALUE x86_32
#elif defined _M_X64
#error ARCH_VALUE x86_64
#endif
#error ARCH_VALUE unknown
]=])
try_compile(_UNUSED_VAR "${CMAKE_CURRENT_BINARY_DIR}"
"${CMAKE_CURRENT_BINARY_DIR}/arch.c"
OUTPUT_VARIABLE _COMPILATION_LOG)
string(REGEX
REPLACE ".*ARCH_VALUE ([a-zA-Z0-9_]+).*"
"\\1"
_TARGET_ARCH
"${_COMPILATION_LOG}")
# construct library path
if(_TARGET_ARCH STREQUAL "x86_32")
string(APPEND _PLATFORM_PATH "Win32")
elseif(_TARGET_ARCH STREQUAL "x86_64")
string(APPEND _PLATFORM_PATH "x64")
else()
message(
FATAL_ERROR
"the ${_TARGET_ARCH} architecture is not supported by Findsodium.cmake."
)
endif()
string(APPEND _PLATFORM_PATH "/$$CONFIG$$")
if(MSVC_VERSION LESS 1900)
math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 60")
else()
math(EXPR _VS_VERSION "${MSVC_VERSION} / 10 - 50")
endif()
string(APPEND _PLATFORM_PATH "/v${_VS_VERSION}")
if(sodium_USE_STATIC_LIBS)
string(APPEND _PLATFORM_PATH "/static")
else()
string(APPEND _PLATFORM_PATH "/dynamic")
endif()
string(REPLACE "$$CONFIG$$"
"Debug"
_DEBUG_PATH_SUFFIX
"${_PLATFORM_PATH}")
string(REPLACE "$$CONFIG$$"
"Release"
_RELEASE_PATH_SUFFIX
"${_PLATFORM_PATH}")
find_library(sodium_LIBRARY_DEBUG libsodium.lib
HINTS ${sodium_DIR}
PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX})
find_library(sodium_LIBRARY_RELEASE libsodium.lib
HINTS ${sodium_DIR}
PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX})
if(NOT sodium_USE_STATIC_LIBS)
set(CMAKE_FIND_LIBRARY_SUFFIXES_BCK ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ".dll")
find_library(sodium_DLL_DEBUG libsodium
HINTS ${sodium_DIR}
PATH_SUFFIXES ${_DEBUG_PATH_SUFFIX})
find_library(sodium_DLL_RELEASE libsodium
HINTS ${sodium_DIR}
PATH_SUFFIXES ${_RELEASE_PATH_SUFFIX})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_BCK})
endif()
elseif(_GCC_COMPATIBLE)
if(sodium_USE_STATIC_LIBS)
find_library(sodium_LIBRARY_DEBUG libsodium.a
HINTS ${sodium_DIR}
PATH_SUFFIXES lib)
find_library(sodium_LIBRARY_RELEASE libsodium.a
HINTS ${sodium_DIR}
PATH_SUFFIXES lib)
else()
find_library(sodium_LIBRARY_DEBUG libsodium.dll.a
HINTS ${sodium_DIR}
PATH_SUFFIXES lib)
find_library(sodium_LIBRARY_RELEASE libsodium.dll.a
HINTS ${sodium_DIR}
PATH_SUFFIXES lib)
file(GLOB _DLL
LIST_DIRECTORIES false
RELATIVE "${sodium_DIR}/bin"
"${sodium_DIR}/bin/libsodium*.dll")
find_library(sodium_DLL_DEBUG ${_DLL} libsodium
HINTS ${sodium_DIR}
PATH_SUFFIXES bin)
find_library(sodium_DLL_RELEASE ${_DLL} libsodium
HINTS ${sodium_DIR}
PATH_SUFFIXES bin)
endif()
else()
message(FATAL_ERROR "this platform is not supported by FindSodium.cmake")
endif()
# ############################################################################
# unsupported
else()
message(FATAL_ERROR "this platform is not supported by FindSodium.cmake")
endif()
# ##############################################################################
# common stuff
# extract sodium version
if(sodium_INCLUDE_DIR)
set(_VERSION_HEADER "${sodium_INCLUDE_DIR}/sodium/version.h")
if(EXISTS "${_VERSION_HEADER}")
file(READ "${_VERSION_HEADER}" _VERSION_HEADER_CONTENT)
string(REGEX
REPLACE ".*define[ \t]+SODIUM_VERSION_STRING[^\"]+\"([^\"]+)\".*"
"\\1"
sodium_VERSION_STRING
"${_VERSION_HEADER_CONTENT}")
set(sodium_VERSION_STRING "${sodium_VERSION_STRING}")
endif()
endif()
# communicate results
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(sodium
REQUIRED_VARS
sodium_LIBRARY_RELEASE
sodium_LIBRARY_DEBUG
sodium_INCLUDE_DIR
VERSION_VAR
sodium_VERSION_STRING)
# mark file paths as advanced
mark_as_advanced(sodium_INCLUDE_DIR)
mark_as_advanced(sodium_LIBRARY_DEBUG)
mark_as_advanced(sodium_LIBRARY_RELEASE)
if(WIN32)
mark_as_advanced(sodium_DLL_DEBUG)
mark_as_advanced(sodium_DLL_RELEASE)
endif()
# create imported target
if(sodium_USE_STATIC_LIBS)
set(_LIB_TYPE STATIC)
else()
set(_LIB_TYPE SHARED)
endif()
add_library(sodium ${_LIB_TYPE} IMPORTED)
set_target_properties(sodium
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
"${sodium_INCLUDE_DIR}"
IMPORTED_LINK_INTERFACE_LANGUAGES
"C")
if(sodium_USE_STATIC_LIBS)
set_target_properties(sodium
PROPERTIES INTERFACE_COMPILE_DEFINITIONS
"SODIUM_STATIC"
IMPORTED_LOCATION
"${sodium_LIBRARY_RELEASE}"
IMPORTED_LOCATION_DEBUG
"${sodium_LIBRARY_DEBUG}")
else()
if(UNIX)
set_target_properties(sodium
PROPERTIES IMPORTED_LOCATION
"${sodium_LIBRARY_RELEASE}"
IMPORTED_LOCATION_DEBUG
"${sodium_LIBRARY_DEBUG}")
elseif(WIN32)
set_target_properties(sodium
PROPERTIES IMPORTED_IMPLIB
"${sodium_LIBRARY_RELEASE}"
IMPORTED_IMPLIB_DEBUG
"${sodium_LIBRARY_DEBUG}")
if(NOT (sodium_DLL_DEBUG MATCHES ".*-NOTFOUND"))
set_target_properties(sodium
PROPERTIES IMPORTED_LOCATION_DEBUG
"${sodium_DLL_DEBUG}")
endif()
if(NOT (sodium_DLL_RELEASE MATCHES ".*-NOTFOUND"))
set_target_properties(sodium
PROPERTIES IMPORTED_LOCATION_RELWITHDEBINFO
"${sodium_DLL_RELEASE}"
IMPORTED_LOCATION_MINSIZEREL
"${sodium_DLL_RELEASE}"
IMPORTED_LOCATION_RELEASE
"${sodium_DLL_RELEASE}")
endif()
endif()
endif()

View file

@ -0,0 +1,27 @@
package=abseil
$(package)_version=$(native_$(package)_version)
$(package)_download_path=$(native_$(package)_download_path)
$(package)_download_file=$(native_$(package)_download_file)
$(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash)
$(package)_patches=no_librt.patch
define $(package)_set_vars
$(package)_cxxflags+=-std=c++17
endef
define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/no_librt.patch
endef
define $(package)_config_cmds
$($(package)_cmake)
endef
define $(package)_build_cmds
$(MAKE)
endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef

View file

@ -3,7 +3,6 @@ $(package)_version=1.85.0
$(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version)/source/ $(package)_download_path=https://boostorg.jfrog.io/artifactory/main/release/$($(package)_version)/source/
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz $(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz
$(package)_sha256_hash=be0d91732d5b0cc6fbb275c7939974457e79b54d6f07ce2e3dfdd68bef883b0b $(package)_sha256_hash=be0d91732d5b0cc6fbb275c7939974457e79b54d6f07ce2e3dfdd68bef883b0b
$(package)_dependencies=libiconv
$(package)_patches=disable_addr2line.patch $(package)_patches=disable_addr2line.patch
define $(package)_set_vars define $(package)_set_vars
@ -21,7 +20,8 @@ $(package)_toolset_$(host_os)=gcc
$(package)_archiver_$(host_os)=$($(package)_ar) $(package)_archiver_$(host_os)=$($(package)_ar)
$(package)_toolset_darwin=darwin $(package)_toolset_darwin=darwin
$(package)_archiver_darwin=$($(package)_libtool) $(package)_archiver_darwin=$($(package)_libtool)
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale,stacktrace $(package)_config_libraries_$(host_os)="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,stacktrace"
$(package)_config_libraries_mingw32="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,stacktrace,locale"
$(package)_cxxflags=-std=c++17 $(package)_cxxflags=-std=c++17
$(package)_cxxflags_linux=-fPIC $(package)_cxxflags_linux=-fPIC
$(package)_cxxflags_freebsd=-fPIC $(package)_cxxflags_freebsd=-fPIC
@ -33,7 +33,7 @@ define $(package)_preprocess_cmds
endef endef
define $(package)_config_cmds define $(package)_config_cmds
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries) ./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries_$(host_os))
endef endef
define $(package)_build_cmds define $(package)_build_cmds

View file

@ -1,21 +1,20 @@
package=expat package=expat
$(package)_version=2.6.2 $(package)_version=2.6.3
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_$(subst .,_,$($(package)_version))/ $(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_$(subst .,_,$($(package)_version))/
$(package)_file_name=$(package)-$($(package)_version).tar.xz $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=ee14b4c5d8908b1bec37ad937607eab183d4d9806a08adee472c3c3121d27364 $(package)_sha256_hash=17aa6cfc5c4c219c09287abfc10bc13f0c06f30bb654b28bfe6f567ca646eb79
$(package)_build_subdir=build
# -D_DEFAULT_SOURCE defines __USE_MISC, which exposes additional
# definitions in endian.h, which are required for a working
# endianess check in configure when building with -flto.
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples $(package)_config_opts := -DEXPAT_BUILD_TOOLS=OFF
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking $(package)_config_opts += -DEXPAT_BUILD_EXAMPLES=OFF
$(package)_config_opts += --without-xmlwf --with-pic $(package)_config_opts += -DEXPAT_BUILD_TESTS=OFF
$(package)_cppflags += -D_DEFAULT_SOURCE $(package)_config_opts += -DBUILD_SHARED_LIBS=OFF
$(package)_config_opts += -DCMAKE_POSITION_INDEPENDENT_CODE=ON
endef endef
define $(package)_config_cmds define $(package)_config_cmds
$($(package)_autoconf) $($(package)_cmake) -S .. -B .
endef endef
define $(package)_build_cmds define $(package)_build_cmds
@ -27,5 +26,5 @@ define $(package)_stage_cmds
endef endef
define $(package)_postprocess_cmds define $(package)_postprocess_cmds
rm -rf share lib/cmake lib/*.la rm -rf share lib/cmake
endef endef

View file

@ -1,18 +1,20 @@
package=freetype package=freetype
$(package)_version=2.13.2 $(package)_version=2.13.3
$(package)_download_path=https://sourceforge.net/projects/freetype/files/freetype2/$($(package)_version)/ $(package)_download_path=https://sourceforge.net/projects/freetype/files/freetype2/$($(package)_version)/
$(package)_file_name=freetype-$($(package)_version).tar.xz $(package)_file_name=freetype-$($(package)_version).tar.gz
$(package)_sha256_hash=12991c4e55c506dd7f9b765933e62fd2be2e06d421505d7950a132e4f1bb484d $(package)_sha256_hash=5c3a8e78f7b24c20b25b54ee575d6daa40007a5f4eea2845861c3409b3021747
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts = --without-zlib --without-png --without-harfbuzz --without-bzip2 --enable-static --disable-shared $(package)_config_opts := --without-zlib --without-png --without-harfbuzz --without-bzip2 --enable-static --disable-shared
$(package)_config_opts += --enable-option-checking --without-brotli $(package)_config_opts += --enable-option-checking --without-brotli
$(package)_config_opts += --with-pic $(package)_config_opts += --with-pic
endef endef
define $(package)_preprocess_cmds
rm -rf docs
endef
define $(package)_config_cmds define $(package)_config_cmds
printenv && \
echo "$($(package)_autoconf)" && \
$($(package)_autoconf) $($(package)_autoconf)
endef endef

View file

@ -1,8 +1,8 @@
package=libgcrypt package=libgcrypt
$(package)_version=1.10.3 $(package)_version=1.11.0
$(package)_download_path=https://www.gnupg.org/ftp/gcrypt/libgcrypt/ $(package)_download_path=https://www.gnupg.org/ftp/gcrypt/libgcrypt/
$(package)_file_name=libgcrypt-$($(package)_version).tar.bz2 $(package)_file_name=libgcrypt-$($(package)_version).tar.gz
$(package)_sha256_hash=8b0870897ac5ac67ded568dcfadf45969cfa8a6beb0fd60af2a9eadc2a3272aa $(package)_sha256_hash=2382891207d3b000b20c81dbf2036516a535d31abd80f57d455e711e1dde5ff5
$(package)_dependencies=libgpg-error $(package)_dependencies=libgpg-error
define $(package)_set_vars define $(package)_set_vars
@ -13,16 +13,9 @@ define $(package)_preprocess_cmds
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux
endef endef
# TODO: building on linux with $($(package)_autoconf) fails for mysterious reasons
ifeq ($(host_os),linux)
define $(package)_config_cmds
CFLAGS='-fPIE' CXXFLAGS='-fPIE' ./configure --host=$(host) --enable-digests="sha256 blake2" --enable-ciphers="aes chacha20" --disable-amd64-as-feature-detection --disable-asm --disable-avx-support --disable-avx2-support --disable-sse41-support --disable-shared --enable-static --disable-doc --with-libgpg-error-prefix=$(host_prefix) --prefix=$(host_prefix)
endef
else
define $(package)_config_cmds define $(package)_config_cmds
$($(package)_autoconf) --disable-shared --enable-static --disable-doc --disable-asm --with-libgpg-error-prefix=$(host_prefix) $($(package)_autoconf) --disable-shared --enable-static --disable-doc --disable-asm --with-libgpg-error-prefix=$(host_prefix)
endef endef
endif
define $(package)_build_cmds define $(package)_build_cmds
$(MAKE) $($(package)_build_opts) $(MAKE) $($(package)_build_opts)

View file

@ -1,25 +1,30 @@
package=libgpg-error package=libgpg-error
$(package)_version=1.49 $(package)_version=1.50
$(package)_download_path=https://www.gnupg.org/ftp/gcrypt/libgpg-error/ $(package)_download_path=https://www.gnupg.org/ftp/gcrypt/libgpg-error/
$(package)_file_name=libgpg-error-$($(package)_version).tar.gz $(package)_file_name=libgpg-error-$($(package)_version).tar.gz
$(package)_sha256_hash=e59cc3ced0ae86f49073e2f2344676919a82fc5033716bee7232f6f778158792 $(package)_sha256_hash=34a3b36ec8ad830f8f3ceb5db583d1f6dc8ae4c31d04f6da18ea18dd95396ab0
$(package)_patches=declare_environ_macos.patch
define $(package)_set_vars define $(package)_set_vars
$(package)_build_opts=CFLAGS="-fPIE" $(package)_config_opts := --enable-static --disable-shared
$(package)_config_opts += --disable-doc --disable-tests
$(package)_config_opts += --enable-install-gpg-error-config
$(package)_build_opts := CFLAGS="-fPIE"
endef endef
define $(package)_preprocess_cmds define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/declare_environ_macos.patch && \
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux
endef endef
define $(package)_config_cmds define $(package)_config_cmds
$($(package)_autoconf) --enable-static --disable-shared --enable-install-gpg-error-config $($(package)_autoconf)
endef endef
define $(package)_build_cmds define $(package)_build_cmds
$(MAKE) $($(package)_build_opts) $(MAKE) $($(package)_build_opts)
endef endef
define $(package)_stage_cmds define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install $(MAKE) DESTDIR=$($(package)_staging_dir) install
endef endef

View file

@ -1,29 +0,0 @@
package=libiconv
$(package)_version=1.17
$(package)_download_path=https://ftp.gnu.org/gnu/libiconv
$(package)_file_name=libiconv-$($(package)_version).tar.gz
$(package)_sha256_hash=8f74213b56238c85a50a5329f77e06198771e70dd9a739779f4c02f65d971313
define $(package)_set_vars
$(package)_config_opts=--disable-nls
$(package)_config_opts=--enable-static
$(package)_config_opts=--disable-shared
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_freebsd=--with-pic
endef
define $(package)_config_cmds
$($(package)_autoconf) AR_FLAGS=$($(package)_arflags)
endef
define $(package)_build_cmds
$(MAKE)
endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
define $(package)_postprocess_cmds
rm lib/*.la
endef

View file

@ -1,12 +1,12 @@
package=libxcb_util_cursor package=libxcb_util_cursor
$(package)_version=0.1.4 $(package)_version=0.1.5
$(package)_download_path=https://xcb.freedesktop.org/dist $(package)_download_path=https://xcb.freedesktop.org/dist
$(package)_file_name=xcb-util-cursor-$($(package)_version).tar.gz $(package)_file_name=xcb-util-cursor-$($(package)_version).tar.gz
$(package)_sha256_hash=cc8608ebb695742b6cf84712be29b2b66aa5f6768039528794fca0fa283022bf $(package)_sha256_hash=0e9c5446dc6f3beb8af6ebfcc9e27bcc6da6fe2860f7fc07b99144dfa568e93b
$(package)_dependencies=libxcb libxcb_util_render libxcb_util_image $(package)_dependencies=libxcb libxcb_util_render libxcb_util_image
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--disable-shared --disable-devel-docs --without-doxygen $(package)_config_opts := --disable-shared --disable-devel-docs --without-doxygen
$(package)_config_opts += --disable-dependency-tracking --enable-option-checking $(package)_config_opts += --disable-dependency-tracking --enable-option-checking
endef endef

View file

@ -1,17 +1,33 @@
package=libzip package=libzip
$(package)_version=1.10.1 $(package)_version=1.11.1
$(package)_download_path=https://libzip.org/download/ $(package)_download_path=https://libzip.org/download/
$(package)_file_name=$(package)-$($(package)_version).tar.xz $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=dc3c8d5b4c8bbd09626864f6bcf93de701540f761d76b85d7c7d710f4bd90318 $(package)_sha256_hash=c0e6fa52a62ba11efd30262290dc6970947aef32e0cc294ee50e9005ceac092a
$(package)_dependencies=zlib $(package)_dependencies=zlib
$(package)_patches += no-clonefile.patch
define $(package)_set_vars
$(package)_config_opts := -DENABLE_BZIP2=OFF
$(package)_config_opts += -DENABLE_LZMA=OFF
$(package)_config_opts += -DENABLE_ZSTD=OFF
$(package)_config_opts += -DENABLE_COMMONCRYPTO=OFF
$(package)_config_opts += -DENABLE_GNUTLS=OFF
$(package)_config_opts += -DENABLE_MBEDTLS=OFF
$(package)_config_opts += -DENABLE_OPENSSL=OFF
$(package)_config_opts += -DENABLE_WINDOWS_CRYPTO=OFF
$(package)_config_opts += -DBUILD_SHARED_LIBS=OFF
$(package)_config_opts += -DBUILD_TOOLS=OFF
$(package)_config_opts += -DBUILD_REGRESS=OFF
$(package)_config_opts += -DBUILD_OSSFUZZ=OFF
$(package)_config_opts += -DBUILD_EXAMPLES=OFF
$(package)_config_opts += -DBUILD_DOC=OFF
endef
define $(package)_preprocess_cmds define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/no-clonefile.patch rm -rf regress ossfuzz
endef endef
define $(package)_config_cmds define $(package)_config_cmds
$($(package)_cmake) -DZLIB_ROOT=$(host_prefix) -DENABLE_BZIP2=Off -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=$(host_prefix) . $($(package)_cmake) .
endef endef
define $(package)_build_cmds define $(package)_build_cmds
@ -20,4 +36,4 @@ endef
define $(package)_stage_cmds define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install $(MAKE) DESTDIR=$($(package)_staging_dir) install
endef endef

View file

@ -0,0 +1,18 @@
package=native_abseil
$(package)_version=20240722.0
$(package)_download_path=https://github.com/abseil/abseil-cpp/archive/refs/tags/
$(package)_download_file=$($(package)_version).tar.gz
$(package)_file_name=abseil-$($(package)_version).tar.gz
$(package)_sha256_hash=f50e5ac311a81382da7fa75b97310e4b9006474f9560ac46f54a9967f07d4ae3
define $(package)_config_cmds
$($(package)_cmake)
endef
define $(package)_build_cmds
$(MAKE)
endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef

View file

@ -1,27 +1,34 @@
package=native_protobuf package=native_protobuf
$(package)_version=3.21.12 $(package)_version=28.2
$(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v21.12/ $(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v$($(package)_version)
$(package)_file_name=protobuf-cpp-$($(package)_version).tar.gz $(package)_file_name=protobuf-$($(package)_version).tar.gz
$(package)_sha256_hash=4eab9b524aa5913c6fffb20b2a8abf5ef7f95a80bc0701f3a6dbb4c607f73460 $(package)_sha256_hash=b2340aa47faf7ef10a0328190319d3f3bee1b24f426d4ce8f4253b6f27ce16db
$(package)_cxxflags=-std=c++11 $(package)_dependencies=native_abseil
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--disable-shared --prefix=$(build_prefix) $(package)_cxxflags+=-std=c++17
$(package)_config_opts_linux=--with-pic $(package)_config_opts=-Dprotobuf_BUILD_TESTS=OFF
$(package)_config_opts+=-Dprotobuf_ABSL_PROVIDER=package
$(package)_config_opts+=-Dprotobuf_BUILD_SHARED_LIBS=OFF
$(package)_config_opts+=-Dprotobuf_WITH_ZLIB=OFF
endef
define $(package)_preprocess_cmds
rm -rf docs php/src/GPBMetadata compatibility objectivec/Tests csharp/keys php/tests src/google/protobuf/testdata csharp/src/Google.Protobuf.Test
endef endef
define $(package)_config_cmds define $(package)_config_cmds
$($(package)_autoconf) $($(package)_cmake)
endef endef
define $(package)_build_cmds define $(package)_build_cmds
$(MAKE) -C src protoc $(MAKE)
endef endef
define $(package)_stage_cmds define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-binPROGRAMS install-nobase_dist_protoDATA $(MAKE) DESTDIR=$($(package)_staging_dir) install
endef endef
define $(package)_postprocess_cmds define $(package)_postprocess_cmds
rm -rf lib/ rm -rf lib64
endef endef

View file

@ -1,9 +1,9 @@
package=native_qt package=native_qt
$(package)_version=6.7.2 $(package)_version=6.7.3
$(package)_download_path=https://download.qt.io/official_releases/qt/6.7/$($(package)_version)/submodules $(package)_download_path=https://download.qt.io/official_releases/qt/6.7/$($(package)_version)/submodules
$(package)_suffix=everywhere-src-$($(package)_version).tar.xz $(package)_suffix=everywhere-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix) $(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 $(package)_sha256_hash=8ccbb9ab055205ac76632c9eeddd1ed6fc66936fc56afc2ed0fd5d9e23da3097
$(package)_qt_libs=corelib network widgets gui plugins testlib $(package)_qt_libs=corelib network widgets gui plugins testlib
$(package)_patches = dont_hardcode_pwd.patch $(package)_patches = dont_hardcode_pwd.patch
$(package)_patches += fast_fixed_dtoa_no_optimize.patch $(package)_patches += fast_fixed_dtoa_no_optimize.patch
@ -13,16 +13,16 @@ $(package)_patches += rcc_hardcode_timestamp.patch
$(package)_patches += root_CMakeLists.txt $(package)_patches += root_CMakeLists.txt
$(package)_qttools_file_name=qttools-$($(package)_suffix) $(package)_qttools_file_name=qttools-$($(package)_suffix)
$(package)_qttools_sha256_hash=58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a $(package)_qttools_sha256_hash=f03bb7df619cd9ac9dba110e30b7bcab5dd88eb8bdc9cc752563b4367233203f
$(package)_qtsvg_file_name=qtsvg-$($(package)_suffix) $(package)_qtsvg_file_name=qtsvg-$($(package)_suffix)
$(package)_qtsvg_sha256_hash=fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 $(package)_qtsvg_sha256_hash=40142cb71fb1e07ad612bc361b67f5d54cd9367f9979ae6b86124a064deda06b
$(package)_qtmultimedia_file_name=qtmultimedia-$($(package)_suffix) $(package)_qtmultimedia_file_name=qtmultimedia-$($(package)_suffix)
$(package)_qtmultimedia_sha256_hash=8ef835115acb9a1d3d2c9f23cfacb43f2c537e3786a8ab822299a2a7765651d3 $(package)_qtmultimedia_sha256_hash=304d28b8e592435293893b0110d5f3534407604d1e04d8a0b0e5b34afe577303
$(package)_qtshadertools_file_name=qtshadertools-$($(package)_suffix) $(package)_qtshadertools_file_name=qtshadertools-$($(package)_suffix)
$(package)_qtshadertools_sha256_hash=edfa34c0ac8c00fcaa949df1d8e7a77d89dadd6386e683ce6c3e3b117e2f7cc1 $(package)_qtshadertools_sha256_hash=74e512798c7ddbda354a2d8d975211454bbabb47afb7e598892067a5828c0995
$(package)_extra_sources += $($(package)_qttools_file_name) $(package)_extra_sources += $($(package)_qttools_file_name)
$(package)_extra_sources += $($(package)_qtsvg_file_name) $(package)_extra_sources += $($(package)_qtsvg_file_name)

View file

@ -1,5 +1,5 @@
packages := boost openssl libiconv unbound qrencode libsodium polyseed hidapi protobuf libusb zlib libgpg-error libgcrypt expat libzip zxing-cpp libarchive packages := boost openssl unbound qrencode libsodium polyseed hidapi abseil protobuf libusb zlib libgpg-error libgcrypt expat libzip zxing-cpp
native_packages := native_qt native_protobuf native_packages := native_qt native_abseil native_protobuf
linux_packages := eudev libfuse libsquashfuse zstd appimage_runtime linux_packages := eudev libfuse libsquashfuse zstd appimage_runtime
linux_native_packages = linux_native_packages =

View file

@ -3,27 +3,30 @@ $(package)_version=$(native_$(package)_version)
$(package)_download_path=$(native_$(package)_download_path) $(package)_download_path=$(native_$(package)_download_path)
$(package)_file_name=$(native_$(package)_file_name) $(package)_file_name=$(native_$(package)_file_name)
$(package)_sha256_hash=$(native_$(package)_sha256_hash) $(package)_sha256_hash=$(native_$(package)_sha256_hash)
$(package)_dependencies=native_$(package) $(package)_dependencies=abseil
$(package)_cxxflags=-std=c++11
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc $(package)_cxxflags+=-std=c++17
$(package)_config_opts_linux=--with-pic $(package)_config_opts=-Dprotobuf_ABSL_PROVIDER=package
$(package)_config_opts+=-Dprotobuf_BUILD_TESTS=OFF
$(package)_config_opts+=-Dprotobuf_BUILD_SHARED_LIBS=OFF
$(package)_config_opts+=-Dprotobuf_BUILD_PROTOC_BINARIES=OFF
$(package)_config_opts+=-Dprotobuf_WITH_ZLIB=OFF
$(package)_config_opts+=-Dprotobuf_BUILD_LIBUPB=OFF
endef
define $(package)_preprocess_cmds
rm -rf docs php/src/GPBMetadata compatibility objectivec/Tests csharp/keys php/tests src/google/protobuf/testdata csharp/src/Google.Protobuf.Test
endef endef
define $(package)_config_cmds define $(package)_config_cmds
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . && \ $($(package)_cmake)
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub ./third_party/googletest/googletest/build-aux/ && \
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub ./third_party/googletest/googlemock/build-aux/ && \
$($(package)_autoconf)
endef endef
define $(package)_build_cmds define $(package)_build_cmds
$(MAKE) -C src libprotobuf.la $(MAKE)
endef endef
define $(package)_stage_cmds define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-nobase_includeHEADERS &&\ $(MAKE) DESTDIR=$($(package)_staging_dir) install
$(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA &&\
cp -f src/.libs/libprotobuf.a $($(package)_staging_prefix_dir)/lib/
endef endef

View file

@ -1,9 +1,9 @@
package=qt package=qt
$(package)_version=6.7.2 $(package)_version=6.7.3
$(package)_download_path=https://download.qt.io/official_releases/qt/6.7/$($(package)_version)/submodules $(package)_download_path=https://download.qt.io/official_releases/qt/6.7/$($(package)_version)/submodules
$(package)_suffix=everywhere-src-$($(package)_version).tar.xz $(package)_suffix=everywhere-src-$($(package)_version).tar.xz
$(package)_file_name=qtbase-$($(package)_suffix) $(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=c5f22a5e10fb162895ded7de0963328e7307611c688487b5d152c9ee64767599 $(package)_sha256_hash=8ccbb9ab055205ac76632c9eeddd1ed6fc66936fc56afc2ed0fd5d9e23da3097
$(package)_darwin_dependencies=native_cctools native_qt openssl $(package)_darwin_dependencies=native_cctools native_qt openssl
$(package)_mingw32_dependencies=openssl native_qt $(package)_mingw32_dependencies=openssl native_qt
$(package)_linux_dependencies=openssl native_qt freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm libxcb_util_cursor dbus $(package)_linux_dependencies=openssl native_qt freetype fontconfig libxcb libxkbcommon libxcb_util libxcb_util_render libxcb_util_keysyms libxcb_util_image libxcb_util_wm libxcb_util_cursor dbus
@ -22,23 +22,22 @@ $(package)_patches += revert-macOS-Silence-warning-about-supporting-secure.patch
$(package)_patches += no-resonance-audio.patch $(package)_patches += no-resonance-audio.patch
$(package)_patches += fix_static_qt_darwin_camera_permissions.patch $(package)_patches += fix_static_qt_darwin_camera_permissions.patch
$(package)_patches += revert-f67ee7c39.patch $(package)_patches += revert-f67ee7c39.patch
$(package)_patches += CVE-2024-39936.patch
#$(package)_patches += fix-static-fontconfig-static-linking.patch #$(package)_patches += fix-static-fontconfig-static-linking.patch
$(package)_qttools_file_name=qttools-$($(package)_suffix) $(package)_qttools_file_name=qttools-$($(package)_suffix)
$(package)_qttools_sha256_hash=58e855ad1b2533094726c8a425766b63a04a0eede2ed85086860e54593aa4b2a $(package)_qttools_sha256_hash=f03bb7df619cd9ac9dba110e30b7bcab5dd88eb8bdc9cc752563b4367233203f
$(package)_qtsvg_file_name=qtsvg-$($(package)_suffix) $(package)_qtsvg_file_name=qtsvg-$($(package)_suffix)
$(package)_qtsvg_sha256_hash=fb0d1286a35be3583fee34aeb5843c94719e07193bdf1d4d8b0dc14009caef01 $(package)_qtsvg_sha256_hash=40142cb71fb1e07ad612bc361b67f5d54cd9367f9979ae6b86124a064deda06b
$(package)_qtwebsockets_file_name=qtwebsockets-$($(package)_suffix) $(package)_qtwebsockets_file_name=qtwebsockets-$($(package)_suffix)
$(package)_qtwebsockets_sha256_hash=5bde4af6ec9ce8c8632b782ab77b82d910721be2c714e6d38902521bcd1d215f $(package)_qtwebsockets_sha256_hash=ba03007db7ee68a5bc3e3bd1d71e11f3e1f84e470bcb8c54cd7c01bbe1c5990e
$(package)_qtmultimedia_file_name=qtmultimedia-$($(package)_suffix) $(package)_qtmultimedia_file_name=qtmultimedia-$($(package)_suffix)
$(package)_qtmultimedia_sha256_hash=8ef835115acb9a1d3d2c9f23cfacb43f2c537e3786a8ab822299a2a7765651d3 $(package)_qtmultimedia_sha256_hash=304d28b8e592435293893b0110d5f3534407604d1e04d8a0b0e5b34afe577303
$(package)_qtshadertools_file_name=qtshadertools-$($(package)_suffix) $(package)_qtshadertools_file_name=qtshadertools-$($(package)_suffix)
$(package)_qtshadertools_sha256_hash=edfa34c0ac8c00fcaa949df1d8e7a77d89dadd6386e683ce6c3e3b117e2f7cc1 $(package)_qtshadertools_sha256_hash=74e512798c7ddbda354a2d8d975211454bbabb47afb7e598892067a5828c0995
$(package)_extra_sources += $($(package)_qttools_file_name) $(package)_extra_sources += $($(package)_qttools_file_name)
$(package)_extra_sources += $($(package)_qtsvg_file_name) $(package)_extra_sources += $($(package)_qtsvg_file_name)
@ -55,7 +54,6 @@ $(package)_config_opts += -DINSTALL_LIBEXECDIR=$(build_prefix)/bin
$(package)_config_opts += -DQT_BUILD_EXAMPLES=FALSE $(package)_config_opts += -DQT_BUILD_EXAMPLES=FALSE
$(package)_config_opts += -DQT_BUILD_TESTS=FALSE $(package)_config_opts += -DQT_BUILD_TESTS=FALSE
$(package)_config_opts += -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake $(package)_config_opts += -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
$(package)_config_opts += -DINPUT_cups=no $(package)_config_opts += -DINPUT_cups=no
$(package)_config_opts += -DINPUT_egl=no $(package)_config_opts += -DINPUT_egl=no
$(package)_config_opts += -DINPUT_eglfs=no $(package)_config_opts += -DINPUT_eglfs=no
@ -200,7 +198,6 @@ define $(package)_preprocess_cmds
patch -p1 -i $($(package)_patch_dir)/libxau-fix.patch && \ patch -p1 -i $($(package)_patch_dir)/libxau-fix.patch && \
patch -p1 -i $($(package)_patch_dir)/revert-macOS-Silence-warning-about-supporting-secure.patch && \ patch -p1 -i $($(package)_patch_dir)/revert-macOS-Silence-warning-about-supporting-secure.patch && \
patch -p1 -i $($(package)_patch_dir)/fix_static_qt_darwin_camera_permissions.patch && \ patch -p1 -i $($(package)_patch_dir)/fix_static_qt_darwin_camera_permissions.patch && \
patch -p1 -i $($(package)_patch_dir)/CVE-2024-39936.patch && \
cd ../qtmultimedia && \ cd ../qtmultimedia && \
patch -p1 -i $($(package)_patch_dir)/qtmultimedia-fixes.patch && \ patch -p1 -i $($(package)_patch_dir)/qtmultimedia-fixes.patch && \
patch -p1 -i $($(package)_patch_dir)/v4l2.patch && \ patch -p1 -i $($(package)_patch_dir)/v4l2.patch && \

View file

@ -4,6 +4,7 @@ $(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=e7dca7d6b0f81bdfa6fa64ebf1053b5a999a5ae9278a87ef182425067ea14521 $(package)_sha256_hash=e7dca7d6b0f81bdfa6fa64ebf1053b5a999a5ae9278a87ef182425067ea14521
$(package)_dependencies=openssl expat $(package)_dependencies=openssl expat
$(package)_patches += CVE-2024-8508.patch
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) $(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix)
@ -18,6 +19,7 @@ endef
define $(package)_preprocess_cmds define $(package)_preprocess_cmds
rm configure~ doc/IP-BasedActions.pdf doc/ietf67-design-02.odp doc/ietf67-design-02.pdf doc/CNAME-basedRedirectionDesignNotes.pdf &&\ rm configure~ doc/IP-BasedActions.pdf doc/ietf67-design-02.odp doc/ietf67-design-02.pdf doc/CNAME-basedRedirectionDesignNotes.pdf &&\
rm -rf testdata dnscrypt/testdata &&\ rm -rf testdata dnscrypt/testdata &&\
patch -p1 -i $($(package)_patch_dir)/CVE-2024-8508.patch && \
autoconf autoconf
endef endef

View file

@ -1,28 +1,23 @@
package=utf8proc package=utf8proc
$(package)_version=2.8.0 $(package)_version=2.9.0
$(package)_download_path=https://github.com/JuliaStrings/utf8proc/archive/refs/tags/ $(package)_download_path=https://github.com/JuliaStrings/utf8proc/releases/download/v$($(package)_version)/
$(package)_download_file=v$($(package)_version).tar.gz
$(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=a0a60a79fe6f6d54e7d411facbfcc867a6e198608f2cd992490e46f04b1bcecc $(package)_sha256_hash=bd215d04313b5bc42c1abedbcb0a6574667e31acee1085543a232204e36384c4
$(package)_patches=force_static.patch $(package)_patches=force_static.patch
$(package)_build_subdir=build
define $(package)_preprocess_cmds define $(package)_preprocess_cmds
patch -p1 < $($(package)_patch_dir)/force_static.patch patch -p1 < $($(package)_patch_dir)/force_static.patch
endef endef
define $(package)_config_cmds define $(package)_config_cmds
echo "$($(package)_cmake)" && \ $($(package)_cmake) -S .. -B .
mkdir build && \
cd build && \
$($(package)_cmake) ..
endef endef
define $(package)_build_cmds define $(package)_build_cmds
cd build && \ $(MAKE)
$(MAKE)
endef endef
define $(package)_stage_cmds define $(package)_stage_cmds
cd build && \ $(MAKE) DESTDIR=$($(package)_staging_dir) install
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef endef

View file

@ -0,0 +1,12 @@
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 97994fc6..06ab426c 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -240,7 +240,6 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS}
LINKOPTS
${ABSL_DEFAULT_LINKOPTS}
- $<$<BOOL:${LIBRT}>:-lrt>
$<$<BOOL:${MINGW}>:-ladvapi32>
DEPS
absl::atomic_hook

View file

@ -13,6 +13,7 @@ endian = 'little'
[project options] [project options]
utils = false utils = false
examples = false
[built-in options] [built-in options]
default_library = 'static' default_library = 'static'

View file

@ -0,0 +1,20 @@
Subject: [PATCH] core: Declare environ for macOS and others.
---
Index: src/spawn-posix.c
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/spawn-posix.c b/src/spawn-posix.c
--- a/src/spawn-posix.c (revision d18e28a948307fab016b1eed467a70653ca9576e)
+++ b/src/spawn-posix.c (revision a59e902b887fd92337c9728f668cf9c89da3957a)
@@ -57,6 +57,9 @@
#include "gpgrt-int.h"
+/* (Only glibc's unistd.h declares this iff _GNU_SOURCE is used.) */
+extern char **environ;
+
/* Definition for the gpgrt_spawn_actions_t. Note that there is a
* different one for Windows. */

View file

@ -1,13 +0,0 @@
diff --git a/preload/configure b/preload/configure
index aab5c77..e20b8f0 100755
--- a/preload/configure
+++ b/preload/configure
@@ -588,7 +588,7 @@ MAKEFLAGS=
PACKAGE_NAME='libiconv'
PACKAGE_TARNAME='libiconv'
PACKAGE_VERSION='0'
-PACKAGE_STRING='libiconv 0'
+PACKAGE_STRING='libiconv0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''

View file

@ -1,10 +0,0 @@
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -99,7 +99,6 @@ check_function_exists(_strtoi64 HAVE__STRTOI64)
check_function_exists(_strtoui64 HAVE__STRTOUI64)
check_function_exists(_unlink HAVE__UNLINK)
check_function_exists(arc4random HAVE_ARC4RANDOM)
-check_function_exists(clonefile HAVE_CLONEFILE)
check_function_exists(explicit_bzero HAVE_EXPLICIT_BZERO)
check_function_exists(explicit_memset HAVE_EXPLICIT_MEMSET)
check_function_exists(fchmod HAVE_FCHMOD)

View file

@ -1,235 +0,0 @@
From 2b1e36e183ce75c224305c7a94457b92f7a5cf58 Mon Sep 17 00:00:00 2001
From: Mårten Nordheim <marten.nordheim@qt.io>
Date: Tue, 25 Jun 2024 17:09:35 +0200
Subject: [PATCH] HTTP2: Delay any communication until encrypted() can be responded to
We have the encrypted() signal that lets users do extra checks on the
established connection. It is emitted as BlockingQueued, so the HTTP
thread stalls until it is done emitting. Users can potentially call
abort() on the QNetworkReply at that point, which is passed as a Queued
call back to the HTTP thread. That means that any currently queued
signal emission will be processed before the abort() call is processed.
In the case of HTTP2 it is a little special since it is multiplexed and
the code is built to start requests as they are available. This means
that, while the code worked fine for HTTP1, since one connection only
has one request, it is not working for HTTP2, since we try to send more
requests in-between the encrypted() signal and the abort() call.
This patch changes the code to delay any communication until the
encrypted() signal has been emitted and processed, for HTTP2 only.
It's done by adding a few booleans, both to know that we have to return
early and so we can keep track of what events arose and what we need to
resume once enough time has passed that any abort() call must have been
processed.
Fixes: QTBUG-126610
Pick-to: 6.5 6.2 5.15 5.12
Change-Id: Ic25a600c278203256e35f541026f34a8783235ae
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit b1e75376cc3adfc7da5502a277dfe9711f3e0536)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
(cherry picked from commit 0fb43e4395da34d561814242a0186999e4956e28)
---
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 0abd99b..3631b13 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -303,12 +303,12 @@
}
}
- if (!prefaceSent && !sendClientPreface())
- return false;
-
if (!requests.size())
return true;
+ if (!prefaceSent && !sendClientPreface())
+ return false;
+
m_channel->state = QHttpNetworkConnectionChannel::WritingState;
// Check what was promised/pushed, maybe we do not have to send a request
// and have a response already?
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 6766989..1e4161d 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -209,6 +209,10 @@
bool QHttpNetworkConnectionChannel::sendRequest()
{
Q_ASSERT(protocolHandler);
+ if (waitingForPotentialAbort) {
+ needInvokeSendRequest = true;
+ return false; // this return value is unused
+ }
return protocolHandler->sendRequest();
}
@@ -221,21 +225,28 @@
void QHttpNetworkConnectionChannel::sendRequestDelayed()
{
QMetaObject::invokeMethod(this, [this] {
- Q_ASSERT(protocolHandler);
if (reply)
- protocolHandler->sendRequest();
+ sendRequest();
}, Qt::ConnectionType::QueuedConnection);
}
void QHttpNetworkConnectionChannel::_q_receiveReply()
{
Q_ASSERT(protocolHandler);
+ if (waitingForPotentialAbort) {
+ needInvokeReceiveReply = true;
+ return;
+ }
protocolHandler->_q_receiveReply();
}
void QHttpNetworkConnectionChannel::_q_readyRead()
{
Q_ASSERT(protocolHandler);
+ if (waitingForPotentialAbort) {
+ needInvokeReadyRead = true;
+ return;
+ }
protocolHandler->_q_readyRead();
}
@@ -1239,7 +1250,18 @@
if (!h2RequestsToSend.isEmpty()) {
// Similar to HTTP/1.1 counterpart below:
const auto &pair = std::as_const(h2RequestsToSend).first();
+ waitingForPotentialAbort = true;
emit pair.second->encrypted();
+
+ // We don't send or handle any received data until any effects from
+ // emitting encrypted() have been processed. This is necessary
+ // because the user may have called abort(). We may also abort the
+ // whole connection if the request has been aborted and there is
+ // no more requests to send.
+ QMetaObject::invokeMethod(this,
+ &QHttpNetworkConnectionChannel::checkAndResumeCommunication,
+ Qt::QueuedConnection);
+
// In case our peer has sent us its settings (window size, max concurrent streams etc.)
// let's give _q_receiveReply a chance to read them first ('invokeMethod', QueuedConnection).
}
@@ -1257,6 +1279,28 @@
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
+
+void QHttpNetworkConnectionChannel::checkAndResumeCommunication()
+{
+ Q_ASSERT(connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2
+ || connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2Direct);
+
+ // Because HTTP/2 requires that we send a SETTINGS frame as the first thing we do, and respond
+ // to a SETTINGS frame with an ACK, we need to delay any handling until we can ensure that any
+ // effects from emitting encrypted() have been processed.
+ // This function is called after encrypted() was emitted, so check for changes.
+
+ if (!reply && h2RequestsToSend.isEmpty())
+ abort();
+ waitingForPotentialAbort = false;
+ if (needInvokeReadyRead)
+ _q_readyRead();
+ if (needInvokeReceiveReply)
+ _q_receiveReply();
+ if (needInvokeSendRequest)
+ sendRequest();
+}
+
void QHttpNetworkConnectionChannel::requeueHttp2Requests()
{
const auto h2RequestsToSendCopy = std::exchange(h2RequestsToSend, {});
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index c42290f..061f20f 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -74,6 +74,10 @@
QAbstractSocket *socket;
bool ssl;
bool isInitialized;
+ bool waitingForPotentialAbort = false;
+ bool needInvokeReceiveReply = false;
+ bool needInvokeReadyRead = false;
+ bool needInvokeSendRequest = false;
ChannelState state;
QHttpNetworkRequest request; // current request, only used for HTTP
QHttpNetworkReply *reply; // current reply for this request, only used for HTTP
@@ -146,6 +150,8 @@
void closeAndResendCurrentRequest();
void resendCurrentRequest();
+ void checkAndResumeCommunication();
+
bool isSocketBusy() const;
bool isSocketWriting() const;
bool isSocketWaiting() const;
diff --git a/tests/auto/network/access/http2/tst_http2.cpp b/tests/auto/network/access/http2/tst_http2.cpp
index 00efbc9..c02e7b7 100644
--- a/tests/auto/network/access/http2/tst_http2.cpp
+++ b/tests/auto/network/access/http2/tst_http2.cpp
@@ -106,6 +106,8 @@
void duplicateRequestsWithAborts();
+ void abortOnEncrypted();
+
protected slots:
// Slots to listen to our in-process server:
void serverStarted(quint16 port);
@@ -1479,6 +1481,48 @@
QCOMPARE(finishedCount, ExpectedSuccessfulRequests);
}
+void tst_Http2::abortOnEncrypted()
+{
+#if !QT_CONFIG(ssl)
+ QSKIP("TLS support is needed for this test");
+#else
+ clearHTTP2State();
+ serverPort = 0;
+
+ ServerPtr targetServer(newServer(defaultServerSettings, H2Type::h2Direct));
+
+ QMetaObject::invokeMethod(targetServer.data(), "startServer", Qt::QueuedConnection);
+ runEventLoop();
+
+ nRequests = 1;
+ nSentRequests = 0;
+
+ const auto url = requestUrl(H2Type::h2Direct);
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::Http2DirectAttribute, true);
+
+ std::unique_ptr<QNetworkReply> reply{manager->get(request)};
+ reply->ignoreSslErrors();
+ connect(reply.get(), &QNetworkReply::encrypted, reply.get(), [reply = reply.get()](){
+ reply->abort();
+ });
+ connect(reply.get(), &QNetworkReply::errorOccurred, this, &tst_Http2::replyFinishedWithError);
+
+ runEventLoop();
+ STOP_ON_FAILURE
+
+ QCOMPARE(nRequests, 0);
+ QCOMPARE(reply->error(), QNetworkReply::OperationCanceledError);
+
+ const bool res = QTest::qWaitFor(
+ [this, server = targetServer.get()]() {
+ return serverGotSettingsACK || prefaceOK || nSentRequests > 0;
+ },
+ 500);
+ QVERIFY(!res);
+#endif // QT_CONFIG(ssl)
+}
+
void tst_Http2::serverStarted(quint16 port)
{
serverPort = port;

View file

@ -0,0 +1,236 @@
diff --git a/util/data/msgencode.c b/util/data/msgencode.c
index 898ff841..6d116fb5 100644
--- a/util/data/msgencode.c
+++ b/util/data/msgencode.c
@@ -62,6 +62,10 @@
#define RETVAL_TRUNC -4
/** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
#define RETVAL_OK 0
+/** Max compressions we are willing to perform; more than that will result
+ * in semi-compressed messages, or truncated even on TCP for huge messages, to
+ * avoid locking the CPU for long */
+#define MAX_COMPRESSION_PER_MESSAGE 120
/**
* Data structure to help domain name compression in outgoing messages.
@@ -284,15 +288,17 @@ write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs,
/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
static int
-compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
- struct regional* region, struct compress_tree_node** tree,
- size_t owner_pos, uint16_t* owner_ptr, int owner_labs)
+compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
+ struct regional* region, struct compress_tree_node** tree,
+ size_t owner_pos, uint16_t* owner_ptr, int owner_labs,
+ size_t* compress_count)
{
struct compress_tree_node* p;
struct compress_tree_node** insertpt = NULL;
if(!*owner_ptr) {
/* compress first time dname */
- if((p = compress_tree_lookup(tree, key->rk.dname,
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ (p = compress_tree_lookup(tree, key->rk.dname,
owner_labs, &insertpt))) {
if(p->labs == owner_labs)
/* avoid ptr chains, since some software is
@@ -301,6 +307,7 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
if(!write_compressed_dname(pkt, key->rk.dname,
owner_labs, p))
return RETVAL_TRUNC;
+ (*compress_count)++;
/* check if typeclass+4 ttl + rdatalen is available */
if(sldns_buffer_remaining(pkt) < 4+4+2)
return RETVAL_TRUNC;
@@ -313,7 +320,8 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
if(owner_pos <= PTR_MAX_OFFSET)
*owner_ptr = htons(PTR_CREATE(owner_pos));
}
- if(!compress_tree_store(key->rk.dname, owner_labs,
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ !compress_tree_store(key->rk.dname, owner_labs,
owner_pos, region, p, insertpt))
return RETVAL_OUTMEM;
} else {
@@ -333,20 +341,24 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
/** compress any domain name to the packet, return RETVAL_* */
static int
-compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
- struct regional* region, struct compress_tree_node** tree)
+compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
+ struct regional* region, struct compress_tree_node** tree,
+ size_t* compress_count)
{
struct compress_tree_node* p;
struct compress_tree_node** insertpt = NULL;
size_t pos = sldns_buffer_position(pkt);
- if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ (p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
if(!write_compressed_dname(pkt, dname, labs, p))
return RETVAL_TRUNC;
+ (*compress_count)++;
} else {
if(!dname_buffer_write(pkt, dname))
return RETVAL_TRUNC;
}
- if(!compress_tree_store(dname, labs, pos, region, p, insertpt))
+ if(*compress_count < MAX_COMPRESSION_PER_MESSAGE &&
+ !compress_tree_store(dname, labs, pos, region, p, insertpt))
return RETVAL_OUTMEM;
return RETVAL_OK;
}
@@ -364,9 +376,9 @@ type_rdata_compressable(struct ub_packed_rrset_key* key)
/** compress domain names in rdata, return RETVAL_* */
static int
-compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
- struct regional* region, struct compress_tree_node** tree,
- const sldns_rr_descriptor* desc)
+compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
+ struct regional* region, struct compress_tree_node** tree,
+ const sldns_rr_descriptor* desc, size_t* compress_count)
{
int labs, r, rdf = 0;
size_t dname_len, len, pos = sldns_buffer_position(pkt);
@@ -380,8 +392,8 @@ compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
switch(desc->_wireformat[rdf]) {
case LDNS_RDF_TYPE_DNAME:
labs = dname_count_size_labels(rdata, &dname_len);
- if((r=compress_any_dname(rdata, pkt, labs, region,
- tree)) != RETVAL_OK)
+ if((r=compress_any_dname(rdata, pkt, labs, region,
+ tree, compress_count)) != RETVAL_OK)
return r;
rdata += dname_len;
todolen -= dname_len;
@@ -449,7 +461,8 @@ static int
packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
uint16_t* num_rrs, time_t timenow, struct regional* region,
int do_data, int do_sig, struct compress_tree_node** tree,
- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
+ size_t* compress_count)
{
size_t i, j, owner_pos;
int r, owner_labs;
@@ -477,9 +490,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
for(i=0; i<data->count; i++) {
/* rrset roundrobin */
j = (i + rr_offset) % data->count;
- if((r=compress_owner(key, pkt, region, tree,
- owner_pos, &owner_ptr, owner_labs))
- != RETVAL_OK)
+ if((r=compress_owner(key, pkt, region, tree,
+ owner_pos, &owner_ptr, owner_labs,
+ compress_count)) != RETVAL_OK)
return r;
sldns_buffer_write(pkt, &key->rk.type, 2);
sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
@@ -489,8 +502,8 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
else sldns_buffer_write_u32(pkt, data->rr_ttl[j]-adjust);
if(c) {
if((r=compress_rdata(pkt, data->rr_data[j],
- data->rr_len[j], region, tree, c))
- != RETVAL_OK)
+ data->rr_len[j], region, tree, c,
+ compress_count)) != RETVAL_OK)
return r;
} else {
if(sldns_buffer_remaining(pkt) < data->rr_len[j])
@@ -510,9 +523,9 @@ packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
return RETVAL_TRUNC;
sldns_buffer_write(pkt, &owner_ptr, 2);
} else {
- if((r=compress_any_dname(key->rk.dname,
- pkt, owner_labs, region, tree))
- != RETVAL_OK)
+ if((r=compress_any_dname(key->rk.dname,
+ pkt, owner_labs, region, tree,
+ compress_count)) != RETVAL_OK)
return r;
if(sldns_buffer_remaining(pkt) <
4+4+data->rr_len[i])
@@ -544,7 +557,8 @@ static int
insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
sldns_buffer* pkt, size_t rrsets_before, time_t timenow,
struct regional* region, struct compress_tree_node** tree,
- sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset,
+ size_t* compress_count)
{
int r;
size_t i, setstart;
@@ -560,7 +574,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
setstart = sldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 1, 1, tree,
- s, qtype, dnssec, rr_offset))
+ s, qtype, dnssec, rr_offset, compress_count))
!= RETVAL_OK) {
/* Bad, but if due to size must set TC bit */
/* trim off the rrset neatly. */
@@ -573,7 +587,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
setstart = sldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 1, 0, tree,
- s, qtype, dnssec, rr_offset))
+ s, qtype, dnssec, rr_offset, compress_count))
!= RETVAL_OK) {
sldns_buffer_set_position(pkt, setstart);
return r;
@@ -584,7 +598,7 @@ insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
setstart = sldns_buffer_position(pkt);
if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
pkt, num_rrs, timenow, region, 0, 1, tree,
- s, qtype, dnssec, rr_offset))
+ s, qtype, dnssec, rr_offset, compress_count))
!= RETVAL_OK) {
sldns_buffer_set_position(pkt, setstart);
return r;
@@ -677,6 +691,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
struct compress_tree_node* tree = 0;
int r;
size_t rr_offset;
+ size_t compress_count=0;
sldns_buffer_clear(buffer);
if(udpsize < sldns_buffer_limit(buffer))
@@ -723,7 +738,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
arep.rrsets = &qinfo->local_alias->rrset;
if((r=insert_section(&arep, 1, &ancount, buffer, 0,
timezero, region, &tree, LDNS_SECTION_ANSWER,
- qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) {
+ qinfo->qtype, dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
sldns_buffer_write_u16_at(buffer, 6, ancount);
@@ -738,7 +753,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
/* insert answer section */
if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
- dnssec, rr_offset)) != RETVAL_OK) {
+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
sldns_buffer_write_u16_at(buffer, 6, ancount);
@@ -756,7 +771,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
rep->an_numrrsets, timenow, region, &tree,
LDNS_SECTION_AUTHORITY, qinfo->qtype,
- dnssec, rr_offset)) != RETVAL_OK) {
+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
sldns_buffer_write_u16_at(buffer, 8, nscount);
@@ -773,7 +788,7 @@ reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
&tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
- dnssec, rr_offset)) != RETVAL_OK) {
+ dnssec, rr_offset, &compress_count)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* no need to set TC bit, this is the additional */
sldns_buffer_write_u16_at(buffer, 10, arcount);

View file

@ -40,6 +40,9 @@ SET(Terminfo_LIBRARY @prefix@/lib/libtinfo.a)
SET(UNBOUND_INCLUDE_DIR @prefix@/include) SET(UNBOUND_INCLUDE_DIR @prefix@/include)
SET(UNBOUND_LIBRARIES @prefix@/lib/libunbound.a) SET(UNBOUND_LIBRARIES @prefix@/lib/libunbound.a)
SET(CMAKE_FIND_USE_PACKAGE_ROOT_PATH ON)
SET(absl_ROOT @prefix@)
SET(NATIVE_BIN_PATH @prefix@/native/bin CACHE FILEPATH "path to native binaries" FORCE) SET(NATIVE_BIN_PATH @prefix@/native/bin CACHE FILEPATH "path to native binaries" FORCE)
SET(LRELEASE_PATH @prefix@/native/bin CACHE FILEPATH "path to lrelease" FORCE) SET(LRELEASE_PATH @prefix@/native/bin CACHE FILEPATH "path to lrelease" FORCE)
@ -52,17 +55,10 @@ if(NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a) SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a)
SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a) SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a)
SET(Protobuf_FOUND 1)
SET(Protobuf_PROTOC_EXECUTABLE @prefix@/native/bin/protoc CACHE FILEPATH "Path to the native protoc")
SET(Protobuf_INCLUDE_DIR @prefix@/include CACHE PATH "Protobuf include dir")
SET(Protobuf_INCLUDE_DIRS @prefix@/include CACHE PATH "Protobuf include dir")
SET(Protobuf_LIBRARY @prefix@/lib/libprotobuf.a CACHE FILEPATH "Protobuf library")
endif() endif()
endif() endif()
set(ICONV_LIBRARIES @prefix@/lib/libiconv.a)
SET(ZMQ_INCLUDE_PATH @prefix@/include) SET(ZMQ_INCLUDE_PATH @prefix@/include)
SET(ZMQ_LIB @prefix@/lib/libzmq.a) SET(ZMQ_LIB @prefix@/lib/libzmq.a)
@ -123,22 +119,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
SET(CMAKE_CXX_STANDARD 17) SET(CMAKE_CXX_STANDARD 17)
SET(LLVM_ENABLE_PIC OFF) SET(LLVM_ENABLE_PIC OFF)
SET(LLVM_ENABLE_PIE OFF) SET(LLVM_ENABLE_PIE OFF)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
SET(ANDROID TRUE)
if(ARCHITECTURE STREQUAL "arm")
SET(CMAKE_ANDROID_ARCH_ABI "armeabi-v7a")
SET(CMAKE_SYSTEM_PROCESSOR "armv7-a")
SET(CMAKE_ANDROID_ARM_MODE ON)
SET(CMAKE_C_COMPILER_TARGET arm-linux-androideabi)
SET(CMAKE_CXX_COMPILER_TARGET arm-linux-androideabi)
SET(_CMAKE_TOOLCHAIN_PREFIX arm-linux-androideabi-)
elseif(ARCHITECTURE STREQUAL "aarch64")
SET(CMAKE_ANDROID_ARCH_ABI "arm64-v8a")
SET(CMAKE_SYSTEM_PROCESSOR "aarch64")
endif()
SET(CMAKE_ANDROID_STANDALONE_TOOLCHAIN @prefix@/native)
SET(CMAKE_C_COMPILER "${_CMAKE_TOOLCHAIN_PREFIX}clang")
SET(CMAKE_CXX_COMPILER "${_CMAKE_TOOLCHAIN_PREFIX}clang++")
else() else()
SET(CMAKE_C_COMPILER @CC@) SET(CMAKE_C_COMPILER @CC@)
SET(CMAKE_CXX_COMPILER @CXX@) SET(CMAKE_CXX_COMPILER @CXX@)

View file

@ -1,21 +1,72 @@
# Bootstrappable Feather Wallet Builds # Bootstrappable Feather Wallet Builds
This directory contains the files necessary to perform bootstrappable Feather Wallet This directory contains the files necessary to perform [bootstrappable](https://bootstrappable.org) Feather Wallet builds.
builds.
[Bootstrappability][b17e] furthers our binary security guarantees by allowing us Bootstrappability allows us to _audit and reproduce_ our toolchain instead of blindly _trusting_ binary downloads.
to _audit and reproduce_ our toolchain instead of blindly _trusting_ binary Our build environment can be built from source, [all the way down](https://guix.gnu.org/en/blog/2023/the-full-source-bootstrap-building-from-source-all-the-way-down/).
downloads.
We achieve bootstrappability by using Guix as a functional package manager. We achieve bootstrappability by using [Guix](https://guix.gnu.org/) as a functional package manager. Guix runs on any Linux distribution and on
most architectures (x86_64, aarch64, riscv64). To produce reproducible release binaries, you only need to install Guix
and run the build script.
Guix allows us to modify any detail about our build environment with ease.
Unlike [Gitian](https://github.com/devrandom/gitian-builder), we are not limited to the package set of a particular Ubuntu version.
With Guix, we can configure our toolchains to use the latest compilers while still targeting older versions of glibc.
We drastically reduce our supply chain attack surface by only including the package we need in our build environment, and nothing else.
Packages that are not available in Guix can easily be defined in the [manifest](https://github.com/feather-wallet/feather/blob/master/contrib/guix/manifest.scm) or upstreamed.
Feather releases are independently reproduced and cryptographically attested to by multiple contributors.
You can submit attestations to the [feather-sigs](https://github.com/feather-wallet/feather-sigs) repo.
# Requirements # Requirements
Conservatively, you will need an x86_64 machine with: - any Linux distribution
- 50 GB of free disk space
- 4 or more cores recommended
- 2 GB RAM per thread
- 16GB of free disk space on the partition that /gnu/store will reside in # Quick setup
- 8GB of free disk space **per platform triple** you're planning on building
(see the `HOSTS` [environment variable description][env-vars-list]) If you're just here to get a build running (e.g. to test your changes) and quickly want to get up and running:
### Install Guix
On Ubuntu 22.04, Debian 11, or later:
```bash
$ apt install guix
```
If Guix is not available in your package manager, use the official [install script](https://guix.gnu.org/manual/en/html_node/Binary-Installation.html).
### Clone the repo
```bash
$ git clone https://github.com/feather-wallet/feather
$ cd feather
```
### Run the build
To build all targets using all available cores:
```bash
$ ./contrib/guix/guix-build
```
To limit the number of threads to N:
```
$ JOBS=N ./contrib/guix/guix-build
```
To only build the x86_64 linux target:
```
$ HOSTS="x86_64-linux-gnu" ./contrib/guix/guix-build
```
More recognized environment variables can be found further below.
# Installation and Setup # Installation and Setup
@ -362,6 +413,5 @@ used.
If you start `guix-daemon` using an init script, you can edit said script to If you start `guix-daemon` using an init script, you can edit said script to
supply this flag. supply this flag.
[b17e]: https://bootstrappable.org/
[r12e/source-date-epoch]: https://reproducible-builds.org/docs/source-date-epoch/ [r12e/source-date-epoch]: https://reproducible-builds.org/docs/source-date-epoch/
[env-vars-list]: #recognized-environment-variables [env-vars-list]: #recognized-environment-variables

View file

@ -292,6 +292,8 @@ case "$HOST" in
arm-linux-gnueabihf) HOST_CXXFLAGS="${HOST_CXXFLAGS} -Wno-psabi" ;; arm-linux-gnueabihf) HOST_CXXFLAGS="${HOST_CXXFLAGS} -Wno-psabi" ;;
esac esac
export USE_DEVICE_TREZOR_MANDATORY=1
# Make $HOST-specific native binaries from depends available in $PATH # Make $HOST-specific native binaries from depends available in $PATH
export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}" export PATH="${BASEPREFIX}/${HOST}/native/bin:${PATH}"
mkdir -p "$DISTSRC" mkdir -p "$DISTSRC"

View file

@ -51,7 +51,7 @@ fi
time-machine() { time-machine() {
# shellcheck disable=SC2086 # shellcheck disable=SC2086
guix time-machine --url=https://github.com/tobtoht/guix.git \ guix time-machine --url=https://github.com/tobtoht/guix.git \
--commit=f0bb724211872cd6158fce6162e0b8c73efed126 \ --commit=7bf1d7aeaffba15c4f680f93ae88fbef25427252 \
--cores="$JOBS" \ --cores="$JOBS" \
--keep-failed \ --keep-failed \
--fallback \ --fallback \

View file

@ -120,10 +120,17 @@ desirable for building Feather Wallet release binaries."
(search-our-patches "gcc-remap-guix-store.patch" (search-our-patches "gcc-remap-guix-store.patch"
"vmov-alignment.patch"))) "vmov-alignment.patch")))
(define (winpthreads-patches mingw-w64-x86_64-winpthreads)
(package-with-extra-patches mingw-w64-x86_64-winpthreads
(search-our-patches "winpthreads-remap-guix-store.patch")))
(define (make-mingw-pthreads-cross-toolchain target) (define (make-mingw-pthreads-cross-toolchain target)
"Create a cross-compilation toolchain package for TARGET" "Create a cross-compilation toolchain package for TARGET"
(let* ((xbinutils (cross-binutils target)) (let* ((xbinutils (cross-binutils target))
(pthreads-xlibc mingw-w64-x86_64-winpthreads) (machine (substring target 0 (string-index target #\-)))
(pthreads-xlibc (winpthreads-patches (make-mingw-w64 machine
#:xgcc (cross-gcc target #:xgcc (gcc-mingw-patches base-gcc))
#:with-winpthreads? #t)))
(pthreads-xgcc (cross-gcc target (pthreads-xgcc (cross-gcc target
#:xgcc (gcc-mingw-patches mingw-w64-base-gcc) #:xgcc (gcc-mingw-patches mingw-w64-base-gcc)
#:xbinutils xbinutils #:xbinutils xbinutils
@ -322,8 +329,8 @@ chain for " target " development."))
(make-bitcoin-cross-toolchain target))) (make-bitcoin-cross-toolchain target)))
((string-contains target "darwin") ((string-contains target "darwin")
(list (list
gcc-toolchain-10 gcc-toolchain-11
(list gcc-toolchain-10 "static") (list gcc-toolchain-11 "static")
binutils binutils
clang-toolchain-10 clang-toolchain-10
ldid)) ldid))

View file

@ -0,0 +1,17 @@
Without ffile-prefix-map, the debug symbols will contain paths for the
guix store which will include the hashes of each package. However, the
hash for the same package will differ when on different architectures.
In order to be reproducible regardless of the architecture used to build
the package, map all guix store prefixes to something fixed, e.g. /usr.
--- a/mingw-w64-libraries/winpthreads/Makefile.in
+++ b/mingw-w64-libraries/winpthreads/Makefile.in
@@ -478,7 +478,7 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
SUBDIRS = . tests
-AM_CFLAGS = -Wall -DWIN32_LEAN_AND_MEAN $(am__append_1)
+AM_CFLAGS = -Wall -DWIN32_LEAN_AND_MEAN $(am__append_1) $(shell find /gnu/store -maxdepth 1 -mindepth 1 -type d -exec echo -n " -ffile-prefix-map={}=/usr" \;)
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libwinpthread.la
include_HEADERS = include/pthread.h include/sched.h include/semaphore.h include/pthread_unistd.h include/pthread_time.h include/pthread_compat.h include/pthread_signal.h

@ -1 +0,0 @@
Subproject commit 1c8e9318b29b18b08e0302c1e34e4f3581e7895c

0
external/feather-docs vendored Normal file
View file

2
monero

@ -1 +1 @@
Subproject commit 6a88faa9af20c56363bac563a5c0b803ea2695dd Subproject commit 55a6b0018bb61abb9985a3054837d48f4d1020d8

101
src/Application.cpp Normal file
View file

@ -0,0 +1,101 @@
// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: 2020-2024 The Monero Project
#include "Application.h"
#include "config.h"
#include <QLocalSocket>
#include <QLockFile>
#include <QStandardPaths>
namespace
{
constexpr int WaitTimeoutMSec = 150;
const char BlockSizeProperty[] = "blockSize";
} // namespace
Application::Application(int& argc, char** argv)
: QApplication(argc, argv)
, m_alreadyRunning(false)
, m_lockFile(nullptr)
{
QString userName = qgetenv("USER");
if (userName.isEmpty()) {
userName = qgetenv("USERNAME");
}
QString identifier = "feather";
if (!userName.isEmpty()) {
identifier += "-" + userName;
}
QString lockName = identifier + ".lock";
m_socketName = identifier + ".socket";
// According to documentation we should use RuntimeLocation on *nixes, but even Qt doesn't respect
// this and creates sockets in TempLocation, so let's be consistent.
m_lockFile = new QLockFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + lockName);
m_lockFile->setStaleLockTime(0);
m_lockFile->tryLock();
m_lockServer.setSocketOptions(QLocalServer::UserAccessOption);
connect(&m_lockServer, SIGNAL(newConnection()), this, SIGNAL(anotherInstanceStarted()));
connect(&m_lockServer, &QLocalServer::newConnection, this, &Application::processIncomingConnection);
switch (m_lockFile->error()) {
case QLockFile::NoError:
// No existing lock was found, start listener
m_lockServer.listen(m_socketName);
break;
case QLockFile::LockFailedError: {
// Attempt to connect to the existing instance
QLocalSocket client;
for (int i = 0; i < 3; ++i) {
client.connectToServer(m_socketName);
if (client.waitForConnected(WaitTimeoutMSec)) {
// Connection succeeded, this will raise the existing window if minimized
client.abort();
m_alreadyRunning = true;
break;
}
}
if (!m_alreadyRunning) {
// If we get here then the original instance is likely dead
qWarning() << "Existing single-instance lock file is invalid. Launching new instance.";
// forceably reset the lock file
m_lockFile->removeStaleLockFile();
m_lockFile->tryLock();
// start the listen server
m_lockServer.listen(m_socketName);
}
break;
}
default:
qWarning() << "The lock file could not be created. Single-instance mode disabled.";
}
}
Application::~Application()
{
qDebug() << "~Application";
if (m_lockFile) {
m_lockFile->unlock();
delete m_lockFile;
}
}
bool Application::isAlreadyRunning() const
{
return m_alreadyRunning;
}
void Application::processIncomingConnection()
{
qDebug() << "We got an incoming connection";
if (m_lockServer.hasPendingConnections()) {
QLocalSocket* socket = m_lockServer.nextPendingConnection();
socket->setProperty(BlockSizeProperty, 0);
}
}

35
src/Application.h Normal file
View file

@ -0,0 +1,35 @@
// SPDX-License-Identifier: BSD-3-Clause
// SPDX-FileCopyrightText: 2020-2024 The Monero Project
#ifndef FEATHER_APPLICATION_H
#define FEATHER_APPLICATION_H
#include <QApplication>
#include <QtNetwork/qlocalserver.h>
class QLockFile;
class Application : public QApplication {
Q_OBJECT
public:
Application(int& argc, char** argv);
~Application() override;
bool isAlreadyRunning() const;
signals:
void anotherInstanceStarted();
private slots:
void processIncomingConnection();
private:
bool m_alreadyRunning;
QLockFile* m_lockFile;
QLocalServer m_lockServer;
QString m_socketName;
};
#endif //FEATHER_APPLICATION_H

View file

@ -20,11 +20,6 @@ endif()
find_package(Qt6 REQUIRED COMPONENTS ${QT_COMPONENTS}) find_package(Qt6 REQUIRED COMPONENTS ${QT_COMPONENTS})
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
add_subdirectory(third-party/singleapplication)
if (CHECK_UPDATES) if (CHECK_UPDATES)
add_subdirectory(openpgp) add_subdirectory(openpgp)
endif() endif()
@ -227,7 +222,7 @@ if(STATIC)
endif() endif()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_definitions(feather PRIVATE QT_NO_DEBUG=0) target_compile_definitions(feather PRIVATE QT_NO_DEBUG=1)
endif() endif()
target_compile_definitions(feather target_compile_definitions(feather
@ -254,11 +249,8 @@ if (DEPENDS)
endif() endif()
target_link_libraries(feather PRIVATE target_link_libraries(feather PRIVATE
wallet_merged wallet_api
${LMDB_LIBRARY}
epee epee
${UNBOUND_LIBRARY}
${SODIUM_LIBRARY}
easylogging easylogging
ringct ringct
${Boost_LIBRARIES} ${Boost_LIBRARIES}
@ -274,7 +266,6 @@ target_link_libraries(feather PRIVATE
Threads::Threads Threads::Threads
${QRENCODE_LIBRARY} ${QRENCODE_LIBRARY}
${POLYSEED_LIBRARY} ${POLYSEED_LIBRARY}
SingleApplication::SingleApplication
${ICU_LIBRARIES} ${ICU_LIBRARIES}
${LIBZIP_LIBRARIES} ${LIBZIP_LIBRARIES}
${ZLIB_LIBRARIES} ${ZLIB_LIBRARIES}
@ -285,11 +276,11 @@ if(CHECK_UPDATES)
target_link_libraries(feather PRIVATE openpgp) target_link_libraries(feather PRIVATE openpgp)
endif() endif()
if(DEPENDS)
target_link_libraries(feather PRIVATE ${ICONV_LIBRARIES})
endif()
if(DEVICE_TREZOR_READY) if(DEVICE_TREZOR_READY)
find_package(Protobuf CONFIG)
if (NOT Protobuf_FOUND)
find_package(Protobuf REQUIRED)
endif()
target_link_libraries(feather PRIVATE ${TREZOR_DEP_LIBS}) target_link_libraries(feather PRIVATE ${TREZOR_DEP_LIBS})
endif() endif()

View file

@ -324,18 +324,12 @@ QVector<CoinsInfo*> CoinsWidget::currentEntries() {
} }
void CoinsWidget::freezeCoins(QStringList &pubkeys) { void CoinsWidget::freezeCoins(QStringList &pubkeys) {
for (auto &pubkey : pubkeys) { m_wallet->coins()->freeze(pubkeys);
m_wallet->coins()->freeze(pubkey);
}
m_wallet->coins()->refresh();
m_wallet->updateBalance(); m_wallet->updateBalance();
} }
void CoinsWidget::thawCoins(QStringList &pubkeys) { void CoinsWidget::thawCoins(QStringList &pubkeys) {
for (auto &pubkey : pubkeys) { m_wallet->coins()->thaw(pubkeys);
m_wallet->coins()->thaw(pubkey);
}
m_wallet->coins()->refresh();
m_wallet->updateBalance(); m_wallet->updateBalance();
} }

View file

@ -7,7 +7,10 @@
#include <QMessageBox> #include <QMessageBox>
#include "dialog/ContactsDialog.h" #include "dialog/ContactsDialog.h"
#include "model/AddressBookModel.h"
#include "model/AddressBookProxyModel.h"
#include "libwalletqt/AddressBook.h" #include "libwalletqt/AddressBook.h"
#include "libwalletqt/Wallet.h"
#include "libwalletqt/WalletManager.h" #include "libwalletqt/WalletManager.h"
#include "utils/Icons.h" #include "utils/Icons.h"
#include "utils/Utils.h" #include "utils/Utils.h"

View file

@ -8,9 +8,9 @@
#include <QWidget> #include <QWidget>
#include <QMenu> #include <QMenu>
#include "model/AddressBookModel.h" class AddressBookModel;
#include "model/AddressBookProxyModel.h" class AddressBookProxyModel;
#include "libwalletqt/Wallet.h" class Wallet;
namespace Ui { namespace Ui {
class ContactsWidget; class ContactsWidget;

View file

@ -8,6 +8,8 @@
#include "dialog/TxInfoDialog.h" #include "dialog/TxInfoDialog.h"
#include "dialog/TxProofDialog.h" #include "dialog/TxProofDialog.h"
#include "model/TransactionHistoryProxyModel.h"
#include "libwalletqt/Wallet.h"
#include "libwalletqt/WalletManager.h" #include "libwalletqt/WalletManager.h"
#include "utils/config.h" #include "utils/config.h"
#include "utils/Icons.h" #include "utils/Icons.h"

View file

@ -7,10 +7,8 @@
#include <QWidget> #include <QWidget>
#include <QMenu> #include <QMenu>
#include "libwalletqt/Coins.h" class TransactionHistoryProxyModel;
#include "libwalletqt/Wallet.h" class Wallet;
#include "model/TransactionHistoryModel.h"
#include "model/TransactionHistoryProxyModel.h"
namespace Ui { namespace Ui {
class HistoryWidget; class HistoryWidget;

View file

@ -26,12 +26,13 @@
#include "libwalletqt/AddressBook.h" #include "libwalletqt/AddressBook.h"
#include "libwalletqt/rows/CoinsInfo.h" #include "libwalletqt/rows/CoinsInfo.h"
#include "libwalletqt/Transfer.h" #include "libwalletqt/Transfer.h"
#include "libwalletqt/TransactionHistory.h"
#include "model/AddressBookModel.h"
#include "plugins/PluginRegistry.h" #include "plugins/PluginRegistry.h"
#include "utils/AppData.h" #include "utils/AppData.h"
#include "utils/AsyncTask.h" #include "utils/AsyncTask.h"
#include "utils/ColorScheme.h" #include "utils/ColorScheme.h"
#include "utils/Icons.h" #include "utils/Icons.h"
#include "utils/SemanticVersion.h"
#include "utils/TorManager.h" #include "utils/TorManager.h"
#include "utils/WebsocketNotifier.h" #include "utils/WebsocketNotifier.h"
@ -116,6 +117,9 @@ MainWindow::MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *pa
this->onWalletOpened(); this->onWalletOpened();
connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &MainWindow::updateBalance);
connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &MainWindow::updateBalance);
#ifdef DONATE_BEG #ifdef DONATE_BEG
this->donationNag(); this->donationNag();
#endif #endif
@ -312,6 +316,7 @@ void MainWindow::initMenu() {
// [Wallet] -> [History] // [Wallet] -> [History]
connect(ui->actionExport_CSV, &QAction::triggered, this, &MainWindow::onExportHistoryCSV); connect(ui->actionExport_CSV, &QAction::triggered, this, &MainWindow::onExportHistoryCSV);
connect(ui->actionImportHistoryCSV, &QAction::triggered, this, &MainWindow::onImportHistoryDescriptionsCSV);
// [Wallet] -> [Contacts] // [Wallet] -> [Contacts]
connect(ui->actionExportContactsCSV, &QAction::triggered, this, &MainWindow::onExportContactsCSV); connect(ui->actionExportContactsCSV, &QAction::triggered, this, &MainWindow::onExportContactsCSV);
@ -324,7 +329,7 @@ void MainWindow::initMenu() {
// Show/Hide Coins // Show/Hide Coins
connect(ui->actionShow_Coins, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); connect(ui->actionShow_Coins, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
m_tabShowHideMapper["Coins"] = new ToggleTab(ui->tabCoins, "Coins", "Coins", ui->actionShow_Coins); m_tabShowHideMapper["Coins"] = new ToggleTab(ui->tabCoins, "Coins", "Coins", ui->actionShow_Coins, this);
m_tabShowHideSignalMapper->setMapping(ui->actionShow_Coins, "Coins"); m_tabShowHideSignalMapper->setMapping(ui->actionShow_Coins, "Coins");
// Show/Hide Plugins.. // Show/Hide Plugins..
@ -336,7 +341,7 @@ void MainWindow::initMenu() {
auto* pluginAction = new QAction(QString("Show %1").arg(plugin->displayName()), this); auto* pluginAction = new QAction(QString("Show %1").arg(plugin->displayName()), this);
ui->menuView->insertAction(plugin->insertFirst() ? ui->actionPlaceholderBegin : ui->actionPlaceholderEnd, pluginAction); ui->menuView->insertAction(plugin->insertFirst() ? ui->actionPlaceholderBegin : ui->actionPlaceholderEnd, pluginAction);
connect(pluginAction, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map)); connect(pluginAction, &QAction::triggered, m_tabShowHideSignalMapper, QOverload<>::of(&QSignalMapper::map));
m_tabShowHideMapper[plugin->displayName()] = new ToggleTab(plugin->tab(), plugin->displayName(), plugin->displayName(), pluginAction); m_tabShowHideMapper[plugin->displayName()] = new ToggleTab(plugin->tab(), plugin->displayName(), plugin->displayName(), pluginAction, this);
m_tabShowHideSignalMapper->setMapping(pluginAction, plugin->displayName()); m_tabShowHideSignalMapper->setMapping(pluginAction, plugin->displayName());
} }
ui->actionPlaceholderBegin->setVisible(false); ui->actionPlaceholderBegin->setVisible(false);
@ -482,6 +487,12 @@ void MainWindow::initWalletContext() {
m_windowManager->notify("Payment received", notify, 5000); m_windowManager->notify("Payment received", notify, 5000);
} }
}); });
connect(m_wallet, &Wallet::moneyReceived, this, [this](const QString &txId, uint64_t amount, bool coinbase){
if (m_wallet->isSynchronized() && !m_locked && coinbase) {
auto notify = QString("%1 XMR").arg(WalletManager::displayAmount(amount, false));
m_windowManager->notify("Mining payment received", notify, 5000);
}
});
// Device // Device
connect(m_wallet, &Wallet::deviceButtonRequest, this, &MainWindow::onDeviceButtonRequest); connect(m_wallet, &Wallet::deviceButtonRequest, this, &MainWindow::onDeviceButtonRequest);
@ -566,7 +577,7 @@ void MainWindow::onWalletOpened() {
m_wallet->history()->refresh(); m_wallet->history()->refresh();
}); });
// Vice versa // Vice versa
connect(m_wallet->history(), &TransactionHistory::txNoteChanged, [this] { connect(m_wallet->transactionHistoryModel(), &TransactionHistoryModel::transactionDescriptionChanged, [this] {
m_wallet->coins()->refresh(); m_wallet->coins()->refresh();
}); });
@ -581,6 +592,10 @@ void MainWindow::onWalletOpened() {
} }
} }
void MainWindow::updateBalance() {
this->onBalanceUpdated(m_wallet->balance(), m_wallet->unlockedBalance());
}
void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) {
bool hide = conf()->get(Config::hideBalance).toBool(); bool hide = conf()->get(Config::hideBalance).toBool();
int displaySetting = conf()->get(Config::balanceDisplay).toInt(); int displaySetting = conf()->get(Config::balanceDisplay).toInt();
@ -601,6 +616,12 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) {
} }
} }
if (conf()->get(Config::balanceShowFiat).toBool() && !hide) {
QString fiatCurrency = conf()->get(Config::preferredFiatCurrency).toString();
double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balance / constants::cdiv);
balance_str += QString(" (%1)").arg(Utils::amountToCurrencyString(balanceFiatAmount, fiatCurrency));
}
m_statusLabelBalance->setToolTip("Click for details"); m_statusLabelBalance->setToolTip("Click for details");
m_statusLabelBalance->setText(balance_str); m_statusLabelBalance->setText(balance_str);
} }
@ -911,7 +932,7 @@ void MainWindow::onTransactionCreated(PendingTransaction *tx, const QVector<QStr
return; return;
} }
else if (tx->txCount() > 1) { else if (tx->txCount() > 1) {
Utils::showError(this, "Failed to construct transaction", "Split transactions are not supported", {"Try sending a smaller amount."}); Utils::showError(this, "Failed to construct transaction", "Transaction tries to spend too many inputs", {"Send a smaller amount of XMR to yourself first."});
m_wallet->disposeTransaction(tx); m_wallet->disposeTransaction(tx);
return; return;
} }
@ -1208,6 +1229,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO;
if (!this->cleanedUp) { if (!this->cleanedUp) {
qDebug() << "MainWindow: cleaning up";
this->cleanedUp = true; this->cleanedUp = true;
emit aboutToQuit(); emit aboutToQuit();
@ -1693,6 +1715,21 @@ void MainWindow::onExportHistoryCSV() {
Utils::showInfo(this, "CSV export", QString("Transaction history exported to %1").arg(fn)); Utils::showInfo(this, "CSV export", QString("Transaction history exported to %1").arg(fn));
} }
void MainWindow::onImportHistoryDescriptionsCSV() {
const QString fileName = QFileDialog::getOpenFileName(this, "Import CSV file", QDir::homePath(), "CSV Files (*.csv)");
if (fileName.isEmpty()) {
return;
}
QString error = m_wallet->history()->importLabelsFromCSV(fileName);
if (!error.isEmpty()) {
Utils::showError(this, "Unable to import transaction descriptions from CSV", error);
}
else {
Utils::showInfo(this, "Successfully imported transaction descriptions from CSV");
}
}
void MainWindow::onExportContactsCSV() { void MainWindow::onExportContactsCSV() {
auto *model = m_wallet->addressBookModel(); auto *model = m_wallet->addressBookModel();
if (model->rowCount() <= 0){ if (model->rowCount() <= 0){
@ -1762,8 +1799,8 @@ void MainWindow::donationNag() {
donationCounter++; donationCounter++;
if (donationCounter % constants::donationBoundary == 0) { if (donationCounter % constants::donationBoundary == 0) {
auto msg = "Feather is a 100% community-sponsored endeavor. Please consider supporting " auto msg = "Feather development is funded entirely through donations.\n\nPlease consider supporting "
"the project financially. Get rid of this message by donating any amount."; "the project. Donate any amount to remove this reminder.";
int ret = QMessageBox::information(this, "Donate to Feather", msg, QMessageBox::Yes, QMessageBox::No); int ret = QMessageBox::information(this, "Donate to Feather", msg, QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::Yes) { if (ret == QMessageBox::Yes) {
this->donateButtonClicked(); this->donateButtonClicked();
@ -1935,5 +1972,5 @@ int MainWindow::findTab(const QString &title) {
} }
MainWindow::~MainWindow() { MainWindow::~MainWindow() {
qDebug() << "~MainWindow"; qDebug() << "~MainWindow" << QThread::currentThreadId();
} }

View file

@ -51,9 +51,12 @@ namespace Ui {
class MainWindow; class MainWindow;
} }
struct ToggleTab { class ToggleTab : QObject {
ToggleTab(QWidget *tab, QString name, QString description, QAction *menuAction) : Q_OBJECT
tab(tab), key(std::move(name)), name(std::move(description)), menuAction(menuAction) {}
public:
ToggleTab(QWidget *tab, QString name, QString description, QAction *menuAction, QObject *parent = nullptr) :
QObject(parent), tab(tab), key(std::move(name)), name(std::move(description)), menuAction(menuAction) {}
QWidget *tab; QWidget *tab;
QString key; QString key;
QString name; QString name;
@ -110,6 +113,7 @@ private slots:
void menuToggleTabVisible(const QString &key); void menuToggleTabVisible(const QString &key);
void menuClearHistoryClicked(); void menuClearHistoryClicked();
void onExportHistoryCSV(); void onExportHistoryCSV();
void onImportHistoryDescriptionsCSV();
void onExportContactsCSV(); void onExportContactsCSV();
void onCreateDesktopEntry(); void onCreateDesktopEntry();
void onShowDocumentation(); void onShowDocumentation();
@ -128,6 +132,7 @@ private slots:
void onTxPoolBacklog(const QVector<quint64> &backlog, quint64 originalFeeLevel, quint64 automaticFeeLevel); void onTxPoolBacklog(const QVector<quint64> &backlog, quint64 originalFeeLevel, quint64 automaticFeeLevel);
// libwalletqt // libwalletqt
void updateBalance();
void onBalanceUpdated(quint64 balance, quint64 spendable); void onBalanceUpdated(quint64 balance, quint64 spendable);
void onSyncStatus(quint64 height, quint64 target, bool daemonSync); void onSyncStatus(quint64 height, quint64 target, bool daemonSync);
void onWalletOpened(); void onWalletOpened();

View file

@ -499,6 +499,7 @@
<string>History</string> <string>History</string>
</property> </property>
<addaction name="actionExport_CSV"/> <addaction name="actionExport_CSV"/>
<addaction name="actionImportHistoryCSV"/>
</widget> </widget>
<widget class="QMenu" name="menuContacts"> <widget class="QMenu" name="menuContacts">
<property name="title"> <property name="title">
@ -939,6 +940,11 @@
<string>Tx pool viewer</string> <string>Tx pool viewer</string>
</property> </property>
</action> </action>
<action name="actionImportHistoryCSV">
<property name="text">
<string>Import descriptions from CSV</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

View file

@ -5,7 +5,6 @@
#include "ui_ReceiveWidget.h" #include "ui_ReceiveWidget.h"
#include <QMenu> #include <QMenu>
#include <QMessageBox>
#include "dialog/PaymentRequestDialog.h" #include "dialog/PaymentRequestDialog.h"
#include "dialog/QrCodeDialog.h" #include "dialog/QrCodeDialog.h"
@ -71,7 +70,7 @@ ReceiveWidget::ReceiveWidget(Wallet *wallet, QWidget *parent)
// context menu // context menu
ui->addresses->setContextMenuPolicy(Qt::CustomContextMenu); ui->addresses->setContextMenuPolicy(Qt::CustomContextMenu);
m_showTransactionsAction = new QAction("Show transactions"); m_showTransactionsAction = new QAction("Show transactions", this);
connect(m_showTransactionsAction, &QAction::triggered, this, &ReceiveWidget::onShowTransactions); connect(m_showTransactionsAction, &QAction::triggered, this, &ReceiveWidget::onShowTransactions);
connect(ui->addresses, &QTreeView::customContextMenuRequested, this, &ReceiveWidget::showContextMenu); connect(ui->addresses, &QTreeView::customContextMenuRequested, this, &ReceiveWidget::showContextMenu);
connect(ui->addresses, &SubaddressView::copyAddress, this, &ReceiveWidget::copyAddress); connect(ui->addresses, &SubaddressView::copyAddress, this, &ReceiveWidget::copyAddress);

View file

@ -6,7 +6,6 @@
#include <QMenu> #include <QMenu>
#include <QWidget> #include <QWidget>
#include <QSvgWidget>
#include "libwalletqt/Subaddress.h" #include "libwalletqt/Subaddress.h"
#include "libwalletqt/Wallet.h" #include "libwalletqt/Wallet.h"

View file

@ -4,13 +4,12 @@
#include "SendWidget.h" #include "SendWidget.h"
#include "ui_SendWidget.h" #include "ui_SendWidget.h"
#include <QMessageBox>
#include "ColorScheme.h" #include "ColorScheme.h"
#include "constants.h" #include "constants.h"
#include "utils/AppData.h" #include "utils/AppData.h"
#include "utils/config.h" #include "utils/config.h"
#include "Icons.h" #include "Icons.h"
#include "libwalletqt/Wallet.h"
#include "libwalletqt/WalletManager.h" #include "libwalletqt/WalletManager.h"
#if defined(WITH_SCANNER) #if defined(WITH_SCANNER)
@ -29,8 +28,7 @@ SendWidget::SendWidget(Wallet *wallet, QWidget *parent)
QString amount_rx = R"(^\d{0,8}[\.,]\d{0,12}|(all)$)"; QString amount_rx = R"(^\d{0,8}[\.,]\d{0,12}|(all)$)";
QRegularExpression rx; QRegularExpression rx;
rx.setPattern(amount_rx); rx.setPattern(amount_rx);
QValidator *validator = new QRegularExpressionValidator(rx, this); ui->lineAmount->setValidator(new QRegularExpressionValidator(rx, this));
ui->lineAmount->setValidator(validator);
connect(m_wallet, &Wallet::initiateTransaction, this, &SendWidget::disableSendButton); connect(m_wallet, &Wallet::initiateTransaction, this, &SendWidget::disableSendButton);
connect(m_wallet, &Wallet::transactionCreated, this, &SendWidget::enableSendButton); connect(m_wallet, &Wallet::transactionCreated, this, &SendWidget::enableSendButton);
@ -47,7 +45,7 @@ SendWidget::SendWidget(Wallet *wallet, QWidget *parent)
connect(ui->lineAmount, &QLineEdit::textChanged, this, &SendWidget::amountEdited); connect(ui->lineAmount, &QLineEdit::textChanged, this, &SendWidget::amountEdited);
connect(ui->lineAddress, &QPlainTextEdit::textChanged, this, &SendWidget::addressEdited); connect(ui->lineAddress, &QPlainTextEdit::textChanged, this, &SendWidget::addressEdited);
connect(ui->btn_openAlias, &QPushButton::clicked, this, &SendWidget::aliasClicked); connect(ui->btn_openAlias, &QPushButton::clicked, this, &SendWidget::aliasClicked);
connect(ui->lineAddress, &PayToEdit::dataPasted, this, &SendWidget::onDataPasted); connect(ui->lineAddress, &PayToEdit::dataPasted, this, &SendWidget::onDataFromQR);
ui->label_conversionAmount->setText(""); ui->label_conversionAmount->setText("");
ui->label_conversionAmount->hide(); ui->label_conversionAmount->hide();
ui->btn_openAlias->hide(); ui->btn_openAlias->hide();
@ -142,7 +140,7 @@ void SendWidget::scanClicked() {
auto dialog = new QrCodeScanDialog(this, false); auto dialog = new QrCodeScanDialog(this, false);
dialog->exec(); dialog->exec();
ui->lineAddress->setText(dialog->decodedString()); this->onDataFromQR(dialog->decodedString());
dialog->deleteLater(); dialog->deleteLater();
#else #else
Utils::showError(this, "Can't open QR scanner", "Feather was built without webcam QR scanner support"); Utils::showError(this, "Can't open QR scanner", "Feather was built without webcam QR scanner support");
@ -404,13 +402,17 @@ void SendWidget::setSubtractFeeFromAmountEnabled(bool enabled) {
ui->check_subtractFeeFromAmount->setVisible(enabled); ui->check_subtractFeeFromAmount->setVisible(enabled);
} }
void SendWidget::onDataPasted(const QString &data) { void SendWidget::onDataFromQR(const QString &data) {
if (!data.isEmpty()) { if (!data.isEmpty()) {
QVariantMap uriData = m_wallet->parse_uri_to_object(data); QVariantMap uriData = m_wallet->parse_uri_to_object(data);
if (!uriData.contains("error")) { if (!uriData.contains("error")) {
ui->lineAddress->setText(uriData.value("address").toString()); ui->lineAddress->setText(uriData.value("address").toString());
ui->lineDescription->setText(uriData.value("tx_description").toString()); ui->lineDescription->setText(uriData.value("tx_description").toString());
ui->lineAmount->setText(uriData.value("amount").toString());
// Strip trailing zeroes
auto amountStr = uriData.value("amount").toString();
auto amount = WalletManager::amountFromString(amountStr);
ui->lineAmount->setText(WalletManager::displayAmount(amount, false));
} else { } else {
ui->lineAddress->setText(data); ui->lineAddress->setText(data);
} }

View file

@ -6,7 +6,7 @@
#include <QWidget> #include <QWidget>
#include "libwalletqt/Wallet.h" class Wallet;
namespace Ui { namespace Ui {
class SendWidget; class SendWidget;
@ -49,7 +49,7 @@ public slots:
void disallowSending(); void disallowSending();
private slots: private slots:
void onDataPasted(const QString &data); void onDataFromQR(const QString &data);
private: private:
void setupComboBox(); void setupComboBox();

View file

@ -12,10 +12,9 @@
#include "libwalletqt/WalletManager.h" #include "libwalletqt/WalletManager.h"
#include "utils/AppData.h" #include "utils/AppData.h"
#include "utils/Icons.h" #include "utils/Icons.h"
#include "utils/nodes.h"
#include "utils/WebsocketNotifier.h" #include "utils/WebsocketNotifier.h"
#include "widgets/NetworkProxyWidget.h" #include "widgets/NetworkProxyWidget.h"
#include "WindowManager.h"
#include "plugins/PluginRegistry.h"
#include "utils/ColorScheme.h" #include "utils/ColorScheme.h"
Settings::Settings(Nodes *nodes, QWidget *parent) Settings::Settings(Nodes *nodes, QWidget *parent)
@ -132,10 +131,18 @@ void Settings::setupAppearanceTab() {
emit updateBalance(); emit updateBalance();
}); });
// [Balance show fiat]
ui->checkBox_balanceShowFiat->setChecked(conf()->get(Config::balanceShowFiat).toBool());
connect(ui->checkBox_balanceShowFiat, &QCheckBox::toggled, [this](bool toggled){
conf()->set(Config::balanceShowFiat, toggled);
emit updateBalance();
});
// [Preferred fiat currency] // [Preferred fiat currency]
QStringList availableFiatCurrencies = appData()->prices.rates.keys(); QStringList availableFiatCurrencies = appData()->prices.rates.keys();
for (const auto &currency : availableFiatCurrencies) { for (const auto &currency : availableFiatCurrencies) {
ui->comboBox_fiatCurrency->addItem(currency); ui->comboBox_fiatCurrency->addItem(currency);
emit updateBalance();
} }
QStringList fiatCurrencies; QStringList fiatCurrencies;
@ -152,6 +159,7 @@ void Settings::setupAppearanceTab() {
QString selection = ui->comboBox_fiatCurrency->itemText(index); QString selection = ui->comboBox_fiatCurrency->itemText(index);
conf()->set(Config::preferredFiatCurrency, selection); conf()->set(Config::preferredFiatCurrency, selection);
emit preferredFiatCurrencyChanged(selection); emit preferredFiatCurrencyChanged(selection);
emit updateBalance();
}); });
} }

View file

@ -4,17 +4,13 @@
#ifndef FEATHER_SettingsDIALOG_H #ifndef FEATHER_SettingsDIALOG_H
#define FEATHER_SettingsDIALOG_H #define FEATHER_SettingsDIALOG_H
#include <QAbstractButton>
#include <QDialog> #include <QDialog>
#include <QSettings>
#include "widgets/NodeWidget.h"
namespace Ui { namespace Ui {
class Settings; class Settings;
} }
class Nodes;
class Settings : public QDialog class Settings : public QDialog
{ {
Q_OBJECT Q_OBJECT

View file

@ -129,17 +129,17 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="6" column="0">
<widget class="QLabel" name="label_17"> <widget class="QLabel" name="label_17">
<property name="text"> <property name="text">
<string>Fiat currency:</string> <string>Fiat currency:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<widget class="QComboBox" name="comboBox_fiatCurrency"/> <widget class="QComboBox" name="comboBox_fiatCurrency"/>
</item> </item>
<item row="6" column="0"> <item row="7" column="0">
<spacer name="verticalSpacer_3"> <spacer name="verticalSpacer_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@ -152,6 +152,13 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="5" column="1">
<widget class="QCheckBox" name="checkBox_balanceShowFiat">
<property name="text">
<string>Show fiat balance in statusbar</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>

View file

@ -3,21 +3,27 @@
#include "WindowManager.h" #include "WindowManager.h"
#include <QApplication>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QInputDialog> #include <QInputDialog>
#include <QMessageBox> #include <QMessageBox>
#include <QWindow> #include <QWindow>
#include "Application.h"
#include "constants.h" #include "constants.h"
#include "MainWindow.h"
#include "dialog/DocsDialog.h"
#include "dialog/PasswordDialog.h" #include "dialog/PasswordDialog.h"
#include "dialog/SplashDialog.h" #include "dialog/SplashDialog.h"
#include "dialog/TorInfoDialog.h"
#include "libwalletqt/WalletManager.h"
#include "libwalletqt/Wallet.h"
#include "utils/Icons.h" #include "utils/Icons.h"
#include "utils/NetworkManager.h" #include "utils/NetworkManager.h"
#include "utils/os/tails.h" #include "utils/os/tails.h"
#include "utils/os/whonix.h" #include "utils/os/whonix.h"
#include "utils/TorManager.h" #include "utils/TorManager.h"
#include "utils/WebsocketNotifier.h" #include "utils/WebsocketNotifier.h"
#include "utils/AppData.h"
WindowManager::WindowManager(QObject *parent) WindowManager::WindowManager(QObject *parent)
: QObject(parent) : QObject(parent)
@ -33,6 +39,7 @@ WindowManager::WindowManager(QObject *parent)
connect(m_walletManager, &WalletManager::deviceError, this, &WindowManager::onDeviceError); connect(m_walletManager, &WalletManager::deviceError, this, &WindowManager::onDeviceError);
connect(m_walletManager, &WalletManager::walletPassphraseNeeded, this, &WindowManager::onWalletPassphraseNeeded); connect(m_walletManager, &WalletManager::walletPassphraseNeeded, this, &WindowManager::onWalletPassphraseNeeded);
connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(raise()));
connect(qApp, &QGuiApplication::lastWindowClosed, this, &WindowManager::quitAfterLastWindow); connect(qApp, &QGuiApplication::lastWindowClosed, this, &WindowManager::quitAfterLastWindow);
m_tray = new QSystemTrayIcon(icons()->icon("appicons/64x64.png")); m_tray = new QSystemTrayIcon(icons()->icon("appicons/64x64.png"));
@ -66,6 +73,7 @@ WindowManager::~WindowManager() {
qDebug() << "~WindowManager"; qDebug() << "~WindowManager";
m_cleanupThread->quit(); m_cleanupThread->quit();
m_cleanupThread->wait(); m_cleanupThread->wait();
qDebug() << "WindowManager: cleanup thread done" << QThread::currentThreadId();
} }
// ######################## APPLICATION LIFECYCLE ######################## // ######################## APPLICATION LIFECYCLE ########################
@ -80,7 +88,7 @@ void WindowManager::quitAfterLastWindow() {
} }
void WindowManager::close() { void WindowManager::close() {
qDebug() << Q_FUNC_INFO; qDebug() << Q_FUNC_INFO << QThread::currentThreadId();
for (const auto &window: m_windows) { for (const auto &window: m_windows) {
window->close(); window->close();
} }
@ -100,11 +108,14 @@ void WindowManager::close() {
torManager()->stop(); torManager()->stop();
deleteLater();
qDebug() << "Calling QApplication::quit()";
QApplication::quit(); QApplication::quit();
} }
void WindowManager::closeWindow(MainWindow *window) { void WindowManager::closeWindow(MainWindow *window) {
qDebug() << "closing Window"; qDebug() << "WindowManager: closing Window";
m_windows.removeOne(window); m_windows.removeOne(window);
// Move Wallet to a different thread for cleanup, so it doesn't block GUI thread // Move Wallet to a different thread for cleanup, so it doesn't block GUI thread
@ -273,17 +284,29 @@ void WindowManager::onWalletOpened(Wallet *wallet) {
bool showIncorrectPassword = m_openWalletTriedOnce; bool showIncorrectPassword = m_openWalletTriedOnce;
m_openWalletTriedOnce = true; m_openWalletTriedOnce = true;
this->onWalletOpenPasswordRequired(showIncorrectPassword, wallet->keysPath()); this->onWalletOpenPasswordRequired(showIncorrectPassword, wallet->keysPath());
return; // Do not remove this
} }
else if (errMsg == QString("basic_string::_M_replace_aux") || errMsg == QString("std::bad_alloc") || errMsg == "invalid signature") { else if (errMsg == QString("basic_string::_M_replace_aux") || errMsg == QString("std::bad_alloc") || errMsg == "invalid signature") {
qCritical() << errMsg; qCritical() << errMsg;
WalletManager::clearWalletCache(wallet->cachePath()); WalletManager::clearWalletCache(wallet->cachePath());
errMsg = QString("%1\n\nWallet cache is unusable, moving it.").arg(errMsg); errMsg = QString("%1\n\nWallet cache is unusable, moving it.").arg(errMsg);
this->handleWalletError({nullptr, Utils::ERROR, "Unable to open wallet", errMsg, {"Try opening this wallet again.", "If this keeps happening, please file a bug report."}, "report_an_issue"}); this->handleWalletError({nullptr, Utils::ERROR, "Unable to open wallet", errMsg, {"Try opening this wallet again.", "If this keeps happening, please file a bug report."}, "report_an_issue"});
} else { }
else if (errMsg.startsWith("failed to read file")) {
#if defined(Q_OS_MACOS)
Utils::Message message{nullptr, Utils::ERROR, "Unable to open wallet", errMsg, {"You may need to give Feather permission to access the folder", "In the System Settings app, go to 'Privacy & Security' -> 'Files & Folders'"}};
#else
Utils::Message message{nullptr, Utils::ERROR, "Unable to open wallet", errMsg, {"You may need to change the permissions on the wallet directory."}};
#endif
this->handleWalletError(message);
}
else {
Utils::Message message{nullptr, Utils::ERROR, "Unable to open wallet"}; Utils::Message message{nullptr, Utils::ERROR, "Unable to open wallet"};
this->handleDeviceError(errMsg, message); this->handleDeviceError(errMsg, message);
this->handleWalletError(message); this->handleWalletError(message);
} }
m_openingWallet = false;
return; return;
} }

View file

@ -5,17 +5,20 @@
#define FEATHER_WINDOWMANAGER_H #define FEATHER_WINDOWMANAGER_H
#include <QObject> #include <QObject>
#include <QSystemTrayIcon>
#include "dialog/DocsDialog.h" #include "utils/EventFilter.h"
#include "dialog/TorInfoDialog.h"
#include "libwalletqt/WalletManager.h"
#include "libwalletqt/Wallet.h"
#include "MainWindow.h"
#include "utils/nodes.h" #include "utils/nodes.h"
#include "wizard/WalletWizard.h" #include "wizard/WalletWizard.h"
#include "Utils.h" #include "Utils.h"
class MainWindow; class MainWindow;
class DocsDialog;
class TorInfoDialog;
class WalletManager;
class Wallet;
class SplashDialog;
class WindowManager : public QObject { class WindowManager : public QObject {
Q_OBJECT Q_OBJECT
@ -30,7 +33,6 @@ public:
void closeWindow(MainWindow *window); void closeWindow(MainWindow *window);
void showWizard(WalletWizard::Page startPage); void showWizard(WalletWizard::Page startPage);
void restartApplication(const QString &binaryFilename); void restartApplication(const QString &binaryFilename);
void raise();
void showSettings(Nodes *nodes, QWidget *parent, bool showProxyTab = false); void showSettings(Nodes *nodes, QWidget *parent, bool showProxyTab = false);
@ -59,6 +61,7 @@ public slots:
void tryOpenWallet(const QString &path, const QString &password); void tryOpenWallet(const QString &path, const QString &password);
private slots: private slots:
void raise();
void onWalletOpened(Wallet *wallet); void onWalletOpened(Wallet *wallet);
void onWalletCreated(Wallet *wallet); void onWalletCreated(Wallet *wallet);
void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path); void onWalletOpenPasswordRequired(bool invalidPassword, const QString &path);

View file

@ -3,8 +3,6 @@
"tor": [ "tor": [
"sfprpc2fws6ltnq4hyr7lvpul3nank5layd7q7tyc5h4gy4h77gtabad.onion:18089", "sfprpc2fws6ltnq4hyr7lvpul3nank5layd7q7tyc5h4gy4h77gtabad.onion:18089",
"moneroxmrxw44lku6qniyarpwgznpcwml4drq7vb24ppatlcg4kmxpqd.onion:18089", "moneroxmrxw44lku6qniyarpwgznpcwml4drq7vb24ppatlcg4kmxpqd.onion:18089",
"6dsdenp6vjkvqzy4wzsnzn6wixkdzihx3khiumyzieauxuxslmcaeiad.onion:18081",
"56wl7y2ebhamkkiza4b7il4mrzwtyvpdym7bm2bkg3jrei2je646k3qd.onion:18089",
"ip4zpbps7unk6xhlanqtw24f75akfbl3upeckfjqjks7ftfnk4i73oid.onion:18081", "ip4zpbps7unk6xhlanqtw24f75akfbl3upeckfjqjks7ftfnk4i73oid.onion:18081",
"mhfsxznn5pi4xuxohj5k7unqp73sa6d44mbeewbpxnm25z3wzfogcfyd.onion:18081", "mhfsxznn5pi4xuxohj5k7unqp73sa6d44mbeewbpxnm25z3wzfogcfyd.onion:18081",
"7inib34hqn2ocmlaaxjshdavbdn5w5rfdff735lbz33765j2pz3tn4ad.onion:18081", "7inib34hqn2ocmlaaxjshdavbdn5w5rfdff735lbz33765j2pz3tn4ad.onion:18081",
@ -21,10 +19,10 @@
"rucknium757bokwv3ss35ftgc3gzb7hgbvvglbg3hisp7tsj2fkd2nyd.onion:18081" "rucknium757bokwv3ss35ftgc3gzb7hgbvvglbg3hisp7tsj2fkd2nyd.onion:18081"
], ],
"i2p": [ "i2p": [
"ynk3hrwte23asonojqeskoulek2g2cd6tqg4neghnenfyljrvhga.b32.i2p:18081", "ofrnxmr5ltaazarexs3damrcsldc5p6qlcos3vk25cwdgyjvrueq.b32.i2p:18089",
"t7lce3j7mwxt32h755u3njjp3k6og3defgueo3iecgsexxnkoezouobc.b32.i2p:18089", "vdmnehdjkpkg57nthgnjfuaqgku673r5bpbqg56ix6fyqoywgqrq.b32.i2p:18089",
"ecnfc7oyzzw3jmwc2omxzccbik33wyyaofxsfow7342z6kjanq6a.b32.i2p:18089", "uqj3aphckqtjsitz7kxx5flqpwjlq5ppr3chazfued7xucv3nheq.b32.i2p:18089",
"xmp3afekvuhbmzxl2bgj6ju23d6feqpumxuzdqzq4aysbijohdxa.b32.i2p:18089" "ugnlcdciyhghh2zert7c3kl4biwkirc43ke33jiy5slnd3mv2trq.b32.i2p:18089"
], ],
"clearnet": [ "clearnet": [
"node.community.rino.io:18081", "node.community.rino.io:18081",

View file

@ -2141,4 +2141,30 @@
1723042527:3210000 1723042527:3210000
1723220196:3211500 1723220196:3211500
1723401886:3213000 1723401886:3213000
1723577283:3214500 1723577283:3214500
1723758523:3216000
1723943045:3217500
1724123516:3219000
1724300973:3220500
1724484278:3222000
1724666887:3223500
1724849987:3225000
1725015093:3226500
1725197019:3228000
1725383293:3229500
1725558474:3231000
1725742245:3232500
1725924657:3234000
1726105045:3235500
1726283197:3237000
1726463211:3238500
1726636517:3240000
1726818897:3241500
1727000277:3243000
1727180466:3244500
1727359618:3246000
1727542507:3247500
1727723723:3249000
1727906604:3250500
1728083420:3252000
1728259944:3253500

View file

@ -1108,4 +1108,30 @@
1722983267:1660500 1722983267:1660500
1723166957:1662000 1723166957:1662000
1723347339:1663500 1723347339:1663500
1723524898:1665000 1723524898:1665000
1723704308:1666500
1723860608:1668000
1724036267:1669500
1724260269:1671000
1724443530:1672500
1724620063:1674000
1724802245:1675500
1724981057:1677000
1725166685:1678500
1725344930:1680000
1725518960:1681500
1725706849:1683000
1725884468:1684500
1726020096:1686000
1726227873:1687500
1726405463:1689000
1726586949:1690500
1726765988:1692000
1726945486:1693500
1727125243:1695000
1727307226:1696500
1727549352:1698000
1727727177:1699500
1727908581:1701000
1728092922:1702500
1728273508:1704000

View file

@ -4,8 +4,7 @@
#ifndef FEATHER_CONSTANTS_H #ifndef FEATHER_CONSTANTS_H
#define FEATHER_CONSTANTS_H #define FEATHER_CONSTANTS_H
#include <QtGlobal> #include <QString>
#include <QUrl>
#include "networktype.h" #include "networktype.h"

View file

@ -5,6 +5,7 @@
#include "ui_AboutDialog.h" #include "ui_AboutDialog.h"
#include <QMessageBox> #include <QMessageBox>
#include <QDate>
#include "config-feather.h" #include "config-feather.h"
#include "utils/Utils.h" #include "utils/Utils.h"

View file

@ -4,9 +4,6 @@
#ifndef FEATHER_ABOUT_H #ifndef FEATHER_ABOUT_H
#define FEATHER_ABOUT_H #define FEATHER_ABOUT_H
#include <QDialog>
#include <QStringListModel>
#include "components.h" #include "components.h"
namespace Ui { namespace Ui {

View file

@ -8,6 +8,7 @@
#include "libwalletqt/SubaddressAccount.h" #include "libwalletqt/SubaddressAccount.h"
#include "libwalletqt/WalletManager.h" #include "libwalletqt/WalletManager.h"
#include "model/SubaddressAccountModel.h"
#include "utils/Icons.h" #include "utils/Icons.h"
#include "utils/Utils.h" #include "utils/Utils.h"

View file

@ -4,10 +4,8 @@
#ifndef FEATHER_ACCOUNTSWITCHERDIALOG_H #ifndef FEATHER_ACCOUNTSWITCHERDIALOG_H
#define FEATHER_ACCOUNTSWITCHERDIALOG_H #define FEATHER_ACCOUNTSWITCHERDIALOG_H
#include <QDialog>
#include "libwalletqt/Wallet.h"
#include "components.h" #include "components.h"
#include "libwalletqt/Wallet.h"
#include "model/SubaddressAccountModel.h" #include "model/SubaddressAccountModel.h"
namespace Ui { namespace Ui {

View file

@ -7,6 +7,7 @@
#include "utils/Utils.h" #include "utils/Utils.h"
#include "components.h" #include "components.h"
#include "dialog/QrCodeDialog.h" #include "dialog/QrCodeDialog.h"
#include "libwalletqt/Wallet.h"
AddressCheckerIndexDialog::AddressCheckerIndexDialog(Wallet *wallet, QWidget *parent) AddressCheckerIndexDialog::AddressCheckerIndexDialog(Wallet *wallet, QWidget *parent)
: WindowModalDialog(parent) : WindowModalDialog(parent)

View file

@ -5,7 +5,8 @@
#define ADDRESSCHECKERINDEXDIALOG_H #define ADDRESSCHECKERINDEXDIALOG_H
#include "components.h" #include "components.h"
#include "Wallet.h"
class Wallet;
namespace Ui { namespace Ui {
class AddressCheckerIndexDialog; class AddressCheckerIndexDialog;

View file

@ -4,8 +4,6 @@
#ifndef FEATHER_BALANCEDIALOG_H #ifndef FEATHER_BALANCEDIALOG_H
#define FEATHER_BALANCEDIALOG_H #define FEATHER_BALANCEDIALOG_H
#include <QDialog>
#include "components.h" #include "components.h"
#include "libwalletqt/Wallet.h" #include "libwalletqt/Wallet.h"

View file

@ -5,6 +5,7 @@
#include "ui_DocsDialog.h" #include "ui_DocsDialog.h"
#include <QScrollBar> #include <QScrollBar>
#include <QDirIterator>
#include "utils/Utils.h" #include "utils/Utils.h"
#include "ColorScheme.h" #include "ColorScheme.h"
@ -133,6 +134,12 @@ DocsDialog::DocsDialog(QWidget *parent)
this->updateHighlights(ui->search->text()); this->updateHighlights(ui->search->text());
}); });
// Pressing 'enter' in the search box shouldn't close the dialog
QPushButton *closeButton = ui->buttonBox->button(QDialogButtonBox::Close);
if (closeButton) {
closeButton->setAutoDefault(false);
}
this->showDoc("report_an_issue"); this->showDoc("report_an_issue");
} }

View file

@ -8,10 +8,8 @@
#include "ColorScheme.h" #include "ColorScheme.h"
#include "utils/Utils.h" #include "utils/Utils.h"
#include "polyseed/polyseed.h" #include "polyseed/polyseed.h"
#include "utils/AsyncTask.h"
#include "device/device_default.hpp" #include "device/device_default.hpp"
#include "cryptonote_basic/account.h" #include "cryptonote_basic/account.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "cryptonote_basic/blobdatatype.h" #include "cryptonote_basic/blobdatatype.h"
#include "common/base58.h" #include "common/base58.h"
#include "serialization/binary_utils.h" #include "serialization/binary_utils.h"

View file

@ -70,10 +70,14 @@ TxInfoDialog::TxInfoDialog(Wallet *wallet, TransactionRow *txInfo, QWidget *pare
ui->frameInputs->hide(); ui->frameInputs->hide();
// } // }
ui->frame_destinationsWarning->hide();
QTextCursor cursor = ui->outputs->textCursor(); QTextCursor cursor = ui->outputs->textCursor();
auto transfers = txInfo->transfers(); auto transfers = txInfo->transfers();
if (!transfers.isEmpty()) { if (!transfers.isEmpty()) {
bool hasIntegrated = false;
for (const auto& transfer : transfers) { for (const auto& transfer : transfers) {
auto address = transfer->address(); auto address = transfer->address();
auto amount = WalletManager::displayAmount(transfer->amount()); auto amount = WalletManager::displayAmount(transfer->amount());
@ -81,9 +85,21 @@ TxInfoDialog::TxInfoDialog(Wallet *wallet, TransactionRow *txInfo, QWidget *pare
cursor.insertText(address, Utils::addressTextFormat(index, transfer->amount())); cursor.insertText(address, Utils::addressTextFormat(index, transfer->amount()));
cursor.insertText(QString(" %1").arg(amount), QTextCharFormat()); cursor.insertText(QString(" %1").arg(amount), QTextCharFormat());
cursor.insertBlock(); cursor.insertBlock();
if (WalletManager::baseAddressFromIntegratedAddress(transfer->address(), constants::networkType) != transfer->address()) {
hasIntegrated = true;
}
} }
ui->label_outputs->setText(QString("Destinations (%2)").arg(QString::number(transfers.size()))); ui->label_outputs->setText(QString("Destinations (%2)").arg(QString::number(transfers.size())));
this->adjustHeight(ui->outputs, transfers.size()); this->adjustHeight(ui->outputs, transfers.size());
// Trezor saves a mangled payment ID.
if (m_wallet->isTrezor() && !hasIntegrated && txInfo->hasPaymentId()) {
ui->frame_destinationsWarning->setInfo(icons()->icon("warning"), "The address displayed here does not contain a payment ID. "
"If you are making a repeat payment to a service, "
"do not copy the address from here to prevent a loss of funds.");
ui->frame_destinationsWarning->show();
}
} else { } else {
ui->frameOutputs->hide(); ui->frameOutputs->hide();
} }

View file

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>929</width> <width>929</width>
<height>715</height> <height>723</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -184,6 +184,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="InfoFrame" name="frame_destinationsWarning">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
</widget>
</item>
<item> <item>
<widget class="QTextEdit" name="outputs"> <widget class="QTextEdit" name="outputs">
<property name="sizePolicy"> <property name="sizePolicy">
@ -287,6 +297,14 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>InfoFrame</class>
<extends>QFrame</extends>
<header>components.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View file

@ -4,8 +4,6 @@
#include "URSettingsDialog.h" #include "URSettingsDialog.h"
#include "ui_URSettingsDialog.h" #include "ui_URSettingsDialog.h"
#include <QFileDialog>
#include "utils/config.h" #include "utils/config.h"
#include "utils/Utils.h" #include "utils/Utils.h"

View file

@ -34,6 +34,8 @@ CoinsInfo* Coins::coin(int index)
void Coins::refresh() void Coins::refresh()
{ {
qDebug() << Q_FUNC_INFO;
emit refreshStarted(); emit refreshStarted();
boost::shared_lock<boost::shared_mutex> transfers_lock(m_wallet2->m_transfers_mutex); boost::shared_lock<boost::shared_mutex> transfers_lock(m_wallet2->m_transfers_mutex);
@ -103,48 +105,52 @@ quint64 Coins::count() const
return m_rows.length(); return m_rows.length();
} }
void Coins::freeze(QString &publicKey) void Coins::freeze(QStringList &publicKeys)
{ {
crypto::public_key pk; crypto::public_key pk;
if (!epee::string_tools::hex_to_pod(publicKey.toStdString(), pk))
{ for (const auto& publicKey : publicKeys) {
qWarning() << "Invalid public key: " << publicKey; if (!epee::string_tools::hex_to_pod(publicKey.toStdString(), pk))
return; {
qWarning() << "Invalid public key: " << publicKey;
continue;
}
try
{
m_wallet2->freeze(pk);
}
catch (const std::exception& e)
{
qWarning() << "freeze: " << e.what();
}
} }
try refresh();
{
m_wallet2->freeze(pk);
refresh();
}
catch (const std::exception& e)
{
qWarning() << "freeze: " << e.what();
}
emit coinFrozen();
} }
void Coins::thaw(QString &publicKey) void Coins::thaw(QStringList &publicKeys)
{ {
crypto::public_key pk; crypto::public_key pk;
if (!epee::string_tools::hex_to_pod(publicKey.toStdString(), pk))
{ for (const auto& publicKey : publicKeys) {
qWarning() << "Invalid public key: " << publicKey; if (!epee::string_tools::hex_to_pod(publicKey.toStdString(), pk))
return; {
qWarning() << "Invalid public key: " << publicKey;
continue;
}
try
{
m_wallet2->thaw(pk);
}
catch (const std::exception& e)
{
qWarning() << "thaw: " << e.what();
}
} }
try refresh();
{
m_wallet2->thaw(pk);
refresh();
}
catch (const std::exception& e)
{
qWarning() << "thaw: " << e.what();
}
emit coinThawed();
} }
QVector<CoinsInfo*> Coins::coins_from_txid(const QString &txid) QVector<CoinsInfo*> Coins::coins_from_txid(const QString &txid)

View file

@ -9,7 +9,6 @@
#include <QObject> #include <QObject>
#include <QList> #include <QList>
#include <QReadWriteLock> #include <QReadWriteLock>
#include <QDateTime>
#include "Wallet.h" #include "Wallet.h"
@ -32,8 +31,10 @@ public:
CoinsInfo * coin(int index); CoinsInfo * coin(int index);
void refresh(); void refresh();
void refreshUnlocked(); void refreshUnlocked();
void freeze(QString &publicKey);
void thaw(QString &publicKey); void freeze(QStringList &publicKeys);
void thaw(QStringList &publicKeys);
QVector<CoinsInfo*> coins_from_txid(const QString &txid); QVector<CoinsInfo*> coins_from_txid(const QString &txid);
QVector<CoinsInfo*> coinsFromKeyImage(const QStringList &keyimages); QVector<CoinsInfo*> coinsFromKeyImage(const QStringList &keyimages);
void setDescription(const QString &publicKey, quint32 accountIndex, const QString &description); void setDescription(const QString &publicKey, quint32 accountIndex, const QString &description);
@ -44,8 +45,6 @@ public:
signals: signals:
void refreshStarted() const; void refreshStarted() const;
void refreshFinished() const; void refreshFinished() const;
void coinFrozen() const;
void coinThawed() const;
void descriptionChanged() const; void descriptionChanged() const;
private: private:

View file

@ -5,6 +5,7 @@
#include "Input.h" #include "Input.h"
#include "Transfer.h" #include "Transfer.h"
#include <wallet/api/wallet2_api.h>
quint64 ConstructionInfo::unlockTime() const { quint64 ConstructionInfo::unlockTime() const {
return m_unlockTime; return m_unlockTime;

View file

@ -4,13 +4,16 @@
#ifndef FEATHER_CONSTRUCTIONINFO_H #ifndef FEATHER_CONSTRUCTIONINFO_H
#define FEATHER_CONSTRUCTIONINFO_H #define FEATHER_CONSTRUCTIONINFO_H
#include <wallet/api/wallet2_api.h>
#include <QObject> #include <QObject>
#include <QSet> #include <QSet>
class Input; class Input;
class Transfer; class Transfer;
namespace Monero {
class TransactionConstructionInfo;
}
class ConstructionInfo : public QObject class ConstructionInfo : public QObject
{ {
Q_OBJECT Q_OBJECT

View file

@ -4,15 +4,11 @@
#ifndef FEATHER_INPUT_H #ifndef FEATHER_INPUT_H
#define FEATHER_INPUT_H #define FEATHER_INPUT_H
#include <wallet/api/wallet2_api.h>
#include <QObject> #include <QObject>
#include <utility>
class Input : public QObject class Input : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(quint64 amount READ amount)
Q_PROPERTY(QString pubKey READ pubKey)
private: private:
explicit Input(uint64_t _amount, QString _address, QObject *parent = nullptr): QObject(parent), m_amount(_amount), m_pubkey(std::move(_address)) {}; explicit Input(uint64_t _amount, QString _address, QObject *parent = nullptr): QObject(parent), m_amount(_amount), m_pubkey(std::move(_address)) {};
@ -20,10 +16,10 @@ private:
friend class ConstructionInfo; friend class ConstructionInfo;
quint64 m_amount; quint64 m_amount;
QString m_pubkey; QString m_pubkey;
public: public:
quint64 amount() const { return m_amount; } quint64 amount() const { return m_amount; }
QString pubKey() const { return m_pubkey; } QString pubKey() const { return m_pubkey; }
}; };
#endif //FEATHER_INPUT_H #endif //FEATHER_INPUT_H

View file

@ -4,7 +4,7 @@
#include "PassphraseHelper.h" #include "PassphraseHelper.h"
#include <QDebug> #include <QDebug>
Monero::optional<std::string> PassphraseHelper::onDevicePassphraseRequest(bool & on_device) std::optional<std::string> PassphraseHelper::onDevicePassphraseRequest(bool & on_device)
{ {
qDebug() << __FUNCTION__; qDebug() << __FUNCTION__;
QMutexLocker locker(&m_mutex_pass); QMutexLocker locker(&m_mutex_pass);
@ -26,9 +26,9 @@ Monero::optional<std::string> PassphraseHelper::onDevicePassphraseRequest(bool &
if (!on_device) { if (!on_device) {
auto tmpPass = m_passphrase.toStdString(); auto tmpPass = m_passphrase.toStdString();
m_passphrase = QString(); m_passphrase = QString();
return Monero::optional<std::string>(tmpPass); return std::optional<std::string>(tmpPass);
} else { } else {
return Monero::optional<std::string>(); return std::optional<std::string>();
} }
} }

View file

@ -4,11 +4,9 @@
#ifndef MONERO_GUI_PASSPHRASEHELPER_H #ifndef MONERO_GUI_PASSPHRASEHELPER_H
#define MONERO_GUI_PASSPHRASEHELPER_H #define MONERO_GUI_PASSPHRASEHELPER_H
#include <wallet/api/wallet2_api.h>
#include <QMutex> #include <QMutex>
#include <QPointer> #include <QPointer>
#include <QWaitCondition> #include <QWaitCondition>
#include <QMutex>
/** /**
* Implements component responsible for showing entry prompt to the user, * Implements component responsible for showing entry prompt to the user,
@ -32,7 +30,7 @@ class PassphraseHelper {
public: public:
PassphraseHelper(PassphrasePrompter * prompter=nullptr): m_prompter(prompter) {}; PassphraseHelper(PassphrasePrompter * prompter=nullptr): m_prompter(prompter) {};
PassphraseHelper(const PassphraseHelper & h): PassphraseHelper(h.m_prompter) {}; PassphraseHelper(const PassphraseHelper & h): PassphraseHelper(h.m_prompter) {};
Monero::optional<std::string> onDevicePassphraseRequest(bool & on_device); std::optional<std::string> onDevicePassphraseRequest(bool & on_device);
void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort); void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort);
private: private:

View file

@ -5,6 +5,8 @@
#include <QVariant> #include <QVariant>
#include <wallet/api/wallet2_api.h>
PendingTransaction::Status PendingTransaction::status() const PendingTransaction::Status PendingTransaction::status() const
{ {
return static_cast<Status>(m_pimpl->status()); return static_cast<Status>(m_pimpl->status());

View file

@ -7,18 +7,21 @@
#include <QObject> #include <QObject>
#include <QList> #include <QList>
#include <wallet/api/wallet2_api.h>
#include "PendingTransactionInfo.h" #include "PendingTransactionInfo.h"
namespace Monero {
class PendingTransaction;
}
class PendingTransaction : public QObject class PendingTransaction : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
enum Status { enum Status {
Status_Ok = Monero::PendingTransaction::Status_Ok, Status_Ok = 0,
Status_Error = Monero::PendingTransaction::Status_Error, Status_Error = 1,
Status_Critical = Monero::PendingTransaction::Status_Critical Status_Critical = 2
}; };
Q_ENUM(Status) Q_ENUM(Status)

View file

@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2020-2024 The Monero Project // SPDX-FileCopyrightText: 2020-2024 The Monero Project
#include "PendingTransactionInfo.h" #include "PendingTransactionInfo.h"
#include <wallet/api/wallet2_api.h>
quint64 PendingTransactionInfo::fee() const { quint64 PendingTransactionInfo::fee() const {
return m_fee; return m_fee;

View file

@ -11,6 +11,10 @@
class Input; class Input;
class Transfer; class Transfer;
namespace Monero {
class PendingTransactionInfo;
}
class PendingTransactionInfo : public ConstructionInfo class PendingTransactionInfo : public ConstructionInfo
{ {
Q_OBJECT Q_OBJECT

View file

@ -4,10 +4,7 @@
#ifndef FEATHER_RINGS_H #ifndef FEATHER_RINGS_H
#define FEATHER_RINGS_H #define FEATHER_RINGS_H
#include <wallet/api/wallet2_api.h>
#include <QObject> #include <QObject>
#include <QList>
#include <utility>
class Ring : public QObject class Ring : public QObject
{ {

View file

@ -4,10 +4,8 @@
#ifndef SUBADDRESS_H #ifndef SUBADDRESS_H
#define SUBADDRESS_H #define SUBADDRESS_H
#include <functional>
#include <QReadWriteLock>
#include <QObject> #include <QObject>
#include <QReadWriteLock>
#include <QList> #include <QList>
#include <QDateTime> #include <QDateTime>

View file

@ -64,6 +64,8 @@ TransactionRow* TransactionHistory::transaction(int index)
void TransactionHistory::refresh() void TransactionHistory::refresh()
{ {
qDebug() << Q_FUNC_INFO;
QDateTime firstDateTime = QDate(2014, 4, 18).startOfDay(); QDateTime firstDateTime = QDate(2014, 4, 18).startOfDay();
QDateTime lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones) QDateTime lastDateTime = QDateTime::currentDateTime().addDays(1); // tomorrow (guard against jitter and timezones)
@ -75,10 +77,10 @@ void TransactionHistory::refresh()
clearRows(); clearRows();
quint64 lastTxHeight = 0; quint64 lastTxHeight = 0;
bool hasFakePaymentId = m_wallet->isTrezor();
m_locked = false; m_locked = false;
m_minutesToUnlock = 0; m_minutesToUnlock = 0;
uint64_t min_height = 0; uint64_t min_height = 0;
uint64_t max_height = (uint64_t)-1; uint64_t max_height = (uint64_t)-1;
uint64_t wallet_height = m_wallet->blockChainHeight(); uint64_t wallet_height = m_wallet->blockChainHeight();
@ -105,7 +107,7 @@ void TransactionHistory::refresh()
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
payment_id = payment_id.substr(0,16); payment_id = payment_id.substr(0,16);
auto* t = new TransactionRow(); auto* t = new TransactionRow(this);
t->m_paymentId = QString::fromStdString(payment_id); t->m_paymentId = QString::fromStdString(payment_id);
t->m_coinbase = pd.m_coinbase; t->m_coinbase = pd.m_coinbase;
t->m_amount = pd.m_amount; t->m_amount = pd.m_amount;
@ -152,7 +154,7 @@ void TransactionHistory::refresh()
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
payment_id = payment_id.substr(0,16); payment_id = payment_id.substr(0,16);
auto* t = new TransactionRow(); auto* t = new TransactionRow(this);
t->m_paymentId = QString::fromStdString(payment_id); t->m_paymentId = QString::fromStdString(payment_id);
t->m_amount = pd.m_amount_out - change; t->m_amount = pd.m_amount_out - change;
@ -176,7 +178,7 @@ void TransactionHistory::refresh()
// single output transaction might contain multiple transfers // single output transaction might contain multiple transfers
for (auto const &d: pd.m_dests) for (auto const &d: pd.m_dests)
{ {
Transfer *transfer = new Transfer(d.amount, QString::fromStdString(d.address(m_wallet2->nettype(), pd.m_payment_id)), this); Transfer *transfer = new Transfer(d.amount, QString::fromStdString(d.address(m_wallet2->nettype(), pd.m_payment_id, !hasFakePaymentId)), this);
t->m_transfers.append(transfer); t->m_transfers.append(transfer);
} }
for (auto const &r: pd.m_rings) for (auto const &r: pd.m_rings)
@ -206,7 +208,7 @@ void TransactionHistory::refresh()
payment_id = payment_id.substr(0,16); payment_id = payment_id.substr(0,16);
bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed; bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed;
auto *t = new TransactionRow(); auto *t = new TransactionRow(this);
t->m_paymentId = QString::fromStdString(payment_id); t->m_paymentId = QString::fromStdString(payment_id);
t->m_amount = pd.m_amount_out - change; t->m_amount = pd.m_amount_out - change;
@ -229,7 +231,7 @@ void TransactionHistory::refresh()
for (auto const &d: pd.m_dests) for (auto const &d: pd.m_dests)
{ {
Transfer *transfer = new Transfer(d.amount, QString::fromStdString(d.address(m_wallet2->nettype(), pd.m_payment_id)), this); Transfer *transfer = new Transfer(d.amount, QString::fromStdString(d.address(m_wallet2->nettype(), pd.m_payment_id, !hasFakePaymentId)), this);
t->m_transfers.append(transfer); t->m_transfers.append(transfer);
} }
for (auto const &r: pd.m_rings) for (auto const &r: pd.m_rings)
@ -254,7 +256,7 @@ void TransactionHistory::refresh()
std::string payment_id = epee::string_tools::pod_to_hex(i->first); std::string payment_id = epee::string_tools::pod_to_hex(i->first);
if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) if (payment_id.substr(16).find_first_not_of('0') == std::string::npos)
payment_id = payment_id.substr(0,16); payment_id = payment_id.substr(0,16);
auto *t = new TransactionRow(); auto *t = new TransactionRow(this);
t->m_paymentId = QString::fromStdString(payment_id); t->m_paymentId = QString::fromStdString(payment_id);
t->m_amount = pd.m_amount; t->m_amount = pd.m_amount;
t->m_balanceDelta = pd.m_amount; t->m_balanceDelta = pd.m_amount;
@ -281,12 +283,14 @@ void TransactionHistory::refresh()
void TransactionHistory::setTxNote(const QString &txid, const QString &note) void TransactionHistory::setTxNote(const QString &txid, const QString &note)
{ {
cryptonote::blobdata txid_data; cryptonote::blobdata txid_data;
if(!epee::string_tools::parse_hexstr_to_binbuff(txid.toStdString(), txid_data) || txid_data.size() != sizeof(crypto::hash)) if (!epee::string_tools::parse_hexstr_to_binbuff(txid.toStdString(), txid_data) || txid_data.size() != sizeof(crypto::hash)) {
qDebug() << Q_FUNC_INFO << "invalid txid";
return; return;
}
const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data()); const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
m_wallet2->set_tx_note(htxid, note.toStdString()); m_wallet2->set_tx_note(htxid, note.toStdString());
refresh();
emit txNoteChanged(); emit txNoteChanged();
} }
@ -401,4 +405,102 @@ bool TransactionHistory::writeCSV(const QString &path) {
data = QString("blockHeight,timestamp,date,accountIndex,direction,balanceDelta,amount,fee,txid,description,paymentId,fiatAmount,fiatCurrency%1").arg(data); data = QString("blockHeight,timestamp,date,accountIndex,direction,balanceDelta,amount,fee,txid,description,paymentId,fiatAmount,fiatCurrency%1").arg(data);
return Utils::fileWrite(path, data); return Utils::fileWrite(path, data);
} }
QStringList parseCSVLine(const QString &line) {
QStringList result;
QString currentField;
bool inQuotes = false;
for (int i = 0; i < line.length(); ++i) {
QChar currentChar = line[i];
if (currentChar == '"') {
if (inQuotes && i + 1 < line.length() && line[i + 1] == '"') {
currentField.append('"');
++i;
} else {
inQuotes = !inQuotes;
}
} else if (currentChar == ',' && !inQuotes) {
result.append(currentField.trimmed());
currentField.clear();
} else {
currentField.append(currentChar);
}
}
result.append(currentField.trimmed());
return result;
}
QString TransactionHistory::importLabelsFromCSV(const QString &fileName) {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return QString("Could not open file: %1").arg(fileName);
}
QTextStream in(&file);
QList<QStringList> fields;
while (!in.atEnd()) {
QString line = in.readLine();
fields.append(parseCSVLine(line));
}
if (fields.empty()) {
return "CSV file appears to be empty";
}
qint64 txidField = -1;
qint64 descriptionField = -1;
QStringList header = fields[0];
for (int i = 0; i < header.length(); i++) {
if (header[i] == "txid") {
txidField = i;
continue;
}
if (header[i] == "description") {
descriptionField = i;
}
}
if (txidField < 0) {
return "'txid' field not found in CSV header";
}
if (descriptionField < 0) {
return "'description' field not found in CSV header";
}
qint64 maxIndex = std::max(txidField, descriptionField);
QList<QPair<QString, QString>> descriptions;
for (int i = 1; i < fields.length(); i++) {
const auto& row = fields[i];
if (maxIndex >= row.length()) {
qDebug() << "Row with invalid length in CSV";
continue;
}
if (row[txidField].isEmpty()) {
continue;
}
if (row[descriptionField].isEmpty()) {
continue;
}
descriptions.push_back({row[txidField], row[descriptionField]});
}
for (const auto& description : descriptions) {
qDebug() << "Setting note for tx:" << description.first << "description:" << description.second;
this->setTxNote(description.first, description.second);
}
this->refresh();
return {};
}

View file

@ -34,7 +34,6 @@ public:
TransactionRow* transaction(int index); TransactionRow* transaction(int index);
void refresh(); void refresh();
void setTxNote(const QString &txid, const QString &note); void setTxNote(const QString &txid, const QString &note);
bool writeCSV(const QString &path);
quint64 count() const; quint64 count() const;
QDateTime firstDateTime() const; QDateTime firstDateTime() const;
QDateTime lastDateTime() const; QDateTime lastDateTime() const;
@ -42,6 +41,9 @@ public:
bool locked() const; bool locked() const;
void clearRows(); void clearRows();
bool writeCSV(const QString &path);
QString importLabelsFromCSV(const QString &fileName);
signals: signals:
void refreshStarted() const; void refreshStarted() const;
void refreshFinished() const; void refreshFinished() const;

View file

@ -2,7 +2,9 @@
// SPDX-FileCopyrightText: 2020-2024 The Monero Project // SPDX-FileCopyrightText: 2020-2024 The Monero Project
#include "UnsignedTransaction.h" #include "UnsignedTransaction.h"
#include <QDebug>
#include "ConstructionInfo.h"
#include <wallet/api/wallet2_api.h>
UnsignedTransaction::Status UnsignedTransaction::status() const UnsignedTransaction::Status UnsignedTransaction::status() const
{ {

View file

@ -6,7 +6,12 @@
#include <QObject> #include <QObject>
#include "libwalletqt/PendingTransactionInfo.h" namespace Monero {
class UnsignedTransaction;
class Wallet;
}
class ConstructionInfo;
class UnsignedTransaction : public QObject class UnsignedTransaction : public QObject
{ {
@ -14,9 +19,9 @@ class UnsignedTransaction : public QObject
public: public:
enum Status { enum Status {
Status_Ok = Monero::UnsignedTransaction::Status_Ok, Status_Ok = 0,
Status_Error = Monero::UnsignedTransaction::Status_Error, Status_Error = 1,
Status_Critical = Monero::UnsignedTransaction::Status_Critical Status_Critical = 2
}; };
Q_ENUM(Status) Q_ENUM(Status)

View file

@ -12,6 +12,7 @@
#include "SubaddressAccount.h" #include "SubaddressAccount.h"
#include "TransactionHistory.h" #include "TransactionHistory.h"
#include "WalletManager.h" #include "WalletManager.h"
#include "WalletListenerImpl.h"
#include "config.h" #include "config.h"
#include "constants.h" #include "constants.h"
@ -73,10 +74,6 @@ Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
this->updateBalance(); this->updateBalance();
} }
connect(this->history(), &TransactionHistory::txNoteChanged, [this]{
this->history()->refresh();
});
connect(this, &Wallet::refreshed, this, &Wallet::onRefreshed); connect(this, &Wallet::refreshed, this, &Wallet::onRefreshed);
connect(this, &Wallet::newBlock, this, &Wallet::onNewBlock); connect(this, &Wallet::newBlock, this, &Wallet::onNewBlock);
connect(this, &Wallet::updated, this, &Wallet::onUpdated); connect(this, &Wallet::updated, this, &Wallet::onUpdated);
@ -357,6 +354,22 @@ void Wallet::setSeedLanguage(const QString &lang)
m_wallet2->set_seed_language(lang.toStdString()); m_wallet2->set_seed_language(lang.toStdString());
} }
QString Wallet::getSecretViewKey() const {
return QString::fromStdString(m_walletImpl->secretViewKey());
}
QString Wallet::getPublicViewKey() const {
return QString::fromStdString(m_walletImpl->publicViewKey());
}
QString Wallet::getSecretSpendKey() const {
return QString::fromStdString(m_walletImpl->secretSpendKey());
}
QString Wallet::getPublicSpendKey() const {
return QString::fromStdString(m_walletImpl->publicSpendKey());
}
// #################### Node connection #################### // #################### Node connection ####################
void Wallet::setOffline(bool offline) { void Wallet::setOffline(bool offline) {
@ -866,7 +879,7 @@ void Wallet::createTransaction(const QString &address, quint64 amount, const QSt
m_scheduler.run([this, all, address, amount, feeLevel, subtractFeeFromAmount] { m_scheduler.run([this, all, address, amount, feeLevel, subtractFeeFromAmount] {
std::set<uint32_t> subaddr_indices; std::set<uint32_t> subaddr_indices;
Monero::PendingTransaction *ptImpl = m_walletImpl->createTransaction(address.toStdString(), "", all ? Monero::optional<uint64_t>() : Monero::optional<uint64_t>(amount), constants::mixin, Monero::PendingTransaction *ptImpl = m_walletImpl->createTransaction(address.toStdString(), "", all ? std::optional<uint64_t>() : std::optional<uint64_t>(amount), constants::mixin,
static_cast<Monero::PendingTransaction::Priority>(feeLevel), static_cast<Monero::PendingTransaction::Priority>(feeLevel),
currentSubaddressAccount(), subaddr_indices, m_selectedInputs, subtractFeeFromAmount); currentSubaddressAccount(), subaddr_indices, m_selectedInputs, subtractFeeFromAmount);
@ -1331,6 +1344,10 @@ bool Wallet::setRingDatabase(const QString &path) {
return m_walletImpl->setRingDatabase(path.toStdString()); return m_walletImpl->setRingDatabase(path.toStdString());
} }
quint64 Wallet::getWalletCreationHeight() const {
return m_walletImpl->getRefreshFromBlockHeight();
}
void Wallet::setWalletCreationHeight(quint64 height) { void Wallet::setWalletCreationHeight(quint64 height) {
m_wallet2->set_refresh_from_block_height(height); m_wallet2->set_refresh_from_block_height(height);
} }
@ -1431,7 +1448,7 @@ void Wallet::getTxPoolStatsAsync() {
Wallet::~Wallet() Wallet::~Wallet()
{ {
qDebug("~Wallet: Closing wallet"); qDebug() << "~Wallet: Closing wallet" << QThread::currentThreadId();
pauseRefresh(); pauseRefresh();
m_walletImpl->stop(); m_walletImpl->stop();
@ -1448,5 +1465,5 @@ Wallet::~Wallet()
delete m_walletImpl; delete m_walletImpl;
m_walletImpl = nullptr; m_walletImpl = nullptr;
qDebug("m_walletImpl deleted"); qDebug() << "m_walletImpl deleted" << QThread::currentThreadId();
} }

View file

@ -4,24 +4,28 @@
#ifndef WALLET_H #ifndef WALLET_H
#define WALLET_H #define WALLET_H
#include <QElapsedTimer>
#include <QObject> #include <QObject>
#include <QMutex> #include <QMutex>
#include <QList>
#include <QtConcurrent/QtConcurrent>
#include "utils/scheduler.h" #include "utils/scheduler.h"
#include "PendingTransaction.h" #include "PendingTransaction.h"
#include "UnsignedTransaction.h" #include "UnsignedTransaction.h"
#include "utils/networktype.h" #include "utils/networktype.h"
#include "PassphraseHelper.h" #include "PassphraseHelper.h"
#include "WalletListenerImpl.h"
#include "rows/TxBacklogEntry.h" #include "rows/TxBacklogEntry.h"
#include <set>
class WalletListenerImpl;
namespace Monero { namespace Monero {
struct Wallet; // forward declaration struct Wallet; // forward declaration
} }
namespace tools {
struct wallet2;
}
struct TxProof { struct TxProof {
TxProof(QString proof, QString error = "") TxProof(QString proof, QString error = "")
: proof(std::move(proof)), error(std::move(error)){} : proof(std::move(proof)), error(std::move(error)){}
@ -94,17 +98,17 @@ public:
~Wallet() override; ~Wallet() override;
enum Status { enum Status {
Status_Ok = Monero::Wallet::Status_Ok, Status_Ok = 0,
Status_Error = Monero::Wallet::Status_Error, Status_Error = 1,
Status_Critical = Monero::Wallet::Status_Critical, Status_Critical = 2,
Status_BadPassword = Monero::Wallet::Status_BadPassword Status_BadPassword = 3
}; };
Q_ENUM(Status) Q_ENUM(Status)
enum ConnectionStatus { enum ConnectionStatus {
ConnectionStatus_Disconnected = Monero::Wallet::ConnectionStatus_Disconnected, ConnectionStatus_Disconnected = 0,
ConnectionStatus_WrongVersion = Monero::Wallet::ConnectionStatus_WrongVersion, ConnectionStatus_WrongVersion = 2,
ConnectionStatus_Connecting = 9, ConnectionStatus_Connecting = 9,
ConnectionStatus_Synchronizing = 10, ConnectionStatus_Synchronizing = 10,
ConnectionStatus_Synchronized = 11 ConnectionStatus_Synchronized = 11
@ -186,10 +190,10 @@ public:
void setSeedLanguage(const QString &lang); void setSeedLanguage(const QString &lang);
//! Get wallet keys //! Get wallet keys
QString getSecretViewKey() const {return QString::fromStdString(m_walletImpl->secretViewKey());} QString getSecretViewKey() const;
QString getPublicViewKey() const {return QString::fromStdString(m_walletImpl->publicViewKey());} QString getPublicViewKey() const;
QString getSecretSpendKey() const {return QString::fromStdString(m_walletImpl->secretSpendKey());} QString getSecretSpendKey() const;
QString getPublicSpendKey() const {return QString::fromStdString(m_walletImpl->publicSpendKey());} QString getPublicSpendKey() const;
// ##### Node connection ##### // ##### Node connection #####
@ -399,7 +403,7 @@ public:
bool setRingDatabase(const QString &path); bool setRingDatabase(const QString &path);
quint64 getWalletCreationHeight() const {return m_walletImpl->getRefreshFromBlockHeight();} quint64 getWalletCreationHeight() const;
void setWalletCreationHeight(quint64 height); void setWalletCreationHeight(quint64 height);
//! Rescan spent outputs //! Rescan spent outputs
@ -431,7 +435,7 @@ signals:
void refreshed(bool success, const QString &message); void refreshed(bool success, const QString &message);
void moneySpent(const QString &txId, quint64 amount); void moneySpent(const QString &txId, quint64 amount);
void moneyReceived(const QString &txId, quint64 amount); void moneyReceived(const QString &txId, quint64 amount, bool coinbase);
void unconfirmedMoneyReceived(const QString &txId, quint64 amount); void unconfirmedMoneyReceived(const QString &txId, quint64 amount);
void newBlock(quint64 height, quint64 targetHeight); void newBlock(quint64 height, quint64 targetHeight);
void walletCreationHeightChanged(); void walletCreationHeightChanged();
@ -529,6 +533,4 @@ private:
std::set<std::string> m_selectedInputs; std::set<std::string> m_selectedInputs;
}; };
#endif // WALLET_H #endif // WALLET_H

View file

@ -25,13 +25,13 @@ void WalletListenerImpl::moneySpent(const std::string &txId, uint64_t amount)
emit m_wallet->moneySpent(qTxId, amount); emit m_wallet->moneySpent(qTxId, amount);
} }
void WalletListenerImpl::moneyReceived(const std::string &txId, uint64_t amount) void WalletListenerImpl::moneyReceived(const std::string &txId, uint64_t amount, bool coinbase)
{ {
// Incoming tx included in a block. // Incoming tx included in a block.
QString qTxId = QString::fromStdString(txId); QString qTxId = QString::fromStdString(txId);
qDebug() << Q_FUNC_INFO << qTxId << " " << WalletManager::displayAmount(amount); qDebug() << Q_FUNC_INFO << qTxId << " " << WalletManager::displayAmount(amount);
emit m_wallet->moneyReceived(qTxId, amount); emit m_wallet->moneyReceived(qTxId, amount, coinbase);
} }
void WalletListenerImpl::unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) void WalletListenerImpl::unconfirmedMoneyReceived(const std::string &txId, uint64_t amount)
@ -85,7 +85,7 @@ void WalletListenerImpl::onPassphraseEntered(const QString &passphrase, bool ent
m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort); m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort);
} }
Monero::optional<std::string> WalletListenerImpl::onDevicePassphraseRequest(bool & on_device) std::optional<std::string> WalletListenerImpl::onDevicePassphraseRequest(bool & on_device)
{ {
qDebug() << __FUNCTION__; qDebug() << __FUNCTION__;
return m_phelper.onDevicePassphraseRequest(on_device); return m_phelper.onDevicePassphraseRequest(on_device);

View file

@ -16,7 +16,7 @@ public:
virtual void moneySpent(const std::string &txId, uint64_t amount) override; virtual void moneySpent(const std::string &txId, uint64_t amount) override;
virtual void moneyReceived(const std::string &txId, uint64_t amount) override; virtual void moneyReceived(const std::string &txId, uint64_t amount, bool coinbase) override;
virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override; virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override;
@ -35,7 +35,7 @@ public:
virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) override; virtual void onPassphraseEntered(const QString &passphrase, bool enter_on_device, bool entry_abort) override;
virtual Monero::optional<std::string> onDevicePassphraseRequest(bool & on_device) override; virtual std::optional<std::string> onDevicePassphraseRequest(bool & on_device) override;
private: private:
Wallet * m_wallet; Wallet * m_wallet;

View file

@ -5,6 +5,7 @@
#include "Wallet.h" #include "Wallet.h"
#include "utils/ScopeGuard.h" #include "utils/ScopeGuard.h"
#include <wallet/api/wallet2_api.h>
class WalletPassphraseListenerImpl : public Monero::WalletListener, public PassphraseReceiver class WalletPassphraseListenerImpl : public Monero::WalletListener, public PassphraseReceiver
{ {
@ -12,7 +13,7 @@ public:
explicit WalletPassphraseListenerImpl(WalletManager * mgr): m_mgr(mgr), m_phelper(mgr) {} explicit WalletPassphraseListenerImpl(WalletManager * mgr): m_mgr(mgr), m_phelper(mgr) {}
void moneySpent(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; }; void moneySpent(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; };
void moneyReceived(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; }; void moneyReceived(const std::string &txId, uint64_t amount, bool coinbase) override { (void)txId; (void)amount; (void)coinbase;};
void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; }; void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) override { (void)txId; (void)amount; };
void newBlock(uint64_t height) override { (void) height; }; void newBlock(uint64_t height) override { (void) height; };
void updated() override {}; void updated() override {};
@ -24,7 +25,7 @@ public:
m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort); m_phelper.onPassphraseEntered(passphrase, enter_on_device, entry_abort);
} }
Monero::optional<std::string> onDevicePassphraseRequest(bool & on_device) override std::optional<std::string> onDevicePassphraseRequest(bool & on_device) override
{ {
qDebug() << __FUNCTION__; qDebug() << __FUNCTION__;
return m_phelper.onDevicePassphraseRequest(on_device); return m_phelper.onDevicePassphraseRequest(on_device);
@ -312,6 +313,7 @@ WalletManager::WalletManager(QObject *parent)
WalletManager::~WalletManager() WalletManager::~WalletManager()
{ {
qDebug() << "~WalletManager" << QThread::currentThreadId();
m_scheduler.shutdownWaitForFinished(); m_scheduler.shutdownWaitForFinished();
} }

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