From 4af00093239836267ea321cb940c856025390571 Mon Sep 17 00:00:00 2001 From: itzaname Date: Thu, 28 Sep 2017 19:27:53 -0400 Subject: [PATCH] Do some autistic shit --- item.go | 102 +++++------------------------------ message.go | 156 ----------------------------------------------------- product.go | 61 +++++++++++++++++++++ session.go | 17 ++++-- user.go | 37 +++++++++++++ 5 files changed, 122 insertions(+), 251 deletions(-) delete mode 100644 message.go create mode 100644 product.go create mode 100644 user.go diff --git a/item.go b/item.go index 4fc5505..0c1edef 100644 --- a/item.go +++ b/item.go @@ -7,16 +7,15 @@ import ( "io/ioutil" "net/http" "net/url" - "regexp" "strconv" ) // Item struct containing data on retrieved items type Item struct { - ProductID string - ItemID string - AssetID string - UserID string + ProductID int + ItemID int + AssetID int + UserID int UserName string Type string Name string @@ -24,83 +23,14 @@ type Item struct { Owned bool } -// ItemInfo return info of selected item -func (s *Session) ItemInfo(url string) (Item, error) { - var item Item - - resp, err := s.client.Get(url) - if err != nil { - return item, err - } - - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return item, fmt.Errorf("Failed to get item info. Status %d", resp.StatusCode) - } - - body, _ := ioutil.ReadAll(resp.Body) - page := string(body) - - pItem := regexp.MustCompile("data-product-id=\"(.+)\"").FindStringSubmatch(page) - if len(pItem) > 0 { - item.ProductID, err = safeRetrieve("data-product-id=\"(.+)\"", page) - if err != nil { - return item, err - } - item.CopyLocked = false - item.UserID, err = safeRetrieve("data-expected-seller-id=\"(.+)\"", page) - if err != nil { - return item, err - } - item.UserName, err = safeRetrieve("data-seller-name=\"(.+)\"", page) - if err != nil { - return item, err - } - } else { - item.ProductID = "locked" - item.CopyLocked = true - item.UserID = "" - item.UserName = "" - item.AssetID = "" - } - - asset := regexp.MustCompile("data-userasset-id=\"(.+)\"").FindStringSubmatch(page) - if len(asset) > 0 { - item.AssetID, err = safeRetrieve("data-userasset-id=\"(.+)\"", page) - if err != nil { - return item, err - } - item.Owned = true - } else { - item.AssetID = "" - item.Owned = false - } - - item.ItemID, err = safeRetrieve("data-item-id=\"(.+)\"", page) - if err != nil { - return item, err - } - item.Name, err = safeRetrieve("data-item-name=\"(.+)\"", page) - if err != nil { - return item, err - } - item.Type, err = safeRetrieve("data-asset-type=\"(.+)\"", page) - if err != nil { - return item, err - } - - return item, nil -} - // AddItem add item by id to inventory -func (s *Session) AddItem(id string, seller string) error { +func (s *Session) AddItem(id int, seller int) error { v := url.Values{} v.Set("rqtype", "purchase") - v.Set("productID", id) + v.Set("productID", strconv.Itoa(id)) v.Set("expectedCurrency", "1") v.Set("expectedPrice", "0") - v.Set("expectedSellerID", seller) + v.Set("expectedSellerID", strconv.Itoa(seller)) v.Set("userAssetID", "") resp, err := s.client.Post("https://www.roblox.com/api/item.ashx?"+v.Encode(), "application/json", bytes.NewBufferString("")) if err != nil { @@ -129,9 +59,9 @@ func (s *Session) AddItem(id string, seller string) error { } // RemoveItem will remove item from inventory -func (s *Session) RemoveItem(id string) error { +func (s *Session) RemoveItem(id int) error { v := url.Values{} - v.Set("assetId", id) + v.Set("assetId", strconv.Itoa(id)) resp, err := s.client.Post("https://www.roblox.com/asset/delete-from-inventory", "application/x-www-form-urlencoded", bytes.NewBufferString(v.Encode())) if err != nil { return err @@ -159,10 +89,10 @@ func (s *Session) RemoveItem(id string) error { } // GetModels will list models in inventory -func (s *Session) GetModels(user string) ([]Item, error) { +func (s *Session) GetModels(user int) ([]Item, error) { var Data []Item - resp, err := s.client.Get("https://www.roblox.com/users/inventory/list-json?assetTypeId=10&userId=" + user) + resp, err := s.client.Get("https://www.roblox.com/users/inventory/list-json?assetTypeId=10&userId=" + strconv.Itoa(user)) if err != nil { return Data, fmt.Errorf("Could not get list: %s", err) } @@ -182,18 +112,10 @@ func (s *Session) GetModels(user string) ([]Item, error) { itm := obj.(map[string]interface{}) iInfo := itm["Item"].(map[string]interface{}) iCreator := itm["Creator"].(map[string]interface{}) - Data = append(Data, Item{"", strconv.Itoa(int(iInfo["AssetId"].(float64))), "", strconv.Itoa(int(iCreator["Id"].(float64))), iCreator["Name"].(string), "Model", iInfo["Name"].(string), false, true}) + Data = append(Data, Item{0, int(iInfo["AssetId"].(float64)), 0, int(iCreator["Id"].(float64)), iCreator["Name"].(string), "Model", iInfo["Name"].(string), false, true}) } return Data, nil } return Data, fmt.Errorf("Could not get models. Status: %d", resp.StatusCode) } - -func safeRetrieve(pattern string, source string) (string, error) { - pItem := regexp.MustCompile(pattern).FindStringSubmatch(source) - if len(pItem) > 0 { - return pItem[1], nil - } - return "", fmt.Errorf("Could not find item on in string") -} diff --git a/message.go b/message.go deleted file mode 100644 index ea2650d..0000000 --- a/message.go +++ /dev/null @@ -1,156 +0,0 @@ -package roblox - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "strconv" -) - -// Message structure for message data -type Message struct { - ID string - Subject string - Body string - FromID string - FromName string -} - -// GetInbox makes a request to retrieve message list -func (s *Session) GetInbox() ([]Message, error) { - var messages []Message - resp, err := s.client.Get("https://www.roblox.com/messages/api/get-messages") - if err != nil { - return messages, err - } - - if resp.StatusCode == 200 { - var data map[string]interface{} - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return messages, err - } - - err = json.Unmarshal(body, &data) - if err != nil { - return messages, err - } - - collection, exists := data["Collection"] - if exists { - for _, value := range collection.([]interface{}) { - // We will assume if we got this far everything exists - msg := value.(map[string]interface{}) - sender := msg["Sender"].(map[string]interface{}) - - message := Message{} - message.ID = strconv.Itoa(int(msg["Id"].(float64))) - message.Subject = msg["Subject"].(string) - message.Body = msg["Body"].(string) - message.FromID = strconv.Itoa(int(sender["UserId"].(float64))) - message.FromName = sender["UserName"].(string) - messages = append(messages, message) - } - } - } - return messages, err -} - -// SendMessage will send a message via post -func (s *Session) SendMessage(subject string, body string, recipientid string) error { - reciever, err := strconv.Atoi(recipientid) - if err != nil { - return err - } - payload := map[string]interface{}{ - "subject": subject, - "body": body, - "recipientId": reciever, - } - data, err := json.Marshal(&payload) - if err != nil { - return err - } - - resp, err := s.client.Post("https://www.roblox.com/messages/send", "application/json", bytes.NewBuffer(data)) - if err != nil { - return err - } - - defer resp.Body.Close() - - // CSRF Token Status - if resp.StatusCode == 403 { - req, err := http.NewRequest("POST", "https://www.roblox.com/messages/send", bytes.NewBuffer(data)) - req.Header.Set("X-Csrf-Token", resp.Header["X-Csrf-Token"][0]) - req.Header.Set("Content-Type", "application/json") - - resp, err := s.client.Do(req) - if err != nil { - return err - } - - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return fmt.Errorf("Messaged send failed. Status %d", resp.StatusCode) - } - } - return nil -} - -// ArchiveMessages will archive a list of messages -func (s *Session) ArchiveMessages(ids []string) error { - if len(ids) <= 0 { - return fmt.Errorf("ID list was empty") - } - - // We do this because when we turn it to json it will look like [1,2,3] - // and not ["1","2","3"] - var newList []int - for i := 0; i < len(ids); i++ { - idString, err := strconv.Atoi(ids[i]) - if err != nil { - return err - } - newList = append(newList, idString) - } - - payload := map[string][]int{ - "messageIds": newList, - } - - data, err := json.Marshal(&payload) - if err != nil { - return err - } - - resp, err := s.client.Post("https://www.roblox.com/messages/api/archive-messages", "application/json", bytes.NewBuffer(data)) - if err != nil { - return err - } - - defer resp.Body.Close() - - // CSRF Token Status - if resp.StatusCode == 403 { - req, err := http.NewRequest("POST", "https://www.roblox.com/messages/api/archive-messages", bytes.NewBuffer(data)) - req.Header.Set("X-Csrf-Token", resp.Header["X-Csrf-Token"][0]) - req.Header.Set("Content-Type", "application/json") - - resp, err := s.client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return fmt.Errorf("Archive failed. Status %d", resp.StatusCode) - } - } - return nil -} diff --git a/product.go b/product.go new file mode 100644 index 0000000..5b79d4b --- /dev/null +++ b/product.go @@ -0,0 +1,61 @@ +package roblox + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "time" +) + +// Product contains info about a product +type Product struct { + TargetID int `json:"TargetId"` + ProductType string `json:"ProductType"` + AssetID int `json:"AssetId"` + ProductID int `json:"ProductId"` + Name string `json:"Name"` + Description string `json:"Description"` + AssetTypeID int `json:"AssetTypeId"` + Creator struct { + ID int `json:"Id"` + Name string `json:"Name"` + CreatorType string `json:"CreatorType"` + CreatorTargetID int `json:"CreatorTargetId"` + } `json:"Creator"` + IconImageAssetID int `json:"IconImageAssetId"` + Created time.Time `json:"Created"` + Updated time.Time `json:"Updated"` + PriceInRobux int `json:"PriceInRobux"` + PriceInTickets int `json:"PriceInTickets"` + Sales int `json:"Sales"` + IsNew bool `json:"IsNew"` + IsForSale bool `json:"IsForSale"` + IsPublicDomain bool `json:"IsPublicDomain"` + IsLimited bool `json:"IsLimited"` + IsLimitedUnique bool `json:"IsLimitedUnique"` + Remaining int `json:"Remaining"` + MinimumMembershipLevel int `json:"MinimumMembershipLevel"` + ContentRatingTypeID int `json:"ContentRatingTypeId"` +} + +// GetProduct will retrieve store information on a product +func (s *Session) GetProduct(id int) (*Product, error) { + resp, err := s.client.Get(fmt.Sprintf("http://api.roblox.com/marketplace/productinfo?assetId=%d", id)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var info Product + err = json.Unmarshal(data, &info) + if err != nil { + return nil, err + } + + return &info, nil +} diff --git a/session.go b/session.go index dafb584..950cd1e 100644 --- a/session.go +++ b/session.go @@ -9,30 +9,37 @@ import ( // Session struct for roblox login session data and members type Session struct { - ID string + ID int Username string client *http.Client } // New create a new session and logs in with provided data -func New(user string, pass string, id string) (*Session, error) { +func New(username, password string) (*Session, error) { cookieJar, _ := cookiejar.New(nil) client := &http.Client{ Jar: cookieJar, } v := url.Values{} - v.Set("username", user) - v.Set("password", pass) + v.Set("username", username) + v.Set("password", password) v.Set("submitLogin", "Log In") v.Set("ReturnUrl", "") - session := Session{id, user, client} + session := Session{0, username, client} resp, err := client.PostForm("https://www.roblox.com/newlogin", v) if resp.StatusCode != 200 { return &session, fmt.Errorf("Messaged send failed. Status %d", resp.StatusCode) } + info, err := session.GetUserInfo() + if err != nil { + return nil, fmt.Errorf("Failed to retrieve user information: %s", err) + } + + session.ID = info.UserID + return &session, err } diff --git a/user.go b/user.go new file mode 100644 index 0000000..71935e1 --- /dev/null +++ b/user.go @@ -0,0 +1,37 @@ +package roblox + +import ( + "encoding/json" + "io/ioutil" +) + +type UserInfo struct { + UserID int `json:"UserID"` + UserName string `json:"UserName"` + RobuxBalance int `json:"RobuxBalance"` + TicketsBalance int `json:"TicketsBalance"` + ThumbnailURL string `json:"ThumbnailUrl"` + IsAnyBuildersClubMember bool `json:"IsAnyBuildersClubMember"` +} + +// GetUserInfo will retrieve local user information +func (s *Session) GetUserInfo() (*UserInfo, error) { + resp, err := s.client.Get("http://www.roblox.com/mobileapi/userinfo") + if err != nil { + return nil, err + } + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + var info UserInfo + err = json.Unmarshal(data, &info) + if err != nil { + return nil, err + } + + return &info, nil +}