From cb06ccf0b77e492e1a75d48dc5cb7d819bd991dc Mon Sep 17 00:00:00 2001 From: Abel Soares Siqueira Date: Thu, 7 Sep 2023 17:06:09 +0200 Subject: [PATCH] [WIP] Trying to setup Matomo --- package-lock.json | 45 +++++++++++--- package.json | 2 + src/App.vue | 8 ++- src/components/PrivacyNotice.vue | 38 ++++++++++++ src/css/app.css | 16 ++++- src/index.template.html | 37 ++++++++++-- src/store/nodeCookies.ts | 59 +++++++++++++++++++ test/jest/__tests__/store/matomo.jest.spec.ts | 33 +++++++++++ 8 files changed, 220 insertions(+), 18 deletions(-) create mode 100644 src/components/PrivacyNotice.vue create mode 100644 src/store/nodeCookies.ts create mode 100644 test/jest/__tests__/store/matomo.jest.spec.ts diff --git a/package-lock.json b/package-lock.json index 72a48564..d69e9dfb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,11 +6,12 @@ "packages": { "": { "name": "cffinit", - "version": "2.2.0", + "version": "2.3.1", "dependencies": { "@quasar/extras": "^1.0.0", "ajv": "^8.6.2", "ajv-formats": "^2.1.1", + "cookie": "^0.5.0", "core-js": "^3.6.5", "deep-filter": "^1.0.2", "js-yaml": "^3.14.1", @@ -24,6 +25,7 @@ "@quasar/app": "^3.0.0", "@quasar/quasar-app-extension-testing": "^2.0.0-beta.2", "@quasar/quasar-app-extension-testing-unit-jest": "^3.0.0-alpha.3", + "@types/cookie": "^0.5.2", "@types/cypress": "^1.1.3", "@types/js-yaml": "^4.0.2", "@types/node": "^10.17.15", @@ -3638,6 +3640,12 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.2.tgz", + "integrity": "sha512-DBpRoJGKJZn7RY92dPrgoMew8xCWc2P71beqsjyhEI/Ds9mOyVmBwtekyfhpwFIVt1WrxTonFifiOZ62V8CnNA==", + "dev": true + }, "node_modules/@types/cordova": { "version": "0.0.34", "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", @@ -6757,10 +6765,9 @@ } }, "node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "dev": true, + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } @@ -9683,6 +9690,15 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -25491,6 +25507,12 @@ "@types/node": "*" } }, + "@types/cookie": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.5.2.tgz", + "integrity": "sha512-DBpRoJGKJZn7RY92dPrgoMew8xCWc2P71beqsjyhEI/Ds9mOyVmBwtekyfhpwFIVt1WrxTonFifiOZ62V8CnNA==", + "dev": true + }, "@types/cordova": { "version": "0.0.34", "resolved": "https://registry.npmjs.org/@types/cordova/-/cordova-0.0.34.tgz", @@ -28003,10 +28025,9 @@ } }, "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "dev": true + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "cookie-signature": { "version": "1.0.6", @@ -30240,6 +30261,12 @@ "vary": "~1.1.2" }, "dependencies": { + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", diff --git a/package.json b/package.json index 270b5867..4d5192b6 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "@quasar/extras": "^1.0.0", "ajv": "^8.6.2", "ajv-formats": "^2.1.1", + "cookie": "^0.5.0", "core-js": "^3.6.5", "deep-filter": "^1.0.2", "js-yaml": "^3.14.1", @@ -38,6 +39,7 @@ "@quasar/app": "^3.0.0", "@quasar/quasar-app-extension-testing": "^2.0.0-beta.2", "@quasar/quasar-app-extension-testing-unit-jest": "^3.0.0-alpha.3", + "@types/cookie": "^0.5.2", "@types/cypress": "^1.1.3", "@types/js-yaml": "^4.0.2", "@types/node": "^10.17.15", diff --git a/src/App.vue b/src/App.vue index 002b026f..8d7a968a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,10 +1,16 @@ + diff --git a/src/components/PrivacyNotice.vue b/src/components/PrivacyNotice.vue new file mode 100644 index 00000000..5b055629 --- /dev/null +++ b/src/components/PrivacyNotice.vue @@ -0,0 +1,38 @@ + diff --git a/src/css/app.css b/src/css/app.css index ec67c330..a3b3a9f6 100644 --- a/src/css/app.css +++ b/src/css/app.css @@ -42,7 +42,7 @@ a:not(.q-btn) { text-decoration: none } -a:not(.q-btn):hover{ +a:not(.q-btn):hover { text-decoration: underline } @@ -69,16 +69,23 @@ h1 { font-size: 32pt; font-weight: bold; } + h2 { font-size: 26pt; } + h3 { font-size: 22pt; } + h4 { font-size: 20pt; } -h1, h2, h3, h4 { + +h1, +h2, +h3, +h4 { line-height: normal; margin: 1rem 0rem; } @@ -133,3 +140,8 @@ body { transform: translateX(-50%); opacity: 1; } + +.link-over-primary { + color: white !important; + text-decoration: underline !important; +} diff --git a/src/index.template.html b/src/index.template.html index b91e4dbf..be812172 100644 --- a/src/index.template.html +++ b/src/index.template.html @@ -1,17 +1,42 @@ - - <%= productName %> + + + + <%= productName %> + - + - - + + + + + + + +
- + + diff --git a/src/store/nodeCookies.ts b/src/store/nodeCookies.ts new file mode 100644 index 00000000..ed5917fd --- /dev/null +++ b/src/store/nodeCookies.ts @@ -0,0 +1,59 @@ +// Copied from https://github.com/research-software-directory/RSD-as-a-service/blob/main/frontend/components/cookies/nodeCookies.ts + +import { IncomingMessage } from 'http' +import cookie from 'cookie' + +export type Matomo = { + id: string | null + consent: boolean | null +} + +/** + * Extract Matomo cookies + * Available only on the server side, using plain Node request + * @param req + * @returns Session + */ +export function getMatomoCookies (req: IncomingMessage) { + // check for cookies + if (req?.headers?.cookie) { + // parse cookies from node request + const cookies = cookie.parse(req.headers.cookie) + // validate and decode + return { + mtm_consent: cookies?.mtm_consent, + mtm_consent_removed: cookies?.mtm_consent_removed + } + } else { + return { + mtm_consent: undefined, + mtm_consent_removed: undefined + } + } +} + +/** + * Extract matomo consent based on cookies + * Available only on the server side, using plain Node request + * @param req + * @returns Session + */ +export function getMatomoConsent (req:IncomingMessage) { + // check for cookies + // console.log('getMatomoConsent...', req) + if (req?.headers?.cookie) { + const matomo = getMatomoCookies(req) + if (matomo?.mtm_consent) { + return { + matomoConsent: true + } + } else if (matomo?.mtm_consent_removed) { + return { + matomoConsent: false + } + } + } + return { + matomoConsent: null + } +} diff --git a/test/jest/__tests__/store/matomo.jest.spec.ts b/test/jest/__tests__/store/matomo.jest.spec.ts new file mode 100644 index 00000000..31b76b2f --- /dev/null +++ b/test/jest/__tests__/store/matomo.jest.spec.ts @@ -0,0 +1,33 @@ +// Copied from https://github.com/research-software-directory/RSD-as-a-service/blob/main/frontend/components/cookies/nodeCookies.test.ts + +import { describe, expect, it, jest } from '@jest/globals' +import { getMatomoConsent } from 'src/store/nodeCookies' + +const mockRequest:any = { + headers: { + cookie: '_pk_id.1.a7f1=7b08ec6de0eadf14.1664460134.; mtm_consent=1664460134155; _pk_ref.1.a7f1=%5B%22%22%2C%22%22%2C1670956090%2C%22https%3A%2F%2Fconnect.surfconext.nl%2F%22%5D; _pk_ses.1.a7f1=1' + } +} + +it('extracts mtm_consent cookie from request', () => { + // extract matomo cookie + const { matomoConsent } = getMatomoConsent(mockRequest) + // assert consent is true + expect(matomoConsent).toBe(true) +}) + +it('extracts mtm_consent_removed cookie from request', () => { + mockRequest.headers.cookie = 'mtm_consent_removed=1664460134155;' + // extract matomo cookie + const { matomoConsent } = getMatomoConsent(mockRequest) + // expect consent is false + expect(matomoConsent).toBe(false) +}) + +it('extracts mtm_consent is not present', () => { + mockRequest.headers.cookie = '_pk_ses.1.a7f1=1;' + // extract matomo cookie + const { matomoConsent } = getMatomoConsent(mockRequest) + // expect consent is false + expect(matomoConsent).toBe(null) +})