Commit Graph

236 Commits (50c470e53d91e4e0ecb075a0086b409d9acbce95)

Author SHA1 Message Date
lilia c4a88dd651 Fix getUnread query
Booleans are not valid keys in indexeddb.
https://www.w3.org/TR/IndexedDB/#dfn-valid-key

// FREEBIE
9 years ago
lilia 1f897f32b7 Track and sync unread messages
// FREEBIE
9 years ago
lilia 781ada64ca Add libtextsecure support for syncing read messages
Plumbing for sending and receiving a new sync protobuf for marking
messages read on/from my other devices.

// FREEBIE
9 years ago
lilia 010297f4c5 Track groups I've left
// FREEBIE
9 years ago
lilia 496ac30d6f Process delivery receipts from yourself
Fixes #668

// FREEBIE
9 years ago
lilia cd7bc78b1d Refactor delivery receipt processing
Replace the where, forEach, and found pattern with a find.

// FREEBIE
9 years ago
lilia b8602a3b42 Make migrations more robust
Occasionally these will fail if they happen to be executed before the
necessary dependencies (storage, ConversationCollection) are declared.

// FREEBIE
9 years ago
lilia 87ddcef333 Make debug log persistent
Save log entries in indexedDB rather than just in memory. Reload them
whenever the background page is refreshed.

// FREEBIE
9 years ago
lilia 925c1bdb33 Add SyncRequest class
Similar in function to an xhr request, a textsecure.SyncRequest object
is initialized from a message sender and receiver pair and initiates a
request for sync from the master device. It later fires a success event
when both contacts and groups are done syncing, or a timeout event after
one minute.

// FREEBIE
9 years ago
lilia 5223e6ed30 Stop ask to re-link forever
Clear the registration flag when we detect that our credentials have
been invalidated, but retain the knowledge that we've been registered
before, so as to preserve post-first-install behaviors like skipping the
introductory install screens, and accessing the main ui.

Fix #541

// FREEBIE
9 years ago
lilia d95f869d62 More logging
// FREEBIE
9 years ago
lilia 51fc10abb6 Don't wake up to check messages if not registered
This chrome alarm business is in place to help us wake up and check for
messages when running in the background. Without it, chrome will suspend
our app after a short period of inactivity. Upon waking, if the app
discovers it is not linked, it prompts you to link it. However, if
you've declined registration (i.e., because you already maxed out your
linked device limit, but chrome auto-added the app to another machine),
we should just wait until explicitly launched again.

Fixes #519

// FREEBIE
9 years ago
lilia 63135a2337 Fix race between sync messages and receipts
Previously, when processing a backlog of sync messages and their
delivery receipts, we would fail to mark some messages as delivered even
though we got a receipt. This was due to an async race condition between
saving a sync message and fetching it after the receipt arrives.

Fix by re-ordering idb requests such that we save the message first and
fetch it after.

Fixes #479

// FREEBIE
9 years ago
lilia 077cba284f Ignore delivery receipts from myself
// FREEBIE
9 years ago
lilia edcb28aebb Don't save a MessageCounterError
Fixes #446

// FREEBIE
9 years ago
lilia d0b1aa3829 Silently remove read messages from existing notifications
Previous commit removed notification models from the global collection
but did not actually update the existing notification.

This commit refactors the notification interface to allow us to update
it without re-surfacing the notifcation onscreen.

// FREEBIE
9 years ago
lilia 4cc6b1ff9a Validate attachment urls
// FREEBIE
10 years ago
ody 156c7c3b3d Add unread count in window title
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
10 years ago
ody 8c59862e3d Fix global unread message counting
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.
10 years ago
lilia a569e34b33 Refactor new message notification and frontend updates
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
10 years ago
lilia a32780d174 Mark delivered messages as sent
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
10 years ago
lilia d3812869d2 Don't throw errors from background
// FREEBIE
10 years ago
lilia e626355e0c Let background page instantiate AccountManagers
Remove the need to expose the server url config as a global.

// FREEBIE
10 years ago
lilia 9e9d767a30 Add MessageSender
textsecure.MessageSender takes server url and credentials and returns
a message sending interface configured for that server.

