Files

61 lines
2.4 KiB
Go
Raw Permalink Normal View History

package webapp
import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
)
// secRegisterDevice is how a device becomes known to the hub: it SIGNS IN, and
// the hub binds the id it names to the account it just authenticated
// (DeviceRegistry.Bind, from BuiltinAuth.finishLogin).
//
// It used to push an empty journal instead, because a first journal write was
// the only thing that could claim an unowned id. That arm is gone: it admitted
// `!known && journalNames(dev, ops)`, a check whose evidence is a field the
// writer writes, so any member with write on any project could take any id that
// had not yet pushed — including every device of every read-only member, which
// can never reach that door to claim its own id at all. The helper follows the
// registration path, so it moved with it. Every assertion in its 13 callers is
// unchanged.
//
// The cookie is the browser session approving the sign-in, which is exactly
// what the loopback flow asks of the person at the keyboard.
func secRegisterDevice(t *testing.T, h http.Handler, projectID string, c *http.Cookie, id, name, os string) *httptest.ResponseRecorder {
t.Helper()
_ = projectID // registration is hub-wide now, not per project
verifier := "0f1e2d3c4b5a69788796a5b4c3d2e1f0"
sum := sha256.Sum256([]byte(verifier))
challenge := base64.RawURLEncoding.EncodeToString(sum[:])
approve := httptest.NewRequest("POST", "/auth/cli?redirect="+
url.QueryEscape("http://127.0.0.1:53123/callback")+"&state=s"+
"&code_challenge="+challenge+"&code_challenge_method=S256", nil)
approve.AddCookie(c)
arec := httptest.NewRecorder()
h.ServeHTTP(arec, approve)
if arec.Code != http.StatusSeeOther {
t.Fatalf("secRegisterDevice: approving the sign-in failed: %d %s", arec.Code, arec.Body)
}
loc, err := url.Parse(arec.Header().Get("Location"))
if err != nil {
t.Fatalf("secRegisterDevice: bad callback %q: %v", arec.Header().Get("Location"), err)
}
body, _ := json.Marshal(map[string]string{
"code": loc.Query().Get("code"), "device": name, "code_verifier": verifier,
})
req := httptest.NewRequest("POST", "/api/auth/exchange", strings.NewReader(string(body)))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Bdrive-Device", id)
req.Header.Set("X-Bdrive-Device-Name", name)
req.Header.Set("X-Bdrive-Os", os)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
return rec
}