new version

This commit is contained in:
Evert Prants 2019-09-06 19:03:42 +03:00
commit 1b15b4f3b7
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
8 changed files with 3320 additions and 67 deletions

137
.eslintrc Normal file
View File

@ -0,0 +1,137 @@
{
"extends": "airbnb-base",
"parserOptions": {
"sourceType": "script"
},
"rules": {
// Customized
"handle-callback-err": [ "error","^(e$|(e|(.*(_e|E)))rr)" ],
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "never"
}],
"no-empty": ["error", { "allowEmptyCatch": true }],
"no-underscore-dangle": "off",
"no-console": "off",
"no-mixed-operators": ["error", { "allowSamePrecedence": true }],
"strict": ["error", "global"],
"consistent-return": "off",
"func-names": "off",
"no-tabs": "off",
"indent": ["error", "tab"],
"no-eq-null": "off",
"camelcase": "off",
"no-new": "off",
"no-shadow": "off",
"no-use-before-define": ["error", "nofunc"],
"no-prototype-builtins": "off",
"new-cap": "off",
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
"object-curly-newline": "off",
"no-restricted-globals": "off",
"function-paren-newline": "off",
"import/no-unresolved": "error",
"quotes": ["error", "single", {
"avoidEscape": true,
"allowTemplateLiterals": true
}],
"no-else-return": [ "error", { "allowElseIf": true } ],
"operator-linebreak": [ "error", "after" ],
// ES6
"prefer-rest-params": "off",
"prefer-spread": "off",
"prefer-arrow-callback": "off",
"prefer-template": "off",
"no-var": "off",
"object-shorthand": "off",
"vars-on-top": "off",
"prefer-destructuring": "off",
// TODO
"import/no-extraneous-dependencies": "off",
"import/no-dynamic-require": "off",
"import/newline-after-import": "off",
"no-bitwise": "off",
"global-require": "off",
"max-len": "off",
"no-param-reassign": "off",
"no-restricted-syntax": "off",
"no-script-url": "off",
"default-case": "off",
"linebreak-style": "off",
// "no-multi-assign": "off",
// "one-var": "off",
// "no-undef": "off",
// "max-nested-callbacks": "off",
// "no-mixed-requires": "off",
// "brace-style": "off",
// "max-statements-per-line": "off",
// "no-unused-vars": "off",
// "no-mixed-spaces-and-tabs": "off",
// "no-useless-concat": "off",
// "require-jsdoc": "off",
// "eqeqeq": "off",
// "no-negated-condition": "off",
// "one-var-declaration-per-line": "off",
// "no-lonely-if": "off",
// "radix": "off",
// "no-else-return": "off",
// "no-useless-escape": "off",
// "block-scoped-var": "off",
// "operator-assignment": "off",
// "yoda": "off",
// "no-loop-func": "off",
// "no-void": "off",
// "valid-jsdoc": "off",
// "no-cond-assign": "off",
// "no-redeclare": "off",
// "no-unreachable": "off",
// "no-nested-ternary": "off",
// "operator-linebreak": "off",
// "guard-for-in": "off",
// "no-unneeded-ternary": "off",
// "no-sequences": "off",
// "no-extend-native": "off",
// "no-shadow-restricted-names": "off",
// "no-extra-boolean-cast": "off",
// "no-path-concat": "off",
// "no-unused-expressions": "off",
// "no-return-assign": "off",
// "no-restricted-modules": "off",
// "object-curly-spacing": "off",
// "indent": "off",
// "padded-blocks": "off",
// "eol-last": "off",
// "lines-around-directive": "off",
// "strict": "off",
// "comma-dangle": "off",
// "no-multi-spaces": "off",
// "quotes": "off",
// "keyword-spacing": "off",
// "no-mixed-operators": "off",
// "comma-spacing": "off",
// "no-trailing-spaces": "off",
// "key-spacing": "off",
// "no-multiple-empty-lines": "off",
// "spaced-comment": "off",
// "space-in-parens": "off",
// "block-spacing": "off",
// "quote-props": "off",
// "space-unary-ops": "off",
// "no-empty": "off",
// "dot-notation": "off",
// "func-call-spacing": "off",
// "array-bracket-spacing": "off",
// "object-property-newline": "off",
// "no-continue": "off",
// "no-extra-semi": "off",
// "no-spaced-func": "off",
// "no-useless-return": "off"
}
}

6
.gitignore vendored
View File

@ -216,3 +216,9 @@ pip-log.txt
sftp-config.json
node_modules/
####################
# JetBrains
####################
.idea

View File

