Files
owncast/webserver/handlers/admin/externalAPIUsers.go
T
CopilotGitHubgabekcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
149d80a07d Inline chat moderation request returning 500s (#4412)
* Initial plan

* Initial analysis of inline chat moderation 500 error issue

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Fix inline chat moderation 500 errors by supporting Authorization header tokens

- Modified RequireUserModerationScopeAccesstoken middleware to check both Authorization header (Bearer tokens) and URL query parameters
- This fixes the issue where inline chat moderation from the web UI was failing with 500 errors
- Maintains backward compatibility with existing code that uses query parameter tokens
- The fix aligns the chat endpoint behavior with the integrations endpoint which already supported Bearer tokens

Addresses the wiring issue between OpenAPI spec and API implementation identified in issue comments.

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Fix inline chat moderation 500 errors by adding nil pointer checks

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

* Fix nil pointer vulnerabilities across all OpenAPI endpoints

Co-authored-by: gabek <414923+gabek@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: gabek <414923+gabek@users.noreply.github.com>
2025-07-04 23:57:03 -07:00

117 lines
3.0 KiB
Go

package admin
import (
"encoding/json"
"errors"
"net/http"
"time"
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/userrepository"
"github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/handlers/generated"
webutils "github.com/owncast/owncast/webserver/utils"
)
// CreateExternalAPIUser will generate a 3rd party access token.
func CreateExternalAPIUser(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
var request generated.CreateExternalAPIUserJSONBody
if err := decoder.Decode(&request); err != nil {
webutils.BadRequestHandler(w, err)
return
}
userRepository := userrepository.Get()
if request.Scopes == nil {
webutils.BadRequestHandler(w, errors.New("scopes field is required"))
return
}
if request.Name == nil {
webutils.BadRequestHandler(w, errors.New("name field is required"))
return
}
// Verify all the scopes provided are valid
if !userRepository.HasValidScopes(*request.Scopes) {
webutils.BadRequestHandler(w, errors.New("one or more invalid scopes provided"))
return
}
token, err := utils.GenerateAccessToken()
if err != nil {
webutils.InternalErrorHandler(w, err)
return
}
color := utils.GenerateRandomDisplayColor(config.MaxUserColor)
if err := userRepository.InsertExternalAPIUser(token, *request.Name, color, *request.Scopes); err != nil {
webutils.InternalErrorHandler(w, err)
return
}
w.Header().Set("Content-Type", "application/json")
webutils.WriteResponse(w, models.ExternalAPIUser{
AccessToken: token,
DisplayName: *request.Name,
DisplayColor: color,
Scopes: *request.Scopes,
CreatedAt: time.Now(),
LastUsedAt: nil,
})
}
// GetExternalAPIUsers will return all 3rd party access tokens.
func GetExternalAPIUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
userRepository := userrepository.Get()
tokens, err := userRepository.GetExternalAPIUser()
if err != nil {
webutils.InternalErrorHandler(w, err)
return
}
webutils.WriteResponse(w, tokens)
}
// DeleteExternalAPIUser will return a single 3rd party access token.
func DeleteExternalAPIUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.Method != http.MethodPost {
webutils.WriteSimpleResponse(w, false, r.Method+" not supported")
return
}
decoder := json.NewDecoder(r.Body)
var request generated.DeleteExternalAPIUserJSONBody
if err := decoder.Decode(&request); err != nil {
webutils.BadRequestHandler(w, err)
return
}
if request.Token == nil {
webutils.BadRequestHandler(w, errors.New("token field is required"))
return
}
if *request.Token == "" {
webutils.BadRequestHandler(w, errors.New("must provide a token"))
return
}
userRepository := userrepository.Get()
if err := userRepository.DeleteExternalAPIUser(*request.Token); err != nil {
webutils.InternalErrorHandler(w, err)
return
}
webutils.WriteSimpleResponse(w, true, "deleted token")
}