Skip to content
14 changes: 12 additions & 2 deletions cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"errors"
"fmt"
"os"
"time"

Expand Down Expand Up @@ -42,7 +43,16 @@ func downloadCmd() *cobra.Command {
acc = infoResult.Account

if errors.Is(lastErr, appstore.ErrPasswordTokenExpired) {
loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{Email: acc.Email, Password: acc.Password})
bagOutput, err := dependencies.AppStore.Bag(appstore.BagInput{})
if err != nil {
return fmt.Errorf("failed to get bag: %w", err)
}

loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{
Email: acc.Email,
Password: acc.Password,
Endpoint: bagOutput.AuthEndpoint,
})
Comment on lines -45 to +49
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, good catch. I had missed this before.

if err != nil {
return err
}
Expand Down Expand Up @@ -112,7 +122,7 @@ func downloadCmd() *cobra.Command {
retry.LastErrorOnly(true),
retry.DelayType(retry.FixedDelay),
retry.Delay(time.Millisecond),
retry.Attempts(2),
retry.Attempts(3),
retry.RetryIf(func(err error) bool {
lastErr = err

Expand Down
12 changes: 11 additions & 1 deletion cmd/get_version_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"errors"
"fmt"
"time"

"github.com/avast/retry-go"
Expand Down Expand Up @@ -37,7 +38,16 @@ func getVersionMetadataCmd() *cobra.Command {
acc = infoResult.Account

if errors.Is(lastErr, appstore.ErrPasswordTokenExpired) {
loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{Email: acc.Email, Password: acc.Password})
bagOutput, err := dependencies.AppStore.Bag(appstore.BagInput{})
if err != nil {
return fmt.Errorf("failed to get bag: %w", err)
}

loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{
Email: acc.Email,
Password: acc.Password,
Endpoint: bagOutput.AuthEndpoint,
})
if err != nil {
return err
}
Expand Down
12 changes: 11 additions & 1 deletion cmd/list_versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"errors"
"fmt"
"time"

"github.com/avast/retry-go"
Expand Down Expand Up @@ -36,7 +37,16 @@ func ListVersionsCmd() *cobra.Command {
acc = infoResult.Account

if errors.Is(lastErr, appstore.ErrPasswordTokenExpired) {
loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{Email: acc.Email, Password: acc.Password})
bagOutput, err := dependencies.AppStore.Bag(appstore.BagInput{})
if err != nil {
return fmt.Errorf("failed to get bag: %w", err)
}

loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{
Email: acc.Email,
Password: acc.Password,
Endpoint: bagOutput.AuthEndpoint,
})
if err != nil {
return err
}
Expand Down
12 changes: 11 additions & 1 deletion cmd/purchase.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"errors"
"fmt"
"time"

"github.com/avast/retry-go"
Expand Down Expand Up @@ -29,7 +30,16 @@ func purchaseCmd() *cobra.Command {
acc = infoResult.Account

if errors.Is(lastErr, appstore.ErrPasswordTokenExpired) {
loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{Email: acc.Email, Password: acc.Password})
bagOutput, err := dependencies.AppStore.Bag(appstore.BagInput{})
if err != nil {
return fmt.Errorf("failed to get bag: %w", err)
}

loginResult, err := dependencies.AppStore.Login(appstore.LoginInput{
Email: acc.Email,
Password: acc.Password,
Endpoint: bagOutput.AuthEndpoint,
})
if err != nil {
return err
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/appstore/appstore_bag.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,13 @@ func (t *appstore) Bag(input BagInput) (BagOutput, error) {
return BagOutput{}, fmt.Errorf("received unexpected status code: %d", res.StatusCode)
}

authEndpoint := res.Data.URLBag.AuthEndpoint
if authEndpoint == "" {
authEndpoint = PrivateAppStoreAPIPathAuthenticate
}

return BagOutput{
AuthEndpoint: res.Data.URLBag.AuthEndpoint,
AuthEndpoint: authEndpoint,
}, nil
}

Expand Down
23 changes: 22 additions & 1 deletion pkg/appstore/appstore_bag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ var _ = Describe("AppStore (Bag)", func() {
})
})

When("request is successful", func() {
When("request is successful with authenticateAccount in urlBag", func() {
const testAuthEndpoint = "https://example.com"

BeforeEach(func() {
Expand Down Expand Up @@ -117,4 +117,25 @@ var _ = Describe("AppStore (Bag)", func() {
Expect(out.AuthEndpoint).To(Equal(testAuthEndpoint))
})
})

When("request is successful but authenticateAccount is empty", func() {
BeforeEach(func() {
mockMachine.EXPECT().
MacAddress().
Return("aa:bb:cc:dd:ee:ff", nil)

mockBagClient.EXPECT().
Send(gomock.Any()).
Return(http.Result[bagResult]{
StatusCode: gohttp.StatusOK,
Data: bagResult{},
}, nil)
})

It("falls back to hardcoded auth endpoint", func() {
out, err := as.Bag(BagInput{})
Expect(err).ToNot(HaveOccurred())
Expect(out.AuthEndpoint).To(Equal(PrivateAppStoreAPIPathAuthenticate))
})
})
})
2 changes: 1 addition & 1 deletion pkg/appstore/appstore_purchase.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (t *appstore) purchaseWithParams(acc Account, app App, guid string, pricing
return ErrSubscriptionRequired
}

if res.Data.FailureType == FailureTypePasswordTokenExpired {
if res.Data.FailureType == FailureTypePasswordTokenExpired || res.Data.CustomerMessage == CustomerMessagePasswordChanged {
return ErrPasswordTokenExpired
Comment thread
birmacher marked this conversation as resolved.
Outdated
}

Expand Down
6 changes: 4 additions & 2 deletions pkg/appstore/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
CustomerMessageBadLogin = "MZFinance.BadLogin.Configurator_message"
CustomerMessageAccountDisabled = "Your account is disabled."
CustomerMessageSubscriptionRequired = "Subscription Required"
CustomerMessagePasswordChanged = "Your password has changed."

iTunesAPIDomain = "itunes.apple.com"
iTunesAPIPathSearch = "/search"
Expand All @@ -17,8 +18,9 @@ const (
PrivateInitDomain = "init." + iTunesAPIDomain
PrivateInitPath = "/bag.xml"

PrivateAppStoreAPIDomain = "buy." + iTunesAPIDomain
PrivateAppStoreAPIPathPurchase = "/WebObjects/MZFinance.woa/wa/buyProduct"
PrivateAppStoreAPIDomain = "buy." + iTunesAPIDomain
PrivateAppStoreAPIPathAuthenticate = "https://" + PrivateAppStoreAPIDomain + "/WebObjects/MZFinance.woa/wa/authenticate"
PrivateAppStoreAPIPathPurchase = "/WebObjects/MZFinance.woa/wa/buyProduct"
PrivateAppStoreAPIPathDownload = "/WebObjects/MZFinance.woa/wa/volumeStoreDownloadProduct"
Comment thread
birmacher marked this conversation as resolved.
Outdated

HTTPHeaderStoreFront = "X-Set-Apple-Store-Front"
Expand Down
Loading