From 99fd996eddc92c1f70d7319b06565cf3048fa903 Mon Sep 17 00:00:00 2001 From: Sean Sica <23294618+seansica@users.noreply.github.com> Date: Thu, 9 Jan 2025 14:45:01 -0500 Subject: [PATCH] fix: resolve linting issues + various biz logic issues All 581 regression tests are now passing! --- .../system-configuration-controller.js | 5 +- app/repository/relationships-repository.js | 20 +--- app/services/attack-objects-service.js | 4 +- app/services/identities-service.js | 53 +--------- app/services/index.js | 29 ++++++ app/services/relationships-service.js | 96 +++++++++++-------- app/services/system-configuration-service.js | 26 +++-- 7 files changed, 114 insertions(+), 119 deletions(-) create mode 100644 app/services/index.js diff --git a/app/controllers/system-configuration-controller.js b/app/controllers/system-configuration-controller.js index a2ec5c8..5902ac0 100644 --- a/app/controllers/system-configuration-controller.js +++ b/app/controllers/system-configuration-controller.js @@ -1,11 +1,12 @@ 'use strict'; const systemConfigurationService = require('../services/system-configuration-service'); +const { SystemConfigurationService } = require('../services/system-configuration-service'); const logger = require('../lib/logger'); exports.retrieveSystemVersion = function (req, res) { try { - const systemVersionInfo = systemConfigurationService.retrieveSystemVersion(); + const systemVersionInfo = SystemConfigurationService.retrieveSystemVersion(); logger.debug( `Success: Retrieved system version, version: ${systemVersionInfo.version}, attackSpecVersion: ${systemVersionInfo.attackSpecVersion}`, ); @@ -57,7 +58,7 @@ exports.setOrganizationIdentity = async function (req, res) { exports.retrieveAuthenticationConfig = function (req, res) { try { - const authenticationConfig = systemConfigurationService.retrieveAuthenticationConfig(); + const authenticationConfig = SystemConfigurationService.retrieveAuthenticationConfig(); logger.debug('Success: Retrieved authentication configuration.'); return res.status(200).send(authenticationConfig); } catch (err) { diff --git a/app/repository/relationships-repository.js b/app/repository/relationships-repository.js index 3edbf06..d597da9 100644 --- a/app/repository/relationships-repository.js +++ b/app/repository/relationships-repository.js @@ -2,6 +2,8 @@ const BaseRepository = require('./_base.repository'); const Relationship = require('../models/relationship-model'); +const { lastUpdatedByQueryHelper } = require('../lib/request-parameter-helper'); +const { DatabaseError } = require('../exceptions'); class RelationshipsRepository extends BaseRepository { async retrieveAll(options) { @@ -73,24 +75,6 @@ class RelationshipsRepository extends BaseRepository { }); } - const facet = { - $facet: { - totalCount: [{ $count: 'totalCount' }], - documents: [], - }, - }; - - if (options.offset) { - facet.$facet.documents.push({ $skip: options.offset }); - } else { - facet.$facet.documents.push({ $skip: 0 }); - } - if (options.limit) { - facet.$facet.documents.push({ $limit: options.limit }); - } - - aggregation.push(facet); - return await this.model.aggregate(aggregation).exec(); } catch (err) { throw new DatabaseError(err); diff --git a/app/services/attack-objects-service.js b/app/services/attack-objects-service.js index cbd5823..749266a 100644 --- a/app/services/attack-objects-service.js +++ b/app/services/attack-objects-service.js @@ -115,10 +115,12 @@ class AttackObjectsService extends BaseService { * Override of base class create() because: * 1. create() requires a STIX `type` -- this service does not define a type */ - async create(data, options, callback) { + create(data, options, callback) { throw new NotImplementedError(this.constructor.name, 'create'); } } +module.exports.AttackObjectsService = AttackObjectsService; + // Export an instance of the service module.exports = new AttackObjectsService(null, attackObjectsRepository); diff --git a/app/services/identities-service.js b/app/services/identities-service.js index f797ab5..a9df91a 100644 --- a/app/services/identities-service.js +++ b/app/services/identities-service.js @@ -5,7 +5,7 @@ const config = require('../config/config'); const identitiesRepository = require('../repository/identities-repository'); const BaseService = require('./_base.service'); const { InvalidTypeError } = require('../exceptions'); -const { Identity: IdentityType } = require('../lib/stix-types'); +const { Identity: IdentityType } = require('../lib/types'); class IdentitiesService extends BaseService { /** @@ -42,55 +42,12 @@ class IdentitiesService extends BaseService { } // Save the document in the database - try { - return await this.repository.save(data); - } catch (err) { - th - } + return await this.repository.save(data); } - - /** - * @public - * CRUD Operation: Read - * Inherited from BaseService - * retrieveAll(options) - */ - - /** - * @public - * CRUD Operation: Read - * Inherited from BaseService - * retrieveById(stixId, options) - */ - - /** - * @public - * CRUD Operation: Read - * Inherited from BaseService - * retrieveVersionById(stixId, modified) - */ - - /** - * @public - * CRUD Operation: Update - * Inherited from BaseService - * updateFull(stixId, modified, data) - */ - - /** - * @public - * CRUD Operation: Delete - * Inherited from BaseService - * deleteVersionById(stixId, modified) - */ - - /** - * @public - * CRUD Operation: Delete - * Inherited from BaseService - * deleteById(stixId) - */ } +//Default export +module.exports.IdentitiesService = IdentitiesService; + // Export an instance of the service module.exports = new IdentitiesService(IdentityType, identitiesRepository); diff --git a/app/services/index.js b/app/services/index.js new file mode 100644 index 0000000..ba4b67d --- /dev/null +++ b/app/services/index.js @@ -0,0 +1,29 @@ +'use strict'; + +//** import repositories */ +const attackObjectsRepository = require('../repository/attack-objects-repository'); +const identitiesRepository = require('../repository/identities-repository'); +const relationshipsRepository = require('../repository/relationships-repository'); + +//** imports services */ +const AttackObjectsService = require('./attack-objects-service'); +const { IdentitiesService } = require('./identities-service'); +const RelationshipsService = require('./relationships-service'); + +//** import types */ +const { Identity: IdentityType, Relationship: RelationshipType } = require('../lib/types'); + +// ** initialize services */ +const identitiesService = new IdentitiesService(IdentityType, identitiesRepository); +const relationshipsService = new RelationshipsService(RelationshipType, relationshipsRepository); +const attackObjectsService = new AttackObjectsService( + attackObjectsRepository, + identitiesService, + relationshipsService, +); + +module.exports = { + identitiesService, + relationshipsService, + attackObjectsService, +}; diff --git a/app/services/relationships-service.js b/app/services/relationships-service.js index 8409618..84052af 100644 --- a/app/services/relationships-service.js +++ b/app/services/relationships-service.js @@ -20,71 +20,87 @@ const objectTypeMap = new Map([ class RelationshipsService extends BaseService { async retrieveAll(options) { - let results = await super.retrieveAll(options); + let results = await this.repository.retrieveAll(options); - if (options.lookupRefs) { - results = Array.isArray(results) ? results : results.data; - - // Filter by source type if specified - if (options.sourceType) { - results = results.filter((document) => { - if (document.source_objects?.length === 0) { - return false; - } + // Filter out relationships that don't reference the source type + if (options.sourceType) { + results = results.filter((document) => { + if (document.source_objects.length === 0) { + return false; + } else { document.source_objects.sort((a, b) => b.stix.modified - a.stix.modified); return objectTypeMap.get(document.source_objects[0].stix.type) === options.sourceType; - }); - } + } + }); + } - // Filter by target type if specified - if (options.targetType) { - results = results.filter((document) => { - if (document.target_objects?.length === 0) { - return false; - } + // Filter out relationships that don't reference the target type + if (options.targetType) { + results = results.filter((document) => { + if (document.target_objects.length === 0) { + return false; + } else { document.target_objects.sort((a, b) => b.stix.modified - a.stix.modified); return objectTypeMap.get(document.target_objects[0].stix.type) === options.targetType; - }); + } + }); + } + + const prePaginationTotal = results.length; + + // Apply pagination parameters + if (options.offset || options.limit) { + const start = options.offset || 0; + if (options.limit) { + const end = start + options.limit; + results = results.slice(start, end); + } else { + results = results.slice(start); } + } - // Move latest source and target objects to non-array properties - for (const document of results) { - if (Array.isArray(document.source_objects)) { - if (document.source_objects.length === 0) { - document.source_objects = undefined; - } else { - document.source_object = document.source_objects[0]; - document.source_objects = undefined; - } + // Move latest source and target objects to a non-array property, then remove array of source and target objects + for (const document of results) { + if (Array.isArray(document.source_objects)) { + if (document.source_objects.length === 0) { + document.source_objects = undefined; + } else { + document.source_object = document.source_objects[0]; + document.source_objects = undefined; } + } - if (Array.isArray(document.target_objects)) { - if (document.target_objects.length === 0) { - document.target_objects = undefined; - } else { - document.target_object = document.target_objects[0]; - document.target_objects = undefined; - } + if (Array.isArray(document.target_objects)) { + if (document.target_objects.length === 0) { + document.target_objects = undefined; + } else { + document.target_object = document.target_objects[0]; + document.target_objects = undefined; } } } - // this does not work: - // return RelationshipsService.paginate(options, results); + if (options.includeIdentities) { + await this.addCreatedByAndModifiedByIdentitiesToAll(results); + } if (options.includePagination) { return { pagination: { - total: results.length, + total: prePaginationTotal, offset: options.offset, limit: options.limit, }, data: results, }; + } else { + return results; } - - return results; } } +// Default export +module.exports.RelationshipsService = RelationshipsService; + +// Default export - export an instance of the service module.exports = new RelationshipsService(RelationshipType, relationshipsRepository); diff --git a/app/services/system-configuration-service.js b/app/services/system-configuration-service.js index ba25d07..e2177a6 100644 --- a/app/services/system-configuration-service.js +++ b/app/services/system-configuration-service.js @@ -14,17 +14,21 @@ const { DefaultMarkingDefinitionsNotFoundError, AnonymousUserAccountNotSetError, AnonymousUserAccountNotFoundError, + NotImplementedError, } = require('../exceptions'); -let allowedValues; - class SystemConfigurationService extends BaseService { + constructor() { + super(null, systemConfigurationRepository); + this._allowedValues = null; + } + /** * @public - * CRUD Operation: Read + * (CRUD Operation: Read) * Returns the system version information */ - retrieveSystemVersion() { + static retrieveSystemVersion() { return { version: config.app.version, attackSpecVersion: config.app.attackSpecVersion, @@ -37,12 +41,12 @@ class SystemConfigurationService extends BaseService { * Returns allowed values for system configuration */ async retrieveAllowedValues() { - if (allowedValues) { - return allowedValues; + if (this._allowedValues) { + return this._allowedValues; } const data = await fs.promises.readFile(config.configurationFiles.allowedValues); - allowedValues = JSON.parse(data); - return allowedValues; + this._allowedValues = JSON.parse(data); + return this._allowedValues; } /** @@ -207,7 +211,7 @@ class SystemConfigurationService extends BaseService { * CRUD Operation: Read * Returns the authentication configuration */ - retrieveAuthenticationConfig() { + static retrieveAuthenticationConfig() { return { mechanisms: [{ authnType: config.userAuthn.mechanism }], }; @@ -248,7 +252,7 @@ class SystemConfigurationService extends BaseService { * Override of base class create() because: * 1. create() requires a STIX `type` -- this service does not define a type */ - async create(data, options, callback) { + create(data, options, callback) { throw new NotImplementedError(this.constructor.name, 'create'); } } @@ -256,3 +260,5 @@ class SystemConfigurationService extends BaseService { // Export an instance of the service // Pass null for type since SystemConfiguration isn't a STIX type module.exports = new SystemConfigurationService(null, systemConfigurationRepository); + +module.exports.SystemConfigurationService = SystemConfigurationService;