346 lines
12 KiB
Go
346 lines
12 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/cookiejar"
|
|
"net/url"
|
|
"os"
|
|
"path"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
//Amazon account structs
|
|
type AmazonBearer struct {
|
|
CustomerId string `json:"customer_id"`
|
|
Extensions struct {
|
|
DeviceInfo struct {
|
|
DeviceSN string `json:"device_serial_number"`
|
|
DeviceType string `json:"device_type"`
|
|
DeviceName string `json:"device_name"`
|
|
} `json:"device_info"`
|
|
CustomerInfo struct {
|
|
Name string `json:"name"`
|
|
HomeRegion string `json:"home_region"`
|
|
AccountPool string `json:"account_pool"`
|
|
GivenName string `json:"given_name"`
|
|
UserId string `json:"user_id"`
|
|
} `json:"customer_info"`
|
|
} `json:"extensions"`
|
|
Tokens struct {
|
|
MacDMS struct {
|
|
ADPToken string `json:"adp_token"`
|
|
DevicePrivateKey string `json:"device_private_key"`
|
|
} `json:"mac_dms"`
|
|
StoreAuthCookie struct {
|
|
Cookie string `json:"cookie"`
|
|
} `json:"store_authentication_cookie"`
|
|
Bearer struct {
|
|
AccessToken string `json:"access_token"`
|
|
ExpiresIn string `json:"expires_in"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
} `json:"bearer"`
|
|
} `json:"tokens"`
|
|
}
|
|
|
|
type AmazonApi struct {
|
|
Payload struct {
|
|
AuthData struct {
|
|
Global string `json:"use_global_authentication"`
|
|
User struct {
|
|
UserId string `json:"user_id"`
|
|
Password string `json:"password"`
|
|
} `json:"user_id_password"`
|
|
AccessToken string `json:"access_token,omitempty"`
|
|
} `json:"auth_data"`
|
|
RegistrationData struct {
|
|
Domain string `json:"domain"`
|
|
Type string `json:"device_type"`
|
|
Serial string `json:"device_serial"`
|
|
AppName string `json:"app_name"`
|
|
AppVersion string `json:"app_version"`
|
|
Model string `json:"device_model"`
|
|
OSVersion string `json:"os_version"`
|
|
SoftwareVersion string `json:"software_version"`
|
|
} `json:"registration_data"`
|
|
RequestedToken []string `json:"requested_token_type"`
|
|
Cookies struct {
|
|
Domain string `json:"domain"`
|
|
Website []string `json:"website_cookies"`
|
|
} `json:"cookies"`
|
|
UserContext struct {
|
|
Frc string `json:"frc"`
|
|
} `json:"user_context_map"`
|
|
DeviceMetadata DeviceMetadata `json:"device_metadata"`
|
|
Extenstions []string `json:"requested_extensions"`
|
|
} `json:"api_payload"`
|
|
Headers struct {
|
|
Login string `json:"login"`
|
|
Refresh string `json:"refresh"`
|
|
Main string `json:"main"`
|
|
Instance string `json:"app_instance"`
|
|
MapVersion MapVersion `json:"map_version"`
|
|
} `json:"headers"`
|
|
}
|
|
type DeviceMetadata struct {
|
|
DeviceOS string `json:"device_os_family"`
|
|
DeviceType string `json:"device_type"`
|
|
DeviceSerial string `json:"device_serial"`
|
|
MacAddress string `json:"mac_address"`
|
|
IMEI string `json:"imei"`
|
|
Manufacturer string `json:"manufacturer"`
|
|
Model string `json:"model"`
|
|
OSVersion string `json:"os_version"`
|
|
AndroidID string `json:"android_id"`
|
|
BuildSerial string `json:"build_serial"`
|
|
Product string `json:"product"`
|
|
}
|
|
type MapVersion struct {
|
|
Version string `json:"current_version"`
|
|
Package string `json:"package_name"`
|
|
Platform string `json:"platform"`
|
|
}
|
|
type RefreshPayload struct {
|
|
AppName string `json:"app_name"`
|
|
AppVersion string `json:"app_version"`
|
|
SourceType string `json:"source_token_type"`
|
|
Token string `json:"source_token"`
|
|
RequestedType string `json:"requested_token_type"`
|
|
MetaData DeviceMetadata `json:"device_metadata"`
|
|
MapVersion MapVersion `json:"map_version"`
|
|
}
|
|
type LoginResponse struct {
|
|
Response struct {
|
|
Success *AmazonBearer `json:"success"`
|
|
Challenge *struct {
|
|
Reason string `json:"challenge_reason"`
|
|
URI string `json:"uri"`
|
|
Method string `json:"required_authentication_method"`
|
|
Context string `json:"challenge_context"`
|
|
} `json:"challenge"`
|
|
} `json:"response"`
|
|
}
|
|
|
|
var (
|
|
TokenExpire time.Time
|
|
api = new(AmazonApi)
|
|
bearer = new(AmazonBearer)
|
|
)
|
|
|
|
func (bearer *AmazonBearer) Save(expiretime time.Time, acctpath string) {
|
|
bearer_file, _ := os.Create(path.Join(acctpath, "amazon-bearer.json"))
|
|
json.NewEncoder(bearer_file).Encode(bearer)
|
|
bearer_file.Close()
|
|
_ = os.Chtimes(".amazon-bearer", time.Now().Local(), expiretime.Add(-1*time.Hour))
|
|
}
|
|
|
|
func (api *AmazonApi) Load(acctpath string) {
|
|
api_file, err := os.Open(path.Join(acctpath, "amazon-api.json"))
|
|
if err != nil {
|
|
api.New()
|
|
} else {
|
|
json.NewDecoder(api_file).Decode(&api)
|
|
api_file.Close()
|
|
}
|
|
}
|
|
|
|
func login() {
|
|
b := new(bytes.Buffer)
|
|
json.NewEncoder(b).Encode(api.Payload)
|
|
client := &http.Client{}
|
|
req, _ := http.NewRequest("POST", "https://api.amazon.com/auth/register", b)
|
|
uuid, _ := uuid.NewRandom()
|
|
req.Header.Add("X-Amzn-RequestId", uuid.String())
|
|
req.Header.Add("x-amzn-identity-auth-domain", ".amazon.com")
|
|
req.Header.Add("User-Agent", api.Headers.Login)
|
|
req.Header.Add("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
var response LoginResponse
|
|
defer resp.Body.Close()
|
|
json.NewDecoder(resp.Body).Decode(&response)
|
|
if response.Response.Success != nil {
|
|
bearer = response.Response.Success
|
|
currenttime := time.Now().Local()
|
|
expire, _ := strconv.Atoi(bearer.Tokens.Bearer.ExpiresIn)
|
|
TokenExpire = currenttime.Add(time.Second * time.Duration(expire))
|
|
fmt.Println("Login Succeeded for Device: " + bearer.Extensions.DeviceInfo.DeviceName)
|
|
} else if response.Response.Challenge != nil {
|
|
scanner := bufio.NewScanner(os.Stdin)
|
|
cookieJar, _ := cookiejar.New(nil)
|
|
client2 := &http.Client{Jar: cookieJar}
|
|
uri, _ := url.Parse(response.Response.Challenge.URI)
|
|
data := uri.Query()
|
|
data.Add("openid.pape.max_auth_age", "0")
|
|
data.Add("openid.identity", "http://specs.openid.net/auth/2.0/identifier_select")
|
|
data.Add("accountStatusPolicy", "P1")
|
|
data.Add("language", "en_US")
|
|
data.Add("openid.return_to", "https://www.amazon.com/ap/maplanding")
|
|
data.Add("openid.assoc_handle", "amzn_device_na")
|
|
data.Add("openid.oa2.response_type", "token")
|
|
data.Add("openid.mode", "checkid_setup")
|
|
data.Add("openid.ns.pape", "http://specs.openid.net/extensions/pape/1.0")
|
|
data.Add("openid.ns.oa2", "http://www.amazon.com/ap/ext/oauth/2")
|
|
data.Add("openid.oa2.scope", "device_auth_access")
|
|
data.Add("openid.claimed_id", "http://specs.openid.net/auth/2.0/identifier_select")
|
|
data.Add("openid.oa2.client_id", "device:"+api.Payload.RegistrationData.Serial)
|
|
data.Add("disableLoginPrepopulate", "0")
|
|
data.Add("openid.ns", "http://specs.openid.net/auth/2.0")
|
|
uri.RawQuery = data.Encode()
|
|
req2, _ := http.NewRequest("GET", uri.String(), nil)
|
|
req2.Header.Add("x-amzn-identity-auth-domain", ".amazon.com")
|
|
req2.Header.Add("User-Agent", api.Headers.Login)
|
|
resp2, err := client2.Do(req2)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
referer := resp2.Request.URL.String()
|
|
fmt.Println(referer)
|
|
defer resp2.Body.Close()
|
|
body, err := ioutil.ReadAll(resp2.Body)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
client3 := &http.Client{Jar: cookieJar, CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
return http.ErrUseLastResponse
|
|
}}
|
|
if response.Response.Challenge.Reason == "MissingRequiredAuthenticationData" {
|
|
if response.Response.Challenge.Method == "OTPCode" {
|
|
fmt.Println("Account set for 2 Factor Authentication")
|
|
fmt.Print("Enter One Time Code: ")
|
|
scanner.Scan()
|
|
otp := scanner.Text()
|
|
re := regexp.MustCompile(`<input type="hidden" name="(.+?)" value="(.+?)"`)
|
|
stuff := re.FindAllStringSubmatch(string(body), -1)
|
|
data2 := url.Values{}
|
|
for _, value := range stuff {
|
|
data2.Set(value[1], value[2])
|
|
}
|
|
data2.Set("otpCode", otp)
|
|
data2.Set("rememberDevice", "")
|
|
req3, _ := http.NewRequest("POST", "https://www.amazon.com/ap/signin", strings.NewReader(data2.Encode()))
|
|
req3.Header.Add("x-amzn-identity-auth-domain", ".amazon.com")
|
|
req3.Header.Add("User-Agent", api.Headers.Login)
|
|
req3.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
resp3, err := client3.Do(req3)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
if resp3.StatusCode == 302 {
|
|
redir := resp3.Header.Get("Location")
|
|
if strings.Contains(redir, "maplanding") {
|
|
fmt.Println("2FA Authentication Successful")
|
|
redir_url, _ := url.Parse(redir)
|
|
data3 := redir_url.Query()
|
|
token := data3.Get("openid.oa2.access_token")
|
|
api.Payload.AuthData.AccessToken = token
|
|
login()
|
|
}
|
|
}
|
|
} else {
|
|
fmt.Println(response.Response.Challenge)
|
|
fmt.Println("MissingRequiredAuthenticationData - Unknown Method")
|
|
os.Exit(0)
|
|
}
|
|
} else if response.Response.Challenge.Reason == "HandleOnWebView" {
|
|
fmt.Println("HandleOnWebView")
|
|
if strings.Contains(referer, "CAPTCHA") {
|
|
fmt.Println("CAPTCHA Verification Required", "Sorry we can't currently handle that")
|
|
os.Exit(0)
|
|
} else {
|
|
fmt.Println("Verification Code Required")
|
|
re := regexp.MustCompile(`<input type="hidden" name="(.+?)" value="(.+?)"`)
|
|
stuff := re.FindAllStringSubmatch(string(body), -1)
|
|
data2 := url.Values{}
|
|
for _, value := range stuff {
|
|
data2.Set(value[1], value[2])
|
|
}
|
|
data2.Set("option", "email")
|
|
req3, _ := http.NewRequest("POST", "https://www.amazon.com/ap/cvf/verify", strings.NewReader(data2.Encode()))
|
|
req3.Header.Add("x-amzn-identity-auth-domain", ".amazon.com")
|
|
req3.Header.Add("User-Agent", api.Headers.Login)
|
|
req3.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
resp3, err := client2.Do(req3)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
if resp3.StatusCode == 200 {
|
|
fmt.Println("Code Sent to Email")
|
|
fmt.Print("Verification Code: ")
|
|
scanner.Scan()
|
|
data2.Del("option")
|
|
data2.Set("code", scanner.Text())
|
|
data2.Set("action", "code")
|
|
req4, _ := http.NewRequest("POST", "https://www.amazon.com/ap/cvf/verify", strings.NewReader(data2.Encode()))
|
|
req4.Header.Add("x-amzn-identity-auth-domain", ".amazon.com")
|
|
req4.Header.Add("User-Agent", api.Headers.Login)
|
|
req4.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
resp4, err := client3.Do(req4)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
if resp4.StatusCode == 302 {
|
|
redir := resp4.Header.Get("Location")
|
|
if strings.Contains(redir, "signin") || strings.Contains(redir, "auth") {
|
|
req5, _ := http.NewRequest("GET", redir, nil)
|
|
req5.Header.Add("x-amzn-identity-auth-domain", ".amazon.com")
|
|
req5.Header.Add("User-Agent", api.Headers.Login)
|
|
resp5, err := client3.Do(req5)
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
}
|
|
if resp5.StatusCode == 302 {
|
|
redir2 := resp5.Header.Get("Location")
|
|
if strings.Contains(redir2, "maplanding") {
|
|
fmt.Println("Verification Successful")
|
|
redir_url, _ := url.Parse(redir2)
|
|
data3 := redir_url.Query()
|
|
token := data3.Get("openid.oa2.access_token")
|
|
api.Payload.AuthData.AccessToken = token
|
|
login()
|
|
} else {
|
|
fmt.Println("Error With Redirect 2", redir)
|
|
os.Exit(0)
|
|
}
|
|
} else {
|
|
fmt.Printf("%d:Error Logging In 2", resp4.StatusCode)
|
|
os.Exit(0)
|
|
}
|
|
} else {
|
|
fmt.Println("Error With Redirect", redir)
|
|
os.Exit(0)
|
|
}
|
|
} else {
|
|
fmt.Printf("%d:Error Logging In", resp4.StatusCode)
|
|
os.Exit(0)
|
|
}
|
|
}
|
|
}
|
|
} else if response.Response.Challenge.Reason == "AuthenticationFailed" {
|
|
fmt.Println("Login Failed - Incorrect User/Pass")
|
|
os.Exit(0)
|
|
} else {
|
|
fmt.Println(response.Response.Challenge)
|
|
fmt.Println("Login Failed due to Challenge")
|
|
os.Exit(0)
|
|
}
|
|
} else {
|
|
fmt.Println("Login Failed for unknown reason")
|
|
fmt.Println(resp.Status)
|
|
io.Copy(os.Stdout, resp.Body)
|
|
os.Exit(0)
|
|
}
|
|
}
|