Authentication refactor'
This commit is contained in:
Родитель
82b6dd84e1
Коммит
7478b17678
|
@ -62,6 +62,6 @@ module.exports = function (err, req, res, next) {
|
|||
error: {},
|
||||
title: err.status === 404 ? 'Not Found' : 'Oops',
|
||||
user: req.user,
|
||||
config: config,
|
||||
config: config.obfuscatedConfig,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -38,6 +38,7 @@ module.exports = function configurePassport(app, passport, initialConfig) {
|
|||
app.get('/signin/github/join', (req, res) => {
|
||||
res.render('creategithubaccount', {
|
||||
title: 'Create a GitHub account',
|
||||
user: req.user,
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -80,6 +81,9 @@ module.exports = function configurePassport(app, passport, initialConfig) {
|
|||
delete req.user.github;
|
||||
}
|
||||
var url = req.headers.referer || '/';
|
||||
if (req.query.redirect === 'github') {
|
||||
url = 'https://github.com/logout';
|
||||
}
|
||||
res.redirect(url);
|
||||
});
|
||||
|
||||
|
|
195
oss/index.js
195
oss/index.js
|
@ -13,8 +13,27 @@ const Team = require('./team');
|
|||
const User = require('./user');
|
||||
const RedisHelper = require('./redis');
|
||||
|
||||
function OpenSourceUserContext(applicationConfiguration, dataClient, user, redisInstance, callback) {
|
||||
function OpenSourceUserContext(options, callback) {
|
||||
var self = this;
|
||||
self.displayNames = {
|
||||
github: null,
|
||||
};
|
||||
self.usernames = {
|
||||
github: null,
|
||||
azure: null,
|
||||
};
|
||||
self.id = {
|
||||
github: null,
|
||||
};
|
||||
self.entities = {
|
||||
link: null,
|
||||
primaryMembership: null,
|
||||
};
|
||||
var applicationConfiguration = options.config;
|
||||
var dataClient = options.dataClient;
|
||||
var redisInstance = options.redisClient;
|
||||
var requestUser = options.request ? options.request.user : null;
|
||||
var link = options.link;
|
||||
var modernUser;
|
||||
this.cache = {
|
||||
orgs: {},
|
||||
|
@ -26,6 +45,7 @@ function OpenSourceUserContext(applicationConfiguration, dataClient, user, redis
|
|||
this.createModernUser = function (id, login) {
|
||||
modernUser = new User(this, id);
|
||||
modernUser.login = login;
|
||||
return modernUser;
|
||||
};
|
||||
this.setting = function (name) {
|
||||
return applicationConfiguration[name];
|
||||
|
@ -36,89 +56,117 @@ function OpenSourceUserContext(applicationConfiguration, dataClient, user, redis
|
|||
this.redisClient = function () {
|
||||
return redisInstance;
|
||||
};
|
||||
this.requestUser = function () {
|
||||
return user;
|
||||
};
|
||||
this.safeConfigurationTemp = safeSettings(applicationConfiguration);
|
||||
this.authenticated = {
|
||||
github: user && user.github && user.github.id,
|
||||
azure: user && user.azure && user.azure.username,
|
||||
};
|
||||
this.entities = {
|
||||
link: null,
|
||||
primaryMembership: null,
|
||||
};
|
||||
this.usernames = {
|
||||
github: user && user.github && user.github.username ? user.github.username : undefined,
|
||||
azure: user && user.azure && user.azure.username ? user.azure.username : undefined,
|
||||
};
|
||||
this.id = {
|
||||
github: user && user.github && user.github.id ? user.github.id.toString() : undefined,
|
||||
};
|
||||
if (this.id.github) {
|
||||
this.createModernUser(this.id.github, this.usernames.github);
|
||||
}
|
||||
this.safeConfiguration = safeSettings(applicationConfiguration);
|
||||
this.baseUrl = '/';
|
||||
this.redis = new RedisHelper(this, applicationConfiguration.redis.prefix);
|
||||
this.initializeBasics(function (initError) {
|
||||
if (callback) {
|
||||
return callback(initError, self);
|
||||
}
|
||||
});
|
||||
if (link && options.request) {
|
||||
return callback(new Error('The context cannot be set from both a request and a link instance.'));
|
||||
}
|
||||
if (link) {
|
||||
return setPropertiesFromLink(self, link, callback);
|
||||
}
|
||||
if (options.request) {
|
||||
return this.resolveLinkFromRequest(options.request, callback);
|
||||
}
|
||||
callback(new Error('Could not initialize the context for the acting user.'), self);
|
||||
}
|
||||
|
||||
function setPropertiesFromLink(context, link, callback) {
|
||||
context.usernames.github = link.ghu;
|
||||
context.id.github = link.ghid.toString();
|
||||
context.usernames.azure = link.aadupn;
|
||||
context.entities.link = link;
|
||||
var modernUser = context.modernUser();
|
||||
if (!modernUser && context.id.github) {
|
||||
modernUser = context.createModernUser(context.id.github, context.usernames.github);
|
||||
}
|
||||
modernUser.link = link;
|
||||
callback(null, context);
|
||||
}
|
||||
|
||||
function tooManyLinksError(self, userLinks, callback) {
|
||||
var tooManyLinksError = new Error(`This account has ${userLinks.length} linked GitHub accounts.`);
|
||||
tooManyLinksError.links = userLinks;
|
||||
tooManyLinksError.tooManyLinks = true;
|
||||
return callback(tooManyLinksError, self);
|
||||
}
|
||||
|
||||
function existingGitHubIdentityError(self, link, requestUser, callback) {
|
||||
var endUser = requestUser.azure.displayName || requestUser.azure.username;
|
||||
var obfuscatedUsername = utils.obfuscate(link.ghu, 4);
|
||||
var anotherGitHubAccountError = new Error(`${endUser}, there is a different GitHub account linked to your corporate identity.`);
|
||||
anotherGitHubAccountError.anotherAccount = true;
|
||||
anotherGitHubAccountError.detailed = `If you need to switch which account is associated with your identity, please unlink the old account first. Your other GitHub account username ends in: ${obfuscatedUsername}.`;
|
||||
anotherGitHubAccountError.fancyLink = {
|
||||
link: '/signout/github/?redirect=github',
|
||||
title: `Sign Out ${requestUser.github.username} on GitHub`,
|
||||
};
|
||||
return callback(anotherGitHubAccountError, self);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Populate the user's OSS context object.
|
||||
// ----------------------------------------------------------------------------
|
||||
OpenSourceUserContext.prototype.initializeBasics = function (callback) {
|
||||
OpenSourceUserContext.prototype.resolveLinkFromRequest = function (request, callback) {
|
||||
var self = this;
|
||||
var requestUser = this.requestUser();
|
||||
if (!userObject && this.setting('primaryAuthenticationScheme') === 'aad' && requestUser.azure && requestUser.azure.username) {
|
||||
return this.dataClient().getUserByAadUpn(requestUser.azure.username, function (findError, userLinks) {
|
||||
var requestUser = request.user;
|
||||
if (requestUser && requestUser.github) {
|
||||
self.usernames.github = requestUser.github.username;
|
||||
self.id.github = requestUser.github.id;
|
||||
self.displayNames.github = requestUser.github.displayName;
|
||||
}
|
||||
if (requestUser && requestUser.azure) {
|
||||
self.usernames.azure = requestUser.azure.username;
|
||||
}
|
||||
if (self.setting('primaryAuthenticationScheme') === 'aad' && requestUser.azure && requestUser.azure.username) {
|
||||
return self.dataClient().getUserByAadUpn(requestUser.azure.username, function (findError, userLinks) {
|
||||
if (findError) {
|
||||
// XXX: wrap with a useful message?
|
||||
return callback(findError);
|
||||
return callback(utils.wrapError(findError, 'There was a problem trying to load the link for the active user.'), self);
|
||||
}
|
||||
if (userLinks.length === 0) {
|
||||
return callback();
|
||||
return callback(null, self);
|
||||
}
|
||||
if (userLinks.length > 1) {
|
||||
var tooManyLinksError = new Error(`This account has ${userLinks.length} linked GitHub accounts.`);
|
||||
tooManyLinksError.links = userLinks;
|
||||
tooManyLinksError.tooManyLinks = true;
|
||||
return callback(tooManyLinksError);
|
||||
return tooManyLinksError(self, userLinks, callback);
|
||||
}
|
||||
var link = userLinks[0];
|
||||
self.usernames.github = link.ghu;
|
||||
self.id.github = link.ghid.toString();
|
||||
self.createModernUser(self.id.github, self.usernames.github);
|
||||
self.entities.link = link;
|
||||
self.modernUser().link = link;
|
||||
// todo: if their AAD name or upn has changed, but oid is still the same... schedule an update!
|
||||
// question: should this.authenticated.github be true or false, since it isn't authenticated yet?
|
||||
callback(null, false);
|
||||
if (requestUser.github && requestUser.github.username && link.ghu !== requestUser.github.username) {
|
||||
if (link.ghid === requestUser.github.id) {
|
||||
// TODO: The user has changed their GitHub name, simply update the link record.
|
||||
} else {
|
||||
return existingGitHubIdentityError(self, link, requestUser, callback);
|
||||
}
|
||||
}
|
||||
if (requestUser.azure.displayName !== link.aadname) {
|
||||
// TODO: update their display name?
|
||||
console.warn(`The user's Azure display name has changed. Link: ${link.aadname}, Passport: ${requestUser.azure.displayName}`);
|
||||
}
|
||||
if (requestUser.azure.username !== link.aadupn) {
|
||||
// Confirm that their OID is the same
|
||||
// RARE: TODO: ??? update their AAD upn in the link
|
||||
// if OID has changed, freak out?
|
||||
console.warn(`The user's Azure username has changed. Link: ${link.aadupn}, Passport: ${requestUser.azure.username}`);
|
||||
}
|
||||
return setPropertiesFromLink(self, link, callback);
|
||||
});
|
||||
}
|
||||
var userObject = this.modernUser();
|
||||
var userObject;
|
||||
if (self.id.github) {
|
||||
userObject = self.createModernUser(self.id.github, self.usernames.github);
|
||||
}
|
||||
if (!userObject) {
|
||||
return callback(new Error('There\'s a logic bug in the user context object. We cannot continue.'));
|
||||
return callback(new Error('There\'s a logic bug in the user context object. We cannot continue.'), self);
|
||||
}
|
||||
userObject.getLink(function (error, link) {
|
||||
if (error) {
|
||||
return callback(utils.wrapError(error, 'We were not able to retrieve information about any link for your user account at this time.'));
|
||||
return callback(utils.wrapError(error, 'We were not able to retrieve information about any link for your user account at this time.'), self);
|
||||
}
|
||||
if (link) {
|
||||
self.entities.link = link;
|
||||
// CONSIDER: If the link values differ from the request properties...
|
||||
return setPropertiesFromLink(self, link, callback);
|
||||
} else {
|
||||
callback(null, self);
|
||||
}
|
||||
callback(null, false);
|
||||
/*self.org().queryUserMembership(true, function (error, result) {
|
||||
// CONSIDER: This is part of the isAdministrator updates...
|
||||
if (result && result.state && result.role && result.role === 'admin') {
|
||||
self.entities.primaryMembership = result;
|
||||
}
|
||||
callback(null, false);
|
||||
});
|
||||
*/
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -559,8 +607,7 @@ OpenSourceUserContext.prototype.saveUserAlert = function (req, message, title, c
|
|||
};
|
||||
|
||||
function safeSettings(config) {
|
||||
// CONSIDER: IMPLEMENT.
|
||||
return config;
|
||||
return config.obfuscatedConfig;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -578,11 +625,31 @@ OpenSourceUserContext.prototype.render = function (req, res, view, title, option
|
|||
if (breadcrumbs && breadcrumbs.length && breadcrumbs.length > 0) {
|
||||
breadcrumbs[breadcrumbs.length - 1].isLast = true;
|
||||
}
|
||||
var authScheme = this.setting('primaryAuthenticationScheme');
|
||||
var user = {
|
||||
primaryAuthenticationScheme: authScheme,
|
||||
primaryUsername: authScheme === 'github' ? this.usernames.github : this.usernames.azure,
|
||||
githubSignout: authScheme === 'github' ? '/signout' : '/signout/github',
|
||||
azureSignout: authScheme === 'github' ? '/signout/azure' : '/signout',
|
||||
};
|
||||
if (this.id.github || this.usernames.github) {
|
||||
user.github = {
|
||||
id: this.id.github,
|
||||
username: this.usernames.github,
|
||||
displayName: this.displayNames.github,
|
||||
increasedScope: null, // TODO: Increased scope should be set in the pipeline
|
||||
};
|
||||
}
|
||||
if (this.usernames.azure) {
|
||||
user.azure = {
|
||||
username: this.usernames.azure,
|
||||
};
|
||||
}
|
||||
var obj = {
|
||||
title: title,
|
||||
config: this.safeConfigurationTemp,
|
||||
config: this.safeConfiguration,
|
||||
serviceBanner: this.setting('serviceBanner'),
|
||||
user: this.requestUser(),
|
||||
user: user,
|
||||
ossLink: this.entities.link,
|
||||
showBreadcrumbs: true,
|
||||
breadcrumbs: breadcrumbs,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
const async = require('async');
|
||||
const utils = require('../utils');
|
||||
const debug = require('debug')('azureossportal');
|
||||
|
||||
|
@ -165,12 +166,12 @@ OpenSourceUser.prototype.unlinkAndDrop = function (callback) {
|
|||
if (getOrganizationsError) {
|
||||
return callback(getOrganizationsError);
|
||||
}
|
||||
async.each(currentOrganizationMemberships, function (org, callback) {
|
||||
async.each(currentOrganizationMemberships, function (org, cb) {
|
||||
org.removeUserMembership(function () {
|
||||
// TODO: We now continue with deletes when one fails. Common
|
||||
// failure case is when they have a pending invite, it will live
|
||||
// on... which is not ideal.
|
||||
callback();
|
||||
cb();
|
||||
});
|
||||
}, function (/* ignored error per above statement */) {
|
||||
var dc = self.oss.dataClient();
|
||||
|
|
|
@ -210,6 +210,22 @@ footer {
|
|||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.pad, vertical-pad, .vertical-pad-top {
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.pad, vertical-pad, .vertical-pad-bottom {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.pad, .horizontal-pad, .horizontal-pad-left {
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.pad, .horizontal-pad, .horizontal-pad-right {
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
code {
|
||||
color: #333;
|
||||
}
|
||||
|
|
|
@ -14,17 +14,17 @@ const linkCleanupRoute = require('./link-cleanup');
|
|||
router.use(function (req, res, next) {
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
if (req.isAuthenticated()) {
|
||||
if (req.user && !req.user.github) {
|
||||
// no github info
|
||||
// IF secondary auth,... 1) check for a link
|
||||
// return next(new Error('We do not have your GitHub stuff.'));
|
||||
var expectedAuthenticationProperty = config.primaryAuthenticationScheme === 'github' ? 'github' : 'azure';
|
||||
if (req.user && !req.user[expectedAuthenticationProperty]) {
|
||||
console.warn(`A user session was authenticated but did not have present the property ${expectedAuthenticationProperty} expected for this type of authentication. Signing them out.`);
|
||||
return res.redirect('/signout');
|
||||
}
|
||||
if (req.user && req.user.github && !req.user.github.id) {
|
||||
return next(new Error('Invalid GitHub user information provided by GitHub.'));
|
||||
var expectedAuthenticationKey = config.primaryAuthenticationScheme === 'github' ? 'id' : 'username';
|
||||
if (!req.user[expectedAuthenticationProperty][expectedAuthenticationKey]) {
|
||||
return next(new Error('Invalid information present for the authentication provider.'));
|
||||
}
|
||||
return next();
|
||||
}
|
||||
|
||||
var url = req.originalUrl;
|
||||
if (url) {
|
||||
if (req.session) {
|
||||
|
@ -36,9 +36,13 @@ router.use(function (req, res, next) {
|
|||
});
|
||||
|
||||
router.use((req, res, next) => {
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
var dc = req.app.settings.dataclient;
|
||||
new OpenSourceUserContext(config, dc, req.user, dc.cleanupInTheFuture.redisClient, function (error, instance) {
|
||||
var options = {
|
||||
config: req.app.settings.runtimeConfig,
|
||||
dataClient: req.app.settings.dataclient,
|
||||
redisClient: req.app.settings.dataclient.cleanupInTheFuture.redisClient,
|
||||
request: req,
|
||||
};
|
||||
new OpenSourceUserContext(options, (error, instance) => {
|
||||
req.oss = instance;
|
||||
if (error && error.tooManyLinks === true) {
|
||||
if (req.url === '/link-cleanup') {
|
||||
|
@ -160,7 +164,7 @@ router.get('/', function (req, res, next) {
|
|||
onboarding = true;
|
||||
}
|
||||
var render = function (results) {
|
||||
var pageTitle = results && results.userOrgMembership === false ? 'My GitHub Account' : config.companyName + ' - Open Source Portal for GitHub';
|
||||
var pageTitle = results && results.userOrgMembership === false ? 'My GitHub Account' : config.companyName + ' - ' + config.portalName;
|
||||
oss.render(req, res, 'index', pageTitle, {
|
||||
accountInfo: results,
|
||||
onboarding: onboarding,
|
||||
|
|
|
@ -10,6 +10,7 @@ const router = express.Router();
|
|||
const async = require('async');
|
||||
const moment = require('moment');
|
||||
const utils = require('../utils');
|
||||
const OpenSourceUserContext = require('../oss');
|
||||
|
||||
// Enforcing just a single GitHub account per Active Directory user. With
|
||||
// mild refactoring, this portal could easily support a session selecting
|
||||
|
@ -37,19 +38,20 @@ router.use((req, res, next) => {
|
|||
});
|
||||
});
|
||||
|
||||
function renderCleanupPage(req, res, optionalUsernameToConfirm) {
|
||||
function renderCleanupPage(req, res, idToConfirm, links) {
|
||||
links = links || req.linksForCleanup;
|
||||
let twoColumns = [[], []];
|
||||
for (let i = 0; i < req.linksForCleanup.length; i++) {
|
||||
if (req.linksForCleanup[i].joined) {
|
||||
req.linksForCleanup[i].joinedDate = new Date(Math.round(req.linksForCleanup[i].joined));
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
if (links[i].joined) {
|
||||
links[i].joinedDate = new Date(Math.round(links[i].joined));
|
||||
}
|
||||
twoColumns[i % 2].push(req.linksForCleanup[i]);
|
||||
twoColumns[i % 2].push(links[i]);
|
||||
}
|
||||
req.oss.render(req, res, 'multiplegithubaccounts', 'GitHub Cleanup', {
|
||||
linksForCleanupByColumn: twoColumns,
|
||||
numberToRemove: req.linksForCleanup.length - 1,
|
||||
confirming: optionalUsernameToConfirm,
|
||||
})
|
||||
confirming: idToConfirm,
|
||||
});
|
||||
}
|
||||
|
||||
router.get('/', (req, res, next) => {
|
||||
|
@ -57,20 +59,45 @@ router.get('/', (req, res, next) => {
|
|||
});
|
||||
|
||||
router.post('/', (req, res, next) => {
|
||||
let username = req.body.unlink;
|
||||
let isConfirming = req.body.confirm === username;
|
||||
if (!isConfirming) {
|
||||
return renderCleanupPage(req, res, username);
|
||||
let id = req.body.unlink;
|
||||
let link = null;
|
||||
let remainingLinks = [];
|
||||
for (let i = 0; i < req.linksForCleanup.length; i++) {
|
||||
if (req.linksForCleanup[i].ghid === id) {
|
||||
link = req.linksForCleanup[i];
|
||||
} else {
|
||||
remainingLinks.push(req.linksForCleanup[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!link) {
|
||||
return next(new Error(`Could not identify the link for GitHub user ${id}.`));
|
||||
}
|
||||
let isConfirming = req.body.confirm === id;
|
||||
if (!isConfirming) {
|
||||
return renderCleanupPage(req, res, id);
|
||||
}
|
||||
var options = {
|
||||
config: req.app.settings.runtimeConfig,
|
||||
dataClient: req.app.settings.dataclient,
|
||||
redisClient: req.app.settings.dataclient.cleanupInTheFuture.redisClient,
|
||||
link: link,
|
||||
};
|
||||
new OpenSourceUserContext(options, function (contextError, unlinkContext) {
|
||||
if (contextError) {
|
||||
return next(contextError);
|
||||
}
|
||||
unlinkContext.modernUser().unlinkAndDrop((unlinkError) => {
|
||||
if (unlinkError) {
|
||||
return next(unlinkError);
|
||||
}
|
||||
if (remainingLinks.length > 1) {
|
||||
renderCleanupPage(req, res, null, remainingLinks);
|
||||
} else {
|
||||
req.oss.saveUserAlert(req, link.ghu + ' has been unlinked. You now have just one GitHub account link.', 'Link cleanup complete', 'success');
|
||||
res.redirect('/');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/* var link = userLinks[0];
|
||||
self.usernames.github = link.ghu;
|
||||
self.id.github = link.ghid.toString();
|
||||
self.createModernUser(self.id.github, self.usernames.github);
|
||||
self.entities.link = link;
|
||||
self.modernUser().link = link;
|
||||
*/
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
@ -45,7 +45,11 @@ router.post('/', function (req, res, next) {
|
|||
});
|
||||
|
||||
router.get('/update', function (req, res, next) {
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
var oss = req.oss;
|
||||
if (config.primaryAuthenticationScheme === 'aad'){
|
||||
return next('Changing a GitHub account is not yet supported.');
|
||||
}
|
||||
if (!(oss.usernames.azure)) {
|
||||
return oss.render(req, res, 'linkUpdate', 'Update your account ' + oss.usernames.github + ' by signing in with corporate credentials.');
|
||||
}
|
||||
|
|
|
@ -28,14 +28,13 @@ function getPackageInfo() {
|
|||
}
|
||||
|
||||
router.get('/', function (req, res) {
|
||||
var config = req.app.settings.runtimeConfig;
|
||||
var config = req.app.settings.runtimeConfig.obfuscatedConfig;
|
||||
var components = getPackageInfo();
|
||||
res.render('thanks', {
|
||||
user: req.user,
|
||||
config: config,
|
||||
components: components,
|
||||
serviceBanner: config && config.serviceBanner ? config.serviceBanner : undefined,
|
||||
title: 'Open Source Portal for GitHub - ' + config.companyName
|
||||
title: 'Open Source Components',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
20
utils.js
20
utils.js
|
@ -160,6 +160,26 @@ exports.arrayToHashById = function athi(inputArray) {
|
|||
return hash;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Obfuscate a string value, optionally leaving a few characters visible.
|
||||
// ----------------------------------------------------------------------------
|
||||
exports.obfuscate = function obfuscate(value, lastCharactersShowCount) {
|
||||
if (value === undefined || value === null || value.length === undefined) {
|
||||
return value;
|
||||
}
|
||||
var length = value.length;
|
||||
lastCharactersShowCount = lastCharactersShowCount || 0;
|
||||
lastCharactersShowCount = Math.min(lastCharactersShowCount, length - 1);
|
||||
var obfuscated = '';
|
||||
for (var i = 0; i < length - lastCharactersShowCount; i++) {
|
||||
obfuscated += '*';
|
||||
}
|
||||
for (var j = length - lastCharactersShowCount; j < length; j++) {
|
||||
obfuscated += value[j];
|
||||
}
|
||||
return obfuscated;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// A very basic breadcrumb stack that ties in to an Express request object.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -7,12 +7,12 @@ doctype html
|
|||
html(lang="en")
|
||||
head
|
||||
meta(charset='utf-8')
|
||||
title= (user && user.github && user.github.username) ? title + ' - ' + user.github.username : title
|
||||
title= (user && user.primaryUsername) ? title + ' - ' + user.primaryUsername : title
|
||||
meta(http-equiv='X-UA-Compatible', content='IE=edge')
|
||||
meta(name='viewport', content='width=device-width, initial-scale=1.0')
|
||||
meta(name='author', content='Microsoft Open Source')
|
||||
link(href='/css/bootstrap.min.css?1', rel='stylesheet')
|
||||
link(href='/repos-css/oss.css?2a', rel='stylesheet')
|
||||
link(href='/repos-css/oss.css?2b', rel='stylesheet')
|
||||
link(rel='shortcut icon', href='/favicon.ico')
|
||||
link(rel='apple-touch-icon', sizes='114x114,72x72,144x144,60x60,120x120,76x76,152x152,180x180', href='/favicon-144.png')
|
||||
meta(name='msapplication-config', content='none')
|
||||
|
@ -73,6 +73,8 @@ html(lang="en")
|
|||
nav(role='navigation')
|
||||
div.container(style='margin-top:24px;margin-bottom:12px')
|
||||
div.row(style=(user && !error && ossLink) ? 'margin-left:0' : 'margin-left:-30px')
|
||||
- var githubSignout = user && user.githubSignout ? user.githubSignout : '/signout'
|
||||
- var azureSignout = user && user.azureSignout ? user.azureSignout : '/signout'
|
||||
div.col-md-6
|
||||
if user && user.github
|
||||
h4 Your GitHub Account
|
||||
|
@ -84,10 +86,16 @@ html(lang="en")
|
|||
img(alt=user.github.displayName, src=user.github.avatarUrl + '&s=80', style='margin-right:10px;width:30px;height:30px', data-user=user.github.id)
|
||||
a.btn.btn-sm.btn-muted(href='https://github.com/settings/profile', target='_new', title='Click to edit your public GitHub profile')= user.github.username
|
||||
a.btn.btn-sm.btn-muted-more(href='https://github.com/settings/profile', target='_new', title='Click to edit your public GitHub profile')= user.github.displayName || user.github.username
|
||||
a.btn.btn-sm.btn-white(href='/signout', style='margin-left:10px') Sign Out
|
||||
if primaryAuthenticationScheme == 'github'
|
||||
a.btn.btn-sm.btn-white(href=githubSignout, style='margin-left:10px') Sign Out
|
||||
else
|
||||
a.btn.btn-sm.btn-white(href='/link/update', style='margin-left:10px') Change
|
||||
else
|
||||
p
|
||||
small Sign in or create your GitHub.com account to manage your #{config && config.companyName || 'corporate'} open source identity.
|
||||
if primaryAuthenticationScheme == 'github'
|
||||
small Sign in or create your GitHub.com account to manage your #{config && config.companyName || 'corporate'} open source identity
|
||||
else
|
||||
small Sign in to GitHub
|
||||
p
|
||||
a.btn.btn-sm.btn-primary(href='/signin/github') Sign in
|
||||
div.col-md-6
|
||||
|
@ -98,16 +106,19 @@ html(lang="en")
|
|||
if ossLink.aadname
|
||||
a.btn.btn-sm.btn-muted(href='/signin/azure')= ossLink.aadname
|
||||
a.btn.btn-sm.btn-muted-more(href='/signin/azure')= ossLink.aadupn
|
||||
a.btn.btn-sm.btn-white(href='/link/update', style='margin-left:10px') Change
|
||||
if primaryAuthenticationScheme == 'github'
|
||||
a.btn.btn-sm.btn-white(href='/link/update', style='margin-left:10px') Change
|
||||
else
|
||||
a.btn.btn-sm.btn-white(href=azureSignout, style='margin-left:10px') Sign Out
|
||||
else if user.azure
|
||||
//- NOTE: This is actually visually backward from the above link display...
|
||||
h4 Your #{config && config.companyName ? config.companyName : 'Corporate'} Identity
|
||||
p
|
||||
if user.azure.username
|
||||
a.btn.btn-sm.btn-muted(href='/signout/azure')= user.azure.username
|
||||
a.btn.btn-sm.btn-muted(href=azureSignout)= user.azure.username
|
||||
if user.azure.displayName
|
||||
a.btn.btn-sm.btn-muted-more(href='/signout/azure')= user.azure.displayName
|
||||
a.btn.btn-sm.btn-white(href='/signout/azure', style='margin-left:10px') Sign Out
|
||||
a.btn.btn-sm.btn-white(href=azureSignout, style='margin-left:10px') Sign Out
|
||||
//- Just show breadcrumbs when there is an interesting path available
|
||||
if showBreadcrumbs === true && breadcrumbs && breadcrumbs.length && breadcrumbs.length > 1
|
||||
div.container
|
||||
|
@ -151,6 +162,8 @@ html(lang="en")
|
|||
h4
|
||||
| Storage:
|
||||
span.bg-danger(style='color:white;padding:2px')= config.azureStorage.account
|
||||
h4
|
||||
| Storage Prefix: #{config.azureStorage.prefix}
|
||||
if config && config.redis
|
||||
h4
|
||||
| Redis:
|
||||
|
|
|
@ -27,7 +27,7 @@ block content
|
|||
tr
|
||||
- gitAlertClass = config.primaryAuthenticationScheme == 'github' ? '' : 'alert-success'
|
||||
- aadAlertClass = config.primaryAuthenticationScheme == 'aad' ? '' : 'alert-success'
|
||||
td(class=gitAlertClass)= user.github.displayUsernameTemporary || user.github.username
|
||||
td(class=gitAlertClass)= user.github.username
|
||||
td
|
||||
div.text-center
|
||||
i.glyphicon.glyphicon-link
|
||||
|
|
|
@ -17,7 +17,7 @@ block content
|
|||
each column in linksForCleanupByColumn
|
||||
div.col-sm-6.col-md-6.col-lg-6
|
||||
each link in column
|
||||
div(style='border:4px solid #ddd;padding:0 24px 0 16px')
|
||||
div.horizontal-pad.vertical-space(style='border:4px solid #ddd')
|
||||
div
|
||||
h2= link.ghu
|
||||
p GitHub Account
|
||||
|
@ -25,11 +25,11 @@ block content
|
|||
| View #{link.ghu} GitHub Profile
|
||||
i.glyphicon.glyphicon-share-alt
|
||||
form(method='post').vertical-space
|
||||
input(type='hidden', name='unlink', value=link.ghu)
|
||||
- var isConfirming = confirming === link.ghu
|
||||
input(type='hidden', name='unlink', value=link.ghid)
|
||||
- var isConfirming = confirming === link.ghid
|
||||
- var buttonClass = isConfirming ? 'btn-danger' : 'btn-default'
|
||||
if isConfirming
|
||||
input(type='hidden', name='confirm', value=link.ghu)
|
||||
input(type='hidden', name='confirm', value=link.ghid)
|
||||
p.text-danger Please confirm that you are ready to unlink this GitHub account. It will lose access to any and all corporate organizations, teams and private repos.
|
||||
input.btn.btn-lg(class=buttonClass, type='submit', value=isConfirming ? 'Yes, unlink #{link.ghu}' : 'Unlink #{link.ghu}')
|
||||
if link.joinedDate
|
||||
|
|
|
@ -32,10 +32,8 @@ block content
|
|||
li Private forks of repos from these orgs, if any, will be removed by GitHub
|
||||
li Work committed in a private fork of a #{config.companyName} org will be lost
|
||||
|
||||
p If you have any questions about this, please contact your team's GitHub liasons or your corporate legal contact.
|
||||
|
||||
form(method='post', action='/unlink')
|
||||
p
|
||||
input.btn.btn-lg.btn-primary(type='submit', value='Remove my corporate link')
|
||||
input.btn.btn-lg.btn-danger(type='submit', value='Remove my corporate link')
|
||||
|
|
||||
a.btn.btn-lg.btn-default(href='/') Cancel
|
||||
|
|
Загрузка…
Ссылка в новой задаче