Skip to content

Commit

Permalink
Merge pull request #2526 from cisagov/2521-refactor-cve-and-product_i…
Browse files Browse the repository at this point in the history
…nfo-tables

2521 Refactor CVE and Product Info Tables
  • Loading branch information
Matthew-Grayson authored Feb 22, 2024
2 parents c221a59 + 7df6707 commit 0d20066
Show file tree
Hide file tree
Showing 21 changed files with 1,421 additions and 330 deletions.
7 changes: 2 additions & 5 deletions backend/src/api/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,8 @@ authenticatedRoute.delete('/api-keys/:keyId', handlerToExpress(apiKeys.del));
authenticatedRoute.post('/search', handlerToExpress(search.search));
authenticatedRoute.post('/search/export', handlerToExpress(search.export_));
authenticatedRoute.get('/cpes/:id', handlerToExpress(cpes.get));
authenticatedRoute.get('/cves/:cve_uid', handlerToExpress(cves.get));
authenticatedRoute.get(
'/cves/name/:cve_name',
handlerToExpress(cves.getByName)
);
authenticatedRoute.get('/cves/:id', handlerToExpress(cves.get));
authenticatedRoute.get('/cves/name/:name', handlerToExpress(cves.getByName));
authenticatedRoute.post('/domain/search', handlerToExpress(domains.list));
authenticatedRoute.post('/domain/export', handlerToExpress(domains.export_));
authenticatedRoute.get('/domain/:domainId', handlerToExpress(domains.get));
Expand Down
17 changes: 8 additions & 9 deletions backend/src/api/cpes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ProductInfo, connectToDatabase } from '../models';
import { Cpe, connectToDatabase } from '../models';
import { wrapHandler, NotFound } from './helpers';

