diff --git a/docs/reference/ocm_credential-handling.md b/docs/reference/ocm_credential-handling.md
index 28e70c6c1..32dc2e39f 100644
--- a/docs/reference/ocm_credential-handling.md
+++ b/docs/reference/ocm_credential-handling.md
@@ -167,7 +167,7 @@ The following credential consumer types are used/supported:
- password
: the basic auth password
- - NpmRegistry
: NPM repository
+ - NpmRegistry
: NPM registry
It matches the NpmRegistry
consumer type and additionally acts like
the hostpath
type.
diff --git a/docs/reference/ocm_get_credentials.md b/docs/reference/ocm_get_credentials.md
index c97d24bb0..1a7205d39 100644
--- a/docs/reference/ocm_get_credentials.md
+++ b/docs/reference/ocm_get_credentials.md
@@ -93,7 +93,7 @@ Matchers exist for the following usage contexts or consumer types:
- password
: the basic auth password
- - NpmRegistry
: NPM repository
+ - NpmRegistry
: NPM registry
It matches the NpmRegistry
consumer type and additionally acts like
the hostpath
type.
diff --git a/pkg/contexts/credentials/builtin/npm/identity/identity.go b/pkg/contexts/credentials/builtin/npm/identity/identity.go
index 308cf8d29..dd90ef107 100644
--- a/pkg/contexts/credentials/builtin/npm/identity/identity.go
+++ b/pkg/contexts/credentials/builtin/npm/identity/identity.go
@@ -1,11 +1,8 @@
package identity
import (
- "path"
+ "net/url"
- . "net/url"
-
- "github.com/open-component-model/ocm/pkg/common"
"github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
"github.com/open-component-model/ocm/pkg/contexts/credentials/identity/hostpath"
"github.com/open-component-model/ocm/pkg/listformat"
@@ -37,31 +34,35 @@ func init() {
ATTR_TOKEN, "the token attribute. May exist after login at any npm registry. Check your .npmrc file!",
})
- cpi.RegisterStandardIdentity(CONSUMER_TYPE, hostpath.IdentityMatcher(CONSUMER_TYPE), `NPM repository
+ cpi.RegisterStandardIdentity(CONSUMER_TYPE, hostpath.IdentityMatcher(CONSUMER_TYPE), `NPM registry
It matches the `+CONSUMER_TYPE+`
consumer type and additionally acts like
the `+hostpath.IDENTITY_TYPE+`
type.`,
attrs)
}
-func GetConsumerId(rawURL string, pkgName string) cpi.ConsumerIdentity {
- url, err := Parse(rawURL)
+var identityMatcher = hostpath.IdentityMatcher(CONSUMER_TYPE)
+
+func IdentityMatcher(pattern, cur, id cpi.ConsumerIdentity) bool {
+ return identityMatcher(pattern, cur, id)
+}
+
+func GetConsumerId(rawURL, groupId string) (cpi.ConsumerIdentity, error) {
+ _url, err := url.JoinPath(rawURL, groupId)
if err != nil {
- return nil
+ return nil, err
}
-
- url.Path = path.Join(url.Path, pkgName)
- return hostpath.GetConsumerIdentity(CONSUMER_TYPE, url.String())
+ return hostpath.GetConsumerIdentity(CONSUMER_TYPE, _url), nil
}
-func GetCredentials(ctx cpi.ContextProvider, repoUrl string, pkgName string) common.Properties {
- id := GetConsumerId(repoUrl, pkgName)
- if id == nil {
- return nil
+func GetCredentials(ctx cpi.ContextProvider, repoUrl string, pkgName string) (cpi.Credentials, error) {
+ id, err := GetConsumerId(repoUrl, pkgName)
+ if err != nil {
+ return nil, err
}
- credentials, err := cpi.CredentialsForConsumer(ctx.CredentialsContext(), id)
- if credentials == nil || err != nil {
- return nil
+ if id == nil {
+ logging.DynamicLogger(REALM).Debug("No consumer identity found.", "url", repoUrl, "groupId", pkgName)
+ return nil, nil
}
- return credentials.Properties()
+ return cpi.CredentialsForConsumer(ctx.CredentialsContext(), id)
}
diff --git a/pkg/contexts/credentials/repositories/npm/config_test.go b/pkg/contexts/credentials/repositories/npm/config_test.go
index e2c2fcfea..d0ed58df8 100644
--- a/pkg/contexts/credentials/repositories/npm/config_test.go
+++ b/pkg/contexts/credentials/repositories/npm/config_test.go
@@ -3,18 +3,17 @@ package npm_test
import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
- . "github.com/open-component-model/ocm/pkg/testutils"
"github.com/open-component-model/ocm/pkg/common"
"github.com/open-component-model/ocm/pkg/contexts/credentials"
"github.com/open-component-model/ocm/pkg/contexts/credentials/builtin/npm/identity"
"github.com/open-component-model/ocm/pkg/contexts/credentials/repositories/npm"
+ . "github.com/open-component-model/ocm/pkg/testutils"
)
var _ = Describe("Config deserialization Test Environment", func() {
It("read .npmrc", func() {
ctx := credentials.New()
-
repo := Must(npm.NewRepository(ctx, "testdata/.npmrc"))
Expect(Must(repo.LookupCredentials("registry.npmjs.org")).Properties()).To(Equal(common.Properties{identity.ATTR_TOKEN: "npm_TOKEN"}))
Expect(Must(repo.LookupCredentials("npm.registry.acme.com/api/npm")).Properties()).To(Equal(common.Properties{identity.ATTR_TOKEN: "bearer_TOKEN"}))
@@ -22,12 +21,9 @@ var _ = Describe("Config deserialization Test Environment", func() {
It("propagates credentials", func() {
ctx := credentials.New()
-
spec := npm.NewRepositorySpec("testdata/.npmrc")
-
_ = Must(ctx.RepositoryForSpec(spec))
- id := identity.GetConsumerId("registry.npmjs.org", "pkg")
-
+ id := Must(identity.GetConsumerId("registry.npmjs.org", "pkg"))
creds := Must(credentials.CredentialsForConsumer(ctx, id))
Expect(creds).NotTo(BeNil())
Expect(creds.GetProperty(identity.ATTR_TOKEN)).To(Equal("npm_TOKEN"))
@@ -39,5 +35,4 @@ var _ = Describe("Config deserialization Test Environment", func() {
Expect(t).NotTo(BeNil())
Expect(t.Description()).NotTo(Equal(""))
})
-
})
diff --git a/pkg/contexts/credentials/repositories/npm/provider.go b/pkg/contexts/credentials/repositories/npm/provider.go
index 2268ff5fa..a60520437 100644
--- a/pkg/contexts/credentials/repositories/npm/provider.go
+++ b/pkg/contexts/credentials/repositories/npm/provider.go
@@ -35,8 +35,12 @@ func (p *ConsumerProvider) get(requested cpi.ConsumerIdentity, currentFound cpi.
var creds cpi.CredentialsSource
for key, value := range all {
- id := npm.GetConsumerId("https://"+key, "")
-
+ id, err := npm.GetConsumerId("https://"+key, "")
+ if err != nil {
+ log := logging.Context().Logger(npm.REALM)
+ log.LogError(err, "Failed to get consumer id", "key", key, "value", value)
+ return nil, nil
+ }
if m(requested, currentFound, id) {
creds = newCredentials(value)
currentFound = id
diff --git a/pkg/contexts/credentials/repositories/npm/repository.go b/pkg/contexts/credentials/repositories/npm/repository.go
index 87c4d326c..0cd48ffa4 100644
--- a/pkg/contexts/credentials/repositories/npm/repository.go
+++ b/pkg/contexts/credentials/repositories/npm/repository.go
@@ -65,7 +65,7 @@ func (r *Repository) Read(force bool) error {
}
if r.path == "" {
- return fmt.Errorf("npmrc path not provided")
+ return errors.New("npmrc path not provided")
}
cfg, path, err := readNpmConfigFile(r.path)
if err != nil {
diff --git a/pkg/contexts/ocm/accessmethods/npm/method.go b/pkg/contexts/ocm/accessmethods/npm/method.go
index fcf60cc67..7d70ecb21 100644
--- a/pkg/contexts/ocm/accessmethods/npm/method.go
+++ b/pkg/contexts/ocm/accessmethods/npm/method.go
@@ -86,7 +86,7 @@ func (a *AccessSpec) AccessMethod(c accspeccpi.ComponentVersionAccess) (accspecc
}
func (a *AccessSpec) GetInexpensiveContentVersionIdentity(access accspeccpi.ComponentVersionAccess) string {
- meta, err := a.getPackageMeta(access.GetContext())
+ meta, err := a.GetPackageVersion(access.GetContext())
if err != nil {
return ""
}
@@ -96,36 +96,49 @@ func (a *AccessSpec) GetInexpensiveContentVersionIdentity(access accspeccpi.Comp
return ""
}
-// PackageUrl returns the URL of the NPM package (Registry/Package/Version).
+// PackageUrl returns the URL of the NPM package (Registry/Package).
func (a *AccessSpec) PackageUrl() string {
- return a.Registry + path.Join("/", a.Package, a.Version)
+ return strings.TrimSuffix(a.Registry, "/") + path.Join("/", a.Package)
}
-func (a *AccessSpec) getPackageMeta(ctx accspeccpi.Context) (*meta, error) {
+// PackageVersionUrl returns the URL of the NPM package-version (Registry/Package/Version).
+func (a *AccessSpec) PackageVersionUrl() string {
+ return strings.TrimSuffix(a.Registry, "/") + path.Join("/", a.Package, a.Version)
+}
+
+func (a *AccessSpec) GetPackageVersion(ctx accspeccpi.Context) (*npm.Version, error) {
r, err := reader(a, vfsattr.Get(ctx), ctx)
if err != nil {
return nil, err
}
- buf := &bytes.Buffer{}
- _, err = io.Copy(buf, io.LimitReader(r, 200000))
+ defer r.Close()
+ buf, err := io.ReadAll(r)
if err != nil {
- return nil, errors.Wrapf(err, "cannot get version metadata for %s", a.PackageUrl())
+ return nil, errors.Wrapf(err, "cannot get version metadata for %s", a.PackageVersionUrl())
}
-
- var metadata meta
-
- err = json.Unmarshal(buf.Bytes(), &metadata)
- if err != nil {
- return nil, errors.Wrapf(err, "cannot unmarshal version metadata for %s", a.PackageUrl())
+ var version npm.Version
+ err = json.Unmarshal(buf, &version)
+ if err != nil || version.Dist.Tarball == "" {
+ // ugly fallback as workaround for https://github.com/sonatype/nexus-public/issues/224
+ var project npm.Project
+ err = json.Unmarshal(buf, &project) // parse the complete project
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot unmarshal version metadata for %s", a.PackageVersionUrl())
+ }
+ v, ok := project.Version[a.Version] // and pick only the specified version
+ if !ok {
+ return nil, errors.Newf("version '%s' doesn't exist", a.Version)
+ }
+ version = v
}
- return &metadata, nil
+ return &version, nil
}
////////////////////////////////////////////////////////////////////////////////
func newMethod(c accspeccpi.ComponentVersionAccess, a *AccessSpec) (accspeccpi.AccessMethodImpl, error) {
factory := func() (blobaccess.BlobAccess, error) {
- meta, err := a.getPackageMeta(c.GetContext())
+ meta, err := a.GetPackageVersion(c.GetContext())
if err != nil {
return nil, err
}
@@ -133,6 +146,20 @@ func newMethod(c accspeccpi.ComponentVersionAccess, a *AccessSpec) (accspeccpi.A
f := func() (io.ReadCloser, error) {
return reader(a, vfsattr.Get(c.GetContext()), c.GetContext(), meta.Dist.Tarball)
}
+ if meta.Dist.Integrity != "" {
+ tf := f
+ f = func() (io.ReadCloser, error) {
+ r, err := tf()
+ if err != nil {
+ return nil, err
+ }
+ digest, err := iotools.DecodeBase64ToHex(meta.Dist.Integrity)
+ if err != nil {
+ return nil, err
+ }
+ return iotools.VerifyingReaderWithHash(r, crypto.SHA512, digest), nil
+ }
+ }
if meta.Dist.Shasum != "" {
tf := f
f = func() (io.ReadCloser, error) {
@@ -149,15 +176,8 @@ func newMethod(c accspeccpi.ComponentVersionAccess, a *AccessSpec) (accspeccpi.A
return accspeccpi.NewDefaultMethodImpl(c, a, "", mime.MIME_TGZ, factory), nil
}
-type meta struct {
- Dist struct {
- Shasum string `json:"shasum"`
- Tarball string `json:"tarball"`
- } `json:"dist"`
-}
-
func reader(a *AccessSpec, fs vfs.FileSystem, ctx cpi.ContextProvider, tar ...string) (io.ReadCloser, error) {
- url := a.PackageUrl()
+ url := a.PackageVersionUrl()
if len(tar) > 0 {
url = tar[0]
}
@@ -170,12 +190,38 @@ func reader(a *AccessSpec, fs vfs.FileSystem, ctx cpi.ContextProvider, tar ...st
if err != nil {
return nil, err
}
- npm.Authorize(req, ctx, a.Registry, a.Package)
+ err = npm.BasicAuth(req, ctx, a.Registry, a.Package)
+ if err != nil {
+ return nil, err
+ }
c := &http.Client{}
resp, err := c.Do(req)
if err != nil {
return nil, err
}
+ defer resp.Body.Close()
+ if resp.StatusCode == http.StatusNotFound {
+ // maybe it's stupid Nexus - https://github.com/sonatype/nexus-public/issues/224?
+ url = a.PackageUrl()
+ req, err = http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
+ if err != nil {
+ return nil, err
+ }
+ err = npm.BasicAuth(req, ctx, a.Registry, a.Package)
+ if err != nil {
+ return nil, err
+ }
+
+ // close body before overwriting to close any pending connections
+ resp.Body.Close()
+ resp, err = c.Do(req)
+ if err != nil {
+ return nil, err
+ }
+
+ defer resp.Body.Close()
+ }
+
if resp.StatusCode != http.StatusOK {
defer resp.Body.Close()
buf := &bytes.Buffer{}
@@ -185,5 +231,9 @@ func reader(a *AccessSpec, fs vfs.FileSystem, ctx cpi.ContextProvider, tar ...st
}
return nil, errors.Newf("version meta data request %s provides %s: %s", url, resp.Status, buf.String())
}
- return resp.Body, nil
+ content, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+ return io.NopCloser(bytes.NewBuffer(content)), nil
}
diff --git a/pkg/contexts/ocm/accessmethods/npm/method_test.go b/pkg/contexts/ocm/accessmethods/npm/method_test.go
index dc4dbd251..97c8ec763 100644
--- a/pkg/contexts/ocm/accessmethods/npm/method_test.go
+++ b/pkg/contexts/ocm/accessmethods/npm/method_test.go
@@ -5,15 +5,15 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
- . "github.com/open-component-model/ocm/pkg/env"
- . "github.com/open-component-model/ocm/pkg/env/builder"
- . "github.com/open-component-model/ocm/pkg/testutils"
"github.com/open-component-model/ocm/pkg/contexts/ocm"
"github.com/open-component-model/ocm/pkg/contexts/ocm/accessmethods/npm"
"github.com/open-component-model/ocm/pkg/contexts/ocm/cpi"
+ . "github.com/open-component-model/ocm/pkg/env"
+ . "github.com/open-component-model/ocm/pkg/env/builder"
"github.com/open-component-model/ocm/pkg/iotools"
"github.com/open-component-model/ocm/pkg/mime"
+ . "github.com/open-component-model/ocm/pkg/testutils"
)
const NPMPATH = "/testdata/registry"
@@ -62,4 +62,20 @@ var _ = Describe("Method", func() {
_, err := m.Reader()
Expect(err).To(MatchError(ContainSubstring("SHA-1 digest mismatch: expected 44a77645201d1a8fc5213ace787c220eabbd0967, found 34a77645201d1a8fc5213ace787c220eabbd0967")))
})
+
+ It("PackageUrl()", func() {
+ packageUrl := "https://registry.npmjs.org/yargs"
+ acc := npm.New("https://registry.npmjs.org", "yargs", "17.7.1")
+ Expect(acc.PackageUrl()).To(Equal(packageUrl))
+ acc = npm.New("https://registry.npmjs.org/", "yargs", "17.7.1")
+ Expect(acc.PackageUrl()).To(Equal(packageUrl))
+ })
+
+ It("PackageVersionUrl()", func() {
+ packageVersionUrl := "https://registry.npmjs.org/yargs/17.7.1"
+ acc := npm.New("https://registry.npmjs.org", "yargs", "17.7.1")
+ Expect(acc.PackageVersionUrl()).To(Equal(packageVersionUrl))
+ acc = npm.New("https://registry.npmjs.org/", "yargs", "17.7.1")
+ Expect(acc.PackageVersionUrl()).To(Equal(packageVersionUrl))
+ })
})
diff --git a/pkg/contexts/ocm/blobhandler/handlers/generic/npm/blobhandler.go b/pkg/contexts/ocm/blobhandler/handlers/generic/npm/blobhandler.go
index 76032ffca..526b1f3dc 100644
--- a/pkg/contexts/ocm/blobhandler/handlers/generic/npm/blobhandler.go
+++ b/pkg/contexts/ocm/blobhandler/handlers/generic/npm/blobhandler.go
@@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
+ crds "github.com/open-component-model/ocm/pkg/contexts/credentials/cpi"
"github.com/open-component-model/ocm/pkg/contexts/ocm/accessmethods/npm"
"github.com/open-component-model/ocm/pkg/contexts/ocm/cpi"
"github.com/open-component-model/ocm/pkg/logging"
@@ -64,14 +65,8 @@ func (b *artifactHandler) StoreBlob(blob cpi.BlobAccess, _ string, _ string, _ c
log = log.WithValues("package", pkg.Name, "version", pkg.Version)
log.Debug("identified")
- token, err := npmLogin.BearerToken(ctx.GetContext(), b.spec.Url, pkg.Name)
- if err != nil {
- // we assume, it's not possible to publish anonymous - without token
- return nil, err
- }
-
// check if package exists
- exists, err := packageExists(b.spec.Url, *pkg, token)
+ exists, err := packageExists(b.spec.Url, *pkg, ctx.GetContext())
if err != nil {
return nil, err
}
@@ -104,8 +99,11 @@ func (b *artifactHandler) StoreBlob(blob cpi.BlobAccess, _ string, _ string, _ c
if err != nil {
return nil, err
}
- req.Header.Set("authorization", "Bearer "+token)
- req.Header.Set("content-type", "application/json")
+ err = npmLogin.Authorize(req, ctx.GetContext(), b.spec.Url, pkg.Name)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("Content-Type", "application/json")
// send PUT request - upload tgz
client := http.Client{}
@@ -127,13 +125,16 @@ func (b *artifactHandler) StoreBlob(blob cpi.BlobAccess, _ string, _ string, _ c
}
// Check if package already exists in npm registry. If it does, checks if it's the same.
-func packageExists(repoUrl string, pkg Package, token string) (bool, error) {
+func packageExists(repoUrl string, pkg Package, ctx crds.ContextProvider) (bool, error) {
client := http.Client{}
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, repoUrl+"/"+url.PathEscape(pkg.Name)+"/"+url.PathEscape(pkg.Version), nil)
if err != nil {
return false, err
}
- req.Header.Set("authorization", "Bearer "+token)
+ err = npmLogin.Authorize(req, ctx, repoUrl, pkg.Name)
+ if err != nil {
+ return false, err
+ }
resp, err := client.Do(req)
if err != nil {
return false, err
diff --git a/pkg/iotools/digests.go b/pkg/iotools/digests.go
new file mode 100644
index 000000000..ab5298849
--- /dev/null
+++ b/pkg/iotools/digests.go
@@ -0,0 +1,21 @@
+package iotools
+
+import (
+ "encoding/base64"
+ "encoding/hex"
+ "regexp"
+)
+
+// Regular expression matching: e.g. 'sha512-', 'SHA-1:', 'Sha-256:', 'sHA42-',.
+var re = regexp.MustCompile(`(?i)^sha(\d+-|\-\d+:)`)
+
+// DecodeBase64ToHex decodes a base64 encoded string and returns the hex representation.
+// Any prefix like 'sha512-' or 'SHA-256:' or 'Sha1-' is removed.
+func DecodeBase64ToHex(b64encoded string) (string, error) {
+ b64encoded = re.ReplaceAllString(b64encoded, "")
+ digest, err := base64.StdEncoding.DecodeString(b64encoded)
+ if err != nil {
+ return "", err
+ }
+ return hex.EncodeToString(digest), nil
+}
diff --git a/pkg/iotools/digests_test.go b/pkg/iotools/digests_test.go
new file mode 100644
index 000000000..980472223
--- /dev/null
+++ b/pkg/iotools/digests_test.go
@@ -0,0 +1,39 @@
+package iotools_test
+
+import (
+ "crypto"
+ "encoding/base64"
+ "encoding/hex"
+
+ . "github.com/onsi/ginkgo/v2"
+ . "github.com/onsi/gomega"
+
+ "github.com/open-component-model/ocm/pkg/iotools"
+)
+
+var _ = Describe("digests.go tests", func() {
+ It("DecodeBase64ToHex", func() {
+ hx, err := iotools.DecodeBase64ToHex("04cXMnFlKzgudf//lH/VqGUtFkplvGv0BCmPREEJsVYTJrxyiBFlsOiZIrjPENBkHWPnK6kOG53VTiqtsILNgw==")
+ Expect(err).To(BeNil())
+ Expect(hx).To(Equal("d387173271652b382e75ffff947fd5a8652d164a65bc6bf404298f444109b1561326bc72881165b0e89922b8cf10d0641d63e72ba90e1b9dd54e2aadb082cd83"))
+
+ hx, err = iotools.DecodeBase64ToHex("sha512-04cXMnFlKzgudf//lH/VqGUtFkplvGv0BCmPREEJsVYTJrxyiBFlsOiZIrjPENBkHWPnK6kOG53VTiqtsILNgw==")
+ Expect(err).To(BeNil())
+ Expect(hx).To(Equal("d387173271652b382e75ffff947fd5a8652d164a65bc6bf404298f444109b1561326bc72881165b0e89922b8cf10d0641d63e72ba90e1b9dd54e2aadb082cd83"))
+
+ hx, err = iotools.DecodeBase64ToHex("SHA512-04cXMnFlKzgudf//lH/VqGUtFkplvGv0BCmPREEJsVYTJrxyiBFlsOiZIrjPENBkHWPnK6kOG53VTiqtsILNgw==")
+ Expect(err).To(BeNil())
+ Expect(hx).To(Equal("d387173271652b382e75ffff947fd5a8652d164a65bc6bf404298f444109b1561326bc72881165b0e89922b8cf10d0641d63e72ba90e1b9dd54e2aadb082cd83"))
+
+ hx, err = iotools.DecodeBase64ToHex("Sha-512:04cXMnFlKzgudf//lH/VqGUtFkplvGv0BCmPREEJsVYTJrxyiBFlsOiZIrjPENBkHWPnK6kOG53VTiqtsILNgw==")
+ Expect(err).To(BeNil())
+ Expect(hx).To(Equal("d387173271652b382e75ffff947fd5a8652d164a65bc6bf404298f444109b1561326bc72881165b0e89922b8cf10d0641d63e72ba90e1b9dd54e2aadb082cd83"))
+
+ s1 := crypto.SHA1.New()
+ s1.Write([]byte("hello"))
+ sum := s1.Sum(nil)
+ hx, err = iotools.DecodeBase64ToHex("sHa-1:" + base64.StdEncoding.EncodeToString(sum))
+ Expect(err).To(BeNil())
+ Expect(hx).To(Equal(hex.EncodeToString(sum)))
+ })
+})
diff --git a/pkg/npm/login.go b/pkg/npm/login.go
index 17f45b029..955750cdf 100644
--- a/pkg/npm/login.go
+++ b/pkg/npm/login.go
@@ -54,46 +54,71 @@ func Login(registry string, username string, password string, email string) (str
return token.Token, nil
}
+func GetCredentials(ctx cpi.ContextProvider, repoUrl string, pkgName string) (string, string, error) {
+ credentials, err := identity.GetCredentials(ctx, repoUrl, pkgName)
+ if err != nil {
+ return "", "", err
+ }
+ if credentials == nil {
+ return "", "", fmt.Errorf("no credentials found for %s. Couldn't access '%s'", repoUrl, pkgName)
+ }
+ return credentials.GetProperty(identity.ATTR_USERNAME), credentials.GetProperty(identity.ATTR_PASSWORD), nil
+}
+
// BearerToken retrieves the bearer token for the given repository URL and package name.
// Either it's setup in the credentials or it will login to the registry and retrieve it.
func BearerToken(ctx cpi.ContextProvider, repoUrl string, pkgName string) (string, error) {
// get credentials and TODO cache it
- cred := identity.GetCredentials(ctx, repoUrl, pkgName)
- if cred == nil {
- return "", fmt.Errorf("no credentials found for %s. Couldn't upload '%s'", repoUrl, pkgName)
+ credentials, err := identity.GetCredentials(ctx, repoUrl, pkgName)
+ if err != nil {
+ return "", err
+ }
+ if credentials == nil {
+ return "", fmt.Errorf("no credentials found for %s. Couldn't access '%s'", repoUrl, pkgName)
}
log := logging.Context().Logger(identity.REALM)
log.Debug("found credentials")
// check if token exists, if not login and retrieve token
- token := cred[identity.ATTR_TOKEN]
+ token := credentials.GetProperty(identity.ATTR_TOKEN)
if token != "" {
log.Debug("token found, skipping login")
return token, nil
}
// use user+pass+mail from credentials to login and retrieve bearer token
- username := cred[identity.ATTR_USERNAME]
- password := cred[identity.ATTR_PASSWORD]
- email := cred[identity.ATTR_EMAIL]
+ username := credentials.GetProperty(identity.ATTR_USERNAME)
+ password := credentials.GetProperty(identity.ATTR_PASSWORD)
+ email := credentials.GetProperty(identity.ATTR_EMAIL)
if username == "" || password == "" || email == "" {
return "", fmt.Errorf("credentials for %s are invalid. Username, password or email missing! Couldn't upload '%s'", repoUrl, pkgName)
}
- log = log.WithValues("user", username, "repo", repoUrl)
- log.Debug("login")
+ log.Debug("login", "user", username, "repo", repoUrl)
// TODO: check different kinds of .npmrc content
- return Login(repoUrl, username, password, email)
+ token, err = Login(repoUrl, username, password, email)
+ return token, err
}
// Authorize the given request with the bearer token for the given repository URL and package name.
// If the token is empty (login failed or credentials not found), it will not be set.
-func Authorize(req *http.Request, ctx cpi.ContextProvider, repoUrl string, pkgName string) {
+func Authorize(req *http.Request, ctx cpi.ContextProvider, repoUrl string, pkgName string) error {
token, err := BearerToken(ctx, repoUrl, pkgName)
if err != nil {
- log := logging.Context().Logger(identity.REALM)
- log.Debug("Couldn't authorize", "error", err.Error(), "repo", repoUrl, "package", pkgName)
+ return err
} else if token != "" {
- req.Header.Set("authorization", "Bearer "+token)
+ req.Header.Set("Authorization", "Bearer "+token)
+ }
+ return nil
+}
+
+func BasicAuth(req *http.Request, ctx cpi.ContextProvider, repoUrl string, pkgName string) error {
+ username, password, err := GetCredentials(ctx, repoUrl, pkgName)
+ if err != nil {
+ return err
+ }
+ if username != "" && password != "" {
+ req.SetBasicAuth(username, password)
}
+ return nil
}
diff --git a/pkg/npm/structs.go b/pkg/npm/structs.go
new file mode 100644
index 000000000..e3c52c6af
--- /dev/null
+++ b/pkg/npm/structs.go
@@ -0,0 +1,18 @@
+package npm
+
+type Dist struct {
+ Integrity string `json:"integrity"`
+ Shasum string `json:"shasum"`
+ Tarball string `json:"tarball"`
+}
+
+type Version struct {
+ Name string `json:"name"`
+ Version string `json:"version"`
+ Dist Dist `json:"dist"`
+}
+
+type Project struct {
+ Name string `json:"name"`
+ Version map[string]Version `json:"versions"`
+}