Used a wrapper function to insert a TextSecureServer instance into
sendmessage.js code at runtime. This will result in function duplication
between different MessageSender objects, pending further refactoring to
use prototypal inheritence.

// FREEBIE
10 years ago
lilia 98aa5156b0 Refactor TextSecureServer for storage
Following the pattern from previous commit, let the server class accept
a url and login credentials from the caller. Then integrate into
MessageReceiver and AccountManager.

// FREEBIE
10 years ago
lilia 19423bf909 Abstract message error handling
// FREEBIE
10 years ago
lilia 1c306df61f Workaround for #363 Multiple open sessions bug
This doesn't solve the problem in the general case, but should at least
unbreak registration.

// FREEBIE
10 years ago
lilia 9a63703340 Close the socket/keepalive when going offline
// FREEBIE
10 years ago
lilia 2bdd0106e7 Add comments
// FREEBIE
10 years ago
lilia eb1cfe9b70 Move notification listeners to background
Otherwise they will be re-registered by the frontend page.

// FREEBIE
10 years ago
lilia 3bf9e36ead Move function declarations out of storage.onready 10 years ago
lilia c8e51563a0 Refactor initial sync codepath to application layer
To reduce dependence on the message sending module, AccountManager
should send no sync requests itself.
10 years ago
lilia f00d118c93 More logging
// FREEBIE
10 years ago
lilia f6b35ffbfc Log error stack traces
// FREEBIE
10 years ago
lilia 21667d9181 Log when we start waiting for an online event
// FREEBIE
10 years ago
lilia 2243c09fea MessageReceiver is an event target
Rather than asking for a global target, the message receiver implements
the EventTarget interface itself. It does not expose the dispatchEvent
method, however. This ensures that events can only be triggered from
within the internal MessageReceiver class, which means we no longer need
to namespace them.

// FREEBIE
10 years ago
lilia a925027cd2 Refactor MessageReceiver for storage/server independence
Let the libtextsecure consumer pass in their own server url, username,
password, and signaling key, as with libtextsecure-java.

Also brings reconnect logic up into the MessageReceiver class, which
is the only place it should apply.
10 years ago
lilia c167fc964d Revert "Remove global updateInbox method"
This reverts commit 1c70293bba.

This broke tests by blocking the database deletion during test
setup.
10 years ago
lilia 1c70293bba Remove global updateInbox method
This operation now needs to be done exactly once, at startup, so we
don't need to expose a global method for it.

// FREEBIE
10 years ago
lilia 0017f196ef Move ConversationController to its own file
Encapsulate the global conversation cache collection against accidental
access, avoiding the data-clobbering bug fixed in previous commit.

Also move some one-off program initialization code from panel controller
to background.js

// FREEBIE
10 years ago
lilia 6f94888659 Use online event listener to reconnect more smrtly
No need to retry if we know we're offline.

// FREEBIE
10 years ago
lilia 37998e261d Log more errors
// FREEBIE
10 years ago
lilia df99da15c6 Mark relevant convos active/unread on key conflict
// FREEBIE
10 years ago
lilia d89e3ccdc4 Don't fetch messages from the background
Only fetch them from a frontend view. If the conversation is not open,
we don't need to load the messages, and if we do load them, they will
render before we've done the initial contact info loading (as
implemented in 74e96ce).

Fixes #344

// FREEBIE
10 years ago
lilia 0509bb0f5d Remove global updateInbox, used scoped version
// FREEBIE
10 years ago
lilia 8dc098093d On delivery receipts, reload messages only
The delivery receipt handler should only update messages, so rather than
reloading the conversation and its contacts, only reload the messages.

// FREEBIE
10 years ago
lilia f764445c86 Remove erroneous license file and headers
We only use GPLV3 around here.

// FREEBIE
10 years ago
lilia 3e5946a12b Move worker initialization to background.js
Not sure why I put it in panel controller. Probably an oversight.

