Skip to content
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

MSC3861: MAS support #3493

Open
wants to merge 79 commits into
base: main
Choose a base branch
from
Open

MSC3861: MAS support #3493

wants to merge 79 commits into from

Conversation

mdnight
Copy link

@mdnight mdnight commented Jan 10, 2025

Pull Request Checklist

Signed-off-by: Roman Isaev <mdnight@riseup.net>

i.e. /_synapse/admin/v1/users/{userID}/_allow_cross_signing_replacement_without_uia
If access token expires the client(i.e. element) expects a specific response with http code
401 and spec.UnknownToken
MAS requires this endpoint to fetch the data for the account management page
Extended logic of the endpoint in order to make it compatible with
MAS
Since MSC3861 is conflicting with standard reg/login flows, we require to disable them before running the server
@mdnight mdnight requested a review from S7evinK January 25, 2025 02:20
@mdnight
Copy link
Author

mdnight commented Jan 25, 2025

@S7evinK the PR is ready for review again. I believe I have addressed all the comments. Please have another look when you have a moment. 🙏

Copy link
Contributor

@S7evinK S7evinK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still didn't get around to finish this (sorry!), but as a first.

Comment on lines 1559 to 1569
if tc.wantOK {
b := make(map[string]bool, 1)
_ = json.NewDecoder(rec.Body).Decode(&b)
available, ok := b["available"]
if !ok {
t.Fatal("'available' not found in body")
}
if available != tc.isAvailable {
t.Fatalf("expected 'available' to be %t, got %t instead", tc.isAvailable, available)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd go with the below, easier to read IMO.

Suggested change
if tc.wantOK {
b := make(map[string]bool, 1)
_ = json.NewDecoder(rec.Body).Decode(&b)
available, ok := b["available"]
if !ok {
t.Fatal("'available' not found in body")
}
if available != tc.isAvailable {
t.Fatalf("expected 'available' to be %t, got %t instead", tc.isAvailable, available)
}
}
// Nothing more to check, test is done.
if !tc.wantOK {
return
}
b := make(map[string]bool, 1)
_ = json.NewDecoder(rec.Body).Decode(&b)
available, ok := b["available"]
if !ok {
t.Fatal("'available' not found in body")
}
if available != tc.isAvailable {
t.Fatalf("expected 'available' to be %t, got %t instead", tc.isAvailable, available)
}

Comment on lines 357 to 358
default:
return util.JSONResponse{Code: http.StatusMethodNotAllowed, JSON: nil}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that it matters much, but I think this is already handled at the router level. (i.e., we only accept PUT and GET, and have this for MethodNotAllowed)
(No change required, as this makes it clearer here)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I know it's dead code, but default is required by the compiler and I thought switch-case would be more readable than

if GET {
   return this
}
return that

but anyway, I'll change this

}
}
if token != serviceToken {
logger.Debugf("Invalid service token '%s'", token)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if it is invalid (maybe just a typo in the token at the end or such), better don't log it.

Suggested change
logger.Debugf("Invalid service token '%s'", token)
logger.Debugf("Invalid service token")

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re right. I should have removed the variable from the message. I forgot to change it after debugging.

}

for _, tc := range testCase {
t.Run("Retrieve existing account", func(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
t.Run("Retrieve existing account", func(t *testing.T) {
t.Run(tc.Name, func(t *testing.T) {

Comment on lines 558 to 579
{
var rs api.QueryDevicesResponse
if err = userAPI.QueryDevices(req.Context(), &api.QueryDevicesRequest{UserID: userID}, &rs); err != nil {
logger.WithError(err).Error("QueryDevices")
return util.JSONResponse{
Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{},
}
}
if !rs.UserExists {
return util.JSONResponse{
Code: http.StatusNotFound,
JSON: spec.NotFound("Given user ID does not exist"),
}
}
for i := range rs.Devices {
if d := rs.Devices[i]; d.ID == payload.DeviceID && d.UserID == userID {
userDeviceExists = true
break
}
}
}
Copy link
Contributor

@S7evinK S7evinK Jan 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to put this in a block, I guess? (Or I missed something)

@@ -234,6 +234,19 @@ func (a *UserInternalAPI) PerformMarkAsStaleIfNeeded(ctx context.Context, req *a
return a.Updater.ManualUpdate(ctx, req.Domain, req.UserID)
}

func (a *UserInternalAPI) QueryMasterKeys(ctx context.Context, req *api.QueryMasterKeysRequest, res *api.QueryMasterKeysResponse) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May not be needed as noted elsewhere.

@@ -46,6 +50,8 @@ type Monolith struct {
// Optional
ExtPublicRoomsProvider api.ExtraPublicRoomsProvider
ExtUserDirectoryProvider userapi.QuerySearchProfilesAPI

UserVerifierProvider *UserVerifierProvider
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
UserVerifierProvider *UserVerifierProvider
UserVerifierProvider httputil.UserVerifier

Comment on lines 91 to 97
type UserVerifierProvider struct {
UserVerifier httputil.UserVerifier
}

func (u *UserVerifierProvider) VerifyUserFromRequest(req *http.Request) (*userapi.Device, *util.JSONResponse) {
return u.UserVerifier.VerifyUserFromRequest(req)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type UserVerifierProvider struct {
UserVerifier httputil.UserVerifier
}
func (u *UserVerifierProvider) VerifyUserFromRequest(req *http.Request) (*userapi.Device, *util.JSONResponse) {
return u.UserVerifier.VerifyUserFromRequest(req)
}
type UserVerifierProvider struct {
httputil.UserVerifier
}
func (u *UserVerifierProvider) VerifyUserFromRequest(req *http.Request) (*userapi.Device, *util.JSONResponse) {
return u.VerifyUserFromRequest(req)
}

IMHO this is easier to read and doesn't stutter.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, this is better, indeed. Didn't know about this

Copy link
Author

@mdnight mdnight Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have to keep return u.UserVerifier.VerifyUserFromRequest(req) as it is because return u.VerifyUserFromRequest(req) causes recursive calls

userapi/storage/sqlite3/cross_signing_keys_table.go Outdated Show resolved Hide resolved
-- Stores data about connections between accounts and third-party auth providers
CREATE TABLE IF NOT EXISTS userapi_localpart_external_ids (
-- The Matrix user ID for this account
localpart TEXT NOT NULL,
Copy link
Contributor

@S7evinK S7evinK Feb 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given an initial implementation for vhosting in Dendrite, localpart should either be user_id (@test:example.com) or use an additional server_name column. (same for SQLite)

Copy link
Author

@mdnight mdnight Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use this table to map local users with their MAS identifiers. Using localpart to identify local users is more than enough, whereas using the server name here does not make any sense because it will always be the same. It will be the same server name in each row.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants