Fix bug where re-installing would cause sync messages to fail and
produce unresolvable error indicators on messages that were actually
sent.
// FREEBIE
If you had an inaccurate unread count due to previously broken unread
tracking, it's possible to go negative and never fully recover. Fixed
by clamping to zero.
// FREEBIE
Messages that are received in the active conversation while the window
is focused, are automatically marked as read.
The conversation appears as unread for a split second as the incoming message
arrives but it gets marked as read as soon as the message is displayed.
The window title now shows the global number of unread messages as
"Signal (1)". This way the user can see the number of unread messages
in the task bar and when alt-tabbing.
Resolves: #384
Fixed the global counting of unread messages. This makes the "unreadCount"
variable in storage to stay in sync with the sum of unread messages in each
conversation. To achieve this, the controller_view updates the global
variable whenever messages are received or read.
encryptMessageFor now requires an array buffer instead of a protobuf.
By converting the message to an array buffer outside the Promise.all, we
avoid allocating a new copy for each device.
// FREEBIE
We don't need to keep them in memory if we're done viewing them,
plus it avoids having to re-render a large collection when we re-open a
conversation. Now that we only load a sensible number of messages at a
time, caching them between usages is less valuable. Removing them from
the collection should free them for garbage collection.
// FREEBIE
Messages with images or media were causing the scroll position to jump
around when they loaded, because rendering them changed the height of their
elements from 0 to full-height sometime after they were inserted into
the DOM.
Now when rendering attachments, we wait for them to load so they can
render at full height immediately, then warn our parent message list
before and after a potential height change, so the scroll position can
be saved and reset.
// FREEBIE
Only load the most recent messages when initially rendering a
conversation. Scrolling to the top of a message list loads older
messages.
This required some slight refactoring of how we insert message elements
into the dom. If the message is added to the end of the collection,
append it at the end. Otherwise, assume it is an older message and
prepend it.
When adding elements to the top, reset the scrollPosition to its
previous distance from scrollHeight. This keeps the current set of
elements fixed in the viewport.
// FREEBIE
Add db adapter support for clean cursor termination when passing
options.index and options.limit together. Previously this would cause a
crash because options.conditions was undefined.
// FREEBIE
Renames extension.windows.beforeUnload to onSuspend, to match the
underlying chrome api call. onClosed fires when the frontend app window
is closed, while onSuspend fires when the background page is closed or
refreshed (which amounts to an app restart).
Frontend views are initialized iff the inbox window is opened, and so
should always be listening to onClosed in order to know when they are no
longer needed.
// FREEBIE
1. Update chrome version because v40 fails to clear the session store
2. Add message view to test page and fix bad reference to chrome
3. Update the message view template in tests with new timestmap markup
// FREEBIE
Create a cleaner seperation between generating notifications
and updating frontend conversation views. The former is now
handled by `conversation.notify` while the latter is achieved
by triggering an event on the conversation model, which will
only be acted on if there are any views listening for it.
Additionally, instead of re-fetching the entire message history,
which is overkill, just add or update the new/modified message.
This will help speed up the newmessage event handler and also
help avoid unnecessary re-rendering when resolving key conflicts.
// FREEBIE
Follow up to b0da4910. When inferring membership of the sender in an
unknown group, remember to save and return the group members.
Generally, this should only effect standalone clients unless someone
managed to clear their groups db table, since linked clients get group
info synced at registration.
// FREEBIE
If you're the last member of the group, it doesn't make sense to send
messages to it. Previously, we would wait forever for a callback,
causing a stuck pending state indicator.
// FREEBIE
Follow up to ddd2e67eb5
but for incoming messages.
* Conflict state sometimes failed to be removed even though the
conflict was resolved.
* Messages failed to re-render after a conflict. We want to
re-render only the error state on outgoing messages, to avoid
flickering attachments. On incoming messages, we need to call
render to populate the message text, avatar, etc...
// FREEBIE
Display format consistent with Android:
* relative time for everything from today
* Day of week + time for within the past 7 days
* Static Month Day time for everything older
Each timestamp will only update as often as needed to stay accurate,
which is once a minute, once an hour, once a week, or never.
// FREEBIE
* Don't open message detail views from message detail views
* When message errors change, re-render the error state, but
not the message markup and contents.
* Fix renderErrors bug not removing the error class correctly.
// FREEBIE
Previously, with a mix of text and media messages in conflict,
asynchronous callbacks aligned so as to fail to remove some of
the conflict objects on messages.
Fix by serializing conflict processing, but making sure to move
on through the message list even if some conflict resolutions fail.
Fixes#370
// FREEBIE
* Refactor options.js into a view
* Break up install flow into a series of screens
* Remove bootstrap
* Make installer window static size, mostly to facilitate positioning
// FREEBIE
When we re-register, our deviceId might change, which makes our sessions
are no longer valid since the recipient will see us as a new device.
Fixes#388
Fix a bad loop scope bug in getKeysForNumber by using forEach.
Refactor the initial process of establishing key material for devices
that do not have open sessions.
// FREEBIE
For non text messages (ex: media messages and group updates), the
lastMessage field was being populated with empty string, resulting in an
empty message preview in the conversation list. Instead, display 'Media
message' or 'Updated the group', etc...
// FREEBIE
These functions accept an array buffer and extract an AES and MAC key
from it without verifying it has the appropriate length. Ciphertext
messages are similarly dissected. The slice function does not raise an
error on out of bounds accesses but instead returns an empty or
partially-filled array. Empty or short arrays will be passed through to
the window.crypto.subtle API, where they will raise an error. We should
not rely on the Web Crypto API to validate key lengths or for MAC checks
to fail. Instead, validate the lengths of given parameters before
extracting their components.
// FREEBIE
This may increase processing latency a bit, particularly with large
attachments, but will ensure that messages are dispatched in the order
they are received.
It would be nice to enforce ordering on only the dispatch step, so that
we could, for example, decrypt the next websocket message while waiting
for an attachment to download, but that will require a more complicated
refactor. Will stick with the quick fix for now and revisit later.
Fixes#342
// FREEBIE
It's rare that we get in a state where we have a device record without a
session, but we should handle errors gracefully in that case. Catch them
and register them, except for identity key errors which are registered
in handleResult.
// FREEBIE
fixup error handling // FREEBIE
This function dynamically declares a bunch of functions which bind to
its input arguments. Instead, use a new prototypal class to define
these functions within the context of a particular message.
// FREEBIE
Add a pendingMessages object to MessageSender. This object holds
one promise per recipient number. We init this promise with
Promise.resolve(), and chain on promises for message sending, replacing
the previous promise with the newly chained promise each time. If the
current promise resolves and finds that it is still the last promise
in the chain, it removes itself.
Websocket resources should have their keepalive timers reset whenever a
message comes in. This is a nicety that slightly reduces the amount of
traffic we send when actively messaging.
Previously this was handled by MessageReceiver, but it's a bit cleaner
to just have the WebsocketResource add an extra 'message' event handler.
// FREEBIE
Bind the sub-view to some data when we initialize it, rather than
passing it in on render. That means the image view click handler will
only ever open the blob we bound it to, even if its src attr changes for
some reason, which should never happen, but if it does, it's nice to
guard against opening arbitrary urls found in the dom.
// FREEBIE
Images that are attached to messages, either sent or received
can be opened in a new tab by clicking on them.
The previous approach that used Anchors to open the image
attachmets failed in various systems because:
- Chrome on Windows recognised "blob" as protocol and tried
to find an app for it
- Chromium on Ubuntu didn't open a new window to load the URL
The new approach adds a "click" listener to the IMG element and
opens the link using window.open (which seems to be working globaly).
Resolves: #252
In rare cases, a race between delivery receipts and outgoing message
requests can cause the sent flag to be reversed. Fix by marking messages
sent at the same time they are marked delivered.
// FREEBIE
Per WhisperSystems/TextSecure@8a1428e, bump GIF limit to 5MB, and
audio/video limit to 100MB. Update toast to notify in correct
human-readable units. The only kB size limit is for images, and will
trigger only if after scaling up to 4 times, the rescaled image did not
come in under the size limit without unacceptable quality loss.
Closes#354
Using the search field produces a filtered view of all contacts and
groups containing the input. To make this fast and scalable, add an
index on a 'tokens' array containing words from the conversation name
and different forms of phone number.
Closes#365
// FREEBIE
Split into separate encrypt and transmit functions. Let the encryption
function also handle all wire formatting (ie, jsonification and base64
encoding), which simplifes TextSecureServer.sendMessages, removes a
TODO, and lets us save fewer params to make network errors replayable.
// FREEBIE
The resend button should disappear once you've clicked it. This was not
happening because the message detail view held a cached copy of the old
message errors. Fix by re-reading the errors when we re-render.
// FREEBIE
This ensures that the containing promise is rejected without triggering
the side effects of an uncaught exception, such as causing the debugger
to pause.
// FREEBIE