Repository: SAP/luigi (js)

Issue:
removal of luigiCookie
<!-- Thank you for your contribution. Before you submit the issue:
1. Search open and closed issues for duplicates.
2. Read the contributing guidelines: https://github.com/SAP/luigi/blob/main/CONTRIBUTING.md
-->

**Description**

I am getting chrome warnings:

```
Reading cookie in cross-site context may be impacted on Chrome 

Cookies with the SameSite=None; Secure and not Partitioned attributes that operate in cross-site contexts are third-party cookies. Chrome is moving towards a new experience that lets people make an informed choice with respect to third-party cookies.
```

and the affected cookie is your `luigiCookie`.

What are your plans with this issue?

Is it possible to remove this cookie and thus get rid of these problems?

**Reasons**

I am not sure how it would function in future chrome versions,
possibly chrome will show an accept cookie popup to users (?),
but it would be better to avoid this complication. 




Pull request:
Adds option to disable luigiCookie
**Description**

Changes proposed in this pull request:

- adds option to disable luigiCookie

**Related issue(s)**

Resolves #3942 


Patch:
diff --git a/client/src/lifecycleManager.js b/client/src/lifecycleManager.js
index 3f6f0c23..5b9f2fab 100644
--- a/client/src/lifecycleManager.js
+++ b/client/src/lifecycleManager.js
@@ -91,6 +91,7 @@ class LifecycleManager extends LuigiClientBase {
       helpers.setLuigiCoreDomain(e.origin);
       this.luigiInitialized = true;
       this._notifyInit(e.origin);
+      this._tpcCheck();
       helpers.sendPostMessageToLuigiCore({ msg: 'luigi.init.ok' });
     });
 
@@ -135,10 +136,12 @@ class LifecycleManager extends LuigiClientBase {
       },
       '*'
     );
