Revert "Plugins: Forbid loading Angular plugins when Angular is disabled (#69225)" (#69657)

This reverts commit ff34279ff4.
This commit is contained in:
Giuseppe Guerra
2023-06-06 18:09:41 +02:00
committed by GitHub
parent d5cbac0f7b
commit 7a132680ef
11 changed files with 60 additions and 216 deletions
@@ -2,6 +2,8 @@ package angulardetector
import (
"bytes"
"fmt"
"io"
"regexp"
"github.com/grafana/grafana/pkg/plugins"
@@ -38,9 +40,43 @@ func (d *regexDetector) Detect(moduleJs []byte) bool {
return d.regex.Match(moduleJs)
}
// Inspector can inspect a module.js and determine if it's an Angular plugin or not.
type Inspector interface {
// Inspect open module.js and checks if the plugin is using Angular by matching against its source code.
// It returns true if module.js matches against any of the detectors in angularDetectors.
Inspect(p *plugins.Plugin) (bool, error)
// angularDetectors contains all the detectors to detect Angular plugins.
// They are executed in the specified order.
var angularDetectors = []detector{
&containsBytesDetector{pattern: []byte("PanelCtrl")},
&containsBytesDetector{pattern: []byte("QueryCtrl")},
&containsBytesDetector{pattern: []byte("app/plugins/sdk")},
&containsBytesDetector{pattern: []byte("angular.isNumber(")},
&containsBytesDetector{pattern: []byte("editor.html")},
&containsBytesDetector{pattern: []byte("ctrl.annotation")},
&containsBytesDetector{pattern: []byte("getLegacyAngularInjector")},
&regexDetector{regex: regexp.MustCompile(`['"](app/core/utils/promiseToDigest)|(app/plugins/.*?)|(app/core/core_module)['"]`)},
&regexDetector{regex: regexp.MustCompile(`from\s+['"]grafana\/app\/`)},
&regexDetector{regex: regexp.MustCompile(`System\.register\(`)},
}
// Inspect open module.js and checks if the plugin is using Angular by matching against its source code.
// It returns true if module.js matches against any of the detectors in angularDetectors.
func Inspect(p *plugins.Plugin) (isAngular bool, err error) {
f, err := p.FS.Open("module.js")
if err != nil {
return false, fmt.Errorf("open module.js: %w", err)
}
defer func() {
if closeErr := f.Close(); closeErr != nil && err == nil {
err = fmt.Errorf("close module.js: %w", closeErr)
}
}()
b, err := io.ReadAll(f)
if err != nil {
return false, fmt.Errorf("module.js readall: %w", err)
}
for _, d := range angularDetectors {
if d.Detect(b) {
isAngular = true
break
}
}
return
}
@@ -44,10 +44,9 @@ func TestAngularDetector_Inspect(t *testing.T) {
},
exp: false,
})
inspector := NewDefaultPatternsListInspector()
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
isAngular, err := inspector.Inspect(tc.plugin)
isAngular, err := Inspect(tc.plugin)
require.NoError(t, err)
require.Equal(t, tc.exp, isAngular)
})
@@ -55,33 +54,7 @@ func TestAngularDetector_Inspect(t *testing.T) {
t.Run("no module.js", func(t *testing.T) {
p := &plugins.Plugin{FS: plugins.NewInMemoryFS(map[string][]byte{})}
_, err := inspector.Inspect(p)
_, err := Inspect(p)
require.ErrorIs(t, err, plugins.ErrFileNotExist)
})
}
func TestFakeInspector(t *testing.T) {
t.Run("FakeInspector", func(t *testing.T) {
var called bool
inspector := FakeInspector{InspectFunc: func(p *plugins.Plugin) (bool, error) {
called = true
return false, nil
}}
r, err := inspector.Inspect(&plugins.Plugin{})
require.True(t, called)
require.NoError(t, err)
require.False(t, r)
})
t.Run("AlwaysAngularFakeInspector", func(t *testing.T) {
r, err := AlwaysAngularFakeInspector.Inspect(&plugins.Plugin{})
require.NoError(t, err)
require.True(t, r)
})
t.Run("NeverAngularFakeInspector", func(t *testing.T) {
r, err := NeverAngularFakeInspector.Inspect(&plugins.Plugin{})
require.NoError(t, err)
require.False(t, r)
})
}
@@ -1,29 +0,0 @@
package angulardetector
import "github.com/grafana/grafana/pkg/plugins"
// FakeInspector is an inspector whose Inspect function can be set to any function.
type FakeInspector struct {
// InspectFunc is the function called when calling Inspect()
InspectFunc func(p *plugins.Plugin) (bool, error)
}
func (i *FakeInspector) Inspect(p *plugins.Plugin) (bool, error) {
return i.InspectFunc(p)
}
var (
// AlwaysAngularFakeInspector is an inspector that always returns `true, nil`
AlwaysAngularFakeInspector = &FakeInspector{
InspectFunc: func(p *plugins.Plugin) (bool, error) {
return true, nil
},
}
// NeverAngularFakeInspector is an inspector that always returns `false, nil`
NeverAngularFakeInspector = &FakeInspector{
InspectFunc: func(p *plugins.Plugin) (bool, error) {
return false, nil
},
}
)
@@ -1,62 +0,0 @@
package angulardetector
import (
"fmt"
"io"
"regexp"
"github.com/grafana/grafana/pkg/plugins"
)
// defaultDetectors contains all the detectors to detect Angular plugins.
// They are executed in the specified order.
var defaultDetectors = []detector{
&containsBytesDetector{pattern: []byte("PanelCtrl")},
&containsBytesDetector{pattern: []byte("QueryCtrl")},
&containsBytesDetector{pattern: []byte("app/plugins/sdk")},
&containsBytesDetector{pattern: []byte("angular.isNumber(")},
&containsBytesDetector{pattern: []byte("editor.html")},
&containsBytesDetector{pattern: []byte("ctrl.annotation")},
&containsBytesDetector{pattern: []byte("getLegacyAngularInjector")},
&regexDetector{regex: regexp.MustCompile(`['"](app/core/utils/promiseToDigest)|(app/plugins/.*?)|(app/core/core_module)['"]`)},
&regexDetector{regex: regexp.MustCompile(`from\s+['"]grafana\/app\/`)},
&regexDetector{regex: regexp.MustCompile(`System\.register\(`)},
}
// PatternsListInspector matches module.js against all the specified patterns, in sequence.
type PatternsListInspector struct {
detectors []detector
}
// NewDefaultPatternsListInspector returns a new *PatternsListInspector using defaultDetectors as detectors.
func NewDefaultPatternsListInspector() *PatternsListInspector {
return &PatternsListInspector{detectors: defaultDetectors}
}
func ProvideService() Inspector {
return NewDefaultPatternsListInspector()
}
func (i *PatternsListInspector) Inspect(p *plugins.Plugin) (isAngular bool, err error) {
f, err := p.FS.Open("module.js")
if err != nil {
return false, fmt.Errorf("open module.js: %w", err)
}
defer func() {
if closeErr := f.Close(); closeErr != nil && err == nil {
err = fmt.Errorf("close module.js: %w", closeErr)
}
}()
b, err := io.ReadAll(f)
if err != nil {
return false, fmt.Errorf("module.js readall: %w", err)
}
for _, d := range i.detectors {
if d.Detect(b) {
isAngular = true
break
}
}
return
}