diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 2e25c99a81..9bdb7b2425 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,5 +1,10 @@ ## RELEASE NOTES +### Version 7.0.41 +**EXUI-1856** Unable to see Present (PED) button +**EXUI-1598** auto-redirect to tabs as expected +**EXUI-1739** not passing service code for case linking + ### Version 7.0.40 **EXUI-1808** Angular 17 update diff --git a/package.json b/package.json index 77563d13c3..ff0cc5fee5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hmcts/ccd-case-ui-toolkit", - "version": "7.0.40", + "version": "7.0.41", "engines": { "node": ">=18.19.0" }, diff --git a/projects/ccd-case-ui-toolkit/package.json b/projects/ccd-case-ui-toolkit/package.json index bac53324bc..e3ad9f42e1 100644 --- a/projects/ccd-case-ui-toolkit/package.json +++ b/projects/ccd-case-ui-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@hmcts/ccd-case-ui-toolkit", - "version": "7.0.40", + "version": "7.0.41", "engines": { "node": ">=18.19.0" }, diff --git a/projects/ccd-case-ui-toolkit/src/lib/app-config.mock.ts b/projects/ccd-case-ui-toolkit/src/lib/app-config.mock.ts index 829be82b1b..5f3a73442c 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/app-config.mock.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/app-config.mock.ts @@ -214,4 +214,10 @@ export class AppMockConfig implements AbstractAppConfig { public getEnableCaseFileViewVersion1_1(): boolean { return true; } + public getIcpEnable(): boolean { + return false; + } + public getIcpJurisdictions(): string[] { + return ['', '']; + } } diff --git a/projects/ccd-case-ui-toolkit/src/lib/app.config.ts b/projects/ccd-case-ui-toolkit/src/lib/app.config.ts index ccbf84fb97..67bd2ac7b2 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/app.config.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/app.config.ts @@ -1,4 +1,5 @@ /* istanbul ignore file */ + // tslint:disable:variable-name export interface AccessManagementBasicViewMockModel { active?: boolean; @@ -50,6 +51,8 @@ export abstract class AbstractAppConfig { public abstract getActivityMaxRequestPerBatch(): number; public abstract getCaseHistoryUrl(caseId: string, eventId: string): string; public abstract getPrintServiceUrl(): string; + public abstract getIcpEnable(): boolean; + public abstract getIcpJurisdictions(): string[]; /** * Dummy version replacing deprecated `getRemotePrintServiceUrl()`, to be removed in next major release @@ -101,6 +104,7 @@ export abstract class AbstractAppConfig { return 'prod'; } + public abstract getRefundsUrl(): string; public abstract getNotificationUrl(): string; public abstract getPaymentReturnUrl(): string; @@ -116,7 +120,6 @@ export abstract class AbstractAppConfig { public abstract getEnableRestrictedCaseAccessConfig(): boolean; public abstract getEnableCaseFileViewVersion1_1(): boolean; } - export class CaseEditorConfig { public api_url: string; public case_data_url: string; @@ -140,6 +143,7 @@ export class CaseEditorConfig { public activity_url: string; public activity_max_request_per_batch: number; public print_service_url: string; + /** * remote_print_service_url marked as optional since deprecation, ahead of removal in next major release * @deprecated @@ -187,4 +191,6 @@ export class CaseEditorConfig { public case_data_store_api_url: string; public enable_restricted_case_access: boolean; public enable_case_file_view_version_1_1: boolean; + public icp_enabled: boolean; + public icp_jurisdictions: string[]; } diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts index a4e2c04320..1d5184c2ce 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.spec.ts @@ -23,7 +23,7 @@ import { PaletteUtilsModule } from '../../../components/palette/utils'; import { ConditionalShowRegistrarService } from '../../../directives'; import { LabelSubstitutorDirective } from '../../../directives/substitutor'; import { PlaceholderService } from '../../../directives/substitutor/services'; -import { CaseView, CaseViewEvent, CaseViewTrigger } from '../../../domain/case-view'; +import { CaseTab, CaseView, CaseViewEvent, CaseViewTrigger } from '../../../domain/case-view'; import { CaseViewEventIds } from '../../../domain/case-view/case-view-event-ids.enum'; import { CaseField } from '../../../domain/definition'; import { HttpError } from '../../../domain/http'; @@ -2183,6 +2183,483 @@ describe('CaseFullAccessViewComponent - get default hrefMarkdownLinkContent', () expect(subscribeSpy).not.toHaveBeenCalled(); }); }); + +describe('CaseFullAccessViewComponent - findPreSelectedActiveTab', () => { + let component: CaseFullAccessViewComponent; + let fixture: ComponentFixture; + let mockLocation: any; + let convertHrefToRouterService; + + beforeEach(async () => { + mockLocation = createSpyObj('location', ['path']); + mockLocation.path.and.returnValue('/cases/case-details/1620409659381330'); + convertHrefToRouterService = jasmine.createSpyObj('ConvertHrefToRouterService', ['getHrefMarkdownLinkContent', 'callAngularRouter']); + convertHrefToRouterService.getHrefMarkdownLinkContent.and.returnValue(of('Default')); + + await TestBed.configureTestingModule({ + imports: [ + PaletteUtilsModule, + MatTabsModule, + BrowserAnimationsModule, + PaletteModule, + PaymentLibModule, + RouterTestingModule.withRoutes([ + { + path: 'cases', + children: [ + { + path: 'case-details', + children: [ + { + path: ':id#overview', + children: [ + { + path: 'tasks', + component: TasksContainerComponent + } + ] + } + ] + } + ] + } + ]), + StoreModule.forRoot({}), + EffectsModule.forRoot([]) + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [ + TasksContainerComponent, + CaseFullAccessViewComponent, + DeleteOrCancelDialogComponent, + EventTriggerComponent, + CallbackErrorsComponent, + // Mocks + caseActivityComponentMock, + caseHeaderComponentMock, + linkComponentMock, + MockRpxTranslatePipe + ], + providers: [ + FieldsUtils, + PlaceholderService, + CaseReferencePipe, + OrderService, + { + provide: Location, + useValue: mockLocation + }, + ErrorNotifierService, + { provide: AbstractAppConfig, useClass: AppMockConfig }, + NavigationNotifierService, + { provide: CaseNotifier, useValue: caseNotifier }, + { provide: ActivatedRoute, useValue: mockRoute }, + ActivityPollingService, + ActivityService, + HttpService, + HttpErrorService, + AuthService, + SessionStorageService, + { provide: DraftService, useValue: draftService }, + { provide: AlertService, useValue: alertService }, + { provide: MatDialog, useValue: dialog }, + { provide: MatDialogRef, useValue: matDialogRef }, + { provide: MatDialogConfig, useValue: DIALOG_CONFIG }, + { provide: ConvertHrefToRouterService, useValue: convertHrefToRouterService }, + { provide: RpxTranslationService, useValue: createSpyObj('RpxTranslationService', ['translate']) }, + DeleteOrCancelDialogComponent + ], + teardown: { destroyAfterEach: false } + }).compileComponents(); + + fixture = TestBed.createComponent(CaseFullAccessViewComponent); + component = fixture.componentInstance; + }); + + it('should return the first unsorted tab if it exists', () => { + component.caseDetails = clone(CASE_VIEW); + component.sortedTabs = [ + { + id: 'HistoryTab', + label: 'History', + order: 1, + fields: [Object.assign(new CaseField(), { + id: 'CaseHistory', + label: 'Case History', + display_context: 'OPTIONAL', + field_type: { + id: 'CaseHistoryViewer', + type: 'CaseHistoryViewer' + }, + order: 1, + value: EVENTS, + show_condition: '', + hint_text: '' + })], + show_condition: '' + }, + { + id: 'NameTab', + label: 'Name', + order: 2, + fields: [ + Object.assign(new CaseField(), { + id: 'PersonFirstName', + label: 'First name', + display_context: 'OPTIONAL', + field_type: { + id: 'Text', + type: 'Text' + }, + order: 2, + value: 'Janet', + show_condition: '', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'PersonLastName', + label: 'Last name', + display_context: 'OPTIONAL', + field_type: { + id: 'Text', + type: 'Text' + }, + order: 1, + value: 'Parker', + show_condition: 'PersonFirstName="Jane*"', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'PersonComplex', + label: 'Complex field', + display_context: 'OPTIONAL', + field_type: { + id: 'Complex', + type: 'Complex', + complex_fields: [] + }, + order: 3, + show_condition: 'PersonFirstName="Park"', + hint_text: '' + }) + ], + show_condition: 'PersonFirstName="Janet"' + }, + { + id: 'SomeTab', + label: 'Some Tab', + order: 3, + fields: [], + show_condition: '' + }, + { + id: 'CaseFlagsTab', + label: 'Case flags', + fields: [ + Object.assign(new CaseField(), { + id: 'FlagLauncher1', + label: 'Flag launcher', + display_context: 'OPTIONAL', + field_type: { + id: 'FlagLauncher', + type: 'FlagLauncher' + }, + order: 4, + value: null, + show_condition: '', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'CaseFlag1', + label: 'First Case Flag', + display_context: null, + field_type: { + id: 'Flags', + type: 'Complex', + complex_fields: [] + }, + value: { + partyName: 'John Smith', + roleOnCase: '', + details: [ + { + id: '9c2129ba-3fc6-4bae-afc3-32808ffd9cbe', + value: { + name: 'Wheel chair access', + subTypeValue: '', + subTypeKey: '', + otherDescription: '', + flagComment: '', + dateTimeModified: new Date('2021-09-09 00:00:00'), + dateTimeCreated: new Date('2021-09-09 00:00:00'), + path: [], + hearingRelevant: false, + flagCode: '', + status: CaseFlagStatus.ACTIVE + } + }, + { + id: '9125aac8-1506-4753-b820-b3a3be451235', + value: { + name: 'Sign language', + subTypeValue: 'British Sign Language (BSL)', + subTypeKey: '', + otherDescription: '', + flagComment: '', + dateTimeModified: new Date('2021-09-09 00:00:00'), + dateTimeCreated: new Date('2021-09-09 00:00:00'), + path: [], + hearingRelevant: false, + flagCode: '', + status: CaseFlagStatus.INACTIVE + } + } + ] + } + }) + ], + show_condition: null + } + ] as CaseTab[]; + + const selectedTab = component.findPreSelectedActiveTab(); + expect(selectedTab.id).toEqual('CaseFlagsTab'); + }); + + it('should return the first sorted tab if no unsorted tabs exist', () => { + component.caseDetails = clone(CASE_VIEW); + component.sortedTabs = [ + { + id: 'HistoryTab', + label: 'History', + order: 1, + fields: [Object.assign(new CaseField(), { + id: 'CaseHistory', + label: 'Case History', + display_context: 'OPTIONAL', + field_type: { + id: 'CaseHistoryViewer', + type: 'CaseHistoryViewer' + }, + order: 1, + value: EVENTS, + show_condition: '', + hint_text: '' + })], + show_condition: '' + }, + { + id: 'NameTab', + label: 'Name', + order: 2, + fields: [ + Object.assign(new CaseField(), { + id: 'PersonFirstName', + label: 'First name', + display_context: 'OPTIONAL', + field_type: { + id: 'Text', + type: 'Text' + }, + order: 2, + value: 'Janet', + show_condition: '', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'PersonLastName', + label: 'Last name', + display_context: 'OPTIONAL', + field_type: { + id: 'Text', + type: 'Text' + }, + order: 1, + value: 'Parker', + show_condition: 'PersonFirstName="Jane*"', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'PersonComplex', + label: 'Complex field', + display_context: 'OPTIONAL', + field_type: { + id: 'Complex', + type: 'Complex', + complex_fields: [] + }, + order: 3, + show_condition: 'PersonFirstName="Park"', + hint_text: '' + }) + ], + show_condition: 'PersonFirstName="Janet"' + }, + { + id: 'SomeTab', + label: 'Some Tab', + order: 3, + fields: [], + show_condition: '' + } + ] as CaseTab[]; + + const selectedTab = component.findPreSelectedActiveTab(); + expect(selectedTab.id).toEqual('HistoryTab'); + }); + + it('should prioritize unsorted tabs over sorted ones', () => { + component.caseDetails = clone(CASE_VIEW); + component.caseDetails.tabs[1].order = null; + component.sortedTabs = [ + { + id: 'NameTab', + label: 'Name', + order: 2, + fields: [ + Object.assign(new CaseField(), { + id: 'PersonFirstName', + label: 'First name', + display_context: 'OPTIONAL', + field_type: { + id: 'Text', + type: 'Text' + }, + order: 2, + value: 'Janet', + show_condition: '', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'PersonLastName', + label: 'Last name', + display_context: 'OPTIONAL', + field_type: { + id: 'Text', + type: 'Text' + }, + order: 1, + value: 'Parker', + show_condition: 'PersonFirstName="Jane*"', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'PersonComplex', + label: 'Complex field', + display_context: 'OPTIONAL', + field_type: { + id: 'Complex', + type: 'Complex', + complex_fields: [] + }, + order: 3, + show_condition: 'PersonFirstName="Park"', + hint_text: '' + }) + ], + show_condition: 'PersonFirstName="Janet"' + }, + { + id: 'SomeTab', + label: 'Some Tab', + order: 3, + fields: [], + show_condition: '' + }, + { + id: 'HistoryTab', + label: 'History', + order: null, + fields: [Object.assign(new CaseField(), { + id: 'CaseHistory', + label: 'Case History', + display_context: 'OPTIONAL', + field_type: { + id: 'CaseHistoryViewer', + type: 'CaseHistoryViewer' + }, + order: 1, + value: EVENTS, + show_condition: '', + hint_text: '' + })], + show_condition: '' + }, + { + id: 'CaseFlagsTab', + label: 'Case flags', + order: null, + fields: [ + Object.assign(new CaseField(), { + id: 'FlagLauncher1', + label: 'Flag launcher', + display_context: 'OPTIONAL', + field_type: { + id: 'FlagLauncher', + type: 'FlagLauncher' + }, + order: 4, + value: null, + show_condition: '', + hint_text: '' + }), + Object.assign(new CaseField(), { + id: 'CaseFlag1', + label: 'First Case Flag', + display_context: null, + field_type: { + id: 'Flags', + type: 'Complex', + complex_fields: [] + }, + value: { + partyName: 'John Smith', + roleOnCase: '', + details: [ + { + id: '9c2129ba-3fc6-4bae-afc3-32808ffd9cbe', + value: { + name: 'Wheel chair access', + subTypeValue: '', + subTypeKey: '', + otherDescription: '', + flagComment: '', + dateTimeModified: new Date('2021-09-09 00:00:00'), + dateTimeCreated: new Date('2021-09-09 00:00:00'), + path: [], + hearingRelevant: false, + flagCode: '', + status: CaseFlagStatus.ACTIVE + } + }, + { + id: '9125aac8-1506-4753-b820-b3a3be451235', + value: { + name: 'Sign language', + subTypeValue: 'British Sign Language (BSL)', + subTypeKey: '', + otherDescription: '', + flagComment: '', + dateTimeModified: new Date('2021-09-09 00:00:00'), + dateTimeCreated: new Date('2021-09-09 00:00:00'), + path: [], + hearingRelevant: false, + flagCode: '', + status: CaseFlagStatus.INACTIVE + } + } + ] + }, + }) + ], + show_condition: null + } + ] as CaseTab[]; + + const selectedTab = component.findPreSelectedActiveTab(); + expect(selectedTab.id).toEqual('HistoryTab'); + }); +}); xdescribe('CaseFullAccessViewComponent - print and event selector disabled', () => { beforeEach((() => { orderService = new OrderService(); diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts index 8c8ed7d4b7..0f3fe11226 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/case-viewer/case-full-access-view/case-full-access-view.component.ts @@ -292,8 +292,8 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges } else { // sort with the order of CCD predefined tabs this.caseDetails.tabs.sort((aTab, bTab) => aTab.order > bTab.order ? 1 : (bTab.order > aTab.order ? -1 : 0)); - // preselect the 1st order of CCD predefined tabs - const preSelectTab: CaseTab = this.caseDetails.tabs[0]; + // select the first tab checking if the tab is visible + const preSelectTab: CaseTab = this.findPreSelectedActiveTab(); this.router.navigate(['cases', 'case-details', this.caseDetails.case_id], { fragment: preSelectTab.label }).then(() => { matTab = this.tabGroup._tabs.find((x) => x.textLabel === preSelectTab.label); // Update selectedIndex only if matTab.position is a non-zero number (positive or negative); this means the @@ -324,6 +324,12 @@ export class CaseFullAccessViewComponent implements OnInit, OnDestroy, OnChanges } } + public findPreSelectedActiveTab(): CaseTab { + const unOrderedTabsInSortedTabs = this.caseDetails.tabs + .filter((tab) => !tab.order && this.sortedTabs.some((sortedTab) => sortedTab.id === tab.id)); + return unOrderedTabsInSortedTabs.length ? unOrderedTabsInSortedTabs[0] : this.sortedTabs[0]; + } + // Refactored under EXUI-110 to address infinite tab loop to use tabIndexChanged instead public tabChanged(tabIndexChanged: number): void { const matTab = this.tabGroup._tabs.find(tab => tab.isActive); diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.html b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.html index 1775c07d57..b7951b9f53 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.html +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.html @@ -45,7 +45,8 @@