-    this._tpcCheck();
   }
 
   _tpcCheck() {
+    if (this.currentContext?.internal?.thirdPartyCookieCheck?.disabled) {
+      return;
+    }
     let tpc = 'enabled';
     let cookies = document.cookie;
     let luigiCookie;
diff --git a/container/.gitignore b/container/.gitignore
index 5d7df85d..b2415001 100644
--- a/container/.gitignore
+++ b/container/.gitignore
@@ -9,6 +9,7 @@
 /test-app/bundle.js
 /test-app/bundle.js.map
 /test-app/compound/luigi-element.js
+/test-app/iframe/luigi-client.js
 /public/**/*.ts
 
 /coverage
diff --git a/container/package.json b/container/package.json
index 37c3d22c..66f42352 100644
--- a/container/package.json
+++ b/container/package.json
@@ -18,8 +18,9 @@
     "bundle": "npm run build",
     "dev": "rollup -c -w",
     "copyBundle": "cp public/bundle.js public/bundle.js.map test-app/ && cp public/bundle.js public/bundle.js.map  examples/ || COPY public\\* test-app\\",
+    "copyLuigiClient": "cp ../client/public/luigi-client.js test-app/iframe",
     "copyLuigiElement": "cp ../client/src/luigi-element.js test-app/compound",
-    "serve": "npm run build && npm run copyLuigiElement && npm run copyBundle && sirv -D -c test-app --no-clear",
+    "serve": "npm run build && npm run copyLuigiClient && npm run copyLuigiElement && npm run copyBundle && sirv -D -c test-app --no-clear",
     "bundle:watch": "chokidar \"src/**/*.*\" -c \"npm run build && npm run copyBundle\"",
     "start": "concurrently -k \"npm run serve\" \"npm run bundle:watch\"",
     "start-examples":"npm run copyBundle && sirv -D -c examples --no-clear",
diff --git a/container/src/LuigiContainer.svelte b/container/src/LuigiContainer.svelte
index 974f91c7..86f9aa0d 100644
--- a/container/src/LuigiContainer.svelte
+++ b/container/src/LuigiContainer.svelte
@@ -20,6 +20,7 @@
       pathParams: { type: 'Object', reflect: false, attribute: 'path-params' },
       sandboxRules: { type: 'Array', reflect: false, attribute: 'sandbox-rules' },
       searchParams: { type: 'Object', reflect: false, attribute: 'search-params' },
+      skipCookieCheck: { type: 'String', reflect: false, attribute: 'skip-cookie-check' },
       skipInitCheck: { type: 'Boolean', reflect: false, attribute: 'skip-init-check' },
       theme: { type: 'String', reflect: false, attribute: 'theme' },
       userSettings: { type: 'Object', reflect: false, attribute: 'user-settings' },
@@ -79,6 +80,7 @@
   export let pathParams: any;
   export let sandboxRules: string[];
   export let searchParams: any;
+  export let skipCookieCheck: 'false' | 'true';
   export let skipInitCheck: boolean;
   export let theme: string;
   export let userSettings: any;
@@ -113,6 +115,7 @@
       pathParams &&
       sandboxRules &&
       searchParams &&
+      skipCookieCheck &&
       skipInitCheck &&
       theme &&
       userSettings
diff --git a/container/src/services/container.service.ts b/container/src/services/container.service.ts
index c25d3d53..5ac67c92 100644
--- a/container/src/services/container.service.ts
+++ b/container/src/services/container.service.ts
@@ -106,7 +106,11 @@ export class ContainerService {
                   {
                     msg: LuigiInternalMessageID.SEND_CONTEXT_HANDSHAKE,
                     context: targetCnt.context || {},
-                    internal: {},
+                    internal: {
+                      thirdPartyCookieCheck: {
+                        disabled: targetCnt.skipCookieCheck === 'true'
+                      }
+                    },
                     authData: targetCnt.authData || {}
                   },
                   '*'
diff --git a/container/typings/LuigiContainer.svelte.d.ts b/container/typings/LuigiContainer.svelte.d.ts
index 6d763c12..357ecfe2 100644
--- a/container/typings/LuigiContainer.svelte.d.ts
+++ b/container/typings/LuigiContainer.svelte.d.ts
@@ -71,6 +71,12 @@ export default class LuigiContainer extends HTMLElement {
    */
   activeFeatureToggleList: string[];
 
+  /**
+   * If set to true, skips third party cookie check
+   * @since NEXT_RELEASE_CONTAINER
+   */
+  skipCookieCheck: 'false' | 'true';
+
   /**
    * If set to true, skips handshake and ready event is fired immediately
    * @since 1.0.0
diff --git a/core/src/App.svelte b/core/src/App.svelte
index 48188f0f..68289bec 100644
--- a/core/src/App.svelte
+++ b/core/src/App.svelte
@@ -120,6 +120,7 @@
       isNavigateBack,
       viewStackSize: preservedViews.length,
       clientPermissions: iframeConf.nextViewUrl ? iframeConf.nextClientPermissions : iframeConf.clientPermissions,
+      thirdPartyCookieCheck: await LuigiConfig.getConfigValue('settings.thirdPartyCookieCheck'),
       userSettings: hasUserSettings ? userSettingGroups[userSettingsGroupName] : null,
       anchor: LuigiRouting.getAnchor(),
       cssVariables: await LuigiTheming.getCSSVariables()
diff --git a/docs/general-settings.md b/docs/general-settings.md
index 776228e5..c9dc86d7 100644
--- a/docs/general-settings.md
+++ b/docs/general-settings.md
@@ -53,6 +53,7 @@ settings: {
     hideAutomatically: true
   },
   thirdPartyCookieCheck = {
+    //disabled: true,
     //thirdPartyCookieScriptLocation: 'https://domain/init.html',
     thirdPartyCookieErrorHandling: () => {
       const alert = {
@@ -298,7 +299,7 @@ This function is called with the following parameters:
 
 ## Third-party cookies support check
 
-You can check whether the user's browser supports third-party cookies by defining a **thirdPartyCookieCheck** object which expects a function called **thirdPartyCookieErrorHandling** and an optional **thirdPartyCookiesScriptLocation** parameter. When **thirdPartyCookiesScriptLocation** is set, the Luigi Core application checks third-party cookie support only once and not on every micro frontend call. If it is *not* set, the Luigi Core application checks third-party cookie support whenever a micro frontend is loaded.
+You can check whether the user's browser supports third-party cookies by defining a **thirdPartyCookieCheck** object which expects a function called **thirdPartyCookieErrorHandling**, optional **disabled** and **thirdPartyCookiesScriptLocation** parameters. When **thirdPartyCookiesScriptLocation** is set, the Luigi Core application checks third-party cookie support only once and not on every micro frontend call. If it is *not* set, the Luigi Core application checks third-party cookie support whenever a micro frontend is loaded.
 
 To detect whether the user's browser supports the mechanism, use the script in the [`third-party-cookies`](https://github.com/SAP/luigi/tree/main/core/third-party-cookies) catalog. Deploy this file on a domain different from your main application's and set **thirdPartyCookieScriptLocation** to the `init.html` file. During initialization, Luigi detects cookies support and produces an alert if cookies are disabled in the user's browser.
 
@@ -306,7 +307,11 @@ To detect whether the user's browser supports the mechanism, use the script in t
 
 #### thirdPartyCookieCheck
 - **type**: object
-- **description**: object defined in the general settings part of the Luigi configuration file, containing the **thirdPartyCookieErrorHandling** function and an optional **thirdPartyCookiesScriptLocation** parameter.
+- **description**: object defined in the general settings part of the Luigi configuration file, containing the **thirdPartyCookieErrorHandling** function and optional **disabled** and **thirdPartyCookiesScriptLocation** parameters.
+
+#### disabled
+- **type**: boolean
+- **description**: if set to true **thirdPartyCookieCheck** is ignored.
 
 #### thirdPartyCookieErrorHandling
 - **type**: function
diff --git a/docs/luigi-container-api.md b/docs/luigi-container-api.md
index 1128a99e..81159143 100644
--- a/docs/luigi-container-api.md
+++ b/docs/luigi-container-api.md
@@ -121,6 +121,16 @@ Type: [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global
 
 *   **since**: 1.0.0
 
+### skipCookieCheck
+
+If set to true, skips third party cookie check
+
+Type: (`"false"` | `"true"`)
+
+**Meta**
+
+*   **since**: NEXT_RELEASE_CONTAINER
+
 ### skipInitCheck
 
 If set to true, skips handshake and ready event is fired immediately


Test patch:
diff --git a/container/cypress/e2e/test-app/iframe/iframe-container.cy.js b/container/cypress/e2e/test-app/iframe/iframe-container.cy.js
index b659bc11..55297964 100644
--- a/container/cypress/e2e/test-app/iframe/iframe-container.cy.js
+++ b/container/cypress/e2e/test-app/iframe/iframe-container.cy.js
@@ -7,6 +7,19 @@ describe('Iframe Container Test', () => {
     stub = cy.stub();
   });
 
+  it('should sent third party cookies request', () => {
+    cy.on('window:alert', stub);
+
+    cy.get(containerSelector).should('not.have.attr', 'skip-cookie-check');
+    cy.get(containerSelector)
+      .shadow()
+      .get('iframe')
+      .then(() => {
+        cy.wrap(stub).should('have.been.calledWith', 'set-third-party-cookies-request');
+        cy.getCookie('luigiCookie').should('exist');
+      });
+  });
+
   it('navigation sent', () => {
     cy.get(containerSelector)
       .shadow()
@@ -24,13 +37,12 @@ describe('Iframe Container Test', () => {
   });
 
   it('sendCustomMessage', () => {
-    cy.get('#btn-1')
-      .click()
+    cy.get('#btn-1').click();
     cy.get(containerSelector)
       .shadow()
       .get('iframe')
       .then(iframe => {
-        const $body = iframe.contents().find('body')
+        const $body = iframe.contents().find('body');
         cy.wrap($body)
           .find('#content')
           .should('have.text', 'Received Custom Message: some data');
diff --git a/container/cypress/e2e/test-app/iframe/iframe-cookies.cy.js b/container/cypress/e2e/test-app/iframe/iframe-cookies.cy.js
new file mode 100644
index 00000000..e9e5e8af
--- /dev/null
+++ b/container/cypress/e2e/test-app/iframe/iframe-cookies.cy.js
@@ -0,0 +1,24 @@
+describe('Iframe Cookies Test', () => {
+  const containerSelector = '[data-test-id="iframe-based-container-test"]';
+  let stub;
+
+  beforeEach(() => {
+    cy.visit('http://localhost:8080/iframe/iframe-cookies.html');
+    stub = cy.stub();
+  });
+
+  it('should not sent third party cookies request', () => {
+    cy.on('window:alert', stub);
+
+    cy.get(containerSelector)
+      .should('have.attr', 'skip-cookie-check')
+      .and('match', /true/);
+    cy.get(containerSelector)
+      .shadow()
+      .get('iframe')
+      .then(() => {
+        cy.wrap(stub).should('not.have.been.calledWith', 'set-third-party-cookies-request');
+        cy.getCookie('luigiCookie').should('not.exist');
+      });
+  });
+});
diff --git a/container/test-app/iframe/iframe-cookies.html b/container/test-app/iframe/iframe-cookies.html
new file mode 100644
index 00000000..27a7d05b
--- /dev/null
+++ b/container/test-app/iframe/iframe-cookies.html
@@ -0,0 +1,38 @@
+<html>
+  <head>
+    <script type="module">
+      import '../bundle.js';
+    </script>
+  </head>
+  <body>
+    <h3>
+      This page is used to test  **skip-cookie-check** feature for iFrame based LuigiContainer
+    </h3>
+
+    <div style="border:solid 1px blue; height: 400px">
+      <!-- Luigi Container to test general functionality-->
+      <luigi-container
+        data-test-id="iframe-based-container-test"
+        viewURL="./microfrontend.html"
+        skip-cookie-check="true"
+      ></luigi-container>
+    </div>
+
+    <script type="module">
+      import Events from '../bundle.js';
+
+      const luigiContainer = document.querySelector(
+        '[data-test-id="iframe-based-container-test"]'
+      );
+
+      // SET_THIRD_PARTY_COOKIES_REQUEST - called on microfrontend startup
+      luigiContainer.addEventListener(Events.SET_THIRD_PARTY_COOKIES_REQUEST, event => {
+        console.log(Events.SET_THIRD_PARTY_COOKIES_REQUEST, event);
+        alert(
+          Events.SET_THIRD_PARTY_COOKIES_REQUEST,
+          'message received: ' + JSON.stringify(event.detail.data.data)
+        );
+      });
+    </script>
+  </body>
+</html>
diff --git a/container/test-app/iframe/microfrontend.html b/container/test-app/iframe/microfrontend.html
index 80e1159d..b69fc1a4 100644
--- a/container/test-app/iframe/microfrontend.html
+++ b/container/test-app/iframe/microfrontend.html
@@ -4,7 +4,7 @@
   <head>
     <title></title>
     <meta charset="utf-8" />
-    <script src="https://fiddle.luigi-project.io/vendor/luigi-client/luigi-client.js"></script>
+    <script src="./luigi-client.js"></script>
     <style>
       html,
       body {
diff --git a/container/test-app/index.html b/container/test-app/index.html
index cd319070..6982499a 100644
--- a/container/test-app/index.html
+++ b/container/test-app/index.html
@@ -68,6 +68,11 @@
             <td><a href="iframe/iframe-settings.html">iFrame Settings</a></td>
             <td><a href="compound/nested.html">Nested</a></td>
           </tr>
+          <tr>
+            <td><a href="#">-</a></td>
+            <td><a href="iframe/iframe-cookies.html">iFrame Cookies</a></td>
+            <td><a href="#">-</a></td>
+          </tr>
           <!-- Add more rows as needed -->
         </tbody>
       </table>
diff --git a/container/test/services/container.service.spec.ts b/container/test/services/container.service.spec.ts
index 5c146767..92359dbf 100644
--- a/container/test/services/container.service.spec.ts
+++ b/container/test/services/container.service.spec.ts
@@ -68,7 +68,7 @@ describe('getContainerManager messageListener', () => {
     gtcSpy.mockRestore();
   });
 
-  it('test get context message', () => {    
+  it('test get context message', () => {
     const event = {
       source: cw,
       data: {
@@ -87,7 +87,16 @@ describe('getContainerManager messageListener', () => {
      cw.postMessage = postMessageMock;
 
     // Define the message to send and target Origin
-    const message = {"context": {}, "internal": {}, "msg": "luigi.init", "authData":{}};
+    const message = {
+      "authData":{},
+      "context": {},
+      "internal": {
+        "thirdPartyCookieCheck": {
+          "disabled": false
+        }
+      },
+      "msg": "luigi.init"
+    };
     const targetOrigin = "*";
 
     // Call the method that should trigger postMessage