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
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
@@ -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()
@@ -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))
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -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())
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"
@@ -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 {
@@ -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

GitHub Actions / Lint

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

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

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
@@ -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)
24 changes: 24 additions & 0 deletions pkg/appstore/appstore_download_test.go
Original file line number Diff line number Diff line change
@@ -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().
6 changes: 2 additions & 4 deletions pkg/appstore/appstore_login.go
Original file line number Diff line number Diff line change
@@ -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
@@ -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

GitHub Actions / Lint

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

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

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

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

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

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

GitHub Actions / Lint

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

@@ -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

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 {
23 changes: 23 additions & 0 deletions pkg/appstore/appstore_login_test.go
Original file line number Diff line number Diff line change
@@ -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().
7 changes: 2 additions & 5 deletions pkg/appstore/appstore_purchase.go
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@ import (
"errors"
"fmt"
gohttp "net/http"
"strings"

"github.com/majd/ipatool/v2/pkg/http"
)
@@ -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")
}
23 changes: 23 additions & 0 deletions pkg/appstore/appstore_purchase_test.go
Original file line number Diff line number Diff line change
@@ -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().

Unchanged files with check annotations Beta

return v, nil
}
}
return "", ErrHeaderNotFound

Check failure on line 25 in pkg/http/result.go

GitHub Actions / Lint

return statements should not be cuddled if block has more than two lines (wsl)
}
if req.Referer() == appStoreAuthURL {
return http.ErrUseLastResponse
}
return nil

Check failure on line 60 in pkg/http/client.go

GitHub Actions / Lint

return with no blank line before (nlreturn)
},
Transport: &AddHeaderTransport{http.DefaultTransport},
},