// FREEBIE
10 years ago
lilia e8b4bd708e Fix lint warnings 10 years ago
lilia e3c56a0c03 Refactor and remove old window mgmt code/globals 10 years ago
lilia baa55c9018 Refactor for less model duplication 10 years ago
lilia 1f8856fa69 MessageReceiver accepts a server websocket url
// FREEBIE
10 years ago
lilia 8a10c96ab4 Reconnect once a minute if internet is down 10 years ago
lilia 9dfff879b6 Remove usage of extension.trigger
This trigger function uses chrome's runtime message passing api, which
traverses between different windows in our runtime, but we only trigger
the updateInbox event from the backgroud page, so we don't need to use
that api, which requires some extra cpu/memory overhead.

// FREEBIE
10 years ago
lilia 853b578551 Change default value for active_at
We're overriding the default with null often enough that we should
just change the default.

Consequently, no more phantom blank conversations with oneself should
appear after receiving a group update. They were being added to the
inbox because they were incorrectly initialized with an active_at value.

Fixes #281
10 years ago
lilia 971079980e Close stale windows on background refresh
All the old event listeners and in-memory objects have perished with the
old background page. Also reopen the inbox if it was already open.

Fixes #289

// FREEBIE
10 years ago
lilia 20586e2dcc Namespace events
Naming conflict was firing the error handler twice.

// FREEBIE
10 years ago
lilia 6e74ac9e28 Dispatch all network errors, not just auth errors
Also streamline the onError handler.
10 years ago
lilia 3711e0a6cd Convert throwHumanError to custom error type
Now with 200% more helpful stack traces.

// FREEBIE
10 years ago
lilia fa4022a4e3 Invert pending/sent model 10 years ago
lilia 5925c2fe84 Support for group sync
Protocol and handling is all analogous to contact sync: Multiple
GroupDetails structs are packed into a single attachment blob and parsed
on our end. We don't display the synced groups in the conversation list
until a new message is sent to one of them.

// FREEBIE
10 years ago
lilia f126e3b21b Work on auth error handling / reinstall 10 years ago
lilia 8dc4e34aaf Bug and test fixes for contact sync
Closes #135

// FREEBIE
10 years ago
lilia b0603bc91a Wrap message receiver for minimum api exposure
Initializing a message receiver opens the socket and starts listening
right away rather than requiring a separate call to connect. The only
other publicly accessible method is to query the socket status.

// FREEBIE
10 years ago
lilia 18433419c9 PushMessageContent is now DataMessage 10 years ago
lilia a833d62a71 Implement sync protocol changes
Update protobuf definitions and refactor message receive and decrypt
codepath to support new protocol, including various flavors of sync
messages (sent messages, contacts, and groups).

Also cleans up background.js and lets libtextsecure internalize
textsecure.processDecrypted and ensure that it is called before handing
DataMessages off to the application.

The Envelope structure now has a generic content field and a
legacyMessage field for backwards compatibility. We'll send outgoing
messages as legacy messages, and sync messages as "content" while
continuing to support both legacy and non-legacy messages on the receive
side until old clients have a chance to transition.
10 years ago
lilia 9882190bde Wake up once a minute to check for messages
If all the application windows are closed (and not merely hidden), the
background page will go inactive and there's nothing we can do to stop
it. However, we can ask chrome to trigger an alarm once per minute,
which will spin up the background page and check for new messages.

This will effectively keep us alive as long as chrome has open windows
or is running in the background, subject to chrome settings'
Advanced -> System -> Continue running background apps
10 years ago
lilia b83ce7a015 Delay conversation creation til post-decrypt 10 years ago
lilia 08878b3dc8 Update inbox after sending a message
Also change the event name to reflect how its being used, and stop
passing the message object around since it is not being used.

// FREEBIE
10 years ago
lilia 65a6068003 Fix for out-of-order message/receipt arrival
In a multi device world, it's possible to receive a receipt for a sync
message before the sync message actually arrives. In this case we need
to keep the receipt around and the process it when the message shows up.
10 years ago
lilia 16e9f03d8f Check for registration when launched 10 years ago
lilia 029c9754f0 Fix tests 10 years ago
lilia 002ff45312 Adapt window management to chrome app window api
Appify tabs, windows, browserAction

