lilia
dfc292ac70
Serialize prekey refreshes & other account mgmt
...
Fixes #1060
// FREEBIE
2017-02-14 15:24:09 -08:00
lilia
f0f6bbb8c0
Update libsignal-protocol 1.1.8
...
// FREEBIE
2017-02-09 10:58:36 -08:00
lilia
819ba8ee74
Support for undefined preKey
2017-02-09 10:58:36 -08:00
haffenloher
d2ddfc72e4
Throw UnregisteredUserErrors in getKeysForNumber()
2017-02-08 17:13:36 -08:00
lilia
053bf20185
Group updates never have body or attachments
...
Why would they? And group.added isn't used anywhere else.
// FREEBIE
2017-02-08 16:56:29 -08:00
haffenloher
04f0142b23
Ignore missing members in incoming group updates
...
Previously, updateNumbers would throw an Error, so the whole group
update was discarded.
Signal-Android handles this the same way in
GroupMessageProcessor.handleGroupUpdate().
Closes #1056
2017-02-08 16:46:09 -08:00
lilia
7e06e014c4
Add debug logging for #1030
...
// FREEBIE
2017-02-03 21:28:01 -08:00
lilia
73e69fe5eb
Update libsignal-protocol 1.1.7
2016-10-05 22:01:52 +09:00
lilia
7c81e4ed2e
Delete extra space
2016-10-05 21:15:58 +09:00
lilia
d52050d43f
Fix group timer updates
2016-10-05 19:09:20 +09:00
lilia
1da44c847b
Fix handling sent messages sans expirationStartTimestamp
2016-10-05 19:09:20 +09:00
lilia
86dbbc9f29
Allow null expireTimer in sendmessage
2016-10-05 19:09:20 +09:00
lilia
7eea88a545
Convert expirationStartTimestamp to number
2016-10-05 19:09:20 +09:00
lilia
ad2174e279
Sync expirationStartTimestamp on outgoing messages
...
Linked devices need to know when to start the clock.
2016-09-29 16:17:01 -07:00
lilia
6074a29046
Send timer update messages when changing the timer
2016-09-29 16:17:01 -07:00
lilia
824b7417e9
Apply expireTimer to outgoing messages
2016-09-29 16:17:01 -07:00
lilia
448835e4d5
Bail early when processing timer updates
...
Also let expireTimer default to 0.
2016-09-29 13:06:25 -07:00
lilia
02ea4f2475
Use read receipt envelope to infer startExpirationTime
...
Avoids display of phantom messages that are only received and marked
read locally long after they have expired on another linked device.
2016-09-28 17:20:02 -07:00
lilia
b3e932dce8
Add protocol support for disappearing messages
2016-09-28 17:20:02 -07:00
lilia
fe209a2f41
Upgrade libsignal-protocol v1.1.6
2016-09-20 13:45:21 -07:00
lilia
7b3b01bdf6
Refactor registration event
...
Make AccountManager into an event target for better separation between
app and service-library handling of registration events.
2016-09-20 13:42:33 -07:00
lilia
b1afb79a14
Set theme based on master device userAgent
...
// FREEBIE
2016-09-15 16:28:46 -07:00
lilia
2b210b3fcd
Fix undefined websocket port
...
Fixes #889
// FREEBIE
2016-09-12 11:44:52 -07:00
lilia
384598fbcc
Log websocket urls
...
// FREEBIE
2016-09-08 14:31:20 -07:00
lilia
0487fa3cd1
Add server fallback port 8443
...
// FREEBIE
2016-09-08 14:31:19 -07:00
lilia
f610233ef6
Add support for syncing blocked numbers
...
// FREEBIE
2016-09-07 13:04:45 -07:00
lilia
254b6621c2
Update libsignal-protocol v1.1.5
...
// FREEBIE
2016-08-24 01:50:46 -07:00
lilia
d11f9fd538
Update libsignal-protocol v1.1.4
...
// FREEBIE
2016-08-18 10:41:06 -07:00
lilia
4c0ed76909
Update libsignal-protocol v1.1.3
...
// FREEBIE
2016-08-01 20:19:09 -07:00
lilia
2cea499736
Reduce log noise from prekey messages
...
// FREEBIE
2016-07-28 18:39:53 -07:00
lilia
c39d6687e5
Reduce log noise from delivery receipts
...
Stop logging envelope messages on receipts since we log the same info as
a receipt in background.js.
// FREEBIE
2016-07-28 18:39:13 -07:00
lilia
005444d09a
Update libsignal-protocol v1.1.2
...
// FREEBIE
2016-06-30 12:45:27 -07:00
lilia
5059fd237a
Disable keepalive logging
...
// FREEBIE
2016-06-29 18:22:27 -07:00
lilia
80c6a2802f
Handle sync request where no groups are sent
...
If a user has no groups, no group sync message is sent. This is a normal
result that should result in a success event rather than a timeout.
// FREEBIE
2016-06-26 15:52:57 -07:00
lilia
5fcf2ea66f
Update libsignal-protocol v1.1.1
...
// FREEBIE
2016-06-23 14:17:01 -07:00
lilia
167f19153c
Update libsignal-protocol v1.1.0
...
Moves padding operations to the service library.
// FREEBIE
2016-06-14 19:30:26 -07:00
lilia
b8fddfbbdd
Update libsignal-protocol v1.0.0
...
// FREEBIE
2016-06-14 16:27:34 -07:00
lilia
d89c3e8e86
Remove devices with no keys
...
// FREEBIE
2016-06-06 17:59:44 -07:00
lilia
89d3b772d5
Define UnregisteredUserError class
...
// FREEBIE
2016-05-25 20:20:10 -07:00
lilia
81dfdd959f
Don't allow retry on unregistered user errors
...
// FREEBIE
2016-05-24 11:36:04 -07:00
lilia
331ca46d75
Fix websocket event name
...
Fixes #798
// FREEBIE
2016-05-23 16:04:06 -07:00
lilia
15e964de81
Update libsignal-protocol v0.13.0
...
* libsignal.Curve is now a synchronous interface.
* libsignal.Curve.async is now the asynchronous interface.
* Fixes bugs in session management.
// FREEBIE
2016-05-18 14:29:30 -07:00
lilia
f216262298
Update libsignal-protocol v0.12.0
...
Moves version byte check to protocol lib.
// FREEBIE
2016-05-18 13:15:58 -07:00
lilia
055c0c323e
Remove unneeded property from device object
...
// FREEBIE
2016-05-18 13:15:57 -07:00
lilia
f8e176fd40
Dedupe methods
...
Define textsecure.crypto in terms of libsignal.crypto.
// FREEBIE
2016-05-18 13:15:57 -07:00
lilia
58452066aa
Move device storage methods to outgoing message
...
This is the only place they are called.
// FREEBIE
2016-05-18 13:15:56 -07:00
lilia
daae664965
Remove unused function
...
// FREEBIE
2016-05-18 13:15:56 -07:00
lilia
d32a352d8a
Use deviceIds/addresses instead of encodedNumbers
...
The getDeviceObjectsForNumber method returns device objects that contain
nothing but the encodedNumber property. Instead, just deal in deviceIds
until a SignalProtocolAddress is constructed to manage both the number
and deviceId.
// FREEBIE
2016-05-18 13:15:55 -07:00
lilia
95935f70ee
Remove relay check from sendmessage
...
We don't currently store any relay information about devices,
and
// FREEBIE
2016-05-18 13:15:55 -07:00
lilia
f16803018c
Update libsignal-protocol v0.11.0
...
* Changes return type from decryption functions
* Update components
// FREEBIE
2016-05-18 13:15:44 -07:00
lilia
148bd32671
Update libsignal-protocol v0.10.0
...
* Changes policy for old session deletion
* Renames putIdentityKey to saveIdentity
* Remove device messages
// FREEBIE
2016-05-18 11:11:11 -07:00
lilia
ffa702c934
Update libsignal-protocol v0.9.0
...
* Exposes crypto APIs.
* Move worker methods to libsigna.worker.
* Move ProvisioningCipher to libtextsecure.
2016-05-17 12:03:37 -07:00
lilia
cd2218ada7
Move hard-coded worker url out of libtextsecure
...
// FREEBIE
2016-05-15 17:04:13 -07:00
lilia
d5f4665fa4
MessageReceiver uses SessionCipher to retry conflicts
...
// FREEBIE
2016-05-15 17:02:45 -07:00
lilia
9ecfe6acb0
Use SignalProtocolAddress in MessageReceiver constructor
...
// FREEBIE
2016-05-15 17:02:45 -07:00
lilia
213b44935d
Update libsignal-protocol v0.8.0
...
Reorder identity key check
2016-05-15 17:02:21 -07:00
lilia
eee93987f8
Update libsignal-protocol v0.7.0
...
Remove unused methods.
// FREEBIE
2016-05-14 23:39:59 -07:00
lilia
6266050a67
Remove unused jobqueue
...
// FREEBIE
2016-05-14 23:26:34 -07:00
lilia
050ea87aaf
Get device ids instead of objects
...
// FREEBIE
2016-05-14 23:26:33 -07:00
lilia
7939b6ae98
Remove hasOpenSession from protocol_wrapper
...
// FREEBIE
2016-05-14 23:26:33 -07:00
lilia
0483fa2f97
Remove closeOpenSessionForDevice from protocol_wrapper
...
// FREEBIE
2016-05-14 23:26:33 -07:00
lilia
0d5ec60a7a
Remove handlePreKeyWhisperMessage from protocol_wrapper
...
// FREEBIE
2016-05-14 23:26:32 -07:00
lilia
8010a09045
Remove decryptWhisperMessage from protocol_wrapper
...
// FREEBIE
2016-05-14 23:26:32 -07:00
lilia
891ddacd35
Remove processPreKey from protocol_wrapper
...
Use SessionBuilder directly instead of protocol_wrapper
// FREEBIE
2016-05-14 23:26:32 -07:00
lilia
843036f0ce
Remove getRegistrationId and encryptMessageFor from protocol_wrapper
...
We can now use protocol classes like SessionCipher directly because it
supports per-device read/write serialization internally.
// FREEBIE
2016-05-14 23:26:31 -07:00
lilia
284cf5be3a
Update libsignal-protocol v0.6.0
...
Adds session accessors on SessionCipher and an internal session lock to
replace the same implemented in protocol_wrapper.js
// FREEBIE
2016-05-14 23:24:34 -07:00
lilia
92293f9da9
Update libsignal-protocol v0.5.0
...
Renames libsignal.util to libsignal.KeyHelper.
// FREEBIE
2016-05-13 19:47:39 -07:00
lilia
e68031019b
Integrate libsignal.SessionCipher
...
Bypass the old protocolInstance wrapper methods and use the shiny new
SessionCipher class directly.
// FREEBIE
2016-05-12 13:13:15 -07:00
lilia
9e6ad27fc5
Update libsignal-protocol v0.4.0
...
// FREEBIE
2016-05-11 15:30:30 -07:00
lilia
56238136ca
Remove trivial wrapper method
...
// FREEBIE
2016-05-10 19:38:44 -07:00
lilia
78cdc0cb52
Remove tempKeys
...
Now that we simply establish and save a session via SessionBuilder
rather than saving the keys to pass in during encrypt, we can stop
caching them in memory in between the identity key check and the
encryption step.
// FREEBIE
2016-05-10 19:38:42 -07:00
lilia
519d3ec31b
Update libsignal-protocol
...
// FREEBIE
2016-05-10 19:24:33 -07:00
lilia
9f871db48a
Update libsignal-protocol / Update prekey format
...
Integrates change in prekey object formatting, which now matches more
conveniently with the representation rendered by the server.
// FREEBIE
2016-05-04 00:33:05 -07:00
lilia
b385b6e48e
Update libsignal-protocol
...
SessionBuilder / SessionRecord refactor.
// FREEBIE
2016-05-04 00:05:37 -07:00
lilia
7dcaf721ca
Add keepalive logging
...
// FREEBIE
2016-04-28 11:27:15 -07:00
lilia
9a1a3bdf64
Rename axolotl to libsignal
...
// FREEBIE
2016-04-22 13:43:30 -07:00
lilia
1d60dc38fb
Rename axolotl storage
...
// FREEBIE
2016-04-22 13:43:30 -07:00
lilia
ee3bc11e3c
Rename axolotlInstance
...
// FREEBIE
2016-04-22 13:32:19 -07:00
lilia
0fe3497d0e
Update libsignal-protocol
...
Remove remaining refs to axolotl from lsp.
// FREEBIE
2016-04-22 13:29:31 -07:00
lilia
4169336776
Update libsignal protobuf package name
...
// FREEBIE
2016-04-21 19:30:34 -07:00
lilia
c1e1dd97ba
Change libsignal-protocol filenames
...
// FREEBIE
2016-04-21 18:42:43 -07:00
lilia
b1d370755a
Rename AxolotlStore
...
// FREEBIE
2016-04-21 18:36:17 -07:00
lilia
1fe5d63015
Update protocol libs
...
Rename storage functions
// FREEBIE
2016-04-21 18:36:16 -07:00
lilia
6a928e3377
Fix reference error in MessageReceiver from fe82e4
...
Fix a reference error when resolving a key conflict on an incoming end
session message. See Signal-Android/5438.
// FREEBIE
2016-04-18 16:01:46 -07:00
lilia
2d6d2a92b9
Update libaxolotl
...
// FREEBIE
2016-04-06 17:33:06 -07:00
lilia
af392c077d
Update libaxolotl
...
// FREEBIE
2016-04-03 14:25:30 -07:00
lilia
7e2c6fd6bc
Remove unused argument
...
// FREEBIE
2016-04-01 18:12:38 -07:00
lilia
ddcdc9e2ff
Log on prekey messages
...
// FREEBIE
2016-03-30 17:18:15 -07:00
lilia
960519d296
Add debug logging
...
// FREEBIE
2016-03-29 12:35:37 -07:00
lilia
2128ee63aa
Update libaxolotl
...
// FREEBIE
2016-03-14 11:28:53 -07:00
lilia
84235ef58e
Use forEach instead of loop
...
// FREEBIE
2016-03-13 14:15:16 -07:00
lilia
c02054d5da
Pass ciphertext as ArrayBuffer instead of string
...
// FREEBIE
2016-03-13 04:56:30 -07:00
lilia
6053fe67ba
Use built-in string conversion on protobuf
...
In lieu of a global helper.
// FREEBIE
2016-03-13 04:56:29 -07:00
lilia
3e0bce2b21
Move, rename, and simplify toArrayBuffer helper
...
This function is only ever used to convert groupIds from strings to
array buffers in sendmessage.
// FREEBIE
2016-03-13 04:56:28 -07:00
lilia
7dff9ac51b
Update libaxolotl
...
// FREEBIE
2016-03-13 04:56:27 -07:00
lilia
57d64fe669
Fix session corruption due to database races
...
Prevent races between encrypt and decrypt calls, and other read/write
operations on the session store by serializing session io ops per
device.
Possible fix for #535
// FREEBIE
2016-03-10 18:37:18 -08:00
lilia
5f07c74f1a
Add log statement when opening provisioning socket
...
Make it more obvious via logs which server someone is attempting to
register with (i.e., to disambiguate staging from prod).
// FREEBIE
2016-02-29 05:08:07 -08:00
lilia
2b7cbef8b1
Rename a function
...
Avoid confusing this operation with actual receipts, which are something
else.
// FREEBIE
2016-02-26 12:41:29 -08:00
lilia
8fdf58971c
Add missing semicolons
...
// FREEBIE
2016-02-24 23:10:17 -08:00
lilia
c3bbdb393f
Refactor media uploading step
...
Move this to its own function which encapsulates the error handling for
it.
// FREEBIE
2016-02-24 23:10:17 -08:00
lilia
44b1a6451d
Add validation to Message class
...
// FREEBIE
2016-02-24 23:10:16 -08:00
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
2016-02-22 17:11:17 -08:00
lilia
010297f4c5
Track groups I've left
...
// FREEBIE
2016-02-22 17:11:16 -08:00
lilia
7e82d1295c
Handle attachment upload errors
...
Adds a new kind of replayable error that handles retry of pre-encryption
failures, e.g., attachment upload.
Fixes #485
// FREEBIE
2016-02-09 13:21:32 -08:00
lilia
910e37649a
Let group messages use new Message class
...
// FREEBIE
2016-02-08 17:07:49 -08:00
lilia
3bffdd96f5
Add sendMessage to handle sending from Message class
...
// FREEBIE
2016-02-08 17:07:49 -08:00
lilia
ecdfa09e97
Create a helper class for constructing messages
...
// FREEBIE
2016-02-08 17:07:48 -08:00
lilia
b73a3aea80
Fix syntax error
...
// FREEBIE
2016-02-08 15:58:06 -08:00
lilia
cee2b3163a
Add missing bind in messageReceiver
...
// FREEBIE
2016-02-08 15:49:34 -08:00
lilia
7dcad67410
Fix handleSentMessage
...
Missing a bind in 27fe7e3
.
// FREEBIE
2016-02-05 11:11:34 -08:00
lilia
d4760452d1
Add signal agent to server requests
...
// FREEBIE
2016-02-04 14:13:04 -08:00
lilia
27fe7e355e
Process end session flags in sync messages
...
Because remote clients will delete all sessions in response to an end
session message, regardless of which device it came from, when our
linked device sends an end session message, we must also end all
sessions with the destination.
This change moves the end session flag processing to processDecrypted,
which is shared between handlers of sent messages, data messages, and
messages which are re-tried after resolving identity conflicts.
// FREEBIE
2016-02-04 11:25:53 -08:00
lilia
fe82e469f2
Make end session consistent with android
...
Close all the sessions for a number when receiving an end session
message.
// FREEBIE
2016-02-03 17:56:24 -08:00
lilia
86132a38a8
Log envelopes and session end events
...
Help debug bad session errors by logging some envelope info about the
message we are about to decrypt. With this, if there is a decryption
error (e.g., bad mac or no session) it is clear from the logs what
number and device message sent the bad message.
Also log when we send and receive end session messages and when we close
sessions for certain devices.
// FREEBIE
2016-02-02 16:16:42 -08:00
lilia
a9cba1471a
Update our own key on re-install
...
Previously we would delete our own key from the trust store when
re-linking, in case it changed. We can also immediately take one step
further and store the new key. Typically this happens in the course of
requesting sync info from the master device, except in the case of
standalone clients.
Closes #596
// FREEBIE
2016-01-21 19:25:55 -08:00
lilia
30aa13079f
Fix sync request argument check
...
Fixes #609
// FREEBIE
2016-01-15 01:40:40 -08:00
lilia
d6da77b6f4
Throw exception on bad args to SyncRequest
...
// FREEBIE
2016-01-14 15:57:38 -08:00
lilia
1b68e652cc
Fire group sync completion event despite errors
...
Sometimes an error is thrown while processing groups from a group sync
message. We still want to fire the groupsync event when we're done
handling all the data, even if some of it was bad.
2016-01-14 15:44:44 -08:00
lilia
75b2c9c5de
Fix crash when removing a listener
...
// FREEBIE
2016-01-14 15:44:43 -08:00
lilia
f7c4fd2fed
DRY up event target implementations
...
Dedupe event target code and make it extensible.
// FREEBIE
2016-01-14 15:44:42 -08:00
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
2016-01-14 15:44:42 -08:00
Karel Bilek
d8381cfc47
Dispatch an event after processing a group sync
...
Related #521
2016-01-14 11:18:21 -08:00
lilia
96520e9fd4
Move envelope decode before ack
...
We should not ack envelope protobufs that fail to decode correctly. If
the server happens to send us such a thing it probably indicates a
protocol mismatch between it and the client, in which case the client
needs to update and re-receive the failed message.
// FREEBIE
2016-01-11 12:14:42 -08:00
lilia
44824df6cb
Refactor for clarity
...
// FREEBIE
2016-01-11 11:00:44 -08:00
Matt Corallo
dac084b604
Send message ACKs immediately after recv, instead of after process
2016-01-11 10:55:53 -08:00
lilia
3d55f2c125
Update libtextsecure
...
Recompile missed in 093eb00
// FREEBIE
2015-12-25 16:52:47 -08:00
lilia
d95f869d62
More logging
...
// FREEBIE
2015-12-17 16:42:54 -08:00
lilia
d201c65f7c
More verbose logging in message receiver
...
// FREEBIE
2015-12-17 16:36:13 -08:00
lilia
bc576e18d5
Fix no delivery receipts on close session messages
...
// FREEBIE
2015-12-11 12:06:45 -08:00
lilia
9031b4c10c
Update libaxolotl
...
Fixes #477
// FREEBIE
2015-12-08 10:51:52 -08:00
lilia
ea980b4385
Don't surface invalid attachment urls to the user
...
Log them, but don't put display them in user-facing error ui.
// FREEBIE
2015-12-07 16:52:45 -08:00
lilia
7b1268e5f7
Log incoming invalid attachment urls also
...
Same as previous commit but for incoming.
// FREEBIE
2015-12-07 16:43:59 -08:00
lilia
fe7505c050
Log invalid attachment urls
...
// FREEBIE
2015-12-07 16:07:10 -08:00
lilia
9c59dfda93
Remove duplicate case statement
...
This line was never being hit due to the duplicate one above (#L166).
Peeking at the server code shows that 403 is only given in response to
registration attempts, where it does in fact indicate an invalid code.
// FREEBIE
2015-12-05 11:07:31 -08:00
lilia
2f469835d9
Handle group quit sync messages
...
Previously, we would incorrectly reject group updates originating from a
linked device instructing us to remove ourselves from the group.
// FREEBIE
2015-12-04 11:25:19 -08:00
lilia
edcb28aebb
Don't save a MessageCounterError
...
Fixes #446
// FREEBIE
2015-12-04 11:20:12 -08:00
lilia
b00d5289cf
Save message timestamp for resending
...
Fix bug where resending due to failed network connection would fail
silently.
Broken in 7b6820 refactor which changed arguments to transmitMessage
// FREEBIE
2015-11-29 18:02:37 -08:00
lilia
e9949152bb
Always return a promise from sendSyncMessage
...
// FREEBIE
2015-11-27 22:26:56 -08:00
lilia
acae4afce3
Handle invalid responses better
...
Depending on the response code, returning an HTTPError here will let us
retry later, if appropriate.
// FREEBIE
2015-11-27 22:26:56 -08:00
lilia
52b039a900
Remove unused function
...
This is now used only internally in libaxolotl, which provides its own
definition.
// FREEBIE
2015-11-27 14:40:20 -08:00
lilia
6445581594
Update libaxolotl
...
isEqual added to internal helper module
// FREEBIE
2015-11-27 14:40:19 -08:00
lilia
63cd3b2788
Use constant time mac comparison
...
In libtextsecure and in libaxolotl.
// FREEBIE
2015-11-27 14:40:17 -08:00
lilia
61439a886f
Validate json responses
...
Perform lightweight validation on json responses from the server. Ensure
that the attributes we depend on have the right type.
// FREEBIE
2015-11-25 12:16:36 -08:00
lilia
b0d4370c2c
Remove unused variable
...
// FREEBIE
2015-11-25 11:42:16 -08:00
lilia
07702c4ee5
Let the application layer send sync messages
...
Previously, libtextsecure would send a sync message automatically
when appropriate. This fails if any recipient has a key conflict
or if our network connection fails mid-send.
Instead, when appropriate, return a the DataMessage encoded as an array
buffer for later syncing. This lets the application choose when to send
it, which we now do after any successful send to a recipient, rather
than after all recipients are successfully sent to.
Eventually we should move the DataMessage protobuf construction and
group sending logic to the application layer entirely, in which case
we wouldn't need libtextsecure to construct the sync message either.
Fixes #408
2015-11-24 17:11:03 -08:00
lilia
5c37c3d6ce
Change return type from sending messages
...
Pass the whole result from the outgoing message callback on to the
caller, and preserve the names of the members.
// FREEBIE
2015-11-24 17:05:25 -08:00
lilia
7b6820d2ac
Refactor messageSender/OutgoingMessage
...
Move encrypt and transmit to OutgoingMessage
Restore per-number queueing to messageSender
// FREEBIE
2015-11-24 17:05:24 -08:00
lilia
adf8445b85
Populate registrationIds on deviceObjects
...
Saves us from doing so later.
// FREEBIE
2015-11-24 17:05:23 -08:00
lilia
cf85c5e25e
Fix key conflict with self after master device re-install
...
Fix bug where re-installing would cause sync messages to fail and
produce unresolvable error indicators on messages that were actually
sent.
// FREEBIE
2015-11-24 16:20:07 -08:00
lilia
4cc6b1ff9a
Validate attachment urls
...
// FREEBIE
2015-11-24 16:20:07 -08:00