package altvr // TODO: Handle paginates import ( "encoding/json" "errors" "fmt" "io" "log" "net/http" "net/url" "strconv" "strings" "github.com/PuerkitoBio/goquery" "golang.org/x/net/html" ) const ( _UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36" ) func (avr *AltVR) doLogin() error { u, _ := url.Parse("https://account.altvr.com/users/sign_in") client := &http.Client{Jar: avr.jar} req, err := http.NewRequest("GET", u.String(), nil) if err != nil { log.Fatalln(err) } req.Header.Set("User-Agent", _UA) resp, err := client.Do(req) if err != nil { log.Fatalln(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("Page unavailable (%d)", resp.StatusCode) } ctype := resp.Header.Get("content-Type") if !strings.HasPrefix(ctype, "text/html") { return errors.New("Invalid content type") } tokenizer := html.NewTokenizer(resp.Body) var authToken string found := false for { tokenType := tokenizer.Next() if tokenType == html.ErrorToken { err := tokenizer.Err() if err == io.EOF { break } return errors.New("Invalid content") } if tokenType == html.SelfClosingTagToken { token := tokenizer.Token() if "input" == token.Data { value := "" for _, a := range token.Attr { if a.Key == "name" { if a.Val == "authenticity_token" { found = true } } if a.Key == "value" { value = a.Val } } if found { authToken = value break } } } } if authToken == "" { return errors.New("Auth token not found") } postData := url.Values{ "authenticity_token": {authToken}, "utf8": {"✓"}, "user[tz_offset]": {"0"}, "user[remember_me]": {"1"}, "user[email]": {avr.username}, "user[password]": {avr.password}, } req, err = http.NewRequest("POST", u.String(), strings.NewReader(postData.Encode())) if err != nil { log.Fatalln(err) } req.Header.Set("User-Agent", _UA) resp, err = client.Do(req) if err != nil { log.Fatalln(err) } defer resp.Body.Close() avr.csrfToken = resp.Header.Get("X-CSRF-Token") // Load the HTML document doc, err := goquery.NewDocumentFromReader(resp.Body) if err != nil { return err } hrefProfile, loggedIn := doc.Find("body > div.main-wrapper > div.nav-bar > div > div > div:nth-child(2) > div:nth-child(2) > a").Attr("href") if !loggedIn { return errorLogin } avr.userID = strings.Replace(strings.Replace(hrefProfile, "/user_profile", "", -1), "/users/", "", -1) return nil } func (avr *AltVR) fetchMyUser() (User, error) { if avr.userID == "" { return User{}, errorLogin } body, err := avr.get("users/" + avr.userID) if err != nil { return User{}, err } var users Users json.Unmarshal(body, &users) return users.Users[0], nil } func (avr *AltVR) fetchClientIP() (string, error) { body, err := avr.get("client_ip.json") if err != nil { return "", err } var cip ClientIP json.Unmarshal(body, &cip) return cip.ClientIP, nil } func (avr *AltVR) fetchFriendships() ([]Friendship, error) { body, err := avr.get("friendships/friends?include_users=false&online=false&per=50&page=1") if err != nil { return []Friendship{}, err } var friendship Friendships json.Unmarshal(body, &friendship) return friendship.Friendships, nil } func (avr *AltVR) fetchFriendshipsOnline() ([]Friendship, error) { body, err := avr.get("friendships/friends?include_users=false&online=true&per=50&page=1") if err != nil { return []Friendship{}, err } var friendship Friendships json.Unmarshal(body, &friendship) return friendship.Friendships, nil } func (avr *AltVR) fetchUsers(userIDs ...string) ([]User, error) { if len(userIDs) == 0 { return []User{}, nil } body, err := avr.get("users/" + strings.Join(userIDs[:], ",")) if err != nil { return []User{}, err } var users Users json.Unmarshal(body, &users) return users.Users, nil } func (avr *AltVR) fetchPendingFriendshipRequests() ([]Friendship, error) { body, err := avr.get("friendships/incoming_friend_requests?include_users=false&per=50&page=1") if err != nil { return []Friendship{}, err } var friendship Friendships json.Unmarshal(body, &friendship) return friendship.Friendships, nil } func (avr *AltVR) acceptPendingFriendshipRequest(friendshipID string) error { _, err := avr.post("friendships/"+friendshipID+"/accept", strings.NewReader("")) //strings.NewReader(url.Values{}.Encode()) return err } func (avr *AltVR) denyPendingFriendshipRequest(friendshipID string) error { _, err := avr.post("friendships/"+friendshipID+"/deny", strings.NewReader("")) return err } func (avr *AltVR) fetchPendingConversations() ([]Conversation, error) { body, err := avr.get("conversations") if err != nil { return []Conversation{}, err } var conversations Conversations json.Unmarshal(body, &conversations) return conversations.Conversations, nil } func (avr *AltVR) postNewConversation(userID, message string) error { uid, _ := strconv.ParseUint(userID, 10, 64) jv, _ := json.Marshal(&ConversationNewMessageOutgoing{ Conversation: ConversationNewMessage{ UserID: uid, Subject: message, }}) _, err := avr.post("conversations.json", strings.NewReader(string(jv))) return err } func (avr *AltVR) markConversationAsRead(conversationID string) error { _, err := avr.post("conversations/"+conversationID+"/mark_as_read", strings.NewReader("")) return err }