social.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. oauth "github.com/gogits/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. 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 !setting.Cfg.MustBool("oauth", "ENABLED") {
  35. return
  36. }
  37. setting.OauthService = &setting.Oauther{}
  38. setting.OauthService.OauthInfos = make(map[string]*setting.OauthInfo)
  39. socialConfigs := make(map[string]*oauth.Config)
  40. allOauthes := []string{"github", "google", "qq", "twitter", "weibo"}
  41. // Load all OAuth config data.
  42. for _, name := range allOauthes {
  43. setting.OauthService.OauthInfos[name] = &setting.OauthInfo{
  44. ClientId: setting.Cfg.MustValue("oauth."+name, "CLIENT_ID"),
  45. ClientSecret: setting.Cfg.MustValue("oauth."+name, "CLIENT_SECRET"),
  46. Scopes: setting.Cfg.MustValue("oauth."+name, "SCOPES"),
  47. AuthUrl: setting.Cfg.MustValue("oauth."+name, "AUTH_URL"),
  48. TokenUrl: setting.Cfg.MustValue("oauth."+name, "TOKEN_URL"),
  49. }
  50. socialConfigs[name] = &oauth.Config{
  51. ClientId: setting.OauthService.OauthInfos[name].ClientId,
  52. ClientSecret: setting.OauthService.OauthInfos[name].ClientSecret,
  53. RedirectURL: strings.TrimSuffix(setting.AppUrl, "/") + SocialBaseUrl + name,
  54. Scope: setting.OauthService.OauthInfos[name].Scopes,
  55. AuthURL: setting.OauthService.OauthInfos[name].AuthUrl,
  56. TokenURL: setting.OauthService.OauthInfos[name].TokenUrl,
  57. }
  58. }
  59. enabledOauths := make([]string, 0, 10)
  60. // GitHub.
  61. if setting.Cfg.MustBool("oauth.github", "ENABLED") {
  62. setting.OauthService.GitHub = true
  63. newGitHubOauth(socialConfigs["github"])
  64. enabledOauths = append(enabledOauths, "GitHub")
  65. }
  66. // Google.
  67. if setting.Cfg.MustBool("oauth.google", "ENABLED") {
  68. setting.OauthService.Google = true
  69. newGoogleOauth(socialConfigs["google"])
  70. enabledOauths = append(enabledOauths, "Google")
  71. }
  72. // QQ.
  73. if setting.Cfg.MustBool("oauth.qq", "ENABLED") {
  74. setting.OauthService.Tencent = true
  75. newTencentOauth(socialConfigs["qq"])
  76. enabledOauths = append(enabledOauths, "QQ")
  77. }
  78. // Twitter.
  79. if setting.Cfg.MustBool("oauth.twitter", "ENABLED") {
  80. setting.OauthService.Twitter = true
  81. newTwitterOauth(socialConfigs["twitter"])
  82. enabledOauths = append(enabledOauths, "Twitter")
  83. }
  84. // Weibo.
  85. if setting.Cfg.MustBool("oauth.weibo", "ENABLED") {
  86. setting.OauthService.Weibo = true
  87. newWeiboOauth(socialConfigs["weibo"])
  88. enabledOauths = append(enabledOauths, "Weibo")
  89. }
  90. log.Info("Oauth Service Enabled %s", enabledOauths)
  91. }
  92. // ________.__ __ ___ ___ ___.
  93. // / _____/|__|/ |_ / | \ __ _\_ |__
  94. // / \ ___| \ __\/ ~ \ | \ __ \
  95. // \ \_\ \ || | \ Y / | / \_\ \
  96. // \______ /__||__| \___|_ /|____/|___ /
  97. // \/ \/ \/
  98. type SocialGithub struct {
  99. Token *oauth.Token
  100. *oauth.Transport
  101. }
  102. func (s *SocialGithub) Type() int {
  103. return int(models.GITHUB)
  104. }
  105. func newGitHubOauth(config *oauth.Config) {
  106. SocialMap["github"] = &SocialGithub{
  107. Transport: &oauth.Transport{
  108. Config: config,
  109. Transport: http.DefaultTransport,
  110. },
  111. }
  112. }
  113. func (s *SocialGithub) SetRedirectUrl(url string) {
  114. s.Transport.Config.RedirectURL = url
  115. }
  116. func (s *SocialGithub) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
  117. transport := &oauth.Transport{
  118. Token: token,
  119. }
  120. var data struct {
  121. Id int `json:"id"`
  122. Name string `json:"login"`
  123. Email string `json:"email"`
  124. }
  125. var err error
  126. r, err := transport.Client().Get(s.Transport.Scope)
  127. if err != nil {
  128. return nil, err
  129. }
  130. defer r.Body.Close()
  131. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  132. return nil, err
  133. }
  134. return &BasicUserInfo{
  135. Identity: strconv.Itoa(data.Id),
  136. Name: data.Name,
  137. Email: data.Email,
  138. }, nil
  139. }
  140. // ________ .__
  141. // / _____/ ____ ____ ____ | | ____
  142. // / \ ___ / _ \ / _ \ / ___\| | _/ __ \
  143. // \ \_\ ( <_> | <_> ) /_/ > |_\ ___/
  144. // \______ /\____/ \____/\___ /|____/\___ >
  145. // \/ /_____/ \/
  146. type SocialGoogle struct {
  147. Token *oauth.Token
  148. *oauth.Transport
  149. }
  150. func (s *SocialGoogle) Type() int {
  151. return int(models.GOOGLE)
  152. }
  153. func newGoogleOauth(config *oauth.Config) {
  154. SocialMap["google"] = &SocialGoogle{
  155. Transport: &oauth.Transport{
  156. Config: config,
  157. Transport: http.DefaultTransport,
  158. },
  159. }
  160. }
  161. func (s *SocialGoogle) SetRedirectUrl(url string) {
  162. s.Transport.Config.RedirectURL = url
  163. }
  164. func (s *SocialGoogle) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
  165. transport := &oauth.Transport{Token: token}
  166. var data struct {
  167. Id string `json:"id"`
  168. Name string `json:"name"`
  169. Email string `json:"email"`
  170. }
  171. var err error
  172. reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
  173. r, err := transport.Client().Get(reqUrl)
  174. if err != nil {
  175. return nil, err
  176. }
  177. defer r.Body.Close()
  178. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  179. return nil, err
  180. }
  181. return &BasicUserInfo{
  182. Identity: data.Id,
  183. Name: data.Name,
  184. Email: data.Email,
  185. }, nil
  186. }
  187. // ________ ________
  188. // \_____ \ \_____ \
  189. // / / \ \ / / \ \
  190. // / \_/. \/ \_/. \
  191. // \_____\ \_/\_____\ \_/
  192. // \__> \__>
  193. type SocialTencent struct {
  194. Token *oauth.Token
  195. *oauth.Transport
  196. reqUrl string
  197. }
  198. func (s *SocialTencent) Type() int {
  199. return int(models.QQ)
  200. }
  201. func newTencentOauth(config *oauth.Config) {
  202. SocialMap["qq"] = &SocialTencent{
  203. reqUrl: "https://open.t.qq.com/api/user/info",
  204. Transport: &oauth.Transport{
  205. Config: config,
  206. Transport: http.DefaultTransport,
  207. },
  208. }
  209. }
  210. func (s *SocialTencent) SetRedirectUrl(url string) {
  211. s.Transport.Config.RedirectURL = url
  212. }
  213. func (s *SocialTencent) UserInfo(token *oauth.Token, URL *url.URL) (*BasicUserInfo, error) {
  214. var data struct {
  215. Data struct {
  216. Id string `json:"openid"`
  217. Name string `json:"name"`
  218. Email string `json:"email"`
  219. } `json:"data"`
  220. }
  221. var err error
  222. // https://open.t.qq.com/api/user/info?
  223. //oauth_consumer_key=APP_KEY&
  224. //access_token=ACCESSTOKEN&openid=openid
  225. //clientip=CLIENTIP&oauth_version=2.a
  226. //scope=all
  227. var urls = url.Values{
  228. "oauth_consumer_key": {s.Transport.Config.ClientId},
  229. "access_token": {token.AccessToken},
  230. "openid": URL.Query()["openid"],
  231. "oauth_version": {"2.a"},
  232. "scope": {"all"},
  233. }
  234. r, err := http.Get(s.reqUrl + "?" + urls.Encode())
  235. if err != nil {
  236. return nil, err
  237. }
  238. defer r.Body.Close()
  239. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  240. return nil, err
  241. }
  242. return &BasicUserInfo{
  243. Identity: data.Data.Id,
  244. Name: data.Data.Name,
  245. Email: data.Data.Email,
  246. }, nil
  247. }
  248. // ___________ .__ __ __
  249. // \__ ___/_ _ _|__|/ |__/ |_ ___________
  250. // | | \ \/ \/ / \ __\ __\/ __ \_ __ \
  251. // | | \ /| || | | | \ ___/| | \/
  252. // |____| \/\_/ |__||__| |__| \___ >__|
  253. // \/
  254. type SocialTwitter struct {
  255. Token *oauth.Token
  256. *oauth.Transport
  257. }
  258. func (s *SocialTwitter) Type() int {
  259. return int(models.TWITTER)
  260. }
  261. func newTwitterOauth(config *oauth.Config) {
  262. SocialMap["twitter"] = &SocialTwitter{
  263. Transport: &oauth.Transport{
  264. Config: config,
  265. Transport: http.DefaultTransport,
  266. },
  267. }
  268. }
  269. func (s *SocialTwitter) SetRedirectUrl(url string) {
  270. s.Transport.Config.RedirectURL = url
  271. }
  272. //https://github.com/mrjones/oauth
  273. func (s *SocialTwitter) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
  274. // transport := &oauth.Transport{Token: token}
  275. // var data struct {
  276. // Id string `json:"id"`
  277. // Name string `json:"name"`
  278. // Email string `json:"email"`
  279. // }
  280. // var err error
  281. // reqUrl := "https://www.googleapis.com/oauth2/v1/userinfo"
  282. // r, err := transport.Client().Get(reqUrl)
  283. // if err != nil {
  284. // return nil, err
  285. // }
  286. // defer r.Body.Close()
  287. // if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  288. // return nil, err
  289. // }
  290. // return &BasicUserInfo{
  291. // Identity: data.Id,
  292. // Name: data.Name,
  293. // Email: data.Email,
  294. // }, nil
  295. return nil, nil
  296. }
  297. // __ __ ._____.
  298. // / \ / \ ____ |__\_ |__ ____
  299. // \ \/\/ // __ \| || __ \ / _ \
  300. // \ /\ ___/| || \_\ ( <_> )
  301. // \__/\ / \___ >__||___ /\____/
  302. // \/ \/ \/
  303. type SocialWeibo struct {
  304. Token *oauth.Token
  305. *oauth.Transport
  306. }
  307. func (s *SocialWeibo) Type() int {
  308. return int(models.WEIBO)
  309. }
  310. func newWeiboOauth(config *oauth.Config) {
  311. SocialMap["weibo"] = &SocialWeibo{
  312. Transport: &oauth.Transport{
  313. Config: config,
  314. Transport: http.DefaultTransport,
  315. },
  316. }
  317. }
  318. func (s *SocialWeibo) SetRedirectUrl(url string) {
  319. s.Transport.Config.RedirectURL = url
  320. }
  321. func (s *SocialWeibo) UserInfo(token *oauth.Token, _ *url.URL) (*BasicUserInfo, error) {
  322. transport := &oauth.Transport{Token: token}
  323. var data struct {
  324. Name string `json:"name"`
  325. }
  326. var err error
  327. var urls = url.Values{
  328. "access_token": {token.AccessToken},
  329. "uid": {token.Extra["id_token"]},
  330. }
  331. reqUrl := "https://api.weibo.com/2/users/show.json"
  332. r, err := transport.Client().Get(reqUrl + "?" + urls.Encode())
  333. if err != nil {
  334. return nil, err
  335. }
  336. defer r.Body.Close()
  337. if err = json.NewDecoder(r.Body).Decode(&data); err != nil {
  338. return nil, err
  339. }
  340. return &BasicUserInfo{
  341. Identity: token.Extra["id_token"],
  342. Name: data.Name,
  343. }, nil
  344. }