<commit_before>//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

const async = require('async');
const debug = require('debug')('azureossportal');
const utils = require('../utils');
const github = require('octonode');

const Org = require('./org');
const Team = require('./team');
const User = require('./user');
const RedisHelper = require('./redis');

/*eslint no-console: ["error", { allow: ["warn"] }] */

function OpenSourceUserContext(options, callback) {
  var self = this;
  self.displayNames = {
    github: null,
    azure: null,
  };
  self.usernames = {
    github: null,
    azure: null,
  };
  self.avatars = {
    github: null,
  };
  self.id = {
    github: null,
  };
  self.entities = {
    link: null,
    primaryMembership: null,
  };
  var applicationConfiguration = options.config;
  var dataClient = options.dataClient;
  var redisInstance = options.redisClient;
  var link = options.link;
  var modernUser;
  this.cache = {
    orgs: {},
    users: {},
  };
  this.modernUser = function () {
    return modernUser;
  };
  this.createModernUser = function (id, login) {
    modernUser = new User(this, id);
    modernUser.login = login;
    return modernUser;
  };
  this.setting = function (name) {
    return applicationConfiguration[name];
  };
  this.dataClient = function () {
    return dataClient;
  };
  this.redisClient = function () {
    return redisInstance;
  };
  this.safeConfiguration = safeSettings(applicationConfiguration);
  this.baseUrl = '/';
  this.redis = new RedisHelper(this, applicationConfiguration.redis.prefix);
  if (link && options.request) {
    return callback(new Error('The context cannot be set from both a request and a link instance.'));
  }
  if (link) {
    return self.setPropertiesFromLink(link, callback);
  }
  if (options.request) {
    return this.resolveLinkFromRequest(options.request, callback);
  }
  callback(new Error('Could not initialize the context for the acting user.'), self);
}

OpenSourceUserContext.prototype.setPropertiesFromLink = function (link, callback) {
  this.usernames.github = link.ghu;
  this.id.github = link.ghid.toString();
  this.usernames.azure = link.aadupn;
  this.entities.link = link;
  this.displayNames.azure = link.aadname;
  this.avatars.github = link.ghavatar;
  var modernUser = this.modernUser();
  if (!modernUser && this.id.github) {
    modernUser = this.createModernUser(this.id.github, this.usernames.github);
  }
  modernUser.link = link;
  callback(null, this);
};

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.resolveLinkFromRequest = function (request, callback) {
  var self = this;
  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;
    self.avatars.github = requestUser.github.avatarUrl;
  }
  if (requestUser && requestUser.azure) {
    self.usernames.azure = requestUser.azure.username;
    self.displayNames.azure = requestUser.azure.displayName;
  }
  if (self.setting('primaryAuthenticationScheme') === 'aad' && requestUser.azure && requestUser.azure.oid) {
    return self.dataClient().getUserByAadOid(requestUser.azure.oid, function (findError, userLinks) {
      if (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(null, self);
      }
      if (userLinks.length > 1) {
        return tooManyLinksError(self, userLinks, callback);
      }
      var link = userLinks[0];
      if (requestUser.github && requestUser.github.username && link.ghu !== requestUser.github.username) {
        if (link.ghid !== requestUser.github.id) {
          return existingGitHubIdentityError(self, link, requestUser, callback);
        }
      }
      return self.setPropertiesFromLink(link, callback);
    });
  }
  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.'), 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.'), self);
    }
    if (link) {
      // CONSIDER: If the link values differ from the request properties...
      return self.setPropertiesFromLink(link, callback);
    } else {
      callback(null, self);
    }
  });
};

