зеркало из
1
0
Форкнуть 0

API session refactor + directory prune

- Client APIs remain behind the session middleware
- Non-client APIs no longer set cookies given their stateless nature
- Simplifies the directory structure
- Removes Microsoft-specific API configuration and code not useful to the OSS version
This commit is contained in:
Jeff Wilcox 2023-05-11 13:07:14 -07:00
Родитель a654aa7117
Коммит 66b87b31d0
95 изменённых файлов: 558 добавлений и 595 удалений

Просмотреть файл

@ -30,6 +30,7 @@
"aadupn",
"accountinfo",
"accountinformation",
"actionperms",
"actionschecked",
"actionsconfigured",
"actionscreated",
@ -170,8 +171,8 @@
"datasharing",
"datatable",
"DATETIME",
"dcount",
"dbaeumer",
"dcount",
"decisionmaker",
"Decisionmaker",
"Decisionmakers",
@ -179,8 +180,8 @@
"defaultbranch",
"deferreason",
"deislabs",
"deletesettingsorgname",
"deletedetected",
"deletesettingsorgname",
"demilestoned",
"departedowners",
"deployr",
@ -278,6 +279,7 @@
"GHID",
"ghname",
"ghowners",
"ghossapis",
"GHPI",
"ghpimigrationphase",
"ghrp",
@ -319,6 +321,7 @@
"IAAD",
"ictext",
"identicons",
"idtoken",
"iitemp",
"inclusivity",
"indiv",
@ -354,6 +357,7 @@
"jeffwilcox",
"jitgrants",
"joblog",
"jobname",
"jsoncontribution",
"jsoncreated",
"jwilcox",
@ -402,6 +406,7 @@
"Maintainerships",
"maintainerupdated",
"maintainerupdatedby",
"maintainerupdatedbytext",
"maints",
"maluuba",
"Maluuba",
@ -561,6 +566,8 @@
"Passcode",
"patachable",
"pcontent",
"permlevel",
"permscheckdate",
"petyan",
"pglink",
"pgpool",
@ -595,6 +602,7 @@
"Puid",
"pullmerges",
"pullrequestreview",
"pullrequests",
"pullrequestsmerged",
"pullrequestsopened",
"pushd",
@ -637,6 +645,7 @@
"repositorymetadata",
"repositoryname",
"repositoryprivate",
"repositoryprojects",
"repositoryteamcache",
"reposize",
"requestedtime",
@ -659,10 +668,11 @@
"samplevault",
"Satya",
"scansummary",
"scorecardreprocessrequest",
"SCIM",
"scorecardreprocessrequest",
"secretscanningonpush",
"secscandata",
"securityevents",
"securitygroupalias",
"selfid",
"SELFSERVICE",
@ -755,13 +765,13 @@
"tlink",
"tolower",
"totalcount",
"toupper",
"touchedtime",
"toupper",
"Tpng",
"treatedconsent",
"treateddirectmanager",
"Treateds",
"tsbuild",
"Tpng",
"Tsvg",
"twentypercent",
"typeahead",

Просмотреть файл

@ -17,7 +17,7 @@ import {
closeOldRequest,
} from '../../../routes/settings/approvals';
import { getProviders } from '../../../transitional';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
const router: Router = Router();

Просмотреть файл

@ -12,7 +12,7 @@ import { IProviders, ReposAppRequest } from '../../../interfaces';
import { jsonError } from '../../../middleware';
import getCompanySpecificDeployment from '../../../middleware/companySpecificDeployment';
import { ErrorHelper, getProviders } from '../../../transitional';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
import routeApprovals from './approvals';
import routeIndividualContextualOrganization from './organization';

Просмотреть файл

@ -14,7 +14,7 @@ import {
} from '../../../../interfaces';
import { jsonError } from '../../../../middleware';
import getCompanySpecificDeployment from '../../../../middleware/companySpecificDeployment';
import { IndividualContext } from '../../../../user';
import { IndividualContext } from '../../../../business/user';
import RouteRepos from './repos';
import RouteTeams from './teams';

Просмотреть файл

@ -13,7 +13,7 @@ import {
getContextualRepository,
getContextualRepositoryPermissions,
} from '../../../../middleware/github/repoPermissions';
import { IndividualContext } from '../../../../user';
import { IndividualContext } from '../../../../business/user';
import { ErrorHelper, getProviders } from '../../../../transitional';
import NewRepositoryLockdownSystem from '../../../../features/newRepositories/newRepositoryLockdown';

Просмотреть файл

@ -10,7 +10,7 @@ import { jsonError } from '../../../../middleware';
import { setContextualRepository } from '../../../../middleware/github/repoPermissions';
import { OrganizationMembershipState, ReposAppRequest } from '../../../../interfaces';
import { IndividualContext } from '../../../../user';
import { IndividualContext } from '../../../../business/user';
import { createRepositoryFromClient } from '../../newOrgRepo';
import RouteContextualRepo from './repo';

Просмотреть файл

@ -25,7 +25,7 @@ import { submitTeamJoinRequest } from '../../../../routes/org/team';
import { postActionDecision, TeamApprovalDecision } from '../../../../routes/org/team/approval';
import { PermissionWorkflowEngine } from '../../../../routes/org/team/approvals';
import { getProviders } from '../../../../transitional';
import { IndividualContext } from '../../../../user';
import { IndividualContext } from '../../../../business/user';
const router: Router = Router();

Просмотреть файл

