Some users [are unable to register][1] because the server [returns a 400
error][2] if passed an invalid `Accept-Language` header.
This commit helps prevent two possible error modes:
- Filters out invalid language tags. Some users reported a "Workshopx"
language, which the server would reject because it's syntactically
invalid. Deleting this language (at the OS level) let them register.
- If no languages are valid, we should send `*` instead of the empty
string. There's no evidence that this happened in practice.
In addition, this commit:
- Adds tests.
- Sends a maximum of 10 languages instead of 6.
- Omits the `q` value when it's 1 because [that's the default][3].
- Marginally improves performance by iterating lazily.
[1]: https://github.com/signalapp/Signal-iOS/issues/5261
[2]: bf6d3aa324/service/src/main/java/org/whispersystems/textsecuregcm/controllers/AccountController.java (L271-L275)
[3]: https://www.rfc-editor.org/rfc/rfc9110.html#section-12.4.2
Co-authored-by: Nora Trapp <nora@signal.org>
This commit:
1. Adds a new donation receipt type: gifts.
2. Saves receipts when sending someone a gift.
The first part was the main challenge. Previously, donation receipts had
logic like this (pseudocode):
def getReceiptType(self):
if self.subscriptionLevel:
return "subscription"
else:
return "one-time"
Now, we explicitly encode the type and have logic to handle "legacy"
receipts that don't have a type encoded.
This disgusting hack removes GRDB's notification
center observers, which prevents it from calling
`DatabasePool.releaseMemory()`.
`releaseMemory` is harmful because it places all
future reads behind a dispatch barrier. The effect
is that even very short reads block on any db
reads that precede the barrier. Some of those can
be very slow, such as orphan message handling.
The practical effect of this barrier is that the
main thread gets stuck on what should be a very
quick operation, such as loading your own avatar
data. iOS can kill the app with 8badf00d.
This change is a temporary workaround. A proper
solution has been added to a PR that I sent to
GRDB, which you can see here:
https://github.com/groue/GRDB.swift/pull/1253
Once that is accepted upstream we should update
GRDB and revert this commit.
This change should fix IOS-2474 and doubtless many
other issues.
This are unused since things got refactored in ec66f3b21e. It
appears as though `contentDescription` is just called directly rather
than calling these wrappers.
Previously, sending a gift badge was not a durable operation, which
meant that crashes/failures could cause users to have their payment
methods charged without actually sending the badge.
Now, the flow is split up into two steps: non-durable parts before the
charge is attempted, and durable parts afterward.
The high-level flow is:
1. Prepare the payment, which involves a couple of repeatable network
requests.
2. Enqueue a job with the prepared payment, that:
1. Charges the payment method (idempotently)
2. Requests a receipt credential (idempotently)
3. Enqueues a gift message, and optionally a text message
3. When the job completes, open the conversation in the UI.
The database writes are ultimately serial, so there’s little benefit to
scheduling each of these on its own queue. If another slow-ish write is
already happening, there’s a chance that we may see thread explosion,
with many threads waiting to write to the database.
We frequently send outgoing messages with some parameters, like "link
preview" or "quoted reply", empty.
This change lets those parameters be omitted (instead of explicitly
empty) for brevity.
This is a stylistic change and should have no user impact.
Tested this by sending a regular message, a message with a link preview,
and two messages with photos.
If you've got the `giftBadgeSending` flag enabled, you can now send gift
badges to anyone who has the capability.
This commit doesn't complete the feature, though. It is missing:
- Proper durability and error handling (to be addressed separately)
- Saving of receipts
- A few other cleanups
This makes a few small changes to `OWSRequestFactory.boostCreatePaymentIntent()`:
- Adds tests
- Rewrites the function in Swift
I made sure I could do a boost (in staging) in the simulator.
anyUpdate runs its closure twice with different
messages but the batching context applied updates
always to the same copy of the message.
Also apply lint fixes.
* Little fix for context menu
* Add 'My Stories' section to stories tab
* Add new story thread types
* Show stories in conversation picker
* Support for sending stories
* Update story list when sending stories
* Add basic 'My Stories' view controller
* Initial stories settings screens
* Consolidate TSPrivateStoryThread and TSMyStoryThread into one class
* Require an explicit read transaction to initialize an outgoing message
* Fix linting
* Allow enabling group story from internal settings
* Fix tests
* PR Feedback
This respects the `giftBadges` capability when trying to send gift
badges. In other words, it prevents you from sending gift badges to
someone who lacks the capability.
The bulk of this change involves fetching and saving of this new
capability. The rest of the code involves showing it on the "choose
recipient" screen (and some debug screens).
A migration (introduced in b2c0e975b6)
tries to save legacy avatars to disk. However, if that legacy avatar
data is invalid, we'd crash on launch.
A user encountered this.
Our possible solutions:
1. If legacy avatar data is invalid, just drop it.
2. If legacy avatar data is invalid, try to repair it. (For example, if
it's too large, try to resize it.) This might not fix the user's
issue—unfortunately, we don't know why the avatar was invalid.
3. Loosen our definition of a valid avatar. (For example, increase the
maximum size.) This also might not fix things—we don't know how the
avatar was invalid.
I went with the first solution.
This was difficult to test. While developing, I made a temporary button
that (1) updated a group, giving it an empty legacy avatar buffer (2)
tried to migrate it.
(Thanks to c5bd634ff1 for making this easy
to diagnose!)
The purpose of this change is to alleviate the
main source of CPU-grinding after sending a
message to a large group: about 20% of the total
time is spent decoding and re-encoding messages as
they are fetched from the DB and then updated with
info about which recipients have acknowledged
delivery.
Prior to this commit, we decrypted the payload and
then processed the message in a single rather deep
call tree that began in `processNextBatch`. There
are two completely different paths through this
tree that lead to handling a delivery receipt
because server-generated delivery receipts have
the necessary info in plaintext in the envelope
and client-generated delivery receipts have it in
the ciphertext.
The idea here is to break incoming envelope
handling into two parts.
In the first part, each envelope is decrypted and
other common activities (like handling sender key
distribution messages) are performed. A processing
request is created for each. Next, processing
requests are handled. It's easy to examine a
processing request to determine if it is a
delivery receipt, and if so, for what outgoing
message. Doing so allows the new
DeliveryReceiptContext class to cache message
fetches and combine updates to the same message.
Processing requests are grouped together so that
sequential delivery receipt requests enjoy caching
of messages and coalescing of updates into a
single fetch/decode/encode/commit. Other kinds of
envelopes are handled immediately to avoid
increasing memory pressure that caching multiple
messages could cause.
The gist is:
```diff
-foo = foo + 1
+foo += 1
```
Most of the violations were in generated files, so I changed and re-ran the generator.
A few of these violations required implementing some new methods, which I added tests for.
See [the docs for this rule][0].
[0]: https://realm.github.io/SwiftLint/shorthand_operator.html
_I recommend reviewing this with whitespace changes disabled._
This fixes violations of [SwiftLint's `implicit_getter` rule][0] by
removing explicit getters when an implicit one would do.
[0]: https://realm.github.io/SwiftLint/implicit_getter.html