From b662c9ed354f940a9662eaa8eae8007a81f7f027 Mon Sep 17 00:00:00 2001 From: Maksadbek Akhmedov Date: Mon, 24 Jun 2024 11:10:09 +0500 Subject: [PATCH] feat: add get-entrypoints command --- src/Commands/GetEntryPoints.ts | 52 +++++++++++++++++++++++++ src/Commands/index.ts | 1 + src/Config/container.ts | 6 +++ src/EntryPoint/EntryPoints.ts | 10 +++++ src/EntryPoint/RestEntryPoints.ts | 63 +++++++++++++++++++++++++++++++ src/EntryPoint/index.ts | 2 + src/index.ts | 6 ++- 7 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 src/Commands/GetEntryPoints.ts create mode 100644 src/EntryPoint/EntryPoints.ts create mode 100644 src/EntryPoint/RestEntryPoints.ts create mode 100644 src/EntryPoint/index.ts diff --git a/src/Commands/GetEntryPoints.ts b/src/Commands/GetEntryPoints.ts new file mode 100644 index 00000000..822df1b3 --- /dev/null +++ b/src/Commands/GetEntryPoints.ts @@ -0,0 +1,52 @@ +import { EntryPoint, EntryPoints, RestProjectsOptions } from '../EntryPoint'; +import { logger } from '../Utils'; +import { Arguments, Argv, CommandModule } from 'yargs'; +import { container } from 'tsyringe'; + +export class GetEntryPoints implements CommandModule { + public readonly command = 'get-entrypoints [options]'; + public readonly describe = 'get all entrypoints of the project.'; + + public builder(argv: Argv): Argv { + return argv + .option('token', { + alias: 't', + describe: 'Bright API-key', + requiresArg: true, + demandOption: true + }) + .option('project', { + alias: 'p', + describe: 'ID of the project', + requiresArg: true, + demandOption: true + }) + .middleware((args: Arguments) => + container.register(RestProjectsOptions, { + useValue: { + insecure: args.insecure as boolean, + baseURL: args.api as string, + apiKey: args.token as string, + proxyURL: (args.proxyExternal ?? args.proxy) as string + } + }) + ); + } + + public async handler(args: Arguments): Promise { + const entryPointsManager: EntryPoints = container.resolve(EntryPoints); + + try { + const entryPoints: EntryPoint[] = await entryPointsManager.entrypoints( + args.project as string + ); + + // eslint-disable-next-line no-console + console.log(entryPoints); + process.exit(0); + } catch (e) { + logger.error(`Error during "get-entrypoints": ${e.error || e.message}`); + process.exit(1); + } + } +} diff --git a/src/Commands/index.ts b/src/Commands/index.ts index 02b3e5d8..0dc609bf 100644 --- a/src/Commands/index.ts +++ b/src/Commands/index.ts @@ -6,3 +6,4 @@ export { StopScan } from './StopScan'; export { PollingScanStatus } from './PollingScanStatus'; export { RunRepeater } from './RunRepeater'; export { Configure } from './Configure'; +export { GetEntryPoints } from './GetEntryPoints'; diff --git a/src/Config/container.ts b/src/Config/container.ts index 52506ea6..8c769656 100644 --- a/src/Config/container.ts +++ b/src/Config/container.ts @@ -34,6 +34,7 @@ import { RestScans, Scans } from '../Scan'; +import { EntryPoints, RestEntryPoints } from '../EntryPoint'; import { Archives, DefaultParserFactory, @@ -166,6 +167,11 @@ container { lifecycle: Lifecycle.Singleton } ) .register(Scans, { useClass: RestScans }, { lifecycle: Lifecycle.Singleton }) + .register( + EntryPoints, + { useClass: RestEntryPoints }, + { lifecycle: Lifecycle.Singleton } + ) .register( Archives, { useClass: RestArchives }, diff --git a/src/EntryPoint/EntryPoints.ts b/src/EntryPoint/EntryPoints.ts new file mode 100644 index 00000000..dfa41511 --- /dev/null +++ b/src/EntryPoint/EntryPoints.ts @@ -0,0 +1,10 @@ +export interface EntryPoints { + entrypoints(projectId: string): Promise; +} + +export const EntryPoints: unique symbol = Symbol('EntryPoints'); + +export interface EntryPoint { + id: string; + url: string; +} diff --git a/src/EntryPoint/RestEntryPoints.ts b/src/EntryPoint/RestEntryPoints.ts new file mode 100644 index 00000000..917dcca5 --- /dev/null +++ b/src/EntryPoint/RestEntryPoints.ts @@ -0,0 +1,63 @@ +import { EntryPoints, EntryPoint } from './EntryPoints'; +import { ProxyFactory } from '../Utils'; +import axios, { Axios } from 'axios'; +import { inject, injectable } from 'tsyringe'; +import http from 'node:http'; +import https from 'node:https'; + +export interface RestProjectsOptions { + baseURL: string; + apiKey: string; + timeout?: number; + insecure?: boolean; + proxyURL?: string; +} + +export const RestProjectsOptions: unique symbol = Symbol('RestProjectsOptions'); + +@injectable() +export class RestEntryPoints implements EntryPoints { + private readonly client: Axios; + + constructor( + @inject(ProxyFactory) private readonly proxyFactory: ProxyFactory, + @inject(RestProjectsOptions) + { + baseURL, + apiKey, + insecure, + proxyURL, + timeout = 10000 + }: RestProjectsOptions + ) { + const { + httpAgent = new http.Agent(), + httpsAgent = new https.Agent({ rejectUnauthorized: !insecure }) + } = proxyURL + ? this.proxyFactory.createProxy({ + proxyUrl: proxyURL, + rejectUnauthorized: !insecure + }) + : {}; + + this.client = axios.create({ + baseURL, + timeout, + httpAgent, + httpsAgent, + responseType: 'json', + headers: { authorization: `Api-Key ${apiKey}` } + }); + } + + public async entrypoints(projectId: string): Promise { + const res = await this.client.get( + `/api/v2/projects/${projectId}/entry-points` + ); + + return res.data.items.map((raw: any) => ({ + id: raw.id, + url: raw.url + })); + } +} diff --git a/src/EntryPoint/index.ts b/src/EntryPoint/index.ts new file mode 100644 index 00000000..acec926f --- /dev/null +++ b/src/EntryPoint/index.ts @@ -0,0 +1,2 @@ +export * from './EntryPoints'; +export * from './RestEntryPoints'; diff --git a/src/index.ts b/src/index.ts index 3c7f396d..15654a86 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,8 @@ import { StopScan, UploadArchive, VersionCommand, - Configure + Configure, + GetEntryPoints } from './Commands'; import { CliBuilder, container } from './Config'; @@ -24,6 +25,7 @@ container.resolve(CliBuilder).build({ new RetestScan(), new StopScan(), new UploadArchive(), - new Configure() + new Configure(), + new GetEntryPoints() ] }).argv;