The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/pkg/plugins/manifest.go

115 lines
3.2 KiB

package plugins
import (
"crypto/sha256"
"fmt"
"io"
"io/ioutil"
"os"
"path"
)
// Soon we can fetch keys from:
// https://grafana.com/api/plugins/ci/keys
var publicKeyText = `-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: OpenPGP.js v4.10.1
Comment: https://openpgpjs.org
xjMEXo5V+RYJKwYBBAHaRw8BAQdAxIzDC0767A5eOHESiU8ACz5c9BWIrkbJ
/5a4m/zsFWnNG0pvbiBTbWl0aCA8am9uQGV4YW1wbGUuY29tPsJ4BBAWCgAg
BQJejlX5BgsJBwgDAgQVCAoCBBYCAQACGQECGwMCHgEACgkQ1uNw7xqtn452
hQD+LK/+1k5vdVVQDxRDyjN3+6Wiy/jK2wwH1JtHdnTUKKsA/iot3glN57wb
gaIQgQSZaE5E9tsIhGYhhNi8R743Oh4GzjgEXo5V+RIKKwYBBAGXVQEFAQEH
QCmdY+K50okUPp1NCFJxdje+Icr859fTwwRy9+hq+vUIAwEIB8JhBBgWCAAJ
BQJejlX5AhsMAAoJENbjcO8arZ+OpMwBAIcGCY1jMPo64h9G4MmFyPjL+wxn
U2YVAvfHQZnN+gD3AP47klt0/0tmSlbNwEvimZxA3tpUfNrtUO1K4E8VxSIn
Dg==
=PA1c
-----END PGP PUBLIC KEY BLOCK-----
`
// PluginManifest holds details for the file manifest
type PluginManifest struct {
Plugin string `json:"plugin"`
Version string `json:"version"`
KeyID string `json:"keyId"`
Time int64 `json:"time"`
Files map[string]string `json:"files"`
}
// readPluginManifest attempts to read and verify the plugin manifest
// if any error occurs or the manifest is not valid, this will return an error
func readPluginManifest(body []byte) (*PluginManifest, error) {
fmt.Printf("TODO... verify: %s", publicKeyText)
// block, _ := clearsign.Decode(body)
// if block == nil {
// return nil, fmt.Errorf("unable to decode manifest")
// }
// txt := string(block.Plaintext)
// fmt.Printf("PLAINTEXT: %s", txt)
// // Convert to a well typed object
// manifest := &PluginManifest{}
// err := json.Unmarshal(block.Plaintext, &manifest)
// if err != nil {
// return nil, fmt.Errorf("Error parsing manifest JSON: %s", err)
// }
// keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(publicKeyText))
// if err != nil {
// return nil, fmt.Errorf("failed to parse public key: %s", err)
// }
// if _, err := openpgp.CheckDetachedSignature(keyring,
// bytes.NewBuffer(block.Bytes),
// block.ArmoredSignature.Body); err != nil {
// return nil, fmt.Errorf("failed to check signature: %s", err)
// }
// return manifest, nil
return nil, fmt.Errorf("not yet parsing the manifest")
}
// GetPluginSignatureState returns the signature state for a plugin
func GetPluginSignatureState(plugin *PluginBase) PluginSignature {
manifestPath := path.Join(plugin.PluginDir, "MANIFEST.txt")
byteValue, err := ioutil.ReadFile(manifestPath)
if err != nil || len(byteValue) < 10 {
return PluginSignatureUnsigned
}
manifest, err := readPluginManifest(byteValue)
if err != nil {
return PluginSignatureInvalid
}
// Make sure the versions all match
if manifest.Plugin != plugin.Id || manifest.Version != plugin.Info.Version {
return PluginSignatureModified
}
// Verify the manifest contents
for p, hash := range manifest.Files {
// Open the file
f, err := os.Open(path.Join(plugin.PluginDir, p))
if err != nil {
return PluginSignatureModified
}
defer f.Close()
h := sha256.New()
if _, err := io.Copy(h, f); err != nil {
return PluginSignatureModified
}
sum := string(h.Sum(nil))
if sum != hash {
return PluginSignatureModified
}
}
// Everything OK
return PluginSignatureValid
}