mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 04:48:26 +08:00
fix: removed resty calls from sync (#1016)
Signed-off-by: Ana-Roberta Lisca <ana.kagome@yahoo.com>
This commit is contained in:
committed by
GitHub
parent
50bdc2f402
commit
14238d4a8d
@@ -1,5 +1,33 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
httpTimeout = 5 * time.Minute
|
||||
certsPath = "/etc/containers/certs.d"
|
||||
homeCertsDir = ".config/containers/certs.d"
|
||||
clientCertFilename = "client.cert"
|
||||
clientKeyFilename = "client.key"
|
||||
caCertFilename = "ca.crt"
|
||||
)
|
||||
|
||||
func Contains(slice []string, item string) bool {
|
||||
for _, v := range slice {
|
||||
if item == v {
|
||||
@@ -9,3 +37,177 @@ func Contains(slice []string, item string) bool {
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GetTLSConfig(certsPath string, caCertPool *x509.CertPool) (*tls.Config, error) {
|
||||
clientCert := filepath.Join(certsPath, clientCertFilename)
|
||||
clientKey := filepath.Join(certsPath, clientKeyFilename)
|
||||
caCertFile := filepath.Join(certsPath, caCertFilename)
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(clientCert, clientKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caCert, err := os.ReadFile(caCertFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
RootCAs: caCertPool,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func loadPerHostCerts(caCertPool *x509.CertPool, host string) *tls.Config {
|
||||
// Check if the /home/user/.config/containers/certs.d/$IP:$PORT dir exists
|
||||
home := os.Getenv("HOME")
|
||||
clientCertsDir := filepath.Join(home, homeCertsDir, host)
|
||||
|
||||
if DirExists(clientCertsDir) {
|
||||
tlsConfig, err := GetTLSConfig(clientCertsDir, caCertPool)
|
||||
|
||||
if err == nil {
|
||||
return tlsConfig
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the /etc/containers/certs.d/$IP:$PORT dir exists
|
||||
clientCertsDir = filepath.Join(certsPath, host)
|
||||
if DirExists(clientCertsDir) {
|
||||
tlsConfig, err := GetTLSConfig(clientCertsDir, caCertPool)
|
||||
|
||||
if err == nil {
|
||||
return tlsConfig
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateHTTPClient(verifyTLS bool, host string, certDir string) (*http.Client, error) {
|
||||
htr := http.DefaultTransport.(*http.Transport).Clone() //nolint: forcetypeassert
|
||||
if !verifyTLS {
|
||||
htr.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} //nolint: gosec
|
||||
|
||||
return &http.Client{
|
||||
Timeout: httpTimeout,
|
||||
Transport: htr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Add a copy of the system cert pool
|
||||
caCertPool, _ := x509.SystemCertPool()
|
||||
|
||||
tlsConfig := loadPerHostCerts(caCertPool, host)
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = &tls.Config{RootCAs: caCertPool, MinVersion: tls.VersionTLS12}
|
||||
}
|
||||
|
||||
htr.TLSClientConfig = tlsConfig
|
||||
|
||||
if certDir != "" {
|
||||
clientCert := path.Join(certDir, "client.cert")
|
||||
clientKey := path.Join(certDir, "client.key")
|
||||
caCertPath := path.Join(certDir, "ca.crt")
|
||||
|
||||
caCert, err := os.ReadFile(caCertPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
|
||||
cert, err := tls.LoadX509KeyPair(clientCert, clientKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
htr.TLSClientConfig.Certificates = append(htr.TLSClientConfig.Certificates, cert)
|
||||
}
|
||||
|
||||
return &http.Client{
|
||||
Timeout: httpTimeout,
|
||||
Transport: htr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TypeOf(v interface{}) string {
|
||||
return fmt.Sprintf("%T", v)
|
||||
}
|
||||
|
||||
func MakeHTTPGetRequest(httpClient *http.Client, username string, password string, resultPtr interface{},
|
||||
blobURL string, mediaType string, log log.Logger,
|
||||
) ([]byte, int, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, blobURL, nil) //nolint
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", mediaType)
|
||||
|
||||
req.SetBasicAuth(username, password)
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
log.Error().Str("errorType", TypeOf(err)).
|
||||
Err(err).Msgf("couldn't get blob: %s", blobURL)
|
||||
|
||||
return nil, -1, err
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Error().Str("errorType", TypeOf(err)).
|
||||
Err(err).Msgf("couldn't get blob: %s", blobURL)
|
||||
|
||||
return nil, resp.StatusCode, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Error().Str("status code", fmt.Sprint(resp.StatusCode)).Err(err).Msgf("couldn't get blob: %s", blobURL)
|
||||
|
||||
return nil, resp.StatusCode, errors.New(string(body)) //nolint:goerr113
|
||||
}
|
||||
|
||||
// read blob
|
||||
|
||||
err = json.Unmarshal(body, &resultPtr)
|
||||
if err != nil {
|
||||
log.Error().Str("errorType", TypeOf(err)).
|
||||
Err(err).Msgf("couldn't unmarshal blob: %s", blobURL)
|
||||
|
||||
return body, resp.StatusCode, err
|
||||
}
|
||||
|
||||
return body, resp.StatusCode, err
|
||||
}
|
||||
|
||||
func DirExists(d string) bool {
|
||||
if !utf8.ValidString(d) {
|
||||
return false
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(d)
|
||||
if err != nil {
|
||||
if e, ok := err.(*fs.PathError); ok && errors.Is(e.Err, syscall.ENAMETOOLONG) || //nolint: errorlint
|
||||
errors.Is(e.Err, syscall.EINVAL) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil && os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !fileInfo.IsDir() {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
package common_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
|
||||
"zotregistry.io/zot/pkg/api"
|
||||
"zotregistry.io/zot/pkg/api/config"
|
||||
"zotregistry.io/zot/pkg/common"
|
||||
"zotregistry.io/zot/pkg/log"
|
||||
"zotregistry.io/zot/pkg/test"
|
||||
)
|
||||
|
||||
func TestCommon(t *testing.T) {
|
||||
@@ -15,4 +24,89 @@ func TestCommon(t *testing.T) {
|
||||
So(common.Contains(first, "peach"), ShouldBeFalse)
|
||||
So(common.Contains([]string{}, "apple"), ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("test getTLSConfig()", t, func() {
|
||||
caCertPool, _ := x509.SystemCertPool()
|
||||
tlsConfig, err := common.GetTLSConfig("wrongPath", caCertPool)
|
||||
So(tlsConfig, ShouldBeNil)
|
||||
So(err, ShouldNotBeNil)
|
||||
|
||||
tempDir := t.TempDir()
|
||||
err = test.CopyFiles("../../test/data", tempDir)
|
||||
So(err, ShouldBeNil)
|
||||
err = os.Chmod(path.Join(tempDir, "ca.crt"), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
_, err = common.GetTLSConfig(tempDir, caCertPool)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("test dirExists()", t, func() {
|
||||
exists := common.DirExists("testdir")
|
||||
So(exists, ShouldBeFalse)
|
||||
|
||||
file, err := os.Create("file.txt")
|
||||
So(err, ShouldBeNil)
|
||||
isDir := common.DirExists(file.Name())
|
||||
So(isDir, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("test CreateHTTPClient() no permissions on certificate", t, func() {
|
||||
tempDir := t.TempDir()
|
||||
err := test.CopyFiles("../../test/data", tempDir)
|
||||
So(err, ShouldBeNil)
|
||||
err = os.Chmod(path.Join(tempDir, "ca.crt"), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, err = common.CreateHTTPClient(true, "localhost", tempDir)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("test CreateHTTPClient() no permissions on key", t, func() {
|
||||
tempDir := t.TempDir()
|
||||
err := test.CopyFiles("../../test/data", tempDir)
|
||||
So(err, ShouldBeNil)
|
||||
err = os.Chmod(path.Join(tempDir, "client.key"), 0o000)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
_, err = common.CreateHTTPClient(true, "localhost", tempDir)
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("test MakeHTTPGetRequest() no permissions on key", t, func() {
|
||||
port := test.GetFreePort()
|
||||
baseURL := test.GetBaseURL(port)
|
||||
|
||||
conf := config.New()
|
||||
conf.HTTP.Port = port
|
||||
|
||||
ctlr := api.NewController(conf)
|
||||
tempDir := t.TempDir()
|
||||
err := test.CopyFiles("../../test/data", tempDir)
|
||||
So(err, ShouldBeNil)
|
||||
ctlr.Config.Storage.RootDirectory = tempDir
|
||||
|
||||
go startServer(ctlr)
|
||||
defer stopServer(ctlr)
|
||||
test.WaitTillServerReady(baseURL)
|
||||
|
||||
var resultPtr interface{}
|
||||
httpClient, err := common.CreateHTTPClient(true, "localhost", tempDir)
|
||||
So(err, ShouldBeNil)
|
||||
_, _, err = common.MakeHTTPGetRequest(httpClient, "", "",
|
||||
resultPtr, baseURL+"/v2/", ispec.MediaTypeImageManifest, log.NewLogger("", ""))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
}
|
||||
|
||||
func startServer(c *api.Controller) {
|
||||
// this blocks
|
||||
ctx := context.Background()
|
||||
if err := c.Run(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func stopServer(c *api.Controller) {
|
||||
ctx := context.Background()
|
||||
_ = c.Server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user