mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
The `localize-translate` CLI tool uses the `locale` field from translation files to expand the `{{LOCALE}}` placeholder in the output directory. It failed to sanitize `locale` input, allowing malicious translations to write files outside of the configured output directory.
This change mitigates this issue by combining.
Closes #67906
(cherry picked from commit 7871093822)
53 lines
2.5 KiB
TypeScript
53 lines
2.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.dev/license
|
|
*/
|
|
import {
|
|
absoluteFrom,
|
|
getFileSystem,
|
|
PathManipulation,
|
|
} from '@angular/compiler-cli/src/ngtsc/file_system';
|
|
import {runInEachFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/testing';
|
|
|
|
import {getOutputPathFn} from '../../src/translate/output_path';
|
|
|
|
runInEachFileSystem(() => {
|
|
let fs: PathManipulation;
|
|
beforeEach(() => (fs = getFileSystem()));
|
|
|
|
describe('getOutputPathFn()', () => {
|
|
it('should return a function that joins the `outputPath` and the `relativePath`', () => {
|
|
const fn = getOutputPathFn(fs, absoluteFrom('/output/path'));
|
|
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output/path/relative/path'));
|
|
expect(fn('en', '../parent/path')).toEqual(absoluteFrom('/output/parent/path'));
|
|
});
|
|
|
|
it('should return a function that interpolates the `{{LOCALE}}` in the middle of the `outputPath`', () => {
|
|
const fn = getOutputPathFn(fs, absoluteFrom('/output/{{LOCALE}}/path'));
|
|
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output/en/path/relative/path'));
|
|
expect(fn('fr', 'relative/path')).toEqual(absoluteFrom('/output/fr/path/relative/path'));
|
|
});
|
|
|
|
it('should return a function that interpolates the `{{LOCALE}}` in the middle of a path segment in the `outputPath`', () => {
|
|
const fn = getOutputPathFn(fs, absoluteFrom('/output-{{LOCALE}}-path'));
|
|
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output-en-path/relative/path'));
|
|
expect(fn('fr', 'relative/path')).toEqual(absoluteFrom('/output-fr-path/relative/path'));
|
|
});
|
|
|
|
it('should return a function that interpolates the `{{LOCALE}}` at the end of the `outputPath`', () => {
|
|
const fn = getOutputPathFn(fs, absoluteFrom('/output/{{LOCALE}}'));
|
|
expect(fn('en', 'relative/path')).toEqual(absoluteFrom('/output/en/relative/path'));
|
|
expect(fn('fr', 'relative/path')).toEqual(absoluteFrom('/output/fr/relative/path'));
|
|
});
|
|
|
|
it('should throw if the locale contains path traversal characters', () => {
|
|
const fn = getOutputPathFn(fs, absoluteFrom('/output/{{LOCALE}}'));
|
|
expect(() => fn('../escaped', 'relative/path')).toThrowError(/Invalid Locale/);
|
|
expect(() => fn('foo/bar', 'relative/path')).toThrowError(/Invalid Locale/);
|
|
expect(() => fn('foo\\bar', 'relative/path')).toThrowError(/Invalid Locale/);
|
|
});
|
|
});
|
|
});
|