Port the extension.windows.focus function to new window api and
generalize its error handling in the case where the requested window
does not exist. An error will be passed to the callback.

Port extension.browserAction and rename it to the more generic
extension.onLaunched.

Use of the id option when opening a window ensures that attempting to
open a duplicate window merely focuses the existing window.

Finally, after registration, close the options window and open the
inbox.

Port extension.remove
10 years ago
lilia 3f37cd21a9 Remove remaining traces of localStorage
Add window.storage to the background page, which loads all data from the
'items' store in indexeddb, caching them in memory for synchronous
access, then override textsecure storage to use that in memory store.
10 years ago
lilia b8c5bc293c App windows cannot be refreshed 10 years ago
lilia 36b1e87214 Add textsecure.MessageReceiver
Encapsulate the websocket resources and socket setup process in a
friendly OO class. The MessageReceiver constructor expects an instance
of EventTarget on which to fire message events asynchronously. The
provider of the EventTarget can then add/remove listeners as desired.
10 years ago
lilia 6f3de68834 Move browserAction call 10 years ago
Matt Corallo 00cb420d37 Merge (un)encrypted storage layers 10 years ago
lilia 5ffa265559 Revert "Popout inbox"
This reverts commit 31e7d285e3.

This seemed like a nice feature, but the popup bubble isn't very
conducive to nontrivial user inputs, e.g. file inputs.

Fixes #211
10 years ago
lilia 9930937707 Move handlePushMessageContent to message model
And retool message handling flow to helps us avoid instantiating
duplicate message and conversation models.
10 years ago
lilia c642854ddf Extract app-level logic from libtextsecure
Ensure that both tryAgain functions return promises, allowing the
application to take appropriate action in the result of success or
failure. This lets us remove all dependency from libtextsecure on
app-level constructs like message objects/ids and the `extenion.trigger`
function.

Corresponding frontend changes to follow in another commit.
10 years ago
lilia 31e7d285e3 Popout inbox
Rather than opening the inbox in its own window, let it appear as a
browser action popup by default, but allow promotion to its own window
if requested.
10 years ago
lilia fa3699cdd3 Trigger desktop notifications
Notifications show the conversation name, avatar, and new message text.
Clicking the notification opens the conversation.
10 years ago
lilia 019a9d1fbc Unread counts
Update unreadCounts per-conversation on incoming messages. Render unread
conversations with font-weigh: bold in the inbox view.

To ensure that the inbox and conversation views remain in sync, the
background page now ensures that the same models objects are used for
both views.
10 years ago
lilia fd6e2954f7 Curtail over-zealous websocket reconnects
Closes #173

Previously, in the event of a failed websocket auth, we would attempt to
reconnect once a second ad infinitum. This changeset ensures that we
only reconnect automatically if the socket closed 'normally' as
indicated by the code on the socket's CloseEvent. Otherwise, show a
'Websocket closed' error on the inbox view.

Ideally we would show a more contextual error (ie, 'Unauthorized'), but
unfortunately the actual server response code is not available to our
code. It can be observed in the console output from the background page,
but programmatically, we only receive the WebSocket CloseEvent codes
listed here:
https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent#Status_codes

The websocket error message is displayed by a normally-hidden but ever
present socket status element. Clicking this element will immediately
refresh the background page, which will try again to open the websocket
connection.
10 years ago
Matt Corallo 5abf3073d5 Check END_SESSION messages in processDecrypted 10 years ago
lilia 06e8e0dca7 Remove an extension.trigger
No need to trigger an extension-wide event now that all our models live
in the background page. We can just update them more or less directly.
10 years ago
lilia 626b63ee7c Fix some jshints 10 years ago
lilia 296dae544d Open conversation on receiving a message w/ errors 10 years ago
lilia 85bec04010 Render leave-group messages correctly 10 years ago
lilia f00a8f1e81 Render end session messages correctly 10 years ago
lilia 96af6b56ef Handle incoming sync messages
Assign them to the correct conversation and mark them outgoing with the
correct timestamp.

