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 67 commits into
base: main
Choose a base branch
from
Open

MSC3861: MAS support #3493

wants to merge 67 commits into from

Conversation

mdnight
Copy link

@mdnight mdnight commented Jan 10, 2025

Pull Request Checklist

Signed-off-by: Roman Isaev <[email protected]>

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 a team as a code owner January 15, 2025 19:02
@mdnight mdnight changed the title WIP: MSC3861: MAS support MSC3861: MAS support Jan 15, 2025
@codecov-commenter
Copy link

codecov-commenter commented Jan 15, 2025

Codecov Report

Attention: Patch coverage is 50.32258% with 770 lines in your changes missing coverage. Please review.

Project coverage is 49.44%. Comparing base (a41f9cc) to head (641f5b5).
Report is 8 commits behind head on main.

Files with missing lines Patch % Lines
clientapi/routing/admin.go 52.26% 153 Missing and 37 partials ⚠️
setup/mscs/msc3861/msc3861_user_verifier.go 48.27% 106 Missing and 29 partials ⚠️
clientapi/routing/routing.go 54.35% 24 Missing and 65 partials ⚠️
clientapi/routing/key_crosssigning.go 25.24% 74 Missing and 3 partials ⚠️
...erapi/storage/postgres/cross_signing_keys_table.go 42.37% 30 Missing and 4 partials ⚠️
...serapi/storage/sqlite3/cross_signing_keys_table.go 42.37% 30 Missing and 4 partials ⚠️
...as/2024123101150000_drop_primary_key_constraint.go 44.44% 29 Missing and 1 partial ⚠️
clientapi/routing/profile.go 12.50% 18 Missing and 3 partials ⚠️
userapi/storage/shared/storage.go 54.34% 15 Missing and 6 partials ⚠️
setup/config/config_clientapi.go 54.28% 14 Missing and 2 partials ⚠️
... and 19 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3493      +/-   ##
==========================================
- Coverage   49.44%   49.44%   -0.01%     
==========================================
  Files         524      533       +9     
  Lines       59799    60996    +1197     
==========================================
+ Hits        29569    30159     +590     
- Misses      26750    27251     +501     
- Partials     3480     3586     +106     
Flag Coverage Δ
unittests 49.44% <50.32%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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.

From what I've seen so far (and tested), this is awesome! Thanks a lot for this!

The requested changes are only minor, still need to go through 34 changed files 🙃

