Skip to content
Permalink
Browse files Browse the repository at this point in the history
feat: add searchPattern as an option and restrict default search patt…
…ern (#75)

With version 15, the behavior of the environment variable lookup changed to try to find occurrences in the whole workspace. This could lead to a potential information disclosure vulnerability, by exposing environment variables meant for a backend/Node.js application.
This PR mitigates this possibility, by restricting the lookup path of environment variables to `sourceRoot` of the related angular.json project and excluding files having `server` in their name (a common pattern for universal apps).
  • Loading branch information
kyubisation committed Mar 22, 2023
1 parent caf4e17 commit d701f51
Show file tree
Hide file tree
Showing 44 changed files with 914 additions and 148 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -10,6 +10,7 @@ pids
*.pid
*.seed
*.pid.lock
test/test-project-*

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
Expand Down
1 change: 1 addition & 0 deletions .nvmrc
@@ -0,0 +1 @@
18
32 changes: 27 additions & 5 deletions README.md
Expand Up @@ -20,13 +20,33 @@ Starting with version 13, there are experimental builders for the `build` and `s
To install the experimental builders run `ng add angular-server-side-configuration` and answer
`Would you like to use the experimental builders for build and serve?` with `y(es)`.

## Changes with version 15.1

With the change in version 15 to search all files for environment variables, a potential
information disclosure vulnerability was introduced, as unintended environment variables might
be exposed.

You might be affected, if you use environment variables in your angular.json workspace that expose
application internals (like used services/tools) or secrets that are also available on the
deployed environment (e.g. a monorepo that also contains a Node.js backend, which is deployed in
the same system/container/pod as the frontend bundle).

This should have little to no impact, if you only have a simple angular.json workspace without
a backend component.

With 15.1 this risk is mitigated, as the lookup path is restricted by adding an option
`searchPattern` which defaults to `{sourceRoot}/**/!(*server*).ts` (only search `sourceRoot`
of the related angular.json project and exclude files with `server` in the name).


## Changes with version 15

With version 15 of the Angular CLI, environment files are no longer generated by default. In
order to adapt, using `ng add angular-server-side-configuration` will try to add the import in
either `app.module.ts`, `app.components.ts` or `main.ts` depending on availability. The ngssc
builder will also now search all files for environment variable usages instead of just the
defined environment file. Due to this, the `ngsscEnvironmentFile` option can be removed.
either `environment.prod.ts`, `environment.ts`, `app.module.ts`, `app.components.ts` or `main.ts`
depending on availability. The ngssc builder will also now search all files for environment
variable usages instead of just the defined environment file. Due to this, the
`ngsscEnvironmentFile` option can be removed.

## Getting Started

Expand Down Expand Up @@ -74,7 +94,9 @@ used environment variables and generate an [ngssc.json](#ngsscjson) in the defin
"browserTarget": "your-project-name:build",
// Optional
// (Defaults to the basename of the index option of the browser target)
"filePattern": "index.html"
"filePattern": "index.html",
// (Defaults to {sourceRoot}/**/!(*server*).ts)
"searchPattern": "src/environments/environment*.ts"
},
"configurations": {
"production": {
Expand All @@ -93,7 +115,7 @@ used environment variables and generate an [ngssc.json](#ngsscjson) in the defin

To run the ngssc build, run the command `ng run your-project-name:ngsscbuild:production`.

### environment.prod.ts
### TypeScript files

angular-server-side-configuration supports two variants for using environment variables:
process.env._ or NG_ENV._
Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -11,6 +11,7 @@
"build:demo-i18n": "ng build ngssc-builders-app -c i18n",
"build": "run-s build:*",
"format": "prettier --write **/*.{js,ts,css,scss,json,md,html}",
"pretest:lib": "yarn -s build:lib",
"test:lib": "node test/jasmine.js",
"test:app": "ng test ngssc-app --configuration=ci",
"test:cli": "cd cli && go test",
Expand Down Expand Up @@ -78,6 +79,7 @@
"cross-env": "^7.0.3",
"eslint": "^8.28.0",
"eslint-plugin-import": "2.26.0",
"glob": "^9.3.1",
"jasmine": "~4.5.0",
"jasmine-core": "~4.5.0",
"karma": "~6.4.0",
Expand Down
Expand Up @@ -64,7 +64,9 @@
}
},
"additionalProperties": false,
"required": ["input"]
"required": [
"input"
]
},
{
"type": "string",
Expand Down Expand Up @@ -100,7 +102,9 @@
}
},
"additionalProperties": false,
"required": ["input"]
"required": [
"input"
]
},
{
"type": "string",
Expand All @@ -114,7 +118,12 @@
"description": "The stylesheet language to use for the application's inline component styles.",
"type": "string",
"default": "css",
"enum": ["css", "less", "sass", "scss"]
"enum": [
"css",
"less",
"sass",
"scss"
]
},
"stylePreprocessorOptions": {
"description": "Options to pass to style preprocessors.",
Expand Down Expand Up @@ -286,13 +295,21 @@
"i18nMissingTranslation": {
"type": "string",
"description": "How to handle missing translations for i18n.",
"enum": ["warning", "error", "ignore"],
"enum": [
"warning",
"error",
"ignore"
],
"default": "warning"
},
"i18nDuplicateTranslation": {
"type": "string",
"description": "How to handle duplicate translations for i18n.",
"enum": ["warning", "error", "ignore"],
"enum": [
"warning",
"error",
"ignore"
],
"default": "warning"
},
"localize": {
Expand Down Expand Up @@ -322,7 +339,12 @@
"type": "string",
"description": "Define the output filename cache-busting hashing mode.",
"default": "none",
"enum": ["none", "all", "media", "bundles"]
"enum": [
"none",
"all",
"media",
"bundles"
]
},
"poll": {
"type": "number",
Expand Down Expand Up @@ -389,7 +411,9 @@
"description": "The output path of the application's generated HTML index file. The full provided path will be used and will be considered relative to the application's configured output path."
}
},
"required": ["input"]
"required": [
"input"
]
}
]
},
Expand All @@ -414,7 +438,11 @@
"type": "string",
"description": "Define the crossorigin attribute setting of elements that provide CORS support.",
"default": "none",
"enum": ["none", "anonymous", "use-credentials"]
"enum": [
"none",
"anonymous",
"use-credentials"
]
},
"allowedCommonJsDependencies": {
"description": "A list of CommonJS packages that are allowed to be used without a build time warning.",
Expand All @@ -432,10 +460,20 @@
"type": "string",
"description": "The file pattern, into which the environment variables should be inserted during ngssc insert (Defaults to index.html)",
"default": ""
},
"searchPattern": {
"type": "string",
"description": "The search pattern to use when searching for environment variable occurrences (Defaults to {sourceRoot}/**/!(*server*).ts)",
"default": ""
}
},
"additionalProperties": false,
"required": ["outputPath", "index", "main", "tsConfig"],
"required": [
"outputPath",
"index",
"main",
"tsConfig"
],
"definitions": {
"assetPattern": {
"oneOf": [
Expand Down Expand Up @@ -468,7 +506,11 @@
}
},
"additionalProperties": false,
"required": ["glob", "input", "output"]
"required": [
"glob",
"input",
"output"
]
},
{
"type": "string"
Expand All @@ -490,7 +532,10 @@
}
},
"additionalProperties": false,
"required": ["src", "replaceWith"]
"required": [
"src",
"replaceWith"
]
},
{
"type": "object",
Expand All @@ -505,7 +550,10 @@
}
},
"additionalProperties": false,
"required": ["replace", "with"]
"required": [
"replace",
"with"
]
}
]
},
Expand All @@ -515,7 +563,15 @@
"type": {
"type": "string",
"description": "The type of budget.",
"enum": ["all", "allScript", "any", "anyScript", "anyComponentStyle", "bundle", "initial"]
"enum": [
"all",
"allScript",
"any",
"anyScript",
"anyComponentStyle",
"bundle",
"initial"
]
},
"name": {
"type": "string",
Expand Down Expand Up @@ -551,7 +607,9 @@
}
},
"additionalProperties": false,
"required": ["type"]
"required": [
"type"
]
}
}
}
}
Expand Up @@ -33,7 +33,7 @@ export function ngsscServeWebpackBrowser(
} = {}
): Observable<DevServerBuilderOutput> {
transforms.indexHtml = async (content: string) => {
const ngsscContext = await detectVariables(context);
const ngsscContext = await detectVariables(context, options.searchPattern);
const ngssc = buildNgssc(ngsscContext, options);
const populatedVariables = populateVariables(ngssc.environmentVariables);
context.logger.info(
Expand Down
Expand Up @@ -104,8 +104,15 @@
"type": "string",
"description": "The file pattern, into which the environment variables should be inserted during ngssc insert (Defaults to index.html)",
"default": ""
},
"searchPattern": {
"type": "string",
"description": "The search pattern to use when searching for environment variable occurrences (Defaults to {sourceRoot}/**/!(*server*).ts)",
"default": ""
}
},
"additionalProperties": false,
"required": ["browserTarget"]
}
"required": [
"browserTarget"
]
}

0 comments on commit d701f51

Please sign in to comment.