@ -14,4 +14,6 @@ NodeBB Plugin that allows users to login/register via any configured OAuth provi
## Trouble?
The NodeBB team builds out SSO plugins for a nominal fee. [Reach out to us for a quote.](mailto:sales@nodebb.org)
Find us on [the community forums](http://community.nodebb.org)!

3
commitlint.config.js Normal file
View File

@ -0,0 +1,3 @@
'use strict';
module.exports = { extends: ['@commitlint/config-angular'] };

View File

@ -1,6 +1,6 @@
(function(module) {
"use strict";
'use strict';
(function (module) {
/*
Welcome to the SSO OAuth plugin! If you're inspecting this code, you're probably looking to
hook up NodeBB with your existing OAuth endpoint.
@ -16,18 +16,16 @@
Step 4: If all goes well, you'll be able to login/register via your OAuth endpoint credentials.
*/
var User = module.parent.require('./user'),
Groups = module.parent.require('./groups'),
meta = module.parent.require('./meta'),
db = module.parent.require('../src/database'),
passport = module.parent.require('passport'),
fs = module.parent.require('fs'),
path = module.parent.require('path'),
nconf = module.parent.require('nconf'),
winston = module.parent.require('winston'),
async = module.parent.require('async');
const User = require.main.require('./src/user');
const Groups = require.main.require('./src/groups');
const db = require.main.require('./src/database');
const authenticationController = require.main.require('./src/controllers/authentication');
var authenticationController = module.parent.require('./controllers/authentication');
const async = require('async');
const passport = module.parent.require('passport');
const nconf = module.parent.require('nconf');
const winston = module.parent.require('winston');
/**
* REMEMBER
@ -48,27 +46,30 @@
* `OAUTH__ID=someoauthid OAUTH__SECRET=youroauthsecret node app.js`
*/
var constants = Object.freeze({
type: 'oauth2', // Either 'oauth' or 'oauth2'
name: 'icynet', // Something unique to your OAuth provider in lowercase, like "github", or "nodebb"
scope: 'email privilege',
oauth: {
requestTokenURL: '',
accessTokenURL: '',
userAuthorizationURL: '',
consumerKey: nconf.get('oauth:key'), // don't change this line
consumerSecret: nconf.get('oauth:secret'), // don't change this line
},
oauth2: {
authorizationURL: nconf.get('oauth:provider') + '/oauth2/authorize',
tokenURL: nconf.get('oauth:provider') + '/oauth2/token',
clientID: nconf.get('oauth:id'),
clientSecret: nconf.get('oauth:secret'),
},
userRoute: nconf.get('oauth:provider') + '/oauth2/user'
}),
configOk = false,
OAuth = {}, passportOAuth, opts;
const constants = Object.freeze({
type: 'oauth2', // Either 'oauth' or 'oauth2'
name: 'icynet', // Something unique to your OAuth provider in lowercase, like "github", or "nodebb"
scope: 'email privilege',
oauth: {
requestTokenURL: '',
accessTokenURL: '',
userAuthorizationURL: '',
consumerKey: nconf.get('oauth:key'), // don't change this line
consumerSecret: nconf.get('oauth:secret'), // don't change this line
},
oauth2: {
authorizationURL: nconf.get('oauth:provider') + '/oauth2/authorize',
tokenURL: nconf.get('oauth:provider') + '/oauth2/token',
clientID: nconf.get('oauth:id'),
clientSecret: nconf.get('oauth:secret'),
},
userRoute: nconf.get('oauth:provider') + '/oauth2/user'
})
const OAuth = {};
let configOk = false;
let passportOAuth;
let opts;
if (!constants.name) {
winston.error('[sso-oauth] Please specify a name for your OAuth provider (library.js:32)');
@ -80,7 +81,7 @@
configOk = true;
}
OAuth.getStrategy = function(strategies, callback) {
OAuth.getStrategy = function (strategies, callback) {
if (configOk) {
passportOAuth = require('passport-oauth')[constants.type === 'oauth' ? 'OAuthStrategy' : 'OAuth2Strategy'];
@ -89,19 +90,21 @@
opts = constants.oauth;
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
passportOAuth.Strategy.prototype.userProfile = function(token, secret, params, done) {
this._oauth.get(constants.userRoute, token, secret, function(err, body, res) {
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
passportOAuth.Strategy.prototype.userProfile = function (token, secret, params, done) {
this._oauth.get(constants.userRoute, token, secret, function (err, body/* , res */) {
if (err) {
return done(err);
}
try {
var json = JSON.parse(body);
OAuth.parseUserReturn(json, function(err, profile) {
OAuth.parseUserReturn(json, function (err, profile) {
if (err) return done(err);
profile.provider = constants.name;
done(null, profile);
});
} catch(e) {
} catch (e) {
done(e);
}
});
@ -111,19 +114,21 @@
opts = constants.oauth2;
opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';
passportOAuth.Strategy.prototype.userProfile = function(accessToken, done) {
this._oauth2.get(constants.userRoute, accessToken, function(err, body, res) {
if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }
passportOAuth.Strategy.prototype.userProfile = function (accessToken, done) {
this._oauth2.get(constants.userRoute, accessToken, function (err, body/* , res */) {
if (err) {
return done(err);
}
try {
var json = JSON.parse(body);
OAuth.parseUserReturn(json, function(err, profile) {
OAuth.parseUserReturn(json, function (err, profile) {
if (err) return done(err);
profile.provider = constants.name;
done(null, profile);
});
} catch(e) {
} catch (e) {
done(e);
}
});
@ -132,7 +137,7 @@
opts.passReqToCallback = true;
passport.use(constants.name, new passportOAuth(opts, function(req, token, secret, profile, done) {
passport.use(constants.name, new passportOAuth(opts, function (req, token, secret, profile, done) {
OAuth.login({
oAuthid: profile.id,
handle: profile.displayName,
@ -154,7 +159,7 @@
url: '/auth/' + constants.name,
callbackURL: '/auth/' + constants.name + '/callback',
icon: 'fa-check-square',
scope: (constants.scope || '').split(',')
scope: (constants.scope || '').split(','),
});
callback(null, strategies);
@ -163,7 +168,7 @@
}
};
OAuth.parseUserReturn = function(data, callback) {
OAuth.parseUserReturn = function (data, callback) {
// Alter this section to include whatever data is necessary
// NodeBB *requires* the following: id, displayName, emails.
// Everything else is optional.
@ -185,42 +190,43 @@
//process.stdout.write('===\nAt this point, you\'ll need to customise the above section to id, displayName, and emails into the "profile" object.\n===');
//return callback(new Error('Congrats! So far so good -- please see server log for details'));
// eslint-disable-next-line
callback(null, profile);
}
};
OAuth.login = function(payload, callback) {
OAuth.getUidByOAuthid(payload.oAuthid, function(err, uid) {
if(err) {
OAuth.login = function (payload, callback) {
OAuth.getUidByOAuthid(payload.oAuthid, function (err, uid) {
if (err) {
return callback(err);
}
if (uid !== null) {
// Existing User
callback(null, {
uid: uid
uid: uid,
});
} else {
// New User
var success = function(uid) {
var success = function (uid) {
// Save provider-specific information to the user
User.setUserField(uid, constants.name + 'Id', payload.oAuthid);
db.setObjectField(constants.name + 'Id:uid', payload.oAuthid, uid);
if (payload.isAdmin) {
Groups.join('administrators', uid, function(err) {
callback(null, {
uid: uid
Groups.join('administrators', uid, function (err) {
callback(err, {
uid: uid,
});
});
} else {
callback(null, {
uid: uid
uid: uid,
});
}
};
User.getUidByEmail(payload.email, function(err, uid) {
if(err) {
User.getUidByEmail(payload.email, function (err, uid) {
if (err) {
return callback(err);
}
@ -244,8 +250,8 @@
});
};
OAuth.getUidByOAuthid = function(oAuthid, callback) {
db.getObjectField(constants.name + 'Id:uid', oAuthid, function(err, uid) {
OAuth.getUidByOAuthid = function (oAuthid, callback) {
db.getObjectField(constants.name + 'Id:uid', oAuthid, function (err, uid) {
if (err) {
return callback(err);
}
@ -253,13 +259,13 @@
});
};
OAuth.deleteUserData = function(data, callback) {
OAuth.deleteUserData = function (data, callback) {
async.waterfall([
async.apply(User.getUserField, data.uid, constants.name + 'Id'),
function(oAuthIdToDelete, next) {
function (oAuthIdToDelete, next) {
db.deleteObjectField(constants.name + 'Id:uid', oAuthIdToDelete, next);
}
], function(err) {
},
], function (err) {
if (err) {
winston.error('[sso-oauth] Could not remove OAuthId data for uid ' + data.uid + '. Error: ' + err);
return callback(err);
@ -269,5 +275,11 @@
});
};
// If this filter is not there, the deleteUserData function will fail when getting the oauthId for deletion.
OAuth.whitelistFields = function (params, callback) {
params.whitelist.push(constants.name + 'Id');
callback(null, params);
};
module.exports = OAuth;
}(module));

View File

@ -1,6 +1,6 @@
{
"name": "nodebb-plugin-sso-oauth",
"version": "0.3.3",
"version": "0.3.4",
"description": "NodeBB Generic OAuth SSO",
"main": "library.js",
"repository": {
@ -28,10 +28,32 @@
"readme": "",
"readmeFilename": "README.md",
"dependencies": {
"async": "^2",
"passport-oauth": "~1.0.0"
},
"nbbpm": {
"compatibility": "^1.0.1",
"index": false
},
"devDependencies": {
"@commitlint/cli": "^8.0.0",
"@commitlint/config-angular": "^7.1.2",
"eslint": "^5.16.0",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.8.0",
"husky": "^2.4.0",
"lint-staged": "^8.2.0"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
}
}

View File

@ -6,6 +6,7 @@
"library": "./library.js",
"hooks": [
{ "hook": "static:user.delete", "method": "deleteUserData" },
{ "hook": "filter:user.whitelistFields", "method": "whitelistFields" },
{ "hook": "filter:auth.init", "method": "getStrategy" }
]
}

3070
yarn.lock Normal file

File diff suppressed because it is too large Load Diff