Merged/tweaked GitHub login.

This commit is contained in:
Nick Winter 2014-08-26 08:37:11 -07:00
commit 832402af6e
11 changed files with 100 additions and 1 deletions

View file

@ -65,6 +65,8 @@ module.exports = class CocoRouter extends Backbone.Router
'file/*path': 'routeToServer' 'file/*path': 'routeToServer'
'github/*path': 'routeToServer'
'legal': go('LegalView') 'legal': go('LegalView')
'multiplayer': go('MultiplayerView') 'multiplayer': go('MultiplayerView')

View file

@ -1,6 +1,7 @@
FacebookHandler = require 'lib/FacebookHandler' FacebookHandler = require 'lib/FacebookHandler'
GPlusHandler = require 'lib/GPlusHandler' GPlusHandler = require 'lib/GPlusHandler'
LinkedInHandler = require 'lib/LinkedInHandler' LinkedInHandler = require 'lib/LinkedInHandler'
GitHubHandler = require 'lib/GitHubHandler'
locale = require 'locale/locale' # TODO: don't require all of these? Might be slow. (Haven't checked.) locale = require 'locale/locale' # TODO: don't require all of these? Might be slow. (Haven't checked.)
{me} = require 'lib/auth' {me} = require 'lib/auth'
Tracker = require 'lib/Tracker' Tracker = require 'lib/Tracker'
@ -35,9 +36,11 @@ preload = (arrayOfImages) ->
Application = initialize: -> Application = initialize: ->
Router = require('Router') Router = require('Router')
@isProduction = -> document.location.href.search('codecombat.com') isnt -1
@tracker = new Tracker() @tracker = new Tracker()
@facebookHandler = new FacebookHandler() @facebookHandler = new FacebookHandler()
@gplusHandler = new GPlusHandler() @gplusHandler = new GPlusHandler()
@githubHandler = new GitHubHandler()
$(document).bind 'keydown', preventBackspace $(document).bind 'keydown', preventBackspace
@linkedinHandler = new LinkedInHandler() @linkedinHandler = new LinkedInHandler()
preload(COMMON_FILES) preload(COMMON_FILES)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,22 @@
CocoClass = require 'lib/CocoClass'
{me} = require 'lib/auth'
storage = require 'lib/storage'
module.exports = class GitHubHandler extends CocoClass
scopes: 'user:email'
subscriptions:
'github-login': 'commenceGitHubLogin'
constructor: ->
super arguments...
@clientID = if application.isProduction() then '9b405bf5fb84590d1f02' else 'fd5c9d34eb171131bc87'
@redirectURI = if application.isProduction() then 'http://codecombat.com/github/auth_callback' else 'http://localhost:3000/github/auth_callback'
commenceGitHubLogin: ->
request =
scope: @scopes
client_id: @clientID
redirect_uri: @redirectURI
location.href = "https://github.com/login/oauth/authorize?" + $.param(request)

View file

@ -43,6 +43,7 @@ _.extend UserSchema.properties,
photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image to serve as your profile picture.'} photoURL: {type: 'string', format: 'image-file', title: 'Profile Picture', description: 'Upload a 256x256px or larger image to serve as your profile picture.'}
facebookID: c.shortString({title: 'Facebook ID'}) facebookID: c.shortString({title: 'Facebook ID'})
githubID: c.shortString({title: 'GitHub ID'})
gplusID: c.shortString({title: 'G+ ID'}) gplusID: c.shortString({title: 'G+ ID'})
wizardColor1: c.pct({title: 'Wizard Clothes Color'}) wizardColor1: c.pct({title: 'Wizard Clothes Color'})

View file

@ -4,6 +4,14 @@
width: 100px width: 100px
text-align: left text-align: left
#github-login-button
position: relative
top: -1px
border-radius: 5px
img
width: 16px
margin: 0 5px 0 -5px
#gplus-login-button #gplus-login-button
position: relative position: relative
top: 1px top: 1px

View file

@ -69,6 +69,10 @@ block modal-body-wait-content
block modal-footer block modal-footer
.modal-footer .modal-footer
div.network-login
btn.btn.btn-sm.github-login-button#github-login-button
img(src="/images/pages/modal/auth/github_icon.png")
| GitHub
div.network-login div.network-login
.fb-login-button(data-show-faces="false", data-width="200", data-max-rows="1", data-scope="email") .fb-login-button(data-show-faces="false", data-width="200", data-max-rows="1", data-scope="email")
div.network-login div.network-login

