Merge branch 'develop' into event_signing

Conflicts:
	synapse/federation/replication.py
This commit is contained in:
Mark Haines 2014-10-17 17:33:58 +01:00
commit dc3c2823ac
21 changed files with 101 additions and 849 deletions

View File

@ -1,510 +0,0 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
img {
border: 0;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- general body styles --------------------------------------------------- */
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink {
visibility: visible;
}
div.document p.caption {
text-align: inherit;
}
div.document td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
.align-left {
text-align: left;
}
.align-center {
clear: both;
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.document p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.refcount {
color: #060;
}
.optional {
font-size: 1.3em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
tt.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
tt.descclassname {
background-color: transparent;
}
tt.xref, a tt {
background-color: transparent;
font-weight: bold;
}
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.document div.math p {
text-align: center;
}
span.eqno {
float: right;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

View File

@ -1,14 +0,0 @@
#!/bin/bash
MATRIXDOTORG=$HOME/workspace/matrix.org
rst2html-2.7.py --stylesheet=basic.css,nature.css ../docs/specification.rst > $MATRIXDOTORG/docs/spec/index.html
rst2html-2.7.py --stylesheet=basic.css,nature.css ../docs/client-server/howto.rst > $MATRIXDOTORG/docs/howtos/client-server.html
perl -pi -e 's#<head>#<head><link rel="stylesheet" href="/site.css">#' $MATRIXDOTORG/docs/spec/index.html $MATRIXDOTORG/docs/howtos/client-server.html
perl -pi -e 's#<body>#<body><div id="header"><div id="headerContent">&nbsp;</div></div><div id="page"><div id="wrapper"><div style="text-align: center; padding: 40px;"><a href="/"><img src="/matrix.png" width="305" height="130" alt="[matrix]"/></a></div>#' $MATRIXDOTORG/docs/spec/index.html $MATRIXDOTORG/docs/howtos/client-server.html
perl -pi -e 's#</body>#</div></div><div id="footer"><div id="footerContent">&copy 2014 Matrix.org</div></div></body>#' $MATRIXDOTORG/docs/spec/index.html $MATRIXDOTORG/docs/howtos/client-server.html
scp -r $MATRIXDOTORG/docs matrix@ldc-prd-matrix-001:/sites/matrix

View File

@ -1,270 +0,0 @@
/*
* nature.css_t
* ~~~~~~~~~~~~
*
* Sphinx stylesheet -- nature theme.
*
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- page layout ----------------------------------------------------------- */
body {
font-family: Arial, sans-serif;
font-size: 100%;
/*background-color: #111;*/
color: #555;
margin: 0;
padding: 0;
}
div.documentwrapper {
float: left;
width: 100%;
}
div.bodywrapper {
margin: 0 0 0 230px;
}
hr {
border: 1px solid #B1B4B6;
}
/*
div.document {
background-color: #eee;
}
*/
div.document {
background-color: #ffffff;
color: #3E4349;
padding: 0 30px 30px 30px;
font-size: 0.9em;
}
div.footer {
color: #555;
width: 100%;
padding: 13px 0;
text-align: center;
font-size: 75%;
}
div.footer a {
color: #444;
text-decoration: underline;
}
div.related {
background-color: #6BA81E;
line-height: 32px;
color: #fff;
text-shadow: 0px 1px 0 #444;
font-size: 0.9em;
}
div.related a {
color: #E2F3CC;
}
div.sphinxsidebar {
font-size: 0.75em;
line-height: 1.5em;
}
div.sphinxsidebarwrapper{
padding: 20px 0;
}
div.sphinxsidebar h3,
div.sphinxsidebar h4 {
font-family: Arial, sans-serif;
color: #222;
font-size: 1.2em;
font-weight: normal;
margin: 0;
padding: 5px 10px;
background-color: #ddd;
text-shadow: 1px 1px 0 white
}
div.sphinxsidebar h4{
font-size: 1.1em;
}
div.sphinxsidebar h3 a {
color: #444;
}
div.sphinxsidebar p {
color: #888;
padding: 5px 20px;
}
div.sphinxsidebar p.topless {
}
div.sphinxsidebar ul {
margin: 10px 20px;
padding: 0;
color: #000;
}
div.sphinxsidebar a {
color: #444;
}
div.sphinxsidebar input {
border: 1px solid #ccc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar input[type=text]{
margin-left: 20px;
}
/* -- body styles ----------------------------------------------------------- */
a {
color: #005B81;
text-decoration: none;
}
a:hover {
color: #E32E00;
text-decoration: underline;
}
div.document h1,
div.document h2,
div.document h3,
div.document h4,
div.document h5,
div.document h6 {
font-family: Arial, sans-serif;
background-color: #BED4EB;
font-weight: normal;
color: #212224;
margin: 30px 0px 10px 0px;
padding: 5px 0 5px 10px;
text-shadow: 0px 1px 0 white
}
div.document h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
div.document h2 { font-size: 150%; background-color: #C8D5E3; }
div.document h3 { font-size: 120%; background-color: #D8DEE3; }
div.document h4 { font-size: 110%; background-color: #D8DEE3; }
div.document h5 { font-size: 100%; background-color: #D8DEE3; }
div.document h6 { font-size: 100%; background-color: #D8DEE3; }
a.headerlink {
color: #c60f0f;
font-size: 0.8em;
padding: 0 4px 0 4px;
text-decoration: none;
}
a.headerlink:hover {
background-color: #c60f0f;
color: white;
}
div.document p, div.document dd, div.document li {
line-height: 1.5em;
}
div.admonition p.admonition-title + p {
display: inline;
}
div.highlight{
background-color: white;
}
div.note {
background-color: #eee;
border: 1px solid #ccc;
}
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
div.topic {
background-color: #eee;
}
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
p.admonition-title {
display: inline;
}
p.admonition-title:after {
content: ":";
}
pre {
padding: 10px;
background-color: White;
color: #222;
line-height: 1.2em;
border: 1px solid #C6C9CB;
font-size: 1.1em;
margin: 1.5em 0 1.5em 0;
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
-moz-box-shadow: 1px 1px 1px #d8d8d8;
}
tt {
background-color: #ecf0f3;
color: #222;
/* padding: 1px 2px; */
font-size: 1.1em;
font-family: monospace;
}
.viewcode-back {
font-family: Arial, sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}
p {
margin: 0;
}
ul li dd {
margin-top: 0;
}
ul li dl {
margin-bottom: 0;
}
li dl dd {
margin-bottom: 0;
}
dd ul {
padding-left: 0;
}
li dd ul {
margin-bottom: 0;
}

View File

@ -58,8 +58,8 @@ class EventFactory(object):
random_string(10), self.hs.hostname random_string(10), self.hs.hostname
) )
if "ts" not in kwargs: if "origin_server_ts" not in kwargs:
kwargs["ts"] = int(self.clock.time_msec()) kwargs["origin_server_ts"] = int(self.clock.time_msec())
# The "age" key is a delta timestamp that should be converted into an # The "age" key is a delta timestamp that should be converted into an
# absolute timestamp the minute we see it. # absolute timestamp the minute we see it.

View File

@ -95,8 +95,8 @@ class PduCodec(object):
if k not in ["event_id", "room_id", "type"] if k not in ["event_id", "room_id", "type"]
}) })
if "ts" not in kwargs: if "origin_server_ts" not in kwargs:
kwargs["ts"] = int(self.clock.time_msec()) kwargs["origin_server_ts"] = int(self.clock.time_msec())
pdu = Pdu(**kwargs) pdu = Pdu(**kwargs)
pdu = add_event_pdu_content_hash(pdu) pdu = add_event_pdu_content_hash(pdu)

View File

@ -157,7 +157,7 @@ class TransactionActions(object):
transaction.prev_ids = yield self.store.prep_send_transaction( transaction.prev_ids = yield self.store.prep_send_transaction(
transaction.transaction_id, transaction.transaction_id,
transaction.destination, transaction.destination,
transaction.ts, transaction.origin_server_ts,
[(p["pdu_id"], p["origin"]) for p in transaction.pdus] [(p["pdu_id"], p["origin"]) for p in transaction.pdus]
) )

View File

@ -427,7 +427,7 @@ class ReplicationLayer(object):
return Transaction( return Transaction(
origin=self.server_name, origin=self.server_name,
pdus=pdus, pdus=pdus,
ts=int(time_now), origin_server_ts=int(time_now),
destination=None, destination=None,
) )
@ -595,7 +595,7 @@ class _TransactionQueue(object):
logger.debug("TX [%s] Persisting transaction...", destination) logger.debug("TX [%s] Persisting transaction...", destination)
transaction = Transaction.create_new( transaction = Transaction.create_new(
ts=int(self._clock.time_msec()), origin_server_ts=int(self._clock.time_msec()),
transaction_id=str(self._next_txn_id), transaction_id=str(self._next_txn_id),
origin=self.server_name, origin=self.server_name,
destination=destination, destination=destination,

View File

@ -41,7 +41,7 @@ class Pdu(JsonEncodedObject):
{ {
"pdu_id": "78c", "pdu_id": "78c",
"ts": 1404835423000, "origin_server_ts": 1404835423000,
"origin": "bar", "origin": "bar",
"prev_ids": [ "prev_ids": [
["23b", "foo"], ["23b", "foo"],
@ -56,7 +56,7 @@ class Pdu(JsonEncodedObject):
"pdu_id", "pdu_id",
"context", "context",
"origin", "origin",
"ts", "origin_server_ts",
"pdu_type", "pdu_type",
"destinations", "destinations",
"transaction_id", "transaction_id",
@ -84,7 +84,7 @@ class Pdu(JsonEncodedObject):
"pdu_id", "pdu_id",
"context", "context",
"origin", "origin",
"ts", "origin_server_ts",
"pdu_type", "pdu_type",
"content", "content",
] ]
@ -122,6 +122,7 @@ class Pdu(JsonEncodedObject):
""" """
if pdu_tuple: if pdu_tuple:
d = copy.copy(pdu_tuple.pdu_entry._asdict()) d = copy.copy(pdu_tuple.pdu_entry._asdict())
d["origin_server_ts"] = d.pop("ts")
for k in d.keys(): for k in d.keys():
if d[k] is None: if d[k] is None:
@ -212,7 +213,7 @@ class Transaction(JsonEncodedObject):
"transaction_id", "transaction_id",
"origin", "origin",
"destination", "destination",
"ts", "origin_server_ts",
"previous_ids", "previous_ids",
"pdus", "pdus",
"edus", "edus",
@ -229,7 +230,7 @@ class Transaction(JsonEncodedObject):
"transaction_id", "transaction_id",
"origin", "origin",
"destination", "destination",
"ts", "origin_server_ts",
"pdus", "pdus",
] ]
@ -251,10 +252,10 @@ class Transaction(JsonEncodedObject):
@staticmethod @staticmethod
def create_new(pdus, **kwargs): def create_new(pdus, **kwargs):
""" Used to create a new transaction. Will auto fill out """ Used to create a new transaction. Will auto fill out
transaction_id and ts keys. transaction_id and origin_server_ts keys.
""" """
if "ts" not in kwargs: if "origin_server_ts" not in kwargs:
raise KeyError("Require 'ts' to construct a Transaction") raise KeyError("Require 'origin_server_ts' to construct a Transaction")
if "transaction_id" not in kwargs: if "transaction_id" not in kwargs:
raise KeyError( raise KeyError(
"Require 'transaction_id' to construct a Transaction" "Require 'transaction_id' to construct a Transaction"

View File

@ -64,7 +64,7 @@ class MessageHandler(BaseHandler):
defer.returnValue(None) defer.returnValue(None)
@defer.inlineCallbacks @defer.inlineCallbacks
def send_message(self, event=None, suppress_auth=False, stamp_event=True): def send_message(self, event=None, suppress_auth=False):
""" Send a message. """ Send a message.
Args: Args:
@ -72,7 +72,6 @@ class MessageHandler(BaseHandler):
suppress_auth (bool) : True to suppress auth for this message. This suppress_auth (bool) : True to suppress auth for this message. This
is primarily so the home server can inject messages into rooms at is primarily so the home server can inject messages into rooms at
will. will.
stamp_event (bool) : True to stamp event content with server keys.
Raises: Raises:
SynapseError if something went wrong. SynapseError if something went wrong.
""" """
@ -82,9 +81,6 @@ class MessageHandler(BaseHandler):
user = self.hs.parse_userid(event.user_id) user = self.hs.parse_userid(event.user_id)
assert user.is_mine, "User must be our own: %s" % (user,) assert user.is_mine, "User must be our own: %s" % (user,)
if stamp_event:
event.content["hsob_ts"] = int(self.clock.time_msec())
snapshot = yield self.store.snapshot_room(event.room_id, event.user_id) snapshot = yield self.store.snapshot_room(event.room_id, event.user_id)
if not suppress_auth: if not suppress_auth:
@ -132,7 +128,7 @@ class MessageHandler(BaseHandler):
defer.returnValue(chunk) defer.returnValue(chunk)
@defer.inlineCallbacks @defer.inlineCallbacks
def store_room_data(self, event=None, stamp_event=True): def store_room_data(self, event=None):
""" Stores data for a room. """ Stores data for a room.
Args: Args:
@ -151,9 +147,6 @@ class MessageHandler(BaseHandler):
yield self.auth.check(event, snapshot, raises=True) yield self.auth.check(event, snapshot, raises=True)
if stamp_event:
event.content["hsob_ts"] = int(self.clock.time_msec())
yield self.state_handler.handle_new_event(event, snapshot) yield self.state_handler.handle_new_event(event, snapshot)
yield self._on_new_room_event(event, snapshot) yield self._on_new_room_event(event, snapshot)
@ -221,10 +214,7 @@ class MessageHandler(BaseHandler):
defer.returnValue(None) defer.returnValue(None)
@defer.inlineCallbacks @defer.inlineCallbacks
def send_feedback(self, event, stamp_event=True): def send_feedback(self, event):
if stamp_event:
event.content["hsob_ts"] = int(self.clock.time_msec())
snapshot = yield self.store.snapshot_room(event.room_id, event.user_id) snapshot = yield self.store.snapshot_room(event.room_id, event.user_id)
yield self.auth.check(event, snapshot, raises=True) yield self.auth.check(event, snapshot, raises=True)

View File

@ -68,7 +68,7 @@ class PresenceStatusRestServlet(RestServlet):
yield self.handlers.presence_handler.set_state( yield self.handlers.presence_handler.set_state(
target_user=user, auth_user=auth_user, state=state) target_user=user, auth_user=auth_user, state=state)
defer.returnValue((200, "")) defer.returnValue((200, {}))
def on_OPTIONS(self, request): def on_OPTIONS(self, request):
return (200, {}) return (200, {})
@ -141,7 +141,7 @@ class PresenceListRestServlet(RestServlet):
yield defer.DeferredList(deferreds) yield defer.DeferredList(deferreds)
defer.returnValue((200, "")) defer.returnValue((200, {}))
def on_OPTIONS(self, request): def on_OPTIONS(self, request):
return (200, {}) return (200, {})

View File

@ -163,6 +163,8 @@ class DataStore(RoomMemberStore, RoomStore,
cols["unrecognized_keys"] = json.dumps(unrec_keys) cols["unrecognized_keys"] = json.dumps(unrec_keys)
cols["ts"] = cols.pop("origin_server_ts")
logger.debug("Persisting: %s", repr(cols)) logger.debug("Persisting: %s", repr(cols))
for hash_alg, hash_base64 in pdu.hashes.items(): for hash_alg, hash_base64 in pdu.hashes.items():

View File

@ -354,6 +354,7 @@ class SQLBaseStore(object):
d.pop("stream_ordering", None) d.pop("stream_ordering", None)
d.pop("topological_ordering", None) d.pop("topological_ordering", None)
d.pop("processed", None) d.pop("processed", None)
d["origin_server_ts"] = d.pop("ts", 0)
d.update(json.loads(row_dict["unrecognized_keys"])) d.update(json.loads(row_dict["unrecognized_keys"]))
d["content"] = json.loads(d["content"]) d["content"] = json.loads(d["content"])
@ -361,7 +362,7 @@ class SQLBaseStore(object):
if "age_ts" not in d: if "age_ts" not in d:
# For compatibility # For compatibility
d["age_ts"] = d["ts"] if "ts" in d else 0 d["age_ts"] = d.get("origin_server_ts", 0)
return self.event_factory.create_event( return self.event_factory.create_event(
etype=d["type"], etype=d["type"],

View File

@ -87,7 +87,8 @@ class TransactionStore(SQLBaseStore):
txn.execute(query, (code, response_json, transaction_id, origin)) txn.execute(query, (code, response_json, transaction_id, origin))
def prep_send_transaction(self, transaction_id, destination, ts, pdu_list): def prep_send_transaction(self, transaction_id, destination,
origin_server_ts, pdu_list):
"""Persists an outgoing transaction and calculates the values for the """Persists an outgoing transaction and calculates the values for the
previous transaction id list. previous transaction id list.
@ -97,7 +98,7 @@ class TransactionStore(SQLBaseStore):
Args: Args:
transaction_id (str) transaction_id (str)
destination (str) destination (str)
ts (int) origin_server_ts (int)
pdu_list (list) pdu_list (list)
Returns: Returns:
@ -106,11 +107,11 @@ class TransactionStore(SQLBaseStore):
return self.runInteraction( return self.runInteraction(
self._prep_send_transaction, self._prep_send_transaction,
transaction_id, destination, ts, pdu_list transaction_id, destination, origin_server_ts, pdu_list
) )
def _prep_send_transaction(self, txn, transaction_id, destination, ts, def _prep_send_transaction(self, txn, transaction_id, destination,
pdu_list): origin_server_ts, pdu_list):
# First we find out what the prev_txs should be. # First we find out what the prev_txs should be.
# Since we know that we are only sending one transaction at a time, # Since we know that we are only sending one transaction at a time,
@ -131,7 +132,7 @@ class TransactionStore(SQLBaseStore):
None, None,
transaction_id=transaction_id, transaction_id=transaction_id,
destination=destination, destination=destination,
ts=ts, ts=origin_server_ts,
response_code=0, response_code=0,
response_json=None response_json=None
)) ))

View File

@ -158,7 +158,7 @@ class FederationTestCase(unittest.TestCase):
origin="red", origin="red",
destinations=["remote"], destinations=["remote"],
context="my-context", context="my-context",
ts=123456789002, origin_server_ts=123456789002,
pdu_type="m.test", pdu_type="m.test",
content={"testing": "content here"}, content={"testing": "content here"},
depth=1, depth=1,
@ -170,14 +170,14 @@ class FederationTestCase(unittest.TestCase):
"remote", "remote",
path="/_matrix/federation/v1/send/1000000/", path="/_matrix/federation/v1/send/1000000/",
data={ data={
"ts": 1000000, "origin_server_ts": 1000000,
"origin": "test", "origin": "test",
"pdus": [ "pdus": [
{ {
"origin": "red", "origin": "red",
"pdu_id": "abc123def456", "pdu_id": "abc123def456",
"prev_pdus": [], "prev_pdus": [],
"ts": 123456789002, "origin_server_ts": 123456789002,
"context": "my-context", "context": "my-context",
"pdu_type": "m.test", "pdu_type": "m.test",
"is_state": False, "is_state": False,
@ -209,7 +209,7 @@ class FederationTestCase(unittest.TestCase):
path="/_matrix/federation/v1/send/1000000/", path="/_matrix/federation/v1/send/1000000/",
data={ data={
"origin": "test", "origin": "test",
"ts": 1000000, "origin_server_ts": 1000000,
"pdus": [], "pdus": [],
"edus": [ "edus": [
{ {
@ -236,7 +236,7 @@ class FederationTestCase(unittest.TestCase):
"/_matrix/federation/v1/send/1001000/", "/_matrix/federation/v1/send/1001000/",
"""{ """{
"origin": "remote", "origin": "remote",
"ts": 1001000, "origin_server_ts": 1001000,
"pdus": [], "pdus": [],
"edus": [ "edus": [
{ {

View File

@ -75,7 +75,7 @@ class PduCodecTestCase(unittest.TestCase):
context="rooooom", context="rooooom",
pdu_type="m.room.message", pdu_type="m.room.message",
origin="bar.com", origin="bar.com",
ts=12345, origin_server_ts=12345,
depth=5, depth=5,
prev_pdus=[("alice", "bob.com")], prev_pdus=[("alice", "bob.com")],
is_state=False, is_state=False,
@ -130,7 +130,7 @@ class PduCodecTestCase(unittest.TestCase):
context="rooooom", context="rooooom",
pdu_type="m.room.topic", pdu_type="m.room.topic",
origin="bar.com", origin="bar.com",
ts=12345, origin_server_ts=12345,
depth=5, depth=5,
prev_pdus=[("alice", "bob.com")], prev_pdus=[("alice", "bob.com")],
is_state=True, is_state=True,

View File

@ -68,7 +68,7 @@ class FederationTestCase(unittest.TestCase):
pdu_type=MessageEvent.TYPE, pdu_type=MessageEvent.TYPE,
context="foo", context="foo",
content={"msgtype": u"fooo"}, content={"msgtype": u"fooo"},
ts=0, origin_server_ts=0,
pdu_id="a", pdu_id="a",
origin="b", origin="b",
) )
@ -95,7 +95,7 @@ class FederationTestCase(unittest.TestCase):
target_host=self.hostname, target_host=self.hostname,
context=room_id, context=room_id,
content={}, content={},
ts=0, origin_server_ts=0,
pdu_id="a", pdu_id="a",
origin="b", origin="b",
) )
@ -127,7 +127,7 @@ class FederationTestCase(unittest.TestCase):
state_key="@red:not%s" % self.hostname, state_key="@red:not%s" % self.hostname,
context=room_id, context=room_id,
content={}, content={},
ts=0, origin_server_ts=0,
pdu_id="a", pdu_id="a",
origin="b", origin="b",
) )

View File

@ -39,7 +39,7 @@ ONLINE = PresenceState.ONLINE
def _expect_edu(destination, edu_type, content, origin="test"): def _expect_edu(destination, edu_type, content, origin="test"):
return { return {
"origin": origin, "origin": origin,
"ts": 1000000, "origin_server_ts": 1000000,
"pdus": [], "pdus": [],
"edus": [ "edus": [
{ {

View File

@ -29,7 +29,7 @@ from synapse.handlers.typing import TypingNotificationHandler
def _expect_edu(destination, edu_type, content, origin="test"): def _expect_edu(destination, edu_type, content, origin="test"):
return { return {
"origin": origin, "origin": origin,
"ts": 1000000, "origin_server_ts": 1000000,
"pdus": [], "pdus": [],
"edus": [ "edus": [
{ {

View File

@ -599,7 +599,7 @@ def new_fake_pdu(pdu_id, context, pdu_type, state_key, prev_state_id,
prev_state_id=prev_state_id, prev_state_id=prev_state_id,
origin="example.com", origin="example.com",
context="context", context="context",
ts=1405353060021, origin_server_ts=1405353060021,
depth=depth, depth=depth,
content_json="{}", content_json="{}",
unrecognized_keys="{}", unrecognized_keys="{}",

View File

@ -80,4 +80,53 @@ angular.module('matrixWebClient')
return function(text) { return function(text) {
return $sce.trustAsHtml(text); return $sce.trustAsHtml(text);
}; };
}])
// Exactly the same as ngSanitize's linky but instead of pushing sanitized
// text in the addText function, we just push the raw text.
.filter('unsanitizedLinky', ['$sanitize', function($sanitize) {
var LINKY_URL_REGEXP =
/((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/,
MAILTO_REGEXP = /^mailto:/;
return function(text, target) {
if (!text) return text;
var match;
var raw = text;
var html = [];
var url;
var i;
while ((match = raw.match(LINKY_URL_REGEXP))) {
// We can not end in these as they are sometimes found at the end of the sentence
url = match[0];
// if we did not match ftp/http/mailto then assume mailto
if (match[2] == match[3]) url = 'mailto:' + url;
i = match.index;
addText(raw.substr(0, i));
addLink(url, match[0].replace(MAILTO_REGEXP, ''));
raw = raw.substring(i + match[0].length);
}
addText(raw);
return $sanitize(html.join(''));
function addText(text) {
if (!text) {
return;
}
html.push(text);
}
function addLink(url, text) {
html.push('<a ');
if (angular.isDefined(target)) {
html.push('target="');
html.push(target);
html.push('" ');
}
html.push('href="');
html.push(url);
html.push('">');
addText(text);
html.push('</a>');
}
};
}]); }]);

View File

@ -121,7 +121,9 @@
<span ng-show='msg.content.msgtype === "m.text"' <span ng-show='msg.content.msgtype === "m.text"'
class="message" class="message"
ng-class="containsBingWord(msg.content.body) && msg.user_id != state.user_id ? msg.echo_msg_state + ' messageBing' : msg.echo_msg_state" ng-class="containsBingWord(msg.content.body) && msg.user_id != state.user_id ? msg.echo_msg_state + ' messageBing' : msg.echo_msg_state"
ng-bind-html="((msg.content.msgtype === 'm.text') ? msg.content.body : '') | linky:'_blank'"/> ng-bind-html="(msg.content.msgtype === 'm.text' && msg.type === 'm.room.message' && msg.content.format === 'org.matrix.custom.html') ?
(msg.content.formatted_body | unsanitizedLinky) :
(msg.content.msgtype === 'm.text' && msg.type === 'm.room.message') ? (msg.content.body | linky:'_blank') : '' "/>
<span ng-show='msg.type === "m.call.invite" && msg.user_id == state.user_id'>Outgoing Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span> <span ng-show='msg.type === "m.call.invite" && msg.user_id == state.user_id'>Outgoing Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span>
<span ng-show='msg.type === "m.call.invite" && msg.user_id != state.user_id'>Incoming Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span> <span ng-show='msg.type === "m.call.invite" && msg.user_id != state.user_id'>Incoming Call{{ isWebRTCSupported ? '' : ' (But your browser does not support VoIP)' }}</span>