mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 17:45:40 -05:00
GitHub Login implemented
This commit is contained in:
parent
9fd31c70e7
commit
40818fd7bc
10 changed files with 91 additions and 1 deletions
|
@ -63,6 +63,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')
|
||||||
|
|
|
@ -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'
|
locale = require 'locale/locale'
|
||||||
{me} = require 'lib/auth'
|
{me} = require 'lib/auth'
|
||||||
Tracker = require 'lib/Tracker'
|
Tracker = require 'lib/Tracker'
|
||||||
|
@ -36,9 +37,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
|
||||||
$.notify.addStyle 'achievement', html: $(AchievementNotify())
|
$.notify.addStyle 'achievement', html: $(AchievementNotify())
|
||||||
@linkedinHandler = new LinkedInHandler()
|
@linkedinHandler = new LinkedInHandler()
|
||||||
|
|
22
app/lib/GitHubHandler.coffee
Normal file
22
app/lib/GitHubHandler.coffee
Normal 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'
|
||||||
|
@redirect_uri = 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: @redirect_uri
|
||||||
|
|
||||||
|
location.href = "https://github.com/login/oauth/authorize?" + $.param(request)
|
|
@ -19,7 +19,8 @@ module.exports.createUser = (userObject, failure=backboneFailure, nextURL=null)
|
||||||
user.notyErrors = false
|
user.notyErrors = false
|
||||||
user.save({}, {
|
user.save({}, {
|
||||||
error: (model, jqxhr, options) ->
|
error: (model, jqxhr, options) ->
|
||||||
error = parseServerError(jqxhr.responseText)
|
error = parseServerError(jqxhr
|
||||||
|
.responseText)
|
||||||
property = error.property if error.property
|
property = error.property if error.property
|
||||||
if jqxhr.status is 409 and property is 'name'
|
if jqxhr.status is 409 and property is 'name'
|
||||||
anonUserObject = _.omit(userObject, 'name')
|
anonUserObject = _.omit(userObject, 'name')
|
||||||
|
|
|
@ -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'})
|
||||||
|
|
|
@ -69,6 +69,8 @@ block modal-body-wait-content
|
||||||
|
|
||||||
block modal-footer
|
block modal-footer
|
||||||
.modal-footer
|
.modal-footer
|
||||||
|
div.network-login
|
||||||
|
btn.btn.github-login-button#github-login-button 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
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -21,6 +21,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'
|
||||||
|
|
50
server/routes/github.coffee
Normal file
50
server/routes/github.coffee
Normal 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
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in a new issue