nodebb-plugin-sso-github 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +22 -22
- package/LICENSE +7 -7
- package/README.md +15 -15
- package/library.js +258 -249
- package/package.json +1 -1
- package/plugin.json +18 -18
- package/static/lib/admin.js +25 -25
- package/templates/admin/plugins/sso-github.tpl +45 -47
- package/templates/plugins/sso-github/deauth.tpl +16 -16
package/.gitattributes
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
# Auto detect text files and perform LF normalization
|
|
2
|
-
* text=auto
|
|
3
|
-
|
|
4
|
-
# Custom for Visual Studio
|
|
5
|
-
*.cs diff=csharp
|
|
6
|
-
*.sln merge=union
|
|
7
|
-
*.csproj merge=union
|
|
8
|
-
*.vbproj merge=union
|
|
9
|
-
*.fsproj merge=union
|
|
10
|
-
*.dbproj merge=union
|
|
11
|
-
|
|
12
|
-
# Standard to msysgit
|
|
13
|
-
*.doc diff=astextplain
|
|
14
|
-
*.DOC diff=astextplain
|
|
15
|
-
*.docx diff=astextplain
|
|
16
|
-
*.DOCX diff=astextplain
|
|
17
|
-
*.dot diff=astextplain
|
|
18
|
-
*.DOT diff=astextplain
|
|
19
|
-
*.pdf diff=astextplain
|
|
20
|
-
*.PDF diff=astextplain
|
|
21
|
-
*.rtf diff=astextplain
|
|
22
|
-
*.RTF diff=astextplain
|
|
1
|
+
# Auto detect text files and perform LF normalization
|
|
2
|
+
* text=auto
|
|
3
|
+
|
|
4
|
+
# Custom for Visual Studio
|
|
5
|
+
*.cs diff=csharp
|
|
6
|
+
*.sln merge=union
|
|
7
|
+
*.csproj merge=union
|
|
8
|
+
*.vbproj merge=union
|
|
9
|
+
*.fsproj merge=union
|
|
10
|
+
*.dbproj merge=union
|
|
11
|
+
|
|
12
|
+
# Standard to msysgit
|
|
13
|
+
*.doc diff=astextplain
|
|
14
|
+
*.DOC diff=astextplain
|
|
15
|
+
*.docx diff=astextplain
|
|
16
|
+
*.DOCX diff=astextplain
|
|
17
|
+
*.dot diff=astextplain
|
|
18
|
+
*.DOT diff=astextplain
|
|
19
|
+
*.pdf diff=astextplain
|
|
20
|
+
*.PDF diff=astextplain
|
|
21
|
+
*.rtf diff=astextplain
|
|
22
|
+
*.RTF diff=astextplain
|
package/LICENSE
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
Copyright (c) 2013-2014, psychobunny <psycho.bunny@hotmail.com>
|
|
2
|
-
All rights reserved.
|
|
3
|
-
|
|
4
|
-
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
5
|
-
|
|
6
|
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
7
|
-
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
1
|
+
Copyright (c) 2013-2014, psychobunny <psycho.bunny@hotmail.com>
|
|
2
|
+
All rights reserved.
|
|
3
|
+
|
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
5
|
+
|
|
6
|
+
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
7
|
+
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
8
8
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# NodeBB GitHub SSO
|
|
2
|
-
|
|
3
|
-
NodeBB Plugin that allows users to login/register via their GitHub account.
|
|
4
|
-
|
|
5
|
-
----
|
|
6
|
-
Nov 13, 2020. Fixed a few problems:
|
|
7
|
-
|
|
8
|
-
1. fetch non-public github emails.
|
|
9
|
-
2. fetch user's github avatar.
|
|
10
|
-
3. add setting of trusting user's github email or not.
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
npm install nodebb-plugin-sso-github
|
|
15
|
-
|
|
1
|
+
# NodeBB GitHub SSO
|
|
2
|
+
|
|
3
|
+
NodeBB Plugin that allows users to login/register via their GitHub account.
|
|
4
|
+
|
|
5
|
+
----
|
|
6
|
+
Nov 13, 2020. Fixed a few problems:
|
|
7
|
+
|
|
8
|
+
1. fetch non-public github emails.
|
|
9
|
+
2. fetch user's github avatar.
|
|
10
|
+
3. add setting of trusting user's github email or not.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
npm install nodebb-plugin-sso-github
|
|
15
|
+
|
package/library.js
CHANGED
|
@@ -1,249 +1,258 @@
|
|
|
1
|
-
(function(module) {
|
|
2
|
-
"use strict";
|
|
3
|
-
|
|
4
|
-
var User = require.main.require('./src/user');
|
|
5
|
-
var db = require.main.require('./src/database');
|
|
6
|
-
var meta = require.main.require('./src/meta');
|
|
7
|
-
var nconf = require.main.require('nconf');
|
|
8
|
-
var async = require.main.require('async');
|
|
9
|
-
var passport = require.main.require('passport');
|
|
10
|
-
var GithubStrategy = require('passport-github2').Strategy;
|
|
11
|
-
|
|
12
|
-
var winston = require.main.require('winston');
|
|
13
|
-
|
|
14
|
-
var authenticationController = require.main.require('./src/controllers/authentication');
|
|
15
|
-
|
|
16
|
-
var constants = Object.freeze({
|
|
17
|
-
'name': "GitHub",
|
|
18
|
-
'admin': {
|
|
19
|
-
'icon': 'fa-github',
|
|
20
|
-
'route': '/plugins/sso-github'
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
var GitHub = {};
|
|
25
|
-
|
|
26
|
-
GitHub.getStrategy = function(strategies, callback) {
|
|
27
|
-
meta.settings.get('sso-github', function(err, settings) {
|
|
28
|
-
GitHub.settings = settings;
|
|
29
|
-
|
|
30
|
-
if (!err && settings.id && settings.secret) {
|
|
31
|
-
passport.use(new GithubStrategy({
|
|
32
|
-
clientID: settings.id,
|
|
33
|
-
clientSecret: settings.secret,
|
|
34
|
-
callbackURL: nconf.get('url') + '/auth/github/callback',
|
|
35
|
-
passReqToCallback: true,
|
|
36
|
-
scope: [ 'user:email' ] // fetches non-public emails as well
|
|
37
|
-
}, function(req, token, tokenSecret, profile, done) {
|
|
38
|
-
if (req.hasOwnProperty('user') && req.user.hasOwnProperty('uid') && req.user.uid > 0) {
|
|
39
|
-
// Save GitHub -specific information to the user
|
|
40
|
-
User.setUserField(req.user.uid, 'githubid', profile.id);
|
|
41
|
-
db.setObjectField('githubid:uid', profile.id, req.user.uid);
|
|
42
|
-
return done(null, req.user);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
var email = Array.isArray(profile.emails) && profile.emails.length ? profile.emails[0].value : '';
|
|
46
|
-
var pictureUrl = Array.isArray(profile.photos) && profile.photos.length ? profile.photos[0].value : '';
|
|
47
|
-
GitHub.login(profile.id, profile.displayName, profile.username, email, pictureUrl, function(err, user) {
|
|
48
|
-
if (err) {
|
|
49
|
-
return done(err);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
authenticationController.onSuccessfulLogin(req, user.uid);
|
|
53
|
-
done(null, user);
|
|
54
|
-
});
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
strategies.push({
|
|
58
|
-
name: 'github',
|
|
59
|
-
url: '/auth/github',
|
|
60
|
-
callbackURL: '/auth/github/callback',
|
|
61
|
-
icon: constants.admin.icon,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
res.render('plugins/sso-github
|
|
212
|
-
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
1
|
+
(function(module) {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
var User = require.main.require('./src/user');
|
|
5
|
+
var db = require.main.require('./src/database');
|
|
6
|
+
var meta = require.main.require('./src/meta');
|
|
7
|
+
var nconf = require.main.require('nconf');
|
|
8
|
+
var async = require.main.require('async');
|
|
9
|
+
var passport = require.main.require('passport');
|
|
10
|
+
var GithubStrategy = require('passport-github2').Strategy;
|
|
11
|
+
|
|
12
|
+
var winston = require.main.require('winston');
|
|
13
|
+
|
|
14
|
+
var authenticationController = require.main.require('./src/controllers/authentication');
|
|
15
|
+
|
|
16
|
+
var constants = Object.freeze({
|
|
17
|
+
'name': "GitHub",
|
|
18
|
+
'admin': {
|
|
19
|
+
'icon': 'fa-github',
|
|
20
|
+
'route': '/plugins/sso-github'
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
var GitHub = {};
|
|
25
|
+
|
|
26
|
+
GitHub.getStrategy = function(strategies, callback) {
|
|
27
|
+
meta.settings.get('sso-github', function(err, settings) {
|
|
28
|
+
GitHub.settings = settings;
|
|
29
|
+
|
|
30
|
+
if (!err && settings.id && settings.secret) {
|
|
31
|
+
passport.use(new GithubStrategy({
|
|
32
|
+
clientID: settings.id,
|
|
33
|
+
clientSecret: settings.secret,
|
|
34
|
+
callbackURL: nconf.get('url') + '/auth/github/callback',
|
|
35
|
+
passReqToCallback: true,
|
|
36
|
+
scope: [ 'user:email' ] // fetches non-public emails as well
|
|
37
|
+
}, function(req, token, tokenSecret, profile, done) {
|
|
38
|
+
if (req.hasOwnProperty('user') && req.user.hasOwnProperty('uid') && req.user.uid > 0) {
|
|
39
|
+
// Save GitHub -specific information to the user
|
|
40
|
+
User.setUserField(req.user.uid, 'githubid', profile.id);
|
|
41
|
+
db.setObjectField('githubid:uid', profile.id, req.user.uid);
|
|
42
|
+
return done(null, req.user);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var email = Array.isArray(profile.emails) && profile.emails.length ? profile.emails[0].value : '';
|
|
46
|
+
var pictureUrl = Array.isArray(profile.photos) && profile.photos.length ? profile.photos[0].value : '';
|
|
47
|
+
GitHub.login(profile.id, profile.displayName, profile.username, email, pictureUrl, function(err, user) {
|
|
48
|
+
if (err) {
|
|
49
|
+
return done(err);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
authenticationController.onSuccessfulLogin(req, user.uid);
|
|
53
|
+
done(null, user);
|
|
54
|
+
});
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
strategies.push({
|
|
58
|
+
name: 'github',
|
|
59
|
+
url: '/auth/github',
|
|
60
|
+
callbackURL: '/auth/github/callback',
|
|
61
|
+
icon: constants.admin.icon,
|
|
62
|
+
icons: {
|
|
63
|
+
normal: 'fa-github',
|
|
64
|
+
square: 'fa-github-square',
|
|
65
|
+
},
|
|
66
|
+
labels: {
|
|
67
|
+
login: '[[social:sign-in-with-github]]',
|
|
68
|
+
register: '[[social:sign-up-with-github]]',
|
|
69
|
+
},
|
|
70
|
+
color: '#25292f',
|
|
71
|
+
scope: 'user:email'
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
callback(null, strategies);
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
GitHub.appendUserHashWhitelist = function (data, callback) {
|
|
80
|
+
data.whitelist.push('githubid');
|
|
81
|
+
setImmediate(callback, null, data);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
GitHub.getAssociation = function(data, callback) {
|
|
85
|
+
User.getUserField(data.uid, 'githubid', function(err, githubid) {
|
|
86
|
+
if (err) {
|
|
87
|
+
return callback(err, data);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (githubid) {
|
|
91
|
+
data.associations.push({
|
|
92
|
+
associated: true,
|
|
93
|
+
name: constants.name,
|
|
94
|
+
icon: constants.admin.icon,
|
|
95
|
+
deauthUrl: nconf.get('url') + '/deauth/github',
|
|
96
|
+
});
|
|
97
|
+
} else {
|
|
98
|
+
data.associations.push({
|
|
99
|
+
associated: false,
|
|
100
|
+
url: nconf.get('url') + '/auth/github',
|
|
101
|
+
name: constants.name,
|
|
102
|
+
icon: constants.admin.icon
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
callback(null, data);
|
|
107
|
+
})
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
GitHub.login = function(githubID, displayName, username, email, pictureUrl, callback) {
|
|
111
|
+
if (!email) {
|
|
112
|
+
email = username + '@users.noreply.github.com';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
GitHub.getUidByGitHubID(githubID, function(err, uid) {
|
|
116
|
+
if (err) {
|
|
117
|
+
return callback(err);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (uid) {
|
|
121
|
+
// Existing User
|
|
122
|
+
callback(null, {
|
|
123
|
+
uid: uid
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
// New User
|
|
127
|
+
var success = function(uid) {
|
|
128
|
+
function checkEmail(next) {
|
|
129
|
+
if (GitHub.settings.needToVerifyEmail === 'on') {
|
|
130
|
+
return next();
|
|
131
|
+
}
|
|
132
|
+
User.email.confirmByUid(uid, next);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function mergeUserData(next) {
|
|
136
|
+
async.waterfall([
|
|
137
|
+
async.apply(User.getUserFields, uid, ['picture', 'firstName', 'lastName', 'fullname']),
|
|
138
|
+
function(info, next) {
|
|
139
|
+
if (!info.picture && pictureUrl) { // set profile picture
|
|
140
|
+
User.setUserField(uid, 'uploadedpicture', pictureUrl);
|
|
141
|
+
User.setUserField(uid, 'picture', pictureUrl);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!info.fullname && displayName) {
|
|
145
|
+
User.setUserField(uid, 'fullname', displayName);
|
|
146
|
+
}
|
|
147
|
+
next();
|
|
148
|
+
}
|
|
149
|
+
], next);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// trust the email.
|
|
153
|
+
async.series([
|
|
154
|
+
async.apply(User.setUserField, uid, 'githubid', githubID),
|
|
155
|
+
async.apply(db.setObjectField, 'githubid:uid', githubID, uid),
|
|
156
|
+
checkEmail,
|
|
157
|
+
mergeUserData
|
|
158
|
+
], function (err) {
|
|
159
|
+
callback(err, {
|
|
160
|
+
uid: uid
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
User.getUidByEmail(email, function(err, uid) {
|
|
166
|
+
if (!uid) {
|
|
167
|
+
// Abort user creation if registration via SSO is restricted
|
|
168
|
+
if (GitHub.settings.disableRegistration === 'on') {
|
|
169
|
+
return callback(new Error('[[error:sso-registration-disabled, GitHub]]'));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
User.create({username: username, email: email}, function(err, uid) {
|
|
173
|
+
if (err !== null) {
|
|
174
|
+
callback(err);
|
|
175
|
+
} else {
|
|
176
|
+
success(uid);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
} else {
|
|
180
|
+
success(uid); // Existing account -- merge
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
GitHub.getUidByGitHubID = function(githubID, callback) {
|
|
188
|
+
db.getObjectField('githubid:uid', githubID, function(err, uid) {
|
|
189
|
+
if (err) {
|
|
190
|
+
callback(err);
|
|
191
|
+
} else {
|
|
192
|
+
callback(null, uid);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
GitHub.addMenuItem = function(custom_header, callback) {
|
|
198
|
+
custom_header.authentication.push({
|
|
199
|
+
"route": constants.admin.route,
|
|
200
|
+
"icon": constants.admin.icon,
|
|
201
|
+
"name": constants.name
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
callback(null, custom_header);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
GitHub.init = function(data, callback) {
|
|
208
|
+
var hostHelpers = require.main.require('./src/routes/helpers');
|
|
209
|
+
|
|
210
|
+
function renderAdmin(req, res) {
|
|
211
|
+
res.render('admin/plugins/sso-github', {
|
|
212
|
+
callbackURL: nconf.get('url') + '/auth/github/callback'
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
data.router.get('/admin/plugins/sso-github', data.middleware.admin.buildHeader, renderAdmin);
|
|
217
|
+
data.router.get('/api/admin/plugins/sso-github', renderAdmin);
|
|
218
|
+
|
|
219
|
+
hostHelpers.setupPageRoute(data.router, '/deauth/github', data.middleware, [data.middleware.requireUser], function (req, res) {
|
|
220
|
+
res.render('plugins/sso-github/deauth', {
|
|
221
|
+
service: "GitHub",
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
data.router.post('/deauth/github', [data.middleware.requireUser, data.middleware.applyCSRF], function (req, res, next) {
|
|
225
|
+
GitHub.deleteUserData({
|
|
226
|
+
uid: req.user.uid,
|
|
227
|
+
}, function (err) {
|
|
228
|
+
if (err) {
|
|
229
|
+
return next(err);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
res.redirect(nconf.get('relative_path') + '/me/edit');
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
callback();
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
GitHub.deleteUserData = function(data, callback) {
|
|
240
|
+
var uid = data.uid;
|
|
241
|
+
|
|
242
|
+
async.waterfall([
|
|
243
|
+
async.apply(User.getUserField, uid, 'githubid'),
|
|
244
|
+
function(oAuthIdToDelete, next) {
|
|
245
|
+
db.deleteObjectField('githubid:uid', oAuthIdToDelete, next);
|
|
246
|
+
},
|
|
247
|
+
async.apply(db.deleteObjectField, 'user:' + uid, 'githubid'),
|
|
248
|
+
], function(err) {
|
|
249
|
+
if (err) {
|
|
250
|
+
winston.error('[sso-github] Could not remove OAuthId data for uid ' + uid + '. Error: ' + err);
|
|
251
|
+
return callback(err);
|
|
252
|
+
}
|
|
253
|
+
callback(null, uid);
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
module.exports = GitHub;
|
|
258
|
+
}(module));
|
package/package.json
CHANGED
package/plugin.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
{
|
|
2
|
-
"id": "nodebb-plugin-sso-github",
|
|
3
|
-
"name": "NodeBB GitHub SSO",
|
|
4
|
-
"description": "NodeBB Plugin that allows users to login/register via their GitHub account.",
|
|
5
|
-
"url": "https://github.com/julianlam/nodebb-plugin-sso-github",
|
|
6
|
-
"library": "./library.js",
|
|
7
|
-
"hooks": [
|
|
8
|
-
{ "hook": "static:app.load", "method": "init" },
|
|
9
|
-
{ "hook": "filter:auth.init", "method": "getStrategy" },
|
|
10
|
-
{ "hook": "filter:auth.list", "method": "getAssociation" },
|
|
11
|
-
{ "hook": "filter:admin.header.build", "method": "addMenuItem" },
|
|
12
|
-
{ "hook": "static:user.delete", "method": "deleteUserData" },
|
|
13
|
-
{ "hook": "filter:user.whitelistFields", "method": "appendUserHashWhitelist" }
|
|
14
|
-
],
|
|
15
|
-
"templates": "./templates",
|
|
16
|
-
"modules": {
|
|
17
|
-
"../admin/plugins/sso-github.js": "static/lib/admin.js"
|
|
18
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"id": "nodebb-plugin-sso-github",
|
|
3
|
+
"name": "NodeBB GitHub SSO",
|
|
4
|
+
"description": "NodeBB Plugin that allows users to login/register via their GitHub account.",
|
|
5
|
+
"url": "https://github.com/julianlam/nodebb-plugin-sso-github",
|
|
6
|
+
"library": "./library.js",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{ "hook": "static:app.load", "method": "init" },
|
|
9
|
+
{ "hook": "filter:auth.init", "method": "getStrategy" },
|
|
10
|
+
{ "hook": "filter:auth.list", "method": "getAssociation" },
|
|
11
|
+
{ "hook": "filter:admin.header.build", "method": "addMenuItem" },
|
|
12
|
+
{ "hook": "static:user.delete", "method": "deleteUserData" },
|
|
13
|
+
{ "hook": "filter:user.whitelistFields", "method": "appendUserHashWhitelist" }
|
|
14
|
+
],
|
|
15
|
+
"templates": "./templates",
|
|
16
|
+
"modules": {
|
|
17
|
+
"../admin/plugins/sso-github.js": "static/lib/admin.js"
|
|
18
|
+
}
|
|
19
19
|
}
|
package/static/lib/admin.js
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
define('admin/plugins/sso-github', ['settings'], function(Settings) {
|
|
2
|
-
'use strict';
|
|
3
|
-
/* globals $, app, socket, require */
|
|
4
|
-
|
|
5
|
-
var ACP = {};
|
|
6
|
-
|
|
7
|
-
ACP.init = function() {
|
|
8
|
-
Settings.load('sso-github', $('.sso-github-settings'));
|
|
9
|
-
|
|
10
|
-
$('#save').on('click', function() {
|
|
11
|
-
Settings.save('sso-github', $('.sso-github-settings'), function() {
|
|
12
|
-
|
|
13
|
-
type: 'success',
|
|
14
|
-
alert_id: 'sso-github-saved',
|
|
15
|
-
title: 'Settings Saved',
|
|
16
|
-
message: 'Please reload your NodeBB to apply these settings',
|
|
17
|
-
clickfn: function() {
|
|
18
|
-
socket.emit('admin.reload');
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
return ACP;
|
|
1
|
+
define('admin/plugins/sso-github', ['settings', 'alerts'], function(Settings, alerts) {
|
|
2
|
+
'use strict';
|
|
3
|
+
/* globals $, app, socket, require */
|
|
4
|
+
|
|
5
|
+
var ACP = {};
|
|
6
|
+
|
|
7
|
+
ACP.init = function() {
|
|
8
|
+
Settings.load('sso-github', $('.sso-github-settings'));
|
|
9
|
+
|
|
10
|
+
$('#save').on('click', function() {
|
|
11
|
+
Settings.save('sso-github', $('.sso-github-settings'), function() {
|
|
12
|
+
alerts.alert({
|
|
13
|
+
type: 'success',
|
|
14
|
+
alert_id: 'sso-github-saved',
|
|
15
|
+
title: 'Settings Saved',
|
|
16
|
+
message: 'Please reload your NodeBB to apply these settings',
|
|
17
|
+
clickfn: function() {
|
|
18
|
+
socket.emit('admin.reload');
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return ACP;
|
|
26
26
|
});
|
|
@@ -1,47 +1,45 @@
|
|
|
1
|
-
<div class="row">
|
|
2
|
-
<div class="col-sm-2 col-12 settings-header">GitHub SSO</div>
|
|
3
|
-
<div class="col-sm-10 col-12">
|
|
4
|
-
<div class="alert alert-info">
|
|
5
|
-
Register a new <strong>GitHub Application</strong> via
|
|
6
|
-
<a href="https://github.com/settings/developers">Developer Applications</a> and then paste your application details here.
|
|
7
|
-
</div>
|
|
8
|
-
<form class="sso-github-settings">
|
|
9
|
-
<div class="mb-3">
|
|
10
|
-
<label for="id">Client ID</label>
|
|
11
|
-
<input type="text" name="id" title="Client ID" class="form-control" placeholder="Client ID">
|
|
12
|
-
</div>
|
|
13
|
-
<div class="mb-3">
|
|
14
|
-
<label for="secret">Client Secret</label>
|
|
15
|
-
<input type="text" name="secret" title="Client Secret" class="form-control" placeholder="Client Secret" />
|
|
16
|
-
</div>
|
|
17
|
-
<div class="mb-3 alert alert-warning">
|
|
18
|
-
<label for="callback">Your NodeBB's "Authorization callback URL"</label>
|
|
19
|
-
<input type="text" id="callback" title="Authorization callback URL" class="form-control" value="{callbackURL}" readonly />
|
|
20
|
-
<p class="form-text">
|
|
21
|
-
Ensure that this value is set in your GitHub application's settings
|
|
22
|
-
</p>
|
|
23
|
-
</div>
|
|
24
|
-
<div class="form-check">
|
|
25
|
-
<input type="checkbox" class="form-check-input" id="disableRegistration" name="disableRegistration" />
|
|
26
|
-
<label for="disableRegistration" class="form-check-label">
|
|
27
|
-
Disable user registration via SSO
|
|
28
|
-
</label>
|
|
29
|
-
</div>
|
|
30
|
-
<div class="form-check">
|
|
31
|
-
<input type="checkbox" class="form-check-input" id="needToVerifyEmail" name="needToVerifyEmail" />
|
|
32
|
-
<label for="needToVerifyEmail" class="form-check-label">
|
|
33
|
-
Need user to verify email
|
|
34
|
-
</label>
|
|
35
|
-
</div>
|
|
36
|
-
<p class="form-text">
|
|
37
|
-
Restricting registration means that only registered users can associate their account with this SSO strategy.
|
|
38
|
-
This restriction is useful if you have uesrs bypassing registration controls by using social media accounts, or
|
|
39
|
-
if you wish to use the NodeBB registration queue.
|
|
40
|
-
</p>
|
|
41
|
-
</form>
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<i class="material-icons">save</i>
|
|
47
|
-
</button>
|
|
1
|
+
<div class="row">
|
|
2
|
+
<div class="col-sm-2 col-12 settings-header">GitHub SSO</div>
|
|
3
|
+
<div class="col-sm-10 col-12">
|
|
4
|
+
<div class="alert alert-info">
|
|
5
|
+
Register a new <strong>GitHub Application</strong> via
|
|
6
|
+
<a href="https://github.com/settings/developers">Developer Applications</a> and then paste your application details here.
|
|
7
|
+
</div>
|
|
8
|
+
<form class="sso-github-settings">
|
|
9
|
+
<div class="mb-3">
|
|
10
|
+
<label for="id">Client ID</label>
|
|
11
|
+
<input type="text" name="id" title="Client ID" class="form-control" placeholder="Client ID">
|
|
12
|
+
</div>
|
|
13
|
+
<div class="mb-3">
|
|
14
|
+
<label for="secret">Client Secret</label>
|
|
15
|
+
<input type="text" name="secret" title="Client Secret" class="form-control" placeholder="Client Secret" />
|
|
16
|
+
</div>
|
|
17
|
+
<div class="mb-3 alert alert-warning">
|
|
18
|
+
<label for="callback">Your NodeBB's "Authorization callback URL"</label>
|
|
19
|
+
<input type="text" id="callback" title="Authorization callback URL" class="form-control" value="{callbackURL}" readonly />
|
|
20
|
+
<p class="form-text">
|
|
21
|
+
Ensure that this value is set in your GitHub application's settings
|
|
22
|
+
</p>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="form-check">
|
|
25
|
+
<input type="checkbox" class="form-check-input" id="disableRegistration" name="disableRegistration" />
|
|
26
|
+
<label for="disableRegistration" class="form-check-label">
|
|
27
|
+
Disable user registration via SSO
|
|
28
|
+
</label>
|
|
29
|
+
</div>
|
|
30
|
+
<div class="form-check">
|
|
31
|
+
<input type="checkbox" class="form-check-input" id="needToVerifyEmail" name="needToVerifyEmail" />
|
|
32
|
+
<label for="needToVerifyEmail" class="form-check-label">
|
|
33
|
+
Need user to verify email
|
|
34
|
+
</label>
|
|
35
|
+
</div>
|
|
36
|
+
<p class="form-text">
|
|
37
|
+
Restricting registration means that only registered users can associate their account with this SSO strategy.
|
|
38
|
+
This restriction is useful if you have uesrs bypassing registration controls by using social media accounts, or
|
|
39
|
+
if you wish to use the NodeBB registration queue.
|
|
40
|
+
</p>
|
|
41
|
+
</form>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<!-- IMPORT admin/partials/save_button.tpl -->
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
|
|
2
|
-
<div class="panel panel-default">
|
|
3
|
-
<div class="panel-heading">
|
|
4
|
-
<h3 class="panel-title">[[user:sso.dissociate-confirm-title]]</h3>
|
|
5
|
-
</div>
|
|
6
|
-
<div class="panel-body">
|
|
7
|
-
[[user:sso.dissociate-confirm, {service}]]
|
|
8
|
-
|
|
9
|
-
<hr>
|
|
10
|
-
|
|
11
|
-
<form method="post">
|
|
12
|
-
<input type="hidden" name="_csrf" value="{config.csrf_token}" />
|
|
13
|
-
<button class="btn btn-danger">[[user:sso.dissociate]]</button>
|
|
14
|
-
</form>
|
|
15
|
-
</div>
|
|
16
|
-
</div>
|
|
1
|
+
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
|
|
2
|
+
<div class="panel panel-default">
|
|
3
|
+
<div class="panel-heading">
|
|
4
|
+
<h3 class="panel-title">[[user:sso.dissociate-confirm-title]]</h3>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="panel-body">
|
|
7
|
+
[[user:sso.dissociate-confirm, {service}]]
|
|
8
|
+
|
|
9
|
+
<hr>
|
|
10
|
+
|
|
11
|
+
<form method="post">
|
|
12
|
+
<input type="hidden" name="_csrf" value="{config.csrf_token}" />
|
|
13
|
+
<button class="btn btn-danger">[[user:sso.dissociate]]</button>
|
|
14
|
+
</form>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
17
|
</div>
|