mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 13:46:44 -04:00
Remove 'reader' authenticated user as it just complicates display and API access.
This commit is contained in:
@@ -22,7 +22,6 @@ CREATE TABLE event_settings (
|
||||
plcaddress VARCHAR(255),
|
||||
tbadownloadenabled bool,
|
||||
adminpassword VARCHAR(255),
|
||||
readerpassword VARCHAR(255),
|
||||
habdockingthreshold int
|
||||
);
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ type EventSettings struct {
|
||||
SwitchPassword string
|
||||
PlcAddress string
|
||||
AdminPassword string
|
||||
ReaderPassword string
|
||||
HabDockingThreshold int
|
||||
}
|
||||
|
||||
|
||||
@@ -115,19 +115,13 @@
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Authentication</legend>
|
||||
<p>Configure passwords to enable HTTP Basic authentication, or leave blank to disable.</p>
|
||||
<p>Configure password to enable authentication, or leave blank to disable.</p>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Password for 'admin' user</label>
|
||||
<div class="col-lg-7">
|
||||
<input type="password" class="form-control" name="adminPassword" value="{{.AdminPassword}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-5 control-label">Password for 'reader' user</label>
|
||||
<div class="col-lg-7">
|
||||
<input type="password" class="form-control" name="readerPassword" value="{{.ReaderPassword}}">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Networking</legend>
|
||||
|
||||
@@ -13,10 +13,6 @@ import (
|
||||
|
||||
// Renders the team number and status display shown above each alliance station.
|
||||
func (web *Web) allianceStationDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, map[string]string{"station": "R1"}) {
|
||||
return
|
||||
}
|
||||
@@ -39,10 +35,6 @@ func (web *Web) allianceStationDisplayHandler(w http.ResponseWriter, r *http.Req
|
||||
|
||||
// The websocket endpoint for the alliance station display client to receive status updates.
|
||||
func (web *Web) allianceStationDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -13,10 +13,6 @@ import (
|
||||
|
||||
// Renders the announcer display which shows team info and scores for the current match.
|
||||
func (web *Web) announcerDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, nil) {
|
||||
return
|
||||
}
|
||||
@@ -39,10 +35,6 @@ func (web *Web) announcerDisplayHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// The websocket endpoint for the announcer display client to send control commands and receive status updates.
|
||||
func (web *Web) announcerDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
16
web/api.go
16
web/api.go
@@ -31,10 +31,6 @@ type RankingWithNickname struct {
|
||||
|
||||
// Generates a JSON dump of the matches and results.
|
||||
func (web *Web) matchesApiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
matches, err := web.arena.Database.GetMatchesByType(vars["type"])
|
||||
if err != nil {
|
||||
@@ -75,10 +71,6 @@ func (web *Web) matchesApiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Generates a JSON dump of the sponsor slides for use by the audience display.
|
||||
func (web *Web) sponsorSlidesApiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
sponsors, err := web.arena.Database.GetAllSponsorSlides()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -105,10 +97,6 @@ func (web *Web) sponsorSlidesApiHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Generates a JSON dump of the qualification rankings, primarily for use by the pit display.
|
||||
func (web *Web) rankingsApiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
rankings, err := web.arena.Database.GetAllRankings()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -169,10 +157,6 @@ func (web *Web) rankingsApiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Generates a JSON dump of the alliances.
|
||||
func (web *Web) alliancesApiHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
alliances, err := web.arena.Database.GetAllAlliances()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -14,10 +14,6 @@ import (
|
||||
|
||||
// Renders the audience display to be chroma keyed over the video feed.
|
||||
func (web *Web) audienceDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, map[string]string{"background": "#0f0", "reversed": "false",
|
||||
"overlayLocation": "bottom"}) {
|
||||
return
|
||||
@@ -42,10 +38,6 @@ func (web *Web) audienceDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// The websocket endpoint for the audience display client to receive status updates.
|
||||
func (web *Web) audienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -13,10 +13,6 @@ import (
|
||||
|
||||
// Renders the field monitor display.
|
||||
func (web *Web) fieldMonitorDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, map[string]string{"reversed": "false"}) {
|
||||
return
|
||||
}
|
||||
@@ -38,10 +34,6 @@ func (web *Web) fieldMonitorDisplayHandler(w http.ResponseWriter, r *http.Reques
|
||||
|
||||
// The websocket endpoint for the field monitor display client to receive status updates.
|
||||
func (web *Web) fieldMonitorDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -10,55 +10,35 @@ import (
|
||||
|
||||
func TestLoginDisplay(t *testing.T) {
|
||||
web := setupTestWeb(t)
|
||||
web.arena.EventSettings.ReaderPassword = "reader"
|
||||
web.arena.EventSettings.AdminPassword = "admin"
|
||||
|
||||
// Check that hitting a reader-level protected page redirects to the login.
|
||||
recorder := web.getHttpResponse("/api/alliances")
|
||||
// Check that hitting a protected page redirects to the login.
|
||||
recorder := web.getHttpResponse("/match_play")
|
||||
assert.Equal(t, 307, recorder.Code)
|
||||
assert.Equal(t, "/login?redirect=/api/alliances", recorder.Header().Get("Location"))
|
||||
assert.Equal(t, "/login?redirect=/match_play", recorder.Header().Get("Location"))
|
||||
|
||||
recorder = web.getHttpResponse("/login?redirect=/api/alliances")
|
||||
recorder = web.getHttpResponse("/login?redirect=/match_play")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "Log In - Untitled Event - Cheesy Arena")
|
||||
|
||||
// Check logging in with the wrong username and right password.
|
||||
recorder = web.postHttpResponse("/login?redirect=/api/alliances", "username=blorpy&password=reader")
|
||||
recorder = web.postHttpResponse("/login?redirect=/match_play", "username=blorpy&password=reader")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "Bad username or password")
|
||||
|
||||
// Check logging in with the right username and wrong password.
|
||||
recorder = web.postHttpResponse("/login?redirect=/api/alliances", "username=reader&password=blorpy")
|
||||
recorder = web.postHttpResponse("/login?redirect=/match_play", "username=admin&password=blorpy")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "Bad username or password")
|
||||
|
||||
// Check logging in with the right username and password.
|
||||
recorder = web.postHttpResponse("/login?redirect=/api/alliances", "username=reader&password=reader")
|
||||
recorder = web.postHttpResponse("/login?redirect=/match_play", "username=admin&password=admin")
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
assert.Equal(t, "/api/alliances", recorder.Header().Get("Location"))
|
||||
assert.Equal(t, "/match_play", recorder.Header().Get("Location"))
|
||||
cookie := recorder.Header().Get("Set-Cookie")
|
||||
assert.Contains(t, cookie, "Authorization=")
|
||||
|
||||
// Check that hitting the reader-level protected page works now.
|
||||
recorder = web.getHttpResponseWithHeaders("/api/alliances", map[string]string{"Cookie": cookie})
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
// Check that hitting a admin-level protected at a higher level requires a different login.
|
||||
recorder = web.getHttpResponseWithHeaders("/match_play", map[string]string{"Cookie": cookie})
|
||||
assert.Equal(t, 307, recorder.Code)
|
||||
assert.Equal(t, "/login?redirect=/match_play", recorder.Header().Get("Location"))
|
||||
recorder = web.getHttpResponseWithHeaders("/login?redirect=/match_play", map[string]string{"Cookie": cookie})
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "insufficient privileges")
|
||||
recorder = web.postHttpResponse("/login?redirect=/match_play", "username=admin&password=admin")
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
assert.Equal(t, "/match_play", recorder.Header().Get("Location"))
|
||||
cookie = recorder.Header().Get("Set-Cookie")
|
||||
assert.Contains(t, cookie, "Authorization=")
|
||||
recorder = web.getHttpResponseWithHeaders("/match_play", map[string]string{"Cookie": cookie})
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
|
||||
// Check that the admin user also has access to the reader-level pages.
|
||||
recorder = web.getHttpResponseWithHeaders("/api/alliances", map[string]string{"Cookie": cookie})
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
}
|
||||
|
||||
@@ -26,10 +26,6 @@ type MatchReviewListItem struct {
|
||||
|
||||
// Shows the match review interface.
|
||||
func (web *Web) matchReviewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
practiceMatches, err := web.buildMatchReviewList("practice")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -13,10 +13,6 @@ import (
|
||||
|
||||
// Renders the pit display which shows scrolling rankings.
|
||||
func (web *Web) pitDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, map[string]string{"scrollMsPerRow": "1000"}) {
|
||||
return
|
||||
}
|
||||
@@ -38,10 +34,6 @@ func (web *Web) pitDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// The websocket endpoint for the pit display, used only to force reloads remotely.
|
||||
func (web *Web) pitDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -13,10 +13,6 @@ import (
|
||||
|
||||
// Shows a random ID to visually identify the display so that it can be configured on the server.
|
||||
func (web *Web) placeholderDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, nil) {
|
||||
return
|
||||
}
|
||||
@@ -38,10 +34,6 @@ func (web *Web) placeholderDisplayHandler(w http.ResponseWriter, r *http.Request
|
||||
|
||||
// The websocket endpoint for sending configuration commands to the display.
|
||||
func (web *Web) placeholderDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -16,10 +16,6 @@ const numMatchesToShow = 5
|
||||
|
||||
// Renders the queueing display that shows upcoming matches and timing information.
|
||||
func (web *Web) queueingDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, nil) {
|
||||
return
|
||||
}
|
||||
@@ -61,10 +57,6 @@ func (web *Web) queueingDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// The websocket endpoint for the queueing display to receive updates.
|
||||
func (web *Web) queueingDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -16,10 +16,6 @@ import (
|
||||
|
||||
// Generates a CSV-formatted report of the qualification rankings.
|
||||
func (web *Web) rankingsCsvReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
rankings, err := web.arena.Database.GetAllRankings()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -42,10 +38,6 @@ func (web *Web) rankingsCsvReportHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Generates a PDF-formatted report of the qualification rankings.
|
||||
func (web *Web) rankingsPdfReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
rankings, err := web.arena.Database.GetAllRankings()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -104,10 +96,6 @@ func (web *Web) rankingsPdfReportHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Generates a CSV-formatted report of the match schedule.
|
||||
func (web *Web) scheduleCsvReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
matches, err := web.arena.Database.GetMatchesByType(vars["type"])
|
||||
if err != nil {
|
||||
@@ -131,10 +119,6 @@ func (web *Web) scheduleCsvReportHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Generates a PDF-formatted report of the match schedule.
|
||||
func (web *Web) schedulePdfReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
matches, err := web.arena.Database.GetMatchesByType(vars["type"])
|
||||
if err != nil {
|
||||
@@ -247,10 +231,6 @@ func (web *Web) schedulePdfReportHandler(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// Generates a CSV-formatted report of the team list.
|
||||
func (web *Web) teamsCsvReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
teams, err := web.arena.Database.GetAllTeams()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
@@ -273,10 +253,6 @@ func (web *Web) teamsCsvReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// Generates a PDF-formatted report of the team list.
|
||||
func (web *Web) teamsPdfReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
teams, err := web.arena.Database.GetAllTeams()
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
@@ -65,7 +65,6 @@ func (web *Web) settingsPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
eventSettings.SwitchPassword = r.PostFormValue("switchPassword")
|
||||
eventSettings.PlcAddress = r.PostFormValue("plcAddress")
|
||||
eventSettings.AdminPassword = r.PostFormValue("adminPassword")
|
||||
eventSettings.ReaderPassword = r.PostFormValue("readerPassword")
|
||||
eventSettings.HabDockingThreshold, _ = strconv.Atoi(r.PostFormValue("habDockingThreshold"))
|
||||
|
||||
err := web.arena.Database.SaveEventSettings(eventSettings)
|
||||
|
||||
@@ -13,10 +13,6 @@ import (
|
||||
|
||||
// Renders the Twitch stream view.
|
||||
func (web *Web) twitchDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
if !web.enforceDisplayConfiguration(w, r, map[string]string{"channel": "team254"}) {
|
||||
return
|
||||
}
|
||||
@@ -38,10 +34,6 @@ func (web *Web) twitchDisplayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// The websocket endpoint for sending configuration commands to the display.
|
||||
func (web *Web) twitchDisplayWebsocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !web.userIsReader(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
display, err := web.registerDisplay(r)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
|
||||
26
web/web.go
26
web/web.go
@@ -18,8 +18,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
adminUser = "admin"
|
||||
readerUser = "reader"
|
||||
adminUser = "admin"
|
||||
)
|
||||
|
||||
type Web struct {
|
||||
@@ -108,29 +107,8 @@ func (web *Web) userIsAdmin(w http.ResponseWriter, r *http.Request) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the given user is authorized for read-only operations. Used for HTTP cookie authentication.
|
||||
func (web *Web) userIsReader(w http.ResponseWriter, r *http.Request) bool {
|
||||
if web.arena.EventSettings.ReaderPassword == "" {
|
||||
// Disable auth if there is no password configured.
|
||||
return true
|
||||
}
|
||||
if username := web.cookieAuth.Authorize(r); username == readerUser || username == adminUser {
|
||||
return true
|
||||
} else {
|
||||
http.Redirect(w, r, "/login?redirect="+r.URL.Path, 307)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (web *Web) checkAuthPassword(user, password string) bool {
|
||||
switch user {
|
||||
case adminUser:
|
||||
return password == web.arena.EventSettings.AdminPassword
|
||||
case readerUser:
|
||||
return password == web.arena.EventSettings.ReaderPassword
|
||||
default:
|
||||
return false
|
||||
}
|
||||
return user == adminUser && password == web.arena.EventSettings.AdminPassword
|
||||
}
|
||||
|
||||
// Sets up the mapping between URLs and handlers.
|
||||
|
||||
Reference in New Issue
Block a user