You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

social.go 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. // Copyright 2014 Google Inc. All Rights Reserved.
  2. // Copyright 2014 The Gogs Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package social
  6. import (
  7. "encoding/json"
  8. "net/http"
  9. "net/url"
  10. "strconv"
  11. "strings"
  12. "code.google.com/p/goauth2/oauth"
  13. "github.com/gogits/gogs/models"
  14. "github.com/gogits/gogs/modules/base"
  15. "github.com/gogits/gogs/modules/log"
  16. )
  17. type BasicUserInfo struct {
  18. Identity string
  19. Name string
  20. Email string
  21. }
  22. type SocialConnector interface {
  23. Type() int
  24. SetRedirectUrl(string)
  25. UserInfo(*oauth.Token, *url.URL) (*BasicUserInfo, error)
  26. AuthCodeURL(string) string
  27. Exchange(string) (*oauth.Token, error)
  28. }
  29. var (
  30. SocialBaseUrl = "/user/login"
  31. SocialMap = make(map[string]SocialConnector)
  32. )
  33. func NewOauthService() {
  34. if !base.Cfg.MustBool("oauth", "ENABLED") {
  35. return
  36. }
  37. base.OauthService = &base.Oauther{}
  38. base.OauthService.OauthInfos = make(map[string]*base.OauthInfo)
  39. socialConfigs := make(map[string]*oauth.Config)
  40. allOauthes := []string{"github", "google", "qq", "twitter"}
  41. // Load all OAuth config data.
  42. for _, name := range allOauthes {
  43. base.OauthService.OauthInfos[name] = &base.OauthInfo{
  44. ClientId: base.Cfg.MustValue("oauth."+name, "CLIENT_ID"),
  45. ClientSecret: base.Cfg.MustValue("oauth."+name, "CLIENT_SECRET"),
  46. Scopes: base.Cfg.MustValue("oauth."+name, "SCOPES"),
  47. AuthUrl: base.Cfg.MustValue("oauth."+name, "AUTH_URL"),
  48. TokenUrl: base.Cfg.MustValue("oauth."+name, "TOKEN_URL"),
  49. }
  50. socialConfigs[name] = &oauth.Config{
  51. ClientId: base.OauthService.OauthInfos[name].ClientId,
  52. ClientSecret: base.OauthService.OauthInfos[name].ClientSecret,
  53. RedirectURL: strings.TrimSuffix(base.AppUrl, "/") + SocialBaseUrl + name,
  54. Scope: base.OauthService.OauthInfos[name].Scopes,
  55. AuthURL: base.OauthService.OauthInfos[name].AuthUrl,
  56. TokenURL: base.OauthService.OauthInfos[name].TokenUrl,
  57. }
  58. }
  59. enabledOauths := make([]string, 0, 10)
  60. // GitHub.
  61. if base.Cfg.MustBool("oauth.github", "ENABLED") {
  62. base.OauthService.GitHub = true
  63. newGitHubOauth(socialConfigs["github"])
  64. enabledOauths = append(enabledOauths, "GitHub")
  65. }
  66. // Google.
  67. if base.Cfg.MustBool("oauth.google", "ENABLED") {
  68. base.OauthService.Google = true
  69. newGoogleOauth(socialConfigs["google"])
  70. enabledOauths = append(enabledOauths, "Google")
  71. }
  72. // QQ.
  73. if base.Cfg.MustBool("oauth.qq", "ENABLED") {
  74. base.OauthService.Tencent = true
  75. newTencentOauth(socialConfigs["qq"])
  76. enabledOauths = append(enabledOauths, "QQ")
  77. }
  78. // Twitter.
  79. if base.Cfg.MustBool("oauth.twitter", "ENABLED") {
  80. base.OauthService.Twitter = true
  81. newTwitterOauth(socialConfigs["twitter"])
  82. enabledOauths = append(enabledOauths, "Twitter")
  83. }
  84. log.Info("Oauth Service Enabled %s", enabledOauths)
  85. }
  86. // ________.__ __ ___ ___ ___.
  87. // / _____/|__|/ |_ / | \ __ _\_ |__
  88. // / \ ___| \ __\/ ~ \ | \ __ \
  89. // \ \_\ \ || | \ Y / | / \_\ \
  90. // \______ /__||__| \___|_ /|____/|___ /
  91. // \/ \/ \/
  92. type SocialGithub struct {
  93. Token *oauth.Token
  94. *oauth.Transport
  95. }
  96. func (s *SocialGithub) Type() int {
  97. return models.OT_GITHUB
  98. }
  99. func newGitHubOauth(config *oauth.Config) {
  100. SocialMap["github"] = &SocialGithub{
  101. Transport: &oauth.Transport{
  102. Config: config,
  103. Transport: http.DefaultTransport,
  104. },
  105. }
  106. }
  107. func (s *SocialGithub) SetRedirectUrl(url string) {
  108. s.Transport.Config.RedirectURL = url
  109. }
  110. func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
  111. transport := &oauth.Transport{
  112. Token: token,
  113. }
  114. var data struct {
  115. Id int `json:"id"`
  116. Name string `json:"login"`
  117. Email string `json:"email"`
  118. }
  119. var err error
  120. r, err := transport.Client().Get(s.Transport.Scope)
  121. if err != nil {
  122. return nil, err
  123. }
  124. defer r.Body.Close()
  125. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  126. return nil, err
  127. }
  128. return &BasicUserInfo{
  129. Identity: strconv.Itoa(data.Id),
  130. Name: data.Name,
  131. Email: data.Email,
  132. }, nil
  133. }
  134. // ________ .__
  135. // / _____/ ____ ____ ____ | | ____
  136. // / \ ___ / _ \ / _ \ / ___\| | _/ __ \
  137. // \ \_\ ( <_> | <_> ) /_/ > |_\ ___/
  138. // \______ /\____/ \____/\___ /|____/\___ >
  139. // \/ /_____/ \/
  140. type SocialGoogle struct {
  141. Token *oauth.Token
  142. *oauth.Transport
  143. }
  144. func (s *SocialGoogle) Type() int {
  145. return models.OT_GOOGLE
  146. }
  147. func newGoogleOauth(config *oauth.Config) {
  148. SocialMap["google"] = &SocialGoogle{
  149. Transport: &oauth.Transport{
  150. Config: config,
  151. Transport: http.DefaultTransport,
  152. },
  153. }
  154. }
  155. func (s *SocialGoogle) SetRedirectUrl(url string) {
  156. s.Transport.Config.RedirectURL = url
  157. }
  158. func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
  159. transport := &oauth.Transport{Token: token}
  160. var data struct {
  161. Id string `json:"id"`
  162. Name string `json:"name"`
  163. Email string `json:"email"`
  164. }
  165. var err error
  166. reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
  167. r, err := transport.Client().Get(reqUrl)
  168. if err != nil {
  169. return nil, err
  170. }
  171. defer r.Body.Close()
  172. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  173. return nil, err
  174. }
  175. return &BasicUserInfo{
  176. Identity: data.Id,
  177. Name: data.Name,
  178. Email: data.Email,
  179. }, nil
  180. }
  181. // ________ ________
  182. // \_____ \ \_____ \
  183. // / / \ \ / / \ \
  184. // / \_/. \/ \_/. \
  185. // \_____\ \_/\_____\ \_/
  186. // \__> \__>
  187. type SocialTencent struct {
  188. Token *oauth.Token
  189. *oauth.Transport
  190. reqUrl string
  191. }
  192. func (s *SocialTencent) Type() int {
  193. return models.OT_QQ
  194. }
  195. func newTencentOauth(config *oauth.Config) {
  196. SocialMap["qq"] = &SocialTencent{
  197. reqUrl: "https://open.t.qq.com/api/user/info",
  198. Transport: &oauth.Transport{
  199. Config: config,
  200. Transport: http.DefaultTransport,
  201. },
  202. }
  203. }
  204. func (s *SocialTencent) SetRedirectUrl(url string) {
  205. s.Transport.Config.RedirectURL = url
  206. }
  207. func (s *SocialTencent) UserInfo(token *oauth.Token, URL *url.URL) (*BasicUserInfo, error) {
  208. var data struct {
  209. Data struct {
  210. Id string `json:"openid"`
  211. Name string `json:"name"`
  212. Email string `json:"email"`
  213. } `json:"data"`
  214. }
  215. var err error
  216. // https://open.t.qq.com/api/user/info?
  217. //oauth_consumer_key=APP_KEY&
  218. //access_token=ACCESSTOKEN&openid=openid
  219. //clientip=CLIENTIP&oauth_version=2.a
  220. //scope=all
  221. var urls = url.Values{
  222. "oauth_consumer_key": {s.Transport.Config.ClientId},
  223. "access_token": {token.AccessToken},
  224. "openid": URL.Query()["openid"],
  225. "oauth_version": {"2.a"},
  226. "scope": {"all"},
  227. }
  228. r, err := http.Get(s.reqUrl + "?" + urls.Encode())
  229. if err != nil {
  230. return nil, err
  231. }
  232. defer r.Body.Close()
  233. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  234. return nil, err
  235. }
  236. return &BasicUserInfo{
  237. Identity: data.Data.Id,
  238. Name: data.Data.Name,
  239. Email: data.Data.Email,
  240. }, nil
  241. }
  242. // ___________ .__ __ __
  243. // \__ ___/_ _ _|__|/ |__/ |_ ___________
  244. // | | \ \/ \/ / \ __\ __\/ __ \_ __ \
  245. // | | \ /| || | | | \ ___/| | \/
  246. // |____| \/\_/ |__||__| |__| \___ >__|
  247. // \/
  248. type SocialTwitter struct {
  249. Token *oauth.Token
  250. *oauth.Transport
  251. }
  252. func (s *SocialTwitter) Type() int {
  253. return models.OT_TWITTER
  254. }
  255. func newTwitterOauth(config *oauth.Config) {
  256. SocialMap["twitter"] = &SocialTwitter{
  257. Transport: &oauth.Transport{
  258. Config: config,
  259. Transport: http.DefaultTransport,
  260. },
  261. }
  262. }
  263. func (s *SocialTwitter) SetRedirectUrl(url string) {
  264. s.Transport.Config.RedirectURL = url
  265. }
  266. //https://github.com/mrjones/oauth
  267. func (s *SocialTwitter) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
  268. // transport := &oauth.Transport{Token: token}
  269. // var data struct {
  270. // Id string `json:"id"`
  271. // Name string `json:"name"`
  272. // Email string `json:"email"`
  273. // }
  274. // var err error
  275. // reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
  276. // r, err := transport.Client().Get(reqUrl)
  277. // if err != nil {
  278. // return nil, err
  279. // }
  280. // defer r.Body.Close()
  281. // if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  282. // return nil, err
  283. // }
  284. // return &BasicUserInfo{
  285. // Identity: data.Id,
  286. // Name: data.Name,
  287. // Email: data.Email,
  288. // }, nil
  289. return nil, nil
  290. }