0

Config repository (#3988)

* WIP

* fix(test): fix ap test failing

* fix: fix unkeyed fields being used

* chore(tests): clean up browser tests by splitting out federation UI tests
This commit is contained in:
Gabe Kangas 2024-11-15 19:20:58 -08:00 committed by GitHub
parent 56d52c283c
commit 0b5d7c8a4d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
88 changed files with 2078 additions and 1643 deletions

View File

@ -6,6 +6,7 @@ import (
"github.com/owncast/owncast/activitypub/outbox" "github.com/owncast/owncast/activitypub/outbox"
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/activitypub/workerpool" "github.com/owncast/owncast/activitypub/workerpool"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
@ -14,15 +15,16 @@ import (
// Start will initialize and start the federation support. // Start will initialize and start the federation support.
func Start(datastore *data.Datastore) { func Start(datastore *data.Datastore) {
configRepository := configrepository.Get()
persistence.Setup(datastore) persistence.Setup(datastore)
workerpool.InitOutboundWorkerPool() workerpool.InitOutboundWorkerPool()
inbox.InitInboxWorkerPool() inbox.InitInboxWorkerPool()
// Generate the keys for signing federated activity if needed. // Generate the keys for signing federated activity if needed.
if data.GetPrivateKey() == "" { if configRepository.GetPrivateKey() == "" {
privateKey, publicKey, err := crypto.GenerateKeys() privateKey, publicKey, err := crypto.GenerateKeys()
_ = data.SetPrivateKey(string(privateKey)) _ = configRepository.SetPrivateKey(string(privateKey))
_ = data.SetPublicKey(string(publicKey)) _ = configRepository.SetPublicKey(string(publicKey))
if err != nil { if err != nil {
log.Errorln("Unable to get private key", err) log.Errorln("Unable to get private key", err)
} }

View File

@ -6,7 +6,7 @@ import (
"github.com/go-fed/activity/streams" "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab" "github.com/go-fed/activity/streams/vocab"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
) )
// PrivacyAudience represents the audience for an activity. // PrivacyAudience represents the audience for an activity.
@ -87,8 +87,10 @@ func MakeActivityDirect(activity vocab.ActivityStreamsCreate, toIRI *url.URL) vo
// MakeActivityPublic sets the required properties to make this activity // MakeActivityPublic sets the required properties to make this activity
// seen as public. // seen as public.
func MakeActivityPublic(activity vocab.ActivityStreamsCreate) vocab.ActivityStreamsCreate { func MakeActivityPublic(activity vocab.ActivityStreamsCreate) vocab.ActivityStreamsCreate {
configRepository := configrepository.Get()
// TO the public if we're not treating ActivityPub as "private". // TO the public if we're not treating ActivityPub as "private".
if !data.GetFederationIsPrivate() { if !configRepository.GetFederationIsPrivate() {
public, _ := url.Parse(PUBLIC) public, _ := url.Parse(PUBLIC)
to := streams.NewActivityStreamsToProperty() to := streams.NewActivityStreamsToProperty()
@ -121,7 +123,9 @@ func MakeUpdateActivity(activityID *url.URL) vocab.ActivityStreamsUpdate {
activity.SetJSONLDId(id) activity.SetJSONLDId(id)
// CC the public if we're not treating ActivityPub as "private". // CC the public if we're not treating ActivityPub as "private".
if !data.GetFederationIsPrivate() { configRepository := configrepository.Get()
if !configRepository.GetFederationIsPrivate() {
public, _ := url.Parse(PUBLIC) public, _ := url.Parse(PUBLIC)
cc := streams.NewActivityStreamsCcProperty() cc := streams.NewActivityStreamsCcProperty()
cc.AppendIRI(public) cc.AppendIRI(public)

View File

@ -9,8 +9,8 @@ import (
"github.com/go-fed/activity/streams" "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab" "github.com/go-fed/activity/streams/vocab"
"github.com/owncast/owncast/activitypub/crypto" "github.com/owncast/owncast/activitypub/crypto"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -101,11 +101,13 @@ func MakeActorPropertyWithID(idIRI *url.URL) vocab.ActivityStreamsActorProperty
// MakeServiceForAccount will create a new local actor service with the the provided username. // MakeServiceForAccount will create a new local actor service with the the provided username.
func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService { func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
configRepository := configrepository.Get()
actorIRI := MakeLocalIRIForAccount(accountName) actorIRI := MakeLocalIRIForAccount(accountName)
person := streams.NewActivityStreamsService() person := streams.NewActivityStreamsService()
nameProperty := streams.NewActivityStreamsNameProperty() nameProperty := streams.NewActivityStreamsNameProperty()
nameProperty.AppendXMLSchemaString(data.GetServerName()) nameProperty.AppendXMLSchemaString(configRepository.GetServerName())
person.SetActivityStreamsName(nameProperty) person.SetActivityStreamsName(nameProperty)
preferredUsernameProperty := streams.NewActivityStreamsPreferredUsernameProperty() preferredUsernameProperty := streams.NewActivityStreamsPreferredUsernameProperty()
@ -119,7 +121,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
person.SetActivityStreamsInbox(inboxProp) person.SetActivityStreamsInbox(inboxProp)
needsFollowApprovalProperty := streams.NewActivityStreamsManuallyApprovesFollowersProperty() needsFollowApprovalProperty := streams.NewActivityStreamsManuallyApprovesFollowersProperty()
needsFollowApprovalProperty.Set(data.GetFederationIsPrivate()) needsFollowApprovalProperty.Set(configRepository.GetFederationIsPrivate())
person.SetActivityStreamsManuallyApprovesFollowers(needsFollowApprovalProperty) person.SetActivityStreamsManuallyApprovesFollowers(needsFollowApprovalProperty)
outboxIRI := MakeLocalIRIForResource("/user/" + accountName + "/outbox") outboxIRI := MakeLocalIRIForResource("/user/" + accountName + "/outbox")
@ -152,7 +154,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKeyType) publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKeyType)
person.SetW3IDSecurityV1PublicKey(publicKeyProp) person.SetW3IDSecurityV1PublicKey(publicKeyProp)
if t, err := data.GetServerInitTime(); t != nil { if t, err := configRepository.GetServerInitTime(); t != nil {
publishedDateProp := streams.NewActivityStreamsPublishedProperty() publishedDateProp := streams.NewActivityStreamsPublishedProperty()
publishedDateProp.Set(t.Time) publishedDateProp.Set(t.Time)
person.SetActivityStreamsPublished(publishedDateProp) person.SetActivityStreamsPublished(publishedDateProp)
@ -163,8 +165,8 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
// Profile properties // Profile properties
// Avatar // Avatar
uniquenessString := data.GetLogoUniquenessString() uniquenessString := configRepository.GetLogoUniquenessString()
userAvatarURLString := data.GetServerURL() + "/logo/external" userAvatarURLString := configRepository.GetServerURL() + "/logo/external"
userAvatarURL, err := url.Parse(userAvatarURLString) userAvatarURL, err := url.Parse(userAvatarURLString)
userAvatarURL.RawQuery = "uc=" + uniquenessString userAvatarURL.RawQuery = "uc=" + uniquenessString
if err != nil { if err != nil {
@ -195,14 +197,14 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
// Profile bio // Profile bio
summaryProperty := streams.NewActivityStreamsSummaryProperty() summaryProperty := streams.NewActivityStreamsSummaryProperty()
summaryProperty.AppendXMLSchemaString(data.GetServerSummary()) summaryProperty.AppendXMLSchemaString(configRepository.GetServerSummary())
person.SetActivityStreamsSummary(summaryProperty) person.SetActivityStreamsSummary(summaryProperty)
// Links // Links
if serverURL := data.GetServerURL(); serverURL != "" { if serverURL := configRepository.GetServerURL(); serverURL != "" {
addMetadataLinkToProfile(person, "Stream", serverURL) addMetadataLinkToProfile(person, "Stream", serverURL)
} }
for _, link := range data.GetSocialHandles() { for _, link := range configRepository.GetSocialHandles() {
addMetadataLinkToProfile(person, link.Platform, link.URL) addMetadataLinkToProfile(person, link.Platform, link.URL)
} }
@ -220,7 +222,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
// Tags // Tags
tagProp := streams.NewActivityStreamsTagProperty() tagProp := streams.NewActivityStreamsTagProperty()
for _, tagString := range data.GetServerMetadataTags() { for _, tagString := range configRepository.GetServerMetadataTags() {
hashtag := MakeHashtag(tagString) hashtag := MakeHashtag(tagString)
tagProp.AppendTootHashtag(hashtag) tagProp.AppendTootHashtag(hashtag)
} }
@ -229,7 +231,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
// Work around an issue where a single attachment will not serialize // Work around an issue where a single attachment will not serialize
// as an array, so add another item to the mix. // as an array, so add another item to the mix.
if len(data.GetSocialHandles()) == 1 { if len(configRepository.GetSocialHandles()) == 1 {
addMetadataLinkToProfile(person, "Owncast", "https://owncast.online") addMetadataLinkToProfile(person, "Owncast", "https://owncast.online")
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/go-fed/activity/streams" "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab" "github.com/go-fed/activity/streams/vocab"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/persistence/configrepository"
) )
func makeFakeService() vocab.ActivityStreamsService { func makeFakeService() vocab.ActivityStreamsService {
@ -55,9 +56,11 @@ func TestMain(m *testing.M) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
data.SetupPersistence(dbFile.Name()) data.SetupPersistence(dbFile.Name())
data.SetServerURL("https://my.cool.site.biz")
configRepository := configrepository.Get()
configRepository.SetServerURL("https://my.cool.site.biz")
m.Run() m.Run()
} }

View File

@ -8,7 +8,7 @@ import (
"github.com/go-fed/activity/streams" "github.com/go-fed/activity/streams"
"github.com/go-fed/activity/streams/vocab" "github.com/go-fed/activity/streams/vocab"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -27,7 +27,9 @@ func MakeRemoteIRIForResource(resourcePath string, host string) (*url.URL, error
// MakeLocalIRIForResource will create an IRI for the local server. // MakeLocalIRIForResource will create an IRI for the local server.
func MakeLocalIRIForResource(resourcePath string) *url.URL { func MakeLocalIRIForResource(resourcePath string) *url.URL {
host := data.GetServerURL() configRepository := configrepository.Get()
host := configRepository.GetServerURL()
u, err := url.Parse(host) u, err := url.Parse(host)
if err != nil { if err != nil {
log.Errorln("unable to parse local IRI url", host, err) log.Errorln("unable to parse local IRI url", host, err)
@ -41,7 +43,9 @@ func MakeLocalIRIForResource(resourcePath string) *url.URL {
// MakeLocalIRIForAccount will return a full IRI for the local server account username. // MakeLocalIRIForAccount will return a full IRI for the local server account username.
func MakeLocalIRIForAccount(account string) *url.URL { func MakeLocalIRIForAccount(account string) *url.URL {
host := data.GetServerURL() configRepository := configrepository.Get()
host := configRepository.GetServerURL()
u, err := url.Parse(host) u, err := url.Parse(host)
if err != nil { if err != nil {
log.Errorln("unable to parse local IRI account server url", err) log.Errorln("unable to parse local IRI account server url", err)
@ -64,7 +68,9 @@ func Serialize(obj vocab.Type) ([]byte, error) {
// MakeLocalIRIForStreamURL will return a full IRI for the local server stream url. // MakeLocalIRIForStreamURL will return a full IRI for the local server stream url.
func MakeLocalIRIForStreamURL() *url.URL { func MakeLocalIRIForStreamURL() *url.URL {
host := data.GetServerURL() configRepository := configrepository.Get()
host := configRepository.GetServerURL()
u, err := url.Parse(host) u, err := url.Parse(host)
if err != nil { if err != nil {
log.Errorln("unable to parse local IRI stream url", err) log.Errorln("unable to parse local IRI stream url", err)
@ -78,7 +84,9 @@ func MakeLocalIRIForStreamURL() *url.URL {
// MakeLocalIRIforLogo will return a full IRI for the local server logo. // MakeLocalIRIforLogo will return a full IRI for the local server logo.
func MakeLocalIRIforLogo() *url.URL { func MakeLocalIRIforLogo() *url.URL {
host := data.GetServerURL() configRepository := configrepository.Get()
host := configRepository.GetServerURL()
u, err := url.Parse(host) u, err := url.Parse(host)
if err != nil { if err != nil {
log.Errorln("unable to parse local IRI stream url", err) log.Errorln("unable to parse local IRI stream url", err)
@ -93,7 +101,9 @@ func MakeLocalIRIforLogo() *url.URL {
// GetLogoType will return the rel value for the webfinger response and // GetLogoType will return the rel value for the webfinger response and
// the default static image is of type png. // the default static image is of type png.
func GetLogoType() string { func GetLogoType() string {
imageFilename := data.GetLogoPath() configRepository := configrepository.Get()
imageFilename := configRepository.GetLogoPath()
if imageFilename == "" { if imageFilename == "" {
return "image/png" return "image/png"
} }

View File

@ -9,12 +9,14 @@ import (
"github.com/owncast/owncast/activitypub/apmodels" "github.com/owncast/owncast/activitypub/apmodels"
"github.com/owncast/owncast/activitypub/crypto" "github.com/owncast/owncast/activitypub/crypto"
"github.com/owncast/owncast/activitypub/requests" "github.com/owncast/owncast/activitypub/requests"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
) )
// ActorHandler handles requests for a single actor. // ActorHandler handles requests for a single actor.
func ActorHandler(w http.ResponseWriter, r *http.Request) { func ActorHandler(w http.ResponseWriter, r *http.Request) {
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
@ -22,7 +24,7 @@ func ActorHandler(w http.ResponseWriter, r *http.Request) {
pathComponents := strings.Split(r.URL.Path, "/") pathComponents := strings.Split(r.URL.Path, "/")
accountName := pathComponents[3] accountName := pathComponents[3]
if _, valid := data.GetFederatedInboxMap()[accountName]; !valid { if _, valid := configRepository.GetFederatedInboxMap()[accountName]; !valid {
// User is not valid // User is not valid
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return

View File

@ -16,7 +16,7 @@ import (
"github.com/owncast/owncast/activitypub/crypto" "github.com/owncast/owncast/activitypub/crypto"
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/activitypub/requests" "github.com/owncast/owncast/activitypub/requests"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
) )
const ( const (
@ -145,7 +145,9 @@ func getFollowersPage(page string, r *http.Request) (vocab.ActivityStreamsOrdere
} }
func createPageURL(r *http.Request, page *string) (*url.URL, error) { func createPageURL(r *http.Request, page *string) (*url.URL, error) {
domain := data.GetServerURL() configRepository := configrepository.Get()
domain := configRepository.GetServerURL()
if domain == "" { if domain == "" {
return nil, errors.New("unable to get server URL") return nil, errors.New("unable to get server URL")
} }

View File

@ -7,7 +7,7 @@ import (
"github.com/owncast/owncast/activitypub/apmodels" "github.com/owncast/owncast/activitypub/apmodels"
"github.com/owncast/owncast/activitypub/inbox" "github.com/owncast/owncast/activitypub/inbox"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -22,7 +22,9 @@ func InboxHandler(w http.ResponseWriter, r *http.Request) {
} }
func acceptInboxRequest(w http.ResponseWriter, r *http.Request) { func acceptInboxRequest(w http.ResponseWriter, r *http.Request) {
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
@ -39,7 +41,7 @@ func acceptInboxRequest(w http.ResponseWriter, r *http.Request) {
// The account this request is for must match the account name we have set // The account this request is for must match the account name we have set
// for federation. // for federation.
if forLocalAccount != data.GetFederationUsername() { if forLocalAccount != configRepository.GetFederationUsername() {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }

View File

@ -10,7 +10,7 @@ import (
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/activitypub/requests" "github.com/owncast/owncast/activitypub/requests"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -25,12 +25,14 @@ func NodeInfoController(w http.ResponseWriter, r *http.Request) {
Links []links `json:"links"` Links []links `json:"links"`
} }
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
serverURL := data.GetServerURL() serverURL := configRepository.GetServerURL()
if serverURL == "" { if serverURL == "" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
@ -89,7 +91,9 @@ func NodeInfoV2Controller(w http.ResponseWriter, r *http.Request) {
Metadata metadata `json:"metadata"` Metadata metadata `json:"metadata"`
} }
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
@ -117,7 +121,7 @@ func NodeInfoV2Controller(w http.ResponseWriter, r *http.Request) {
OpenRegistrations: false, OpenRegistrations: false,
Protocols: []string{"activitypub"}, Protocols: []string{"activitypub"},
Metadata: metadata{ Metadata: metadata{
ChatEnabled: !data.GetChatDisabled(), ChatEnabled: !configRepository.GetChatDisabled(),
}, },
} }
@ -163,12 +167,14 @@ func XNodeInfo2Controller(w http.ResponseWriter, r *http.Request) {
OpenRegistrations bool `json:"openRegistrations"` OpenRegistrations bool `json:"openRegistrations"`
} }
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
serverURL := data.GetServerURL() serverURL := configRepository.GetServerURL()
if serverURL == "" { if serverURL == "" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
@ -178,7 +184,7 @@ func XNodeInfo2Controller(w http.ResponseWriter, r *http.Request) {
res := &response{ res := &response{
Organization: Organization{ Organization: Organization{
Name: data.GetServerName(), Name: configRepository.GetServerName(),
Contact: serverURL, Contact: serverURL,
}, },
Server: Server{ Server: Server{
@ -232,12 +238,14 @@ func InstanceV1Controller(w http.ResponseWriter, r *http.Request) {
InvitesEnabled bool `json:"invites_enabled"` InvitesEnabled bool `json:"invites_enabled"`
} }
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
serverURL := data.GetServerURL() serverURL := configRepository.GetServerURL()
if serverURL == "" { if serverURL == "" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
@ -254,9 +262,9 @@ func InstanceV1Controller(w http.ResponseWriter, r *http.Request) {
res := response{ res := response{
URI: serverURL, URI: serverURL,
Title: data.GetServerName(), Title: configRepository.GetServerName(),
ShortDescription: data.GetServerSummary(), ShortDescription: configRepository.GetServerSummary(),
Description: data.GetServerSummary(), Description: configRepository.GetServerSummary(),
Version: config.GetReleaseString(), Version: config.GetReleaseString(),
Stats: Stats{ Stats: Stats{
UserCount: 1, UserCount: 1,
@ -275,7 +283,9 @@ func InstanceV1Controller(w http.ResponseWriter, r *http.Request) {
} }
func writeResponse(payload interface{}, w http.ResponseWriter) error { func writeResponse(payload interface{}, w http.ResponseWriter) error {
accountName := data.GetDefaultFederationUsername() configRepository := configrepository.Get()
accountName := configRepository.GetDefaultFederationUsername()
actorIRI := apmodels.MakeLocalIRIForAccount(accountName) actorIRI := apmodels.MakeLocalIRIForAccount(accountName)
publicKey := crypto.GetPublicKey(actorIRI) publicKey := crypto.GetPublicKey(actorIRI)
@ -284,13 +294,15 @@ func writeResponse(payload interface{}, w http.ResponseWriter) error {
// HostMetaController points to webfinger. // HostMetaController points to webfinger.
func HostMetaController(w http.ResponseWriter, r *http.Request) { func HostMetaController(w http.ResponseWriter, r *http.Request) {
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
log.Debugln("host meta request rejected! Federation is not enabled") log.Debugln("host meta request rejected! Federation is not enabled")
return return
} }
serverURL := data.GetServerURL() serverURL := configRepository.GetServerURL()
if serverURL == "" { if serverURL == "" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return

View File

@ -8,31 +8,33 @@ import (
"github.com/owncast/owncast/activitypub/crypto" "github.com/owncast/owncast/activitypub/crypto"
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/activitypub/requests" "github.com/owncast/owncast/activitypub/requests"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// ObjectHandler handles requests for a single federated ActivityPub object. // ObjectHandler handles requests for a single federated ActivityPub object.
func ObjectHandler(w http.ResponseWriter, r *http.Request) { func ObjectHandler(w http.ResponseWriter, r *http.Request) {
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }
// If private federation mode is enabled do not allow access to objects. // If private federation mode is enabled do not allow access to objects.
if data.GetFederationIsPrivate() { if configRepository.GetFederationIsPrivate() {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }
iri := strings.Join([]string{strings.TrimSuffix(data.GetServerURL(), "/"), r.URL.Path}, "") iri := strings.Join([]string{strings.TrimSuffix(configRepository.GetServerURL(), "/"), r.URL.Path}, "")
object, _, _, err := persistence.GetObjectByIRI(iri) object, _, _, err := persistence.GetObjectByIRI(iri)
if err != nil { if err != nil {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }
accountName := data.GetDefaultFederationUsername() accountName := configRepository.GetDefaultFederationUsername()
actorIRI := apmodels.MakeLocalIRIForAccount(accountName) actorIRI := apmodels.MakeLocalIRIForAccount(accountName)
publicKey := crypto.GetPublicKey(actorIRI) publicKey := crypto.GetPublicKey(actorIRI)

View File

@ -6,20 +6,22 @@ import (
"strings" "strings"
"github.com/owncast/owncast/activitypub/apmodels" "github.com/owncast/owncast/activitypub/apmodels"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// WebfingerHandler will handle webfinger lookup requests. // WebfingerHandler will handle webfinger lookup requests.
func WebfingerHandler(w http.ResponseWriter, r *http.Request) { func WebfingerHandler(w http.ResponseWriter, r *http.Request) {
if !data.GetFederationEnabled() { configRepository := configrepository.Get()
if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
log.Debugln("webfinger request rejected! Federation is not enabled") log.Debugln("webfinger request rejected! Federation is not enabled")
return return
} }
instanceHostURL := data.GetServerURL() instanceHostURL := configRepository.GetServerURL()
if instanceHostURL == "" { if instanceHostURL == "" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
log.Warnln("webfinger request rejected! Federation is enabled but server URL is empty.") log.Warnln("webfinger request rejected! Federation is enabled but server URL is empty.")
@ -29,7 +31,7 @@ func WebfingerHandler(w http.ResponseWriter, r *http.Request) {
instanceHostString := utils.GetHostnameFromURLString(instanceHostURL) instanceHostString := utils.GetHostnameFromURLString(instanceHostURL)
if instanceHostString == "" { if instanceHostString == "" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
log.Warnln("webfinger request rejected! Federation is enabled but server URL is not set properly. data.GetServerURL(): " + data.GetServerURL()) log.Warnln("webfinger request rejected! Federation is enabled but server URL is not set properly. data.GetServerURL(): " + configRepository.GetServerURL())
return return
} }
@ -51,7 +53,7 @@ func WebfingerHandler(w http.ResponseWriter, r *http.Request) {
host := userComponents[1] host := userComponents[1]
user := userComponents[0] user := userComponents[0]
if _, valid := data.GetFederatedInboxMap()[user]; !valid { if _, valid := configRepository.GetFederatedInboxMap()[user]; !valid {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
log.Debugln("webfinger request rejected! Invalid user: " + user) log.Debugln("webfinger request rejected! Invalid user: " + user)
return return

View File

@ -8,13 +8,15 @@ import (
"errors" "errors"
"net/url" "net/url"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// GetPublicKey will return the public key for the provided actor. // GetPublicKey will return the public key for the provided actor.
func GetPublicKey(actorIRI *url.URL) PublicKey { func GetPublicKey(actorIRI *url.URL) PublicKey {
key := data.GetPublicKey() configRepository := configrepository.Get()
key := configRepository.GetPublicKey()
idURL, err := url.Parse(actorIRI.String() + "#main-key") idURL, err := url.Parse(actorIRI.String() + "#main-key")
if err != nil { if err != nil {
log.Errorln("unable to parse actor iri string", idURL, err) log.Errorln("unable to parse actor iri string", idURL, err)
@ -29,7 +31,9 @@ func GetPublicKey(actorIRI *url.URL) PublicKey {
// GetPrivateKey will return the internal server private key. // GetPrivateKey will return the internal server private key.
func GetPrivateKey() *rsa.PrivateKey { func GetPrivateKey() *rsa.PrivateKey {
key := data.GetPrivateKey() configRepository := configrepository.Get()
key := configRepository.GetPrivateKey()
block, _ := pem.Decode([]byte(key)) block, _ := pem.Decode([]byte(key))
if block == nil { if block == nil {

View File

@ -7,17 +7,19 @@ import (
"github.com/owncast/owncast/activitypub/resolvers" "github.com/owncast/owncast/activitypub/resolvers"
"github.com/owncast/owncast/core/chat" "github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
) )
func handleEngagementActivity(eventType events.EventType, isLiveNotification bool, actorReference vocab.ActivityStreamsActorProperty, action string) error { func handleEngagementActivity(eventType events.EventType, isLiveNotification bool, actorReference vocab.ActivityStreamsActorProperty, action string) error {
configRepository := configrepository.Get()
// Do nothing if displaying engagement actions has been turned off. // Do nothing if displaying engagement actions has been turned off.
if !data.GetFederationShowEngagement() { if !configRepository.GetFederationShowEngagement() {
return nil return nil
} }
// Do nothing if chat is disabled // Do nothing if chat is disabled
if data.GetChatDisabled() { if configRepository.GetChatDisabled() {
return nil return nil
} }
@ -36,11 +38,11 @@ func handleEngagementActivity(eventType events.EventType, isLiveNotification boo
if isLiveNotification && action == events.FediverseEngagementLike { if isLiveNotification && action == events.FediverseEngagementLike {
suffix = "liked that this stream went live." suffix = "liked that this stream went live."
} else if action == events.FediverseEngagementLike { } else if action == events.FediverseEngagementLike {
suffix = fmt.Sprintf("liked a post from %s.", data.GetServerName()) suffix = fmt.Sprintf("liked a post from %s.", configRepository.GetServerName())
} else if isLiveNotification && action == events.FediverseEngagementRepost { } else if isLiveNotification && action == events.FediverseEngagementRepost {
suffix = "shared this stream with their followers." suffix = "shared this stream with their followers."
} else if action == events.FediverseEngagementRepost { } else if action == events.FediverseEngagementRepost {
suffix = fmt.Sprintf("shared a post from %s.", data.GetServerName()) suffix = fmt.Sprintf("shared a post from %s.", configRepository.GetServerName())
} else if action == events.FediverseEngagementFollow { } else if action == events.FediverseEngagementFollow {
suffix = "followed this stream." suffix = "followed this stream."
} else { } else {

View File

@ -10,13 +10,15 @@ import (
"github.com/owncast/owncast/activitypub/requests" "github.com/owncast/owncast/activitypub/requests"
"github.com/owncast/owncast/activitypub/resolvers" "github.com/owncast/owncast/activitypub/resolvers"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsFollow) error { func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsFollow) error {
configRepository := configrepository.Get()
follow, err := resolvers.MakeFollowRequest(c, activity) follow, err := resolvers.MakeFollowRequest(c, activity)
if err != nil { if err != nil {
log.Errorln("unable to create follow inbox request", err) log.Errorln("unable to create follow inbox request", err)
@ -27,7 +29,7 @@ func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsF
return fmt.Errorf("unable to handle request") return fmt.Errorf("unable to handle request")
} }
approved := !data.GetFederationIsPrivate() approved := !configRepository.GetFederationIsPrivate()
followRequest := *follow followRequest := *follow
@ -36,7 +38,7 @@ func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsF
return err return err
} }
localAccountName := data.GetDefaultFederationUsername() localAccountName := configRepository.GetDefaultFederationUsername()
if approved { if approved {
if err := requests.SendFollowAccept(follow.Inbox, activity, localAccountName); err != nil { if err := requests.SendFollowAccept(follow.Inbox, activity, localAccountName); err != nil {

View File

@ -15,7 +15,7 @@ import (
"github.com/owncast/owncast/activitypub/apmodels" "github.com/owncast/owncast/activitypub/apmodels"
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/activitypub/resolvers" "github.com/owncast/owncast/activitypub/resolvers"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -131,7 +131,9 @@ func Verify(request *http.Request) (bool, error) {
} }
func isBlockedDomain(domain string) bool { func isBlockedDomain(domain string) bool {
blockedDomains := data.GetBlockedFederatedDomains() configRepository := configrepository.Get()
blockedDomains := configRepository.GetBlockedFederatedDomains()
for _, blockedDomain := range blockedDomains { for _, blockedDomain := range blockedDomains {
if strings.Contains(domain, blockedDomain) { if strings.Contains(domain, blockedDomain) {

View File

@ -9,6 +9,7 @@ import (
"github.com/owncast/owncast/activitypub/apmodels" "github.com/owncast/owncast/activitypub/apmodels"
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/persistence/configrepository"
) )
func makeFakePerson() vocab.ActivityStreamsPerson { func makeFakePerson() vocab.ActivityStreamsPerson {
@ -49,21 +50,24 @@ func makeFakePerson() vocab.ActivityStreamsPerson {
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
data.SetupPersistence(":memory:") data.SetupPersistence(":memory:")
data.SetServerURL("https://my.cool.site.biz") configRepository := configrepository.Get()
configRepository.SetServerURL("https://my.cool.site.biz")
persistence.Setup(data.GetDatastore()) persistence.Setup(data.GetDatastore())
m.Run() m.Run()
} }
func TestBlockedDomains(t *testing.T) { func TestBlockedDomains(t *testing.T) {
configRepository := configrepository.Get()
person := makeFakePerson() person := makeFakePerson()
data.SetBlockedFederatedDomains([]string{"freedom.eagle", "guns.life"}) configRepository.SetBlockedFederatedDomains([]string{"freedom.eagle", "guns.life"})
if len(data.GetBlockedFederatedDomains()) != 2 { if len(configRepository.GetBlockedFederatedDomains()) != 2 {
t.Error("Blocked federated domains is not set correctly") t.Error("Blocked federated domains is not set correctly")
} }
for _, domain := range data.GetBlockedFederatedDomains() { for _, domain := range configRepository.GetBlockedFederatedDomains() {
if domain == person.GetJSONLDId().GetIRI().Host { if domain == person.GetJSONLDId().GetIRI().Host {
return return
} }

View File

@ -16,10 +16,10 @@ import (
"github.com/owncast/owncast/activitypub/resolvers" "github.com/owncast/owncast/activitypub/resolvers"
"github.com/owncast/owncast/activitypub/webfinger" "github.com/owncast/owncast/activitypub/webfinger"
"github.com/owncast/owncast/activitypub/workerpool" "github.com/owncast/owncast/activitypub/workerpool"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/teris-io/shortid" "github.com/teris-io/shortid"
@ -27,7 +27,9 @@ import (
// SendLive will send all followers the message saying you started a live stream. // SendLive will send all followers the message saying you started a live stream.
func SendLive() error { func SendLive() error {
textContent := data.GetFederationGoLiveMessage() configRepository := configrepository.Get()
textContent := configRepository.GetFederationGoLiveMessage()
// If the message is empty then do not send it. // If the message is empty then do not send it.
if textContent == "" { if textContent == "" {
@ -38,7 +40,7 @@ func SendLive() error {
reg := regexp.MustCompile("[^a-zA-Z0-9]+") reg := regexp.MustCompile("[^a-zA-Z0-9]+")
tagProp := streams.NewActivityStreamsTagProperty() tagProp := streams.NewActivityStreamsTagProperty()
for _, tagString := range data.GetServerMetadataTags() { for _, tagString := range configRepository.GetServerMetadataTags() {
tagWithoutSpecialCharacters := reg.ReplaceAllString(tagString, "") tagWithoutSpecialCharacters := reg.ReplaceAllString(tagString, "")
hashtag := apmodels.MakeHashtag(tagWithoutSpecialCharacters) hashtag := apmodels.MakeHashtag(tagWithoutSpecialCharacters)
tagProp.AppendTootHashtag(hashtag) tagProp.AppendTootHashtag(hashtag)
@ -57,15 +59,15 @@ func SendLive() error {
tagsString := strings.Join(tagStrings, " ") tagsString := strings.Join(tagStrings, " ")
var streamTitle string var streamTitle string
if title := data.GetStreamTitle(); title != "" { if title := configRepository.GetStreamTitle(); title != "" {
streamTitle = fmt.Sprintf("<p>%s</p>", title) streamTitle = fmt.Sprintf("<p>%s</p>", title)
} }
textContent = fmt.Sprintf("<p>%s</p>%s<p>%s</p><p><a href=\"%s\">%s</a></p>", textContent, streamTitle, tagsString, data.GetServerURL(), data.GetServerURL()) textContent = fmt.Sprintf("<p>%s</p>%s<p>%s</p><p><a href=\"%s\">%s</a></p>", textContent, streamTitle, tagsString, configRepository.GetServerURL(), configRepository.GetServerURL())
activity, _, note, noteID := createBaseOutboundMessage(textContent) activity, _, note, noteID := createBaseOutboundMessage(textContent)
// To the public if we're not treating ActivityPub as "private". // To the public if we're not treating ActivityPub as "private".
if !data.GetFederationIsPrivate() { if !configRepository.GetFederationIsPrivate() {
note = apmodels.MakeNotePublic(note) note = apmodels.MakeNotePublic(note)
activity = apmodels.MakeActivityPublic(activity) activity = apmodels.MakeActivityPublic(activity)
} }
@ -73,7 +75,7 @@ func SendLive() error {
note.SetActivityStreamsTag(tagProp) note.SetActivityStreamsTag(tagProp)
// Attach an image along with the Federated message. // Attach an image along with the Federated message.
previewURL, err := url.Parse(data.GetServerURL()) previewURL, err := url.Parse(configRepository.GetServerURL())
if err == nil { if err == nil {
var imageToAttach string var imageToAttach string
var mediaType string var mediaType string
@ -94,7 +96,7 @@ func SendLive() error {
} }
} }
if data.GetNSFW() { if configRepository.GetNSFW() {
// Mark content as sensitive. // Mark content as sensitive.
sensitive := streams.NewActivityStreamsSensitiveProperty() sensitive := streams.NewActivityStreamsSensitiveProperty()
sensitive.AppendXMLSchemaBoolean(true) sensitive.AppendXMLSchemaBoolean(true)
@ -151,6 +153,8 @@ func SendDirectMessageToAccount(textContent, account string) error {
// SendPublicMessage will send a public message to all followers. // SendPublicMessage will send a public message to all followers.
func SendPublicMessage(textContent string) error { func SendPublicMessage(textContent string) error {
configRepository := configrepository.Get()
originalContent := textContent originalContent := textContent
textContent = utils.RenderSimpleMarkdown(textContent) textContent = utils.RenderSimpleMarkdown(textContent)
@ -173,7 +177,7 @@ func SendPublicMessage(textContent string) error {
activity, _, note, noteID := createBaseOutboundMessage(textContent) activity, _, note, noteID := createBaseOutboundMessage(textContent)
note.SetActivityStreamsTag(tagProp) note.SetActivityStreamsTag(tagProp)
if !data.GetFederationIsPrivate() { if !configRepository.GetFederationIsPrivate() {
note = apmodels.MakeNotePublic(note) note = apmodels.MakeNotePublic(note)
activity = apmodels.MakeActivityPublic(activity) activity = apmodels.MakeActivityPublic(activity)
} }
@ -197,7 +201,8 @@ func SendPublicMessage(textContent string) error {
// nolint: unparam // nolint: unparam
func createBaseOutboundMessage(textContent string) (vocab.ActivityStreamsCreate, string, vocab.ActivityStreamsNote, string) { func createBaseOutboundMessage(textContent string) (vocab.ActivityStreamsCreate, string, vocab.ActivityStreamsNote, string) {
localActor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername()) configRepository := configrepository.Get()
localActor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
noteID := shortid.MustGenerate() noteID := shortid.MustGenerate()
noteIRI := apmodels.MakeLocalIRIForResource(noteID) noteIRI := apmodels.MakeLocalIRIForResource(noteID)
id := shortid.MustGenerate() id := shortid.MustGenerate()
@ -218,7 +223,8 @@ func getHashtagLinkHTMLFromTagString(baseHashtag string) string {
// SendToFollowers will send an arbitrary payload to all follower inboxes. // SendToFollowers will send an arbitrary payload to all follower inboxes.
func SendToFollowers(payload []byte) error { func SendToFollowers(payload []byte) error {
localActor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername()) configRepository := configrepository.Get()
localActor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
followers, _, err := persistence.GetFederationFollowers(-1, 0) followers, _, err := persistence.GetFederationFollowers(-1, 0)
if err != nil { if err != nil {
@ -241,7 +247,8 @@ func SendToFollowers(payload []byte) error {
// SendToUser will send a payload to a single specific inbox. // SendToUser will send a payload to a single specific inbox.
func SendToUser(inbox *url.URL, payload []byte) error { func SendToUser(inbox *url.URL, payload []byte) error {
localActor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername()) configRepository := configrepository.Get()
localActor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
req, err := requests.CreateSignedRequest(payload, inbox, localActor) req, err := requests.CreateSignedRequest(payload, inbox, localActor)
if err != nil { if err != nil {
@ -255,8 +262,10 @@ func SendToUser(inbox *url.URL, payload []byte) error {
// UpdateFollowersWithAccountUpdates will send an update to all followers alerting of a profile update. // UpdateFollowersWithAccountUpdates will send an update to all followers alerting of a profile update.
func UpdateFollowersWithAccountUpdates() error { func UpdateFollowersWithAccountUpdates() error {
configRepository := configrepository.Get()
// Don't do anything if federation is disabled. // Don't do anything if federation is disabled.
if !data.GetFederationEnabled() { if !configRepository.GetFederationEnabled() {
return nil return nil
} }
@ -265,7 +274,7 @@ func UpdateFollowersWithAccountUpdates() error {
activity := apmodels.MakeUpdateActivity(objectID) activity := apmodels.MakeUpdateActivity(objectID)
actor := streams.NewActivityStreamsPerson() actor := streams.NewActivityStreamsPerson()
actorID := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername()) actorID := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
actorIDProperty := streams.NewJSONLDIdProperty() actorIDProperty := streams.NewJSONLDIdProperty()
actorIDProperty.Set(actorID) actorIDProperty.Set(actorID)
actor.SetJSONLDId(actorIDProperty) actor.SetJSONLDId(actorIDProperty)

View File

@ -10,7 +10,7 @@ import (
"github.com/go-fed/activity/streams/vocab" "github.com/go-fed/activity/streams/vocab"
"github.com/owncast/owncast/activitypub/apmodels" "github.com/owncast/owncast/activitypub/apmodels"
"github.com/owncast/owncast/activitypub/crypto" "github.com/owncast/owncast/activitypub/crypto"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -47,11 +47,12 @@ func Resolve(c context.Context, data []byte, callbacks ...interface{}) error {
// ResolveIRI will resolve an IRI ahd call the correct callback for the resolved type. // ResolveIRI will resolve an IRI ahd call the correct callback for the resolved type.
func ResolveIRI(c context.Context, iri string, callbacks ...interface{}) error { func ResolveIRI(c context.Context, iri string, callbacks ...interface{}) error {
configRepository := configrepository.Get()
log.Debugln("Resolving", iri) log.Debugln("Resolving", iri)
req, _ := http.NewRequest(http.MethodGet, iri, nil) req, _ := http.NewRequest(http.MethodGet, iri, nil)
actor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername()) actor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
if err := crypto.SignRequest(req, nil, actor); err != nil { if err := crypto.SignRequest(req, nil, actor); err != nil {
return err return err
} }

View File

@ -11,7 +11,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -47,6 +47,8 @@ func setupExpiredRequestPruner() {
// StartAuthFlow will begin the IndieAuth flow by generating an auth request. // StartAuthFlow will begin the IndieAuth flow by generating an auth request.
func StartAuthFlow(authHost, userID, accessToken, displayName string) (*url.URL, error) { func StartAuthFlow(authHost, userID, accessToken, displayName string) (*url.URL, error) {
configRepository := configrepository.Get()
// Limit the number of pending requests // Limit the number of pending requests
if len(pendingAuthRequests) >= maxPendingRequests { if len(pendingAuthRequests) >= maxPendingRequests {
return nil, errors.New("Please try again later. Too many pending requests.") return nil, errors.New("Please try again later. Too many pending requests.")
@ -68,7 +70,7 @@ func StartAuthFlow(authHost, userID, accessToken, displayName string) (*url.URL,
return nil, errors.New("only servers secured with https are supported") return nil, errors.New("only servers secured with https are supported")
} }
serverURL := data.GetServerURL() serverURL := configRepository.GetServerURL()
if serverURL == "" { if serverURL == "" {
return nil, errors.New("Owncast server URL must be set when using auth") return nil, errors.New("Owncast server URL must be set when using auth")
} }

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/teris-io/shortid" "github.com/teris-io/shortid"
) )
@ -70,6 +70,8 @@ func StartServerAuth(clientID, redirectURI, codeChallenge, state, me string) (*S
// CompleteServerAuth will verify that the values provided in the final step // CompleteServerAuth will verify that the values provided in the final step
// of the IndieAuth flow are correct, and return some basic profile info. // of the IndieAuth flow are correct, and return some basic profile info.
func CompleteServerAuth(code, redirectURI, clientID string, codeVerifier string) (*ServerProfileResponse, error) { func CompleteServerAuth(code, redirectURI, clientID string, codeVerifier string) (*ServerProfileResponse, error) {
configRepository := configrepository.Get()
request, pending := pendingServerAuthRequests[code] request, pending := pendingServerAuthRequests[code]
if !pending { if !pending {
return nil, errors.New("no pending authentication request") return nil, errors.New("no pending authentication request")
@ -89,11 +91,11 @@ func CompleteServerAuth(code, redirectURI, clientID string, codeVerifier string)
} }
response := ServerProfileResponse{ response := ServerProfileResponse{
Me: data.GetServerURL(), Me: configRepository.GetServerURL(),
Profile: ServerProfile{ Profile: ServerProfile{
Name: data.GetServerName(), Name: configRepository.GetServerName(),
URL: data.GetServerURL(), URL: configRepository.GetServerURL(),
Photo: fmt.Sprintf("%s/%s", data.GetServerURL(), data.GetLogoPath()), Photo: fmt.Sprintf("%s/%s", configRepository.GetServerURL(), configRepository.GetLogoPath()),
}, },
} }

View File

@ -7,8 +7,8 @@ import (
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promauto"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -23,6 +23,8 @@ var (
func Start(getStatusFunc func() models.Status) error { func Start(getStatusFunc func() models.Status) error {
setupPersistence() setupPersistence()
configRepository := configrepository.Get()
getStatus = getStatusFunc getStatus = getStatusFunc
_server = NewChat() _server = NewChat()
@ -35,7 +37,7 @@ func Start(getStatusFunc func() models.Status) error {
Help: "The number of chat messages incremented over time.", Help: "The number of chat messages incremented over time.",
ConstLabels: map[string]string{ ConstLabels: map[string]string{
"version": config.VersionNumber, "version": config.VersionNumber,
"host": data.GetServerURL(), "host": configRepository.GetServerURL(),
}, },
}) })

View File

@ -13,8 +13,8 @@ import (
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/services/geoip" "github.com/owncast/owncast/services/geoip"
) )
@ -133,7 +133,9 @@ func (c *Client) readPump() {
} }
// Check if this message passes the optional language filter // Check if this message passes the optional language filter
if data.GetChatSlurFilterEnabled() && !c.messageFilter.Allow(string(message)) { configRepository := configrepository.Get()
if configRepository.GetChatSlurFilterEnabled() && !c.messageFilter.Allow(string(message)) {
c.sendAction("Sorry, that message contained language that is not allowed in this chat.") c.sendAction("Sorry, that message contained language that is not allowed in this chat.")
continue continue
} }
@ -209,9 +211,11 @@ func (c *Client) close() {
} }
func (c *Client) passesRateLimit() bool { func (c *Client) passesRateLimit() bool {
configRepository := configrepository.Get()
// If spam rate limiting is disabled, or the user is a moderator, always // If spam rate limiting is disabled, or the user is a moderator, always
// allow the message. // allow the message.
if !data.GetChatSpamProtectionEnabled() || c.User.IsModerator() { if !configRepository.GetChatSpamProtectionEnabled() || c.User.IsModerator() {
return true return true
} }

View File

@ -8,8 +8,8 @@ import (
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/webhooks" "github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/userrepository" "github.com/owncast/owncast/persistence/userrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -22,10 +22,12 @@ func (s *Server) userNameChanged(eventData chatClientEvent) {
return return
} }
configRepository := configrepository.Get()
proposedUsername := receivedEvent.NewName proposedUsername := receivedEvent.NewName
// Check if name is on the blocklist // Check if name is on the blocklist
blocklist := data.GetForbiddenUsernameList() blocklist := configRepository.GetForbiddenUsernameList()
// Names have a max length // Names have a max length
proposedUsername = utils.MakeSafeStringOfLength(proposedUsername, config.MaxChatDisplayNameLength) proposedUsername = utils.MakeSafeStringOfLength(proposedUsername, config.MaxChatDisplayNameLength)

View File

@ -1,6 +1,8 @@
package events package events
import "github.com/owncast/owncast/core/data" import (
"github.com/owncast/owncast/persistence/configrepository"
)
// FediverseEngagementEvent is a message displayed in chat on representing an action on the Fediverse. // FediverseEngagementEvent is a message displayed in chat on representing an action on the Fediverse.
type FediverseEngagementEvent struct { type FediverseEngagementEvent struct {
@ -13,6 +15,8 @@ type FediverseEngagementEvent struct {
// GetBroadcastPayload will return the object to send to all chat users. // GetBroadcastPayload will return the object to send to all chat users.
func (e *FediverseEngagementEvent) GetBroadcastPayload() EventPayload { func (e *FediverseEngagementEvent) GetBroadcastPayload() EventPayload {
configRepository := configrepository.Get()
return EventPayload{ return EventPayload{
"id": e.ID, "id": e.ID,
"timestamp": e.Timestamp, "timestamp": e.Timestamp,
@ -22,7 +26,7 @@ func (e *FediverseEngagementEvent) GetBroadcastPayload() EventPayload {
"title": e.UserAccountName, "title": e.UserAccountName,
"link": e.Link, "link": e.Link,
"user": EventPayload{ "user": EventPayload{
"displayName": data.GetServerName(), "displayName": configRepository.GetServerName(),
}, },
} }
} }

View File

@ -1,6 +1,8 @@
package events package events
import "github.com/owncast/owncast/core/data" import (
"github.com/owncast/owncast/persistence/configrepository"
)
// SystemMessageEvent is a message displayed in chat on behalf of the server. // SystemMessageEvent is a message displayed in chat on behalf of the server.
type SystemMessageEvent struct { type SystemMessageEvent struct {
@ -10,13 +12,15 @@ type SystemMessageEvent struct {
// GetBroadcastPayload will return the object to send to all chat users. // GetBroadcastPayload will return the object to send to all chat users.
func (e *SystemMessageEvent) GetBroadcastPayload() EventPayload { func (e *SystemMessageEvent) GetBroadcastPayload() EventPayload {
configRepository := configrepository.Get()
return EventPayload{ return EventPayload{
"id": e.ID, "id": e.ID,
"timestamp": e.Timestamp, "timestamp": e.Timestamp,
"body": e.Body, "body": e.Body,
"type": SystemMessageSent, "type": SystemMessageSent,
"user": EventPayload{ "user": EventPayload{
"displayName": data.GetServerName(), "displayName": configRepository.GetServerName(),
}, },
} }
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/authrepository"
"github.com/owncast/owncast/persistence/tables" "github.com/owncast/owncast/persistence/tables"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -24,7 +25,9 @@ const (
func setupPersistence() { func setupPersistence() {
_datastore = data.GetDatastore() _datastore = data.GetDatastore()
tables.CreateMessagesTable(_datastore.DB) tables.CreateMessagesTable(_datastore.DB)
data.CreateBanIPTable(_datastore.DB)
authRepository := authrepository.Get()
authRepository.CreateBanIPTable(_datastore.DB)
chatDataPruner := time.NewTicker(5 * time.Minute) chatDataPruner := time.NewTicker(5 * time.Minute)
go func() { go func() {

View File

@ -13,9 +13,10 @@ import (
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/webhooks" "github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/authrepository"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/userrepository" "github.com/owncast/owncast/persistence/userrepository"
"github.com/owncast/owncast/services/geoip" "github.com/owncast/owncast/services/geoip"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
@ -95,7 +96,9 @@ func (s *Server) Addclient(conn *websocket.Conn, user *models.User, accessToken
ConnectedAt: time.Now(), ConnectedAt: time.Now(),
} }
shouldSendJoinedMessages := data.GetChatJoinPartMessagesEnabled() configRepository := configrepository.Get()
shouldSendJoinedMessages := configRepository.GetChatJoinPartMessagesEnabled()
// If there are existing clients connected for this user do not send // If there are existing clients connected for this user do not send
// a user joined message. Do not put this under a mutex, as // a user joined message. Do not put this under a mutex, as
@ -186,8 +189,10 @@ func (s *Server) sendUserPartedMessage(c *Client) {
userPartEvent.User = c.User userPartEvent.User = c.User
userPartEvent.ClientID = c.Id userPartEvent.ClientID = c.Id
configRepository := configrepository.Get()
// If part messages are disabled. // If part messages are disabled.
if data.GetChatJoinPartMessagesEnabled() { if configRepository.GetChatJoinPartMessagesEnabled() {
if err := s.Broadcast(userPartEvent.GetBroadcastPayload()); err != nil { if err := s.Broadcast(userPartEvent.GetBroadcastPayload()); err != nil {
log.Errorln("error sending chat part message", err) log.Errorln("error sending chat part message", err)
} }
@ -198,14 +203,17 @@ func (s *Server) sendUserPartedMessage(c *Client) {
// HandleClientConnection is fired when a single client connects to the websocket. // HandleClientConnection is fired when a single client connects to the websocket.
func (s *Server) HandleClientConnection(w http.ResponseWriter, r *http.Request) { func (s *Server) HandleClientConnection(w http.ResponseWriter, r *http.Request) {
if data.GetChatDisabled() { configRepository := configrepository.Get()
authRepository := authrepository.Get()
if configRepository.GetChatDisabled() {
_, _ = w.Write([]byte(events.ChatDisabled)) _, _ = w.Write([]byte(events.ChatDisabled))
return return
} }
ipAddress := utils.GetIPAddressFromRequest(r) ipAddress := utils.GetIPAddressFromRequest(r)
// Check if this client's IP address is banned. If so send a rejection. // Check if this client's IP address is banned. If so send a rejection.
if blocked, err := data.IsIPAddressBanned(ipAddress); blocked { if blocked, err := authRepository.IsIPAddressBanned(ipAddress); blocked {
log.Debugln("Client ip address has been blocked. Rejecting.") log.Debugln("Client ip address has been blocked. Rejecting.")
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
@ -377,12 +385,14 @@ func SendActionToUser(userID string, text string) error {
} }
func (s *Server) eventReceived(event chatClientEvent) { func (s *Server) eventReceived(event chatClientEvent) {
configRepository := configrepository.Get()
c := event.client c := event.client
u := c.User u := c.User
// If established chat user only mode is enabled and the user is not old // If established chat user only mode is enabled and the user is not old
// enough then reject this event and send them an informative message. // enough then reject this event and send them an informative message.
if u != nil && data.GetChatEstbalishedUsersOnlyMode() && time.Since(event.client.User.CreatedAt) < config.GetDefaults().ChatEstablishedUserModeTimeDuration && !u.IsModerator() { if u != nil && configRepository.GetChatEstbalishedUsersOnlyMode() && time.Since(event.client.User.CreatedAt) < config.GetDefaults().ChatEstablishedUserModeTimeDuration && !u.IsModerator() {
s.sendActionToClient(c, "You have not been an established chat participant long enough to take part in chat. Please enjoy the stream and try again later.") s.sendActionToClient(c, "You have not been an established chat participant long enough to take part in chat. Please enjoy the stream and try again later.")
return return
} }
@ -409,10 +419,12 @@ func (s *Server) eventReceived(event chatClientEvent) {
} }
func (s *Server) sendWelcomeMessageToClient(c *Client) { func (s *Server) sendWelcomeMessageToClient(c *Client) {
configRepository := configrepository.Get()
// Add an artificial delay so people notice this message come in. // Add an artificial delay so people notice this message come in.
time.Sleep(7 * time.Second) time.Sleep(7 * time.Second)
welcomeMessage := utils.RenderSimpleMarkdown(data.GetServerWelcomeMessage()) welcomeMessage := utils.RenderSimpleMarkdown(configRepository.GetServerWelcomeMessage())
if welcomeMessage != "" { if welcomeMessage != "" {
s.sendSystemMessageToClient(c, welcomeMessage) s.sendSystemMessageToClient(c, welcomeMessage)
@ -420,7 +432,9 @@ func (s *Server) sendWelcomeMessageToClient(c *Client) {
} }
func (s *Server) sendAllWelcomeMessage() { func (s *Server) sendAllWelcomeMessage() {
welcomeMessage := utils.RenderSimpleMarkdown(data.GetServerWelcomeMessage()) configRepository := configrepository.Get()
welcomeMessage := utils.RenderSimpleMarkdown(configRepository.GetServerWelcomeMessage())
if welcomeMessage != "" { if welcomeMessage != "" {
clientMessage := events.SystemMessageEvent{ clientMessage := events.SystemMessageEvent{

View File

@ -16,6 +16,7 @@ import (
"github.com/owncast/owncast/core/webhooks" "github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/notifications" "github.com/owncast/owncast/notifications"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/tables" "github.com/owncast/owncast/persistence/tables"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/yp" "github.com/owncast/owncast/yp"
@ -34,10 +35,10 @@ var (
// Start starts up the core processing. // Start starts up the core processing.
func Start() error { func Start() error {
resetDirectories() resetDirectories()
configRepository := configrepository.Get()
// configRepository.PopulateDefaults()
data.PopulateDefaults() if err := configRepository.VerifySettings(); err != nil {
if err := data.VerifySettings(); err != nil {
log.Error(err) log.Error(err)
return err return err
} }
@ -75,7 +76,7 @@ func Start() error {
// start the rtmp server // start the rtmp server
go rtmp.Start(setStreamAsConnected, setBroadcaster) go rtmp.Start(setStreamAsConnected, setBroadcaster)
rtmpPort := data.GetRTMPPortNumber() rtmpPort := configRepository.GetRTMPPortNumber()
if rtmpPort != 1935 { if rtmpPort != 1935 {
log.Infof("RTMP is accepting inbound streams on port %d.", rtmpPort) log.Infof("RTMP is accepting inbound streams on port %d.", rtmpPort)
} }
@ -113,7 +114,8 @@ func transitionToOfflineVideoStreamContent() {
go _transcoder.Start(false) go _transcoder.Start(false)
// Copy the logo to be the thumbnail // Copy the logo to be the thumbnail
logo := data.GetLogoPath() configRepository := configrepository.Get()
logo := configRepository.GetLogoPath()
dst := filepath.Join(config.TempDir, "thumbnail.jpg") dst := filepath.Join(config.TempDir, "thumbnail.jpg")
if err = utils.Copy(filepath.Join("data", logo), dst); err != nil { if err = utils.Copy(filepath.Join("data", logo), dst); err != nil {
log.Warnln(err) log.Warnln(err)
@ -130,7 +132,8 @@ func resetDirectories() {
utils.CleanupDirectory(config.HLSStoragePath) utils.CleanupDirectory(config.HLSStoragePath)
// Remove the previous thumbnail // Remove the previous thumbnail
logo := data.GetLogoPath() configRepository := configrepository.Get()
logo := configRepository.GetLogoPath()
if utils.DoesFileExists(logo) { if utils.DoesFileExists(logo) {
err := utils.Copy(path.Join("data", logo), filepath.Join(config.DataDirectory, "thumbnail.jpg")) err := utils.Copy(path.Join("data", logo), filepath.Join(config.DataDirectory, "thumbnail.jpg"))
if err != nil { if err != nil {

View File

@ -1,13 +0,0 @@
package data
// GetFederatedInboxMap is a mapping between account names and their outbox.
func GetFederatedInboxMap() map[string]string {
return map[string]string{
GetDefaultFederationUsername(): GetDefaultFederationUsername(),
}
}
// GetDefaultFederationUsername will return the username used for sending federation activities.
func GetDefaultFederationUsername() string {
return GetFederationUsername()
}

File diff suppressed because it is too large Load Diff

View File

@ -1,23 +0,0 @@
package data
// GetPublicKey will return the public key.
func GetPublicKey() string {
value, _ := _datastore.GetString(publicKeyKey)
return value
}
// SetPublicKey will save the public key.
func SetPublicKey(key string) error {
return _datastore.SetString(publicKeyKey, key)
}
// GetPrivateKey will return the private key.
func GetPrivateKey() string {
value, _ := _datastore.GetString(privateKeyKey)
return value
}
// SetPrivateKey will save the private key.
func SetPrivateKey(key string) error {
return _datastore.SetString(privateKeyKey, key)
}

View File

@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"os" "os"
"testing" "testing"
"github.com/owncast/owncast/models"
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -89,7 +91,7 @@ func TestCustomType(t *testing.T) {
} }
// Save config entry to the database // Save config entry to the database
if err := _datastore.Save(ConfigEntry{&testStruct, testKey}); err != nil { if err := _datastore.Save(models.ConfigEntry{&testStruct, testKey}); err != nil {
t.Error(err) t.Error(err)
} }
@ -101,7 +103,7 @@ func TestCustomType(t *testing.T) {
// Get a typed struct out of it // Get a typed struct out of it
var testResult TestStruct var testResult TestStruct
if err := entryResult.getObject(&testResult); err != nil { if err := entryResult.GetObject(&testResult); err != nil {
t.Error(err) t.Error(err)
} }
@ -121,7 +123,7 @@ func TestStringMap(t *testing.T) {
} }
// Save config entry to the database // Save config entry to the database
if err := _datastore.Save(ConfigEntry{&testMap, testKey}); err != nil { if err := _datastore.Save(models.ConfigEntry{Value: &testMap, Key: testKey}); err != nil {
t.Error(err) t.Error(err)
} }
@ -131,7 +133,7 @@ func TestStringMap(t *testing.T) {
t.Error(err) t.Error(err)
} }
testResult, err := entryResult.getStringMap() testResult, err := entryResult.GetStringMap()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@ -5,12 +5,11 @@ import (
"database/sql" "database/sql"
"encoding/gob" "encoding/gob"
"sync" "sync"
"time"
// sqlite requires a blank import. // sqlite requires a blank import.
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/db" "github.com/owncast/owncast/db"
"github.com/owncast/owncast/models"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -21,7 +20,8 @@ type Datastore struct {
DbLock *sync.Mutex DbLock *sync.Mutex
} }
func (ds *Datastore) warmCache() { // WarmCache pre-caches all configuration values in memory.
func (ds *Datastore) WarmCache() {
log.Traceln("Warming config value cache") log.Traceln("Warming config value cache")
res, err := ds.DB.Query("SELECT key, value FROM datastore") res, err := ds.DB.Query("SELECT key, value FROM datastore")
@ -46,10 +46,10 @@ func (ds *Datastore) GetQueries() *db.Queries {
} }
// Get will query the database for the key and return the entry. // Get will query the database for the key and return the entry.
func (ds *Datastore) Get(key string) (ConfigEntry, error) { func (ds *Datastore) Get(key string) (models.ConfigEntry, error) {
cachedValue, err := ds.GetCachedValue(key) cachedValue, err := ds.GetCachedValue(key)
if err == nil { if err == nil {
return ConfigEntry{ return models.ConfigEntry{
Key: key, Key: key,
Value: cachedValue, Value: cachedValue,
}, nil }, nil
@ -60,10 +60,10 @@ func (ds *Datastore) Get(key string) (ConfigEntry, error) {
row := ds.DB.QueryRow("SELECT key, value FROM datastore WHERE key = ? LIMIT 1", key) row := ds.DB.QueryRow("SELECT key, value FROM datastore WHERE key = ? LIMIT 1", key)
if err := row.Scan(&resultKey, &resultValue); err != nil { if err := row.Scan(&resultKey, &resultValue); err != nil {
return ConfigEntry{}, err return models.ConfigEntry{}, err
} }
result := ConfigEntry{ result := models.ConfigEntry{
Key: resultKey, Key: resultKey,
Value: resultValue, Value: resultValue,
} }
@ -73,7 +73,7 @@ func (ds *Datastore) Get(key string) (ConfigEntry, error) {
} }
// Save will save the ConfigEntry to the database. // Save will save the ConfigEntry to the database.
func (ds *Datastore) Save(e ConfigEntry) error { func (ds *Datastore) Save(e models.ConfigEntry) error {
ds.DbLock.Lock() ds.DbLock.Lock()
defer ds.DbLock.Unlock() defer ds.DbLock.Unlock()
@ -93,7 +93,6 @@ func (ds *Datastore) Save(e ConfigEntry) error {
return err return err
} }
_, err = stmt.Exec(e.Key, dataGob.Bytes()) _, err = stmt.Exec(e.Key, dataGob.Bytes())
if err != nil { if err != nil {
return err return err
} }
@ -121,26 +120,6 @@ func (ds *Datastore) Setup() {
);` );`
ds.MustExec(createTableSQL) ds.MustExec(createTableSQL)
if !HasPopulatedDefaults() {
PopulateDefaults()
}
if !hasPopulatedFederationDefaults() {
if err := SetFederationGoLiveMessage(config.GetDefaults().FederationGoLiveMessage); err != nil {
log.Errorln(err)
}
if err := _datastore.SetBool("HAS_POPULATED_FEDERATION_DEFAULTS", true); err != nil {
log.Errorln(err)
}
}
// Set the server initialization date if needed.
if hasSetInitDate, _ := GetServerInitTime(); hasSetInitDate == nil || !hasSetInitDate.Valid {
_ = SetServerInitTime(time.Now())
}
migrateDatastoreValues(_datastore)
} }
// Reset will delete all config entries in the datastore and start over. // Reset will delete all config entries in the datastore and start over.
@ -156,8 +135,6 @@ func (ds *Datastore) Reset() {
if _, err = stmt.Exec(); err != nil { if _, err = stmt.Exec(); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }
PopulateDefaults()
} }
// GetDatastore returns the shared instance of the owncast datastore. // GetDatastore returns the shared instance of the owncast datastore.

View File

@ -1,54 +0,0 @@
package data
import (
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/models"
)
// HasPopulatedDefaults will determine if the defaults have been inserted into the database.
func HasPopulatedDefaults() bool {
hasPopulated, err := _datastore.GetBool("HAS_POPULATED_DEFAULTS")
if err != nil {
return false
}
return hasPopulated
}
func hasPopulatedFederationDefaults() bool {
hasPopulated, err := _datastore.GetBool("HAS_POPULATED_FEDERATION_DEFAULTS")
if err != nil {
return false
}
return hasPopulated
}
// PopulateDefaults will set default values in the database.
func PopulateDefaults() {
_datastore.warmCache()
defaults := config.GetDefaults()
if HasPopulatedDefaults() {
return
}
_ = SetAdminPassword(defaults.AdminPassword)
_ = SetStreamKeys(defaults.StreamKeys)
_ = SetHTTPPortNumber(float64(defaults.WebServerPort))
_ = SetRTMPPortNumber(float64(defaults.RTMPServerPort))
_ = SetLogoPath(defaults.Logo)
_ = SetServerMetadataTags([]string{"owncast", "streaming"})
_ = SetServerSummary(defaults.Summary)
_ = SetServerWelcomeMessage("")
_ = SetServerName(defaults.Name)
_ = SetExtraPageBodyContent(defaults.PageBodyContent)
_ = SetFederationGoLiveMessage(defaults.FederationGoLiveMessage)
_ = SetSocialHandles([]models.SocialHandle{
{
Platform: "github",
URL: "https://github.com/owncast/owncast",
},
})
_ = _datastore.SetBool("HAS_POPULATED_DEFAULTS", true)
}

View File

@ -1,14 +1,5 @@
package data package data
import (
"context"
"database/sql"
"github.com/owncast/owncast/db"
"github.com/owncast/owncast/models"
log "github.com/sirupsen/logrus"
)
// GetMessagesCount will return the number of messages in the database. // GetMessagesCount will return the number of messages in the database.
func GetMessagesCount() int64 { func GetMessagesCount() int64 {
query := `SELECT COUNT(*) FROM messages` query := `SELECT COUNT(*) FROM messages`
@ -25,58 +16,3 @@ func GetMessagesCount() int64 {
} }
return count return count
} }
// CreateBanIPTable will create the IP ban table if needed.
func CreateBanIPTable(db *sql.DB) {
createTableSQL := ` CREATE TABLE IF NOT EXISTS ip_bans (
"ip_address" TEXT NOT NULL PRIMARY KEY,
"notes" TEXT,
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`
stmt, err := db.Prepare(createTableSQL)
if err != nil {
log.Fatal("error creating ip ban table", err)
}
defer stmt.Close()
if _, err := stmt.Exec(); err != nil {
log.Fatal("error creating ip ban table", err)
}
}
// BanIPAddress will persist a new IP address ban to the datastore.
func BanIPAddress(address, note string) error {
return _datastore.GetQueries().BanIPAddress(context.Background(), db.BanIPAddressParams{
IpAddress: address,
Notes: sql.NullString{String: note, Valid: true},
})
}
// IsIPAddressBanned will return if an IP address has been previously blocked.
func IsIPAddressBanned(address string) (bool, error) {
blocked, error := _datastore.GetQueries().IsIPAddressBlocked(context.Background(), address)
return blocked > 0, error
}
// GetIPAddressBans will return all the banned IP addresses.
func GetIPAddressBans() ([]models.IPAddress, error) {
result, err := _datastore.GetQueries().GetIPAddressBans(context.Background())
if err != nil {
return nil, err
}
response := []models.IPAddress{}
for _, ip := range result {
response = append(response, models.IPAddress{
IPAddress: ip.IpAddress,
Notes: ip.Notes.String,
CreatedAt: ip.CreatedAt.Time,
})
}
return response, err
}
// RemoveIPAddressBan will remove a previously banned IP address.
func RemoveIPAddressBan(address string) error {
return _datastore.GetQueries().RemoveIPAddressBan(context.Background(), address)
}

View File

@ -1,17 +1,19 @@
package data package data
import "github.com/owncast/owncast/models"
// GetStringSlice will return the string slice value for a key. // GetStringSlice will return the string slice value for a key.
func (ds *Datastore) GetStringSlice(key string) ([]string, error) { func (ds *Datastore) GetStringSlice(key string) ([]string, error) {
configEntry, err := ds.Get(key) configEntry, err := ds.Get(key)
if err != nil { if err != nil {
return []string{}, err return []string{}, err
} }
return configEntry.getStringSlice() return configEntry.GetStringSlice()
} }
// SetStringSlice will set the string slice value for a key. // SetStringSlice will set the string slice value for a key.
func (ds *Datastore) SetStringSlice(key string, value []string) error { func (ds *Datastore) SetStringSlice(key string, value []string) error {
configEntry := ConfigEntry{value, key} configEntry := models.ConfigEntry{Value: value, Key: key}
return ds.Save(configEntry) return ds.Save(configEntry)
} }
@ -21,12 +23,12 @@ func (ds *Datastore) GetString(key string) (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return configEntry.getString() return configEntry.GetString()
} }
// SetString will set the string value for a key. // SetString will set the string value for a key.
func (ds *Datastore) SetString(key string, value string) error { func (ds *Datastore) SetString(key string, value string) error {
configEntry := ConfigEntry{value, key} configEntry := models.ConfigEntry{Value: value, Key: key}
return ds.Save(configEntry) return ds.Save(configEntry)
} }
@ -36,12 +38,12 @@ func (ds *Datastore) GetNumber(key string) (float64, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
return configEntry.getNumber() return configEntry.GetNumber()
} }
// SetNumber will set the numeric value for a key. // SetNumber will set the numeric value for a key.
func (ds *Datastore) SetNumber(key string, value float64) error { func (ds *Datastore) SetNumber(key string, value float64) error {
configEntry := ConfigEntry{value, key} configEntry := models.ConfigEntry{Value: value, Key: key}
return ds.Save(configEntry) return ds.Save(configEntry)
} }
@ -51,12 +53,12 @@ func (ds *Datastore) GetBool(key string) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
return configEntry.getBool() return configEntry.GetBool()
} }
// SetBool will set the boolean value for a key. // SetBool will set the boolean value for a key.
func (ds *Datastore) SetBool(key string, value bool) error { func (ds *Datastore) SetBool(key string, value bool) error {
configEntry := ConfigEntry{value, key} configEntry := models.ConfigEntry{Value: value, Key: key}
return ds.Save(configEntry) return ds.Save(configEntry)
} }
@ -66,11 +68,11 @@ func (ds *Datastore) GetStringMap(key string) (map[string]string, error) {
if err != nil { if err != nil {
return map[string]string{}, err return map[string]string{}, err
} }
return configEntry.getStringMap() return configEntry.GetStringMap()
} }
// SetStringMap will set the string map value for a key. // SetStringMap will set the string map value for a key.
func (ds *Datastore) SetStringMap(key string, value map[string]string) error { func (ds *Datastore) SetStringMap(key string, value map[string]string) error {
configEntry := ConfigEntry{value, key} configEntry := models.ConfigEntry{Value: value, Key: key}
return ds.Save(configEntry) return ds.Save(configEntry)
} }

View File

@ -12,8 +12,8 @@ import (
"github.com/nareix/joy5/format/rtmp" "github.com/nareix/joy5/format/rtmp"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
) )
var _hasInboundRTMPConnection = false var _hasInboundRTMPConnection = false
@ -33,7 +33,9 @@ func Start(setStreamAsConnected func(*io.PipeReader), setBroadcaster func(models
_setStreamAsConnected = setStreamAsConnected _setStreamAsConnected = setStreamAsConnected
_setBroadcaster = setBroadcaster _setBroadcaster = setBroadcaster
port := data.GetRTMPPortNumber() configRepository := configrepository.Get()
port := configRepository.GetRTMPPortNumber()
s := rtmp.NewServer() s := rtmp.NewServer()
var lis net.Listener var lis net.Listener
var err error var err error
@ -78,8 +80,10 @@ func HandleConn(c *rtmp.Conn, nc net.Conn) {
return return
} }
configRepository := configrepository.Get()
accessGranted := false accessGranted := false
validStreamingKeys := data.GetStreamKeys() validStreamingKeys := configRepository.GetStreamKeys()
// If a stream key override was specified then use that instead. // If a stream key override was specified then use that instead.
if config.TemporaryStreamKey != "" { if config.TemporaryStreamKey != "" {

View File

@ -7,8 +7,8 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/services/geoip" "github.com/owncast/owncast/services/geoip"
) )
@ -48,7 +48,8 @@ func IsStreamConnected() bool {
// Kind of a hack. It takes a handful of seconds between a RTMP connection and when HLS data is available. // Kind of a hack. It takes a handful of seconds between a RTMP connection and when HLS data is available.
// So account for that with an artificial buffer of four segments. // So account for that with an artificial buffer of four segments.
timeSinceLastConnected := time.Since(_stats.LastConnectTime.Time).Seconds() timeSinceLastConnected := time.Since(_stats.LastConnectTime.Time).Seconds()
waitTime := math.Max(float64(data.GetStreamLatencyLevel().SecondsPerSegment)*3.0, 7) configRepository := configrepository.Get()
waitTime := math.Max(float64(configRepository.GetStreamLatencyLevel().SecondsPerSegment)*3.0, 7)
if timeSinceLastConnected < waitTime { if timeSinceLastConnected < waitTime {
return false return false
} }
@ -75,7 +76,7 @@ func SetViewerActive(viewer *models.Viewer) {
l.Lock() l.Lock()
defer l.Unlock() defer l.Unlock()
// Asynchronously, optionally, fetch GeoIP data. // Asynchronously, optionally, fetch GeoIP configRepository.
go func(viewer *models.Viewer) { go func(viewer *models.Viewer) {
viewer.Geo = _geoIPClient.GetGeoFromIP(viewer.IPAddress) viewer.Geo = _geoIPClient.GetGeoFromIP(viewer.IPAddress)
}(viewer) }(viewer)
@ -111,27 +112,29 @@ func pruneViewerCount() {
} }
func saveStats() { func saveStats() {
if err := data.SetPeakOverallViewerCount(_stats.OverallMaxViewerCount); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetPeakOverallViewerCount(_stats.OverallMaxViewerCount); err != nil {
log.Errorln("error saving viewer count", err) log.Errorln("error saving viewer count", err)
} }
if err := data.SetPeakSessionViewerCount(_stats.SessionMaxViewerCount); err != nil { if err := configRepository.SetPeakSessionViewerCount(_stats.SessionMaxViewerCount); err != nil {
log.Errorln("error saving viewer count", err) log.Errorln("error saving viewer count", err)
} }
if _stats.LastDisconnectTime != nil && _stats.LastDisconnectTime.Valid { if _stats.LastDisconnectTime != nil && _stats.LastDisconnectTime.Valid {
if err := data.SetLastDisconnectTime(_stats.LastDisconnectTime.Time); err != nil { if err := configRepository.SetLastDisconnectTime(_stats.LastDisconnectTime.Time); err != nil {
log.Errorln("error saving disconnect time", err) log.Errorln("error saving disconnect time", err)
} }
} }
} }
func getSavedStats() models.Stats { func getSavedStats() models.Stats {
savedLastDisconnectTime, _ := data.GetLastDisconnectTime() configRepository := configrepository.Get()
savedLastDisconnectTime, _ := configRepository.GetLastDisconnectTime()
result := models.Stats{ result := models.Stats{
ChatClients: make(map[string]models.Client), ChatClients: make(map[string]models.Client),
Viewers: make(map[string]*models.Viewer), Viewers: make(map[string]*models.Viewer),
SessionMaxViewerCount: data.GetPeakSessionViewerCount(), SessionMaxViewerCount: configRepository.GetPeakSessionViewerCount(),
OverallMaxViewerCount: data.GetPeakOverallViewerCount(), OverallMaxViewerCount: configRepository.GetPeakOverallViewerCount(),
LastDisconnectTime: savedLastDisconnectTime, LastDisconnectTime: savedLastDisconnectTime,
} }

View File

@ -2,8 +2,8 @@ package core
import ( import (
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
) )
// GetStatus gets the status of the system. // GetStatus gets the status of the system.
@ -17,6 +17,7 @@ func GetStatus() models.Status {
viewerCount = len(_stats.Viewers) viewerCount = len(_stats.Viewers)
} }
configRepository := configrepository.Get()
return models.Status{ return models.Status{
Online: IsStreamConnected(), Online: IsStreamConnected(),
ViewerCount: viewerCount, ViewerCount: viewerCount,
@ -25,7 +26,7 @@ func GetStatus() models.Status {
LastDisconnectTime: _stats.LastDisconnectTime, LastDisconnectTime: _stats.LastDisconnectTime,
LastConnectTime: _stats.LastConnectTime, LastConnectTime: _stats.LastConnectTime,
VersionNumber: config.VersionNumber, VersionNumber: config.VersionNumber,
StreamTitle: data.GetStreamTitle(), StreamTitle: configRepository.GetStreamTitle(),
} }
} }

View File

@ -1,12 +1,13 @@
package core package core
import ( import (
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/storageproviders" "github.com/owncast/owncast/core/storageproviders"
"github.com/owncast/owncast/persistence/configrepository"
) )
func setupStorage() error { func setupStorage() error {
s3Config := data.GetS3Config() configRepository := configrepository.Get()
s3Config := configRepository.GetS3Config()
if s3Config.Enabled { if s3Config.Enabled {
_storage = storageproviders.NewS3Storage() _storage = storageproviders.NewS3Storage()

View File

@ -5,9 +5,8 @@ import (
"path/filepath" "path/filepath"
"sort" "sort"
"github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/owncast/owncast/core/data"
) )
// LocalStorage represents an instance of the local storage provider for HLS video. // LocalStorage represents an instance of the local storage provider for HLS video.
@ -22,7 +21,8 @@ func NewLocalStorage() *LocalStorage {
// Setup configures this storage provider. // Setup configures this storage provider.
func (s *LocalStorage) Setup() error { func (s *LocalStorage) Setup() error {
s.host = data.GetVideoServingEndpoint() configRepository := configrepository.Get()
s.host = configRepository.GetVideoServingEndpoint()
return nil return nil
} }
@ -63,7 +63,8 @@ func (s *LocalStorage) Save(filePath string, retryCount int) (string, error) {
// Cleanup will remove old files from the storage provider. // Cleanup will remove old files from the storage provider.
func (s *LocalStorage) Cleanup() error { func (s *LocalStorage) Cleanup() error {
// Determine how many files we should keep on disk // Determine how many files we should keep on disk
maxNumber := data.GetStreamLatencyLevel().SegmentCount configRepository := configrepository.Get()
maxNumber := configRepository.GetStreamLatencyLevel().SegmentCount
buffer := 10 buffer := 10
return localCleanup(maxNumber + buffer) return localCleanup(maxNumber + buffer)
} }

View File

@ -11,7 +11,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -64,9 +64,9 @@ func NewS3Storage() *S3Storage {
// Setup sets up the s3 storage for saving the video to s3. // Setup sets up the s3 storage for saving the video to s3.
func (s *S3Storage) Setup() error { func (s *S3Storage) Setup() error {
log.Trace("Setting up S3 for external storage of video...") log.Trace("Setting up S3 for external storage of video...")
configRepository := configrepository.Get()
s3Config := data.GetS3Config() s3Config := configRepository.GetS3Config()
customVideoServingEndpoint := data.GetVideoServingEndpoint() customVideoServingEndpoint := configRepository.GetVideoServingEndpoint()
if customVideoServingEndpoint != "" { if customVideoServingEndpoint != "" {
s.host = customVideoServingEndpoint s.host = customVideoServingEndpoint
@ -106,8 +106,9 @@ func (s *S3Storage) SegmentWritten(localFilePath string) {
averagePerformance := utils.GetAveragePerformance(performanceMonitorKey) averagePerformance := utils.GetAveragePerformance(performanceMonitorKey)
// Warn the user about long-running save operations // Warn the user about long-running save operations
configRepository := configrepository.Get()
if averagePerformance != 0 { if averagePerformance != 0 {
if averagePerformance > float64(data.GetStreamLatencyLevel().SecondsPerSegment)*0.9 { if averagePerformance > float64(configRepository.GetStreamLatencyLevel().SecondsPerSegment)*0.9 {
log.Warnln("Possible slow uploads: average upload S3 save duration", averagePerformance, "s. troubleshoot this issue by visiting https://owncast.online/docs/troubleshooting/") log.Warnln("Possible slow uploads: average upload S3 save duration", averagePerformance, "s. troubleshoot this issue by visiting https://owncast.online/docs/troubleshooting/")
} }
} }
@ -220,7 +221,8 @@ func (s *S3Storage) Cleanup() error {
// RemoteCleanup will remove old files from the remote storage provider. // RemoteCleanup will remove old files from the remote storage provider.
func (s *S3Storage) RemoteCleanup() error { func (s *S3Storage) RemoteCleanup() error {
// Determine how many files we should keep on S3 storage // Determine how many files we should keep on S3 storage
maxNumber := data.GetStreamLatencyLevel().SegmentCount configRepository := configrepository.Get()
maxNumber := configRepository.GetStreamLatencyLevel().SegmentCount
buffer := 20 buffer := 20
keys, err := s.getDeletableVideoSegmentsWithOffset(maxNumber + buffer) keys, err := s.getDeletableVideoSegmentsWithOffset(maxNumber + buffer)

View File

@ -16,6 +16,7 @@ import (
"github.com/owncast/owncast/core/webhooks" "github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/notifications" "github.com/owncast/owncast/notifications"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
) )
@ -39,9 +40,11 @@ func setStreamAsConnected(rtmpOut *io.PipeReader) {
_stats.LastConnectTime = &now _stats.LastConnectTime = &now
_stats.SessionMaxViewerCount = 0 _stats.SessionMaxViewerCount = 0
configRepository := configrepository.Get()
_currentBroadcast = &models.CurrentBroadcast{ _currentBroadcast = &models.CurrentBroadcast{
LatencyLevel: data.GetStreamLatencyLevel(), LatencyLevel: configRepository.GetStreamLatencyLevel(),
OutputSettings: data.GetStreamOutputVariants(), OutputSettings: configRepository.GetStreamOutputVariants(),
} }
StopOfflineCleanupTimer() StopOfflineCleanupTimer()
@ -69,7 +72,7 @@ func setStreamAsConnected(rtmpOut *io.PipeReader) {
}() }()
go webhooks.SendStreamStatusEvent(models.StreamStarted) go webhooks.SendStreamStatusEvent(models.StreamStarted)
selectedThumbnailVideoQualityIndex, isVideoPassthrough := data.FindHighestVideoQualityIndex(_currentBroadcast.OutputSettings) selectedThumbnailVideoQualityIndex, isVideoPassthrough := configRepository.FindHighestVideoQualityIndex(_currentBroadcast.OutputSettings)
transcoder.StartThumbnailGenerator(segmentPath, selectedThumbnailVideoQualityIndex, isVideoPassthrough) transcoder.StartThumbnailGenerator(segmentPath, selectedThumbnailVideoQualityIndex, isVideoPassthrough)
_ = chat.SendSystemAction("Stay tuned, the stream is **starting**!", true) _ = chat.SendSystemAction("Stay tuned, the stream is **starting**!", true)
@ -176,8 +179,9 @@ func startLiveStreamNotificationsTimer() context.CancelFunc {
return return
} }
configRepository := configrepository.Get()
// Send Fediverse message. // Send Fediverse message.
if data.GetFederationEnabled() { if configRepository.GetFederationEnabled() {
log.Traceln("Sending Federated Go Live message.") log.Traceln("Sending Federated Go Live message.")
if err := activitypub.SendLive(); err != nil { if err := activitypub.SendLive(); err != nil {
log.Errorln(err) log.Errorln(err)

View File

@ -11,7 +11,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
) )
@ -88,9 +88,9 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
if len(names) == 0 { if len(names) == 0 {
return nil return nil
} }
configRepository := configrepository.Get()
mostRecentFile := path.Join(framePath, names[0]) mostRecentFile := path.Join(framePath, names[0])
ffmpegPath := utils.ValidatedFfmpegPath(data.GetFfMpegPath()) ffmpegPath := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
outputFileTemp := path.Join(config.TempDir, "tempthumbnail.jpg") outputFileTemp := path.Join(config.TempDir, "tempthumbnail.jpg")
thumbnailCmdFlags := []string{ thumbnailCmdFlags := []string{
@ -120,7 +120,8 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
} }
func makeAnimatedGifPreview(sourceFile string, outputFile string) { func makeAnimatedGifPreview(sourceFile string, outputFile string) {
ffmpegPath := utils.ValidatedFfmpegPath(data.GetFfMpegPath()) configRepository := configrepository.Get()
ffmpegPath := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
outputFileTemp := path.Join(config.TempDir, "temppreview.gif") outputFileTemp := path.Join(config.TempDir, "temppreview.gif")
// Filter is pulled from https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/ // Filter is pulled from https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/

View File

@ -12,9 +12,9 @@ import (
"github.com/teris-io/shortid" "github.com/teris-io/shortid"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/logging" "github.com/owncast/owncast/logging"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
) )
@ -275,15 +275,16 @@ func getVariantFromConfigQuality(quality models.StreamOutputVariant, index int)
// NewTranscoder will return a new Transcoder, populated by the config. // NewTranscoder will return a new Transcoder, populated by the config.
func NewTranscoder() *Transcoder { func NewTranscoder() *Transcoder {
ffmpegPath := utils.ValidatedFfmpegPath(data.GetFfMpegPath()) configRepository := configrepository.Get()
ffmpegPath := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
transcoder := new(Transcoder) transcoder := new(Transcoder)
transcoder.ffmpegPath = ffmpegPath transcoder.ffmpegPath = ffmpegPath
transcoder.internalListenerPort = config.InternalHLSListenerPort transcoder.internalListenerPort = config.InternalHLSListenerPort
transcoder.currentStreamOutputSettings = data.GetStreamOutputVariants() transcoder.currentStreamOutputSettings = configRepository.GetStreamOutputVariants()
transcoder.currentLatencyLevel = data.GetStreamLatencyLevel() transcoder.currentLatencyLevel = configRepository.GetStreamLatencyLevel()
transcoder.codec = getCodec(data.GetVideoCodec()) transcoder.codec = getCodec(configRepository.GetVideoCodec())
transcoder.segmentOutputPath = config.HLSStoragePath transcoder.segmentOutputPath = config.HLSStoragePath
transcoder.playlistOutputPath = config.HLSStoragePath transcoder.playlistOutputPath = config.HLSStoragePath

View File

@ -8,7 +8,7 @@ import (
"sync" "sync"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -99,9 +99,9 @@ func handleTranscoderMessage(message string) {
func createVariantDirectories() { func createVariantDirectories() {
// Create private hls data dirs // Create private hls data dirs
utils.CleanupDirectory(config.HLSStoragePath) utils.CleanupDirectory(config.HLSStoragePath)
configRepository := configrepository.Get()
if len(data.GetStreamOutputVariants()) != 0 { if len(configRepository.GetStreamOutputVariants()) != 0 {
for index := range data.GetStreamOutputVariants() { for index := range configRepository.GetStreamOutputVariants() {
if err := os.MkdirAll(path.Join(config.HLSStoragePath, strconv.Itoa(index)), 0o750); err != nil { if err := os.MkdirAll(path.Join(config.HLSStoragePath, strconv.Itoa(index)), 0o750); err != nil {
log.Fatalln(err) log.Fatalln(err)
} }

View File

@ -3,8 +3,8 @@ package webhooks
import ( import (
"time" "time"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/teris-io/shortid" "github.com/teris-io/shortid"
) )
@ -14,13 +14,15 @@ func SendStreamStatusEvent(eventType models.EventType) {
} }
func sendStreamStatusEvent(eventType models.EventType, id string, timestamp time.Time) { func sendStreamStatusEvent(eventType models.EventType, id string, timestamp time.Time) {
configRepository := configrepository.Get()
SendEventToWebhooks(WebhookEvent{ SendEventToWebhooks(WebhookEvent{
Type: eventType, Type: eventType,
EventData: map[string]interface{}{ EventData: map[string]interface{}{
"id": id, "id": id,
"name": data.GetServerName(), "name": configRepository.GetServerName(),
"summary": data.GetServerSummary(), "summary": configRepository.GetServerSummary(),
"streamTitle": data.GetStreamTitle(), "streamTitle": configRepository.GetStreamTitle(),
"status": getStatus(), "status": getStatus(),
"timestamp": timestamp, "timestamp": timestamp,
}, },

View File

@ -5,14 +5,16 @@ import (
"time" "time"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
) )
func TestSendStreamStatusEvent(t *testing.T) { func TestSendStreamStatusEvent(t *testing.T) {
data.SetServerName("my server") configRepository := configrepository.Get()
data.SetServerSummary("my server where I stream")
data.SetStreamTitle("my stream") configRepository.SetServerName("my server")
configRepository.SetServerSummary("my server where I stream")
configRepository.SetStreamTitle("my stream")
checkPayload(t, models.StreamStarted, func() { checkPayload(t, models.StreamStarted, func() {
sendStreamStatusEvent(events.StreamStarted, "id", time.Unix(72, 6).UTC()) sendStreamStatusEvent(events.StreamStarted, "id", time.Unix(72, 6).UTC())

15
main.go
View File

@ -6,6 +6,7 @@ import (
"strconv" "strconv"
"github.com/owncast/owncast/logging" "github.com/owncast/owncast/logging"
"github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
@ -111,8 +112,10 @@ func main() {
} }
func handleCommandLineFlags() { func handleCommandLineFlags() {
configRepository := configrepository.Get()
if *newAdminPassword != "" { if *newAdminPassword != "" {
if err := data.SetAdminPassword(*newAdminPassword); err != nil { if err := configRepository.SetAdminPassword(*newAdminPassword); err != nil {
log.Errorln("Error setting your admin password.", err) log.Errorln("Error setting your admin password.", err)
log.Exit(1) log.Exit(1)
} else { } else {
@ -134,25 +137,25 @@ func handleCommandLineFlags() {
} }
log.Println("Saving new web server port number to", portNumber) log.Println("Saving new web server port number to", portNumber)
if err := data.SetHTTPPortNumber(float64(portNumber)); err != nil { if err := configRepository.SetHTTPPortNumber(float64(portNumber)); err != nil {
log.Errorln(err) log.Errorln(err)
} }
} }
config.WebServerPort = data.GetHTTPPortNumber() config.WebServerPort = configRepository.GetHTTPPortNumber()
// Set the web server ip // Set the web server ip
if *webServerIPOverride != "" { if *webServerIPOverride != "" {
log.Println("Saving new web server listen IP address to", *webServerIPOverride) log.Println("Saving new web server listen IP address to", *webServerIPOverride)
if err := data.SetHTTPListenAddress(*webServerIPOverride); err != nil { if err := configRepository.SetHTTPListenAddress(*webServerIPOverride); err != nil {
log.Errorln(err) log.Errorln(err)
} }
} }
config.WebServerIP = data.GetHTTPListenAddress() config.WebServerIP = configRepository.GetHTTPListenAddress()
// Set the rtmp server port // Set the rtmp server port
if *rtmpPortOverride > 0 { if *rtmpPortOverride > 0 {
log.Println("Saving new RTMP server port number to", *rtmpPortOverride) log.Println("Saving new RTMP server port number to", *rtmpPortOverride)
if err := data.SetRTMPPortNumber(float64(*rtmpPortOverride)); err != nil { if err := configRepository.SetRTMPPortNumber(float64(*rtmpPortOverride)); err != nil {
log.Errorln(err) log.Errorln(err)
} }
} }

View File

@ -5,8 +5,8 @@ import (
"sort" "sort"
"github.com/owncast/owncast/core" "github.com/owncast/owncast/core"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
) )
@ -68,8 +68,8 @@ func networkSpeedHealthOverviewMessage() string {
isVideoPassthrough bool isVideoPassthrough bool
bitrate int bitrate int
} }
configRepository := configrepository.Get()
outputVariants := data.GetStreamOutputVariants() outputVariants := configRepository.GetStreamOutputVariants()
streamSortVariants := make([]singleVariant, len(outputVariants)) streamSortVariants := make([]singleVariant, len(outputVariants))
for i, variant := range outputVariants { for i, variant := range outputVariants {
@ -155,7 +155,8 @@ func wastefulBitrateOverviewMessage() string {
return "" return ""
} }
outputVariants := data.GetStreamOutputVariants() configRepository := configrepository.Get()
outputVariants := configRepository.GetStreamOutputVariants()
type singleVariant struct { type singleVariant struct {
isVideoPassthrough bool isVideoPassthrough bool
@ -229,7 +230,8 @@ func errorCountHealthOverviewMessage() string {
healthyPercentage := utils.IntPercentage(clientsWithErrors, totalNumberOfClients) healthyPercentage := utils.IntPercentage(clientsWithErrors, totalNumberOfClients)
isUsingPassthrough := false isUsingPassthrough := false
outputVariants := data.GetStreamOutputVariants() configRepository := configrepository.Get()
outputVariants := configRepository.GetStreamOutputVariants()
for _, variant := range outputVariants { for _, variant := range outputVariants {
if variant.IsVideoPassthrough { if variant.IsVideoPassthrough {
isUsingPassthrough = true isUsingPassthrough = true

View File

@ -5,8 +5,8 @@ import (
"time" "time"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
) )
// How often we poll for updates. // How often we poll for updates.
@ -56,8 +56,9 @@ var _getStatus func() models.Status
// Start will begin the metrics collection and alerting. // Start will begin the metrics collection and alerting.
func Start(getStatus func() models.Status) { func Start(getStatus func() models.Status) {
configRepository := configrepository.Get()
_getStatus = getStatus _getStatus = getStatus
host := data.GetServerURL() host := configRepository.GetServerURL()
if host == "" { if host == "" {
host = "unknown" host = "unknown"
} }

View File

@ -1,4 +1,4 @@
package data package models
import ( import (
"bytes" "bytes"
@ -12,48 +12,48 @@ type ConfigEntry struct {
Key string Key string
} }
func (c *ConfigEntry) getStringSlice() ([]string, error) { func (c *ConfigEntry) GetStringSlice() ([]string, error) {
decoder := c.getDecoder() decoder := c.GetDecoder()
var result []string var result []string
err := decoder.Decode(&result) err := decoder.Decode(&result)
return result, err return result, err
} }
func (c *ConfigEntry) getStringMap() (map[string]string, error) { func (c *ConfigEntry) GetStringMap() (map[string]string, error) {
decoder := c.getDecoder() decoder := c.GetDecoder()
var result map[string]string var result map[string]string
err := decoder.Decode(&result) err := decoder.Decode(&result)
return result, err return result, err
} }
func (c *ConfigEntry) getString() (string, error) { func (c *ConfigEntry) GetString() (string, error) {
decoder := c.getDecoder() decoder := c.GetDecoder()
var result string var result string
err := decoder.Decode(&result) err := decoder.Decode(&result)
return result, err return result, err
} }
func (c *ConfigEntry) getNumber() (float64, error) { func (c *ConfigEntry) GetNumber() (float64, error) {
decoder := c.getDecoder() decoder := c.GetDecoder()
var result float64 var result float64
err := decoder.Decode(&result) err := decoder.Decode(&result)
return result, err return result, err
} }
func (c *ConfigEntry) getBool() (bool, error) { func (c *ConfigEntry) GetBool() (bool, error) {
decoder := c.getDecoder() decoder := c.GetDecoder()
var result bool var result bool
err := decoder.Decode(&result) err := decoder.Decode(&result)
return result, err return result, err
} }
func (c *ConfigEntry) getObject(result interface{}) error { func (c *ConfigEntry) GetObject(result interface{}) error {
decoder := c.getDecoder() decoder := c.GetDecoder()
err := decoder.Decode(result) err := decoder.Decode(result)
return err return err
} }
func (c *ConfigEntry) getDecoder() *gob.Decoder { func (c *ConfigEntry) GetDecoder() *gob.Decoder {
valueBytes := c.Value.([]byte) valueBytes := c.Value.([]byte)
decoder := gob.NewDecoder(bytes.NewBuffer(valueBytes)) decoder := gob.NewDecoder(bytes.NewBuffer(valueBytes))
return decoder return decoder

View File

@ -8,6 +8,7 @@ import (
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/db" "github.com/owncast/owncast/db"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/tables" "github.com/owncast/owncast/persistence/tables"
"github.com/owncast/owncast/notifications/browser" "github.com/owncast/owncast/notifications/browser"
@ -18,9 +19,10 @@ import (
// Notifier is an instance of the live stream notifier. // Notifier is an instance of the live stream notifier.
type Notifier struct { type Notifier struct {
datastore *data.Datastore datastore *data.Datastore
browser *browser.Browser browser *browser.Browser
discord *discord.Discord discord *discord.Discord
configRepository configrepository.ConfigRepository
} }
// Setup will perform any pre-use setup for the notifier. // Setup will perform any pre-use setup for the notifier.
@ -30,8 +32,10 @@ func Setup(datastore *data.Datastore) {
} }
func initializeBrowserPushIfNeeded() { func initializeBrowserPushIfNeeded() {
pubKey, _ := data.GetBrowserPushPublicKey() configRepository := configrepository.Get()
privKey, _ := data.GetBrowserPushPrivateKey()
pubKey, _ := configRepository.GetBrowserPushPublicKey()
privKey, _ := configRepository.GetBrowserPushPrivateKey()
// We need browser push keys so people can register for pushes. // We need browser push keys so people can register for pushes.
if pubKey == "" || privKey == "" { if pubKey == "" || privKey == "" {
@ -40,26 +44,27 @@ func initializeBrowserPushIfNeeded() {
log.Errorln("unable to initialize browser push notification keys", err) log.Errorln("unable to initialize browser push notification keys", err)
} }
if err := data.SetBrowserPushPrivateKey(browserPrivateKey); err != nil { if err := configRepository.SetBrowserPushPrivateKey(browserPrivateKey); err != nil {
log.Errorln("unable to set browser push private key", err) log.Errorln("unable to set browser push private key", err)
} }
if err := data.SetBrowserPushPublicKey(browserPublicKey); err != nil { if err := configRepository.SetBrowserPushPublicKey(browserPublicKey); err != nil {
log.Errorln("unable to set browser push public key", err) log.Errorln("unable to set browser push public key", err)
} }
} }
// Enable browser push notifications by default. // Enable browser push notifications by default.
if !data.GetHasPerformedInitialNotificationsConfig() { if !configRepository.GetHasPerformedInitialNotificationsConfig() {
_ = data.SetBrowserPushConfig(models.BrowserNotificationConfiguration{Enabled: true, GoLiveMessage: config.GetDefaults().FederationGoLiveMessage}) _ = configRepository.SetBrowserPushConfig(models.BrowserNotificationConfiguration{Enabled: true, GoLiveMessage: config.GetDefaults().FederationGoLiveMessage})
_ = data.SetHasPerformedInitialNotificationsConfig(true) _ = configRepository.SetHasPerformedInitialNotificationsConfig(true)
} }
} }
// New creates a new instance of the Notifier. // New creates a new instance of the Notifier.
func New(datastore *data.Datastore) (*Notifier, error) { func New(datastore *data.Datastore) (*Notifier, error) {
notifier := Notifier{ notifier := Notifier{
datastore: datastore, datastore: datastore,
configRepository: configrepository.Get(),
} }
if err := notifier.setupBrowserPush(); err != nil { if err := notifier.setupBrowserPush(); err != nil {
@ -73,13 +78,13 @@ func New(datastore *data.Datastore) (*Notifier, error) {
} }
func (n *Notifier) setupBrowserPush() error { func (n *Notifier) setupBrowserPush() error {
if data.GetBrowserPushConfig().Enabled { if n.configRepository.GetBrowserPushConfig().Enabled {
publicKey, err := data.GetBrowserPushPublicKey() publicKey, err := n.configRepository.GetBrowserPushPublicKey()
if err != nil || publicKey == "" { if err != nil || publicKey == "" {
return errors.Wrap(err, "browser notifier disabled, failed to get browser push public key") return errors.Wrap(err, "browser notifier disabled, failed to get browser push public key")
} }
privateKey, err := data.GetBrowserPushPrivateKey() privateKey, err := n.configRepository.GetBrowserPushPrivateKey()
if err != nil || privateKey == "" { if err != nil || privateKey == "" {
return errors.Wrap(err, "browser notifier disabled, failed to get browser push private key") return errors.Wrap(err, "browser notifier disabled, failed to get browser push private key")
} }
@ -99,7 +104,7 @@ func (n *Notifier) notifyBrowserPush() {
log.Errorln("error getting browser push notification destinations", err) log.Errorln("error getting browser push notification destinations", err)
} }
for _, destination := range destinations { for _, destination := range destinations {
unsubscribed, err := n.browser.Send(destination, data.GetServerName(), data.GetBrowserPushConfig().GoLiveMessage) unsubscribed, err := n.browser.Send(destination, n.configRepository.GetServerName(), n.configRepository.GetBrowserPushConfig().GoLiveMessage)
if unsubscribed { if unsubscribed {
// If the error is "unsubscribed", then remove the destination from the database. // If the error is "unsubscribed", then remove the destination from the database.
if err := RemoveNotificationForChannel(BrowserPushNotification, destination); err != nil { if err := RemoveNotificationForChannel(BrowserPushNotification, destination); err != nil {
@ -112,14 +117,14 @@ func (n *Notifier) notifyBrowserPush() {
} }
func (n *Notifier) setupDiscord() error { func (n *Notifier) setupDiscord() error {
discordConfig := data.GetDiscordConfig() discordConfig := n.configRepository.GetDiscordConfig()
if discordConfig.Enabled && discordConfig.Webhook != "" { if discordConfig.Enabled && discordConfig.Webhook != "" {
var image string var image string
if serverURL := data.GetServerURL(); serverURL != "" { if serverURL := n.configRepository.GetServerURL(); serverURL != "" {
image = serverURL + "/logo" image = serverURL + "/logo"
} }
discordNotifier, err := discord.New( discordNotifier, err := discord.New(
data.GetServerName(), n.configRepository.GetServerName(),
image, image,
discordConfig.Webhook, discordConfig.Webhook,
) )
@ -132,12 +137,12 @@ func (n *Notifier) setupDiscord() error {
} }
func (n *Notifier) notifyDiscord() { func (n *Notifier) notifyDiscord() {
goLiveMessage := data.GetDiscordConfig().GoLiveMessage goLiveMessage := n.configRepository.GetDiscordConfig().GoLiveMessage
streamTitle := data.GetStreamTitle() streamTitle := n.configRepository.GetStreamTitle()
if streamTitle != "" { if streamTitle != "" {
goLiveMessage += "\n" + streamTitle goLiveMessage += "\n" + streamTitle
} }
message := fmt.Sprintf("%s\n\n%s", goLiveMessage, data.GetServerURL()) message := fmt.Sprintf("%s\n\n%s", goLiveMessage, n.configRepository.GetServerURL())
if err := n.discord.Send(message); err != nil { if err := n.discord.Send(message); err != nil {
log.Errorln("error sending discord message", err) log.Errorln("error sending discord message", err)
@ -158,6 +163,7 @@ func (n *Notifier) Notify() {
// RemoveNotificationForChannel removes a notification destination. // RemoveNotificationForChannel removes a notification destination.
func RemoveNotificationForChannel(channel, destination string) error { func RemoveNotificationForChannel(channel, destination string) error {
log.Debugln("Removing notification for channel", channel) log.Debugln("Removing notification for channel", channel)
return data.GetDatastore().GetQueries().RemoveNotificationDestinationForChannel(context.Background(), db.RemoveNotificationDestinationForChannelParams{ return data.GetDatastore().GetQueries().RemoveNotificationDestinationForChannel(context.Background(), db.RemoveNotificationDestinationForChannelParams{
Channel: channel, Channel: channel,
Destination: destination, Destination: destination,

View File

@ -0,0 +1,15 @@
package authrepository
import (
"database/sql"
"github.com/owncast/owncast/models"
)
type AuthRepository interface {
CreateBanIPTable(db *sql.DB)
BanIPAddress(address, note string) error
IsIPAddressBanned(address string) (bool, error)
GetIPAddressBans() ([]models.IPAddress, error)
RemoveIPAddressBan(address string) error
}

View File

@ -0,0 +1,65 @@
package authrepository
import (
"context"
"database/sql"
"log"
"github.com/owncast/owncast/db"
"github.com/owncast/owncast/models"
)
// CreateBanIPTable will create the IP ban table if needed.
func (r *SqlAuthRepository) CreateBanIPTable(db *sql.DB) {
createTableSQL := ` CREATE TABLE IF NOT EXISTS ip_bans (
"ip_address" TEXT NOT NULL PRIMARY KEY,
"notes" TEXT,
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);`
stmt, err := db.Prepare(createTableSQL)
if err != nil {
log.Fatal("error creating ip ban table", err)
}
defer stmt.Close()
if _, err := stmt.Exec(); err != nil {
log.Fatal("error creating ip ban table", err)
}
}
// BanIPAddress will persist a new IP address ban to the datastore.
func (r *SqlAuthRepository) BanIPAddress(address, note string) error {
return r.datastore.GetQueries().BanIPAddress(context.Background(), db.BanIPAddressParams{
IpAddress: address,
Notes: sql.NullString{String: note, Valid: true},
})
}
// IsIPAddressBanned will return if an IP address has been previously blocked.
func (r *SqlAuthRepository) IsIPAddressBanned(address string) (bool, error) {
blocked, error := r.datastore.GetQueries().IsIPAddressBlocked(context.Background(), address)
return blocked > 0, error
}
// GetIPAddressBans will return all the banned IP addresses.
func (r *SqlAuthRepository) GetIPAddressBans() ([]models.IPAddress, error) {
result, err := r.datastore.GetQueries().GetIPAddressBans(context.Background())
if err != nil {
return nil, err
}
response := []models.IPAddress{}
for _, ip := range result {
response = append(response, models.IPAddress{
IPAddress: ip.IpAddress,
Notes: ip.Notes.String,
CreatedAt: ip.CreatedAt.Time,
})
}
return response, err
}
// RemoveIPAddressBan will remove a previously banned IP address.
func (r *SqlAuthRepository) RemoveIPAddressBan(address string) error {
return r.datastore.GetQueries().RemoveIPAddressBan(context.Background(), address)
}

View File

@ -0,0 +1,30 @@
package authrepository
import (
"github.com/owncast/owncast/core/data"
)
type SqlAuthRepository struct {
datastore *data.Datastore
}
// NOTE: This is temporary during the transition period.
var temporaryGlobalInstance AuthRepository
// Get will return the user repository.
func Get() AuthRepository {
if temporaryGlobalInstance == nil {
i := New(data.GetDatastore())
temporaryGlobalInstance = i
}
return temporaryGlobalInstance
}
// New will create a new instance of the UserRepository.
func New(datastore *data.Datastore) *SqlAuthRepository {
r := &SqlAuthRepository{
datastore: datastore,
}
return r
}

View File

@ -0,0 +1,13 @@
package configrepository
// GetFederatedInboxMap is a mapping between account names and their outbox.
func (r SqlConfigRepository) GetFederatedInboxMap() map[string]string {
return map[string]string{
r.GetDefaultFederationUsername(): r.GetDefaultFederationUsername(),
}
}
// GetDefaultFederationUsername will return the username used for sending federation activities.
func (r *SqlConfigRepository) GetDefaultFederationUsername() string {
return r.GetFederationUsername()
}

View File

@ -1,8 +1,9 @@
package data package configrepository
import ( import (
"strings" "strings"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -12,8 +13,8 @@ const (
datastoreValueVersionKey = "DATA_STORE_VERSION" datastoreValueVersionKey = "DATA_STORE_VERSION"
) )
func migrateDatastoreValues(datastore *Datastore) { func migrateDatastoreValues(datastore *data.Datastore) {
currentVersion, _ := _datastore.GetNumber(datastoreValueVersionKey) currentVersion, _ := datastore.GetNumber(datastoreValueVersionKey)
if currentVersion == 0 { if currentVersion == 0 {
currentVersion = datastoreValuesVersion currentVersion = datastoreValuesVersion
} }
@ -33,12 +34,12 @@ func migrateDatastoreValues(datastore *Datastore) {
log.Fatalln("missing datastore values migration step") log.Fatalln("missing datastore values migration step")
} }
} }
if err := _datastore.SetNumber(datastoreValueVersionKey, datastoreValuesVersion); err != nil { if err := datastore.SetNumber(datastoreValueVersionKey, datastoreValuesVersion); err != nil {
log.Errorln("error setting datastore value version:", err) log.Errorln("error setting datastore value version:", err)
} }
} }
func migrateToDatastoreValues1(datastore *Datastore) { func migrateToDatastoreValues1(datastore *data.Datastore) {
// Migrate the forbidden usernames to be a slice instead of a string. // Migrate the forbidden usernames to be a slice instead of a string.
forbiddenUsernamesString, _ := datastore.GetString(blockedUsernamesKey) forbiddenUsernamesString, _ := datastore.GetString(blockedUsernamesKey)
if forbiddenUsernamesString != "" { if forbiddenUsernamesString != "" {
@ -58,28 +59,32 @@ func migrateToDatastoreValues1(datastore *Datastore) {
} }
} }
func migrateToDatastoreValues2(datastore *Datastore) { func migrateToDatastoreValues2(datastore *data.Datastore) {
configRepository := Get()
oldAdminPassword, _ := datastore.GetString("stream_key") oldAdminPassword, _ := datastore.GetString("stream_key")
// Avoids double hashing the password // Avoids double hashing the password
_ = datastore.SetString("admin_password_key", oldAdminPassword) _ = datastore.SetString("admin_password_key", oldAdminPassword)
_ = SetStreamKeys([]models.StreamKey{ _ = configRepository.SetStreamKeys([]models.StreamKey{
{Key: oldAdminPassword, Comment: "Default stream key"}, {Key: oldAdminPassword, Comment: "Default stream key"},
}) })
} }
func migrateToDatastoreValues3ServingEndpoint3(_ *Datastore) { func migrateToDatastoreValues3ServingEndpoint3(_ *data.Datastore) {
s3Config := GetS3Config() configRepository := Get()
s3Config := configRepository.GetS3Config()
if !s3Config.Enabled { if !s3Config.Enabled {
return return
} }
_ = SetVideoServingEndpoint(s3Config.ServingEndpoint) _ = configRepository.SetVideoServingEndpoint(s3Config.ServingEndpoint)
} }
func migrateToDatastoreValues4(datastore *Datastore) { func migrateToDatastoreValues4(datastore *data.Datastore) {
configRepository := Get()
unhashed_pass, _ := datastore.GetString("admin_password_key") unhashed_pass, _ := datastore.GetString("admin_password_key")
err := SetAdminPassword(unhashed_pass) err := configRepository.SetAdminPassword(unhashed_pass)
if err != nil { if err != nil {
log.Fatalln("error migrating admin password:", err) log.Fatalln("error migrating admin password:", err)
} }

View File

@ -0,0 +1,62 @@
package configrepository
const (
extraContentKey = "extra_page_content"
streamTitleKey = "stream_title"
adminPasswordKey = "admin_password_key"
logoPathKey = "logo_path"
logoUniquenessKey = "logo_uniqueness"
serverSummaryKey = "server_summary"
serverWelcomeMessageKey = "server_welcome_message"
serverNameKey = "server_name"
serverURLKey = "server_url"
httpPortNumberKey = "http_port_number"
httpListenAddressKey = "http_listen_address"
websocketHostOverrideKey = "websocket_host_override"
rtmpPortNumberKey = "rtmp_port_number"
serverMetadataTagsKey = "server_metadata_tags"
directoryEnabledKey = "directory_enabled"
directoryRegistrationKeyKey = "directory_registration_key"
socialHandlesKey = "social_handles"
peakViewersSessionKey = "peak_viewers_session"
peakViewersOverallKey = "peak_viewers_overall"
lastDisconnectTimeKey = "last_disconnect_time"
ffmpegPathKey = "ffmpeg_path"
nsfwKey = "nsfw"
s3StorageConfigKey = "s3_storage_config"
videoLatencyLevel = "video_latency_level"
videoStreamOutputVariantsKey = "video_stream_output_variants"
chatDisabledKey = "chat_disabled"
externalActionsKey = "external_actions"
customStylesKey = "custom_styles"
customJavascriptKey = "custom_javascript"
videoCodecKey = "video_codec"
blockedUsernamesKey = "blocked_usernames"
publicKeyKey = "public_key"
privateKeyKey = "private_key"
serverInitDateKey = "server_init_date"
federationEnabledKey = "federation_enabled"
federationUsernameKey = "federation_username"
federationPrivateKey = "federation_private"
federationGoLiveMessageKey = "federation_go_live_message"
federationShowEngagementKey = "federation_show_engagement"
federationBlockedDomainsKey = "federation_blocked_domains"
suggestedUsernamesKey = "suggested_usernames"
chatJoinMessagesEnabledKey = "chat_join_messages_enabled"
chatEstablishedUsersOnlyModeKey = "chat_established_users_only_mode"
chatSpamProtectionEnabledKey = "chat_spam_protection_enabled"
chatSlurFilterEnabledKey = "chat_slur_filter_enabled"
notificationsEnabledKey = "notifications_enabled"
discordConfigurationKey = "discord_configuration"
browserPushConfigurationKey = "browser_push_configuration"
browserPushPublicKeyKey = "browser_push_public_key"
// nolint:gosec
browserPushPrivateKeyKey = "browser_push_private_key"
hasConfiguredInitialNotificationsKey = "has_configured_initial_notifications"
hideViewerCountKey = "hide_viewer_count"
customOfflineMessageKey = "custom_offline_message"
customColorVariableValuesKey = "custom_color_variable_values"
streamKeysKey = "stream_keys"
disableSearchIndexingKey = "disable_search_indexing"
videoServingEndpointKey = "video_serving_endpoint"
)

View File

@ -0,0 +1,129 @@
package configrepository
import (
"time"
"github.com/owncast/owncast/models"
"github.com/owncast/owncast/utils"
)
type ConfigRepository interface {
GetExtraPageBodyContent() string
SetExtraPageBodyContent(content string) error
GetStreamTitle() string
SetStreamTitle(title string) error
GetAdminPassword() string
SetAdminPassword(key string) error
GetLogoPath() string
SetLogoPath(logo string) error
SetLogoUniquenessString(uniqueness string) error
GetLogoUniquenessString() string
GetServerSummary() string
SetServerSummary(summary string) error
GetServerWelcomeMessage() string
SetServerWelcomeMessage(welcomeMessage string) error
GetServerName() string
SetServerName(name string) error
GetServerURL() string
SetServerURL(url string) error
GetHTTPPortNumber() int
SetWebsocketOverrideHost(host string) error
GetWebsocketOverrideHost() string
SetHTTPPortNumber(port float64) error
GetHTTPListenAddress() string
SetHTTPListenAddress(address string) error
GetRTMPPortNumber() int
SetRTMPPortNumber(port float64) error
GetServerMetadataTags() []string
SetServerMetadataTags(tags []string) error
GetDirectoryEnabled() bool
SetDirectoryEnabled(enabled bool) error
SetDirectoryRegistrationKey(key string) error
GetDirectoryRegistrationKey() string
GetSocialHandles() []models.SocialHandle
SetSocialHandles(socialHandles []models.SocialHandle) error
GetPeakSessionViewerCount() int
SetPeakSessionViewerCount(count int) error
GetPeakOverallViewerCount() int
SetPeakOverallViewerCount(count int) error
GetLastDisconnectTime() (*utils.NullTime, error)
SetLastDisconnectTime(disconnectTime time.Time) error
SetNSFW(isNSFW bool) error
GetNSFW() bool
SetFfmpegPath(path string) error
GetFfMpegPath() string
GetS3Config() models.S3
SetS3Config(config models.S3) error
GetStreamLatencyLevel() models.LatencyLevel
SetStreamLatencyLevel(level float64) error
GetStreamOutputVariants() []models.StreamOutputVariant
SetStreamOutputVariants(variants []models.StreamOutputVariant) error
SetChatDisabled(disabled bool) error
GetChatDisabled() bool
SetChatEstablishedUsersOnlyMode(enabled bool) error
GetChatEstbalishedUsersOnlyMode() bool
SetChatSpamProtectionEnabled(enabled bool) error
GetChatSpamProtectionEnabled() bool
SetChatSlurFilterEnabled(enabled bool) error
GetChatSlurFilterEnabled() bool
GetExternalActions() []models.ExternalAction
SetExternalActions(actions []models.ExternalAction) error
SetCustomStyles(styles string) error
GetCustomStyles() string
SetCustomJavascript(styles string) error
GetCustomJavascript() string
SetVideoCodec(codec string) error
GetVideoCodec() string
VerifySettings() error
FindHighestVideoQualityIndex(qualities []models.StreamOutputVariant) (int, bool)
GetForbiddenUsernameList() []string
SetForbiddenUsernameList(usernames []string) error
GetSuggestedUsernamesList() []string
SetSuggestedUsernamesList(usernames []string) error
GetServerInitTime() (*utils.NullTime, error)
SetServerInitTime(t time.Time) error
SetFederationEnabled(enabled bool) error
GetFederationEnabled() bool
SetFederationUsername(username string) error
GetFederationUsername() string
SetFederationGoLiveMessage(message string) error
GetFederationGoLiveMessage() string
SetFederationIsPrivate(isPrivate bool) error
GetFederationIsPrivate() bool
SetFederationShowEngagement(showEngagement bool) error
GetFederationShowEngagement() bool
SetBlockedFederatedDomains(domains []string) error
GetBlockedFederatedDomains() []string
SetChatJoinMessagesEnabled(enabled bool) error
GetChatJoinPartMessagesEnabled() bool
SetNotificationsEnabled(enabled bool) error
GetNotificationsEnabled() bool
GetDiscordConfig() models.DiscordConfiguration
SetDiscordConfig(config models.DiscordConfiguration) error
GetBrowserPushConfig() models.BrowserNotificationConfiguration
SetBrowserPushConfig(config models.BrowserNotificationConfiguration) error
SetBrowserPushPublicKey(key string) error
GetBrowserPushPublicKey() (string, error)
SetBrowserPushPrivateKey(key string) error
GetBrowserPushPrivateKey() (string, error)
SetHasPerformedInitialNotificationsConfig(hasConfigured bool) error
GetHasPerformedInitialNotificationsConfig() bool
GetHideViewerCount() bool
SetHideViewerCount(hide bool) error
GetCustomOfflineMessage() string
SetCustomOfflineMessage(message string) error
SetCustomColorVariableValues(variables map[string]string) error
GetCustomColorVariableValues() map[string]string
GetStreamKeys() []models.StreamKey
SetStreamKeys(actions []models.StreamKey) error
SetDisableSearchIndexing(disableSearchIndexing bool) error
GetDisableSearchIndexing() bool
GetVideoServingEndpoint() string
SetVideoServingEndpoint(message string) error
GetFederatedInboxMap() map[string]string
GetDefaultFederationUsername() string
GetPublicKey() string
GetPrivateKey() string
SetPublicKey(key string) error
SetPrivateKey(key string) error
}

View File

@ -0,0 +1,23 @@
package configrepository
// GetPublicKey will return the public key.
func (r *SqlConfigRepository) GetPublicKey() string {
value, _ := r.datastore.GetString(publicKeyKey)
return value
}
// SetPublicKey will save the public key.
func (r *SqlConfigRepository) SetPublicKey(key string) error {
return r.datastore.SetString(publicKeyKey, key)
}
// GetPrivateKey will return the private key.
func (r *SqlConfigRepository) GetPrivateKey() string {
value, _ := r.datastore.GetString(privateKeyKey)
return value
}
// SetPrivateKey will save the private key.
func (r *SqlConfigRepository) SetPrivateKey(key string) error {
return r.datastore.SetString(privateKeyKey, key)
}

View File

@ -0,0 +1,62 @@
package configrepository
import (
"github.com/owncast/owncast/config"
"github.com/owncast/owncast/models"
log "github.com/sirupsen/logrus"
)
// PopulateDefaults will set default values in the database.
func (r *SqlConfigRepository) PopulateDefaults() {
key := "HAS_POPULATED_DEFAULTS"
r.datastore.WarmCache()
defaults := config.GetDefaults()
_ = r.SetAdminPassword(defaults.AdminPassword)
_ = r.SetStreamKeys(defaults.StreamKeys)
_ = r.SetHTTPPortNumber(float64(defaults.WebServerPort))
_ = r.SetRTMPPortNumber(float64(defaults.RTMPServerPort))
_ = r.SetLogoPath(defaults.Logo)
_ = r.SetServerMetadataTags([]string{"owncast", "streaming"})
_ = r.SetServerSummary(defaults.Summary)
_ = r.SetServerWelcomeMessage("")
_ = r.SetServerName(defaults.Name)
_ = r.SetExtraPageBodyContent(defaults.PageBodyContent)
_ = r.SetFederationGoLiveMessage(defaults.FederationGoLiveMessage)
_ = r.SetSocialHandles([]models.SocialHandle{
{
Platform: "github",
URL: "https://github.com/owncast/owncast",
},
})
if !r.HasPopulatedFederationDefaults() {
if err := r.SetFederationGoLiveMessage(config.GetDefaults().FederationGoLiveMessage); err != nil {
log.Errorln(err)
}
if err := r.datastore.SetBool("HAS_POPULATED_FEDERATION_DEFAULTS", true); err != nil {
log.Errorln(err)
}
}
_ = r.datastore.SetBool(key, true)
}
// HasPopulatedDefaults will determine if the defaults have been inserted into the database.
func (r *SqlConfigRepository) HasPopulatedDefaults() bool {
hasPopulated, err := r.datastore.GetBool("HAS_POPULATED_DEFAULTS")
if err != nil {
return false
}
return hasPopulated
}
func (r *SqlConfigRepository) HasPopulatedFederationDefaults() bool {
hasPopulated, err := r.datastore.GetBool("HAS_POPULATED_FEDERATION_DEFAULTS")
if err != nil {
return false
}
return hasPopulated
}

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/webserver/handlers/generated" "github.com/owncast/owncast/webserver/handlers/generated"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
) )
@ -23,7 +23,8 @@ func SetCustomColorVariableValues(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetCustomColorVariableValues(*values.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetCustomColorVariableValues(*values.Value); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }

View File

@ -11,8 +11,9 @@ import (
"github.com/owncast/owncast/core/chat" "github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/chat/events" "github.com/owncast/owncast/core/chat/events"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/authrepository"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/userrepository" "github.com/owncast/owncast/persistence/userrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/handlers/generated" "github.com/owncast/owncast/webserver/handlers/generated"
@ -62,7 +63,9 @@ func BanIPAddress(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.BanIPAddress(configValue.Value.(string), "manually added"); err != nil { authRepository := authrepository.Get()
if err := authRepository.BanIPAddress(configValue.Value.(string), "manually added"); err != nil {
webutils.WriteSimpleResponse(w, false, "error saving IP address ban") webutils.WriteSimpleResponse(w, false, "error saving IP address ban")
return return
} }
@ -82,7 +85,9 @@ func UnBanIPAddress(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.RemoveIPAddressBan(configValue.Value.(string)); err != nil { authRepository := authrepository.Get()
if err := authRepository.RemoveIPAddressBan(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, "error removing IP address ban") webutils.WriteSimpleResponse(w, false, "error removing IP address ban")
return return
} }
@ -92,7 +97,9 @@ func UnBanIPAddress(w http.ResponseWriter, r *http.Request) {
// GetIPAddressBans will return all the banned IP addresses. // GetIPAddressBans will return all the banned IP addresses.
func GetIPAddressBans(w http.ResponseWriter, r *http.Request) { func GetIPAddressBans(w http.ResponseWriter, r *http.Request) {
bans, err := data.GetIPAddressBans() authRepository := authrepository.Get()
bans, err := authRepository.GetIPAddressBans()
if err != nil { if err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
@ -168,11 +175,13 @@ func UpdateUserEnabled(w http.ResponseWriter, r *http.Request) {
localIP6Address := "::1" localIP6Address := "::1"
// Ban this user's IP address. // Ban this user's IP address.
authRepository := authrepository.Get()
for _, client := range clients { for _, client := range clients {
ipAddress := client.IPAddress ipAddress := client.IPAddress
if ipAddress != localIP4Address && ipAddress != localIP6Address { if ipAddress != localIP4Address && ipAddress != localIP6Address {
reason := fmt.Sprintf("Banning of %s", disconnectedUser.DisplayName) reason := fmt.Sprintf("Banning of %s", disconnectedUser.DisplayName)
if err := data.BanIPAddress(ipAddress, reason); err != nil { if err := authRepository.BanIPAddress(ipAddress, reason); err != nil {
log.Errorln("error banning IP address: ", err) log.Errorln("error banning IP address: ", err)
} }
} }
@ -366,7 +375,8 @@ func SetEnableEstablishedChatUserMode(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetChatEstablishedUsersOnlyMode(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetChatEstablishedUsersOnlyMode(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }

View File

@ -13,9 +13,9 @@ import (
"github.com/owncast/owncast/activitypub/outbox" "github.com/owncast/owncast/activitypub/outbox"
"github.com/owncast/owncast/core/chat" "github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/webhooks" "github.com/owncast/owncast/core/webhooks"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/handlers/generated" "github.com/owncast/owncast/webserver/handlers/generated"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
@ -44,7 +44,8 @@ func SetTags(w http.ResponseWriter, r *http.Request) {
tagStrings = append(tagStrings, strings.TrimLeft(tag.Value.(string), "#")) tagStrings = append(tagStrings, strings.TrimLeft(tag.Value.(string), "#"))
} }
if err := data.SetServerMetadataTags(tagStrings); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetServerMetadataTags(tagStrings); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -70,8 +71,9 @@ func SetStreamTitle(w http.ResponseWriter, r *http.Request) {
} }
value := configValue.Value.(string) value := configValue.Value.(string)
configRepository := configrepository.Get()
if err := data.SetStreamTitle(value); err != nil { if err := configRepository.SetStreamTitle(value); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -104,7 +106,8 @@ func SetServerName(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetServerName(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetServerName(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -129,7 +132,8 @@ func SetServerSummary(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetServerSummary(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetServerSummary(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -154,7 +158,8 @@ func SetCustomOfflineMessage(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetCustomOfflineMessage(strings.TrimSpace(configValue.Value.(string))); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetCustomOfflineMessage(strings.TrimSpace(configValue.Value.(string))); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -173,7 +178,8 @@ func SetServerWelcomeMessage(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetServerWelcomeMessage(strings.TrimSpace(configValue.Value.(string))); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetServerWelcomeMessage(strings.TrimSpace(configValue.Value.(string))); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -192,7 +198,8 @@ func SetExtraPageContent(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetExtraPageBodyContent(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetExtraPageBodyContent(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -211,7 +218,8 @@ func SetAdminPassword(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetAdminPassword(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetAdminPassword(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -247,12 +255,14 @@ func SetLogo(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetLogoPath("logo" + extension); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetLogoPath("logo" + extension); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
if err := data.SetLogoUniquenessString(shortid.MustGenerate()); err != nil { if err := configRepository.SetLogoUniquenessString(shortid.MustGenerate()); err != nil {
log.Error("Error saving logo uniqueness string: ", err) log.Error("Error saving logo uniqueness string: ", err)
} }
@ -276,7 +286,8 @@ func SetNSFW(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetNSFW(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetNSFW(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -301,7 +312,8 @@ func SetFfmpegPath(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetFfmpegPath(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetFfmpegPath(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -320,12 +332,13 @@ func SetWebServerPort(w http.ResponseWriter, r *http.Request) {
return return
} }
configRepository := configrepository.Get()
if port, ok := configValue.Value.(float64); ok { if port, ok := configValue.Value.(float64); ok {
if (port < 1) || (port > 65535) { if (port < 1) || (port > 65535) {
webutils.WriteSimpleResponse(w, false, "Port number must be between 1 and 65535") webutils.WriteSimpleResponse(w, false, "Port number must be between 1 and 65535")
return return
} }
if err := data.SetHTTPPortNumber(port); err != nil { if err := configRepository.SetHTTPPortNumber(port); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -348,9 +361,10 @@ func SetWebServerIP(w http.ResponseWriter, r *http.Request) {
return return
} }
configRepository := configrepository.Get()
if input, ok := configValue.Value.(string); ok { if input, ok := configValue.Value.(string); ok {
if ip := net.ParseIP(input); ip != nil { if ip := net.ParseIP(input); ip != nil {
if err := data.SetHTTPListenAddress(ip.String()); err != nil { if err := configRepository.SetHTTPListenAddress(ip.String()); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -376,7 +390,8 @@ func SetRTMPServerPort(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetRTMPPortNumber(configValue.Value.(float64)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetRTMPPortNumber(configValue.Value.(float64)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -415,10 +430,12 @@ func SetServerURL(w http.ResponseWriter, r *http.Request) {
return return
} }
configRepository := configrepository.Get()
// Trim any trailing slash // Trim any trailing slash
serverURL := strings.TrimRight(rawValue, "/") serverURL := strings.TrimRight(rawValue, "/")
if err := data.SetServerURL(serverURL); err != nil { if err := configRepository.SetServerURL(serverURL); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -437,7 +454,9 @@ func SetSocketHostOverride(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetWebsocketOverrideHost(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetWebsocketOverrideHost(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -456,7 +475,9 @@ func SetDirectoryEnabled(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetDirectoryEnabled(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetDirectoryEnabled(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -474,7 +495,9 @@ func SetStreamLatencyLevel(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetStreamLatencyLevel(configValue.Value.(float64)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetStreamLatencyLevel(configValue.Value.(float64)); err != nil {
webutils.WriteSimpleResponse(w, false, "error setting stream latency "+err.Error()) webutils.WriteSimpleResponse(w, false, "error setting stream latency "+err.Error())
return return
} }
@ -521,7 +544,8 @@ func SetS3Configuration(w http.ResponseWriter, r *http.Request) {
} }
} }
if err := data.SetS3Config(newS3Config.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetS3Config(newS3Config.Value); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -545,7 +569,8 @@ func SetStreamOutputVariants(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetStreamOutputVariants(videoVariants.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetStreamOutputVariants(videoVariants.Value); err != nil {
webutils.WriteSimpleResponse(w, false, "unable to update video config with provided values "+err.Error()) webutils.WriteSimpleResponse(w, false, "unable to update video config with provided values "+err.Error())
return return
} }
@ -570,7 +595,8 @@ func SetSocialHandles(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetSocialHandles(socialHandles.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetSocialHandles(socialHandles.Value); err != nil {
webutils.WriteSimpleResponse(w, false, "unable to update social handles with provided values") webutils.WriteSimpleResponse(w, false, "unable to update social handles with provided values")
return return
} }
@ -596,7 +622,8 @@ func SetChatDisabled(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetChatDisabled(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetChatDisabled(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -616,7 +643,8 @@ func SetVideoCodec(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetVideoCodec(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetVideoCodec(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, "unable to update codec") webutils.WriteSimpleResponse(w, false, "unable to update codec")
return return
} }
@ -637,7 +665,8 @@ func SetExternalActions(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetExternalActions(actions.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetExternalActions(actions.Value); err != nil {
webutils.WriteSimpleResponse(w, false, "unable to update external actions with provided values") webutils.WriteSimpleResponse(w, false, "unable to update external actions with provided values")
return return
} }
@ -653,7 +682,8 @@ func SetCustomStyles(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetCustomStyles(customStyles.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetCustomStyles(customStyles.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -669,7 +699,8 @@ func SetCustomJavascript(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetCustomJavascript(customJavascript.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetCustomJavascript(customJavascript.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -687,7 +718,8 @@ func SetForbiddenUsernameList(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetForbiddenUsernameList(*request.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetForbiddenUsernameList(*request.Value); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -705,7 +737,8 @@ func SetSuggestedUsernameList(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetSuggestedUsernamesList(*request.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetSuggestedUsernamesList(*request.Value); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -725,7 +758,8 @@ func SetChatJoinMessagesEnabled(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetChatJoinMessagesEnabled(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetChatJoinMessagesEnabled(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -745,7 +779,8 @@ func SetHideViewerCount(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetHideViewerCount(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetHideViewerCount(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -765,7 +800,8 @@ func SetDisableSearchIndexing(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetDisableSearchIndexing(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetDisableSearchIndexing(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -787,7 +823,8 @@ func SetVideoServingEndpoint(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetVideoServingEndpoint(value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetVideoServingEndpoint(value); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -806,7 +843,8 @@ func SetChatSpamProtectionEnabled(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetChatSpamProtectionEnabled(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetChatSpamProtectionEnabled(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -824,7 +862,8 @@ func SetChatSlurFilterEnabled(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetChatSlurFilterEnabled(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetChatSlurFilterEnabled(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -900,7 +939,8 @@ func SetStreamKeys(w http.ResponseWriter, r *http.Request) {
} }
} }
if err := data.SetStreamKeys(streamKeys.Value); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetStreamKeys(streamKeys.Value); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }

View File

@ -6,7 +6,7 @@ import (
"github.com/owncast/owncast/activitypub" "github.com/owncast/owncast/activitypub"
"github.com/owncast/owncast/activitypub/outbox" "github.com/owncast/owncast/activitypub/outbox"
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
) )
@ -46,7 +46,9 @@ func SetFederationEnabled(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetFederationEnabled(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetFederationEnabled(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -64,7 +66,9 @@ func SetFederationActivityPrivate(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetFederationIsPrivate(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetFederationIsPrivate(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -89,7 +93,8 @@ func SetFederationShowEngagement(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetFederationShowEngagement(configValue.Value.(bool)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetFederationShowEngagement(configValue.Value.(bool)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -107,7 +112,8 @@ func SetFederationUsername(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetFederationUsername(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetFederationUsername(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -126,7 +132,8 @@ func SetFederationGoLiveMessage(w http.ResponseWriter, r *http.Request) {
return return
} }
if err := data.SetFederationGoLiveMessage(configValue.Value.(string)); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetFederationGoLiveMessage(configValue.Value.(string)); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }
@ -151,7 +158,8 @@ func SetFederationBlockDomains(w http.ResponseWriter, r *http.Request) {
domainStrings = append(domainStrings, domain.Value.(string)) domainStrings = append(domainStrings, domain.Value.(string))
} }
if err := data.SetBlockedFederatedDomains(domainStrings); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetBlockedFederatedDomains(domainStrings); err != nil {
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return
} }

View File

@ -6,7 +6,7 @@ import (
"github.com/owncast/owncast/activitypub/persistence" "github.com/owncast/owncast/activitypub/persistence"
"github.com/owncast/owncast/activitypub/requests" "github.com/owncast/owncast/activitypub/requests"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/webserver/handlers/generated" "github.com/owncast/owncast/webserver/handlers/generated"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
) )
@ -36,7 +36,8 @@ func ApproveFollower(w http.ResponseWriter, r *http.Request) {
return return
} }
localAccountName := data.GetDefaultFederationUsername() configRepository := configrepository.Get()
localAccountName := configRepository.GetDefaultFederationUsername()
followRequest, err := persistence.GetFollower(*approval.ActorIRI) followRequest, err := persistence.GetFollower(*approval.ActorIRI)
if err != nil { if err != nil {

View File

@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
) )
@ -19,6 +19,8 @@ func SetDiscordNotificationConfiguration(w http.ResponseWriter, r *http.Request)
Value models.DiscordConfiguration `json:"value"` Value models.DiscordConfiguration `json:"value"`
} }
configRepository := configrepository.Get()
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(r.Body)
var config request var config request
if err := decoder.Decode(&config); err != nil { if err := decoder.Decode(&config); err != nil {
@ -26,7 +28,7 @@ func SetDiscordNotificationConfiguration(w http.ResponseWriter, r *http.Request)
return return
} }
if err := data.SetDiscordConfig(config.Value); err != nil { if err := configRepository.SetDiscordConfig(config.Value); err != nil {
webutils.WriteSimpleResponse(w, false, "unable to update discord config with provided values") webutils.WriteSimpleResponse(w, false, "unable to update discord config with provided values")
return return
} }
@ -44,6 +46,7 @@ func SetBrowserNotificationConfiguration(w http.ResponseWriter, r *http.Request)
Value models.BrowserNotificationConfiguration `json:"value"` Value models.BrowserNotificationConfiguration `json:"value"`
} }
configRepository := configrepository.Get()
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(r.Body)
var config request var config request
if err := decoder.Decode(&config); err != nil { if err := decoder.Decode(&config); err != nil {
@ -51,7 +54,7 @@ func SetBrowserNotificationConfiguration(w http.ResponseWriter, r *http.Request)
return return
} }
if err := data.SetBrowserPushConfig(config.Value); err != nil { if err := configRepository.SetBrowserPushConfig(config.Value); err != nil {
webutils.WriteSimpleResponse(w, false, "unable to update browser push config with provided values") webutils.WriteSimpleResponse(w, false, "unable to update browser push config with provided values")
return return
} }

View File

@ -5,9 +5,9 @@ import (
"net/http" "net/http"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/transcoder" "github.com/owncast/owncast/core/transcoder"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/router/middleware" "github.com/owncast/owncast/webserver/router/middleware"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -15,12 +15,13 @@ import (
// GetServerConfig gets the config details of the server. // GetServerConfig gets the config details of the server.
func GetServerConfig(w http.ResponseWriter, r *http.Request) { func GetServerConfig(w http.ResponseWriter, r *http.Request) {
ffmpeg := utils.ValidatedFfmpegPath(data.GetFfMpegPath()) configRepository := configrepository.Get()
usernameBlocklist := data.GetForbiddenUsernameList() ffmpeg := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
usernameSuggestions := data.GetSuggestedUsernamesList() usernameBlocklist := configRepository.GetForbiddenUsernameList()
usernameSuggestions := configRepository.GetSuggestedUsernamesList()
videoQualityVariants := make([]models.StreamOutputVariant, 0) videoQualityVariants := make([]models.StreamOutputVariant, 0)
for _, variant := range data.GetStreamOutputVariants() { for _, variant := range configRepository.GetStreamOutputVariants() {
videoQualityVariants = append(videoQualityVariants, models.StreamOutputVariant{ videoQualityVariants = append(videoQualityVariants, models.StreamOutputVariant{
Name: variant.GetName(), Name: variant.GetName(),
IsAudioPassthrough: variant.GetIsAudioPassthrough(), IsAudioPassthrough: variant.GetIsAudioPassthrough(),
@ -35,61 +36,61 @@ func GetServerConfig(w http.ResponseWriter, r *http.Request) {
} }
response := serverConfigAdminResponse{ response := serverConfigAdminResponse{
InstanceDetails: webConfigResponse{ InstanceDetails: webConfigResponse{
Name: data.GetServerName(), Name: configRepository.GetServerName(),
Summary: data.GetServerSummary(), Summary: configRepository.GetServerSummary(),
Tags: data.GetServerMetadataTags(), Tags: configRepository.GetServerMetadataTags(),
ExtraPageContent: data.GetExtraPageBodyContent(), ExtraPageContent: configRepository.GetExtraPageBodyContent(),
StreamTitle: data.GetStreamTitle(), StreamTitle: configRepository.GetStreamTitle(),
WelcomeMessage: data.GetServerWelcomeMessage(), WelcomeMessage: configRepository.GetServerWelcomeMessage(),
OfflineMessage: data.GetCustomOfflineMessage(), OfflineMessage: configRepository.GetCustomOfflineMessage(),
Logo: data.GetLogoPath(), Logo: configRepository.GetLogoPath(),
SocialHandles: data.GetSocialHandles(), SocialHandles: configRepository.GetSocialHandles(),
NSFW: data.GetNSFW(), NSFW: configRepository.GetNSFW(),
CustomStyles: data.GetCustomStyles(), CustomStyles: configRepository.GetCustomStyles(),
CustomJavascript: data.GetCustomJavascript(), CustomJavascript: configRepository.GetCustomJavascript(),
AppearanceVariables: data.GetCustomColorVariableValues(), AppearanceVariables: configRepository.GetCustomColorVariableValues(),
}, },
FFmpegPath: ffmpeg, FFmpegPath: ffmpeg,
AdminPassword: data.GetAdminPassword(), AdminPassword: configRepository.GetAdminPassword(),
StreamKeys: data.GetStreamKeys(), StreamKeys: configRepository.GetStreamKeys(),
StreamKeyOverridden: config.TemporaryStreamKey != "", StreamKeyOverridden: config.TemporaryStreamKey != "",
WebServerPort: config.WebServerPort, WebServerPort: config.WebServerPort,
WebServerIP: config.WebServerIP, WebServerIP: config.WebServerIP,
RTMPServerPort: data.GetRTMPPortNumber(), RTMPServerPort: configRepository.GetRTMPPortNumber(),
ChatDisabled: data.GetChatDisabled(), ChatDisabled: configRepository.GetChatDisabled(),
ChatJoinMessagesEnabled: data.GetChatJoinPartMessagesEnabled(), ChatJoinMessagesEnabled: configRepository.GetChatJoinPartMessagesEnabled(),
SocketHostOverride: data.GetWebsocketOverrideHost(), SocketHostOverride: configRepository.GetWebsocketOverrideHost(),
VideoServingEndpoint: data.GetVideoServingEndpoint(), VideoServingEndpoint: configRepository.GetVideoServingEndpoint(),
ChatEstablishedUserMode: data.GetChatEstbalishedUsersOnlyMode(), ChatEstablishedUserMode: configRepository.GetChatEstbalishedUsersOnlyMode(),
ChatSpamProtectionEnabled: data.GetChatSpamProtectionEnabled(), ChatSpamProtectionEnabled: configRepository.GetChatSpamProtectionEnabled(),
ChatSlurFilterEnabled: data.GetChatSlurFilterEnabled(), ChatSlurFilterEnabled: configRepository.GetChatSlurFilterEnabled(),
HideViewerCount: data.GetHideViewerCount(), HideViewerCount: configRepository.GetHideViewerCount(),
DisableSearchIndexing: data.GetDisableSearchIndexing(), DisableSearchIndexing: configRepository.GetDisableSearchIndexing(),
VideoSettings: videoSettings{ VideoSettings: videoSettings{
VideoQualityVariants: videoQualityVariants, VideoQualityVariants: videoQualityVariants,
LatencyLevel: data.GetStreamLatencyLevel().Level, LatencyLevel: configRepository.GetStreamLatencyLevel().Level,
}, },
YP: yp{ YP: yp{
Enabled: data.GetDirectoryEnabled(), Enabled: configRepository.GetDirectoryEnabled(),
InstanceURL: data.GetServerURL(), InstanceURL: configRepository.GetServerURL(),
}, },
S3: data.GetS3Config(), S3: configRepository.GetS3Config(),
ExternalActions: data.GetExternalActions(), ExternalActions: configRepository.GetExternalActions(),
SupportedCodecs: transcoder.GetCodecs(ffmpeg), SupportedCodecs: transcoder.GetCodecs(ffmpeg),
VideoCodec: data.GetVideoCodec(), VideoCodec: configRepository.GetVideoCodec(),
ForbiddenUsernames: usernameBlocklist, ForbiddenUsernames: usernameBlocklist,
SuggestedUsernames: usernameSuggestions, SuggestedUsernames: usernameSuggestions,
Federation: federationConfigResponse{ Federation: federationConfigResponse{
Enabled: data.GetFederationEnabled(), Enabled: configRepository.GetFederationEnabled(),
IsPrivate: data.GetFederationIsPrivate(), IsPrivate: configRepository.GetFederationIsPrivate(),
Username: data.GetFederationUsername(), Username: configRepository.GetFederationUsername(),
GoLiveMessage: data.GetFederationGoLiveMessage(), GoLiveMessage: configRepository.GetFederationGoLiveMessage(),
ShowEngagement: data.GetFederationShowEngagement(), ShowEngagement: configRepository.GetFederationShowEngagement(),
BlockedDomains: data.GetBlockedFederatedDomains(), BlockedDomains: configRepository.GetBlockedFederatedDomains(),
}, },
Notifications: notificationsConfigResponse{ Notifications: notificationsConfigResponse{
Discord: data.GetDiscordConfig(), Discord: configRepository.GetDiscordConfig(),
Browser: data.GetBrowserPushConfig(), Browser: configRepository.GetBrowserPushConfig(),
}, },
} }

View File

@ -5,15 +5,17 @@ import (
"net/http" "net/http"
"github.com/owncast/owncast/core" "github.com/owncast/owncast/core"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/metrics" "github.com/owncast/owncast/metrics"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/webserver/router/middleware" "github.com/owncast/owncast/webserver/router/middleware"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// Status gets the details of the inbound broadcaster. // Status gets the details of the inbound broadcaster.
func Status(w http.ResponseWriter, r *http.Request) { func Status(w http.ResponseWriter, r *http.Request) {
configRepository := configrepository.Get()
broadcaster := core.GetBroadcaster() broadcaster := core.GetBroadcaster()
status := core.GetStatus() status := core.GetStatus()
currentBroadcast := core.GetCurrentBroadcast() currentBroadcast := core.GetCurrentBroadcast()
@ -27,7 +29,7 @@ func Status(w http.ResponseWriter, r *http.Request) {
OverallPeakViewerCount: status.OverallMaxViewerCount, OverallPeakViewerCount: status.OverallMaxViewerCount,
SessionPeakViewerCount: status.SessionMaxViewerCount, SessionPeakViewerCount: status.SessionMaxViewerCount,
VersionNumber: status.VersionNumber, VersionNumber: status.VersionNumber,
StreamTitle: data.GetStreamTitle(), StreamTitle: configRepository.GetStreamTitle(),
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@ -5,8 +5,8 @@ import (
"net/http" "net/http"
"github.com/owncast/owncast/core" "github.com/owncast/owncast/core"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/metrics" "github.com/owncast/owncast/metrics"
"github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -40,8 +40,9 @@ func GetVideoPlaybackMetrics(w http.ResponseWriter, r *http.Request) {
availableBitrates = append(availableBitrates, variants.VideoBitrate) availableBitrates = append(availableBitrates, variants.VideoBitrate)
} }
} else { } else {
segmentLength = data.GetStreamLatencyLevel().SecondsPerSegment configRepository := configrepository.Get()
for _, variants := range data.GetStreamOutputVariants() { segmentLength = configRepository.GetStreamLatencyLevel().SecondsPerSegment
for _, variants := range configRepository.GetStreamOutputVariants() {
availableBitrates = append(availableBitrates, variants.VideoBitrate) availableBitrates = append(availableBitrates, variants.VideoBitrate)
} }
} }

View File

@ -3,7 +3,7 @@ package admin
import ( import (
"net/http" "net/http"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -11,7 +11,8 @@ import (
// ResetYPRegistration will clear the YP protocol registration key. // ResetYPRegistration will clear the YP protocol registration key.
func ResetYPRegistration(w http.ResponseWriter, r *http.Request) { func ResetYPRegistration(w http.ResponseWriter, r *http.Request) {
log.Traceln("Resetting YP registration key") log.Traceln("Resetting YP registration key")
if err := data.SetDirectoryRegistrationKey(""); err != nil { configRepository := configrepository.Get()
if err := configRepository.SetDirectoryRegistrationKey(""); err != nil {
log.Errorln(err) log.Errorln(err)
webutils.WriteSimpleResponse(w, false, err.Error()) webutils.WriteSimpleResponse(w, false, err.Error())
return return

View File

@ -8,8 +8,8 @@ import (
"github.com/owncast/owncast/activitypub" "github.com/owncast/owncast/activitypub"
fediverseauth "github.com/owncast/owncast/auth/fediverse" fediverseauth "github.com/owncast/owncast/auth/fediverse"
"github.com/owncast/owncast/core/chat" "github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/userrepository" "github.com/owncast/owncast/persistence/userrepository"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -39,7 +39,8 @@ func RegisterFediverseOTPRequest(u models.User, w http.ResponseWriter, r *http.R
return return
} }
msg := fmt.Sprintf("<p>One-time code from %s: %s. If you did not request this message please ignore or block.</p>", data.GetServerName(), reg.Code) configRepository := configrepository.Get()
msg := fmt.Sprintf("<p>One-time code from %s: %s. If you did not request this message please ignore or block.</p>", configRepository.GetServerName(), reg.Code)
if err := activitypub.SendDirectFederatedMessage(msg, reg.Account); err != nil { if err := activitypub.SendDirectFederatedMessage(msg, reg.Account); err != nil {
webutils.WriteSimpleResponse(w, false, "Could not send code to fediverse: "+err.Error()) webutils.WriteSimpleResponse(w, false, "Could not send code to fediverse: "+err.Error())
return return

View File

@ -6,8 +6,8 @@ import (
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/chat" "github.com/owncast/owncast/core/chat"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/userrepository" "github.com/owncast/owncast/persistence/userrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/handlers/generated" "github.com/owncast/owncast/webserver/handlers/generated"
@ -105,7 +105,8 @@ func RegisterAnonymousChatUser(w http.ResponseWriter, r *http.Request) {
} }
func generateDisplayName() string { func generateDisplayName() string {
suggestedUsernamesList := data.GetSuggestedUsernamesList() configRepository := configrepository.Get()
suggestedUsernamesList := configRepository.GetSuggestedUsernamesList()
minSuggestedUsernamePoolLength := 10 minSuggestedUsernamePoolLength := 10
if len(suggestedUsernamesList) >= minSuggestedUsernamePoolLength { if len(suggestedUsernamesList) >= minSuggestedUsernamePoolLength {

View File

@ -8,8 +8,8 @@ import (
"github.com/owncast/owncast/activitypub" "github.com/owncast/owncast/activitypub"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/router/middleware" "github.com/owncast/owncast/webserver/router/middleware"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
@ -73,9 +73,10 @@ func GetWebConfig(w http.ResponseWriter, r *http.Request) {
} }
func getConfigResponse() webConfigResponse { func getConfigResponse() webConfigResponse {
pageContent := utils.RenderPageContentMarkdown(data.GetExtraPageBodyContent()) configRepository := configrepository.Get()
offlineMessage := utils.RenderSimpleMarkdown(data.GetCustomOfflineMessage()) pageContent := utils.RenderPageContentMarkdown(configRepository.GetExtraPageBodyContent())
socialHandles := data.GetSocialHandles() offlineMessage := utils.RenderSimpleMarkdown(configRepository.GetCustomOfflineMessage())
socialHandles := configRepository.GetSocialHandles()
for i, handle := range socialHandles { for i, handle := range socialHandles {
platform := models.GetSocialHandle(handle.Platform) platform := models.GetSocialHandle(handle.Platform)
if platform != nil { if platform != nil {
@ -84,16 +85,16 @@ func getConfigResponse() webConfigResponse {
} }
} }
serverSummary := data.GetServerSummary() serverSummary := configRepository.GetServerSummary()
var federationResponse federationConfigResponse var federationResponse federationConfigResponse
federationEnabled := data.GetFederationEnabled() federationEnabled := configRepository.GetFederationEnabled()
followerCount, _ := activitypub.GetFollowerCount() followerCount, _ := activitypub.GetFollowerCount()
if federationEnabled { if federationEnabled {
serverURLString := data.GetServerURL() serverURLString := configRepository.GetServerURL()
serverURL, _ := url.Parse(serverURLString) serverURL, _ := url.Parse(serverURLString)
account := fmt.Sprintf("%s@%s", data.GetDefaultFederationUsername(), serverURL.Host) account := fmt.Sprintf("%s@%s", configRepository.GetDefaultFederationUsername(), serverURL.Host)
federationResponse = federationConfigResponse{ federationResponse = federationConfigResponse{
Enabled: federationEnabled, Enabled: federationEnabled,
FollowerCount: int(followerCount), FollowerCount: int(followerCount),
@ -101,8 +102,8 @@ func getConfigResponse() webConfigResponse {
} }
} }
browserPushEnabled := data.GetBrowserPushConfig().Enabled browserPushEnabled := configRepository.GetBrowserPushConfig().Enabled
browserPushPublicKey, err := data.GetBrowserPushPublicKey() browserPushPublicKey, err := configRepository.GetBrowserPushPublicKey()
if err != nil { if err != nil {
log.Errorln("unable to fetch browser push notifications public key", err) log.Errorln("unable to fetch browser push notifications public key", err)
browserPushEnabled = false browserPushEnabled = false
@ -116,31 +117,31 @@ func getConfigResponse() webConfigResponse {
} }
authenticationResponse := authenticationConfigResponse{ authenticationResponse := authenticationConfigResponse{
IndieAuthEnabled: data.GetServerURL() != "", IndieAuthEnabled: configRepository.GetServerURL() != "",
} }
return webConfigResponse{ return webConfigResponse{
Name: data.GetServerName(), Name: configRepository.GetServerName(),
Summary: serverSummary, Summary: serverSummary,
OfflineMessage: offlineMessage, OfflineMessage: offlineMessage,
Logo: "/logo", Logo: "/logo",
Tags: data.GetServerMetadataTags(), Tags: configRepository.GetServerMetadataTags(),
Version: config.GetReleaseString(), Version: config.GetReleaseString(),
NSFW: data.GetNSFW(), NSFW: configRepository.GetNSFW(),
SocketHostOverride: data.GetWebsocketOverrideHost(), SocketHostOverride: configRepository.GetWebsocketOverrideHost(),
ExtraPageContent: pageContent, ExtraPageContent: pageContent,
StreamTitle: data.GetStreamTitle(), StreamTitle: configRepository.GetStreamTitle(),
SocialHandles: socialHandles, SocialHandles: socialHandles,
ChatDisabled: data.GetChatDisabled(), ChatDisabled: configRepository.GetChatDisabled(),
ChatSpamProtectionDisabled: data.GetChatSpamProtectionEnabled(), ChatSpamProtectionDisabled: configRepository.GetChatSpamProtectionEnabled(),
ExternalActions: data.GetExternalActions(), ExternalActions: configRepository.GetExternalActions(),
CustomStyles: data.GetCustomStyles(), CustomStyles: configRepository.GetCustomStyles(),
MaxSocketPayloadSize: config.MaxSocketPayloadSize, MaxSocketPayloadSize: config.MaxSocketPayloadSize,
Federation: federationResponse, Federation: federationResponse,
Notifications: notificationsResponse, Notifications: notificationsResponse,
Authentication: authenticationResponse, Authentication: authenticationResponse,
AppearanceVariables: data.GetCustomColorVariableValues(), AppearanceVariables: configRepository.GetCustomColorVariableValues(),
HideViewerCount: data.GetHideViewerCount(), HideViewerCount: configRepository.GetHideViewerCount(),
} }
} }

View File

@ -3,13 +3,14 @@ package handlers
import ( import (
"net/http" "net/http"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
) )
// ServeCustomJavascript will serve optional custom Javascript. // ServeCustomJavascript will serve optional custom Javascript.
func ServeCustomJavascript(w http.ResponseWriter, r *http.Request) { func ServeCustomJavascript(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/javascript; charset=utf-8") w.Header().Set("Content-Type", "text/javascript; charset=utf-8")
js := data.GetCustomJavascript() configRepository := configrepository.Get()
js := configRepository.GetCustomJavascript()
_, _ = w.Write([]byte(js)) _, _ = w.Write([]byte(js))
} }

View File

@ -9,8 +9,8 @@ import (
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core" "github.com/owncast/owncast/core"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/router/middleware" "github.com/owncast/owncast/webserver/router/middleware"
) )
@ -29,7 +29,8 @@ func HandleHLSRequest(w http.ResponseWriter, r *http.Request) {
// If using external storage then only allow requests for the // If using external storage then only allow requests for the
// master playlist at stream.m3u8, no variants or segments. // master playlist at stream.m3u8, no variants or segments.
if data.GetS3Config().Enabled && relativePath != "stream.m3u8" { configRepository := configrepository.Get()
if configRepository.GetS3Config().Enabled && relativePath != "stream.m3u8" {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }

View File

@ -13,8 +13,8 @@ import (
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core" "github.com/owncast/owncast/core"
"github.com/owncast/owncast/core/cache" "github.com/owncast/owncast/core/cache"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/static" "github.com/owncast/owncast/static"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/router/middleware" "github.com/owncast/owncast/webserver/router/middleware"
@ -86,11 +86,12 @@ func renderIndexHtml(w http.ResponseWriter, nonce string) {
return return
} }
configRepository := configrepository.Get()
content := serverSideContent{ content := serverSideContent{
Name: data.GetServerName(), Name: configRepository.GetServerName(),
Summary: data.GetServerSummary(), Summary: configRepository.GetServerSummary(),
RequestedURL: fmt.Sprintf("%s%s", data.GetServerURL(), "/"), RequestedURL: fmt.Sprintf("%s%s", configRepository.GetServerURL(), "/"),
TagsString: strings.Join(data.GetServerMetadataTags(), ","), TagsString: strings.Join(configRepository.GetServerMetadataTags(), ","),
ThumbnailURL: "thumbnail.jpg", ThumbnailURL: "thumbnail.jpg",
Thumbnail: "thumbnail.jpg", Thumbnail: "thumbnail.jpg",
Image: "logo/external", Image: "logo/external",
@ -145,8 +146,8 @@ func handleScraperMetadataPage(w http.ResponseWriter, r *http.Request) {
} }
scheme := "http" scheme := "http"
configRepository := configrepository.Get()
if siteURL := data.GetServerURL(); siteURL != "" { if siteURL := configRepository.GetServerURL(); siteURL != "" {
if parsed, err := url.Parse(siteURL); err == nil && parsed.Scheme != "" { if parsed, err := url.Parse(siteURL); err == nil && parsed.Scheme != "" {
scheme = parsed.Scheme scheme = parsed.Scheme
} }
@ -177,16 +178,16 @@ func handleScraperMetadataPage(w http.ResponseWriter, r *http.Request) {
thumbnailURL = imageURL.String() thumbnailURL = imageURL.String()
} }
tagsString := strings.Join(data.GetServerMetadataTags(), ",") tagsString := strings.Join(configRepository.GetServerMetadataTags(), ",")
metadata := MetadataPage{ metadata := MetadataPage{
Name: data.GetServerName(), Name: configRepository.GetServerName(),
RequestedURL: fullURL.String(), RequestedURL: fullURL.String(),
Image: imageURL.String(), Image: imageURL.String(),
Summary: data.GetServerSummary(), Summary: configRepository.GetServerSummary(),
Thumbnail: thumbnailURL, Thumbnail: thumbnailURL,
TagsString: tagsString, TagsString: tagsString,
Tags: data.GetServerMetadataTags(), Tags: configRepository.GetServerMetadataTags(),
SocialHandles: data.GetSocialHandles(), SocialHandles: configRepository.GetSocialHandles(),
} }
// Cache the rendered HTML // Cache the rendered HTML

View File

@ -7,7 +7,7 @@ import (
"strconv" "strconv"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/static" "github.com/owncast/owncast/static"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -17,7 +17,8 @@ var _hasWarnedSVGLogo = false
// GetLogo will return the logo image as a response. // GetLogo will return the logo image as a response.
func GetLogo(w http.ResponseWriter, r *http.Request) { func GetLogo(w http.ResponseWriter, r *http.Request) {
imageFilename := data.GetLogoPath() configRepository := configrepository.Get()
imageFilename := configRepository.GetLogoPath()
if imageFilename == "" { if imageFilename == "" {
returnDefault(w) returnDefault(w)
return return
@ -47,7 +48,8 @@ func GetLogo(w http.ResponseWriter, r *http.Request) {
// Used for sharing to external social networks that generally // Used for sharing to external social networks that generally
// don't support SVG. // don't support SVG.
func GetCompatibleLogo(w http.ResponseWriter, r *http.Request) { func GetCompatibleLogo(w http.ResponseWriter, r *http.Request) {
imageFilename := data.GetLogoPath() configRepository := configrepository.Get()
imageFilename := configRepository.GetLogoPath()
// If the logo image is not a SVG then we can return it // If the logo image is not a SVG then we can return it
// without any problems. // without any problems.

View File

@ -8,7 +8,7 @@ import (
"strings" "strings"
"github.com/owncast/owncast/activitypub/webfinger" "github.com/owncast/owncast/activitypub/webfinger"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/webserver/handlers/generated" "github.com/owncast/owncast/webserver/handlers/generated"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
) )
@ -31,8 +31,9 @@ func RemoteFollow(w http.ResponseWriter, r *http.Request) {
return return
} }
localActorPath, _ := url.Parse(data.GetServerURL()) configRepository := configrepository.Get()
localActorPath.Path = fmt.Sprintf("/federation/user/%s", data.GetDefaultFederationUsername()) localActorPath, _ := url.Parse(configRepository.GetServerURL())
localActorPath.Path = fmt.Sprintf("/federation/user/%s", configRepository.GetDefaultFederationUsername())
var template string var template string
links, err := webfinger.GetWebfingerLinks(*request.Account) links, err := webfinger.GetWebfingerLinks(*request.Account)
if err != nil { if err != nil {

View File

@ -4,7 +4,7 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
) )
// GetRobotsDotTxt returns the contents of our robots.txt. // GetRobotsDotTxt returns the contents of our robots.txt.
@ -16,7 +16,8 @@ func GetRobotsDotTxt(w http.ResponseWriter, r *http.Request) {
"Disallow: /api", "Disallow: /api",
} }
if data.GetDisableSearchIndexing() { configRepository := configrepository.Get()
if configRepository.GetDisableSearchIndexing() {
contents = append(contents, "Disallow: /") contents = append(contents, "Disallow: /")
} }

View File

@ -6,7 +6,7 @@ import (
"time" "time"
"github.com/owncast/owncast/core" "github.com/owncast/owncast/core"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
"github.com/owncast/owncast/webserver/router/middleware" "github.com/owncast/owncast/webserver/router/middleware"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
@ -34,7 +34,8 @@ func getStatusResponse() webStatusResponse {
VersionNumber: status.VersionNumber, VersionNumber: status.VersionNumber,
StreamTitle: status.StreamTitle, StreamTitle: status.StreamTitle,
} }
if !data.GetHideViewerCount() { configRepository := configrepository.Get()
if !configRepository.GetHideViewerCount() {
response.ViewerCount = status.ViewerCount response.ViewerCount = status.ViewerCount
} }
return response return response

View File

@ -4,7 +4,7 @@ import (
"net/http" "net/http"
"sort" "sort"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
webutils "github.com/owncast/owncast/webserver/utils" webutils "github.com/owncast/owncast/webserver/utils"
) )
@ -22,7 +22,8 @@ type variantsResponse struct {
// GetVideoStreamOutputVariants will return the video variants available. // GetVideoStreamOutputVariants will return the video variants available.
func GetVideoStreamOutputVariants(w http.ResponseWriter, r *http.Request) { func GetVideoStreamOutputVariants(w http.ResponseWriter, r *http.Request) {
outputVariants := data.GetStreamOutputVariants() configRepository := configrepository.Get()
outputVariants := configRepository.GetStreamOutputVariants()
streamSortVariants := make([]variantsSort, len(outputVariants)) streamSortVariants := make([]variantsSort, len(outputVariants))
for i, variant := range outputVariants { for i, variant := range outputVariants {

View File

@ -4,15 +4,16 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/owncast/owncast/core/data" "github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
) )
// RequireActivityPubOrRedirect will validate the requested content types and // RequireActivityPubOrRedirect will validate the requested content types and
// redirect to the main Owncast page if it doesn't match. // redirect to the main Owncast page if it doesn't match.
func RequireActivityPubOrRedirect(handler http.HandlerFunc) http.HandlerFunc { func RequireActivityPubOrRedirect(handler http.HandlerFunc) http.HandlerFunc {
configRepository := configrepository.Get()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !data.GetFederationEnabled() { if !configRepository.GetFederationEnabled() {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
} }

View File

@ -5,8 +5,9 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/authrepository"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/persistence/userrepository" "github.com/owncast/owncast/persistence/userrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -21,9 +22,10 @@ type UserAccessTokenHandlerFunc func(models.User, http.ResponseWriter, *http.Req
// RequireAdminAuth wraps a handler requiring HTTP basic auth for it using the given // RequireAdminAuth wraps a handler requiring HTTP basic auth for it using the given
// the stream key as the password and and a hardcoded "admin" for username. // the stream key as the password and and a hardcoded "admin" for username.
func RequireAdminAuth(handler http.HandlerFunc) http.HandlerFunc { func RequireAdminAuth(handler http.HandlerFunc) http.HandlerFunc {
configRepository := configrepository.Get()
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
username := "admin" username := "admin"
password := data.GetAdminPassword() password := configRepository.GetAdminPassword()
realm := "Owncast Authenticated Request" realm := "Owncast Authenticated Request"
// Alow CORS only for localhost:3000 to support Owncast development. // Alow CORS only for localhost:3000 to support Owncast development.
@ -102,6 +104,7 @@ func RequireExternalAPIAccessToken(scope string, handler ExternalAccessTokenHand
// RequireUserAccessToken will validate a provided user's access token and make sure the associated user is enabled. // RequireUserAccessToken will validate a provided user's access token and make sure the associated user is enabled.
// Not to be used for validating 3rd party access. // Not to be used for validating 3rd party access.
func RequireUserAccessToken(handler UserAccessTokenHandlerFunc) http.HandlerFunc { func RequireUserAccessToken(handler UserAccessTokenHandlerFunc) http.HandlerFunc {
authRepository := authrepository.Get()
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
accessToken := r.URL.Query().Get("accessToken") accessToken := r.URL.Query().Get("accessToken")
if accessToken == "" { if accessToken == "" {
@ -111,7 +114,7 @@ func RequireUserAccessToken(handler UserAccessTokenHandlerFunc) http.HandlerFunc
ipAddress := utils.GetIPAddressFromRequest(r) ipAddress := utils.GetIPAddressFromRequest(r)
// Check if this client's IP address is banned. // Check if this client's IP address is banned.
if blocked, err := data.IsIPAddressBanned(ipAddress); blocked { if blocked, err := authRepository.IsIPAddressBanned(ipAddress); blocked {
log.Debugln("Client ip address has been blocked. Rejecting.") log.Debugln("Client ip address has been blocked. Rejecting.")
accessDenied(w) accessDenied(w)
return return

View File

@ -4,8 +4,8 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
"github.com/owncast/owncast/utils" "github.com/owncast/owncast/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -28,28 +28,29 @@ type ypDetailsResponse struct {
// GetYPResponse gets the status of the server for YP purposes. // GetYPResponse gets the status of the server for YP purposes.
func GetYPResponse(w http.ResponseWriter, r *http.Request) { func GetYPResponse(w http.ResponseWriter, r *http.Request) {
if !data.GetDirectoryEnabled() { configRepository := configrepository.Get()
if !configRepository.GetDirectoryEnabled() {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
return return
} }
status := getStatus() status := getStatus()
streamTitle := data.GetStreamTitle() streamTitle := configRepository.GetStreamTitle()
response := ypDetailsResponse{ response := ypDetailsResponse{
Name: data.GetServerName(), Name: configRepository.GetServerName(),
Description: data.GetServerSummary(), Description: configRepository.GetServerSummary(),
StreamTitle: streamTitle, StreamTitle: streamTitle,
Logo: "/logo", Logo: "/logo",
NSFW: data.GetNSFW(), NSFW: configRepository.GetNSFW(),
Tags: data.GetServerMetadataTags(), Tags: configRepository.GetServerMetadataTags(),
Online: status.Online, Online: status.Online,
ViewerCount: status.ViewerCount, ViewerCount: status.ViewerCount,
OverallMaxViewerCount: status.OverallMaxViewerCount, OverallMaxViewerCount: status.OverallMaxViewerCount,
SessionMaxViewerCount: status.SessionMaxViewerCount, SessionMaxViewerCount: status.SessionMaxViewerCount,
LastConnectTime: status.LastConnectTime, LastConnectTime: status.LastConnectTime,
Social: data.GetSocialHandles(), Social: configRepository.GetSocialHandles(),
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")

View File

@ -9,8 +9,8 @@ import (
"time" "time"
"github.com/owncast/owncast/config" "github.com/owncast/owncast/config"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/models" "github.com/owncast/owncast/models"
"github.com/owncast/owncast/persistence/configrepository"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -61,7 +61,9 @@ func (yp *YP) Stop() {
} }
func (yp *YP) ping() { func (yp *YP) ping() {
if !data.GetDirectoryEnabled() { configRepository := configrepository.Get()
if !configRepository.GetDirectoryEnabled() {
return return
} }
@ -71,7 +73,7 @@ func (yp *YP) ping() {
return return
} }
myInstanceURL := data.GetServerURL() myInstanceURL := configRepository.GetServerURL()
if myInstanceURL == "" { if myInstanceURL == "" {
log.Warnln("Server URL not set in the configuration. Directory access is disabled until this is set.") log.Warnln("Server URL not set in the configuration. Directory access is disabled until this is set.")
return return
@ -85,9 +87,9 @@ func (yp *YP) ping() {
return return
} }
key := data.GetDirectoryRegistrationKey() key := configRepository.GetDirectoryRegistrationKey()
log.Traceln("Pinging YP as: ", data.GetServerName(), "with key", key) log.Traceln("Pinging YP as: ", configRepository.GetServerName(), "with key", key)
request := ypPingRequest{ request := ypPingRequest{
Key: key, Key: key,
@ -129,7 +131,7 @@ func (yp *YP) ping() {
_inErrorState = false _inErrorState = false
if pingResponse.Key != key { if pingResponse.Key != key {
if err := data.SetDirectoryRegistrationKey(key); err != nil { if err := configRepository.SetDirectoryRegistrationKey(key); err != nil {
log.Errorln("unable to save directory key:", err) log.Errorln("unable to save directory key:", err)
} }
} }