internal/httputil/httpapi.go Show resolved Hide resolved
@@ -817,7 +819,7 @@ func checkAndCompleteFlow(
return util.JSONResponse{
Code: http.StatusUnauthorized,
JSON: newUserInteractiveResponse(sessionID,
cfg.Derived.Registration.Flows, cfg.Derived.Registration.Params),
cfg.Derived.Registration.Flows, cfg.Derived.Registration.Params, ""),
Copy link
Contributor

Choose a reason for hiding this comment

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

We should add a default message instead of returning nothing, I think.

Copy link
Author

@mdnight mdnight Jan 23, 2025

Choose a reason for hiding this comment

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

We need the message field only once, when we want to show this: To reset your end-to-end encryption cross-signing identity, you first need to approve it at ${URL} and then try again.
For other cases, we simply ignore the empty field and do not return it in the response.

type userInteractiveResponse struct {
	Flows     []authtypes.Flow       `json:"flows"`
        ...
	Msg       string                 `json:"msg,omitempty"`      <--- this
}

Also, I can't find msg in the spec 🤷

@@ -129,6 +132,7 @@ type QuerySearchProfilesAPI interface {
QuerySearchProfiles(ctx context.Context, req *QuerySearchProfilesRequest, res *QuerySearchProfilesResponse) error
}

// FIXME: typo in Acccess
Copy link
Contributor

Choose a reason for hiding this comment

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

🙃 Ooops.

Localpart string
ExternalID string
AuthProvider string
CreatedTs int64
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
CreatedTs int64
CreatedTS int64

})).Methods(http.MethodPost)
} else {
// If msc3861 is enabled, these endpoints are either redundant or replaced by Matrix Auth Service (MAS)
// Once we migrate to MAS completely, these edndpoints should be removed
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
// Once we migrate to MAS completely, these edndpoints should be removed
// Once we migrate to MAS completely, these endpoints should be removed

@@ -119,6 +120,20 @@ func (s *syncUserAPI) PerformLastSeenUpdate(ctx context.Context, req *userapi.Pe
return nil
}

type userVerifier struct {
m map[string]struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is m? (more descriptive field name please, something like accessTokenToDeviceAndResponse, maybe?)

@@ -0,0 +1,23 @@
package deltas
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned OOB, we probably don't need this migration and can instead use

// sessionsDict keeps track of completed auth stages for each session.
// It shouldn't be passed by value because it contains a mutex.
type sessionsDict struct {
sync.RWMutex
sessions map[string][]authtypes.LoginType
sessionCompletedResult map[string]registerResponse
params map[string]registerRequest
timer map[string]*time.Timer
// deleteSessionToDeviceID protects requests to DELETE /devices/{deviceID} from being abused.
// If a UIA session is started by trying to delete device1, and then UIA is completed by deleting device2,
// the delete request will fail for device2 since the UIA was initiated by trying to delete device1.
deleteSessionToDeviceID map[string]string
}
instead? (same goes for the SQLite migration etc.)

Copy link
Author

@mdnight mdnight Jan 23, 2025

Choose a reason for hiding this comment

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

Not sure I have a clear understanding of how this structure might apply to our case. I need to reflect on it a bit. 🤔

Copy link
Author

@mdnight mdnight Jan 25, 2025

Choose a reason for hiding this comment

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

Done. Added a new map to the structure for managing this kind of session and covered new methods with tests. Also deleted xsigning_updatable_without_uia_before_ms column from the database and reverted all related logic

@@ -116,6 +116,7 @@ func (s *accountsStatements) InsertAccount(
localpart string, serverName spec.ServerName,
hash, appserviceID string, accountType api.AccountType,
) (*api.Account, error) {
// TODO: can we replace "UnixNano() / 1M" with "UnixMilli()"?
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes we can! :)

As a followup PR, use spec.AsTimestamp(time.Now()) which does the same, and update AsTimestamp in gomatrixserverlib to use UnixMilli().

Copy link
Author

@mdnight mdnight Jan 22, 2025

Choose a reason for hiding this comment

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

created a pull requests for gomatrixserverlib 🙂 matrix-org/gomatrixserverlib#447

// 'msc2444': Peeking over federation - https://github.com/matrix-org/matrix-doc/pull/2444
// 'msc2753': Peeking via /sync - https://github.com/matrix-org/matrix-doc/pull/2753
// 'msc2836': Threading - https://github.com/matrix-org/matrix-doc/pull/2836
MSCs []string `yaml:"mscs"`

// MSC3861 contains config related to the experimental feature MSC3861. It takes effect only if 'msc3861' is included in 'MSCs' array
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
// MSC3861 contains config related to the experimental feature MSC3861. It takes effect only if 'msc3861' is included in 'MSCs' array
// MSC3861 contains config related to the experimental feature MSC3861.
// It takes effect only if 'msc3861' is included in 'MSCs' array.

c.RecaptchaApiJsUrl = "https://www.google.com/recaptcha/api.js"

if c.MSCs.MSC3861Enabled() {
if c.RecaptchaEnabled || !c.RegistrationDisabled {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe just me, but I prefer reading the "not" path first.

Suggested change
if c.RecaptchaEnabled || !c.RegistrationDisabled {
if !c.RegistrationDisabled || c.RecaptchaEnabled {

For a different PR: We should only have either Enabled or Disabled in our config. Otherwise stuff like this might become confusing.

Copy link
Author

Choose a reason for hiding this comment

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

I don't have any preferences regarding the "not" path, but I agree that registration should go first. 😄

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.

Didn't want to request changes again, just wanted to add a few more comments..

Comment on lines 40 to 41
const deleteUserExternalIDSQL = "" +
"SELECT localpart, external_id, auth_provider, created_ts FROM userapi_localpart_external_ids WHERE external_id = $1 AND auth_provider = $2"
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't look like a DELETE. (same for SQLite)

Copy link
Author

Choose a reason for hiding this comment

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

🤦

serverName spec.ServerName,
cfg *config.MSC3861,
allowGuest bool,
httpClient *http.Client,
Copy link
Contributor

Choose a reason for hiding this comment

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

httpClient should probably be a fclient.Client, see https://github.com/matrix-org/gomatrixserverlib/blob/0a1b2bafb5cf72727787359d39653493b3318398/fclient/client.go#L44-L50

And it should be an error if it is not set, we shouldn't use http.DefaultClient.

@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. 🙏

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