mirror of
https://github.com/navidrome/navidrome.git
synced 2026-04-18 13:39:34 -04:00
* feat: add Path to TrackInfo struct * refactor: improve naming to follow the rest of the code * test: add tests * fix: actually check for filesystem permission * refactor: remove library logic from specific plugins * refactor: move hasFilesystemPermission to a Manifest method * test(plugins): add unit tests for hasLibraryFilesystemAccess method Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): remove hasFilesystemPerm field and use manifest for filesystem permission checks Signed-off-by: Deluan <deluan@navidrome.org> * refactor(plugins): streamline library filesystem access checks in lyrics and scrobbler adapters Signed-off-by: Deluan <deluan@navidrome.org> --------- Signed-off-by: Deluan <deluan@navidrome.org> Co-authored-by: Deluan <deluan@navidrome.org>
78 lines
2.2 KiB
Go
78 lines
2.2 KiB
Go
package plugins
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"errors"
|
|
"io"
|
|
|
|
extism "github.com/extism/go-sdk"
|
|
"github.com/tetratelabs/wazero"
|
|
)
|
|
|
|
// plugin represents a loaded plugin
|
|
type plugin struct {
|
|
name string // Plugin name (from filename)
|
|
path string // Path to the wasm file
|
|
manifest *Manifest
|
|
compiled *extism.CompiledPlugin
|
|
capabilities []Capability // Auto-detected capabilities based on exported functions
|
|
closers []io.Closer // Cleanup functions to call on unload
|
|
metrics PluginMetricsRecorder
|
|
allowedUserIDs []string // User IDs this plugin can access (from DB configuration)
|
|
allUsers bool // If true, plugin can access all users
|
|
libraries libraryAccess
|
|
}
|
|
|
|
// instance creates a new plugin instance for the given context.
|
|
// The context is used for cancellation - if cancelled during a call,
|
|
// the module will be terminated and the instance becomes unusable.
|
|
func (p *plugin) instance(ctx context.Context) (*extism.Plugin, error) {
|
|
instance, err := p.compiled.Instance(ctx, extism.PluginInstanceConfig{
|
|
ModuleConfig: wazero.NewModuleConfig().WithSysWalltime().WithRandSource(rand.Reader),
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
instance.SetLogger(extismLogger(p.name))
|
|
return instance, nil
|
|
}
|
|
|
|
func (p *plugin) Close() error {
|
|
var errs []error
|
|
for _, f := range p.closers {
|
|
err := f.Close()
|
|
if err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
return errors.Join(errs...)
|
|
}
|
|
|
|
func (p *plugin) hasLibraryFilesystemAccess(libID int) bool {
|
|
return p.manifest.HasLibraryFilesystemPermission() && p.libraries.contains(libID)
|
|
}
|
|
|
|
// libraryAccess captures the set of libraries a plugin is permitted to see,
|
|
// precomputed at load time for O(1) lookup.
|
|
type libraryAccess struct {
|
|
allLibraries bool
|
|
libraryIDSet map[int]struct{}
|
|
}
|
|
|
|
func newLibraryAccess(allowedLibraryIDs []int, allLibraries bool) libraryAccess {
|
|
set := make(map[int]struct{}, len(allowedLibraryIDs))
|
|
for _, id := range allowedLibraryIDs {
|
|
set[id] = struct{}{}
|
|
}
|
|
return libraryAccess{allLibraries: allLibraries, libraryIDSet: set}
|
|
}
|
|
|
|
func (a libraryAccess) contains(libID int) bool {
|
|
if a.allLibraries {
|
|
return true
|
|
}
|
|
_, ok := a.libraryIDSet[libID]
|
|
return ok
|
|
}
|