[MM-56653] Improve license loading errors (#26050)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
1a9355b2eb
Коммит
71e26b8df2
@@ -11,6 +11,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -32,33 +33,32 @@ func init() {
|
||||
|
||||
type LicenseValidatorIface interface {
|
||||
LicenseFromBytes(licenseBytes []byte) (*model.License, *model.AppError)
|
||||
ValidateLicense(signed []byte) (bool, string)
|
||||
ValidateLicense(signed []byte) (string, error)
|
||||
}
|
||||
|
||||
type LicenseValidatorImpl struct {
|
||||
}
|
||||
|
||||
func (l *LicenseValidatorImpl) LicenseFromBytes(licenseBytes []byte) (*model.License, *model.AppError) {
|
||||
success, licenseStr := l.ValidateLicense(licenseBytes)
|
||||
if !success {
|
||||
return nil, model.NewAppError("LicenseFromBytes", model.InvalidLicenseError, nil, "", http.StatusBadRequest)
|
||||
licenseStr, err := l.ValidateLicense(licenseBytes)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("LicenseFromBytes", model.InvalidLicenseError, nil, "", http.StatusBadRequest).Wrap(err)
|
||||
}
|
||||
|
||||
var license model.License
|
||||
if jsonErr := json.Unmarshal([]byte(licenseStr), &license); jsonErr != nil {
|
||||
return nil, model.NewAppError("LicenseFromBytes", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(jsonErr)
|
||||
if err := json.Unmarshal([]byte(licenseStr), &license); err != nil {
|
||||
return nil, model.NewAppError("LicenseFromBytes", "api.unmarshal_error", nil, "", http.StatusInternalServerError).Wrap(err)
|
||||
}
|
||||
|
||||
return &license, nil
|
||||
}
|
||||
|
||||
func (l *LicenseValidatorImpl) ValidateLicense(signed []byte) (bool, string) {
|
||||
func (l *LicenseValidatorImpl) ValidateLicense(signed []byte) (string, error) {
|
||||
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(signed)))
|
||||
|
||||
_, err := base64.StdEncoding.Decode(decoded, signed)
|
||||
if err != nil {
|
||||
mlog.Error("Encountered error decoding license", mlog.Err(err))
|
||||
return false, ""
|
||||
return "", fmt.Errorf("encountered error decoding license: %w", err)
|
||||
}
|
||||
|
||||
// remove null terminator
|
||||
@@ -67,8 +67,7 @@ func (l *LicenseValidatorImpl) ValidateLicense(signed []byte) (bool, string) {
|
||||
}
|
||||
|
||||
if len(decoded) <= 256 {
|
||||
mlog.Error("Signed license not long enough")
|
||||
return false, ""
|
||||
return "", fmt.Errorf("Signed license not long enough")
|
||||
}
|
||||
|
||||
plaintext := decoded[:len(decoded)-256]
|
||||
@@ -85,8 +84,7 @@ func (l *LicenseValidatorImpl) ValidateLicense(signed []byte) (bool, string) {
|
||||
|
||||
public, err := x509.ParsePKIXPublicKey(block.Bytes)
|
||||
if err != nil {
|
||||
mlog.Error("Encountered error signing license", mlog.Err(err))
|
||||
return false, ""
|
||||
return "", fmt.Errorf("Encountered error signing license: %w", err)
|
||||
}
|
||||
|
||||
rsaPublic := public.(*rsa.PublicKey)
|
||||
@@ -97,37 +95,34 @@ func (l *LicenseValidatorImpl) ValidateLicense(signed []byte) (bool, string) {
|
||||
|
||||
err = rsa.VerifyPKCS1v15(rsaPublic, crypto.SHA512, d, signature)
|
||||
if err != nil {
|
||||
mlog.Error("Invalid signature", mlog.Err(err))
|
||||
return false, ""
|
||||
return "", fmt.Errorf("Invalid signature: %w", err)
|
||||
}
|
||||
|
||||
return true, string(plaintext)
|
||||
return string(plaintext), nil
|
||||
}
|
||||
|
||||
func GetAndValidateLicenseFileFromDisk(location string) (*model.License, []byte) {
|
||||
func GetAndValidateLicenseFileFromDisk(location string) (*model.License, []byte, error) {
|
||||
fileName := GetLicenseFileLocation(location)
|
||||
|
||||
mlog.Info("License key has not been uploaded. Loading license key from disk.", mlog.String("filename", fileName))
|
||||
|
||||
if _, err := os.Stat(fileName); err != nil {
|
||||
mlog.Debug("We could not find the license key in the database or on disk at", mlog.String("filename", fileName))
|
||||
return nil, nil
|
||||
return nil, nil, fmt.Errorf("We could not find the license key on disk at %s: %w", fileName, err)
|
||||
}
|
||||
|
||||
mlog.Info("License key has not been uploaded. Loading license key from disk at", mlog.String("filename", fileName))
|
||||
licenseBytes := GetLicenseFileFromDisk(fileName)
|
||||
|
||||
success, licenseStr := LicenseValidator.ValidateLicense(licenseBytes)
|
||||
if !success {
|
||||
mlog.Error("Found license key at %v but it appears to be invalid.", mlog.String("filename", fileName))
|
||||
return nil, nil
|
||||
licenseStr, err := LicenseValidator.ValidateLicense(licenseBytes)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("Found license key at %s but it appears to be invalid: %w", fileName, err)
|
||||
}
|
||||
|
||||
var license model.License
|
||||
if jsonErr := json.Unmarshal([]byte(licenseStr), &license); jsonErr != nil {
|
||||
mlog.Error("Failed to decode license from JSON", mlog.Err(jsonErr))
|
||||
return nil, nil
|
||||
return nil, nil, fmt.Errorf("Found license key at %s but it appears to be invalid: %w", fileName, err)
|
||||
}
|
||||
|
||||
return &license, licenseBytes
|
||||
return &license, licenseBytes, nil
|
||||
}
|
||||
|
||||
func GetLicenseFileFromDisk(fileName string) []byte {
|
||||
|
||||
@@ -19,12 +19,12 @@ var validTestLicense = []byte("eyJpZCI6InpvZ3c2NW44Z2lmajVkbHJoYThtYnUxcGl3Iiwia
|
||||
func TestValidateLicense(t *testing.T) {
|
||||
t.Run("should fail with junk data", func(t *testing.T) {
|
||||
b1 := []byte("junk")
|
||||
ok, _ := LicenseValidator.ValidateLicense(b1)
|
||||
require.False(t, ok, "should have failed - bad license")
|
||||
_, err := LicenseValidator.ValidateLicense(b1)
|
||||
require.Error(t, err, "should have failed - bad license")
|
||||
|
||||
b2 := []byte("junkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunk")
|
||||
ok, _ = LicenseValidator.ValidateLicense(b2)
|
||||
require.False(t, ok, "should have failed - bad license")
|
||||
_, err = LicenseValidator.ValidateLicense(b2)
|
||||
require.Error(t, err, "should have failed - bad license")
|
||||
})
|
||||
|
||||
t.Run("should not panic on shorter than expected input", func(t *testing.T) {
|
||||
@@ -42,8 +42,8 @@ func TestValidateLicense(t *testing.T) {
|
||||
err = encoder.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
ok, str := LicenseValidator.ValidateLicense(licenseData.Bytes())
|
||||
require.False(t, ok)
|
||||
str, err := LicenseValidator.ValidateLicense(licenseData.Bytes())
|
||||
require.Error(t, err)
|
||||
require.Empty(t, str)
|
||||
})
|
||||
|
||||
@@ -61,8 +61,8 @@ func TestValidateLicense(t *testing.T) {
|
||||
err = encoder.Close()
|
||||
require.NoError(t, err)
|
||||
|
||||
ok, str := LicenseValidator.ValidateLicense(licenseData.Bytes())
|
||||
require.False(t, ok)
|
||||
str, err := LicenseValidator.ValidateLicense(licenseData.Bytes())
|
||||
require.Error(t, err)
|
||||
require.Empty(t, str)
|
||||
})
|
||||
|
||||
@@ -70,8 +70,8 @@ func TestValidateLicense(t *testing.T) {
|
||||
os.Setenv("MM_SERVICEENVIRONMENT", model.ServiceEnvironmentTest)
|
||||
defer os.Unsetenv("MM_SERVICEENVIRONMENT")
|
||||
|
||||
ok, str := LicenseValidator.ValidateLicense(nil)
|
||||
require.False(t, ok)
|
||||
str, err := LicenseValidator.ValidateLicense(nil)
|
||||
require.Error(t, err)
|
||||
require.Empty(t, str)
|
||||
})
|
||||
|
||||
@@ -79,8 +79,8 @@ func TestValidateLicense(t *testing.T) {
|
||||
os.Setenv("MM_SERVICEENVIRONMENT", model.ServiceEnvironmentTest)
|
||||
defer os.Unsetenv("MM_SERVICEENVIRONMENT")
|
||||
|
||||
ok, str := LicenseValidator.ValidateLicense(validTestLicense)
|
||||
require.True(t, ok)
|
||||
str, err := LicenseValidator.ValidateLicense(validTestLicense)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, str)
|
||||
})
|
||||
|
||||
@@ -88,8 +88,8 @@ func TestValidateLicense(t *testing.T) {
|
||||
os.Setenv("MM_SERVICEENVIRONMENT", model.ServiceEnvironmentProduction)
|
||||
defer os.Unsetenv("MM_SERVICEENVIRONMENT")
|
||||
|
||||
ok, str := LicenseValidator.ValidateLicense(validTestLicense)
|
||||
require.False(t, ok)
|
||||
str, err := LicenseValidator.ValidateLicense(validTestLicense)
|
||||
require.Error(t, err)
|
||||
require.Empty(t, str)
|
||||
})
|
||||
}
|
||||
@@ -117,7 +117,7 @@ func TestGetLicenseFileFromDisk(t *testing.T) {
|
||||
fileBytes := GetLicenseFileFromDisk(f.Name())
|
||||
require.NotEmpty(t, fileBytes, "should have read the file")
|
||||
|
||||
success, _ := LicenseValidator.ValidateLicense(fileBytes)
|
||||
assert.False(t, success, "should have been an invalid file")
|
||||
_, err = LicenseValidator.ValidateLicense(fileBytes)
|
||||
assert.Error(t, err, "should have been an invalid file")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -43,24 +43,24 @@ func (_m *LicenseValidatorIface) LicenseFromBytes(licenseBytes []byte) (*model.L
|
||||
}
|
||||
|
||||
// ValidateLicense provides a mock function with given fields: signed
|
||||
func (_m *LicenseValidatorIface) ValidateLicense(signed []byte) (bool, string) {
|
||||
func (_m *LicenseValidatorIface) ValidateLicense(signed []byte) (string, error) {
|
||||
ret := _m.Called(signed)
|
||||
|
||||
var r0 bool
|
||||
var r1 string
|
||||
if rf, ok := ret.Get(0).(func([]byte) (bool, string)); ok {
|
||||
var r0 string
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func([]byte) (string, error)); ok {
|
||||
return rf(signed)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func([]byte) bool); ok {
|
||||
if rf, ok := ret.Get(0).(func([]byte) string); ok {
|
||||
r0 = rf(signed)
|
||||
} else {
|
||||
r0 = ret.Get(0).(bool)
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func([]byte) string); ok {
|
||||
if rf, ok := ret.Get(1).(func([]byte) error); ok {
|
||||
r1 = rf(signed)
|
||||
} else {
|
||||
r1 = ret.Get(1).(string)
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
|
||||
Ссылка в новой задаче
Block a user