Previously, HomeModel could listen to all subscriptions throughout the
app, and it would handle reaction and repost counting.
Once moved to the local relay model, HomeModel no longer had access to
all subscriptions, causing those counts to disappear.
The issue was fixed by doing the counting from ThreadModel itself, which
better isolates concerns throughout the app.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit fixes a crash that caused the app to crash when getting all
the follows from a profile.
This issue was caused by a use-after-free memory error on inherited
transactions after the original transaction is deinitialized.
The issue was fixed by introducing a reference count on all transactions
and only deallocating the C transaction when the ref count goes to zero.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
The widespread usage of the SubscriptionManager caused new crashes to
occur when swapping apps.
This was caused due to an access to Ndb memory after Ndb has been closed
from the app background signal.
The issue was fixed with improved task management logic and ensuring all
subscription tasks are finished before closing Ndb.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit introduces a verification step at the relay connection
level, to help ensure notes get validated at the source and prevent
security issues associated with untrusted relays.
`RelayConnection.swift` — the source that initially handles WebSocket
messages — was analyzed, and measures were put in place to prevent
(or at least minimize) unverified nostr event data being spread
throughout the app.
The following measures were taken:
1. A note verification step was added prior to the `self.handleEvent(.nostr_event(ev))` call (which sends a Nostr response to the rest of the app for logical handling).
a. From code analysis, there is only one such call in `RelayConnection.swift`.
2. `NostrConnectionEvent`, the object that gets passed to event handlers, had its interface modified to remove the "message" case, since:
a. that could be a source of unverified nostr events.
b. it is redundant an unneeded due to the `.nostr_event` case.
c. there were no usages of it around the codebase
3. The raw websocket event handler had its label renamed to "handleUnverifiedWSEvent", to make it clear to the caller about the verification status of the data.
a. Usages of this were inspected and no significant risk was detected.
4. A new `verify` method in NdbNote was created to verify Nostr notes, and unit tests were added to confirm tampering detections around all the major fields in a Nostr note.
5. Care was taken to ensure the performance regression is as little as
possible.
It is worth noting that we will not need this once the local relay model
architecture is introduced, since that architecture ensures note
validation before it reaches the rest of the application and the user.
In other words, this is a temporary fix.
However, since the migration to that new architecture is a major
undertaking that will take some time to be completed, this fix was written
in order to address security concerns while the migration is unfinished.
This fix was written in a way that attempts to be as effective as
possible in reducing security risks without a risky and lenghty
refactor of the code that would delay the fix from being published.
Changelog-Fixed: Improved security around note validation
Closes: https://github.com/damus-io/damus/issues/1341
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit fixes a crash that occurred when swapping between Damus and
other apps.
When Damus enters background mode, NostrDB is closed and its resources
released. When Damus re-enters foreground mode, NostrDB is reopened.
However, an issue with the transaction inheritance logic
caused a race condition where a side menu profile lookup would get an
obsolete transaction containing pointers that have been freedwhen
NostrDB was closed, causing a "use-after-free" memory error.
The issue was fixed by improving the transaction inheritance logic to
double-check if the "generation" counter (which auto increments when
Damus closes and re-opens) matches the generation marked on the
thread-specific transaction. This effectively prevents lookups from
inheriting an obsolete transaction from a previous NostrDB generation.
Closes: https://github.com/damus-io/damus/issues/3167
Changelog-Fixed: Fixed an issue where the app would crash when swapping between apps
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
It was decided on a standup meeting that this feature is not important
and failing tests can be disabled.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit fixes a stack corruption issue caused by
an off-by-one error in one of the functions responsible
for parsing bech32 entities.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Previously two addresses from different memory regions were being
subtracted, which will lead to the incorrect number. This commit
improves the calculation.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Currently NostrDB does not seem to handle encryption/decryption of DMs.
Since NostrDB now controls the block parsing process and fetches note
contents directly from the database, we have to add a specific condition
that injects decrypted content directly to the ndb content parser.
This is done in conjunction with some minor refactoring to `NdbBlocks`
and associated structs, as in C those are separated between the content
string and the offsets for each block, but in Swift this is more
ergonomically represented as a standalone/self-containing object.
No changelog entry is added because the previously broken version was
never released to the public, and therefore this fix produces no
user-facing changes compared to the last released version.
Changelog-None
Closes: https://github.com/damus-io/damus/issues/3106
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
NostrDB relies on manual memory management, so it is a good idea to
enable the address sanitizer on debug configurations, as it helps find
memory-related issues on the app, which will allow us to identify memory
issues and potential crashes earlier in the development process.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit introduces new interfaces for working with NostrDB from
Swift, including `NostrFilter` conversion, subscription streaming via
AsyncStreams and lookup/wait functions.
No user-facing changes.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
The Address Sanitizer detected a heap buffer overflow during a memcpy operation
in nostrdb.c associated with note parsing.
It was found that not enough memory was being allocated to the buffer to
support all the content parsing.
Allocation size was increased to support the memory needed for the
parsing operations. However, the new number was not carefully calculated
as we will not run into this code path once we switch to the local relay
model.
Changelog-Fixed: Fixed memory error in nostrdb
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit enhances the ImageCarousel component to maintain a consistent
height when navigating between images of different aspect ratios. The
changes prevent the UI from "jumping" during carousel navigation, which
improves the overall user experience.
Key improvements:
- Added `first_image_fill` property to store dimensions of the first image
- Modified height calculation to prioritize the first image's dimensions
- Refactored image fill calculation into a reusable `compute_item_fill` method
- Added proper view clipping to prevent content overflow
- Simplified filling behavior for more predictable layout
These changes provide a smoother, more stable carousel experience by
maintaining consistent dimensions throughout image navigation.
Changelog-Changed: Improved the image sizing behavior on the image carousel for a smoother experience
Closes: https://github.com/damus-io/damus/issues/2724
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit improves error handling in the wallet's "send" feature, by
displaying more specific wallet response error messages when available.
Closes: https://github.com/damus-io/damus/issues/3095
Changelog-Fixed: Improve error handling on wallet send feature
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
During the implementation of the "hide balance" feature, the balance
view was refactored in a way that caused it to not be redacted anymore,
making it show the "??" instead of the intended skeleton loader.
This commit fixes that issue without reverting the hide balance feature.
Changelog-Fixed: Fixed issue where the text "??" would appear on the balance while loading
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Soon after tightening error handling around NWC, it was noticed that
Damus was trying to process NWC responses meant for other people,
which caused a failure around the decryption process and a spam of
errors.
This commit modifies the relay filter to include only responses destined
to the user, and also guards the NWC response processing logic to ignore
responses meant for other users.
Changelog-Changed: Improved handling around NWC responses
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Changelog-Changed: Added more human visible errors on NWC wallets to aid with troubleshooting
Changelog-Added: Added copy technical info button to user visible errors, so that users can more easily share errors with developers
Closes: https://github.com/damus-io/damus/issues/3010
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit moves Kingfisher data to Apple's designated caches folder
to avoid it from being backed up to iCloud.
Closes: https://github.com/damus-io/damus/issues/2993
Changelog-Fixed: Fixed issue where cached images would be backed up to iCloud
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This is a minor refactor on the way wallet invoice URLs are handled, in
order to better fit the interface, enforce the design pattern, and avoid
side-effects in a particular function that handles opening URLs.
This design pattern was introduced to prevent issues on the previous
pattern, where URL handling was done with side-effects inside multiple
levels of nested logic and separate function calls, which would make
debugging very difficult, and cause the app to fail silently.
Closes: https://github.com/damus-io/damus/issues/3023
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This is a palliative fix for an issue where videos become unplayable
after a long user session.
The fix works by detecting the error state anytime the video gets
played, and reinitializes the video and corresponding player views in
order to clear the error.
Changelog-Fixed: Fixed issue where some videos would become unplayable after some time using the app
Closes: https://github.com/damus-io/damus/issues/2878
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit adds a reminder to users who hold more than 100K sats in
their NWC wallet, reminding them to learn about self-custody.
Changelog-Added: Added safety reminder to wallets with higher balance
Closes: https://github.com/damus-io/damus/issues/2984
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit fixes a regression on the highlighter and share extensions,
which was caused by a change in the code's architecture, which required
the network manager to be initialized.
Fixes: 8d48f77d95138c93ed93989989fa930b61c2d6fb
Closes: https://github.com/damus-io/damus/issues/2955
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit implements a one-click Coinos wallet setup.
This was implemented using the Coinos API, and using account details
that are deterministically generated from the user's private key.
Closes: https://github.com/damus-io/damus/issues/2961
Changelog-Added: Added one-click Coinos wallet setup
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This adds a First aid tool to repair the NIP-65 relay list
Changelog-Added: Added separated first aid option for relay lists that does not need a contact list reset
Closes: https://github.com/damus-io/damus/issues/2120
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit implements a new layer called NostrNetworkManager,
responsible for managing interactions with the Nostr network, and
providing a higher level API that is easier and more secure to use for
the layer above it.
It also integrates it with the rest of the app, by moving RelayPool and PostBox
into NostrNetworkManager, along with all their usages.
Changelog-Added: Added NIP-65 relay list support
Changelog-Changed: Improved robustness of relay list handling
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit introduces a new interface that makes it easier and safer to
handle unowned NostrDB notes, by leveraging new non-copyable and borrow
features from modern Swift.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit adds the base models needed for the NIP-65 relay list support.
This introduces no user-facing changes.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This is a non-functional refactor that organizes some classes and
structs used by RelayPool under the same namespace.
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit introduces two minor improvements:
1. It ensures better consistency between ThreadModel and EventCache
2. It avoids unnecessary recursion calls on `add_event`
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This fixes a regression where ThreadModel would no longer look at
NostrDB saved notes for parent events, causing some instability on
thread loading — especially in poor networking conditions.
This was fixed by adding a call that searches for parent events in
EventCache/NostrDB each time an event is added to the ThreadModel.
That `add_event` function is the ideal spot to place the call because it
is the only interface used for all information updates incoming to the
ThreadModel, including:
- anytime an event is loaded from the network into the thread model.
- when the ThreadModel is first initialized, with an initial event.
Fixes: 74d5bee1f6
Changelog-Fixed: Fixed an issue where threads would not load properly
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Push notifications were not opened reliably. To improve robustness, the
following changes were introduced:
1. The notification opening logic was updated to become more similar to
URL handling, in a way that uses better defined interfaces and
functions that provide better result guarantees, by separating
complex handling logic, and the side-effects/mutations that
are made after computing the open action — instead of relying on a
complex logic function that produces side-effects as a result, which
obfuscates the actual behavior of the function.
2. The LoadableThreadView was expanded and renamed to
LoadableNostrEventView, to reflect that it can also handle non-thread
nostr events, such as DMs, which is a necessity for handling push
notifications.
3. A new type of Notify object, the `QueueableNotify` was introduced, to
address issues where the listener/handler is not instantiated at the
time the app notifies that there is a push notification to be opened.
This was implemented using async streams, which simplifies the usage
of this down to a simple "for-in" loop.
Closes: https://github.com/damus-io/damus/issues/2825
Changelog-Fixed: Fixed issue where some push notifications would not open in the app and leave users confused
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit implements an optional developer feature to scramble text
and blur images to prevent distractions during development and testing.
It is not perfect (It breaks some mentions and rich text objects, and
does not scramble non-alphanumeric languages such as Japanese), but
good enough to avoid distractions while working on most features.
No changelog entry is needed because this is not meant for the final
user.
Changelog-None
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit fixes an issue where the post view would scroll to the text
cursor at seemingly random times.
This was done by detaching the save view and its logic, so that we have
3 components:
1. The `PostView`
2. An auto-save view model (which is an Observable object)
3. A separate SwiftUI view for the auto-save indicator
The auto-save view model is shared between the `PostView` and the new
indicator view to ensure proper signaling and communication across
views.
However, this view model is only observed by the indicator view,
ensuring it updates its own view, while not causing any re-renders on
the rest of the `PostView`.
This refactor had the side-effect of making the auto-save logic and view
more reusable. It is now a separate collection of elements that can be
used anywhere else.
Beyond the scroll issue, this commit also prevents empty drafts from
being saved, by introducing the new save state called `.nothingToSave`
Note: No changelog item is needed because the new drafts feature was never
publicly released.
Changelog-None
Closes: https://github.com/damus-io/damus/issues/2826
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit removes rust-nostr dependency, and replaces the NIP-44 logic
with a new NIP-44 module based on the Swift NostrSDK implementation.
The decision to move away from rust-nostr and the Swift NostrSDK was
made for the following reasons:
1. `rust-nostr` caused the app size to double
2. We only need NIP44 functionality, and we don't need to bring
everything else
3. The Swift NostrSDK caused conflicts around the secp256k1 dependency
that is hard to address
4. The way we do things in the codebase is far different from the Swift
NostrSDK, and we optimize it for use with NostrDB. Bringing it an
outside library causes significant complexity in integration with
NostrDB, and would effectively cause the codebase to be split into
two different ways of achieving the same results. Therefore it is
cleaner if we stick to our own Nostr structures and functions and
focus on maintaining them.
However, the library CryptoSwift was added as a dependency, to bring in
ChaCha20 which is not supported by CryptoKit (CryptoKit supports the
ChaCha20-Poly1305 cipher, but NIP-44 uses ChaCha20 with HMAC-SHA256
instead)
Closes: https://github.com/damus-io/damus/issues/2849
Changelog-Changed: Made internal changes to reduce the app binary size
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Changelog-Changed: Improved clarity of the mute button to indicate it can be used for blocking a user
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This makes the microphone access request contain a message that is more
clear to the user
Changelog-Changed: Made the microphone access request message more clear to users
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>