Skip to content

Commit

Permalink
Merge branch 'develop' into 'master' for 4.2.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
shauke committed Sep 11, 2023
2 parents 4789404 + 07f595e commit b2bc0ca
Show file tree
Hide file tree
Showing 183 changed files with 4,451 additions and 3,500 deletions.
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
/dist/**/*
!/dist/.gitignore
!/dist/entrypoint.sh
!/dist/healthcheck.js
!/dist/robots.txt

# from docs/.gitignore
Expand Down
1 change: 1 addition & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@
"max": 10
}
],
"curly": "warn",
"dot-notation": "off", // disabled in favor of @typescript-eslint/dot-notation
"eqeqeq": ["error", "always"],
"etc/no-commented-out-code": "warn",
Expand Down
1 change: 1 addition & 0 deletions .vscode/intershop.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cxml
cybersource
datepicker
decamelize
deth
directdebit
dockerignore
dockerized
Expand Down
462 changes: 243 additions & 219 deletions 3rd-party-licenses.txt

Large diffs are not rendered by default.

170 changes: 115 additions & 55 deletions CHANGELOG.md

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,23 @@ COPY templates/webpack/* /workspace/templates/webpack/
ARG testing=false
ENV TESTING=${testing}
ARG activeThemes=
RUN if [ ! -z "${activeThemes}" ]; then npm config set active-themes="${activeThemes}"; fi
RUN if [ ! -z "${activeThemes}" ]; then npm pkg set config.active-themes="${activeThemes}"; fi
RUN npm run build:multi client -- --deploy-url=DEPLOY_URL_PLACEHOLDER
COPY tsconfig.server.json server.ts /workspace/
RUN npm run build:multi server
RUN node scripts/compile-docker-scripts
COPY dist/* /workspace/dist/

FROM node:18.16.0-alpine
RUN apk add --no-cache tini
COPY --from=buildstep /workspace/dist /dist
RUN cd dist && npm install
ARG displayVersion=
LABEL displayVersion="${displayVersion}"
ENV DISPLAY_VERSION=${displayVersion} NODE_PATH=/dist/node_modules PATH=$PATH:/dist/node_modules/.bin
ENV LOG_ALL=on
EXPOSE 4200 9113
RUN mkdir /.pm2 && chmod 777 -Rf /.pm2 && touch /dist/ecosystem.yml && chmod 777 -f /dist/ecosystem.yml
USER nobody
HEALTHCHECK --interval=60s --timeout=20s --start-period=2s CMD node /dist/healthcheck.js
ENTRYPOINT ["sh","/dist/entrypoint.sh"]
ENTRYPOINT [ "/sbin/tini", "--", "sh", "/dist/entrypoint.sh" ]
1 change: 0 additions & 1 deletion dist/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/**/*
!.gitignore
!/entrypoint.sh
!/healthcheck.js
!/robots.txt
8 changes: 2 additions & 6 deletions dist/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,14 @@

set -e

trap 'echo recieved INT; exit 1' SIGINT
trap 'echo recieved TERM; exit 0' SIGTERM
trap 'echo recieved KILL; exit 1' SIGKILL

if [ -z "$*" ]
then
# use 'node dist/<theme>/run-standalone'
# use 'exec node dist/<theme>/run-standalone'
# instead of pm2 to fallback to running
# a single theme only

node dist/build-ecosystem.js
pm2-runtime dist/ecosystem.yml
exec pm2-runtime dist/ecosystem.yml
else
exec "$@"
fi
4 changes: 4 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ services:
serviceWorker: 'false'
# activeThemes: b2b
# activeThemes: b2c
# command: ['node', 'dist/b2c/run-standalone']
# command: ['node', 'dist/b2b/run-standalone']
environment:
# ICM_BASE_URL:
LOGGING: 'true'
# LOG_ALL: 'false'
SOURCE_MAPS: 'true'
TRUST_ICM: 'true'
# PROXY_ICM: 'true'
Expand Down Expand Up @@ -66,6 +69,7 @@ services:
UPSTREAM_PWA: 'http://pwa:4200'
NGINX_ENTRYPOINT_QUIET_LOGS: ANYVALUE
CACHE: 0
# LOG_ALL: off
# SSL: 1
# SSR: 0
# DEBUG: 1
Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ kb_sync_latest_only
- [Guide - Data Handling with Mappers](./guides/data-handling-with-mappers.md)
- [Guide - Working with ESLint](./guides/eslint.md)
- [Guide - Accessibility](./guides/accessibility.md)
- [Concept - Captcha](./concepts/captcha.md)

