-
Notifications
You must be signed in to change notification settings - Fork 46
GitHub Auth #91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GitHub Auth #91
Changes from all commits
805e799
bfd244c
a9556e5
2dffca1
d37bbb8
7dfc8a5
1b51534
fd8cb75
a25ceda
03847ad
f3a4a80
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| .source_login { | ||
| display: inline-block; | ||
| height: 40px; | ||
| float: right; | ||
|
|
||
| margin-top: 2px; | ||
| vertical-align: top; | ||
| } | ||
|
|
||
| .source_login-avatar { | ||
| width: 25px; | ||
| height: 25px; | ||
|
|
||
| border-radius: 50%; | ||
| border: 1px solid #FFF; | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| .source_login-avatar.anonymous { | ||
| border: 1px solid #333; | ||
| } | ||
|
|
||
| .source_login-button { | ||
| display: inline-block; | ||
|
|
||
| color: #999; | ||
| text-decoration: none; | ||
| line-height: 1; | ||
| cursor: pointer; | ||
| vertical-align: top; | ||
| margin: 5px 0px 0px 10px; | ||
| } | ||
| .source_login-button:hover { | ||
| color: #FFF | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| define([ | ||
| 'jquery', | ||
| 'sourceModules/module' | ||
| ], function($, Module) { | ||
|
|
||
| 'use strict'; | ||
|
|
||
| /** | ||
| * @Object default module option values | ||
| */ | ||
| var defaults = { | ||
| 'storageKey': 'sourcejsUser', | ||
| 'defaultAvatarURL': '/source/assets/i/unknown.gif', | ||
| 'classes': { | ||
| 'controlsWrapper': 'source_login', | ||
| 'loginButton': 'source_login-button', | ||
| 'avatar': 'source_login-avatar', | ||
| 'anonymous': 'anonymous', | ||
| 'hook': 'js-hook' | ||
| }, | ||
| 'labels': { | ||
| 'login': 'Login', | ||
| 'logout': 'Logout' | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * @module Auth - basic GitHub authorization module. | ||
| * | ||
| * @constructor | ||
| * | ||
| * @param [Object] config - auth inline configuration set of options | ||
| * | ||
| * @param [Object] config.target - jquery domElement which goes to be auth controlls container | ||
| * | ||
| * @param [Object] config.options - options set, which allows to define component configuration. | ||
| */ | ||
|
|
||
| function Auth(config) { | ||
| var _this = this; | ||
|
|
||
| this.conf = $.extend(true, {}, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It must be possible to override config from global optionjs.js.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
| defaults, | ||
| config.options, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think config options must have more priority than user overrides.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so. This config is common for entire project (for team), options is used to customize local instance (single user). |
||
| this.options.modulesOptions.auth | ||
| ); | ||
|
|
||
| this.target = config.target || $(this.conf.classes.hook); | ||
| if(!$(this.target).hasClass(this.conf.classes.controlsWrapper)) { | ||
| $(this.target).addClass(this.conf.classes.controlsWrapper); | ||
| } | ||
| this.popup; | ||
|
|
||
| $(function() { | ||
| _this.init(); | ||
| }); | ||
| } | ||
|
|
||
| Auth.prototype = Module.createInstance(); | ||
| Auth.prototype.constructor = Auth; | ||
|
|
||
| Auth.renderers = { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you leave renderers private? It could be useful to override them in some cases.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just static. the same renderers for all instances. It would be changed then we will use new base module. |
||
| 'avatar': function() { | ||
| var hasAvatar = this.user && this.user.avatar_url; | ||
| this.target.append($([ | ||
| '<img class="', this.conf.classes.avatar, ' ', | ||
| (hasAvatar ? '' : this.conf.classes.anonymous), '" src="', | ||
| (hasAvatar ? this.user.avatar_url : this.conf.defaultAvatarURL), | ||
| '">' | ||
| ].join('') | ||
| )); | ||
| }, | ||
| 'loginButton': function() { | ||
| this.target.append($([ | ||
| '<div class="', this.conf.classes.loginButton, '">', | ||
| (this.user && this.user.id ? this.conf.labels.logout : this.conf.labels.login), | ||
| '</div>' | ||
| ].join('') | ||
| )); | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * @method Auth.login. | ||
| * This function initiates logging in process and creates github login popup. | ||
| */ | ||
| Auth.prototype.login = function() { | ||
| this.popup = open('/auth/stub', 'popup', 'width=1015,height=500'); | ||
| }; | ||
|
|
||
| /** | ||
| * @method Auth.logout. | ||
| * This method removes existed user entity and refreshes control. | ||
| */ | ||
| Auth.prototype.logout = function() { | ||
| localStorage.removeItem(this.conf.storageKey); | ||
| this.render(); | ||
| }; | ||
|
|
||
| /** | ||
| * @method Auth.isLoginned User state getter. | ||
| * | ||
| * @returns {Boolean} isLoginned. It returns true if user is loginned. | ||
| */ | ||
| Auth.prototype.isLoginned = function() { | ||
| return !!localStorage[this.conf.storageKey]; | ||
| }; | ||
|
|
||
| /** | ||
| * @method Auth.getUser GitHub user entity getter. | ||
| * | ||
| * @returns {Object} user || null. | ||
| * If user is loginned it returns user object and null in other case. | ||
| */ | ||
| Auth.prototype.getUser = function() { | ||
| return this.isLoginned() | ||
| ? JSON.parse(localStorage.getItem(this.conf.storageKey)) | ||
| : null; | ||
| }; | ||
|
|
||
| Auth.prototype.init = function() { | ||
| window.sourcejs = window.sourcejs || {}; | ||
| var self = window.sourcejs.__auth = this; | ||
| this.render(); | ||
| $('body').on('click', '.' + this.conf.classes.loginButton, function(e) { | ||
| e.preventDefault(); | ||
| if (self.isLoginned()) { | ||
| self.logout(); | ||
| } else { | ||
| self.login(); | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| Auth.prototype.render = function() { | ||
| var user = this.getUser(); | ||
| var self = this; | ||
| this.target.html(''); | ||
| Object.keys(Auth.renderers).forEach(function(name) { | ||
| Auth.renderers[name].call({ | ||
| 'target': self.target, | ||
| 'user': user, | ||
| 'conf': self.conf | ||
| }); | ||
| }); | ||
| }; | ||
|
|
||
| Auth.prototype.done = function(user) { | ||
| this.popup.close(); | ||
| localStorage.setItem(this.conf.storageKey, JSON.stringify(user)); | ||
| this.render(); | ||
| }; | ||
|
|
||
| return Auth; | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| var everyauth = require('everyauth'); | ||
| var fs = require('fs'); | ||
| var ejs = require('ejs'); | ||
| var path = require('path'); | ||
|
|
||
| module.exports = function(app) { | ||
| "use strict"; | ||
|
|
||
| app.states = app.states || {}; | ||
| app.states.users = app.states.users || {}; | ||
|
|
||
| var currentUserId = ""; | ||
|
|
||
| // users data processing | ||
| /** | ||
| * @method getUser - user getter | ||
| * | ||
| * @param {String} id - github user id | ||
| * | ||
| * @returns {Object} - user - github user entity or empty object, if user is undefined | ||
| */ | ||
| var getUser = function(id) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want this methods globally available, for plugins and other modules. |
||
| return app.states.users[id] || {}; | ||
| }; | ||
|
|
||
| /** | ||
| * @method setUser - user setter | ||
| * | ||
| * @param {Object} user - github user entity | ||
| * | ||
| * @param {String} user.id - required user field, which is used as user templral storage key. | ||
| * | ||
| * @returns {Object} user - returns user parameter | ||
| */ | ||
| var setUser = function(user) { | ||
| if (typeof user !== "object" || !user.id) return; | ||
| app.states.users[user.id] = user; | ||
| return user; | ||
| }; | ||
|
|
||
| everyauth.everymodule.findUserById(function(id, callback) { | ||
| callback(null, getUser(id)); | ||
| }); | ||
|
|
||
| // TODO: separated id & secret for dev mode | ||
| everyauth.github | ||
| .appId(global.opts.github.appId) | ||
| .appSecret(global.opts.github.appSecret) | ||
| .findOrCreateUser(function(sess, accessToken, accessTokenExtra, ghUser) { | ||
| setUser(ghUser); | ||
| currentUserId = ghUser.id; | ||
| return ghUser; | ||
| }) | ||
| .redirectPath('/auth/done'); | ||
|
|
||
|
|
||
| everyauth.everymodule.handleLogout( function (req, res) { | ||
| delete req.session.authCache; | ||
| req.logout(); | ||
| this.redirect(res, this.logoutRedirectPath()); | ||
| }); | ||
|
|
||
| // application routes | ||
| var authTemplate = fs.readFileSync(path.join(global.pathToApp, '/core/views/auth-done.ejs'), "utf8"); | ||
| app.get('/auth/stub', function (req, res) { | ||
| res.send(require('ejs').render(authTemplate, { | ||
| 'user': JSON.stringify({}) | ||
| })); | ||
| }); | ||
|
|
||
| app.get('/auth/done', function (req, res) { | ||
| req.session.authCache = req.session.auth; | ||
|
|
||
| res.send(ejs.render(authTemplate, { | ||
| 'user': JSON.stringify(getUser(currentUserId)) | ||
| })); | ||
| }); | ||
|
|
||
| return { | ||
| 'getUser': getUser, | ||
| 'setUser': setUser, | ||
| 'everyauth': everyauth | ||
| }; | ||
|
|
||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| <!DOCTYPE html> | ||
| <head> | ||
| <title>Github OAuth</title> | ||
| <style type="text/css"> | ||
| body { overflow: hidden; margin: 0; text-align: center; } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <img src="/source/assets/i/github-loagind.gif" width="500" alt="Loading"> | ||
| <script type="text/javascript"> | ||
| window.addEventListener('load', function() { | ||
| var data; | ||
| try { | ||
| data = JSON.parse("<%= user %>".split(""").join('"')); | ||
| } catch(e) { | ||
| console.log('incorrect user data', e); | ||
| } | ||
| if (!data instanceof Object || !data.id) { | ||
| window.location = "/auth/github"; | ||
| } else { | ||
| opener.sourcejs.__auth.done(data); | ||
| } | ||
| }); | ||
| </script> | ||
| </body> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like