Skip to content
Merged
45,892 changes: 15,148 additions & 30,744 deletions package-lock.json

Large diffs are not rendered by default.

18 changes: 12 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"dependencies": {
"@angular/animations": "^13.0.0",
"@angular/cdk": "^13.0.0",
"@angular/cli": "^21.0.5",
"@angular/common": "^13.0.0",
"@angular/compiler": "^13.0.0",
"@angular/core": "^13.0.0",
Expand All @@ -28,28 +27,29 @@
"@grafana/faro-web-tracing": "^1.12.2",
"@ngneat/until-destroy": "^10.0.0-beta.0",
"d3": "^7.5.0",
"exceljs": "^4.4.0",
"js-yaml": "^4.1.1",
"markdown-it": "^13.0.1",
"rxjs": "~7.5.0",
"tslib": "^2.8.1",
"xlsx": "^0.18.5",
"yaml": "^2.8.1",
"yamljs": "^0.3.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^21.0.5",
"@angular-devkit/build-angular": "^13.3.11",
"@angular-eslint/builder": "^13.0.0",
"@angular-eslint/eslint-plugin": "^13.0.0",
"@angular-eslint/eslint-plugin-template": "^13.0.0",
"@angular-eslint/schematics": "^21.1.0",
"@angular-eslint/schematics": "^13.0.0",
"@angular-eslint/template-parser": "^13.0.0",
"@angular/cli": "^13.3.11",
"@angular/compiler-cli": "^13.0.0",
"@grafana/faro-webpack-plugin": "^0.1.1",
"@types/d3": "^7.4.0",
"@types/jasmine": "~3.10.0",
"@types/js-yaml": "^4.0.9",
"@types/markdown-it": "^12.2.3",
"@types/markdown-it": "12.2.0",
"@types/node": "^12.11.1",
"@types/yamljs": "^0.2.31",
"@typescript-eslint/eslint-plugin": "5.27.1",
Expand All @@ -70,7 +70,13 @@
"prettier": "^2.7.1",
"prettier-eslint": "^15.0.1",
"qs": "^6.11.0",
"typescript": "^4.6.4"
"typescript": "~4.6.4"
},
"overrides": {
"axios": ">=1.8.2",
"form-data": ">=4.0.4",
"@types/d3-dispatch": "3.0.6",
"@types/linkify-it": "3.0.5"
},
"browser": {
"fs": false,
Expand Down
3 changes: 3 additions & 0 deletions src/app/pages/circular-heatmap/circular-heatmap.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,9 @@ export class CircularHeatmapComponent implements OnInit, OnDestroy {
.append('text')
.append('textPath')
.attr('text-anchor', 'middle')
// SECURITY NOTE: xlink:href usage here is safe - it references a static internal ID
// not user-controlled data. This does not expose XSS vulnerability (Dependabot #58).
// When upgrading to Angular 19+, consider using href instead of xlink:href.
.attr('xlink:href', '#segment-label-path-' + id)
.style('font-size', segmentLabelFontSize + 'px')
.attr('startOffset', function (d, i) {
Expand Down
55 changes: 48 additions & 7 deletions src/app/pages/mapping/mapping.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';
import { COMMA, ENTER } from '@angular/cdk/keycodes';
import { FormControl } from '@angular/forms';
import * as XLSX from 'xlsx';
import * as ExcelJS from 'exceljs';
import { LoaderService } from 'src/app/service/loader/data-loader.service';
import {
DialogInfo,
Expand All @@ -15,6 +15,9 @@ import { perfNow } from 'src/app/util/util';
import { SettingsService } from 'src/app/service/settings/settings.service';

const SEPARATOR = '\x1F'; // ASCII Unit Separator
const DEFAULT_COLUMN_WIDTH = 10;
const COLUMN_PADDING = 2;
const MAX_COLUMN_WIDTH = 50;

export interface MappingRow {
uuid: Uuid;
Expand Down Expand Up @@ -157,12 +160,50 @@ export class MappingComponent implements OnInit, AfterViewInit {
});
}

exportToExcel() {
let element = document.getElementById('excel-table');
const ws: XLSX.WorkSheet = XLSX.utils.table_to_sheet(element, { raw: true });
const wb: XLSX.WorkBook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
XLSX.writeFile(wb, 'DSOMM - Activities.xlsx');
async exportToExcel() {
const element = document.getElementById('excel-table');
if (!element) {
console.error('Excel table element not found');
return;
}

const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet('Sheet1');

// Extract table data
const table = element as HTMLTableElement;
const rows = Array.from(table.querySelectorAll('tr'));

rows.forEach(row => {
const cells = Array.from(row.querySelectorAll('th, td'));
const rowData = cells.map(cell => cell.textContent?.trim() || '');
worksheet.addRow(rowData);
});

// Auto-fit columns (optional, improves readability)
worksheet.columns.forEach(column => {
let maxLength = 0;
column.eachCell?.({ includeEmpty: true }, cell => {
const cellLength = cell.value ? cell.value.toString().length : DEFAULT_COLUMN_WIDTH;
if (cellLength > maxLength) {
maxLength = cellLength;
}
});
column.width = Math.min(maxLength + COLUMN_PADDING, MAX_COLUMN_WIDTH);
});

// Write file
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = window.URL.createObjectURL(blob);
const anchor = document.createElement('a');
anchor.href = url;
anchor.download = 'DSOMM - Activities.xlsx';
anchor.click();
window.URL.revokeObjectURL(url);

console.log(`${perfNow()}: Mapping: Exported to Excel`);
}

Expand Down
25 changes: 25 additions & 0 deletions src/app/util/security-audit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Security utility to validate URLs before binding to SVG/MathML attributes
* Addresses Dependabot Alert #58 (Angular XSS via SVG attributes)
*/
export class SecurityAudit {
/**
* Validates that a URL is safe for use in href/xlink:href attributes
* Blocks javascript:, data:, and other dangerous protocols
*/
static isSafeUrl(url: string): boolean {
if (!url || typeof url !== 'string') return false;

const dangerous = ['javascript:', 'data:', 'vbscript:', 'file:'];
const lowerUrl = url.trim().toLowerCase();

return !dangerous.some(protocol => lowerUrl.startsWith(protocol));
}

/**
* Sanitizes a URL for safe use, returns empty string if dangerous
*/
static sanitizeUrl(url: string): string {
return this.isSafeUrl(url) ? url : '';
}
}
Binary file modified src/assets/images/Dark-mode-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/assets/images/logo-image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/assets/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/assets/images/sponsors/heroku.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@
<title>DSOMM</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Content Security Policy for XSS mitigation (Dependabot #58)
Note: 'unsafe-inline' and 'unsafe-eval' are required for Angular 13.
These will be removed when upgrading to Angular 19+ which supports stricter CSP. -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdnjs.cloudflare.com;
img-src 'self' data: https:;
font-src 'self' data: https://fonts.gstatic.com;
connect-src 'self' https:;
object-src 'none';
base-uri 'self';" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link
Expand Down