Closes #150
10 years ago
Matt Corallo 403ae4376d Move attachment/websocket [en|de]cryption to libtextsecure 10 years ago
Matt Corallo 184b1ec89c Move protocol protobufs to libaxolotl/, handling DeviceControl 10 years ago
lilia a104ee9ca6 Remove unused variables 10 years ago
lilia 3279dddcc3 Consolidate window logic in panel controller
Previously the conversation window would query the background page
for a model id and then fetch the conversation. Instead, we can fetch
the conversation before opening the window, which simplifies the front
end scripts and avoids creating multiple copies of the same model.
10 years ago
lilia ce4ce164af Stop clobbering conversation attributes
Unless the background page fetches the latest details of a conversation
before updating it, it may clobber or nullify some attributes e.g., the
contact's name.
10 years ago
lilia aca3db97da New messages auto-update the inbox & conversation
When a new message arrives, if its conversation is not already opened,
the background page opens it. If it is alrady open the window is
focused. Finally, the 'message' event is triggered, resulting in
   1. the inbox refetches conversations
   2. all conversations fetch new messages

TODO: only send this event to the target window
10 years ago
lilia 51dd287b60 Break up a long line 10 years ago
lilia 607d5d3307 Abstract chrome browser action and windows stuff 10 years ago
lilia 71da6a1df1 Move index2 to index 10 years ago
Riley Shaw 94ce4d4b91 Simplify panel state management and message passing 10 years ago
Riley Shaw 783a3f7c15 Prevent duplicate conversations and refocus on click (still buggy) 10 years ago
Riley Shaw 7ec27f814f Get conversations loading through localStorage 10 years ago
Riley Shaw 2cbcb28ee3 Start on panels 10 years ago
lilia d52db8fe6f Render group updates
Not pretty, but it works. Also allows for later localization.
Copy/behavior is borrowed from the Android client.

Closes #104
Fixes #65
10 years ago
lilia 4e6faf4e27 Always listen for (re-)registration events
If we clear local storage and re-register in a foreground page, the
background page needs to re-init its websocket with the new account
credentials.
10 years ago
lilia fca67d7b0e Simplify pushMessageContent handler slightly
New private conversations have their type set in onMessageReceived. New
group conversations should be handled the same way as normal group
updates. It was pointed out we should never have to handle a group
message without a preceding group update, as those would be rejected by
textsecure.processDecrypted. An exception would be if you delete the
group from indexedDB but not localStorage, but that's not a mode we
should be supporting.

Also in this change I switched to instantiating a new conversation
object on every call to handlePushMessageContent. Originally, I thought
to use the local conversation list as a cache, but it's a bit simpler to
re-read from the database every time for now. Later on we should revisit
and optimize for fewer read/writes per incoming message.
10 years ago
lilia 0ea176dfa0 Don't require a conversation name
Just display a sensible default in the frontend if it's unset.
For private conversations this should be the phone number, for
groups, the list of numbers.
10 years ago
lilia 0292c12712 Catch and save Bad Mac errors on the incoming message model 10 years ago
lilia 40b54185f3 If we happen to get a group message with no update, use a blank name 10 years ago
Dave Sescleifer 2462aba24b Fixed timestamps and added last message to the gutter 10 years ago
lilia 80993753de Fix bug overwriting existing conversation names
On incoming messages for pre-existing conversations, don't update any
attributes unless it's a group update message.
10 years ago
lilia 30bca85f5a Fix undefined proto.source 10 years ago
lilia ccc98d2f3d Fixup delivery receipts
Uses app-level timestamps for outgoing messages.
Adds timestamp property to the outgoing jsonData.
Triggers a runtime event to notify frontend on delivery receipts.
Renders delivered messages with a 'delivered' class.
10 years ago
lilia 6cbde7894a Delivery receipts 10 years ago
lilia 9c736df7d0 Handle incoming identity key changes
This ended up turning into a rewrite/refactor of the background page.
For best results, view this diff with `-w` to ignore whitespace. In
order to support retrying message decryption, possibly at a much later
time than the message is received, we now implement the following:

Each message is saved before it is decrypted. This generates a unique
message_id which is later used to update the database entry with the
message contents, or with any errors generated during processing.

When an IncomingIdentityKeyError occurs, we catch it and save it on the
model, then update the front end as usual. When the user clicks to
accept the new key, the error is replayed, which causes the message to
be decrypted and then passed to the background page for normal
processing.
10 years ago
lilia 5762e59c41 DRY up registration event callbacks
This was just a special case of the extension.on/trigger interface.
10 years ago
lilia 470346c9c4 Save incoming messages and pass to frontend asynchronously
After a message is saved asynchronsly, fire an event and pass the
message attributes to frontend listeners via the chrome-runtime API.

This behavior is similar to the 'storage' event fired by localStorage.
11 years ago
lilia ced295a630 Move message and conversation storage to IndexedDB
Getting up and running with IndexedDB was pretty easy, thanks to
backbone. The tricky part was making reads and writes asynchronous.
In that process I did some refactoring on Whisper.Threads, which
has been renamed Conversations for consistency with the view names.

This change also adds the unlimitedStorage permission.
11 years ago
lilia 7f04439b37 New websocket protocol 11 years ago
lilia 735737f0bc Merge Whisper.Messages into Whisper Threads
Eliminates the global Whisper.Messages object and consolidates shared
send/receive logic in Whisper.Threads.

To the latter end, note that the decrypted array buffer on an attachment
pointer is now named data instead of decrypted, in order to match the
format of outgoing attachments presented by
FileReader.readAsArrayBuffers and let us use the same handler to base64
encode them.
11 years ago
lilia 5a0e199fc5 Namespace registration helpers 11 years ago
lilia 13446e9c17 "Fix dirty hack" (runtime.reload) in chromium.js
Runtime reload is overkill and causes a jarring ux. Instead, send and
receive messages across the runtime. Also, if we need to jump between
the main ui and options pages, simply navigate within the current tab
rather than spawning a new one.
11 years ago
lilia a1a528ccdd Finish abstracting native client
Firstly, don't initialize textsecure.nativclient unless the browser
supports it. The mimetype-check trick is hewn from nacl-common.js.

Secondly, nativeclient crypto functions will all automatically wait for
the module to load before sending messages, so we needn't register any
onload callbacks outside nativeclient.js. (Previously, if you wanted to
do crypto with native client, you would have to register a call back and
wait for the module to load.) Now that the native client crypto is
encapsulated behind a nice interface, it can handle all that
onload-callback jazz internally: if the module isn't loaded when you
call a nativeclient function, return a promise that waits for the load
callback, and eventually resolves with the result of the requested
command. This removes the need for textsecure.registerOnLoadCallback.

Finally, although native client has its quirks, it's significantly
faster than the alternative (emscripten compiled js), so this commit
also lets the crypto backend use native client opportunistically, if
it's available, falling back to js if not, which should make us
compatible with older versions of chrome and chromium.
11 years ago
Arlo Breault bc5dea62c3 Use FileReader to base64 encode attachments
* Implements #82
11 years ago
Marco 69ba6581b0 moved some chromium-specific code into chromium.js (using extension.navigator namespace) 11 years ago
Matt Corallo d9bf0a41fb textsecure.storage, chromium.js 11 years ago
Matt Corallo be82547ea1 Move message saving out of helpers.js 11 years ago
Matt Corallo 6bc19ef558 More namespacing 11 years ago
Matt Corallo 8d408e6d8f THOUGH SALL USE TABSTOP AND SHIFTWIDTH 4 (so that indents read right) 11 years ago
Matt Corallo 1137f9d711 Add TODO file showing what still needs to be done 11 years ago
Matt Corallo 3e60368a16 LGPL license (I'd like to be an axolotl/TS JS lib in the future) 11 years ago
Matt Corallo 2ae5628122 Send-to-self works =D 11 years ago
Matt Corallo 8db3885659 Updates, NaCL 11 years ago
Matt Corallo eec4c66ef6 Fixup dir structure 11 years ago