Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customizable GUID #321

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ func initWithCommand(cmd *cobra.Command) {
verbose := cmd.Flag("verbose").Value.String() == "true"
interactive, _ := cmd.Context().Value("interactive").(bool)
format := util.Must(OutputFormatFromString(cmd.Flag("format").Value.String()))
guid := cmd.Flag("guid").Value.String()

dependencies.Logger = newLogger(format, verbose)
dependencies.OS = operatingsystem.New()
Expand All @@ -112,6 +113,7 @@ func initWithCommand(cmd *cobra.Command) {
OperatingSystem: dependencies.OS,
Keychain: dependencies.Keychain,
Machine: dependencies.Machine,
Guid: guid,
})

util.Must("", createConfigDirectory(dependencies.OS, dependencies.Machine))
Expand Down
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func rootCmd() *cobra.Command {
cmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "enables verbose logs")
cmd.PersistentFlags().BoolVarP(&nonInteractive, "non-interactive", "", false, "run in non-interactive session")
cmd.PersistentFlags().StringVar(&keychainPassphrase, "keychain-passphrase", "", "passphrase for unlocking keychain")
cmd.PersistentFlags().String("guid", "", "GUID used in HTTP requests")

cmd.AddCommand(authCmd())
cmd.AddCommand(downloadCmd())
Expand Down
17 changes: 17 additions & 0 deletions pkg/appstore/appstore.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package appstore

import (
"fmt"
"strings"

"github.com/majd/ipatool/v2/pkg/http"
"github.com/majd/ipatool/v2/pkg/keychain"
"github.com/majd/ipatool/v2/pkg/util/machine"
Expand Down Expand Up @@ -36,13 +39,15 @@
httpClient http.Client[interface{}]
machine machine.Machine
os operatingsystem.OperatingSystem
guid string
}

type Args struct {
Keychain keychain.Keychain
CookieJar http.CookieJar
OperatingSystem operatingsystem.OperatingSystem
Machine machine.Machine
Guid string
}

func NewAppStore(args Args) AppStore {
Expand All @@ -59,5 +64,17 @@
httpClient: http.NewClient[interface{}](clientArgs),
machine: args.Machine,
os: args.OperatingSystem,
guid: args.Guid,
}
}

func (t *appstore) getGuid() (string, error) {
if t.guid == "" {
if macAddr, err := t.machine.MacAddress(); err != nil {
return "", fmt.Errorf("failed to get mac address: %w", err)
} else {
t.guid = strings.ReplaceAll(strings.ToUpper(macAddr), ":", "")
}
}
return t.guid, nil

Check failure on line 79 in pkg/appstore/appstore.go

View workflow job for this annotation

GitHub Actions / Lint

return statements should not be cuddled if block has more than two lines (wsl)
}
6 changes: 2 additions & 4 deletions pkg/appstore/appstore_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,11 @@ func (t *appstore) Download(input DownloadInput) (DownloadOutput, error) {
return DownloadOutput{}, fmt.Errorf("failed to resolve destination path: %w", err)
}

macAddr, err := t.machine.MacAddress()
guid, err := t.getGuid()
if err != nil {
return DownloadOutput{}, fmt.Errorf("failed to get mac address: %w", err)
return DownloadOutput{}, fmt.Errorf("failed to get GUID: %w", err)
}

guid := strings.ReplaceAll(strings.ToUpper(macAddr), ":", "")

req := t.downloadRequest(input.Account, input.App, guid)

res, err := t.downloadClient.Send(req)
Expand Down
24 changes: 24 additions & 0 deletions pkg/appstore/appstore_download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,30 @@ var _ = Describe("AppStore (Download)", func() {
})
})

When("user provides GUID", func() {
BeforeEach(func() {
as.(*appstore).guid = "GUID"
mockMachine.EXPECT().MacAddress().Times(0)
mockOS.EXPECT().Getwd().Return("", nil)
mockDownloadClient.EXPECT().
Send(gomock.Any()).
Do(func(req http.Request) {
Expect(req.Payload).To(BeAssignableToTypeOf(&http.XMLPayload{}))
x := req.Payload.(*http.XMLPayload)
Expect(x.Content).To(HaveKeyWithValue("guid", "GUID"))
}).
Return(http.Result[downloadResult]{}, errors.New(""))
})
AfterEach(func() {
as.(*appstore).guid = ""
})

It("sends the HTTP request with the specified GUID", func() {
_, err := as.Download(DownloadInput{})
Expect(err).To(HaveOccurred())
})
})

