mirror of
https://github.com/navidrome/navidrome.git
synced 2025-07-14 07:31:28 +03:00
* chore: .gitignore any navidrome binary Signed-off-by: Deluan <deluan@navidrome.org> * feat: implement internal authentication handling in middleware Signed-off-by: Deluan <deluan@navidrome.org> * feat(manager): add SubsonicRouter to Manager for API routing Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add SubsonicAPI Host service for plugins and an example plugin Signed-off-by: Deluan <deluan@navidrome.org> * fix lint Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): refactor path handling in SubsonicAPI to extract endpoint correctly Signed-off-by: Deluan <deluan@navidrome.org> * docs(plugins): add SubsonicAPI service documentation to README Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): implement permission checks for SubsonicAPI service Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): enhance SubsonicAPI service initialization with atomic router handling Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): better encapsulated dependency injection Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): rename parameter in WithInternalAuth for clarity Signed-off-by: Deluan <deluan@navidrome.org> * docs(plugins): update SubsonicAPI permissions section in README for clarity and detail Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): enhance SubsonicAPI permissions output with allowed usernames and admin flag Signed-off-by: Deluan <deluan@navidrome.org> * feat(plugins): add schema reference to example plugins Signed-off-by: Deluan <deluan@navidrome.org> * remove import alias Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org>
427 lines
15 KiB
Go
427 lines
15 KiB
Go
// Code generated by github.com/atombender/go-jsonschema, DO NOT EDIT.
|
|
|
|
package schema
|
|
|
|
import "encoding/json"
|
|
import "fmt"
|
|
import "reflect"
|
|
|
|
type BasePermission struct {
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *BasePermission) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in BasePermission: required")
|
|
}
|
|
type Plain BasePermission
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = BasePermission(plain)
|
|
return nil
|
|
}
|
|
|
|
// Schema for Navidrome Plugin manifest.json files
|
|
type PluginManifest struct {
|
|
// Author or organization that created the plugin
|
|
Author string `json:"author" yaml:"author" mapstructure:"author"`
|
|
|
|
// List of capabilities implemented by this plugin
|
|
Capabilities []PluginManifestCapabilitiesElem `json:"capabilities" yaml:"capabilities" mapstructure:"capabilities"`
|
|
|
|
// A brief description of the plugin's functionality
|
|
Description string `json:"description" yaml:"description" mapstructure:"description"`
|
|
|
|
// Name of the plugin
|
|
Name string `json:"name" yaml:"name" mapstructure:"name"`
|
|
|
|
// Host services the plugin is allowed to access
|
|
Permissions PluginManifestPermissions `json:"permissions" yaml:"permissions" mapstructure:"permissions"`
|
|
|
|
// Plugin version using semantic versioning format
|
|
Version string `json:"version" yaml:"version" mapstructure:"version"`
|
|
|
|
// Website URL for the plugin or its documentation
|
|
Website string `json:"website" yaml:"website" mapstructure:"website"`
|
|
}
|
|
|
|
type PluginManifestCapabilitiesElem string
|
|
|
|
const PluginManifestCapabilitiesElemLifecycleManagement PluginManifestCapabilitiesElem = "LifecycleManagement"
|
|
const PluginManifestCapabilitiesElemMetadataAgent PluginManifestCapabilitiesElem = "MetadataAgent"
|
|
const PluginManifestCapabilitiesElemSchedulerCallback PluginManifestCapabilitiesElem = "SchedulerCallback"
|
|
const PluginManifestCapabilitiesElemScrobbler PluginManifestCapabilitiesElem = "Scrobbler"
|
|
const PluginManifestCapabilitiesElemWebSocketCallback PluginManifestCapabilitiesElem = "WebSocketCallback"
|
|
|
|
var enumValues_PluginManifestCapabilitiesElem = []interface{}{
|
|
"MetadataAgent",
|
|
"Scrobbler",
|
|
"SchedulerCallback",
|
|
"LifecycleManagement",
|
|
"WebSocketCallback",
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestCapabilitiesElem) UnmarshalJSON(value []byte) error {
|
|
var v string
|
|
if err := json.Unmarshal(value, &v); err != nil {
|
|
return err
|
|
}
|
|
var ok bool
|
|
for _, expected := range enumValues_PluginManifestCapabilitiesElem {
|
|
if reflect.DeepEqual(v, expected) {
|
|
ok = true
|
|
break
|
|
}
|
|
}
|
|
if !ok {
|
|
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValues_PluginManifestCapabilitiesElem, v)
|
|
}
|
|
*j = PluginManifestCapabilitiesElem(v)
|
|
return nil
|
|
}
|
|
|
|
// Host services the plugin is allowed to access
|
|
type PluginManifestPermissions struct {
|
|
// Artwork corresponds to the JSON schema field "artwork".
|
|
Artwork *PluginManifestPermissionsArtwork `json:"artwork,omitempty" yaml:"artwork,omitempty" mapstructure:"artwork,omitempty"`
|
|
|
|
// Cache corresponds to the JSON schema field "cache".
|
|
Cache *PluginManifestPermissionsCache `json:"cache,omitempty" yaml:"cache,omitempty" mapstructure:"cache,omitempty"`
|
|
|
|
// Config corresponds to the JSON schema field "config".
|
|
Config *PluginManifestPermissionsConfig `json:"config,omitempty" yaml:"config,omitempty" mapstructure:"config,omitempty"`
|
|
|
|
// Http corresponds to the JSON schema field "http".
|
|
Http *PluginManifestPermissionsHttp `json:"http,omitempty" yaml:"http,omitempty" mapstructure:"http,omitempty"`
|
|
|
|
// Scheduler corresponds to the JSON schema field "scheduler".
|
|
Scheduler *PluginManifestPermissionsScheduler `json:"scheduler,omitempty" yaml:"scheduler,omitempty" mapstructure:"scheduler,omitempty"`
|
|
|
|
// Subsonicapi corresponds to the JSON schema field "subsonicapi".
|
|
Subsonicapi *PluginManifestPermissionsSubsonicapi `json:"subsonicapi,omitempty" yaml:"subsonicapi,omitempty" mapstructure:"subsonicapi,omitempty"`
|
|
|
|
// Websocket corresponds to the JSON schema field "websocket".
|
|
Websocket *PluginManifestPermissionsWebsocket `json:"websocket,omitempty" yaml:"websocket,omitempty" mapstructure:"websocket,omitempty"`
|
|
|
|
AdditionalProperties interface{} `mapstructure:",remain"`
|
|
}
|
|
|
|
// Artwork service permissions
|
|
type PluginManifestPermissionsArtwork struct {
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsArtwork) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in PluginManifestPermissionsArtwork: required")
|
|
}
|
|
type Plain PluginManifestPermissionsArtwork
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = PluginManifestPermissionsArtwork(plain)
|
|
return nil
|
|
}
|
|
|
|
// Cache service permissions
|
|
type PluginManifestPermissionsCache struct {
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsCache) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in PluginManifestPermissionsCache: required")
|
|
}
|
|
type Plain PluginManifestPermissionsCache
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = PluginManifestPermissionsCache(plain)
|
|
return nil
|
|
}
|
|
|
|
// Configuration service permissions
|
|
type PluginManifestPermissionsConfig struct {
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsConfig) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in PluginManifestPermissionsConfig: required")
|
|
}
|
|
type Plain PluginManifestPermissionsConfig
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = PluginManifestPermissionsConfig(plain)
|
|
return nil
|
|
}
|
|
|
|
// HTTP service permissions
|
|
type PluginManifestPermissionsHttp struct {
|
|
// Whether to allow requests to local/private network addresses
|
|
AllowLocalNetwork bool `json:"allowLocalNetwork,omitempty" yaml:"allowLocalNetwork,omitempty" mapstructure:"allowLocalNetwork,omitempty"`
|
|
|
|
// Map of URL patterns (e.g., 'https://api.example.com/*') to allowed HTTP
|
|
// methods. Redirect destinations must also be included.
|
|
AllowedUrls map[string][]PluginManifestPermissionsHttpAllowedUrlsValueElem `json:"allowedUrls" yaml:"allowedUrls" mapstructure:"allowedUrls"`
|
|
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
type PluginManifestPermissionsHttpAllowedUrlsValueElem string
|
|
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemDELETE PluginManifestPermissionsHttpAllowedUrlsValueElem = "DELETE"
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemGET PluginManifestPermissionsHttpAllowedUrlsValueElem = "GET"
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemHEAD PluginManifestPermissionsHttpAllowedUrlsValueElem = "HEAD"
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemOPTIONS PluginManifestPermissionsHttpAllowedUrlsValueElem = "OPTIONS"
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemPATCH PluginManifestPermissionsHttpAllowedUrlsValueElem = "PATCH"
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemPOST PluginManifestPermissionsHttpAllowedUrlsValueElem = "POST"
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemPUT PluginManifestPermissionsHttpAllowedUrlsValueElem = "PUT"
|
|
const PluginManifestPermissionsHttpAllowedUrlsValueElemWildcard PluginManifestPermissionsHttpAllowedUrlsValueElem = "*"
|
|
|
|
var enumValues_PluginManifestPermissionsHttpAllowedUrlsValueElem = []interface{}{
|
|
"GET",
|
|
"POST",
|
|
"PUT",
|
|
"DELETE",
|
|
"PATCH",
|
|
"HEAD",
|
|
"OPTIONS",
|
|
"*",
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsHttpAllowedUrlsValueElem) UnmarshalJSON(value []byte) error {
|
|
var v string
|
|
if err := json.Unmarshal(value, &v); err != nil {
|
|
return err
|
|
}
|
|
var ok bool
|
|
for _, expected := range enumValues_PluginManifestPermissionsHttpAllowedUrlsValueElem {
|
|
if reflect.DeepEqual(v, expected) {
|
|
ok = true
|
|
break
|
|
}
|
|
}
|
|
if !ok {
|
|
return fmt.Errorf("invalid value (expected one of %#v): %#v", enumValues_PluginManifestPermissionsHttpAllowedUrlsValueElem, v)
|
|
}
|
|
*j = PluginManifestPermissionsHttpAllowedUrlsValueElem(v)
|
|
return nil
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsHttp) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["allowedUrls"]; raw != nil && !ok {
|
|
return fmt.Errorf("field allowedUrls in PluginManifestPermissionsHttp: required")
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in PluginManifestPermissionsHttp: required")
|
|
}
|
|
type Plain PluginManifestPermissionsHttp
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if v, ok := raw["allowLocalNetwork"]; !ok || v == nil {
|
|
plain.AllowLocalNetwork = false
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = PluginManifestPermissionsHttp(plain)
|
|
return nil
|
|
}
|
|
|
|
// Scheduler service permissions
|
|
type PluginManifestPermissionsScheduler struct {
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsScheduler) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in PluginManifestPermissionsScheduler: required")
|
|
}
|
|
type Plain PluginManifestPermissionsScheduler
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = PluginManifestPermissionsScheduler(plain)
|
|
return nil
|
|
}
|
|
|
|
// SubsonicAPI service permissions
|
|
type PluginManifestPermissionsSubsonicapi struct {
|
|
// If false, reject calls where the u is an admin
|
|
AllowAdmins bool `json:"allowAdmins,omitempty" yaml:"allowAdmins,omitempty" mapstructure:"allowAdmins,omitempty"`
|
|
|
|
// List of usernames the plugin can pass as u. Any user if empty
|
|
AllowedUsernames []string `json:"allowedUsernames,omitempty" yaml:"allowedUsernames,omitempty" mapstructure:"allowedUsernames,omitempty"`
|
|
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsSubsonicapi) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in PluginManifestPermissionsSubsonicapi: required")
|
|
}
|
|
type Plain PluginManifestPermissionsSubsonicapi
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if v, ok := raw["allowAdmins"]; !ok || v == nil {
|
|
plain.AllowAdmins = false
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = PluginManifestPermissionsSubsonicapi(plain)
|
|
return nil
|
|
}
|
|
|
|
// WebSocket service permissions
|
|
type PluginManifestPermissionsWebsocket struct {
|
|
// Whether to allow connections to local/private network addresses
|
|
AllowLocalNetwork bool `json:"allowLocalNetwork,omitempty" yaml:"allowLocalNetwork,omitempty" mapstructure:"allowLocalNetwork,omitempty"`
|
|
|
|
// List of WebSocket URL patterns that the plugin is allowed to connect to
|
|
AllowedUrls []string `json:"allowedUrls" yaml:"allowedUrls" mapstructure:"allowedUrls"`
|
|
|
|
// Explanation of why this permission is needed
|
|
Reason string `json:"reason" yaml:"reason" mapstructure:"reason"`
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifestPermissionsWebsocket) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["allowedUrls"]; raw != nil && !ok {
|
|
return fmt.Errorf("field allowedUrls in PluginManifestPermissionsWebsocket: required")
|
|
}
|
|
if _, ok := raw["reason"]; raw != nil && !ok {
|
|
return fmt.Errorf("field reason in PluginManifestPermissionsWebsocket: required")
|
|
}
|
|
type Plain PluginManifestPermissionsWebsocket
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if v, ok := raw["allowLocalNetwork"]; !ok || v == nil {
|
|
plain.AllowLocalNetwork = false
|
|
}
|
|
if plain.AllowedUrls != nil && len(plain.AllowedUrls) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "allowedUrls", 1)
|
|
}
|
|
if len(plain.Reason) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "reason", 1)
|
|
}
|
|
*j = PluginManifestPermissionsWebsocket(plain)
|
|
return nil
|
|
}
|
|
|
|
// UnmarshalJSON implements json.Unmarshaler.
|
|
func (j *PluginManifest) UnmarshalJSON(value []byte) error {
|
|
var raw map[string]interface{}
|
|
if err := json.Unmarshal(value, &raw); err != nil {
|
|
return err
|
|
}
|
|
if _, ok := raw["author"]; raw != nil && !ok {
|
|
return fmt.Errorf("field author in PluginManifest: required")
|
|
}
|
|
if _, ok := raw["capabilities"]; raw != nil && !ok {
|
|
return fmt.Errorf("field capabilities in PluginManifest: required")
|
|
}
|
|
if _, ok := raw["description"]; raw != nil && !ok {
|
|
return fmt.Errorf("field description in PluginManifest: required")
|
|
}
|
|
if _, ok := raw["name"]; raw != nil && !ok {
|
|
return fmt.Errorf("field name in PluginManifest: required")
|
|
}
|
|
if _, ok := raw["permissions"]; raw != nil && !ok {
|
|
return fmt.Errorf("field permissions in PluginManifest: required")
|
|
}
|
|
if _, ok := raw["version"]; raw != nil && !ok {
|
|
return fmt.Errorf("field version in PluginManifest: required")
|
|
}
|
|
if _, ok := raw["website"]; raw != nil && !ok {
|
|
return fmt.Errorf("field website in PluginManifest: required")
|
|
}
|
|
type Plain PluginManifest
|
|
var plain Plain
|
|
if err := json.Unmarshal(value, &plain); err != nil {
|
|
return err
|
|
}
|
|
if plain.Capabilities != nil && len(plain.Capabilities) < 1 {
|
|
return fmt.Errorf("field %s length: must be >= %d", "capabilities", 1)
|
|
}
|
|
*j = PluginManifest(plain)
|
|
return nil
|
|
}
|