social.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. "io/ioutil"
  9. "net/http"
  10. "net/url"
  11. "strconv"
  12. "github.com/macaron-contrib/oauth2"
  13. "github.com/gogits/gogs/models"
  14. "github.com/gogits/gogs/modules/log"
  15. "github.com/gogits/gogs/modules/setting"
  16. )
  17. type BasicUserInfo struct {
  18. Identity string
  19. Name string
  20. Email string
  21. }
  22. type SocialConnector interface {
  23. Type() int
  24. UserInfo(*oauth2.Token, *url.URL) (*BasicUserInfo, error)
  25. }
  26. var (
  27. SocialMap = make(map[string]SocialConnector)
  28. )
  29. func NewOauthService() {
  30. if !setting.Cfg.MustBool("oauth", "ENABLED") {
  31. return
  32. }
  33. setting.OauthService = &setting.Oauther{}
  34. setting.OauthService.OauthInfos = make(map[string]*setting.OauthInfo)
  35. socialConfigs := make(map[string]*oauth2.Options)
  36. allOauthes := []string{"github", "google", "qq", "twitter", "weibo"}
  37. // Load all OAuth config data.
  38. for _, name := range allOauthes {
  39. if !setting.Cfg.MustBool("oauth."+name, "ENABLED") {
  40. continue
  41. }
  42. setting.OauthService.OauthInfos[name] = &setting.OauthInfo{
  43. Options: oauth2.Options{
  44. ClientID: setting.Cfg.MustValue("oauth."+name, "CLIENT_ID"),
  45. ClientSecret: setting.Cfg.MustValue("oauth."+name, "CLIENT_SECRET"),
  46. Scopes: setting.Cfg.MustValueArray("oauth."+name, "SCOPES", " "),
  47. PathLogin: "/user/login/oauth2/" + name,
  48. PathCallback: setting.AppSubUrl + "/user/login/" + name,
  49. RedirectURL: setting.AppUrl + "user/login/" + name,
  50. },
  51. AuthUrl: setting.Cfg.MustValue("oauth."+name, "AUTH_URL"),
  52. TokenUrl: setting.Cfg.MustValue("oauth."+name, "TOKEN_URL"),
  53. }
  54. socialConfigs[name] = &oauth2.Options{
  55. ClientID: setting.OauthService.OauthInfos[name].ClientID,
  56. ClientSecret: setting.OauthService.OauthInfos[name].ClientSecret,
  57. Scopes: setting.OauthService.OauthInfos[name].Scopes,
  58. }
  59. }
  60. enabledOauths := make([]string, 0, 10)
  61. // GitHub.
  62. if setting.Cfg.MustBool("oauth.github", "ENABLED") {
  63. setting.OauthService.GitHub = true
  64. newGitHubOauth(socialConfigs["github"])
  65. enabledOauths = append(enabledOauths, "GitHub")
  66. }
  67. // Google.
  68. if setting.Cfg.MustBool("oauth.google", "ENABLED") {
  69. setting.OauthService.Google = true
  70. newGoogleOauth(socialConfigs["google"])
  71. enabledOauths = append(enabledOauths, "Google")
  72. }
  73. // QQ.
  74. if setting.Cfg.MustBool("oauth.qq", "ENABLED") {
  75. setting.OauthService.Tencent = true
  76. newTencentOauth(socialConfigs["qq"])
  77. enabledOauths = append(enabledOauths, "QQ")
  78. }
  79. // Twitter.
  80. // if setting.Cfg.MustBool("oauth.twitter", "ENABLED") {
  81. // setting.OauthService.Twitter = true
  82. // newTwitterOauth(socialConfigs["twitter"])
  83. // enabledOauths = append(enabledOauths, "Twitter")
  84. // }
  85. // Weibo.
  86. if setting.Cfg.MustBool("oauth.weibo", "ENABLED") {
  87. setting.OauthService.Weibo = true
  88. newWeiboOauth(socialConfigs["weibo"])
  89. enabledOauths = append(enabledOauths, "Weibo")
  90. }
  91. log.Info("Oauth Service Enabled %s", enabledOauths)
  92. }
  93. // ________.__ __ ___ ___ ___.
  94. // / _____/|__|/ |_ / | \ __ _\_ |__
  95. // / \ ___| \ __\/ ~ \ | \ __ \
  96. // \ \_\ \ || | \ Y / | / \_\ \
  97. // \______ /__||__| \___|_ /|____/|___ /
  98. // \/ \/ \/
  99. type SocialGithub struct {
  100. opts *oauth2.Options
  101. }
  102. func newGitHubOauth(opts *oauth2.Options) {
  103. SocialMap["github"] = &SocialGithub{opts}
  104. }
  105. func (s *SocialGithub) Type() int {
  106. return int(models.GITHUB)
  107. }
  108. func (s *SocialGithub) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  109. transport := s.opts.NewTransportFromToken(token)
  110. var data struct {
  111. Id int `json:"id"`
  112. Name string `json:"login"`
  113. Email string `json:"email"`
  114. }
  115. r, err := transport.Client().Get("https://api.github.com/user")
  116. if err != nil {
  117. return nil, err
  118. }
  119. defer r.Body.Close()
  120. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  121. return nil, err
  122. }
  123. return &BasicUserInfo{
  124. Identity: strconv.Itoa(data.Id),
  125. Name: data.Name,
  126. Email: data.Email,
  127. }, nil
  128. }
  129. // ________ .__
  130. // / _____/ ____ ____ ____ | | ____
  131. // / \ ___ / _ \ / _ \ / ___\| | _/ __ \
  132. // \ \_\ ( <_> | <_> ) /_/ > |_\ ___/
  133. // \______ /\____/ \____/\___ /|____/\___ >
  134. // \/ /_____/ \/
  135. type SocialGoogle struct {
  136. opts *oauth2.Options
  137. }
  138. func (s *SocialGoogle) Type() int {
  139. return int(models.GOOGLE)
  140. }
  141. func newGoogleOauth(opts *oauth2.Options) {
  142. SocialMap["google"] = &SocialGoogle{opts}
  143. }
  144. func (s *SocialGoogle) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  145. transport := s.opts.NewTransportFromToken(token)
  146. var data struct {
  147. Id string `json:"id"`
  148. Name string `json:"name"`
  149. Email string `json:"email"`
  150. }
  151. r, err := transport.Client().Get("https://www.googleapis.com/userinfo/v2/me")
  152. if err != nil {
  153. return nil, err
  154. }
  155. defer r.Body.Close()
  156. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  157. return nil, err
  158. }
  159. return &BasicUserInfo{
  160. Identity: data.Id,
  161. Name: data.Name,
  162. Email: data.Email,
  163. }, nil
  164. }
  165. // ________ ________
  166. // \_____ \ \_____ \
  167. // / / \ \ / / \ \
  168. // / \_/. \/ \_/. \
  169. // \_____\ \_/\_____\ \_/
  170. // \__> \__>
  171. type SocialTencent struct {
  172. opts *oauth2.Options
  173. }
  174. func newTencentOauth(opts *oauth2.Options) {
  175. SocialMap["qq"] = &SocialTencent{opts}
  176. }
  177. func (s *SocialTencent) Type() int {
  178. return int(models.QQ)
  179. }
  180. func (s *SocialTencent) UserInfo(token *oauth2.Token, URL *url.URL) (*BasicUserInfo, error) {
  181. r, err := http.Get("https://graph.z.qq.com/moc2/me?access_token=" + url.QueryEscape(token.AccessToken))
  182. if err != nil {
  183. return nil, err
  184. }
  185. defer r.Body.Close()
  186. body, err := ioutil.ReadAll(r.Body)
  187. if err != nil {
  188. return nil, err
  189. }
  190. vals, err := url.ParseQuery(string(body))
  191. if err != nil {
  192. return nil, err
  193. }
  194. return &BasicUserInfo{
  195. Identity: vals.Get("openid"),
  196. }, nil
  197. }
  198. // ___________ .__ __ __
  199. // \__ ___/_ _ _|__|/ |__/ |_ ___________
  200. // | | \ \/ \/ / \ __\ __\/ __ \_ __ \
  201. // | | \ /| || | | | \ ___/| | \/
  202. // |____| \/\_/ |__||__| |__| \___ >__|
  203. // \/
  204. // type SocialTwitter struct {
  205. // Token *oauth2.Token
  206. // *oauth2.Transport
  207. // }
  208. // func (s *SocialTwitter) Type() int {
  209. // return int(models.TWITTER)
  210. // }
  211. // func newTwitterOauth(config *oauth2.Config) {
  212. // SocialMap["twitter"] = &SocialTwitter{
  213. // Transport: &oauth.Transport{
  214. // Config: config,
  215. // Transport: http.DefaultTransport,
  216. // },
  217. // }
  218. // }
  219. // func (s *SocialTwitter) SetRedirectUrl(url string) {
  220. // s.Transport.Config.RedirectURL = url
  221. // }
  222. // //https://github.com/mrjones/oauth
  223. // func (s *SocialTwitter) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  224. // // transport := &oauth.Transport{Token: token}
  225. // // var data struct {
  226. // // Id string `json:"id"`
  227. // // Name string `json:"name"`
  228. // // Email string `json:"email"`
  229. // // }
  230. // // var err error
  231. // // reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
  232. // // r, err := transport.Client().Get(reqUrl)
  233. // // if err != nil {
  234. // // return nil, err
  235. // // }
  236. // // defer r.Body.Close()
  237. // // if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  238. // // return nil, err
  239. // // }
  240. // // return &BasicUserInfo{
  241. // // Identity: data.Id,
  242. // // Name: data.Name,
  243. // // Email: data.Email,
  244. // // }, nil
  245. // return nil, nil
  246. // }
  247. // __ __ ._____.
  248. // / \ / \ ____ |__\_ |__ ____
  249. // \ \/\/ // __ \| || __ \ / _ \
  250. // \ /\ ___/| || \_\ ( <_> )
  251. // \__/\ / \___ >__||___ /\____/
  252. // \/ \/ \/
  253. type SocialWeibo struct {
  254. opts *oauth2.Options
  255. }
  256. func newWeiboOauth(opts *oauth2.Options) {
  257. SocialMap["weibo"] = &SocialWeibo{opts}
  258. }
  259. func (s *SocialWeibo) Type() int {
  260. return int(models.WEIBO)
  261. }
  262. func (s *SocialWeibo) UserInfo(token *oauth2.Token, _ *url.URL) (*BasicUserInfo, error) {
  263. transport := s.opts.NewTransportFromToken(token)
  264. var data struct {
  265. Name string `json:"name"`
  266. }
  267. var urls = url.Values{
  268. "access_token": {token.AccessToken},
  269. "uid": {token.Extra("uid")},
  270. }
  271. reqUrl := "https://api.weibo.com/2/users/show.json"
  272. r, err := transport.Client().Get(reqUrl + "?" + urls.Encode())
  273. if err != nil {
  274. return nil, err
  275. }
  276. defer r.Body.Close()
  277. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  278. return nil, err
  279. }
  280. return &BasicUserInfo{
  281. Identity: token.Extra("uid"),
  282. Name: data.Name,
  283. }, nil
  284. }