View file

@ -14,6 +14,7 @@ module.exports = class AuthModal extends ModalView
# login buttons # login buttons
'click #switch-to-signup-button': 'onSignupInstead' 'click #switch-to-signup-button': 'onSignupInstead'
'click #signup-confirm-age': 'checkAge' 'click #signup-confirm-age': 'checkAge'
'click #github-login-button': 'onGitHubLoginClicked'
'submit': 'onSubmitForm' # handles both submit buttons 'submit': 'onSubmitForm' # handles both submit buttons
'keyup #name': 'onNameChange' 'keyup #name': 'onNameChange'
@ -101,3 +102,6 @@ module.exports = class AuthModal extends ModalView
else else
@suggestedName = newName @suggestedName = newName
forms.setErrorToProperty @$el, 'name', "That name is taken! How about #{newName}?", true forms.setErrorToProperty @$el, 'name', "That name is taken! How about #{newName}?", true
onGitHubLoginClicked: ->
Backbone.Mediator.publish 'github-login'

View file

@ -22,6 +22,7 @@ module.exports.routes =
'routes/db' 'routes/db'
'routes/file' 'routes/file'
'routes/folder' 'routes/folder'
'routes/github'
'routes/languages' 'routes/languages'
'routes/mail' 'routes/mail'
'routes/sprites' 'routes/sprites'

View file

@ -0,0 +1,50 @@
log = require 'winston'
errors = require '../commons/errors'
mongoose = require 'mongoose'
config = require('../../server_config')
request = require 'request'
User = require '../users/User'
module.exports.setup = (app) ->
app.get '/github/auth_callback', (req, res) ->
return errors.forbidden res unless req.user # need identity
response =
code: req.query.code
client_id: config.github.client_id
client_secret: config.github.client_secret
headers =
Accept: 'application/json'
request.post {uri: 'https://github.com/login/oauth/access_token', json: response, headers: headers}, (err, r, response) ->
log.error err if err?
if response.error or err? # If anything goes wrong just 404
res.send 404, response.error_description or err
else
{access_token, token_type, scope} = response
headers =
Accept: 'application/json'
Authorization: "token #{access_token}"
'User-Agent': if config.isProduction then 'CodeCombat' else 'CodeCombatDev'
request.get {uri: 'https://api.github.com/user', headers: headers}, (err, r, response) ->
return log.error err if err?
githubUser = JSON.parse response
emailLower = githubUser.email.toLowerCase()
# GitHub users can change emails
User.findOne {$or: [{emailLower: emailLower}, {githubID: githubUser.id}]}, (err, user) ->
return errors.serverError res, err if err?
wrapup = (err, user) ->
return errors.serverError res, err if err?
req.login (user), (err) ->
return errors.serverError res, err if err?
res.redirect '/'
unless user
req.user.set 'email', githubUser.email
req.user.set 'githubID', githubUser.id
req.user.save wrapup
else if user.get('githubID') isnt githubUser.id # Add or replace githubID to/with existing user
user.set 'githubID', githubUser.id
user.save wrapup
else if user.get('emailLower') isnt emailLower # Existing GitHub user with us changed email
user.update {email: githubUser.email}, (err) -> wrapup err, user
else # All good you've been here before
wrapup null, user

View file

@ -7,6 +7,10 @@ config.ssl_port = process.env.COCO_SSL_PORT or process.env.COCO_SSL_NODE_PORT or
config.cloudflare = config.cloudflare =
token: process.env.COCO_CLOUDFLARE_API_KEY or '' token: process.env.COCO_CLOUDFLARE_API_KEY or ''
config.github =
client_id: process.env.COCO_GITHUB_CLIENT_ID or 'fd5c9d34eb171131bc87'
client_secret: process.env.COCO_GITHUB_CLIENT_SECRET or '2555a86b83f850bc44a98c67c472adb2316a3f05'
config.mongo = config.mongo =
port: process.env.COCO_MONGO_PORT or 27017 port: process.env.COCO_MONGO_PORT or 27017
host: process.env.COCO_MONGO_HOST or 'localhost' host: process.env.COCO_MONGO_HOST or 'localhost'