Skip to content
This repository has been archived by the owner on Apr 13, 2024. It is now read-only.

Commit

Permalink
optimization, error checking
Browse files Browse the repository at this point in the history
  • Loading branch information
tioffs committed Oct 15, 2021
1 parent aac0e77 commit 41fc0b3
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 94 deletions.
50 changes: 35 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@
```go
package main
import "github.com/tioffs/tgah"
import (
"context"
"fmt"
"os"
"time"
"github.com/tioffs/tgah"
)
func main() {
// phone number no +
Expand All @@ -28,27 +35,40 @@ func main() {
// set setting
tgah.Setting(int32(botID), domain)
// send push notify user (Auth)
if err := tgah.SendPhoneTelegram(phone); err != nil {
panic(err)
if confirm := tgah.SendPhoneTelegram(context.Background(), phone);
confirm.Error != nil || confirm.Status != tgah.Success {
panic(confirm.Error)
}
// check accept user is auth you bot
user, err := tgah.ChecksIsAcceptUserAuth(phone)
if err != nil {
panic(err)
for {
<-time.After(3 * time.Second)
confirm := tgah.ChecksIsAcceptUserAuth(context.Background(), phone)
if confirm.Error != nil {
panic(confirm.Error)
}
switch confirm.Status {
case tgah.Success:
fmt.Println(confirm.User)
break
case tgah.Cancel:
panic(confirm.Error)
case tgah.Pending:
println(tgah.Pending)
}
}
println(user)
}
```
#### User profile
```go
type User struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
Username string `json:"username"`
PhotoURL string `json:"photo_url"`
AuthDate int `json:"auth_date"`
Hash string `json:"hash"`
Phone string `json:"phone"`
type user struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Username string `json:"username"`
PhotoURL string `json:"photo_url"`
AuthDate int `json:"auth_date"`
Hash string `json:"hash"`
Phone string `json:"phone"`
}
```
153 changes: 95 additions & 58 deletions auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
"io/ioutil"
"net/http"
"regexp"
"strconv"
"strings"
"time"

"github.com/pkg/errors"
)

type status string

