116 lines
3.1 KiB
Go
116 lines
3.1 KiB
Go
// gomuks - A terminal Matrix client written in Go.
|
|
// Copyright (C) 2020 Tulir Asokan
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package matrix
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"maunium.net/go/mautrix"
|
|
|
|
"maunium.net/go/gomuks/debug"
|
|
"maunium.net/go/gomuks/lib/open"
|
|
)
|
|
|
|
const uiaFallbackPage = `<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>gomuks user-interactive auth</title>
|
|
<meta charset="utf-8"/>
|
|
<style>
|
|
body {
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h2>Please complete the login in the popup window</h2>
|
|
<p>Keep this page open while logging in, it will close automatically after the login finishes.</p>
|
|
<button onclick="openPopup()">Open popup</button>
|
|
<button onclick="finish(false)">Cancel</button>
|
|
<script>
|
|
const url = location.hash.substr(1)
|
|
let popupWindow
|
|
|
|
function finish(success) {
|
|
if (popupWindow) {
|
|
popupWindow.close()
|
|
}
|
|
fetch("", {method: success ? "POST" : "DELETE"}).then(() => window.close())
|
|
}
|
|
|
|
function openPopup() {
|
|
popupWindow = window.open(url)
|
|
}
|
|
|
|
window.addEventListener("message", evt => evt.data === "authDone" && finish(true))
|
|
</script>
|
|
</body>
|
|
</html>
|
|
`
|
|
|
|
func (c *Container) UIAFallback(loginType mautrix.AuthType, sessionID string) error {
|
|
errChan := make(chan error, 1)
|
|
server := &http.Server{Addr: ":29325"}
|
|
server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method == "GET" {
|
|
w.Header().Add("Content-Type", "text/html")
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write([]byte(uiaFallbackPage))
|
|
} else if r.Method == "POST" || r.Method == "DELETE" {
|
|
w.Header().Add("Content-Type", "text/html")
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
go func() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
err := server.Shutdown(ctx)
|
|
if err != nil {
|
|
debug.Printf("Failed to shut down SSO server: %v\n", err)
|
|
}
|
|
if r.Method == "DELETE" {
|
|
errChan <- errors.New("login cancelled")
|
|
} else {
|
|
errChan <- nil
|
|
}
|
|
}()
|
|
} else {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
}
|
|
})
|
|
go server.ListenAndServe()
|
|
defer server.Close()
|
|
authURL := c.client.BuildURLWithQuery(mautrix.ClientURLPath{"v3", "auth", loginType, "fallback", "web"}, map[string]string{
|
|
"session": sessionID,
|
|
})
|
|
link := url.URL{
|
|
Scheme: "http",
|
|
Host: "localhost:29325",
|
|
Path: "/",
|
|
Fragment: authURL,
|
|
}
|
|
err := open.Open(link.String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = <-errChan
|
|
return err
|
|
}
|