When("request fails", func() {
BeforeEach(func() {
mockOS.EXPECT().
Expand Down
6 changes: 2 additions & 4 deletions pkg/appstore/appstore_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@
}

func (t *appstore) Login(input LoginInput) (LoginOutput, error) {
macAddr, err := t.machine.MacAddress()
guid, err := t.getGuid()
if err != nil {
return LoginOutput{}, fmt.Errorf("failed to get mac address: %w", err)
return LoginOutput{}, fmt.Errorf("failed to get GUID: %w", err)
}

guid := strings.ReplaceAll(strings.ToUpper(macAddr), ":", "")

acc, err := t.login(input.Email, input.Password, input.AuthCode, guid)
if err != nil {
return LoginOutput{}, err
Expand Down Expand Up @@ -63,19 +61,19 @@

func (t *appstore) login(email, password, authCode, guid string) (Account, error) {
redirect := ""
var err error

Check failure on line 64 in pkg/appstore/appstore_login.go

View workflow job for this annotation

GitHub Actions / Lint

declarations should never be cuddled (wsl)
retry := true

Check failure on line 65 in pkg/appstore/appstore_login.go

View workflow job for this annotation

GitHub Actions / Lint

assignments should only be cuddled with other assignments (wsl)
var res http.Result[loginResult]

Check failure on line 66 in pkg/appstore/appstore_login.go

View workflow job for this annotation

GitHub Actions / Lint

declarations should never be cuddled (wsl)

for attempt := 1; retry && attempt <= 4; attempt++ {
ac := authCode
if attempt == 1 {
ac = ""
}
request := t.loginRequest(email, password, ac, guid, attempt)

Check failure on line 73 in pkg/appstore/appstore_login.go

View workflow job for this annotation

GitHub Actions / Lint

assignments should only be cuddled with other assignments (wsl)
request.URL, redirect = util.IfEmpty(redirect, request.URL), ""

Check failure on line 74 in pkg/appstore/appstore_login.go

View workflow job for this annotation

GitHub Actions / Lint

ineffectual assignment to redirect (ineffassign)
res, err = t.loginClient.Send(request)
if err != nil {

Check failure on line 76 in pkg/appstore/appstore_login.go

View workflow job for this annotation

GitHub Actions / Lint

only one cuddle assignment allowed before if statement (wsl)
return Account{}, fmt.Errorf("request failed: %w", err)
}

Expand Down Expand Up @@ -136,7 +134,7 @@
} else if res.StatusCode != 200 || res.Data.PasswordToken == "" || res.Data.DirectoryServicesID == "" {
err = NewErrorWithMetadata(errors.New("something went wrong"), res)
}
return

Check failure on line 137 in pkg/appstore/appstore_login.go

View workflow job for this annotation

GitHub Actions / Lint

return statements should not be cuddled if block has more than two lines (wsl)
}

func (t *appstore) loginRequest(email, password, authCode, guid string, attempt int) http.Request {
Expand Down
23 changes: 23 additions & 0 deletions pkg/appstore/appstore_login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,29 @@ var _ = Describe("AppStore (Login)", func() {
})
})

When("user provides GUID", func() {
BeforeEach(func() {
as.(*appstore).guid = "GUID"
mockMachine.EXPECT().MacAddress().Times(0)
mockClient.EXPECT().
Send(gomock.Any()).
Do(func(req http.Request) {
Expect(req.Payload).To(BeAssignableToTypeOf(&http.XMLPayload{}))
x := req.Payload.(*http.XMLPayload)
Expect(x.Content).To(HaveKeyWithValue("guid", "GUID"))
}).
Return(http.Result[loginResult]{}, errors.New(""))
})
AfterEach(func() {
as.(*appstore).guid = ""
})

It("sends the HTTP request with the specified GUID", func() {
_, err := as.Login(LoginInput{})
Expect(err).To(HaveOccurred())
})
})

When("successfully reads machine's MAC address", func() {
BeforeEach(func() {
mockMachine.EXPECT().
Expand Down
7 changes: 2 additions & 5 deletions pkg/appstore/appstore_purchase.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
gohttp "net/http"
"strings"

"github.com/majd/ipatool/v2/pkg/http"
)
Expand All @@ -21,13 +20,11 @@ type PurchaseInput struct {
}

func (t *appstore) Purchase(input PurchaseInput) error {
macAddr, err := t.machine.MacAddress()
guid, err := t.getGuid()
if err != nil {
return fmt.Errorf("failed to get mac address: %w", err)
return fmt.Errorf("failed to get GUID: %w", err)
}

guid := strings.ReplaceAll(strings.ToUpper(macAddr), ":", "")

if input.App.Price > 0 {
return errors.New("purchasing paid apps is not supported")
}
Expand Down
23 changes: 23 additions & 0 deletions pkg/appstore/appstore_purchase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,29 @@ var _ = Describe("AppStore (Purchase)", func() {
})
})

When("user provides GUID", func() {
BeforeEach(func() {
as.guid = "GUID"
mockMachine.EXPECT().MacAddress().Times(0)
mockPurchaseClient.EXPECT().
Send(gomock.Any()).
Do(func(req http.Request) {
Expect(req.Payload).To(BeAssignableToTypeOf(&http.XMLPayload{}))
x := req.Payload.(*http.XMLPayload)
Expect(x.Content).To(HaveKeyWithValue("guid", "GUID"))
}).
Return(http.Result[purchaseResult]{}, errors.New(""))
})
AfterEach(func() {
as.guid = ""
})

It("sends the HTTP request with the specified GUID", func() {
err := as.Purchase(PurchaseInput{})
Expect(err).To(HaveOccurred())
})
})

When("app is paid", func() {
BeforeEach(func() {
mockMachine.EXPECT().
Expand Down
Loading