package api import ( "net/http" "net/url" "github.com/gin-gonic/gin" ) func (server *ApiServer) loadEndpoints() { server.engine.GET("/ping", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) // info for user-end html pages serverInfo := ServerInfo{ ClientID: server.conf.ClientID, AuthParams: TwitchAuthParams{ ClientID: server.conf.ClientID, ForceVerify: false, RedirectURI: server.conf.RedirectURI, ResponseType: "code", Scope: []string{ "bits:read", "channel:bot", "channel:read:goals", "channel:read:hype_train", "channel:read:polls", "channel:manage:polls", "channel:read:predictions", "channel:manage:predictions", "channel:read:redemptions", "channel:manage:redemptions", "channel:read:vips", "channel:moderate", "user:bot", "user:read:broadcast", "user:read:chat", "user:read:emotes", "user:write:chat", }, State: "", // TODO make this unique per request }, } server.engine.GET("/info", func(c *gin.Context) { c.JSON(http.StatusOK, serverInfo) }) server.engine.GET("/auth", func(c *gin.Context) { q := c.Request.URL.Query() if resp := loadAuthQueryOk(q); resp != nil { // ok // TODO check state (need state system) // TODO POST https://id.twitch.tv/oauth2/token - returns TwitchAuthTokenResp // convert expiresIn to time.Time (minus like 15 minutes as a buffer period) // UpdateUserAuth() // TODO return twitch ok (or err if can't POST) } else if resp := loadAuthQueryErr(q); resp != nil { // err from twitch // TODO check state (need state system) // TODO return twitch err } else { // err in params // TODO return param err } // TODO auth response from twitch // parse args as TwitchAuthRespOk or TwitchAuthRespErr // verify state with db and client id with config c.JSON(http.StatusOK, serverInfo) }) } type ServerInfo struct { ClientID string `json:"client_id"` AuthParams TwitchAuthParams `json:"auth_params"` } type TwitchAuthParams struct { ClientID string `json:"client_id"` ForceVerify bool `json:"force_verify"` RedirectURI string `json:"redirect_uri"` ResponseType string `json:"response_type"` Scope []string `json:"scope"` State string `json:"state"` } func loadAuthQueryOk(query url.Values) *TwitchAuthRespOk { if query.Has("code") && query.Has("scope") && query.Has("state") { return &TwitchAuthRespOk{ Code: query.Get("code"), Scope: query.Get("scope"), State: query.Get("state"), } } return nil } func loadAuthQueryErr(query url.Values) *TwitchAuthRespErr { if query.Has("error") && query.Has("error_description") && query.Has("state") { return &TwitchAuthRespErr{ Err: query.Get("error"), ErrDesc: query.Get("error_description"), State: query.Get("state"), } } return nil } type TwitchAuthRespOk struct { Code string `json:"code"` Scope string `json:"scope"` State string `json:"state"` } type TwitchAuthRespErr struct { Err string `json:"error"` ErrDesc string `json:"error_description"` State string `json:"state"` } type TwitchAuthTokenResp struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` RefreshToken string `json:"refresh_token"` Scope []string `json:"scope"` TokenType string `json:"token_type"` }