Case file

[contentType]="currentDocument.content_type" [enableAnnotations]="true" [enableRedactions]="true" - [height]="'94.5vh'"> + [height]="'94.5vh'" + [enableICP]="isIcpEnabled()"> diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.spec.ts index 2d208750bb..a587260871 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.spec.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.spec.ts @@ -12,12 +12,15 @@ import { SessionStorageService } from '../../../services/session/session-storage import { CaseFileViewFieldComponent } from './case-file-view-field.component'; import SpyObj = jasmine.SpyObj; import createSpyObj = jasmine.createSpyObj; +import { CaseNotifier } from '../../case-editor'; +import { AbstractAppConfig } from '../../../../app.config'; describe('CaseFileViewFieldComponent', () => { let component: CaseFileViewFieldComponent; let fixture: ComponentFixture; let mockCaseFileViewService: jasmine.SpyObj; let mockLoadingService: jasmine.SpyObj; + let mockabstractConfig: jasmine.SpyObj; let mockSessionStorageService: jasmine.SpyObj; const cidParam = '1234123412341234'; let mockRoute: { params: Observable<{ cid: string }>, snapshot: { paramMap: SpyObj } }; @@ -48,7 +51,7 @@ describe('CaseFileViewFieldComponent', () => { beforeEach(waitForAsync(() => { mockRoute = { - params: of({cid: cidParam}), + params: of({ cid: cidParam }), snapshot: { paramMap: createSpyObj('paramMap', ['get']), } @@ -61,6 +64,9 @@ describe('CaseFileViewFieldComponent', () => { mockCaseFileViewService.getCategoriesAndDocuments.and.returnValue(of(null)); mockLoadingService = createSpyObj('LoadingService', ['register', 'unregister']); + mockabstractConfig = createSpyObj('LoadingService', ['getIcpJurisdictions', 'getIcpEnable']); + mockabstractConfig.getIcpJurisdictions.and.returnValue('["ST_CIC", "IA"]'); + mockabstractConfig.getIcpEnable.and.returnValue(true); mockLoadingService.register.and.returnValue('loadingToken'); mockLoadingService.unregister.and.returnValue(null); @@ -82,7 +88,10 @@ describe('CaseFileViewFieldComponent', () => { { provide: CaseFileViewService, useValue: mockCaseFileViewService }, { provide: DocumentManagementService, useValue: mockDocumentManagementService }, { provide: LoadingService, useValue: mockLoadingService }, - { provide: SessionStorageService, useValue: mockSessionStorageService } + { provide: SessionStorageService, useValue: mockSessionStorageService }, + { provide: CaseNotifier, useValue: ['ST-CIC'] }, + { provide: AbstractAppConfig, useValue: mockabstractConfig }, + ] }) .compileComponents(); @@ -163,68 +172,68 @@ describe('CaseFileViewFieldComponent', () => { it('should register loadingToken, call updateDocumentCategory and unregister loadingToken on finalize ' + 'when calling moveDocument and successful', () => { - const document = new DocumentTreeNode(); - Object.assign(document, { - document: { - name: 'name', - type: DocumentTreeNodeType.DOCUMENT, - children: [], - document_filename: 'document_filename', - document_binary_url: 'document_binary_url', - attribute_path: 'attribute_path' - }, - newCategory: 'newCategoryId' - }); + const document = new DocumentTreeNode(); + Object.assign(document, { + document: { + name: 'name', + type: DocumentTreeNodeType.DOCUMENT, + children: [], + document_filename: 'document_filename', + document_binary_url: 'document_binary_url', + attribute_path: 'attribute_path' + }, + newCategory: 'newCategoryId' + }); - const data = { - document, - newCategory: 'newCategoryId' - }; + const data = { + document, + newCategory: 'newCategoryId' + }; - mockCaseFileViewService.updateDocumentCategory.and.returnValue(of({ response: true })); - component.reloadPage = () => {}; - spyOn(component, 'reloadPage').and.callThrough(); - spyOn(component, 'resetErrorMessages').and.callThrough(); - - component.moveDocument(data); - - expect(mockCaseFileViewService.updateDocumentCategory) - // @ts-expect-error - component.caseVersion is a private property - .toHaveBeenCalledWith(cidParam, component.caseVersion, data.document.attribute_path, data.newCategory); - // @ts-expect-error - loadingService private property - expect(component.loadingService.register).toHaveBeenCalled(); - // @ts-expect-error - loadingService private property - expect(component.loadingService.unregister).toHaveBeenCalled(); - expect(component.resetErrorMessages).toHaveBeenCalled(); - expect(component.reloadPage).toHaveBeenCalled(); - }); + mockCaseFileViewService.updateDocumentCategory.and.returnValue(of({ response: true })); + component.reloadPage = () => { }; + spyOn(component, 'reloadPage').and.callThrough(); + spyOn(component, 'resetErrorMessages').and.callThrough(); + + component.moveDocument(data); + + expect(mockCaseFileViewService.updateDocumentCategory) + // @ts-expect-error - component.caseVersion is a private property + .toHaveBeenCalledWith(cidParam, component.caseVersion, data.document.attribute_path, data.newCategory); + // @ts-expect-error - loadingService private property + expect(component.loadingService.register).toHaveBeenCalled(); + // @ts-expect-error - loadingService private property + expect(component.loadingService.unregister).toHaveBeenCalled(); + expect(component.resetErrorMessages).toHaveBeenCalled(); + expect(component.reloadPage).toHaveBeenCalled(); + }); it('should set errorMessages after calling updateDocumentCategory and unregister loadingToken on finalize ' + 'when calling moveDocument and it throws an error', () => { - const document = new DocumentTreeNode(); - Object.assign(document, { - document: { - name: 'name', - type: DocumentTreeNodeType.DOCUMENT, - children: [], - document_filename: 'document_filename', - document_binary_url: 'document_binary_url', - attribute_path: 'attribute_path' - }, - newCategory: 'newCategoryId' - }); + const document = new DocumentTreeNode(); + Object.assign(document, { + document: { + name: 'name', + type: DocumentTreeNodeType.DOCUMENT, + children: [], + document_filename: 'document_filename', + document_binary_url: 'document_binary_url', + attribute_path: 'attribute_path' + }, + newCategory: 'newCategoryId' + }); - const data = { - document, - newCategory: 'newCategoryId' - }; + const data = { + document, + newCategory: 'newCategoryId' + }; - expect(component.errorMessages.length).toBe(0); - mockCaseFileViewService.updateDocumentCategory.and.returnValue(throwError({ response: 'error' })); - component.reloadPage = () => {}; - component.moveDocument(data); - expect(component.errorMessages.length).toBe(1); - }); + expect(component.errorMessages.length).toBe(0); + mockCaseFileViewService.updateDocumentCategory.and.returnValue(throwError({ response: 'error' })); + component.reloadPage = () => { }; + component.moveDocument(data); + expect(component.errorMessages.length).toBe(1); + }); it('should display the error messages', () => { component.errorMessages = ['Error 1', 'Error 2']; @@ -233,4 +242,30 @@ describe('CaseFileViewFieldComponent', () => { const errorMessagesFromElements = listElements.map(item => item.nativeElement.textContent); expect(component.errorMessages).toEqual(errorMessagesFromElements); }); + + it('should disable icp when config contains false', () => { + mockabstractConfig.getIcpEnable.and.returnValue(false); + fixture.detectChanges(); + expect(component.icpEnabled).toBeFalsy(); + }); + + it('should enable icp when config contains true', () => { + mockabstractConfig.getIcpEnable.and.returnValue(true); + fixture.detectChanges(); + expect(component.icpEnabled).toBeTruthy(); + }); + + it('should return false if jurisdiction value is not present', () => { + mockabstractConfig.getIcpJurisdictions.and.returnValue(['FAKE']); + fixture.detectChanges(); + const callIcpEnabled = component.isIcpEnabled(); + expect(callIcpEnabled).toBeFalsy(); + }); + + it('should return true if jurisdiction is empty', () => { + mockabstractConfig.getIcpJurisdictions.and.returnValue([]); + fixture.detectChanges(); + const callIcpEnabled = component.isIcpEnabled(); + expect(callIcpEnabled).toBeTruthy(); + }); }); diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.ts index 4cea9974c4..8a4a6135d7 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/case-file-view/case-file-view-field.component.ts @@ -6,6 +6,8 @@ import { CaseField } from '../../../domain'; import { CaseFileViewDocument, CategoriesAndDocuments, DocumentTreeNode } from '../../../domain/case-file-view'; import { UserInfo } from '../../../domain/user/user-info.model'; import { CaseFileViewService, DocumentManagementService, LoadingService, SessionStorageService } from '../../../services'; +import { AbstractAppConfig } from '../../../../app.config'; +import { CaseNotifier } from '../../case-editor/services'; @Component({ selector: 'ccd-case-file-view-field', @@ -22,13 +24,17 @@ export class CaseFileViewFieldComponent implements OnInit, AfterViewInit, OnDest public errorMessages = [] as string[]; private caseVersion: number; public caseField: CaseField; + public icp_jurisdictions: string[] = []; + public icpEnabled: boolean = false; constructor(private readonly elementRef: ElementRef, private readonly route: ActivatedRoute, private caseFileViewService: CaseFileViewService, private documentManagementService: DocumentManagementService, private readonly loadingService: LoadingService, - private readonly sessionStorageService: SessionStorageService + private readonly sessionStorageService: SessionStorageService, + private readonly caseNotifier: CaseNotifier, + private readonly abstractConfig: AbstractAppConfig, ) { } public ngOnInit(): void { @@ -47,6 +53,8 @@ export class CaseFileViewFieldComponent implements OnInit, AfterViewInit, OnDest const acls = this.caseField.acls.filter(acl => userInfo.roles.includes(acl.role)); // As there can be more than one intersecting role, if any acls are update: true this.allowMoving = acls.some(acl => acl.update); + this.icp_jurisdictions = this.abstractConfig.getIcpJurisdictions(); + this.icpEnabled = this.abstractConfig.getIcpEnable(); } public ngAfterViewInit(): void { @@ -68,7 +76,7 @@ export class CaseFileViewFieldComponent implements OnInit, AfterViewInit, OnDest documentTreeContainerWidth }; }), - takeUntil(mouseup$)); + takeUntil(mouseup$)); } ) ); @@ -105,7 +113,7 @@ export class CaseFileViewFieldComponent implements OnInit, AfterViewInit, OnDest this.resetErrorMessages(); this.reloadPage(); } - }); + }); } public reloadPage(): void { @@ -121,4 +129,9 @@ export class CaseFileViewFieldComponent implements OnInit, AfterViewInit, OnDest this.categoriesAndDocumentsSubscription.unsubscribe(); } } + + public isIcpEnabled(): boolean { + return this.icpEnabled && ((this.icp_jurisdictions?.length < 1) || this.icp_jurisdictions.includes( + this.caseNotifier?.cachedCaseView?.case_type?.jurisdiction.id)); + } } diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.spec.ts index 072a7980e2..0ee80f99ff 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.spec.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.spec.ts @@ -73,7 +73,7 @@ describe('WriteLinkedCasesFieldComponent', () => { cancelled, validate: (caseEventData: CaseEventData) => of(caseEventData), saveDraft: (_: CaseEventData) => of(someObservable), - caseDetails: { case_id: '1234567812345678', tabs: [], metadataFields: [caseField2] }, + caseDetails: { case_id: '1234567812345678', tabs: [], metadataFields: [caseField2] } }; route = { params: of({ id: 123 }), @@ -202,7 +202,7 @@ describe('WriteLinkedCasesFieldComponent', () => { parent_category: '', active_flag: 'Y', child_nodes: null, - from: 'exui-default', + from: 'exui-default' }, { key: 'bail', @@ -216,7 +216,7 @@ describe('WriteLinkedCasesFieldComponent', () => { parent_category: '', active_flag: 'Y', child_nodes: null, - from: 'exui-default', + from: 'exui-default' }, { key: 'other', @@ -230,8 +230,8 @@ describe('WriteLinkedCasesFieldComponent', () => { parent_category: '', active_flag: 'Y', child_nodes: null, - from: 'exui-default', - }, + from: 'exui-default' + } ] }; @@ -248,9 +248,8 @@ describe('WriteLinkedCasesFieldComponent', () => { service_id: 39, service_short_description: 'short descr', sub_business_area: 'buss area' - } - ] + ]; beforeEach(waitForAsync(() => { appConfig = createSpyObj('appConfig', ['getRDCommonDataApiUrl']); @@ -298,9 +297,9 @@ describe('WriteLinkedCasesFieldComponent', () => { }); it('should initialise get OrgService', () => { - spyOn(component, 'getLinkedCaseReasons').and.returnValue(of([])); + spyOn(component, 'getLinkedCaseReasons').and.returnValue(of(serviceOrgData)); component.getOrgService(); - expect(component.getLinkedCaseReasons).toHaveBeenCalled(); + expect(component.getLinkedCaseReasons).toHaveBeenCalledWith(serviceOrgData[0].service_code); }); it('should initialise case details', () => { diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.ts index 92135e8159..0e16f51629 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/linked-cases/write-linked-cases-field.component.ts @@ -92,28 +92,27 @@ export class WriteLinkedCasesFieldComponent extends AbstractFieldWriteComponent } } - public getLinkedCaseReasons(serviceId: number): void { + public getLinkedCaseReasons(serviceId: string): void { const reasonCodeAPIurl = `${this.appConfig.getRDCommonDataApiUrl()}/lov/categories/CaseLinkingReasonCode?serviceId=${serviceId}`; this.commonDataService.getRefData(reasonCodeAPIurl).subscribe({ - next: reasons => { + next: (reasons) => { // Sort in ascending order const linkCaseReasons = reasons.list_of_values.sort((a, b) => (a.value_en > b.value_en) ? 1 : -1); - this.linkedCasesService.linkCaseReasons = linkCaseReasons?.filter(reason => reason.value_en !== 'Other'); + this.linkedCasesService.linkCaseReasons = linkCaseReasons?.filter((reason) => reason.value_en !== 'Other'); // Move Other option to the end of the list - this.linkedCasesService.linkCaseReasons.push(linkCaseReasons?.find(reason => reason.value_en === 'Other')); + this.linkedCasesService.linkCaseReasons.push(linkCaseReasons?.find((reason) => reason.value_en === 'Other')); } }); } getOrgService(): void { const servicesApiUrl = `refdata/location/orgServices?ccdCaseType=${this.caseDetails?.case_type?.id}`; - this.commonDataService.getServiceOrgData(servicesApiUrl).subscribe(result => { - result.forEach(ids => { - this.getLinkedCaseReasons(ids.service_id); - }) - - }) + this.commonDataService.getServiceOrgData(servicesApiUrl).subscribe((result) => { + result.forEach((ids) => { + this.getLinkedCaseReasons(ids.service_code); + }); + }); } public proceedToNextPage(): void { diff --git a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/waystopay/waystopay-field.component.spec.ts b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/waystopay/waystopay-field.component.spec.ts index be9ec9a499..8d7d498bbf 100644 --- a/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/waystopay/waystopay-field.component.spec.ts +++ b/projects/ccd-case-ui-toolkit/src/lib/shared/components/palette/waystopay/waystopay-field.component.spec.ts @@ -75,7 +75,9 @@ const APP_CONFIG: AbstractAppConfig = { getCaseDataStoreApiUrl: () => 'case_data_store_api_url', getWAServiceConfig: () => 'waServiceConfig', getEnableRestrictedCaseAccessConfig: () => true, - getEnableCaseFileViewVersion1_1: () => true + getEnableCaseFileViewVersion1_1: () => true, + getIcpJurisdictions: () => ['IA'], + getIcpEnable: () => true, }; let paymentWebComponentMock; diff --git a/yarn-audit-known-issues b/yarn-audit-known-issues index 79256b8990..069aaf6ae1 100644 --- a/yarn-audit-known-issues +++ b/yarn-audit-known-issues @@ -1 +1 @@ -{"actions":[],"advisories":{},"muted":[],"metadata":{"vulnerabilities":{"info":0,"low":0,"moderate":0,"high":0,"critical":0},"dependencies":0,"devDependencies":0,"optionalDependencies":0,"totalDependencies":0}} +{"actions":[],"advisories":{"1088948":{"findings":[{"version":"9.6.0","paths":["json-server>update-notifier>latest-version>package-json>got"]}],"metadata":null,"vulnerable_versions":"<11.8.5","module_name":"got","severity":"moderate","github_advisory_id":"GHSA-pfrx-2q88-qq97","cves":["CVE-2022-33987"],"access":"public","patched_versions":">=11.8.5","cvss":{"score":5.3,"vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"},"updated":"2023-01-27T05:05:01.000Z","recommendation":"Upgrade to version 11.8.5 or later","cwe":[],"found_by":null,"deleted":null,"id":1088948,"references":"- https://nvd.nist.gov/vuln/detail/CVE-2022-33987\n- https://github.com/sindresorhus/got/pull/2047\n- https://github.com/sindresorhus/got/compare/v12.0.3...v12.1.0\n- https://github.com/sindresorhus/got/commit/861ccd9ac2237df762a9e2beed7edd88c60782dc\n- https://github.com/sindresorhus/got/releases/tag/v11.8.5\n- https://github.com/sindresorhus/got/releases/tag/v12.1.0\n- https://github.com/advisories/GHSA-pfrx-2q88-qq97","created":"2022-06-19T00:00:21.000Z","reported_by":null,"title":"Got allows a redirect to a UNIX socket","npm_advisory_id":null,"overview":"The got package before 11.8.5 and 12.1.0 for Node.js allows a redirect to a UNIX socket.","url":"https://github.com/advisories/GHSA-pfrx-2q88-qq97"},"1089189":{"findings":[{"version":"1.24.1","paths":["ngx-md>prismjs"]}],"metadata":null,"vulnerable_versions":"<1.25.0","module_name":"prismjs","severity":"moderate","github_advisory_id":"GHSA-hqhp-5p83-hx96","cves":["CVE-2021-3801"],"access":"public","patched_versions":">=1.25.0","cvss":{"score":6.5,"vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H"},"updated":"2023-01-29T05:02:55.000Z","recommendation":"Upgrade to version 1.25.0 or later","cwe":["CWE-400"],"found_by":null,"deleted":null,"id":1089189,"references":"- https://nvd.nist.gov/vuln/detail/CVE-2021-3801\n- https://github.com/prismjs/prism/commit/0ff371bb4775a131634f47d0fe85794c547232f9\n- https://huntr.dev/bounties/8c16ab31-6eb6-46d1-b9a4-387222fe1b8a\n- https://github.com/advisories/GHSA-hqhp-5p83-hx96","created":"2021-09-20T20:44:48.000Z","reported_by":null,"title":"prismjs Regular Expression Denial of Service vulnerability","npm_advisory_id":null,"overview":"Prism is a syntax highlighting library. The prismjs package is vulnerable to ReDoS (regular expression denial of service). An attacker that is able to provide a crafted HTML comment as input may cause an application to consume an excessive amount of CPU.","url":"https://github.com/advisories/GHSA-hqhp-5p83-hx96"},"1090424":{"findings":[{"version":"1.24.1","paths":["ngx-md>prismjs"]}],"metadata":null,"vulnerable_versions":">=1.14.0 <1.27.0","module_name":"prismjs","severity":"high","github_advisory_id":"GHSA-3949-f494-cm99","cves":["CVE-2022-23647"],"access":"public","patched_versions":">=1.27.0","cvss":{"score":7.5,"vectorString":"CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:L/A:L"},"updated":"2023-02-03T05:06:26.000Z","recommendation":"Upgrade to version 1.27.0 or later","cwe":["CWE-79"],"found_by":null,"deleted":null,"id":1090424,"references":"- https://github.com/PrismJS/prism/security/advisories/GHSA-3949-f494-cm99\n- https://nvd.nist.gov/vuln/detail/CVE-2022-23647\n- https://github.com/PrismJS/prism/pull/3341\n- https://github.com/PrismJS/prism/commit/e002e78c343154e1c0ddf9d6a0bb85689e1a5c7c\n- https://github.com/advisories/GHSA-3949-f494-cm99","created":"2022-02-22T19:32:18.000Z","reported_by":null,"title":"Cross-site Scripting in Prism","npm_advisory_id":null,"overview":"### Impact\nPrism's [Command line plugin](https://prismjs.com/plugins/command-line/) can be used by attackers to achieve an XSS attack. The Command line plugin did not properly escape its output, leading to the input text being inserted into the DOM as HTML code.\n\nServer-side usage of Prism is not impacted. Websites that do not use the Command Line plugin are also not impacted.\n\n### Patches\nThis bug has been fixed in v1.27.0.\n\n### Workarounds\nDo not use the Command line plugin on untrusted inputs, or sanitized all code blocks (remove all HTML code text) from all code blocks that use the Command line plugin.\n\n### References\n- https://github.com/PrismJS/prism/pull/3341","url":"https://github.com/advisories/GHSA-3949-f494-cm99"},"1095051":{"findings":[{"version":"0.7.0","paths":["marked","ngx-md>marked"]}],"metadata":null,"vulnerable_versions":"<4.0.10","module_name":"marked","severity":"high","github_advisory_id":"GHSA-rrrm-qjm4-v8hf","cves":["CVE-2022-21680"],"access":"public","patched_versions":">=4.0.10","cvss":{"score":7.5,"vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"},"updated":"2023-11-29T20:51:52.000Z","recommendation":"Upgrade to version 4.0.10 or later","cwe":["CWE-400","CWE-1333"],"found_by":null,"deleted":null,"id":1095051,"references":"- https://github.com/markedjs/marked/security/advisories/GHSA-rrrm-qjm4-v8hf\n- https://nvd.nist.gov/vuln/detail/CVE-2022-21680\n- https://github.com/markedjs/marked/commit/c4a3ccd344b6929afa8a1d50ac54a721e57012c0\n- https://github.com/markedjs/marked/releases/tag/v4.0.10\n- https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AIXDMC3CSHYW3YWVSQOXAWLUYQHAO5UX/\n- https://github.com/advisories/GHSA-rrrm-qjm4-v8hf","created":"2022-01-14T21:04:41.000Z","reported_by":null,"title":"Inefficient Regular Expression Complexity in marked","npm_advisory_id":null,"overview":"### Impact\n\n_What kind of vulnerability is it?_\n\nDenial of service.\n\nThe regular expression `block.def` may cause catastrophic backtracking against some strings.\nPoC is the following.\n\n```javascript\nimport * as marked from \"marked\";\n\nmarked.parse(`[x]:${' '.repeat(1500)}x ${' '.repeat(1500)} x`);\n```\n\n_Who is impacted?_\n\nAnyone who runs untrusted markdown through marked and does not use a worker with a time limit.\n\n### Patches\n\n_Has the problem been patched?_\n\nYes\n\n_What versions should users upgrade to?_\n\n4.0.10\n\n### Workarounds\n\n_Is there a way for users to fix or remediate the vulnerability without upgrading?_\n\nDo not run untrusted markdown through marked or run marked on a [worker](https://marked.js.org/using_advanced#workers) thread and set a reasonable time limit to prevent draining resources.\n\n### References\n\n_Are there any links users can visit to find out more?_\n\n- https://marked.js.org/using_advanced#workers\n- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS\n\n### For more information\n\nIf you have any questions or comments about this advisory:\n\n* Open an issue in [marked](https://github.com/markedjs/marked)\n","url":"https://github.com/advisories/GHSA-rrrm-qjm4-v8hf"},"1095052":{"findings":[{"version":"0.7.0","paths":["marked","ngx-md>marked"]}],"metadata":null,"vulnerable_versions":"<4.0.10","module_name":"marked","severity":"high","github_advisory_id":"GHSA-5v2h-r2cx-5xgj","cves":["CVE-2022-21681"],"access":"public","patched_versions":">=4.0.10","cvss":{"score":7.5,"vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"},"updated":"2023-11-29T20:51:17.000Z","recommendation":"Upgrade to version 4.0.10 or later","cwe":["CWE-1333"],"found_by":null,"deleted":null,"id":1095052,"references":"- https://github.com/markedjs/marked/security/advisories/GHSA-5v2h-r2cx-5xgj\n- https://nvd.nist.gov/vuln/detail/CVE-2022-21681\n- https://github.com/markedjs/marked/commit/8f806573a3f6c6b7a39b8cdb66ab5ebb8d55a5f5\n- https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/AIXDMC3CSHYW3YWVSQOXAWLUYQHAO5UX/\n- https://github.com/markedjs/marked/commit/c4a3ccd344b6929afa8a1d50ac54a721e57012c0\n- https://github.com/advisories/GHSA-5v2h-r2cx-5xgj","created":"2022-01-14T21:04:46.000Z","reported_by":null,"title":"Inefficient Regular Expression Complexity in marked","npm_advisory_id":null,"overview":"### Impact\n\n_What kind of vulnerability is it?_\n\nDenial of service.\n\nThe regular expression `inline.reflinkSearch` may cause catastrophic backtracking against some strings.\nPoC is the following.\n\n```javascript\nimport * as marked from 'marked';\n\nconsole.log(marked.parse(`[x]: x\n\n\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](\\\\[\\\\](`));\n```\n\n_Who is impacted?_\n\nAnyone who runs untrusted markdown through marked and does not use a worker with a time limit.\n\n### Patches\n\n_Has the problem been patched?_\n\nYes\n\n_What versions should users upgrade to?_\n\n4.0.10\n\n### Workarounds\n\n_Is there a way for users to fix or remediate the vulnerability without upgrading?_\n\nDo not run untrusted markdown through marked or run marked on a [worker](https://marked.js.org/using_advanced#workers) thread and set a reasonable time limit to prevent draining resources.\n\n### References\n\n_Are there any links users can visit to find out more?_\n\n- https://marked.js.org/using_advanced#workers\n- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS\n\n### For more information\n\nIf you have any questions or comments about this advisory:\n\n* Open an issue in [marked](https://github.com/markedjs/marked)\n","url":"https://github.com/advisories/GHSA-5v2h-r2cx-5xgj"},"1096570":{"findings":[{"version":"1.1.8","paths":["npm-registry-fetch>make-fetch-happen>socks-proxy-agent>socks>ip","@angular/localize>@angular/compiler-cli>chokidar>fsevents>node-gyp>make-fetch-happen>socks-proxy-agent>socks>ip"]}],"metadata":null,"vulnerable_versions":"<1.1.9","module_name":"ip","severity":"moderate","github_advisory_id":"GHSA-78xj-cgh5-2h22","cves":["CVE-2023-42282"],"access":"public","patched_versions":">=1.1.9","cvss":{"score":0,"vectorString":null},"updated":"2024-02-20T18:30:41.000Z","recommendation":"Upgrade to version 1.1.9 or later","cwe":["CWE-918"],"found_by":null,"deleted":null,"id":1096570,"references":"- https://nvd.nist.gov/vuln/detail/CVE-2023-42282\n- https://cosmosofcyberspace.github.io/npm_ip_cve/npm_ip_cve.html\n- https://github.com/JoshGlazebrook/socks/issues/93#issue-2128357447\n- https://github.com/github/advisory-database/pull/3504#issuecomment-1937179999\n- https://github.com/indutny/node-ip/pull/138\n- https://github.com/indutny/node-ip/commit/32f468f1245574785ec080705737a579be1223aa\n- https://github.com/indutny/node-ip/commit/6a3ada9b471b09d5f0f5be264911ab564bf67894\n- https://github.com/advisories/GHSA-78xj-cgh5-2h22","created":"2024-02-08T18:30:39.000Z","reported_by":null,"title":"NPM IP package incorrectly identifies some private IP addresses as public","npm_advisory_id":null,"overview":"The `isPublic()` function in the NPM package `ip` doesn't correctly identify certain private IP addresses in uncommon formats such as `0x7F.1` as private. Instead, it reports them as public by returning `true`. This can lead to security issues such as Server-Side Request Forgery (SSRF) if `isPublic()` is used to protect sensitive code paths when passed user input. Versions 1.1.9 and 2.0.1 fix the issue.","url":"https://github.com/advisories/GHSA-78xj-cgh5-2h22"},"1096727":{"findings":[{"version":"2.88.2","paths":["json-server>request"]}],"metadata":null,"vulnerable_versions":"<=2.88.2","module_name":"request","severity":"moderate","github_advisory_id":"GHSA-p8p7-x288-28g6","cves":["CVE-2023-28155"],"access":"public","patched_versions":"<0.0.0","cvss":{"score":6.1,"vectorString":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"},"updated":"2024-03-21T17:47:21.000Z","recommendation":"None","cwe":["CWE-918"],"found_by":null,"deleted":null,"id":1096727,"references":"- https://nvd.nist.gov/vuln/detail/CVE-2023-28155\n- https://github.com/request/request/issues/3442\n- https://github.com/request/request/pull/3444\n- https://doyensec.com/resources/Doyensec_Advisory_RequestSSRF_Q12023.pdf\n- https://github.com/github/advisory-database/pull/2500\n- https://github.com/cypress-io/request/blob/master/lib/redirect.js#L116\n- https://github.com/request/request/blob/master/lib/redirect.js#L111\n- https://github.com/cypress-io/request/pull/28\n- https://github.com/cypress-io/request/commit/c5bcf21d40fb61feaff21a0e5a2b3934a440024f\n- https://github.com/cypress-io/request/releases/tag/v3.0.0\n- https://security.netapp.com/advisory/ntap-20230413-0007\n- https://github.com/advisories/GHSA-p8p7-x288-28g6","created":"2023-03-16T15:30:19.000Z","reported_by":null,"title":"Server-Side Request Forgery in Request","npm_advisory_id":null,"overview":"The `request` package through 2.88.2 for Node.js and the `@cypress/request` package prior to 3.0.0 allow a bypass of SSRF mitigations via an attacker-controller server that does a cross-protocol redirect (HTTP to HTTPS, or HTTPS to HTTP).\n\nNOTE: The `request` package is no longer supported by the maintainer.","url":"https://github.com/advisories/GHSA-p8p7-x288-28g6"},"1096748":{"findings":[{"version":"7.22.8","paths":["@angular/localize>@babel/core>@babel/traverse","@angular/localize>@babel/core>@babel/helpers>@babel/traverse","@angular/localize>@angular/compiler-cli>@babel/core>@babel/helpers>@babel/traverse"]}],"metadata":null,"vulnerable_versions":"<7.23.2","module_name":"@babel/traverse","severity":"critical","github_advisory_id":"GHSA-67hx-6x53-jw92","cves":["CVE-2023-45133"],"access":"public","patched_versions":">=7.23.2","cvss":{"score":9.4,"vectorString":"CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H"},"updated":"2023-12-08T19:11:42.000Z","recommendation":"Upgrade to version 7.23.2 or later","cwe":["CWE-184","CWE-697"],"found_by":null,"deleted":null,"id":1096748,"references":"- https://github.com/babel/babel/security/advisories/GHSA-67hx-6x53-jw92\n- https://nvd.nist.gov/vuln/detail/CVE-2023-45133\n- https://github.com/babel/babel/pull/16033\n- https://github.com/babel/babel/commit/b13376b346946e3f62fc0848c1d2a23223314c82\n- https://github.com/babel/babel/releases/tag/v7.23.2\n- https://github.com/babel/babel/releases/tag/v8.0.0-alpha.4\n- https://www.debian.org/security/2023/dsa-5528\n- https://lists.debian.org/debian-lts-announce/2023/10/msg00026.html\n- https://babeljs.io/blog/2023/10/16/cve-2023-45133\n- https://github.com/advisories/GHSA-67hx-6x53-jw92","created":"2023-10-16T13:55:36.000Z","reported_by":null,"title":"Babel vulnerable to arbitrary code execution when compiling specifically crafted malicious code","npm_advisory_id":null,"overview":"### Impact\n\nUsing Babel to compile code that was specifically crafted by an attacker can lead to arbitrary code execution during compilation, when using plugins that rely on the `path.evaluate()`or `path.evaluateTruthy()` internal Babel methods.\n\nKnown affected plugins are:\n- `@babel/plugin-transform-runtime`\n- `@babel/preset-env` when using its [`useBuiltIns`](https://babeljs.io/docs/babel-preset-env#usebuiltins) option\n- Any \"polyfill provider\" plugin that depends on `@babel/helper-define-polyfill-provider`, such as `babel-plugin-polyfill-corejs3`, `babel-plugin-polyfill-corejs2`, `babel-plugin-polyfill-es-shims`, `babel-plugin-polyfill-regenerator`\n\nNo other plugins under the `@babel/` namespace are impacted, but third-party plugins might be.\n\n**Users that only compile trusted code are not impacted.**\n\n### Patches\n\nThe vulnerability has been fixed in `@babel/traverse@7.23.2`.\n\nBabel 6 does not receive security fixes anymore (see [Babel's security policy](https://github.com/babel/babel/security/policy)), hence there is no patch planned for `babel-traverse@6`.\n\n### Workarounds\n\n- Upgrade `@babel/traverse` to v7.23.2 or higher. You can do this by deleting it from your package manager's lockfile and re-installing the dependencies. `@babel/core` >=7.23.2 will automatically pull in a non-vulnerable version.\n- If you cannot upgrade `@babel/traverse` and are using one of the affected packages mentioned above, upgrade them to their latest version to avoid triggering the vulnerable code path in affected `@babel/traverse` versions:\n - `@babel/plugin-transform-runtime` v7.23.2\n - `@babel/preset-env` v7.23.2\n - `@babel/helper-define-polyfill-provider` v0.4.3\n - `babel-plugin-polyfill-corejs2` v0.4.6\n - `babel-plugin-polyfill-corejs3` v0.8.5\n - `babel-plugin-polyfill-es-shims` v0.10.0\n - `babel-plugin-polyfill-regenerator` v0.5.3","url":"https://github.com/advisories/GHSA-67hx-6x53-jw92"}},"muted":[],"metadata":{"vulnerabilities":{"info":0,"low":0,"moderate":5,"high":5,"critical":3},"dependencies":621,"devDependencies":2,"optionalDependencies":0,"totalDependencies":623}}