// ----------------------------------------------------------------------------
// SECURITY METHOD:
// Determine whether the authenticated user is an Administrator of the org. At
// this time there is a special "portal sudoers" team that is used. The GitHub
// admin flag is not used [any longer] for performance reasons to reduce REST
// calls to GitHub.
// ----------------------------------------------------------------------------
OpenSourceUserContext.prototype.isPortalAdministrator = function (callback) {
  /*
  var self = this;
  if (self.entities && self.entities.primaryMembership) {
      var pm = self.entities.primaryMembership;
      if (pm.role && pm.role === 'admin') {
          return callback(null, true);
      }
  }
  */
  this.org().getPortalSudoersTeam().isMember(function (error, isMember) {
    if (error) {<commit_msg>Removing unused comment<commit_after>//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//

const async = require('async');
const debug = require('debug')('azureossportal');
const utils = require('../utils');
const github = require('octonode');

const Org = require('./org');
const Team = require('./team');
const User = require('./user');
const RedisHelper = require('./redis');

/*eslint no-console: ["error", { allow: ["warn"] }] */

function OpenSourceUserContext(options, callback) {
  var self = this;
  self.displayNames = {
    github: null,
    azure: null,
  };
  self.usernames = {
    github: null,
    azure: null,
  };
  self.avatars = {
    github: null,
  };
  self.id = {
    github: null,
  };
  self.entities = {
    link: null,
    primaryMembership: null,
  };
  var applicationConfiguration = options.config;
  var dataClient = options.dataClient;
  var redisInstance = options.redisClient;
  var link = options.link;
  var modernUser;
  this.cache = {
    orgs: {},
    users: {},
  };
  this.modernUser = function () {
    return modernUser;
  };
  this.createModernUser = function (id, login) {
    modernUser = new User(this, id);
    modernUser.login = login;
    return modernUser;
  };
  this.setting = function (name) {
    return applicationConfiguration[name];
  };
  this.dataClient = function () {
    return dataClient;
  };
  this.redisClient = function () {
    return redisInstance;
  };
  this.safeConfiguration = safeSettings(applicationConfiguration);
  this.baseUrl = '/';
  this.redis = new RedisHelper(this, applicationConfiguration.redis.prefix);
  if (link && options.request) {
    return callback(new Error('The context cannot be set from both a request and a link instance.'));
  }
  if (link) {
    return self.setPropertiesFromLink(link, callback);
  }
  if (options.request) {
    return this.resolveLinkFromRequest(options.request, callback);
  }
  callback(new Error('Could not initialize the context for the acting user.'), self);
}

OpenSourceUserContext.prototype.setPropertiesFromLink = function (link, callback) {
  this.usernames.github = link.ghu;
  this.id.github = link.ghid.toString();
  this.usernames.azure = link.aadupn;
  this.entities.link = link;
  this.displayNames.azure = link.aadname;
  this.avatars.github = link.ghavatar;
  var modernUser = this.modernUser();
  if (!modernUser && this.id.github) {
    modernUser = this.createModernUser(this.id.github, this.usernames.github);
  }
  modernUser.link = link;
  callback(null, this);
};

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.resolveLinkFromRequest = function (request, callback) {
  var self = this;
  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;
    self.avatars.github = requestUser.github.avatarUrl;
  }
  if (requestUser && requestUser.azure) {
    self.usernames.azure = requestUser.azure.username;
    self.displayNames.azure = requestUser.azure.displayName;
  }
  if (self.setting('primaryAuthenticationScheme') === 'aad' && requestUser.azure && requestUser.azure.oid) {
    return self.dataClient().getUserByAadOid(requestUser.azure.oid, function (findError, userLinks) {
      if (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(null, self);
      }
      if (userLinks.length > 1) {
        return tooManyLinksError(self, userLinks, callback);
      }
      var link = userLinks[0];
      if (requestUser.github && requestUser.github.username && link.ghu !== requestUser.github.username && link.ghid !== requestUser.github.id) {
        return existingGitHubIdentityError(self, link, requestUser, callback);
      }
      return self.setPropertiesFromLink(link, callback);
    });
  }
  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.'), 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.'), self);
    }
    if (link) {
      return self.setPropertiesFromLink(link, callback);
    } else {
      callback(null, self);
    }
  });
};

// ----------------------------------------------------------------------------
// SECURITY METHOD:
// Determine whether the authenticated user is an Administrator of the org. At
// this time there is a special "portal sudoers" team that is used. The GitHub
// admin flag is not used [any longer] for performance reasons to reduce REST
// calls to GitHub.
// ----------------------------------------------------------------------------
OpenSourceUserContext.prototype.isPortalAdministrator = function (callback) {
  /*
  var self = this;
  if (self.entities && self.entities.primaryMembership) {
      var pm = self.entities.primaryMembership;
      if (pm.role && pm.role === 'admin') {
          return callback(null, true);
      }
  }
  */
  this.org().getPortalSudoersTeam().isMember(function (error, isMember) {
    if (error) {
{'fraction_non_alphanumeric': 0.16117749927134947, 'fraction_numerical': 0.0005829204313611193, 'mean_word_length': 3.0522586359610275, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6107673', 'n_tokens_mistral': 3952, 'n_tokens_neox': 3884, 'n_words': 1033}