provisioning: implement legacy QR endpoint

Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
Sumner Evans
2024-08-27 15:45:25 -06:00
parent 4d9ad4f0af
commit c2d94947ee
4 changed files with 108 additions and 5 deletions

View File

@@ -17,11 +17,13 @@
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"sync"
"github.com/gorilla/websocket"
"github.com/rs/zerolog"
"go.mau.fi/util/exhttp"
"maunium.net/go/mautrix/bridgev2"
@@ -62,6 +64,92 @@ type legacyLogin struct {
var inflightLegacyLoginsLock sync.RWMutex
var inflightLegacyLogins = map[id.UserID]*legacyLogin{}
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
Subprotocols: []string{"net.maunium.telegram.login"},
}
func legacyProvLoginQR(w http.ResponseWriter, r *http.Request) {
log := zerolog.Ctx(r.Context()).With().Str("prov_method", "qr_login").Logger()
ctx := log.WithContext(r.Context())
user := m.Matrix.Provisioning.GetUser(r)
resp := response{Username: user.MXID}
var err error
var loginProcess bridgev2.LoginProcess
var nextStep *bridgev2.LoginStep
if loginProcess, err = c.CreateLogin(ctx, user, connector.LoginFlowIDQR); err != nil {
exhttp.WriteJSONResponse(w, http.StatusInternalServerError, resp.WithError("create_login_failed", fmt.Sprintf("Failed to create a QR login process: %s", err.Error())))
} else if nextStep, err = loginProcess.Start(ctx); err != nil {
exhttp.WriteJSONResponse(w, http.StatusInternalServerError, resp.WithError("start_login_failed", fmt.Sprintf("Failed to start login process: %s", err.Error())))
} else if nextStep.StepID != connector.LoginStepIDShowQR {
exhttp.WriteJSONResponse(w, http.StatusInternalServerError, resp.WithError("unexpected_step", fmt.Sprintf("Unexpected first step %s", nextStep.StepID)))
}
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Err(err).Msg("Failed to upgrade connection to websocket")
return
}
defer func() {
err := ws.Close()
if err != nil {
log.Debug().Err(err).Msg("Error closing websocket")
}
}()
go func() {
// Read everything so SetCloseHandler() works
for {
_, _, err = ws.ReadMessage()
if err != nil {
break
}
}
}()
ctx, cancel := context.WithCancel(context.Background())
ws.SetCloseHandler(func(code int, text string) error {
log.Debug().Int("close_code", code).Msg("Login websocket closed, cancelling login")
cancel()
return nil
})
for {
switch nextStep.StepID {
case connector.LoginStepIDShowQR:
nextStep, err = loginProcess.(bridgev2.LoginProcessDisplayAndWait).Wait(ctx)
if err != nil {
ws.WriteJSON(map[string]any{
"success": false,
"error": "qr_login_failed",
"message": fmt.Sprintf("Failed to login using QR code: %s", err),
})
return
}
ws.WriteJSON(map[string]any{"code": nextStep.DisplayAndWaitParams.Data})
case connector.LoginStepIDComplete:
ws.WriteJSON(map[string]any{"success": true})
return
case connector.LoginStepIDPassword:
inflightLegacyLoginsLock.Lock()
inflightLegacyLogins[user.MXID] = &legacyLogin{Process: loginProcess, NextStep: nextStep}
inflightLegacyLoginsLock.Unlock()
ws.WriteJSON(map[string]any{"success": false, "error": "password-needed"})
return
default:
ws.WriteJSON(map[string]any{
"success": false,
"error": "unexpected_step",
"message": fmt.Sprintf("Unexpected step in QR code login process %s", nextStep.StepID),
})
return
}
}
}
func legacyProvLoginRequestCode(w http.ResponseWriter, r *http.Request) {
log := zerolog.Ctx(r.Context()).With().Str("prov_step", "request_code").Logger()
ctx := log.WithContext(r.Context())

View File

@@ -19,6 +19,8 @@ package main
import (
"encoding/base64"
"fmt"
"net/http"
"strings"
"go.mau.fi/util/dbutil/litestream"
"maunium.net/go/mautrix/bridgev2/bridgeconfig"
@@ -60,7 +62,20 @@ func main() {
versionWithoutCommit := m.Version
m.PostStart = func() {
if m.Matrix.Provisioning != nil {
// m.Matrix.Provisioning.Router.HandleFunc("/v1/user/{userID}/login/qr", legacyProvLoginQR)
m.Matrix.Provisioning.GetAuthFromRequest = func(r *http.Request) string {
if !strings.HasSuffix(r.URL.Path, "/login/qr") {
return ""
}
authParts := strings.Split(r.Header.Get("Sec-WebSocket-Protocol"), ",")
for _, part := range authParts {
part = strings.TrimSpace(part)
if strings.HasPrefix(part, "net.maunium.telegram.auth-") {
return strings.TrimPrefix(part, "net.maunium.telegram.auth-")
}
}
return ""
}
m.Matrix.Provisioning.Router.HandleFunc("/v1/user/{userID}/login/qr", legacyProvLoginQR)
m.Matrix.Provisioning.Router.HandleFunc("/v1/user/{userID}/login/request_code", legacyProvLoginRequestCode)
m.Matrix.Provisioning.Router.HandleFunc("/v1/user/{userID}/login/send_code", legacyProvLoginSendCode)
m.Matrix.Provisioning.Router.HandleFunc("/v1/user/{userID}/login/send_password", legacyProvLoginSendPassword)

4
go.mod
View File

@@ -3,6 +3,7 @@ module go.mau.fi/mautrix-telegram
go 1.22
require (
github.com/gorilla/websocket v1.5.3
github.com/gotd/td v0.105.0
github.com/rs/zerolog v1.33.0
github.com/stretchr/testify v1.9.0
@@ -11,7 +12,7 @@ require (
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
golang.org/x/net v0.28.0
maunium.net/go/mautrix v0.20.1-0.20240827134950-e3eb2953ddda
maunium.net/go/mautrix v0.20.1-0.20240827221252-892e5cf01fc8
)
require (
@@ -23,7 +24,6 @@ require (
github.com/go-faster/jx v1.1.0 // indirect
github.com/go-faster/xor v1.0.0 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/gotd/ige v0.2.2 // indirect
github.com/gotd/neo v0.1.5 // indirect
github.com/klauspost/compress v1.17.9 // indirect

4
go.sum
View File

@@ -116,8 +116,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
maunium.net/go/mautrix v0.20.1-0.20240827134950-e3eb2953ddda h1:3n7LQS2LQFW4uNUeECEUNWCCCaNTygk0CGSE+CZtEqo=
maunium.net/go/mautrix v0.20.1-0.20240827134950-e3eb2953ddda/go.mod h1:7hh/Hx5W9lUcqL0hkSw52kMyY+6nMUPTtdDN0qVEXwI=
maunium.net/go/mautrix v0.20.1-0.20240827221252-892e5cf01fc8 h1:k+HkbFrExb508ofb+Snz+yGa1/GQ6WKqyGzGYXSzT3A=
maunium.net/go/mautrix v0.20.1-0.20240827221252-892e5cf01fc8/go.mod h1:7hh/Hx5W9lUcqL0hkSw52kMyY+6nMUPTtdDN0qVEXwI=
nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0=
nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=