const (
// regxConfirm regx parse hash.
regxConfirm = `hash=([a-z0-9]+)`
Expand All @@ -30,22 +31,26 @@ const (
confirmURL = oauthURL + "auth/push?bot_id=%d&origin=%s&request_access=write"
// sendPhoneURL endpoint.
sendPhoneURL = oauthURL + "auth/request?bot_id=%d&origin=%s&embed=1&request_access=write"
// phone send params body.
phone = "phone=%s"
// cleanupInterval clean cache time second.
cleanupInterval = 10
// expires default time second cache delete.
expires = 60
// cookiesDELETE const status cookie header.
cookiesDELETE = "DELETED"
// declined User cancel auth.
declined = "Declined by the User"
// declined user Cancel auth.
declined = "Declined by the user"
// trueStr check string true.
trueStr = "true"
// Pending status.
Pending status = "pending"
// Cancel status.
Cancel status = "cancel"
// Success status.
Success status = "success"
)

// User struct telegram oauth info User.
type User struct {
// user struct telegram oauth info user.
type user struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Expand All @@ -61,11 +66,17 @@ type item struct {
Created int64
}

type confirmUser struct {
PhoneNumber string
// Confirm struct status, error checks.
type Confirm struct {
Phone string `json:"-"`
User *user `json:"user,omitempty"`
Status status `json:"status"`
Error *string `json:"error,omitempty"`
hash string
context context.Context
}

// store memory auth telegram User.
// store memory auth telegram user.
var store = make(map[string]item)

// domainUrl site connect bot telegram auth.
Expand All @@ -74,7 +85,7 @@ var domainURL string
// bot id bot telegram.
var bot int32

// statusCache is auto delete cache not auth User.
// statusCache is auto delete cache not auth user.
var statusCache = false

// cache goroutine checking and delete item cache memory.
Expand Down Expand Up @@ -121,105 +132,131 @@ func Setting(botID int32, domain string) {
bot = botID
}

// SendPhoneTelegram send push notify telegram User phone.
func SendPhoneTelegram(userPhone string) (err error) {
confirm := &confirmUser{PhoneNumber: userPhone}
phone := fmt.Sprintf(phone, userPhone)
response, err := confirm.httpClient(fmt.Sprintf(sendPhoneURL, bot, domainURL), http.MethodPost, &phone)
// SendPhoneTelegram send push notify telegram user phone.
func SendPhoneTelegram(ctx context.Context, userPhone string) (confirm *Confirm) {
confirm = &Confirm{Phone: userPhone, context: ctx, Status: Cancel}
response, err := confirm.httpClient(fmt.Sprintf(sendPhoneURL, bot, domainURL), http.MethodPost, confirm.pointerString(fmt.Sprintf("phone=%s", userPhone)))
if err != nil {
confirm.Error = confirm.pointerString(err.Error())

return
}
statusSendNotify, err := strconv.ParseBool(string(response))
if err != nil {
confirm.Error = confirm.pointerString(string(response))

if string(response) != "true" {
err = errors.New(string(response))
return
}
if !statusSendNotify {
confirm.Error = confirm.pointerString(string(response))

return
}

confirm.Status = Success

return
}

// ChecksIsAcceptUserAuth Checks Accept User Authentication.
func ChecksIsAcceptUserAuth(userPhone string) (userProfile *User, err error) {
confirm := &confirmUser{PhoneNumber: userPhone}
status, err := confirm.inAccept()
if err != nil {
// ChecksIsAcceptUserAuth Checks Accept user Authentication.
func ChecksIsAcceptUserAuth(ctx context.Context, userPhone string) (confirm *Confirm) {
confirm = &Confirm{Phone: userPhone, context: ctx}
confirm.inAccept()
if confirm.Status != Success {
return
}
if !status {
confirm.parseHash()
if confirm.Status == Cancel {
return
}
hash, err := confirm.parseHash()
if err != nil {
return
}

if err = confirm.isConfirm(hash); err != nil {
confirm.isConfirm()
if confirm.Status == Cancel {
return
}
userProfile, err = confirm.parseUserProfile()
confirm.parseUserProfile()

return
}

func (c *confirmUser) inAccept() (status bool, err error) {
status = false
check, err := c.httpClient(fmt.Sprintf(loginURL, bot, domainURL), http.MethodPost, nil)
func (c *Confirm) inAccept() {
response, err := c.httpClient(fmt.Sprintf(loginURL, bot, domainURL), http.MethodPost, nil)
if err != nil {
c.Error = c.pointerString(err.Error())
c.Status = Cancel

return
}
switch string(check) {
switch string(response) {
case declined:
err = errors.New(declined)
c.Status = Cancel
c.Error = c.pointerString(string(response))
case trueStr:
status = true
c.Status = Success
default:
c.Status = Pending
}

return
}

func (c *confirmUser) parseHash() (hash string, err error) {
func (c *Confirm) parseHash() {
parseConfirm, err := c.httpClient(fmt.Sprintf(authURL, bot, domainURL), http.MethodGet, nil)
if err != nil {
c.Error = c.pointerString(err.Error())
c.Status = Cancel

return
}
confirm := regexp.MustCompile(regxConfirm)
hash = confirm.FindString(string(parseConfirm))

return
c.hash = confirm.FindString(string(parseConfirm))
if c.hash == "" {
c.Status = Cancel
}
c.Status = Success
}

func (c *confirmUser) isConfirm(hash string) (err error) {
_, err = c.httpClient(fmt.Sprintf(confirmHash, bot, domainURL, hash), http.MethodGet, nil)

return
func (c *Confirm) isConfirm() {
_, err := c.httpClient(fmt.Sprintf(confirmHash, bot, domainURL, c.hash), http.MethodGet, nil)
if err != nil {
c.Status = Cancel
c.Error = c.pointerString(err.Error())
}
c.Status = Success
}

func (c *confirmUser) parseUserProfile() (u *User, err error) {
func (c *Confirm) parseUserProfile() {
responseUserRaw, err := c.httpClient(fmt.Sprintf(confirmURL, bot, domainURL), http.MethodGet, nil)
if err != nil {
c.Error = c.pointerString(err.Error())
c.Status = Cancel

return
}
RegxUserRaw := regexp.MustCompile(regxUserJSON)
UserRaw := RegxUserRaw.FindString(string(responseUserRaw))
err = json.Unmarshal([]byte(UserRaw), &u)
if err == nil {
u.Phone = c.PhoneNumber
err = json.Unmarshal([]byte(UserRaw), &c.User)
if err != nil {
c.Error = c.pointerString(err.Error())
c.Status = Cancel

return
}
c.User.Phone = c.Phone
c.Status = Success
}

return
func (c *Confirm) pointerString(s string) *string {
return &s
}

func (c *confirmUser) httpClient(url, method string, body *string) (responseBody []byte, err error) {
func (c *Confirm) httpClient(url, method string, body *string) (responseBody []byte, err error) { //nolint:cyclop
client := http.Client{}
request, err := http.NewRequestWithContext(context.Background(), method, url, nil)
request, err := http.NewRequestWithContext(c.context, method, url, nil)
if body != nil {
request.Body = ioutil.NopCloser(strings.NewReader(*body))
}
if err != nil {
return
}
cookie, is := getCookies(c.PhoneNumber)
cookie, is := getCookies(c.Phone)
if is {
for key, value := range cookie {
request.AddCookie(&http.Cookie{
Expand All @@ -232,7 +269,7 @@ func (c *confirmUser) httpClient(url, method string, body *string) (responseBody
request.Header.Add("origin", domainURL)
request.Header.Add("referer", domainURL)

request.Header.Add("User-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4606.81 Safari/537.36")
request.Header.Add("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4606.81 Safari/537.36")
if method == http.MethodPost {
request.Header.Add("content-type", "application/x-www-form-urlencoded")
}
Expand All @@ -251,7 +288,7 @@ func (c *confirmUser) httpClient(url, method string, body *string) (responseBody
cookie[c.Name] = c.Value
}
}
setCookies(c.PhoneNumber, cookie)
setCookies(c.Phone, cookie)

responseBody, err = ioutil.ReadAll(response.Body)
if err != nil {
Expand Down
29 changes: 8 additions & 21 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var input = document.querySelector('input[name="phone"]');
function send(){
phone = input.value
fetch("/telegram?act=send&phone="+phone, {}).then(r=> r.json().then(data => {
if (data.status) {
if (data.status == "success") {
button.setAttribute("disabled", true)
input.setAttribute("disabled", true)
check()
Expand All @@ -35,8 +35,9 @@ if (data.error) {alert(data.error)}
function check(){
fetch("/telegram?act=check&phone="+phone, {}).then(r=> r.json().then(data => {
if (data.error) {alert(data.error)}
if (data.pending) {setTimeout(check, 3000)}
if (data.id) {document.querySelector('#user').innerHTML = JSON.stringify(data)}
if (data.status == "cancel") {alert(data.error + data.status)}
if (data.status == "pending") {setTimeout(check, 3000)}
if (data.status == "success") {document.querySelector('#user').innerHTML = JSON.stringify(data)}
})).catch(error => { alert(error) })}
</script>
Expand All @@ -54,25 +55,11 @@ func main() {
http.HandleFunc("/telegram", func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Query().Get("act") {
case "send":
if err := tgah.SendPhoneTelegram(r.URL.Query().Get("phone")); err != nil {
ResponseJSON(w, err)

return
}
ResponseJSON(w, map[string]bool{"status": true}, http.StatusOK)
confirm := tgah.SendPhoneTelegram(r.Context(), r.URL.Query().Get("phone"))
ResponseJSON(w, confirm, http.StatusOK)
case "check":
user, err := tgah.ChecksIsAcceptUserAuth(r.URL.Query().Get("phone"))
if err != nil {
ResponseJSON(w, err)

return
}
if user != nil {
ResponseJSON(w, user, http.StatusOK)

return
}
ResponseJSON(w, map[string]bool{"pending": true}, http.StatusOK)
confirm := tgah.ChecksIsAcceptUserAuth(r.Context(), r.URL.Query().Get("phone"))
ResponseJSON(w, confirm, http.StatusOK)
}
})

Expand Down

0 comments on commit 41fc0b3

Please sign in to comment.