@db-ux/core-components 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { glob } from 'glob';
2
- import { exec } from 'node:child_process';
2
+ import { execFile } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
 
5
5
  import { dirname } from 'path';
@@ -8,12 +8,16 @@ import { fileURLToPath } from 'url';
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = dirname(__filename).replaceAll('\\', '/');
10
10
 
11
- const execAsync = promisify(exec);
11
+ // Security: Using execFile instead of exec to eliminate shell injection risks
12
+ // execFile directly executes the binary without involving a shell
13
+ const execFileAsync = promisify(execFile);
12
14
 
13
15
  const generateFonts = async () => {
14
16
  console.log('Generating EU fonts...');
15
17
  try {
16
- await execAsync('pyftsubset --help');
18
+ // Security: Using array arguments instead of concatenated string
19
+ // This prevents shell interpretation of special characters
20
+ await execFileAsync('pyftsubset', ['--help']);
17
21
  } catch (e) {
18
22
  console.warn(
19
23
  'You need to install pyftsubset. Check packages/foundations/assets/fonts/README.md for more information.'
@@ -22,19 +26,28 @@ const generateFonts = async () => {
22
26
 
23
27
  try {
24
28
  const files = await glob(`${__dirname}/*.ttf`);
25
- const commands = files.map((file) =>
26
- [
27
- 'pyftsubset',
29
+
30
+ for (const file of files) {
31
+ // Security: Validate that the file is within the expected directory
32
+ // and has the expected extension to prevent path traversal attacks
33
+ if (!file.startsWith(__dirname) || !file.endsWith('.ttf')) {
34
+ console.warn(`Skipping potentially unsafe file path: ${file}`);
35
+ continue;
36
+ }
37
+
38
+ // Security: Arguments are passed as separate array elements
39
+ // No shell concatenation means no risk of command injection
40
+ const args = [
28
41
  file,
29
42
  '--layout-features=*',
30
43
  '--flavor=woff2',
31
44
  `--unicodes-file=${__dirname}/unicode-eu.txt`,
32
45
  `--output-file=${file.replace('.ttf', '-EU.woff2')}`
33
- ].join(' ')
34
- );
46
+ ];
35
47
 
36
- for (const command of commands) {
37
- const { stdout, stderr } = await execAsync(command);
48
+ // Security: execFile provides better performance and type safety
49
+ // as it doesn't spawn a shell process
50
+ const { stdout, stderr } = await execFileAsync('pyftsubset', args);
38
51
  if (stdout) console.log(`stdout: ${stdout}`);
39
52
  if (stderr) console.error(`stderr: ${stderr}`);
40
53
  }
@@ -1094,14 +1094,11 @@ summary[aria-disabled=true]) {
1094
1094
  text-overflow: ellipsis;
1095
1095
  }
1096
1096
  .db-custom-select [id$=-placeholder] {
1097
- display: none;
1098
- margin-inline-end: calc(var(--db-icon-font-size) + var(--db-spacing-fixed-sm));
1099
- }
1100
- .db-custom-select:has(.db-custom-select-form-field:empty), .db-custom-select:has(.db-custom-select-form-field > :empty) {
1101
1097
  --db-form-component-padding-inline-end: calc(var(--db-icon-font-size) + var(--db-spacing-fixed-sm) + var(--db-spacing-fixed-xs));
1098
+ margin-inline-end: calc(var(--db-icon-font-size) + var(--db-spacing-fixed-sm));
1102
1099
  }
1103
- .db-custom-select:has(.db-custom-select-form-field:empty) [id$=-placeholder], .db-custom-select:has(.db-custom-select-form-field > :empty) [id$=-placeholder] {
1104
- display: block;
1100
+ .db-custom-select:has(summary span) [id$=-placeholder] {
1101
+ display: none;
1105
1102
  }
1106
1103
  .db-custom-select > db-button > .db-button[data-icon=cross][data-variant=ghost],
1107
1104
  .db-custom-select > .db-button[data-icon=cross][data-variant=ghost] {
@@ -43,19 +43,17 @@
43
43
  @include form-components.set-default-form-component(summary);
44
44
 
45
45
  [id$="-placeholder"] {
46
- display: none;
46
+ --db-form-component-padding-inline-end: #{select-components.$select-icon-padding};
47
+
47
48
  margin-inline-end: calc(
48
49
  #{form-components.$font-size-height} +
49
50
  #{variables.$db-spacing-fixed-sm}
50
51
  );
51
52
  }
52
53
 
53
- &:has(.db-custom-select-form-field:empty),
54
- &:has(.db-custom-select-form-field > :empty) {
55
- --db-form-component-padding-inline-end: #{select-components.$select-icon-padding};
56
-
54
+ &:has(summary span) {
57
55
  [id$="-placeholder"] {
58
- display: block;
56
+ display: none;
59
57
  }
60
58
  }
61
59