### Customization

Expand Down
Binary file added docs/concepts/captcha-class-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions docs/concepts/captcha.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<!--
kb_concepts
kb_pwa
kb_everyone
kb_sync_latest_only
-->

# CAPTCHA in the PWA

## Introduction

The PWA supports reCAPTCHA V2 as well as reCAPTCHA V3.
Which CAPTCHA version is used depends on which CAPTCHA service is created and running in the ICM.
The pure CAPTCHA functionality is implemented as a PWA extension and can be found in the _extensions_ folder.
There are two basic CAPTCHA components (one for each CAPTCHA version) and a lazy CAPTCHA component that decides which one to use.

The PWA uses the [Angular Formly framework](https://formly.dev/docs/guide/getting-started) to process web forms, see also [The Formly Guide](../guides/formly.md).
This framework allows you to automatically generate your forms using predefined form field types.
A special type `ish-captcha-field` has been implemented to support the CAPTCHA functionality.
You can define a field of this type in any _Formly_ form, so that this form is validated according to CAPTCHA.

## High Level Overview

The following class diagram shows the major classes of the CAPTCHA workflow that are relevant for most use cases:

![Captcha Class Diagram](captcha-class-diagram.png)

- _CAPTCHA Basic Components_ contains the recommended necessary UI components to integrate the Google reCAPTCHA service.
- The lazy component ensures that the component for the corresponding version is reloaded asynchronously.
- The CAPTCHA facade contains methods to retrieve the sitekey and the reCAPTCHA version used.
- The PWA uses the Formly framework for web forms. A separate type `ish-captcha-field` is available for the reCAPTCHA functionality.
- The three components (_registration-page.component.ts_, _request-reminder-form.component.ts_, _contact-form.component.ts_) contain Formly forms that contain a field of type CAPTCHA.
- When these forms are submitted, the CAPTCHA token is set as a header parameter for the subsequent REST request. (When using CAPTCHA V3, the CAPTCHA action is also set as a header parameter).
- The CAPTCHA validation takes place on the ICM side. If the score exceeds the threshold configured in the managed service, the request is rejected.

## Integration of the CAPTCHA Components

There is a special CAPTCHA field type that makes it very easy to protect any web form using the CAPTCHA functionality.
The following example shows how to add a CAPTCHA field of type `ish-captcha-field` to any Formly form.

The component's TypeScript file looks like this:

```ts
export class ExamplePageComponent implements OnInit {
...
fields: FormlyFieldConfig[];
exampleFormGroup = new UntypedFormGroup({});
...
ngOnInit() {
...
this.fields = [
...
{
type: 'ish-captcha-field',
props: {
topic: 'forgotPassword',
},
},
];
}
...
}
```

The `ish-captcha-field` type is registered in the _src.app.shared.formly.types.**types.module.ts**_.
Additionally, the module binds the corresponding field component to this type.
The topic to be set corresponds to the CAPTCHA channel preferences available in ICM.
If these preferences are disabled in ICM, CAPTCHA validation for this topic is also disabled in the PWA.

The following table shows the mapping between existing PWA CAPTCHA topic names and the CAPTCHA channel preferences in the ICM:

| **CaptchaTopic** | **ICM Settings** |
| ------------------------------------ | --------------------------------------- |
| contactUs | Contact Us |
| emailShoppingCart | E-mail Shopping Cart |
| forgotPassword | Forgot password |
| redemptionOfGiftCardsAndCertificates | Redemption of Gift Cards & Certificates |
| register | Registration |

> :exclamation: The topic value is also appended to the header of the request triggered by submitting the web form. This is necessary to support the [actions concept of Google reCAPTCHA v3](https://developers.google.com/recaptcha/docs/v3#actions).
## Basic Components

As you can see in the high-level overview, there are components that represent the actual CAPTCHA functionality.
Depending on the version used, these components implement either widgets provided by Google or the reCAPTCHA token functionality.
The [ng-recaptcha](https://github.com/DethAriel/ng-recaptcha) library was used for the implementation.

### CAPTCHA V2 (captcha-v2.component.ts)

To add the widgets provided by Google, you need to import the **ReCAPTCHAModule** of the _ng-recaptcha_ library.
Furthermore, _captcha site key_ must be set to initialize the widget.
This site key is a required option on the reCAPTCHA HTML element.
It is also necessary to store the token determined by the CAPTCHA event as a form control parameter.
This allows the response to be validated and handled accordingly.
In case of an error, an error message is displayed; in case of success, the entire form is processed further.

### CAPTCHA V3 (captcha-v3.component.ts)

To implement a callback function to handle the token, you need to import the **RecaptchaV3Module** of the _ng-recaptcha_ library.
This component will trigger a callback every two minutes to retrieve a current reCAPTCHA token.
This token is then appended to the request triggered by the submitted form.
The ICM backend will then validate the token.

## Further References

- [Intershop Knowledge Base | Concept - ReCaptcha v3](https://support.intershop.com/kb/index.php/Display/29X281)
- [Intershop Knowledge Base | Concept - ReCaptcha v2](https://support.intershop.com/kb/index.php/Display/2794B3)
- [Getting Started | Formly](https://formly.dev/docs/guide/getting-started)
- [GitHub - DethAriel/ng-recaptcha: Angular component for Google reCAPTCHA](https://github.com/DethAriel/ng-recaptcha)
- [Developer's Guide | reCAPTCHA | Google for Developers](https://developers.google.com/recaptcha/intro)
1 change: 1 addition & 0 deletions docs/concepts/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Of course, the ICM server must supply appropriate REST resources to leverage fun
| productNotifications | Product notifications feature for price and in stock notifications |
| rating | Display product ratings |
| recently | Display recently viewed products (additional configuration via `dataRetention` configuration options) |
| saveLanguageSelection | Save the user's language selection and restore it after PWA load |
| storeLocator | Display physical stores and their addresses |
| **B2B Features** | |
| businessCustomerRegistration | Create business customers on registration |
Expand Down
4 changes: 2 additions & 2 deletions docs/concepts/pwa-building-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ kb_sync_latest_only
## Intershop Commerce Management (ICM)

The Intershop Commerce Management (ICM) provides the necessary data for running the [default Intershop PWA deployment](https://intershoppwa.azurewebsites.net/home) via a REST API.
Since release [0.23](https://github.com/intershop/intershop-pwa/releases/tag/0.23.0), it uses the new headless application type (see [Migrations - 0.22 to 0.23](../guides/migrations.md#022-to-023)).
Since release [0.23](https://github.com/intershop/intershop-pwa/releases/tag/0.23.0), it uses the new headless application type (see [Migrations / From 0.22 to 0.23](../guides/migrations.md#from-022-to-023)).

Using another backend is also possible as long as it provides a [compatible REST API](cms-integration.md#integration-with-an-external-cms).

Expand Down Expand Up @@ -88,7 +88,7 @@ Upon completing the Angular Universal pre-rendering, all URLs referring explicit
## Stateless vs. Stateful Building Blocks

For scalability and parallelization reasons, considering whether each building block is stateful or stateless is important.
The **ICM** deals with large databases, caches write and read requests and therefore manages a high amount of internal states.
The **ICM** deals with large databases, caches write and read requests and, therefore, manages a high amount of internal states.
Substituting ICM instances at runtime and managing fail-over capacities is not trivial.
The **SSR container** acts like a pure function.
Making the same request is always going to return the same result.
Expand Down
13 changes: 7 additions & 6 deletions docs/guides/cookie-consent.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ cookieConsentOptions: {
description: 'cookie.consent.option.tracking.description',
},
},
allowedCookies: ['cookieConsent', 'apiToken'],
allowedCookies: ['apiToken', 'cookieConsent', 'preferredLocale'],
},
```

Expand All @@ -42,7 +42,7 @@ The `options` array configures the presented options in the _Cookie Preferences_
- The option `id` is the value that will be stored in the user's `cookieConsent` settings.
- The `name` makes up the checkbox label name, usually given as localization key.
- The `description` contains the additional option description, usually given as localization key.
- With the `required` flag, an option can be marked as not deselectable.
- With the `required` flag, an option can be marked as not non-selectable.
In this way, the user can be informed that necessary cookies are always set without explicit consent of the user.

The following screenshot is the rendered representation of the default cookie consent options configuration:
Expand Down Expand Up @@ -100,10 +100,11 @@ This route can be linked to from anywhere within the application.

## PWA Required Cookies

| Name | Expiration | Provider | Description | Category |
| ------------- | ---------- | ------------- | ----------------------------------------------------------------- | ----------- |
| apiToken | 1 year | Intershop PWA | The API token used by the Intershop Commerce Management REST API. | First Party |
| cookieConsent | 1 year | Intershop PWA | Saves the user's cookie consent settings. | First Party |
| Name | Expiration | Provider | Description | Category |
| --------------- | ---------- | ------------- | ----------------------------------------------------------------- | ----------- |
| apiToken | 1 year | Intershop PWA | The API token used by the Intershop Commerce Management REST API. | First Party |
| cookieConsent | 1 year | Intershop PWA | Saves the user's cookie consent settings. | First Party |
| preferredLocale | 1 year | Intershop PWA | Saves the user's language selection. | First Party |

## Disabling the Integrated Cookie Consent Handling

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/eslint.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ To work with and develop new custom ESLint rules, follow these steps:

1. Generate a new rule using our schematic: `ng g eslint-rule` (alias `er`). This generates a new rule file at `eslint-rules/src/rules` and a test file at `eslint-rules/tests`.
2. Write the rule code. Refer to [Working with Rules](https://eslint.org/docs/developer-guide/working-with-rules) as well as examples from available rules to understand how. Add reusable helper functions to `helpers.ts` to reduce repetition.
3. Write rule tests. Refer to [Testing](https://typescript-eslint.io/docs/development/custom-rules#testing) for documentation on the `RuleTester` API that is used in tests. Use `npm run test:eslint-rules` to execute your tests.
3. Write rule tests. Refer to [Testing](https://typescript-eslint.io/developers/custom-rules/#testing) for documentation on the `RuleTester` API that is used in tests. Use `npm run test:eslint-rules` to execute your tests.
4. Build the `eslint-rules` project with your changes using `npm run build:eslint-rules`. The resulting JavaScript files will be located in the `eslint-rules/dist` folder. A generated `index.ts` exports the rules to be consumed in the `.eslintrc.json` configuration file.
5. Add the new rule to the ESLint configuration in [`.eslintrc.json`](../../.eslintrc.json).
6. _Optional_: Restart the ESLint server using the `ESLint: Restart ESLint server` command to see your new configuration applied in VSCode. You can access the command via the editor commands (default keybinding: `ctrl + shift + p`).
3 changes: 2 additions & 1 deletion docs/guides/formly.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,8 @@ Refer to the tables below for an overview of these parts.

### Field Types

Template option `inputClass`: These css class(es) will be added to all input/select/textarea/text tags.
- Template option `inputClass`: These CSS class(es) will be added to all input/select/textarea/text tags.
- Template option `ariaLabel`: Adds an aria-label to all input/select/textarea tags.

| Name | Description | Relevant props |
| -------------------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down
Loading

0 comments on commit b2bc0ca

Please sign in to comment.