@ -6,7 +6,7 @@
import asyncHandler from 'express-async-handler';
import { ReposAppRequest } from '../../../interfaces';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
export default asyncHandler(async (req: ReposAppRequest, res) => {
const activeContext = (req.individualContext || req.apiContext) as IndividualContext;

Просмотреть файл

@ -6,7 +6,7 @@
import asyncHandler from 'express-async-handler';
import { GitHubRepositoryPermission, ReposAppRequest } from '../../../interfaces';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
export default asyncHandler(async (req: ReposAppRequest, res, next) => {
try {

Просмотреть файл

@ -10,7 +10,7 @@ import { sendLinkedAccountMail } from '../../../business/operations/link';
import { ReposAppRequest } from '../../../interfaces';
import { jsonError } from '../../../middleware';
import { CreateError, getProviders } from '../../../transitional';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
const router: Router = Router();

Просмотреть файл

@ -6,7 +6,7 @@
import asyncHandler from 'express-async-handler';
import { ReposAppRequest, TeamJsonFormat } from '../../../interfaces';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
export default asyncHandler(async (req: ReposAppRequest, res, next) => {
const activeContext = (req.individualContext || req.apiContext) as IndividualContext;

Просмотреть файл

@ -17,7 +17,8 @@ import { getProviders } from '../../transitional';
import getCompanySpecificDeployment from '../../middleware/companySpecificDeployment';
import { ReposAppRequest } from '../../interfaces';
import type { ReposAppRequest } from '../../interfaces';
import type { IndividualContext } from '../../business/user';
import routeClientNewRepo from './newRepo';
import routeContext from './context';
@ -61,6 +62,64 @@ router.use('/news', routeNews);
const dynamicStartupInstance = getCompanySpecificDeployment();
dynamicStartupInstance?.routes?.api?.index && dynamicStartupInstance?.routes?.api?.index(router);
router.get('/', (req: ReposAppRequest, res) => {
const { config } = getProviders(req);
const runtimeConfiguration = req.app.runtimeConfiguration;
const activeContext = (req.individualContext || req.apiContext) as IndividualContext;
const isGitHubAuthenticated = !!activeContext.getSessionBasedGitHubIdentity()?.id;
const data = {
deployment: config.continuousDeployment,
frontend: runtimeConfiguration?.client || {},
hosting: {
app: config?.web?.app,
baseUrl: config?.webServer?.baseUrl,
server: {
port: config?.webServer?.port,
hostname: req.hostname,
},
appService: config?.webServer?.appService?.name
? {
name: config?.webServer?.appService?.name,
slot: config?.webServer?.appService?.slot,
region: config?.webServer?.appService?.region,
}
: undefined,
},
runtime: {
node: {
environment: config?.node?.environment,
version: config?.node?.version,
},
},
development: {
githubCodespacesConnected: config?.github?.codespaces?.connected === true ? true : undefined,
githubCodespacesName: config?.github?.codespaces?.name,
},
app: {
environment: config?.environment?.name,
appName: config?.web?.app,
},
session: {
corporateIdentity: activeContext.corporateIdentity,
githubIdentity: activeContext.getGitHubIdentity(),
isAuthenticated: true,
isGitHubAuthenticated,
isLinked: !!activeContext.link,
hasAdditionalLinks: activeContext.hasAdditionalLinks,
impersonation: config.impersonation?.corporateId
? {
corporateId: config.impersonation.corporateId,
githubId: config.impersonation.githubId,
}
: undefined,
},
};
res.contentType('application/json');
return res.send(JSON.stringify(data, null, 2));
});
router.use((req, res, next) => {
return next(jsonError('The resource or endpoint you are looking for is not there', 404));
});

Просмотреть файл

@ -6,7 +6,7 @@
import { Router } from 'express';
import asyncHandler from 'express-async-handler';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { jsonError } from '../../middleware';
import { ErrorHelper, getProviders } from '../../transitional';
import { unlinkInteractive } from '../../routes/unlink';

Просмотреть файл

@ -11,7 +11,7 @@ import _ from 'lodash';
import { getProviders } from '../../transitional';
import { jsonError } from '../../middleware/jsonError';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { Organization } from '../../business/organization';
import { CreateRepository, ICreateRepositoryApiResult, CreateRepositoryEntrypoint } from '../createRepo';
import { Team } from '../../business/team';

Просмотреть файл

@ -21,7 +21,7 @@ import {
OrganizationAnnotation,
} from '../../../entities/organizationAnnotation';
import { ErrorHelper, getProviders } from '../../../transitional';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
import { IProviders } from '../../../interfaces';
const router: Router = Router();

Просмотреть файл

@ -9,7 +9,7 @@ import asyncHandler from 'express-async-handler';
import { jsonError } from '../../../middleware';
import { ErrorHelper, getProviders } from '../../../transitional';
import { Repository } from '../../../business';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
import NewRepositoryLockdownSystem from '../../../features/newRepositories/newRepositoryLockdown';
import {
AddRepositoryPermissionsToRequest,

Просмотреть файл

@ -28,7 +28,7 @@ import {
IApprovalPackage,
} from '../routes/org/repoWorkflowEngine';
import { IMailProvider } from '../lib/mailProvider';
import { IndividualContext } from '../user';
import { IndividualContext } from '../business/user';
import NewRepositoryLockdownSystem from '../features/newRepositories/newRepositoryLockdown';
import {
ICreateRepositoryResult,

Просмотреть файл

@ -9,18 +9,16 @@ const router: Router = Router();
import cors from 'cors';
import { getProviders } from '../transitional';
import { CreateError, getProviders } from '../transitional';
import { jsonError } from '../middleware';
import { IApiRequest } from '../middleware/apiReposAuth';
import apiExtension from './extension';
import apiClient from './client/';
import apiWebhook from './webhook';
import apiPeople from './people';
import AadApiAuthentication from '../middleware/apiAad';
import AadApiAuthentication, { requireAadApiAuthorizedScope } from '../middleware/apiAad';
import AzureDevOpsAuthenticationMiddleware from '../middleware/apiVstsAuth';
import ReposApiAuthentication from '../middleware/apiReposAuth';
import { CreateRepository, CreateRepositoryEntrypoint } from './createRepo';
@ -31,10 +29,20 @@ import { ReposAppRequest } from '../interfaces';
const hardcodedApiVersions = ['2019-10-01', '2019-02-01', '2017-09-01', '2017-03-08', '2016-12-01'];
router.use('/client', apiClient);
function isClientRoute(req: ReposAppRequest) {
const path = req.path.toLowerCase();
return path.startsWith('/client');
}
router.use('/webhook', apiWebhook);
router.use((req: IApiRequest, res, next) => {
if (isClientRoute(req)) {
// The frontend client routes are hooked into Express after
// the session middleware. The client route does not require
// an API version.
return next();
}
const apiVersion = (req.query['api-version'] || req.headers['api-version']) as string;
if (!apiVersion) {
return next(jsonError('This endpoint requires that an API Version be provided.', 422));
@ -75,35 +83,36 @@ router.use('/extension', cors(), multipleProviders, apiExtension);
const dynamicStartupInstance = getCompanySpecificDeployment();
dynamicStartupInstance?.routes?.api?.index && dynamicStartupInstance?.routes?.api?.rootIndex(router);
router.use('/:org', aadAndCustomProviders);
//-----------------------------------------------------------------------------
// Create repository API
//-----------------------------------------------------------------------------
router.post('/:org/repos', aadAndCustomProviders);
router.use('/:org', function (req: IApiRequest, res, next) {
const orgName = req.params.org;
if (!req.apiKeyToken.organizationScopes) {
return next(jsonError('There is a problem with the key configuration (no organization scopes)', 412));
}
// '*'' is authorized for all organizations in this configuration environment
if (!req.apiKeyToken.hasOrganizationScope(orgName)) {
return next(jsonError('The key is not authorized for this organization', 401));
}
if (!req.apiKeyToken.scopes) {
return next(jsonError('There is a problem with the key configuration (no specific API scopes)', 412));
}
if (!req.apiKeyToken.hasScope('createRepo')) {
return next(jsonError('The key is not authorized to use the repo create APIs', 401));
}
router.post(
'/:org/repos',
requireAadApiAuthorizedScope('createRepo'),
function (req: IApiRequest, res, next) {
const orgName = req.params.org;
if (!req.apiKeyToken.organizationScopes) {
return next(jsonError('There is a problem with the key configuration (no organization scopes)', 412));
}
// '*'' is authorized for all organizations in this configuration environment
if (!req.apiKeyToken.hasOrganizationScope(orgName)) {
return next(jsonError('The key is not authorized for this organization', 401));
}
const providers = getProviders(req);
const operations = providers.operations;
let organization = null;
try {
organization = operations.getOrganization(orgName);
} catch (ex) {
return next(jsonError(ex, 400));
const providers = getProviders(req);
const operations = providers.operations;
let organization = null;
try {
organization = operations.getOrganization(orgName);
} catch (ex) {
return next(jsonError(ex, 400));
}
req.organization = organization;
return next();
}
req.organization = organization;
return next();
});
);
router.post(
'/:org/repos',
@ -176,6 +185,16 @@ router.post(
})
);
router.use((req: IApiRequest, res, next) => {
if (isClientRoute(req)) {
// The frontend client routes are hooked into Express after
// the session middleware. The client route does not require
// an API version.
return next();
}
return next(CreateError.NotFound('The API endpoint was not found.'));
});
router.use(JsonErrorHandler);
export default router;

Просмотреть файл

@ -10,7 +10,7 @@ import * as common from './common';
import { wrapError } from '../utils';
import { corporateLinkToJson } from './corporateLink';
import { Organization } from './organization';
import { AppPurpose } from '../github';
import { AppPurpose } from './githubApps';
import { ILinkProvider } from '../lib/linkProviders';
import { CacheDefault, getMaxAgeSeconds } from '.';
import {

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import { Organization } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -8,7 +8,7 @@ import { createAppAuth, InstallationAccessTokenAuthentication } from '@octokit/a
import { AppAuthentication, AuthInterface } from '@octokit/auth-app/dist-types/types';
import { AppPurposeTypes, ICustomAppPurpose } from '.';
import { IAuthorizationHeaderValue } from '../interfaces';
import { IAuthorizationHeaderValue } from '../../interfaces';
import Debug from 'debug';
const debug = Debug('github:tokens');

Просмотреть файл

@ -3,8 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { IReposApplication } from '../interfaces';
import { CreateError } from '../transitional';
import { IReposApplication } from '../../interfaces';
import { CreateError } from '../../transitional';
import Debug from 'debug';
const debug = Debug('github:tokens');

Просмотреть файл

@ -17,11 +17,11 @@ import {
getAppPurposeId,
} from '.';
import { GitHubAppTokens } from './appTokens';
import { IAuthorizationHeaderValue, NoCacheNoBackground } from '../interfaces';
import { OrganizationSetting } from '../entities/organizationSettings/organizationSetting';
import { readFileToText } from '../utils';
import { Operations, OperationsCore, Organization } from '../business';
import { CreateError } from '../transitional';
import { IAuthorizationHeaderValue, NoCacheNoBackground } from '../../interfaces';
import { OrganizationSetting } from '../../entities/organizationSettings/organizationSetting';
import { readFileToText } from '../../utils';
import { Operations, OperationsCore, Organization } from '..';
import { CreateError } from '../../transitional';
export interface IGitHubRateLimit {
limit: number;

Просмотреть файл

@ -4,8 +4,8 @@
//
import { OrganizationSetting } from '../../entities/organizationSettings/organizationSetting';
import { GitHubAppAuthenticationType, AppPurpose, ICustomAppPurpose, AppPurposeTypes } from '../../github';
import { GitHubTokenManager } from '../../github/tokenManager';
import { GitHubAppAuthenticationType, AppPurpose, ICustomAppPurpose, AppPurposeTypes } from '../githubApps';
import { GitHubTokenManager } from '../githubApps/tokenManager';
import {
IProviders,
ICacheDefaultTimes,

Просмотреть файл

@ -9,7 +9,7 @@ import throat from 'throat';
import { Account } from '../account';
import { GraphManager } from '../graphManager';
import { IGitHubOrganizationResponse, Organization } from '../organization';
import { GitHubTokenManager } from '../../github/tokenManager';
import { GitHubTokenManager } from '../githubApps/tokenManager';
import RenderHtmlMail from '../../lib/emailRender';
import { wrapError, sortByCaseInsensitive } from '../../utils';
import { Repository } from '../repository';
@ -20,7 +20,7 @@ import {
GitHubAppAuthenticationType,
GitHubAppPurposes,
IGitHubAppConfiguration,
} from '../../github';
} from '../githubApps';
import {
OrganizationFeature,
OrganizationSetting,

Просмотреть файл

@ -13,7 +13,7 @@ import { Repository } from './repository';
import { wrapError } from '../utils';
import { StripGitHubEntity } from '../lib/github/restApi';
import { GitHubResponseType } from '../lib/github/endpointEntities';
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import {
OrganizationFeature,
OrganizationSetting,
@ -63,7 +63,7 @@ import { CreateError, ErrorHelper } from '../transitional';
import { jsonError } from '../middleware';
import getCompanySpecificDeployment from '../middleware/companySpecificDeployment';
import { ConfigGitHubTemplates } from '../config/github.templates.types';
import { GitHubTokenManager } from '../github/tokenManager';
import { GitHubTokenManager } from './githubApps/tokenManager';
import { OrganizationProjects } from './projects';
import { OrganizationDomains } from './domains';

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import { Organization, Repository } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import { Organization } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import { Organization } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -17,7 +17,7 @@ import {
RepositoryIssue,
} from '.';
import { RepositoryMetadataEntity } from '../entities/repositoryMetadata/repositoryMetadata';
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import {
IPurposefulGetAuthorizationHeader,
IOperationsInstance,

Просмотреть файл

@ -5,7 +5,7 @@
import { Repository } from './repository';
import { getPageSize, getMaxAgeSeconds, CacheDefault } from '.';
import { AppPurpose } from '../github';
import { AppPurpose } from './githubApps';
import {
IPurposefulGetAuthorizationHeader,
IOperationsInstance,

Просмотреть файл

@ -5,7 +5,7 @@
import { Repository } from './repository';
import { wrapError } from '../utils';
import { AppPurpose } from '../github';
import { AppPurpose } from './githubApps';
import { CacheDefault, getMaxAgeSeconds, Operations } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -5,7 +5,7 @@
import { Repository } from './repository';
import { wrapError } from '../utils';
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import { CacheDefault, getMaxAgeSeconds } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { AppPurpose } from '../github';
import { AppPurpose } from './githubApps';
import {
IOperationsInstance,
IPurposefulGetAuthorizationHeader,

Просмотреть файл

@ -4,7 +4,7 @@
//
import { CacheDefault, getMaxAgeSeconds, RepositoryIssue } from '.';
import { AppPurpose, AppPurposeTypes } from '../github';
import { AppPurpose, AppPurposeTypes } from './githubApps';
import {
IOperationsInstance,
IPurposefulGetAuthorizationHeader,

Просмотреть файл

@ -5,7 +5,7 @@
import { Repository } from './repository';
import { wrapError } from '../utils';
import { AppPurpose } from '../github';
import { AppPurpose } from './githubApps';
import { CacheDefault, getMaxAgeSeconds } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -13,7 +13,7 @@ import { TeamMember } from './teamMember';
import { TeamRepositoryPermission } from './teamRepositoryPermission';
import { IApprovalProvider } from '../entities/teamJoinApproval/approvalProvider';
import { TeamJoinApprovalEntity } from '../entities/teamJoinApproval/teamJoinApproval';
import { AppPurpose } from '../github';
import { AppPurpose } from './githubApps';
import { CacheDefault, getMaxAgeSeconds, getPageSize, Organization } from '.';
import {
IOperationsInstance,

Просмотреть файл

@ -10,16 +10,16 @@ import {
Repository,
Team,
TeamRepositoryPermission,
} from '../business';
import QueryCache from '../business/queryCache';
} from '..';
import QueryCache from '../queryCache';
import {
IQueryCacheTeamRepositoryPermission,
OrganizationMembershipRole,
GitHubTeamRole,
OrganizationMembershipRoleQuery,
GitHubRepositoryPermission,
} from '../interfaces';
import { SettleToStateValue, isPermissionBetterThan, ErrorHelper } from '../transitional';
} from '../../interfaces';
import { SettleToStateValue, isPermissionBetterThan, ErrorHelper } from '../../transitional';
import LinkManager from './linkManager';
// PLANNING once consolidated

Просмотреть файл

@ -10,8 +10,8 @@ import objectPath from 'object-path';
import Debug from 'debug';
const debug = Debug.debug('context');
import { addBreadcrumb, isCodespacesAuthenticating } from '../utils';
import { Operations } from '../business/operations';
import { addBreadcrumb, isCodespacesAuthenticating } from '../../utils';
import { Operations } from '../operations';
import { UserContext } from './aggregate';
import {
ReposAppRequest,
@ -21,7 +21,7 @@ import {
IAppSession,
ICorporateLink,
IDictionary,
} from '../interfaces';
} from '../../interfaces';
// - - - identity

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { Operations } from '../business/operations';
import { Operations } from '../operations';
export default class LinkManager {
private _context: any;

Просмотреть файл

@ -10,5 +10,5 @@ export type ConfigRootAuthentication = {
};
export type ConfigAuthentication = ConfigRootAuthenticationVsts & {
scheme: 'aad' | 'github';
scheme: 'aad' | 'github' | 'oauth2';
};

Просмотреть файл

@ -15,6 +15,7 @@ export type ConfigNewsArticleAction = {
export type ConfigNewsArticle = {
title: string;
subtitle: string;
ignore: boolean;
paragraphs: string[];
actions: ConfigNewsArticleAction[];
};

15
config/node.js Normal file
Просмотреть файл

@ -0,0 +1,15 @@
//
// Copyright (c) Microsoft.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
'use strict';
module.exports = function (graphApi) {
const environment = graphApi.environment.get('NODE_ENV');
return {
environment,
isProduction: environment === 'production',
version: process.version,
};
};

Просмотреть файл

@ -1,4 +0,0 @@
{
"environment": "env://NODE_ENV",
"isProduction": "env://NODE_ENV?trueIf=production"
}

Просмотреть файл

@ -9,5 +9,6 @@ export type ConfigRootNode = {
export type ConfigNode = {
environment: string;
version: string;
isProduction: boolean;
};

Просмотреть файл

@ -23,9 +23,15 @@ import {
PostgresJsonEntityQuery,
PostgresSettings,
} from '../../lib/entityMetadataProvider/postgres';
import type { ApiClientGroupDisplay } from '../../interfaces/api';
const type = Type;
export type TokenAadAppInformation = {
clientId: string;
objectId: string;
};
interface ITokenEntityProperties {
token: any;
active: any;
@ -56,6 +62,7 @@ const fieldNames = Object.getOwnPropertyNames(Field);
export class PersonalAccessToken implements IObjectWithDefinedKeys, ITokenEntityProperties {
private _key: string;
private _aadInfo: TokenAadAppInformation;
token: string;
@ -75,12 +82,23 @@ export class PersonalAccessToken implements IObjectWithDefinedKeys, ITokenEntity
this.created = new Date();
}
static CreateFromAadAuthorization({ appId, oid, scopes, organizationScopes }): PersonalAccessToken {
static CreateFromAadAuthorization(
{ appId, oid, scopes, organizationScopes },
optionalDisplayValues: ApiClientGroupDisplay
): PersonalAccessToken {
const pat = new PersonalAccessToken();
pat._aadInfo = {
clientId: appId,
objectId: oid,
};
pat.corporateId = null;
pat.description = `AAD oid ${oid} app ${appId} with scopes ${scopes}`;
pat.source = `AAD oid ${oid} app ${appId}`;
pat.displayUsername = 'AAD Identity';
pat.displayUsername = optionalDisplayValues?.displayName
? `${optionalDisplayValues.displayName}${
optionalDisplayValues.contactAddress ? ' (' + optionalDisplayValues.contactAddress + ')' : ''
}`
: 'AAD Identity';
pat.organizationScopes = organizationScopes;
pat.scopes = scopes;
return pat;
@ -110,6 +128,10 @@ export class PersonalAccessToken implements IObjectWithDefinedKeys, ITokenEntity
return pat;
}
getAadInformation(): TokenAadAppInformation {
return this._aadInfo;
}
getObjectFieldNames(): string[] {
return fieldNames;
}

Просмотреть файл

@ -5,7 +5,7 @@
import { Repository } from '../../business';
import { RepositoryMetadataEntity } from '../../entities/repositoryMetadata/repositoryMetadata';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { validateUserCanSelfDeleteRepository } from './validateSelfServiceDelete';
import { validateUserCanConfigureRepository } from './validateSelfServiceSetup';

Просмотреть файл

@ -8,7 +8,7 @@ import { DateTime } from 'luxon';
import { Repository } from '../../business';
import { RepositoryMetadataEntity } from '../../entities/repositoryMetadata/repositoryMetadata';
import { RepositoryLockdownState } from '../../interfaces';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { daysInMilliseconds } from '../../utils';
export async function validateUserCanSelfDeleteRepository(

Просмотреть файл

@ -5,7 +5,7 @@
import { RepositoryMetadataEntity } from '../../entities/repositoryMetadata/repositoryMetadata';
import { RepositoryLockdownState } from '../../interfaces';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
export async function validateUserCanConfigureRepository(
metadata: RepositoryMetadataEntity,

Просмотреть файл

@ -5,7 +5,7 @@
import { Team } from '../business';
import { Operations } from '../business';
import { IndividualContext } from '../user';
import { IndividualContext } from '../business/user';
import { addArrayToSet } from '../utils';
import { IMail } from '../lib/mailProvider';
import {

9
interfaces/api.ts Normal file
Просмотреть файл

@ -0,0 +1,9 @@
//
// Copyright (c) Microsoft.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
export type ApiClientGroupDisplay = {
displayName: string;
contactAddress: string;
};

Просмотреть файл

@ -6,6 +6,8 @@
import { Application } from 'express';
import { IProviders } from './providers';
import type { RuntimeConfiguration } from './config';
export interface IApplicationProfile {
applicationName: string;
customErrorHandlerRender?: (errorView: any, err: Error, req: any, res: any, next: any) => Promise<void>;
@ -28,6 +30,7 @@ export interface IReposApplication extends Application {
config: any;
isBackgroundJob: boolean;
enableAllGitHubApps: boolean;
runtimeConfiguration: RuntimeConfiguration;
startServer: () => Promise<void>;

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
export interface ICompanySpecificFeatureDemo {
isDemoUser: (activeContext: IndividualContext) => boolean;

Просмотреть файл

@ -5,7 +5,7 @@
import { Organization } from '../../../business';
import { IProviders } from '../../../interfaces';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
export interface ICompanySpecificFeatureOrganizationJoinAcl {
tryAuthorizeOrganizationJoin: (

Просмотреть файл

@ -5,7 +5,7 @@
import { IProviders, LocalApiRepoAction } from '../..';
import { Repository } from '../../../business';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
export interface ICompanySpecificRepositoryStateStatus {}

Просмотреть файл

@ -6,8 +6,9 @@
import { Repository, Team } from '../../business';
import { IContextualRepositoryPermissions } from '../../middleware/github/repoPermissions';
import { IProviders, ReposAppRequest } from '../../interfaces';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { IRequestTeamPermissions } from '../../middleware/github/teamPermissions';
import type { ApiClientGroupDisplay } from '../api';
export interface ICompanySpecificRepoPermissionsMiddlewareCalls {
afterPermissionsInitialized?: (
@ -39,6 +40,16 @@ export interface ICompanySpecificTeamPermissionsMiddlewareCalls {
export interface ICompanySpecificAuthenticationCalls {
shouldRedirectToSignIn?: (providers: IProviders, req: ReposAppRequest) => Promise<boolean>;
getAadApiAuthenticationValidator?(providers: IProviders): IAadAuthenticationValidator;
}
export interface IAadAuthenticationValidator {
isAuthorizedTenant(tenantId: string): Promise<boolean>;
getAudienceIdentities(): Promise<string[]>;
getAuthorizedClientIdToken(clientId: string): Promise<any>;
getAuthorizedObjectIdToken(objectId: string): Promise<any>;
getScopes(tokenRepresentation: any): Promise<string[]>;
getDisplayValues(tokenRepresentation: any): Promise<ApiClientGroupDisplay>;
}
export interface IAttachCompanySpecificMiddleware {

Просмотреть файл

@ -5,3 +5,6 @@
import type { SiteConfiguration } from '../config/index.types';
export type { SiteConfiguration };
import type { RootRuntimeConfigurationClient } from '../middleware/staticClientApp2';
export type RuntimeConfiguration = RootRuntimeConfigurationClient;

Просмотреть файл

@ -3,7 +3,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { AppPurposeTypes } from '../../github';
import { AppPurposeTypes } from '../../business/githubApps';
export interface ICacheOptions {
backgroundRefresh?: any | null | undefined;

Просмотреть файл

@ -7,8 +7,11 @@ import { Session } from 'express-session';
import { Request, Response } from 'express';
import { AccessToken } from 'simple-oauth2';
import type { TelemetryClient } from 'applicationinsights';
import type { IReposApplication } from './app';
import { Organization, Team } from '../business';
import { IndividualContext } from '../user';
import { IndividualContext } from '../business/user';
export enum UserAlertType {
Success = 'success',
@ -40,8 +43,10 @@ export interface ReposAppRequest extends Request {
isAuthenticated(): boolean;
user: any;
app: IReposApplication;
// our extensions
insights?: any;
insights?: TelemetryClient;
reposContext?: IReposAppContext;
currentOrganizationMemberships?: any; // needs a redesign
teamsPagerMode?: string;

Просмотреть файл

@ -14,7 +14,7 @@ import {
IPurposefulGetAuthorizationHeader,
ITeamMembershipOptions,
} from '../../interfaces';
import { AppPurpose } from '../../github';
import { AppPurpose } from '../../business/githubApps';
interface IOrganizationsResponse extends IRestResponse {
orgs?: any;

Просмотреть файл

@ -15,7 +15,7 @@ import { CrossOrganizationCollator } from './crossOrganization';
import { LinkMethods } from './links';
import { IGetAuthorizationHeader, IAuthorizationHeaderValue } from '../../interfaces';
import { ICacheHelper } from '../caching';
import { ICustomAppPurpose } from '../../github';
import { ICustomAppPurpose } from '../../business/githubApps';
export enum CacheMode {
ValidateCache = 'ValidateCache',

Просмотреть файл

@ -1,70 +0,0 @@
//
// Copyright (c) Microsoft.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { getAadApiConfiguration } from './apiAad';
describe('AAD API Configuration', () => {
let standardConfig = {};
let stringConfig = {};
beforeEach(() => {
standardConfig = {
microsoft: {
api: {
aad: {
authorizedTenants: 't1,t2',
apiAppScope: 'api://app',
approvedApps: {
scopes: {
create: {
repos: ['a1'],
},
},
},
approvedOids: {
scopes: {
create: {
repos: ['o1'],
},
},
},
},
},
},
};
stringConfig = {
microsoft: {
api: {
aad: {
authorizedTenants: 't1,t2',
apiAppScope: 'api://app',
approvedApps: {
scopes: {
create: {
repos: 'a1,a2,a3',
},
},
},
approvedOids: {
scopes: {
create: {
repos: 'o1,o2',
},
},
},
},
},
},
};
});
test('OID and app ID string values parse', () => {
getAadApiConfiguration(stringConfig);
});
test('OID and app ID arrays work', () => {
getAadApiConfiguration(standardConfig);
});
});

Просмотреть файл

@ -9,24 +9,22 @@ import jwksClient from 'jwks-rsa';
import { isJsonError, jsonError } from './jsonError';
import { IApiRequest, wrapErrorForImmediateUserError } from './apiReposAuth';
import { PersonalAccessToken } from '../entities/token/token';
import { CreateError, getProviders, splitSemiColonCommas } from '../transitional';
import { CreateError, getProviders } from '../transitional';
import getCompanySpecificDeployment from './companySpecificDeployment';
// TODO: Caching of signing keys
// CONSIDER: Caching of signing keys
interface IConfigAadApiApprovedAppsOrOids {
scopes: {
read: {
links: string[] | string;
maintainers: string[] | string;
'microsoft-github-policy-service': string[] | string;
};
create: {
repos: string[] | string;
};
export function requireAadApiAuthorizedScope(scope: string) {
return (req: IApiRequest, res, next) => {
const { apiKeyToken } = req;
if (!apiKeyToken.hasScope(scope)) {
return next(jsonError(`Not authorized for ${scope}`, 403));
}
return next();
};
}
export default function AadApiMiddleware(req: IApiRequest, res, next) {
export default function aadApiMiddleware(req: IApiRequest, res, next) {
return validateAadAuthorization(req)
.then((ok) => {
return next();
@ -65,142 +63,8 @@ function getSigningKeys(header, callback) {
});
}
export function getAadApiConfiguration(config: any) {
const allowedTenants = Array.isArray(config?.microsoft?.api?.aad?.authorizedTenants)
? config.microsoft.api.aad.authorizedTenants
: (config?.microsoft?.api?.aad?.authorizedTenants || '').split(',');
if (!allowedTenants) {
throw jsonError('App not configured for authorizing specific tenants', 500);
}
let reposApiAudienceIdentities = config?.microsoft?.api?.aad?.apiAppScopes
? (config.microsoft.api.aad.apiAppScopes as string).split(',')
: null;
if (!reposApiAudienceIdentities) {
const reposApiAudienceIdentity = config?.microsoft?.api?.aad?.apiAppScope
? [config.microsoft.api.aad.apiAppScope]
: null;
if (!reposApiAudienceIdentity) {
throw jsonError('App not configured for authorizing APIs via AAD', 500);
}
reposApiAudienceIdentities = reposApiAudienceIdentity;
}
if (!reposApiAudienceIdentities) {
throw jsonError('App not configured for authorizing APIs via AAD', 500);
}
const approvedApps = config?.microsoft?.api?.aad?.approvedApps as IConfigAadApiApprovedAppsOrOids;
if (approvedApps === undefined) {
throw jsonError('AAD API app authentication is not configured', 500);
}
const approvedOids = config?.microsoft?.api?.aad?.approvedOids as IConfigAadApiApprovedAppsOrOids;
if (approvedApps === undefined) {
throw jsonError('AAD API OID authentication is not configured', 500);
}
// Any app that has a valid scope can call the API, but may not be scoped and will error out in the API tier
const approvedAppsToCreateRepos = Array.isArray(approvedApps?.scopes?.create?.repos)
? approvedApps?.scopes?.create?.repos
: approvedApps?.scopes?.create?.repos?.split
? [...approvedApps.scopes.create.repos.split(',')]
: [];
const approvedAppsToReadLinks = Array.isArray(approvedApps?.scopes?.read?.links)
? approvedApps?.scopes?.read?.links
: approvedApps?.scopes?.read?.links?.split
? [...approvedApps.scopes.read.links.split(',')]
: [];
const approvedAppsToReadMaintainers = Array.isArray(approvedApps?.scopes?.read?.maintainers)
? approvedApps?.scopes?.read?.maintainers
: approvedApps?.scopes?.read?.maintainers?.split
? [...approvedApps.scopes.read.maintainers.split(',')]
: [];
const approvedAppsToReadJitConfirms = Array.isArray(approvedApps?.scopes?.read?.['jit/confirm'])
? approvedApps?.scopes?.read?.['jit/confirm']
: approvedApps?.scopes?.read?.['jit/confirm']?.split
? [...approvedApps.scopes.read['jit/confirm'].split(',')]
: [];
const microsoftPolicyServiceApiName = 'microsoft-github-policy-service';
const approvedAppsToReadPolicyService = parse(approvedApps?.scopes?.read?.[microsoftPolicyServiceApiName]);
const approvedOidsToReadPolicyService = parse(approvedOids?.scopes?.read?.[microsoftPolicyServiceApiName]);
const approvedOidsToCreateRepos = Array.isArray(approvedOids?.scopes?.create?.repos)
? approvedOids?.scopes?.create?.repos
: approvedOids?.scopes?.create?.repos?.split
? [...(approvedOids?.scopes?.create?.repos ? approvedOids.scopes.create.repos.split(',') : [])]
: [];
const approvedOidsToReadLinks = Array.isArray(approvedOids?.scopes?.read?.links)
? approvedOids?.scopes?.read?.links
: approvedOids?.scopes?.read?.links?.split
? [...(approvedOids?.scopes?.read?.links ? approvedOids.scopes.read.links.split(',') : [])]
: [];
const approvedOidsToReadJitConfirms = Array.isArray(approvedOids?.scopes?.read?.['jit/confirm'])
? approvedOids?.scopes?.read?.['jit/confirm']
: approvedOids?.scopes?.read?.['jit/confirm']?.split
? [...approvedOids.scopes.read['jit/confirm'].split(',')]
: [];
const oids = [
...approvedOidsToCreateRepos,
...approvedOidsToReadLinks,
...approvedOidsToReadJitConfirms,
...approvedOidsToReadPolicyService,
];
const appIds = [
// hacky temporary design for pulling from config
...approvedAppsToCreateRepos,
...approvedAppsToReadLinks,
...approvedAppsToReadMaintainers,
...approvedAppsToReadJitConfirms,
...approvedAppsToReadPolicyService,
];
return {
allowedTenants,
reposApiAudienceIdentities,
oids,
appIds,
approvedAppsToCreateRepos,
approvedAppsToReadLinks,
approvedAppsToReadMaintainers,
approvedOidsToCreateRepos,
approvedOidsToReadLinks,
approvedAppsToReadJitConfirms,
approvedOidsToReadJitConfirms,
approvedAppsToReadPolicyService,
approvedOidsToReadPolicyService,
};
}
function parse(val: string | string[]): string[] {
if (Array.isArray(val)) {
return val;
}
if (typeof val === 'string') {
return splitSemiColonCommas(val);
}
if (!val) {
return [];
}
throw CreateError.InvalidParameters('Invalid entries');
}
async function validateAadAuthorization(req: IApiRequest): Promise<void> {
const { config, insights } = getProviders(req);
const {
allowedTenants,
reposApiAudienceIdentities,
oids,
appIds,
approvedAppsToCreateRepos,
approvedAppsToReadLinks,
approvedAppsToReadMaintainers,
approvedOidsToCreateRepos,
approvedOidsToReadLinks,
approvedAppsToReadJitConfirms,
approvedOidsToReadJitConfirms,
approvedAppsToReadPolicyService,
approvedOidsToReadPolicyService,
} = getAadApiConfiguration(config);
const { insights } = getProviders(req);
const authorizationHeader = req.headers.authorization;
if (!authorizationHeader) {
@ -224,26 +88,31 @@ async function validateAadAuthorization(req: IApiRequest): Promise<void> {
properties: decodedToken as any,
});
const issuer = decodedToken['iss'] as string;
let isValidTenant = false;
for (let i = 0; isValidTenant === false && i < allowedTenants.length; i++) {
const tenant = allowedTenants[i];
const stsUrl = `https://sts.windows.net/${tenant}/`;
isValidTenant = issuer.startsWith(stsUrl); // support v1.0 or v2.0 as a result
const companySpecificDeployment = getCompanySpecificDeployment();
const aadApiValidator = companySpecificDeployment?.middleware?.authentication
?.getAadApiAuthenticationValidator
? companySpecificDeployment.middleware.authentication.getAadApiAuthenticationValidator(
getProviders(req)
)
: null;
if (!aadApiValidator) {
throw CreateError.InvalidParameters('No AAD API validator');
}
const issuer = decodedToken['iss'] as string;
const isValidTenant = aadApiValidator.isAuthorizedTenant(issuer);
// JWT steps:
// [X] aud: needs to match app ID
// [X] iss: guid portion is the tenant, confirm it's an approved issuer we want
// [X] nbr, exp times (jwt verifies this)
// [X] appid: the client app [*we check our list for this]
const validationOptions = {
audience: reposApiAudienceIdentities,
audience: await aadApiValidator.getAudienceIdentities(),
issuer,
};
const payload = await callJwtVerify(token, validationOptions);
// console.dir(payload);
if (!isValidTenant) {
throw wrapErrorForImmediateUserError(
@ -252,52 +121,30 @@ async function validateAadAuthorization(req: IApiRequest): Promise<void> {
}
const { appid, oid } = payload as any;
let approvedAppMonikerId = await aadApiValidator.getAuthorizedClientIdToken(appid);
if (!approvedAppMonikerId) {
approvedAppMonikerId = await aadApiValidator.getAuthorizedObjectIdToken(oid);
}
const scopes = [];
const isAppApproved = appIds.includes(appid);
const isOidApproved = oids.includes(oid);
const notAuthorized = isAppApproved === false && isOidApproved === false;
const notAuthorized = !approvedAppMonikerId;
if (notAuthorized) {
throw wrapErrorForImmediateUserError(
jsonError(`App ${appid} and object ID ${oid} is not authorized for this API endpoint`, 403)
);
}
if (isAppApproved && approvedAppsToCreateRepos.includes(appid)) {
scopes.push('createRepo');
}
if (isAppApproved && approvedAppsToReadLinks.includes(appid)) {
scopes.push('links');
}
if (isAppApproved && approvedAppsToReadMaintainers.includes(appid)) {
scopes.push('maintainers');
}
if (isAppApproved && approvedAppsToReadJitConfirms.includes(appid)) {
scopes.push('jit/confirm');
}
const policyServiceScopeName = 'microsoft-github-policy-service';
if (isAppApproved && approvedAppsToReadPolicyService.includes(appid)) {
scopes.push(policyServiceScopeName);
}
if (isOidApproved && approvedOidsToCreateRepos.includes(oid)) {
scopes.push('createRepo');
}
if (isOidApproved && approvedOidsToReadLinks.includes(oid)) {
scopes.push('links');
}
if (isOidApproved && approvedOidsToReadJitConfirms.includes(oid)) {
scopes.push('jit/confirm');
}
if (isOidApproved && approvedOidsToReadPolicyService.includes(appid)) {
scopes.push(policyServiceScopeName);
}
const apiToken = PersonalAccessToken.CreateFromAadAuthorization({
appId: appid,
oid,
scopes: scopes.join(','),
organizationScopes: '*',
});
const scopes = await aadApiValidator.getScopes(approvedAppMonikerId);
const displayValues = await aadApiValidator.getDisplayValues(approvedAppMonikerId);
const apiToken = PersonalAccessToken.CreateFromAadAuthorization(
{
appId: appid,
oid,
scopes: scopes.join(','),
organizationScopes: '*',
},
displayValues
);
req.apiKeyToken = apiToken;
req.apiKeyProviderName = 'aad';
insights?.trackEvent({

Просмотреть файл

@ -9,7 +9,12 @@ import Debug from 'debug';
const debug = Debug.debug('user');
import { getProviders } from '../../transitional';
import { ICorporateIdentity, IGitHubIdentity, IndividualContext, GitHubIdentitySource } from '../../user';
import {
ICorporateIdentity,
IGitHubIdentity,
IndividualContext,
GitHubIdentitySource,
} from '../../business/user';
import { storeOriginalUrlAsReferrer } from '../../utils';
import getCompanySpecificDeployment from '../companySpecificDeployment';

Просмотреть файл

@ -8,7 +8,7 @@
import { ReposAppRequest } from '../../interfaces';
import { getProviders } from '../../transitional';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { wrapError } from '../../utils';
import { jsonError } from '../jsonError';

Просмотреть файл

@ -6,7 +6,7 @@
import { jsonError } from '..';
import { IProviders, ReposAppRequest } from '../../interfaces';
import { getProviders } from '../../transitional';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
const cachedCorporateAliasRequestKey = '__corporateAlias';

Просмотреть файл

@ -7,7 +7,7 @@ import { jsonError } from '..';
import { IProviders, ReposAppRequest } from '../../interfaces';
import { IGraphEntry } from '../../lib/graphProvider';
import { getProviders } from '../../transitional';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
const cachedCorporateHierarchyRequestKey = '__corporateTree';

Просмотреть файл

@ -6,7 +6,7 @@
import { jsonError } from '..';
import { IProviders, ReposAppRequest } from '../../interfaces';
import { getProviders } from '../../transitional';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
const cachedCorporateMailRequestKey = '__corporateMail';

Просмотреть файл

@ -10,7 +10,7 @@ import {
WebContext,
SessionUserProperties,
WebApiContext,
} from '../../user';
} from '../../business/user';
import { getProviders } from '../../transitional';
export function webContextMiddleware(req, res, next) {

Просмотреть файл

@ -5,7 +5,7 @@
import { ErrorHelper, getProviders } from '../../transitional';
import { Repository } from '../../business/repository';
import { GitHubIdentitySource, IIndividualContextOptions, IndividualContext } from '../../user';
import { GitHubIdentitySource, IIndividualContextOptions, IndividualContext } from '../../business/user';
import getCompanySpecificDeployment from '../companySpecificDeployment';
import {
ReposAppRequest,

Просмотреть файл

@ -11,7 +11,7 @@ import {
ReposAppRequest,
} from '../../interfaces';
import { getProviders } from '../../transitional';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import getCompanySpecificDeployment from '../companySpecificDeployment';
// --- team2 context

Просмотреть файл

@ -33,15 +33,18 @@ import routeLogger from './logger';
import routeLocals from './locals';
import routePassport from './passport-routes';
import { IProviders, SiteConfiguration } from '../interfaces';
import routeApi from '../api';
import { IProviders, IReposApplication, SiteConfiguration } from '../interfaces';
import { codespacesDevAssistant } from './codespaces';
export default async function initMiddleware(
app,
app: IReposApplication,
express,
config: SiteConfiguration,
dirname,
initializationError
dirname: string,
hasCustomRoutes: boolean,
initializationError: Error
) {
config = config || ({} as SiteConfiguration);
const appDirectory =
@ -88,6 +91,9 @@ export default async function initMiddleware(
app.enable('trust proxy');
debug('proxy: trusting reverse proxy');
}
if (!hasCustomRoutes) {
app.use('/api', routeApi);
}
if (applicationProfile.sessions) {
app.use(await connectSession(app, config, providers));
try {

Просмотреть файл

@ -339,6 +339,9 @@ export default async function initialize(
if (!config || Object.getOwnPropertyNames(config).length === 0) {
throw new Error('Empty configuration object');
}
if (!app.runtimeConfiguration) {
app.runtimeConfiguration = {};
}
const applicationProfile =
config?.web?.app && config.web.app !== 'repos'
? await alternateRoutes(config, app, config.web.app)
@ -453,14 +456,15 @@ export default async function initialize(
exception = initializeError;
}
}
const hasCustomRoutes = !!applicationProfile.customRoutes;
try {
await middlewareIndex(app, express, config, rootdir, exception);
await middlewareIndex(app, express, config, rootdir, hasCustomRoutes, exception);
} catch (middlewareError) {
exception = middlewareError;
}
// ROUTES:
if (!exception) {
if (applicationProfile.customRoutes) {
if (hasCustomRoutes) {
await applicationProfile.customRoutes();
} else {
app.use('/', expressRoutes);

Просмотреть файл

@ -5,7 +5,7 @@
// Within the context, tries to resolve a link if it _can_. It does not force that a user is linked!
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { getProviders } from '../../transitional';
import { wrapError } from '../../utils';
import { ReposAppRequest, IReposError } from '../../interfaces';

Просмотреть файл

@ -11,7 +11,9 @@ import createAADStrategy from './passport/aadStrategy';
import createGithubStrategy from './passport/githubStrategy';
import serializer from './passport/serializer';
export default function (app, config) {
import type { IReposApplication, ReposAppRequest, SiteConfiguration } from '../interfaces';
export default function (app: IReposApplication, config: SiteConfiguration) {
const supportedAuth = ['github', 'aad', 'oauth2'];
if (!supportedAuth.includes(config.authentication.scheme)) {
@ -49,12 +51,12 @@ export default function (app, config) {
}
}
if (config.authentication.scheme == 'aad') {
if (config.authentication.scheme === 'aad') {
const aadStrategies = createAADStrategy(app, config);
for (const name in aadStrategies) {
passport.use(name, aadStrategies[name]);
}
} else if (config.authentication.scheme == 'oauth2') {
} else if (config.authentication.scheme === 'oauth2') {
// Set up oauth2 strategy here
throw new Error('oauth2 is not currently implemented');
}
@ -71,15 +73,9 @@ export default function (app, config) {
passport.deserializeUser(serializer.deserialize(serializerOptions));
serializer.initialize(serializerOptions, app);
app.use((req, res, next) => {
if (
req.insights &&
req.insights.properties &&
config.authentication.scheme === 'aad' &&
req.user &&
req.user.azure
) {
req.insights.properties.aadId = req.user.azure.oid;
app.use((req: ReposAppRequest, res, next) => {
if (req?.insights?.commonProperties && config.authentication.scheme === 'aad' && req?.user?.azure?.oid) {
req.insights.commonProperties.aadId = req.user.azure.oid;
}
next();
});

Просмотреть файл

@ -12,7 +12,7 @@ import appPackage from '../package.json';
import { getStaticBlobCacheFallback } from '../lib/staticBlobCacheFallback';
import { getProviders, splitSemiColonCommas } from '../transitional';
import { ReposAppRequest } from '../interfaces';
import { IndividualContext } from '../user';
import { IndividualContext } from '../business/user';
const staticReactPackageNameKey = 'static-react-package-name';
const staticClientPackageName = appPackage[staticReactPackageNameKey];

Просмотреть файл

@ -3,10 +3,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
import { CreateError, hasStaticReactClientApp } from '../transitional';
import { hasStaticReactClientApp } from '../transitional';
import appPackage from '../package.json';
import { ReposAppRequest } from '../interfaces';
import type { IReposApplication, SiteConfiguration } from '../interfaces';
const packageVariableName = 'static-react-package-name';
const otherPackageVariableName = 'static-client-package-name';
@ -17,7 +18,23 @@ const staticClientFlightingPackageName = appPackage[staticReactFlightingPackageN
import Debug from 'debug';
const debug = Debug.debug('startup');
export function StaticReactClientApp(app, express, config: any) {
export type RuntimeConfigurationClient = {
packageName?: string;
packageVersion?: string;
flighting?: {
packageName: string;
packageVersion: string;
};
};
export type RootRuntimeConfigurationClient = {
client?: RuntimeConfigurationClient;
};
export function StaticReactClientApp(app: IReposApplication, express, config: SiteConfiguration) {
const clientRuntimeConfiguration: RuntimeConfigurationClient = {};
app.runtimeConfiguration.client = clientRuntimeConfiguration;
// Serve/host the static client app from the location reported by the private
// NPM module for the React app. Assumes that the inclusion of the package
// returns the path to host.
@ -39,6 +56,8 @@ export function StaticReactClientApp(app, express, config: any) {
const clientPackage = require(`${staticClientPackageName}/package.json`);
debug(`Hosting React client version ${clientPackage.version} from ${clientDistPath}`);
app.use('/', express.static(clientDistPath));
clientRuntimeConfiguration.packageName = staticClientPackageName;
clientRuntimeConfiguration.packageVersion = clientPackage.version;
} catch (hostClientError) {
console.error(`The React client could not be loaded via package ${staticClientPackageName}`);
throw hostClientError;
@ -56,6 +75,10 @@ export function StaticReactClientApp(app, express, config: any) {
const clientPackage = require(`${staticClientFlightingPackageName}/package.json`);
debug(`Hosting flighting React client version ${clientPackage.version} from ${clientDistPath}`);
app.use('/', express.static(clientDistPath));
clientRuntimeConfiguration.flighting = {
packageName: staticClientFlightingPackageName,
packageVersion: clientPackage.version,
};
} catch (hostClientError) {
console.error(`The flighting React client could not be loaded via package ${staticClientPackageName}`);
throw hostClientError;

320
package-lock.json сгенерированный
Просмотреть файл

@ -11,7 +11,7 @@
"dependencies": {
"@azure/cosmos": "3.17.3",
"@azure/data-tables": "13.2.2",
"@azure/identity": "3.1.4",
"@azure/identity": "3.2.0",
"@azure/keyvault-secrets": "4.7.0",
"@azure/service-bus": "7.9.0",
"@azure/storage-blob": "12.14.0",
@ -50,7 +50,7 @@
"moment": "2.29.4",
"morgan": "1.10.0",
"node-jose": "2.2.0",
"nodemailer": "6.9.1",
"nodemailer": "6.9.2",
"object-path": "0.11.8",
"octicons": "5.0.1",
"passport": "0.6.0",
@ -80,7 +80,7 @@
"@types/luxon": "3.3.0",
"@types/memory-cache": "0.2.2",
"@types/morgan": "1.9.4",
"@types/node": "18.16.3",
"@types/node": "20.1.2",
"@types/node-jose": "1.1.10",
"@types/object-path": "0.11.1",
"@types/passport": "1.0.12",
@ -89,13 +89,13 @@
"@types/pg": "8.6.6",
"@types/pug": "2.0.6",
"@types/recursive-readdir": "2.2.1",
"@types/semver": "7.3.13",
"@types/semver": "7.5.0",
"@types/simple-oauth2": "5.0.4",
"@types/validator": "13.7.15",
"@typescript-eslint/eslint-plugin": "5.59.2",
"@typescript-eslint/parser": "5.59.2",
"@types/validator": "13.7.17",
"@typescript-eslint/eslint-plugin": "5.59.5",
"@typescript-eslint/parser": "5.59.5",
"cspell": "6.31.1",
"eslint": "8.39.0",
"eslint": "8.40.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-n": "15.7.0",
"eslint-plugin-prettier": "4.2.1",
@ -359,9 +359,9 @@
}
},
"node_modules/@azure/identity": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/@azure/identity/-/identity-3.1.4.tgz",
"integrity": "sha512-USvxmO6p7dFEcz1e0Kq/WQY6YbvX8hOeIibxxLBQC4Pxl4QK+DL72agZ9e5RYZc55QjC7Ja6q1+mQaXfmbrLhA==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@azure/identity/-/identity-3.2.0.tgz",
"integrity": "sha512-WgJRnIweTUJn+h34xomlgbG5/5pwoQ0aBA5gbUtZPFx/UDKsrIZylI+uH++OjLkgyjT4FzLfms048+t+goUo6g==",
"dependencies": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
@ -1566,14 +1566,14 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz",
"integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
"integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.5.1",
"espree": "^9.5.2",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
@ -1589,9 +1589,9 @@
}
},
"node_modules/@eslint/js": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz",
"integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz",
"integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -2871,9 +2871,9 @@
"dev": true
},
"node_modules/@types/node": {
"version": "18.16.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
"version": "20.1.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz",
"integrity": "sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g=="
},
"node_modules/@types/node-fetch": {
"version": "2.6.2",
@ -3005,9 +3005,9 @@
}
},
"node_modules/@types/semver": {
"version": "7.3.13",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
"integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
"dev": true
},
"node_modules/@types/serve-static": {
@ -3040,9 +3040,9 @@
}
},
"node_modules/@types/validator": {
"version": "13.7.15",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.15.tgz",
"integrity": "sha512-yeinDVQunb03AEP8luErFcyf/7Lf7AzKCD0NXfgVoGCCQDNpZET8Jgq74oBgqKld3hafLbfzt/3inUdQvaFeXQ==",
"version": "13.7.17",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.17.tgz",
"integrity": "sha512-aqayTNmeWrZcvnG2MG9eGYI6b7S5fl+yKgPs6bAjOTwPS316R5SxBGKvtSExfyoJU7pIeHJfsHI0Ji41RVMkvQ==",
"dev": true
},
"node_modules/@types/yargs": {
@ -3061,15 +3061,15 @@
"dev": true
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz",
"integrity": "sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz",
"integrity": "sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/type-utils": "5.59.2",
"@typescript-eslint/utils": "5.59.2",
"@typescript-eslint/scope-manager": "5.59.5",
"@typescript-eslint/type-utils": "5.59.5",
"@typescript-eslint/utils": "5.59.5",
"debug": "^4.3.4",
"grapheme-splitter": "^1.0.4",
"ignore": "^5.2.0",
@ -3095,14 +3095,14 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz",
"integrity": "sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz",
"integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.2",
"@typescript-eslint/scope-manager": "5.59.5",
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/typescript-estree": "5.59.5",
"debug": "^4.3.4"
},
"engines": {
@ -3122,13 +3122,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz",
"integrity": "sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz",
"integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2"
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/visitor-keys": "5.59.5"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -3139,13 +3139,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz",
"integrity": "sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz",
"integrity": "sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "5.59.2",
"@typescript-eslint/utils": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.5",
"@typescript-eslint/utils": "5.59.5",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
},
@ -3166,9 +3166,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz",
"integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz",
"integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -3179,13 +3179,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz",
"integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz",
"integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2",
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/visitor-keys": "5.59.5",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -3206,17 +3206,17 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz",
"integrity": "sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.5.tgz",
"integrity": "sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.2",
"@typescript-eslint/scope-manager": "5.59.5",
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/typescript-estree": "5.59.5",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
},
@ -3232,12 +3232,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz",
"integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz",
"integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/types": "5.59.5",
"eslint-visitor-keys": "^3.3.0"
},
"engines": {
@ -4886,15 +4886,15 @@
}
},
"node_modules/eslint": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz",
"integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz",
"integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.2",
"@eslint/js": "8.39.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.40.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@ -4905,8 +4905,8 @@
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.0",
"eslint-visitor-keys": "^3.4.0",
"espree": "^9.5.1",
"eslint-visitor-keys": "^3.4.1",
"espree": "^9.5.2",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@ -5084,9 +5084,9 @@
}
},
"node_modules/eslint-visitor-keys": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
"integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
"integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
"dev": true,
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -5121,14 +5121,14 @@
}
},
"node_modules/espree": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
"integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
"version": "9.5.2",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
"integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
"dev": true,
"dependencies": {
"acorn": "^8.8.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.0"
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@ -8297,9 +8297,9 @@
"dev": true
},
"node_modules/nodemailer": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.1.tgz",
"integrity": "sha512-qHw7dOiU5UKNnQpXktdgQ1d3OFgRAekuvbJLcdG5dnEo/GtcTHRYM7+UfJARdOFU9WUQO8OiIamgWPmiSFHYAA==",
"version": "6.9.2",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.2.tgz",
"integrity": "sha512-4+TYaa/e1nIxQfyw/WzNPYTEZ5OvHIDEnmjs4LPmIfccPQN+2CYKmGHjWixn/chzD3bmUTu5FMfpltizMxqzdg==",
"engines": {
"node": ">=6.0.0"
}
@ -10854,9 +10854,9 @@
}
},
"@azure/identity": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/@azure/identity/-/identity-3.1.4.tgz",
"integrity": "sha512-USvxmO6p7dFEcz1e0Kq/WQY6YbvX8hOeIibxxLBQC4Pxl4QK+DL72agZ9e5RYZc55QjC7Ja6q1+mQaXfmbrLhA==",
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/@azure/identity/-/identity-3.2.0.tgz",
"integrity": "sha512-WgJRnIweTUJn+h34xomlgbG5/5pwoQ0aBA5gbUtZPFx/UDKsrIZylI+uH++OjLkgyjT4FzLfms048+t+goUo6g==",
"requires": {
"@azure/abort-controller": "^1.0.0",
"@azure/core-auth": "^1.3.0",
@ -11857,14 +11857,14 @@
"dev": true
},
"@eslint/eslintrc": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz",
"integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz",
"integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==",
"dev": true,
"requires": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
"espree": "^9.5.1",
"espree": "^9.5.2",
"globals": "^13.19.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
@ -11874,9 +11874,9 @@
}
},
"@eslint/js": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz",
"integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz",
"integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==",
"dev": true
},
"@hapi/boom": {
@ -12960,9 +12960,9 @@
"dev": true
},
"@types/node": {
"version": "18.16.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.3.tgz",
"integrity": "sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q=="
"version": "20.1.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz",
"integrity": "sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g=="
},
"@types/node-fetch": {
"version": "2.6.2",
@ -13093,9 +13093,9 @@
}
},
"@types/semver": {
"version": "7.3.13",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==",
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz",
"integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==",
"dev": true
},
"@types/serve-static": {
@ -13128,9 +13128,9 @@
}
},
"@types/validator": {
"version": "13.7.15",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.15.tgz",
"integrity": "sha512-yeinDVQunb03AEP8luErFcyf/7Lf7AzKCD0NXfgVoGCCQDNpZET8Jgq74oBgqKld3hafLbfzt/3inUdQvaFeXQ==",
"version": "13.7.17",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.17.tgz",
"integrity": "sha512-aqayTNmeWrZcvnG2MG9eGYI6b7S5fl+yKgPs6bAjOTwPS316R5SxBGKvtSExfyoJU7pIeHJfsHI0Ji41RVMkvQ==",
"dev": true
},
"@types/yargs": {
@ -13149,15 +13149,15 @@
"dev": true
},
"@typescript-eslint/eslint-plugin": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.2.tgz",
"integrity": "sha512-yVrXupeHjRxLDcPKL10sGQ/QlVrA8J5IYOEWVqk0lJaSZP7X5DfnP7Ns3cc74/blmbipQ1htFNVGsHX6wsYm0A==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.5.tgz",
"integrity": "sha512-feA9xbVRWJZor+AnLNAr7A8JRWeZqHUf4T9tlP+TN04b05pFVhO5eN7/O93Y/1OUlLMHKbnJisgDURs/qvtqdg==",
"dev": true,
"requires": {
"@eslint-community/regexpp": "^4.4.0",
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/type-utils": "5.59.2",
"@typescript-eslint/utils": "5.59.2",
"@typescript-eslint/scope-manager": "5.59.5",
"@typescript-eslint/type-utils": "5.59.5",
"@typescript-eslint/utils": "5.59.5",
"debug": "^4.3.4",
"grapheme-splitter": "^1.0.4",
"ignore": "^5.2.0",
@ -13167,53 +13167,53 @@
}
},
"@typescript-eslint/parser": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.2.tgz",
"integrity": "sha512-uq0sKyw6ao1iFOZZGk9F8Nro/8+gfB5ezl1cA06SrqbgJAt0SRoFhb9pXaHvkrxUpZaoLxt8KlovHNk8Gp6/HQ==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz",
"integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==",
"dev": true,
"requires": {
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.2",
"@typescript-eslint/scope-manager": "5.59.5",
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/typescript-estree": "5.59.5",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.2.tgz",
"integrity": "sha512-dB1v7ROySwQWKqQ8rEWcdbTsFjh2G0vn8KUyvTXdPoyzSL6lLGkiXEV5CvpJsEe9xIdKV+8Zqb7wif2issoOFA==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz",
"integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2"
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/visitor-keys": "5.59.5"
}
},
"@typescript-eslint/type-utils": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.2.tgz",
"integrity": "sha512-b1LS2phBOsEy/T381bxkkywfQXkV1dWda/z0PhnIy3bC5+rQWQDS7fk9CSpcXBccPY27Z6vBEuaPBCKCgYezyQ==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.5.tgz",
"integrity": "sha512-4eyhS7oGym67/pSxA2mmNq7X164oqDYNnZCUayBwJZIRVvKpBCMBzFnFxjeoDeShjtO6RQBHBuwybuX3POnDqg==",
"dev": true,
"requires": {
"@typescript-eslint/typescript-estree": "5.59.2",
"@typescript-eslint/utils": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.5",
"@typescript-eslint/utils": "5.59.5",
"debug": "^4.3.4",
"tsutils": "^3.21.0"
}
},
"@typescript-eslint/types": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.2.tgz",
"integrity": "sha512-LbJ/HqoVs2XTGq5shkiKaNTuVv5tTejdHgfdjqRUGdYhjW1crm/M7og2jhVskMt8/4wS3T1+PfFvL1K3wqYj4w==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz",
"integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.2.tgz",
"integrity": "sha512-+j4SmbwVmZsQ9jEyBMgpuBD0rKwi9RxRpjX71Brr73RsYnEr3Lt5QZ624Bxphp8HUkSKfqGnPJp1kA5nl0Sh7Q==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz",
"integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/visitor-keys": "5.59.2",
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/visitor-keys": "5.59.5",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
@ -13222,28 +13222,28 @@
}
},
"@typescript-eslint/utils": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.2.tgz",
"integrity": "sha512-kSuF6/77TZzyGPhGO4uVp+f0SBoYxCDf+lW3GKhtKru/L8k/Hd7NFQxyWUeY7Z/KGB2C6Fe3yf2vVi4V9TsCSQ==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.5.tgz",
"integrity": "sha512-sCEHOiw+RbyTii9c3/qN74hYDPNORb8yWCoPLmB7BIflhplJ65u2PBpdRla12e3SSTJ2erRkPjz7ngLHhUegxA==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@types/json-schema": "^7.0.9",
"@types/semver": "^7.3.12",
"@typescript-eslint/scope-manager": "5.59.2",
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/typescript-estree": "5.59.2",
"@typescript-eslint/scope-manager": "5.59.5",
"@typescript-eslint/types": "5.59.5",
"@typescript-eslint/typescript-estree": "5.59.5",
"eslint-scope": "^5.1.1",
"semver": "^7.3.7"
}
},
"@typescript-eslint/visitor-keys": {
"version": "5.59.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.2.tgz",
"integrity": "sha512-EEpsO8m3RASrKAHI9jpavNv9NlEUebV4qmF1OWxSTtKSFBpC1NCmWazDQHFivRf0O1DV11BA645yrLEVQ0/Lig==",
"version": "5.59.5",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz",
"integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==",
"dev": true,
"requires": {
"@typescript-eslint/types": "5.59.2",
"@typescript-eslint/types": "5.59.5",
"eslint-visitor-keys": "^3.3.0"
}
},
@ -14476,15 +14476,15 @@
"dev": true
},
"eslint": {
"version": "8.39.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz",
"integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==",
"version": "8.40.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz",
"integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.4.0",
"@eslint/eslintrc": "^2.0.2",
"@eslint/js": "8.39.0",
"@eslint/eslintrc": "^2.0.3",
"@eslint/js": "8.40.0",
"@humanwhocodes/config-array": "^0.11.8",
"@humanwhocodes/module-importer": "^1.0.1",
"@nodelib/fs.walk": "^1.2.8",
@ -14495,8 +14495,8 @@
"doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
"eslint-scope": "^7.2.0",
"eslint-visitor-keys": "^3.4.0",
"espree": "^9.5.1",
"eslint-visitor-keys": "^3.4.1",
"espree": "^9.5.2",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
@ -14628,20 +14628,20 @@
}
},
"eslint-visitor-keys": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
"integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
"integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
"dev": true
},
"espree": {
"version": "9.5.1",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
"integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
"version": "9.5.2",
"resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz",
"integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==",
"dev": true,
"requires": {
"acorn": "^8.8.0",
"acorn-jsx": "^5.3.2",
"eslint-visitor-keys": "^3.4.0"
"eslint-visitor-keys": "^3.4.1"
}
},
"esprima": {
@ -16997,9 +16997,9 @@
"dev": true
},
"nodemailer": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.1.tgz",
"integrity": "sha512-qHw7dOiU5UKNnQpXktdgQ1d3OFgRAekuvbJLcdG5dnEo/GtcTHRYM7+UfJARdOFU9WUQO8OiIamgWPmiSFHYAA=="
"version": "6.9.2",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.2.tgz",
"integrity": "sha512-4+TYaa/e1nIxQfyw/WzNPYTEZ5OvHIDEnmjs4LPmIfccPQN+2CYKmGHjWixn/chzD3bmUTu5FMfpltizMxqzdg=="
},
"normalize-path": {
"version": "3.0.0",

Просмотреть файл

@ -66,7 +66,7 @@
"dependencies": {
"@azure/cosmos": "3.17.3",
"@azure/data-tables": "13.2.2",
"@azure/identity": "3.1.4",
"@azure/identity": "3.2.0",
"@azure/keyvault-secrets": "4.7.0",
"@azure/service-bus": "7.9.0",
"@azure/storage-blob": "12.14.0",
@ -105,7 +105,7 @@
"moment": "2.29.4",
"morgan": "1.10.0",
"node-jose": "2.2.0",
"nodemailer": "6.9.1",
"nodemailer": "6.9.2",
"object-path": "0.11.8",
"octicons": "5.0.1",
"passport": "0.6.0",
@ -135,7 +135,7 @@
"@types/luxon": "3.3.0",
"@types/memory-cache": "0.2.2",
"@types/morgan": "1.9.4",
"@types/node": "18.16.3",
"@types/node": "20.1.2",
"@types/node-jose": "1.1.10",
"@types/object-path": "0.11.1",
"@types/passport": "1.0.12",
@ -144,13 +144,13 @@
"@types/pg": "8.6.6",
"@types/pug": "2.0.6",
"@types/recursive-readdir": "2.2.1",
"@types/semver": "7.3.13",
"@types/semver": "7.5.0",
"@types/simple-oauth2": "5.0.4",
"@types/validator": "13.7.15",
"@typescript-eslint/eslint-plugin": "5.59.2",
"@typescript-eslint/parser": "5.59.2",
"@types/validator": "13.7.17",
"@typescript-eslint/eslint-plugin": "5.59.5",
"@typescript-eslint/parser": "5.59.5",
"cspell": "6.31.1",
"eslint": "8.39.0",
"eslint": "8.40.0",
"eslint-config-prettier": "8.8.0",
"eslint-plugin-n": "15.7.0",
"eslint-plugin-prettier": "4.2.1",

Просмотреть файл

@ -13,7 +13,7 @@ import {
IBasicGitHubAppInstallation,
SpecialTeam,
} from '../../entities/organizationSettings/organizationSetting';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { Operations, Organization } from '../../business';
import GitHubApplication from '../../business/application';
import {

Просмотреть файл

@ -8,7 +8,7 @@ import asyncHandler from 'express-async-handler';
const router: Router = Router();
import { CreateError, hasStaticReactClientApp, getProviders } from '../transitional';
import { IndividualContext } from '../user';
import { IndividualContext } from '../business/user';
import { storeOriginalUrlAsVariable } from '../utils';
import { AuthorizeOnlyCorporateAdministrators } from '../middleware/business/corporateAdministrators';

Просмотреть файл

@ -8,11 +8,7 @@ const router: Router = Router();
import { webContextMiddleware } from '../middleware/business/setContext';
import ApiRoute from '../api';
router.use('/api', ApiRoute);
router.use(webContextMiddleware);
import clientApiRoute from '../api/client';
import ThanksRoute from './thanks';
import MyInfoRoute from './diagnostics';
@ -20,12 +16,16 @@ import ExploreRoute from './explore';
import ApprovalsRoute from './approvals';
import AuthenticatedRoute from './index-authenticated';
router.use('/thanks', ThanksRoute);
router.use('/myinfo', MyInfoRoute);
import { hasStaticReactClientApp } from '../transitional';
import { injectReactClient } from '../middleware';
router.use('/api/client', clientApiRoute);
router.use(webContextMiddleware);
router.use('/thanks', ThanksRoute);
router.use('/myinfo', MyInfoRoute);
const hasReactApp = hasStaticReactClientApp();
const reactRoute = hasReactApp ? injectReactClient() : undefined;
router.use('/approvals', reactRoute || ApprovalsRoute); // redirects into settings for site users

Просмотреть файл

@ -15,7 +15,7 @@ import {
LinkOperationSource,
} from '../interfaces';
import { getProviders, splitSemiColonCommas } from '../transitional';
import { IndividualContext } from '../user';
import { IndividualContext } from '../business/user';
import { isCodespacesAuthenticating, storeOriginalUrlAsReferrer, wrapError } from '../utils';
import validator from 'validator';

Просмотреть файл

@ -8,7 +8,7 @@ import asyncHandler from 'express-async-handler';
const router: Router = Router();
import { getProviders } from '../../transitional';
import { IAggregateUserSummary } from '../../user/aggregate';
import { IAggregateUserSummary } from '../../business/user/aggregate';
import { TeamJoinApprovalEntity } from '../../entities/teamJoinApproval/teamJoinApproval';
import { Team } from '../../business';
import { ReposAppRequest, OrganizationMembershipState } from '../../interfaces';

Просмотреть файл

@ -12,7 +12,7 @@ const router: Router = Router();
import querystring from 'querystring';
import { CreateError, getProviders } from '../../transitional';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { sleep, storeOriginalUrlAsReferrer, wrapError } from '../../utils';
import RequireActiveGitHubSession from '../../middleware/github/requireActiveSession';
import { jsonError } from '../../middleware/jsonError';

Просмотреть файл

@ -16,7 +16,7 @@ import routeAdministrativeLock from './repoAdministrativeLock';
import NewRepositoryLockdownSystem from '../../features/newRepositories/newRepositoryLockdown';
import { IGraphEntry } from '../../lib/graphProvider';
import { IMail } from '../../lib/mailProvider';
import { IndividualContext } from '../../user';
import { IndividualContext } from '../../business/user';
import { Repository, Collaborator, TeamPermission, Organization, OrganizationMember } from '../../business';
import { RepositoryMetadataEntity } from '../../entities/repositoryMetadata/repositoryMetadata';

Просмотреть файл

@ -11,7 +11,7 @@ import { ErrorHelper, getProviders } from '../../../../transitional';
import { Team } from '../../../../business';
import { PermissionWorkflowEngine } from '../approvals';
import RenderHtmlMail from '../../../../lib/emailRender';
import { IndividualContext } from '../../../../user';
import { IndividualContext } from '../../../../business/user';
import { ReposAppRequest, UserAlertType, IProviders } from '../../../../interfaces';
interface ILocalRequest extends ReposAppRequest {

Просмотреть файл

@ -24,7 +24,7 @@ import lowercaser from '../../../middleware/lowercaser';
import RouteMaintainer from './index-maintainer';
import { Operations, Organization, Repository, Team, TeamMember } from '../../../business';
import { IndividualContext } from '../../../user';
import { IndividualContext } from '../../../business/user';
import {
ReposAppRequest,
GitHubTeamRole,

Просмотреть файл

@ -21,7 +21,7 @@ import QueryCache from '../business/queryCache';
import { GitHubRepositoryType, IReposAppWithTeam } from '../interfaces';
import { IRequestTeamPermissions } from '../middleware/github/teamPermissions';
import { getProviders } from '../transitional';
import { UserContext } from '../user/aggregate';
import { UserContext } from '../business/user/aggregate';
interface IGetReposAndOptionalTeamPermissionsResponse {
reposData: Repository[];

Просмотреть файл

@ -13,7 +13,7 @@ import { safeLocalRedirectUrl } from '../../utils';
import { Operations } from '../../business';
import { Team } from '../../business';
import { Organization } from '../../business';
import { IAggregateUserTeams } from '../../user/aggregate';
import { IAggregateUserTeams } from '../../business/user/aggregate';
import { ReposAppRequest, IReposError, UserAlertType } from '../../interfaces';
import { getProviders } from '../../transitional';

Просмотреть файл

@ -10,7 +10,7 @@ import { NextFunction, Response } from 'express';
import { getProviders } from '../transitional';
import { Operations } from '../business';
import { Team } from '../business';
import { UserContext } from '../user/aggregate';
import { UserContext } from '../business/user/aggregate';
import TeamSearch from '../business/teamSearch';
import { ICrossOrganizationMembershipByOrganization, ReposAppRequest } from '../interfaces';

Просмотреть файл

@ -12,7 +12,7 @@ import { ErrorHelper, getProviders } from '../transitional';
import { AuditLogRecord } from '../entities/auditLogRecord/auditLogRecord';
import { daysInMilliseconds } from '../utils';
import { AuditEvents } from '../entities/auditLogRecord';
import { IGitHubIdentity, IndividualContext } from '../user';
import { IGitHubIdentity, IndividualContext } from '../business/user';
import { IMail } from '../lib/mailProvider';
import { GitHubRepositoryPermission, ReposAppRequest, UserAlertType } from '../interfaces';

Просмотреть файл

@ -9,7 +9,7 @@ const router: Router = Router();
import { getProviders } from '../transitional';
import { wrapError } from '../utils';
import { IndividualContext } from '../user';
import { IndividualContext } from '../business/user';
import { jsonError } from '../middleware';
import { ReposAppRequest, OrganizationMembershipState, UnlinkPurpose } from '../interfaces';

Просмотреть файл

@ -133,7 +133,7 @@ export class CreateError {
return error;
}
static NotFound(message: string, innerError?: Error): Error {
static NotFound(message?: string, innerError?: Error): Error {
return ErrorHelper.SetInnerError(CreateError.CreateStatusCodeError(404, message), innerError);
}

Просмотреть файл

@ -24,7 +24,6 @@
"./data/**/*",
"./entities/**/*",
"./features/**/*",
"./github/**/*",
"./interfaces/**/*",
"./jobs/**/*",
"./lib/**/*",
@ -33,7 +32,6 @@
"./routes/**/*",
"./scripts/**/*",
"./test/**/*",
"./user/**/*",
"./webhooks/**/*"
]
}