// TODO: Join cves to cpe get method
Expand All @@ -20,20 +20,19 @@ import { wrapHandler, NotFound } from './helpers';
*/
export const get = wrapHandler(async (event) => {
const connection = await connectToDatabase();
const repository = connection.getRepository(ProductInfo);

const id = event.pathParameters?.id;
if (!id) {
return NotFound;
}

const productInfo = await repository.findOne(id);
if (!productInfo) {
const cpe = await Cpe.createQueryBuilder('cpe')
.leftJoinAndSelect('cpe.cves', 'cve')
.where('cpe.id = :id', { id: id })
.getOne();

if (!cpe) {
return NotFound;
}

return {
statusCode: 200,
body: JSON.stringify(productInfo)
body: JSON.stringify(cpe)
};
});
34 changes: 14 additions & 20 deletions backend/src/api/cves.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,34 @@
import { Cve, connectToDatabase } from '../models';
import { wrapHandler } from './helpers';
import { NotFound, wrapHandler } from './helpers';

// TODO: Add test for joining product_info
// TODO: Add test for joining cpe table
// TODO: Create CveFilters and CveSearch classes to handle filtering and pagination of additional fields

/**
* @swagger
* /cves/{cve_uid}:
* /cves/{id}:
* get:
* description: Retrieve a CVE by ID.
* tags:
* - CVEs
* parameters:
* - in: path
* name: cve_uid
* name: id
* required: true
* schema:
* type: string
*/
export const get = wrapHandler(async (event) => {
await connectToDatabase();
const cve_uid = event.pathParameters?.cve_uid;
const id = event.pathParameters?.id;

const cve = await Cve.createQueryBuilder('cve')
.leftJoinAndSelect('cve.product_info', 'product_info')
.where('cve.cve_uid = :cve_uid', { cve_uid: cve_uid })
.leftJoinAndSelect('cve.cpes', 'cpe')
.where('cve.id = :id', { id: id })
.getOne();

if (!cve) {
return {
statusCode: 404,
body: JSON.stringify(Error)
};
return NotFound;
}

return {
Expand All @@ -44,32 +41,29 @@ export const get = wrapHandler(async (event) => {
/**
* @swagger
*
* /cves/name/{cve_name}:
* /cves/name/{name}:
* get:
* description: Retrieve a single CVE record by its name.
* tags:
* - CVE
* parameters:
* - name: cve_name
* - name: name
* in: path
* required: true
* schema:
* type: string
*/
export const getByName = wrapHandler(async (event) => {
await connectToDatabase();
const cve_name = event.pathParameters?.cve_name;
const name = event.pathParameters?.name;

const cve = await Cve.createQueryBuilder('cve')
.leftJoinAndSelect('cve.product_info', 'product_info')
.where('cve.cve_name = :cve_name', { cve_name })
.leftJoinAndSelect('cve.cpes', 'cpe')
.where('cve.name = :name', { name: name })
.getOne();

if (!cve) {
return {
statusCode: 404,
body: JSON.stringify(Error)
};
return NotFound;
}

return {
Expand Down
4 changes: 2 additions & 2 deletions backend/src/models/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
ApiKey,
SavedSearch,
OrganizationTag,
ProductInfo,
Cpe,
Cve
} from '.';

Expand All @@ -27,7 +27,7 @@ const connectDb = async (logging?: boolean) => {
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
entities: [
ProductInfo,
Cpe,
Cve,
Domain,
Service,
Expand Down
31 changes: 31 additions & 0 deletions backend/src/models/cpe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
BaseEntity,
Unique
} from 'typeorm';
import { Cve } from './cve';

@Entity()
@Unique(['name', 'version', 'vendor'])
export class Cpe extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;

@Column()
name: string;

@Column()
version: string;

@Column()
vendor: string;

@Column()
lastSeenAt: Date;

@ManyToMany(() => Cve, (cve) => cve.cpes)
cves: Cve[];
}
77 changes: 36 additions & 41 deletions backend/src/models/cve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,121 +2,116 @@ import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToMany,
BaseEntity,
JoinTable,
Unique
} from 'typeorm';
import { ProductInfo } from './product-info';
import { Cpe } from './cpe';

//TODO: Refactor column names to camelCase to match the rest of the codebase?
@Entity()
@Unique(['cve_name'])
@Unique(['name'])
export class Cve extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
cve_uid: string; //TODO: Refactor to id to match other UUIDs?
id: string;

@Column({ nullable: true })
cve_name: string;
name: string;

@CreateDateColumn()
published_date: Date;
@Column({ nullable: true })
publishedAt: Date;

@UpdateDateColumn()
last_modified_date: Date;
@Column({ nullable: true })
modifiedAt: Date;

@Column({ nullable: true })
vuln_status: string;
status: string;

@Column({ nullable: true })
description: string;

@Column({ nullable: true })
cvss_v2_source: string;
cvssV2Source: string;

@Column({ nullable: true })
cvss_v2_type: string;
cvssV2Type: string;

@Column({ nullable: true })
cvss_v2_version: string;
cvssV2Version: string;

@Column({ nullable: true })
cvss_v2_vector_string: string;
cvssV2VectorString: string;

@Column({ nullable: true })
cvss_v2_base_score: string;
cvssV2BaseScore: string;

@Column({ nullable: true })
cvss_v2_base_severity: string;
cvssV2BaseSeverity: string;

@Column({ nullable: true })
cvss_v2_exploitability_score: string;
cvssV2ExploitabilityScore: string;

@Column({ nullable: true })
cvss_v2_impact_score: string;
cvssV2ImpactScore: string;

@Column({ nullable: true })
cvss_v3_source: string;
cvssV3Source: string;

@Column({ nullable: true })
cvss_v3_type: string;
cvssV3Type: string;

@Column({ nullable: true })
cvss_v3_version: string;
cvssV3Version: string;

@Column({ nullable: true })
cvss_v3_vector_string: string;
cvssV3VectorString: string;

@Column({ nullable: true })
cvss_v3_base_score: string;
cvssV3BaseScore: string;

@Column({ nullable: true })
cvss_v3_base_severity: string;
cvssV3BaseSeverity: string;

@Column({ nullable: true })
cvss_v3_exploitability_score: string;
cvssV3ExploitabilityScore: string;

@Column({ nullable: true })
cvss_v3_impact_score: string;
cvssV3ImpactScore: string;

@Column({ nullable: true })
cvss_v4_source: string;
cvssV4Source: string;

@Column({ nullable: true })
cvss_v4_type: string;
cvssV4Type: string;

@Column({ nullable: true })
cvss_v4_version: string;
cvssV4Version: string;

@Column({ nullable: true })
cvss_v4_vector_string: string;
cvssV4VectorString: string;

@Column({ nullable: true })
cvss_v4_base_score: string;
cvssV4BaseScore: string;

@Column({ nullable: true })
cvss_v4_base_severity: string;
cvssV4BaseSeverity: string;

@Column({ nullable: true })
cvss_v4_exploitability_score: string;
cvssV4ExploitabilityScore: string;

@Column({ nullable: true })
cvss_v4_impact_score: string;
cvssV4ImpactScore: string;

@Column('simple-array', { nullable: true })
weaknesses: string[];

@Column('simple-array', { nullable: true })
reference_urls: string[];

@Column('simple-array', { nullable: true })
cpe_list: string[];
references: string[];

@ManyToMany(() => ProductInfo, (product_info) => product_info.cve, {
@ManyToMany(() => Cpe, (cpe) => cpe.cves, {
cascade: true
})
@JoinTable()
product_info: ProductInfo[];
cpes: Cpe[];
}
2 changes: 1 addition & 1 deletion backend/src/models/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from './domain';
export * from './cve';
export * from './product-info';
export * from './cpe';
export * from './service';
export * from './connection';
export * from './vulnerability';
Expand Down
33 changes: 0 additions & 33 deletions backend/src/models/product-info.ts

This file was deleted.

Loading

0 comments on commit 0d20066

Please sign in to comment.