-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support HS unbinding 3pids #67
Conversation
Adds autoincrement to local and global associations table so we know IDs will never be re-used if we start deleting associations. Also some bits of the unbind servlet.
Written in theory - comitting now before going to write the synapse part
So I can test federation easily
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, it's missing some important things.
I'm also very concerned that we appear to be ignoring feedback from the community in how this API is implemented.
sydent/db/threepid_associations.sql
Outdated
@@ -14,10 +14,10 @@ See the License for the specific language governing permissions and | |||
limitations under the License. | |||
*/ | |||
|
|||
CREATE TABLE IF NOT EXISTS local_threepid_associations (id integer primary key, medium varchar(16) not null, address varchar(256) not null, mxid varchar(256) not null, ts integer not null, notBefore bigint not null, notAfter bigint not null); | |||
CREATE UNIQUE INDEX IF NOT EXISTS medium_address on local_threepid_associations(medium, address); | |||
CREATE TABLE IF NOT EXISTS local_threepid_associations (id integer primary key autoincrement, medium varchar(16) not null, address varchar(256) not null, mxid varchar(256) not null, ts integer, notBefore bigint, notAfter bigint); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you write a comment which explains what it means for the nullable fields to be null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is no longer in this schema file but I've commented it in the upgrade script
sydent/db/version.py
Outdated
def upgradeSchema(self): | ||
curVer = self._getSchemaVersion() | ||
|
||
if curVer < 1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we do something to make new installations have schema v1 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this wasn't thought through very well. Hopefully this is more sensible now.
sydent/db/version.py
Outdated
) | ||
cur.execute("DROP TABLE old_local_threepid_associations") | ||
|
||
# same for global_threepid_associations |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, except we're keeping the not null
constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point: fixed
sydent/threepid/bind.py
Outdated
@@ -22,7 +23,7 @@ | |||
from sydent.db.invite_tokens import JoinTokenStore | |||
|
|||
from sydent.db.valsession import ThreePidValSessionStore | |||
from sydent.db.threepid_associations import LocalAssociationStore | |||
from sydent.db.threepid_associations import LocalAssociationStore, GlobalAssociationStore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks unused? don't you have a PEP8 checker which catches this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops. No, we probably should do if sydent were a better maintained project.
sydent/sydent.py
Outdated
from http.servlets.replication import ReplicationPushServlet | ||
from http.servlets.getvalidated3pidservlet import GetValidated3pidServlet | ||
from http.servlets.store_invite_servlet import StoreInviteServlet | ||
|
||
from db.version import VersionStore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be up with "from db.sqlitedb import SqliteDatabase" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's gone now anyway
@@ -100,6 +102,9 @@ def pushUpdates(self, sgAssocs): | |||
'/_matrix/identity/replicate/v1/push', | |||
body) | |||
|
|||
# XXX: We'll also need to prune the deleted associations out of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought this was what https://github.com/matrix-org/sydent/pull/67/files#diff-8db67a35998f38ac70c2d2fa7d2d8200R90 was doing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have tried to clarify in the comment
sydent/http/httpclient.py
Outdated
def creatorForNetloc(self, hostname, port): | ||
context = SSL.Context(SSL.SSLv23_METHOD) | ||
try: | ||
_ecCurve = _OpenSSLECCurve(_defaultCurveName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you do matrix-org/synapse#3157 to this please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
||
from sydent.http.servlets import get_args, jsonwrap | ||
from sydent.hs_federation.verifier import NoAuthenticationError | ||
from signedjson.sign import SignatureVerifyException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
before twisted
, please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -31,6 +32,7 @@ | |||
from http.servlets.pubkeyservlets import EphemeralPubkeyIsValidServlet, PubkeyIsValidServlet | |||
from validators.emailvalidator import EmailValidator | |||
from validators.msisdnvalidator import MsisdnValidator | |||
from hs_federation.verifier import Verifier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this appears to be missing from the PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, fixed
* Keep v0 schema in .sql scripts * Run schema scripts if version == 0 * Do schema upgrades if v < current, so new db will get v0 schema then upgrade
Hopefully missing fewer things now. |
sydent/db/sqlitedb.py
Outdated
# We always run the schema files if the version is zero: either the db is | ||
# completely empty and schema-less or it has the v0 schema, which is safe to | ||
# replay the schema files. | ||
if curVer == 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, so the files on disk are the v0 schema, and new installations are made to be v1 by first running the v0 schema and then doing the upgrades?
that's fine, but saying so in the comment would help
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
cur.execute("DROP INDEX IF EXISTS local_threepid_medium_address") | ||
cur.execute("ALTER TABLE local_threepid_associations RENAME TO old_local_threepid_associations"); | ||
cur.execute( | ||
"CREATE TABLE local_threepid_associations (id integer primary key autoincrement, " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
triple-quotes are totally a thing btw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(for reference, doesn't need changing now)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh true, although istr synapse used separate single line quotes. whatever.
sydent/db/threepid_associations.py
Outdated
def removeAssociation(self, threepid, mxid): | ||
cur = self.sydent.db.cursor() | ||
|
||
cur.execute( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we bother with this, ooi?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it's a REPLACE INTO, so we don't need to insert an empty record if there's nothing there to start with
sydent/hs_federation/verifier.py
Outdated
|
||
|
||
""" | ||
Verifies signed json blobs from Matrix Homeservers by finding the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this intended for the file or the class? if the file it goes at the top, if the class it goes inside the class
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yeah
logger = logging.getLogger(__name__) | ||
|
||
|
||
class NoAuthenticationError(Exception): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could this have a docstring describing what it represents please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
sydent/hs_federation/verifier.py
Outdated
client = FederationHttpClient(self.sydent) | ||
result = yield client.get_json("https://%s:%s/_matrix/key/v2/server/" % host_port) | ||
if 'verify_keys' not in result: | ||
raise Exception("No key found in response") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be a SignatureVerifyException
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, it probably ought to
sydent/hs_federation/verifier.py
Outdated
XXX: This contains a very noddy version of the home server | ||
SRV lookup and signature verification. It forms HTTPS URLs | ||
from the result of the SRV lookup which will mean the Host: | ||
parameter in the request will be wrong. It only looks at |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't the wrong Host header going to mess things up? People will have servers behind proxies which rely on it being right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is taken from the impl I did for user directory searching. I've also realised we actually have another impl of this in sydent for the onbind callbacks (https://github.com/matrix-org/sydent/blob/master/sydent/threepid/bind.py#L91) which has the same shortcoming. I guess now is the time to fix both of them as this presumably is going to start impacting people.
auth_headers = request.requestHeaders.getRawHeaders(b"Authorization") | ||
|
||
if not auth_headers: | ||
raise NoAuthenticationError("Missing Authorization headers") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is the logic behind when we raise a SignatureVerifyException and when a NoAuthenticationError?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly just me thinking that the you might want separate errors for them to be slightly more helpful (eg. for if you spelt Authorization with an s or something). Granted, with the way we're using it here we could just have the same exception type with a different message.
@defer.inlineCallbacks | ||
def authenticate_request(self, request, content): | ||
"""Authenticates a Matrix federation request based on the X-Matrix header | ||
XXX: Copied largely from synapse |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could do with some docstring regardless...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
sydent/hs_federation/verifier.py
Outdated
signature each time and does not contact any other servers | ||
to do perspectives checks. | ||
|
||
:param acceptable_server_names If provided and not None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of course we use different docstring conventions in different projects. Anyway there should be a colon after the param name aiui. And ideally documentation of a type.
https://pythonhosted.org/an_example_pypi_project/sphinx.html#function-definitions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
So the Host header will be correct in requests to homeservers.
OK, this now does more sensible SRV lookup - ptal! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm modulo nits
sydent/hs_federation/verifier.py
Outdated
json_request["signatures"].setdefault(origin, {})[key] = sig | ||
|
||
if not json_request["signatures"]: | ||
raise NoAuthenticationError("Missing Authorization headers") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is misleading
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, thanks
sydent/hs_federation/verifier.py
Outdated
:param request: The request object to authenticate | ||
:param content: The content of the request, if any | ||
:type content: bytes or None | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you document the return val please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
As per spec draft matrix-org/matrix-spec-proposals#1194
Related synapse PR: matrix-org/synapse#3276