From 1d1bccdae6d8a9cb2c4917106b38ad9ee9d9ae0f Mon Sep 17 00:00:00 2001 From: MaddoScientisto Date: Sun, 19 Apr 2026 10:26:34 +0200 Subject: [PATCH] Add Playwright tests for live site authentication and race page loading - Introduced `auth.setup.js` to handle authentication against the live site and store the session state. - Created `live-race.spec.js` to test loading a live race page with an authenticated session, including cookie validation. - Added utility functions in `live-site-test-utils.js` for managing authentication, dismissing cookie banners, and checking UI states. - Included a temporary JSON file for live state inspection. - Updated deployment manifest to reflect new and modified files. - Implemented `_inc_faceai_identity.jsp` for managing FaceAI identity cookies and included it in relevant JSP files. - Added language management JavaScript in `lang.js`. - Adjusted `fotoCR-en.jsp` and `fotoCR.jsp` to include the FaceAI identity logic. - Created a tarball for staging deployment. --- .../instructions/instructions.instructions.md | 1 + ...lamiunsorriso-83-149-164-4.instructions.md | 28 + faceai/.env.example | 5 + faceai/.gitignore | 1 + faceai/README.md | 29 + faceai/anonymous_output.html | 1116 ++++++++++++++++ faceai/authenticated_output.html | 1120 +++++++++++++++++ faceai/headers.txt | 0 faceai/login_response.html | 359 ++++++ faceai/package.json | 5 +- faceai/playwright.live.config.js | 38 + faceai/probe.js | 47 + faceai/response.html | 1100 ++++++++++++++++ faceai/tests/live-site/auth.setup.js | 12 + faceai/tests/live-site/live-race.spec.js | 33 + .../tests/live-site/live-site-test-utils.js | 92 ++ faceai/tmp-live-state-inspection.json | 45 + sync/www-deploy-manifest.md | 13 +- www/_inc_faceai_identity.jsp | 260 ++++ www/_js/lang.js | 55 + www/fotoCR-en.jsp | 5 +- www/fotoCR.jsp | 5 +- www_staged.tar | Bin 0 -> 49152 bytes 23 files changed, 4358 insertions(+), 11 deletions(-) create mode 100644 faceai/anonymous_output.html create mode 100644 faceai/authenticated_output.html create mode 100644 faceai/headers.txt create mode 100644 faceai/login_response.html create mode 100644 faceai/playwright.live.config.js create mode 100644 faceai/probe.js create mode 100644 faceai/response.html create mode 100644 faceai/tests/live-site/auth.setup.js create mode 100644 faceai/tests/live-site/live-race.spec.js create mode 100644 faceai/tests/live-site/live-site-test-utils.js create mode 100644 faceai/tmp-live-state-inspection.json create mode 100644 www/_inc_faceai_identity.jsp create mode 100644 www/_js/lang.js create mode 100644 www_staged.tar diff --git a/.github/instructions/instructions.instructions.md b/.github/instructions/instructions.instructions.md index c72cb2c4..7a744482 100644 --- a/.github/instructions/instructions.instructions.md +++ b/.github/instructions/instructions.instructions.md @@ -102,6 +102,7 @@ code example here - **Include Examples**: Real code snippets are more effective than descriptions - **Stay Current**: Reference current versions and best practices - **Link Resources**: Include official documentation and authoritative sources +- **Capture validated shell quirks**: For environment-specific instruction files, record proven terminal behaviors, quoting pitfalls, failing command patterns, and the known-good command form that replaced them ### Instruction Altitude (Goldilocks Zone) diff --git a/.github/instructions/regalamiunsorriso-83-149-164-4.instructions.md b/.github/instructions/regalamiunsorriso-83-149-164-4.instructions.md index 1259fa34..7b153171 100644 --- a/.github/instructions/regalamiunsorriso-83-149-164-4.instructions.md +++ b/.github/instructions/regalamiunsorriso-83-149-164-4.instructions.md @@ -35,6 +35,12 @@ If you need a single elevated command: ssh -tt -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "sudo tcsh -c 'command here'" ``` +From PowerShell on Windows, prefer invoking the SSH binary directly instead of wrapping it in `cmd /c`: + +```powershell +& 'C:\Windows\System32\OpenSSH\ssh.exe' -tt -i 'C:\Users\Maddo\.ssh\id_rsa' -p 410 'marco@83.149.164.4' +``` + ## Shell Behavior On This Host - The remote login shell behaves as `tcsh`. @@ -42,11 +48,15 @@ ssh -tt -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "sudo tcsh -c 'c - The server `sh` does not support `-l`, so use `sh -c`, not `sh -lc`. - `tcsh` treats redirection and pipelines differently from POSIX shells; commands like `find ... 2>/dev/null | head` can fail with `Ambiguous output redirect` unless the whole payload runs under `sh -c`. - Prefer one remote command per SSH invocation when doing reconnaissance. Complex commands with pipes, grouped expressions, or escaped parentheses are much more likely to break under PowerShell-to-SSH-to-`tcsh` quoting. +- On Windows PowerShell, avoid `cmd /c "ssh ..."` and `cmd /c "scp ..."` wrappers for anything nontrivial. Nested quoting can collapse before SSH runs and spill later tokens into the local PowerShell session, which leads to misleading local errors such as `sudo: The term 'sudo' is not recognized` or local attempts to run `cksum`. +- Prefer the PowerShell call operator form `& 'C:\Windows\System32\OpenSSH\ssh.exe' ...` and pass the remote command as a single argument when you must stay non-interactive. - If PowerShell shows the continuation prompt `? >`, the command was malformed locally before SSH executed it. Cancel it and rerun a simpler command instead of trying to answer the prompt. - If `sudo` reports that a terminal is required, reconnect with `-tt`. - When running remote commands from PowerShell, quoting can break if the command contains both nested quotes and file paths with spaces. - For read-only verification commands from PowerShell, prefer `ssh ... --% ` so the remote command is passed verbatim. - For `promote-file.sh` calls that target paths with spaces, prefer a local PowerShell loop that passes the full remote command as a single SSH argument instead of building one long nested quoted command. +- For multi-step privileged work, prefer opening one interactive SSH session, then running `sudo tcsh`, then issuing commands sequentially inside that shell. This is more reliable than trying to encode several `sudo tcsh -c 'a ; b ; c'` operations through PowerShell quoting. +- In an interactive `tcsh` root shell, do not re-send a password or any other text starting with `!` after the password prompt has already succeeded. `tcsh` interprets `!` as history expansion and will emit `Event not found`. - If repeated SSH commands start cancelling or interleaving poorly in the same terminal, rerun them sequentially instead of in parallel. ## Mail Template Runtime Notes @@ -88,6 +98,14 @@ ssh -tt -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "sudo tcsh -c 'c - Incoming staging root: `/home/marco/regalamiunsorriso/incoming/www` - Live site root: `/home/sites/regalamiunsorriso/www` +## Tomcat Logs And Runtime Clues + +- The active Tomcat installation on this host is under `/usr/local/apache-tomcat-9.0`. +- The most useful live runtime log is `/usr/local/apache-tomcat-9.0/logs/catalina.out`. +- Rotated Tomcat logs are under `/usr/local/apache-tomcat-9.0/logs/`, including files such as `catalina.YYYY-MM-DD.log` and `localhost.YYYY-MM-DD.log`. +- Access to generated JSP work files under `/usr/local/apache-tomcat-9.0/work` may require root. +- A broken JSP on this host can still return `HTTP 200` with a visibly truncated HTML body instead of a clean 500 response; when that happens, fetch part of the page body with `curl -L | head -n ...` and compare the cutoff point with recent `catalina.out` output. + ## Staging Workflow When `www/**` files need deployment: @@ -103,6 +121,9 @@ Example staging command pattern: tar -cf - -C K:\various\regalamiunsorriso | ssh -i C:\Users\Maddo\.ssh\id_rsa -p 410 marco@83.149.164.4 "tar -xf - -C /home/marco/regalamiunsorriso/incoming" ``` +- The streamed tar extraction into `/home/marco/regalamiunsorriso/incoming` works as the unprivileged `marco` user and avoids the permission problems seen when uploading an archive and trying to unpack it with `sudo tar`. +- Do not rely on `sudo tar` for staging on this host. `marco` is not permitted to run that extraction as root. + ## Promotion Rules - Promotion to the live site must happen through `sudo tcsh`. @@ -136,6 +157,13 @@ $remote = "sudo tcsh -c \"/home/marco/promote-file.sh '' ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Regalami Un Sorriso ETS - Competitions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+

Running // Running // 42 HALF MARATHON FIRENZE

+
+
+ + +
+
+ +
+
+ +
+ + + + + + + + +
+ + + +
+

Search your photos

+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+

They have been found 35389 photo + + +

+

+
+
+ +
+
+
+ + + go to page + + +
+
+ + +
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ +
+
+
+ +

ATTENTION! GOOGLE ADVERTISING + + + +

+ + + + + +
+ + + + + + + + + + + + + + +
+ +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faceai/authenticated_output.html b/faceai/authenticated_output.html new file mode 100644 index 00000000..e14e1696 --- /dev/null +++ b/faceai/authenticated_output.html @@ -0,0 +1,1120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Regalami Un Sorriso ETS - Competitions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+

Running // Running // 42 HALF MARATHON FIRENZE

+
+
+ + +
+
+ +
+
+ +
+ + + + + + + + +
+ + + +
+

Search your photos

+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+

They have been found 35389 photo + + +

+

+
+
+ +
+
+
+ + + go to page + + +
+
+ + +
+
+ + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + +
+
+
+ +

ATTENTION! GOOGLE ADVERTISING + + + +

+ + + + + +
+ + + + + + + + + + + + + + +
+ +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faceai/headers.txt b/faceai/headers.txt new file mode 100644 index 00000000..e69de29b diff --git a/faceai/login_response.html b/faceai/login_response.html new file mode 100644 index 00000000..ebb9936e --- /dev/null +++ b/faceai/login_response.html @@ -0,0 +1,359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Regalami Un Sorriso ETS - User Area + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+

User Area

+ +

HI Giacomelli Piero
+ Address: Fosso del Masi n. 24, Prato 59100 (PO)
+ Company belonging to: REGALAMI UN SORRISO ONLUS
+ Telephone: 3487258208
+ E-mail: [email protected]
+ Tax ID code: GCMPRI58H25G999U
+ Expiration Date: 15/06/2030
+ No. of photos displayed/No. of photos max: 37045/0
+ Number of photos viewed today: 0

+

Please verify that the information is correct. For changes, please write to [email protected] or go to Edit Data
+ Please note that tacit consent to the accuracy of the member personal data is required.

+ +

.Mancano. 1518 .giorni alla scadenza..
+

+ + +
+
+ +
+
Login ok
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faceai/package.json b/faceai/package.json index 4a363e79..473af682 100644 --- a/faceai/package.json +++ b/faceai/package.json @@ -16,7 +16,10 @@ "start:processor": "npm run start --workspace @regalami/faceai-processor", "test:e2e": "playwright test", "test:e2e:headed": "playwright test --headed", - "test:e2e:install": "playwright install chromium" + "test:e2e:install": "playwright install chromium", + "test:live": "playwright test -c playwright.live.config.js", + "test:live:headed": "playwright test -c playwright.live.config.js --headed", + "test:live:install": "playwright install chromium" }, "devDependencies": { "@playwright/test": "^1.59.1", diff --git a/faceai/playwright.live.config.js b/faceai/playwright.live.config.js new file mode 100644 index 00000000..4795474a --- /dev/null +++ b/faceai/playwright.live.config.js @@ -0,0 +1,38 @@ +const path = require('path'); +const { defineConfig } = require('@playwright/test'); + +const authFile = path.join(__dirname, 'tests/live-site/.auth/user.json'); + +module.exports = defineConfig({ + testDir: './tests/live-site', + timeout: 2 * 60 * 1000, + expect: { + timeout: 20 * 1000 + }, + fullyParallel: false, + workers: 1, + reporter: [['list'], ['html', { open: 'never', outputFolder: 'playwright-report/live-site' }]], + outputDir: 'test-results/live-site', + use: { + baseURL: process.env.LIVE_SITE_BASE_URL || 'https://www.regalamiunsorriso.it', + browserName: 'chromium', + headless: true, + trace: 'retain-on-failure', + screenshot: 'only-on-failure', + video: 'retain-on-failure' + }, + projects: [ + { + name: 'setup', + testMatch: /.*\.setup\.js/ + }, + { + name: 'live-chromium', + dependencies: ['setup'], + testIgnore: /.*\.setup\.js/, + use: { + storageState: authFile + } + } + ] +}); \ No newline at end of file diff --git a/faceai/probe.js b/faceai/probe.js new file mode 100644 index 00000000..e20ca7bb --- /dev/null +++ b/faceai/probe.js @@ -0,0 +1,47 @@ +const { chromium } = require('playwright'); +const fs = require('fs'); + +async function run() { + const browser = await chromium.launch(); + const context = await browser.newContext(); + const page = await context.newPage(); + + try { + const loginUrl = process.env.LIVE_SITE_LOGIN_URL; + const raceUrl = process.env.LIVE_SITE_RACE_URL; + + console.log('--- Step 1: Navigating to Login ---'); + await page.goto(loginUrl, { waitUntil: 'load' }); + + console.log('--- Step 2: Filling credentials ---'); + await page.type('#login', process.env.LIVE_SITE_USERNAME); + await page.type('#pwd', process.env.LIVE_SITE_PASSWORD); + + console.log('--- Step 3: Clicking Accedi ---'); + await page.click('button:has-text("Accedi")'); + await page.waitForTimeout(5000); // Give it time to process and redirect + + console.log('--- Step 4: Navigating to Race Page ---'); + const response = await page.goto(raceUrl, { waitUntil: 'load' }); + + console.log('Race Page URL:', page.url()); + console.log('HTTP Status:', response.status()); + + const cookies = await context.cookies(); + const cookieNames = cookies.map(c => c.name); + console.log('Cookies:', cookieNames.join(', ')); + console.log('rus_faceai_identity:', cookieNames.includes('rus_faceai_identity')); + console.log('JSESSIONID:', cookieNames.includes('JSESSIONID')); + + const logoutCount = await page.locator('a[href*="logout"]').count(); + const loginCount = await page.locator('a[href*="login"]').count(); + console.log('Logout Link Count:', logoutCount); + console.log('Login Link Count:', loginCount); + + } catch (err) { + console.error('Error occurred:', err.message); + } finally { + await browser.close(); + } +} +run(); diff --git a/faceai/response.html b/faceai/response.html new file mode 100644 index 00000000..0d0514e7 --- /dev/null +++ b/faceai/response.html @@ -0,0 +1,1100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Regalami Un Sorriso ETS - Gare + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+

Podismo // Podismo // 42 HALF MARATHON FIRENZE

+
+
+ + +
+
+ +
+
+ +
+ + + + + + + + +
+ + + +
+

Cerca le tue foto

+
+
+
+ + +
+
+
+
+ + +
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+
+
+
+
+

Sono state trovate 35389 foto + + +

+

+
+
+ +
+
+
+ + + vai a pag. + + +
+
+ + +
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ + + +
Hits: 0 -
+
+ +
+
+
+ +

ATTENZIONE ! PUBBLICITA' GOOGLE + + + +

+ + + + + +
+ + + + + + + + + + + + + + +
+ +
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faceai/tests/live-site/auth.setup.js b/faceai/tests/live-site/auth.setup.js new file mode 100644 index 00000000..c0d47555 --- /dev/null +++ b/faceai/tests/live-site/auth.setup.js @@ -0,0 +1,12 @@ +const { test } = require('@playwright/test'); +const { + AUTH_FILE, + ensureAuthDirectory, + performLiveLogin +} = require('./live-site-test-utils'); + +test('authenticate against the live site', async ({ page }) => { + ensureAuthDirectory(); + await performLiveLogin(page); + await page.context().storageState({ path: AUTH_FILE }); +}); \ No newline at end of file diff --git a/faceai/tests/live-site/live-race.spec.js b/faceai/tests/live-site/live-race.spec.js new file mode 100644 index 00000000..1ae3a2d0 --- /dev/null +++ b/faceai/tests/live-site/live-race.spec.js @@ -0,0 +1,33 @@ +const { test, expect } = require('@playwright/test'); +const { + LIVE_SITE_RACE_URL, + dismissCookieBanner, + expectRacePageLoaded, + performLiveLogin, + waitForLoggedInUi +} = require('./live-site-test-utils'); + +test('loads a live race page with an authenticated session', async ({ page }) => { + await page.goto(LIVE_SITE_RACE_URL, { waitUntil: 'domcontentloaded' }); + await dismissCookieBanner(page); + + try { + await waitForLoggedInUi(page); + } catch (error) { + await performLiveLogin(page); + await page.goto(LIVE_SITE_RACE_URL, { waitUntil: 'domcontentloaded' }); + await dismissCookieBanner(page); + await waitForLoggedInUi(page); + } + + await expectRacePageLoaded(page); + await expect(page.locator('h1')).toContainText(/HALF MARATHON FIRENZE|Competitions|Gare/i); + + const cookies = await page.context().cookies(LIVE_SITE_RACE_URL); + const faceAiIdentityCookie = cookies.find((cookie) => cookie.name === 'rus_faceai_identity'); + + expect(faceAiIdentityCookie, 'Expected the race page to mint the FaceAI identity cookie for the authenticated session.').toBeTruthy(); + expect(faceAiIdentityCookie.httpOnly).toBe(true); + expect(faceAiIdentityCookie.secure).toBe(true); + expect(faceAiIdentityCookie.value).toMatch(/\./); +}); \ No newline at end of file diff --git a/faceai/tests/live-site/live-site-test-utils.js b/faceai/tests/live-site/live-site-test-utils.js new file mode 100644 index 00000000..f7f99061 --- /dev/null +++ b/faceai/tests/live-site/live-site-test-utils.js @@ -0,0 +1,92 @@ +const fs = require('fs'); +const path = require('path'); +const { expect } = require('@playwright/test'); + +const LIVE_SITE_BASE_URL = process.env.LIVE_SITE_BASE_URL || 'https://www.regalamiunsorriso.it'; +const LIVE_SITE_LOGIN_URL = process.env.LIVE_SITE_LOGIN_URL || `${LIVE_SITE_BASE_URL}/login_clienti-it.html`; +const LIVE_SITE_RACE_URL = process.env.LIVE_SITE_RACE_URL || `${LIVE_SITE_BASE_URL}/42%20HALF%20MARATHON%20FIRENZE_gara-1018545---96-1.html`; +const LIVE_SITE_USERNAME = process.env.LIVE_SITE_USERNAME || ''; +const LIVE_SITE_PASSWORD = process.env.LIVE_SITE_PASSWORD || ''; +const AUTH_FILE = path.join(__dirname, '.auth', 'user.json'); + +function ensureAuthDirectory() { + fs.mkdirSync(path.dirname(AUTH_FILE), { recursive: true }); +} + +function requireCredentials() { + if (!LIVE_SITE_USERNAME || !LIVE_SITE_PASSWORD) { + throw new Error('LIVE_SITE_USERNAME and LIVE_SITE_PASSWORD must be set before running the live-site Playwright suite.'); + } +} + +async function dismissCookieBanner(page) { + const cookieButton = page.getByRole('button', { name: /^(Accetto|Accept)$/i }); + if (await cookieButton.count()) { + await cookieButton.first().click({ timeout: 5000 }).catch(() => {}); + return; + } + + const fallbackButton = page.locator('.cc-btn, .cc-dismiss, .cc-allow').filter({ hasText: /Accetto|Accept/i }); + if (await fallbackButton.count()) { + await fallbackButton.first().click({ timeout: 5000 }).catch(() => {}); + } +} + +function loginSubmitLocator(page) { + return page.locator('a.btn').filter({ hasText: /Accedi|Sign in/i }).first(); +} + +async function performLiveLogin(page) { + requireCredentials(); + + await page.goto(LIVE_SITE_LOGIN_URL, { waitUntil: 'domcontentloaded' }); + await dismissCookieBanner(page); + await page.locator('#login').fill(LIVE_SITE_USERNAME); + await page.locator('#pwd').fill(LIVE_SITE_PASSWORD); + await loginSubmitLocator(page).click(); + await waitForLoggedInUi(page); +} + +async function waitForLoggedInUi(page) { + const accountMenu = page.locator('#navbarDropdownMenuLink'); + const accountLink = page.locator('a[href*="dettaglio_clienti"]'); + const logoutLink = page.locator('a[href*="user_logout"]'); + + await expect.poll(async () => { + if (await accountMenu.count() && await accountMenu.first().isVisible().catch(() => false)) { + return 'account-menu'; + } + if (await accountLink.count() && await accountLink.first().isVisible().catch(() => false)) { + return 'account-link'; + } + if (await logoutLink.count() && await logoutLink.first().isVisible().catch(() => false)) { + return 'logout-link'; + } + return ''; + }, { + timeout: 30 * 1000, + message: 'Expected the logged-in account UI to appear after authenticating.' + }).not.toBe(''); +} + +async function expectRacePageLoaded(page) { + await expect(page.locator('form[onsubmit="return searching()"]')).toBeVisible(); + await expect(page.locator('#id_gara')).toHaveValue(/\d+/); + await expect(page.locator('script[src*="_js/rus-ecom-240621.js"]')).toHaveCount(1); +} + +module.exports = { + AUTH_FILE, + LIVE_SITE_BASE_URL, + LIVE_SITE_LOGIN_URL, + LIVE_SITE_PASSWORD, + LIVE_SITE_RACE_URL, + LIVE_SITE_USERNAME, + dismissCookieBanner, + ensureAuthDirectory, + expectRacePageLoaded, + loginSubmitLocator, + performLiveLogin, + requireCredentials, + waitForLoggedInUi +}; \ No newline at end of file diff --git a/faceai/tmp-live-state-inspection.json b/faceai/tmp-live-state-inspection.json new file mode 100644 index 00000000..31a25038 --- /dev/null +++ b/faceai/tmp-live-state-inspection.json @@ -0,0 +1,45 @@ +{ + "cookies": [ + { + "name": "JSESSIONID", + "value": "C78CCBD1771ACB52852817531958E96D", + "domain": "www.regalamiunsorriso.it", + "path": "/", + "expires": -1, + "httpOnly": true, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "_pk_id.6.42c1", + "value": "5710c1018f76b02c.1776585670.", + "domain": "www.regalamiunsorriso.it", + "path": "/", + "expires": 1810540870, + "httpOnly": false, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "_pk_ses.6.42c1", + "value": "1", + "domain": "www.regalamiunsorriso.it", + "path": "/", + "expires": 1776587471, + "httpOnly": false, + "secure": false, + "sameSite": "Lax" + }, + { + "name": "g_state", + "value": "{\"i_l\":0,\"i_ll\":1776585670175,\"i_b\":\"TwramoDGp33YsAyHyO2OJCLtRobG3bzu5wR3/nYmZ0E\",\"i_e\":{\"enable_itp_optimization\":0},\"i_et\":1776585670056}", + "domain": "www.regalamiunsorriso.it", + "path": "/", + "expires": 1792137670, + "httpOnly": false, + "secure": false, + "sameSite": "Lax" + } + ], + "origins": [] +} \ No newline at end of file diff --git a/sync/www-deploy-manifest.md b/sync/www-deploy-manifest.md index b1e6ae06..dc174365 100644 --- a/sync/www-deploy-manifest.md +++ b/sync/www-deploy-manifest.md @@ -10,20 +10,17 @@ All files in this rollout are deployed from the current working tree. ## New Files -- None in this rollout. +- `www/_inc_faceai_identity.jsp` +- `www/_js/lang.js` ## Updated Files -- `www/faceai_config.php` -- `www/faceai_handoff.php` -- `www/faceai_return.php` -- `www/fotoCR.jsp` - `www/fotoCR-en.jsp` +- `www/fotoCR.jsp` ## Excluded Files -- `www/faceai_simulator.php` -- `www/faceai_simulator_view.php` +- None in this rollout. ## Remote Copy Target @@ -31,7 +28,7 @@ All files in this rollout are deployed from the current working tree. - Remote host: `marco@83.149.164.4:410` - Remote staging path: `/home/marco/regalamiunsorriso/incoming/www` - Remote live path: `/home/sites/regalamiunsorriso/www` -- Total files in this manifest: `5` +- Total files in this manifest: `4` ## Transfer Method diff --git a/www/_inc_faceai_identity.jsp b/www/_inc_faceai_identity.jsp new file mode 100644 index 00000000..7d3cb783 --- /dev/null +++ b/www/_inc_faceai_identity.jsp @@ -0,0 +1,260 @@ +<%@ page language="java" import="java.nio.charset.StandardCharsets" %> +<%@ page language="java" import="java.util.Base64" %> +<%@ page language="java" import="java.lang.reflect.Method" %> +<%@ page language="java" import="javax.crypto.Mac" %> +<%@ page language="java" import="javax.crypto.spec.SecretKeySpec" %> +<%! +private String faceAiCookieEnv(String key, String defaultValue) { + String value = System.getenv(key); + if (value == null || value.trim().length() == 0) { + value = System.getProperty(key, defaultValue); + } + if (value == null) { + return defaultValue; + } + value = value.trim(); + return value.length() == 0 ? defaultValue : value; +} + +private String faceAiBase64Url(byte[] value) { + return Base64.getUrlEncoder().withoutPadding().encodeToString(value); +} + +private String faceAiJsonEscape(String value) { + if (value == null) { + return ""; + } + + StringBuilder builder = new StringBuilder(value.length() + 16); + for (int index = 0; index < value.length(); index++) { + char current = value.charAt(index); + switch (current) { + case '\\': + builder.append("\\\\"); + break; + case '"': + builder.append("\\\""); + break; + case '\b': + builder.append("\\b"); + break; + case '\f': + builder.append("\\f"); + break; + case '\n': + builder.append("\\n"); + break; + case '\r': + builder.append("\\r"); + break; + case '\t': + builder.append("\\t"); + break; + default: + if (current < 0x20) { + String hex = Integer.toHexString(current); + builder.append("\\u"); + for (int padding = hex.length(); padding < 4; padding++) { + builder.append('0'); + } + builder.append(hex); + } else { + builder.append(current); + } + break; + } + } + return builder.toString(); +} + +private Object faceAiInvoke(Object bean, String methodName) { + if (bean == null || methodName == null || methodName.length() == 0) { + return null; + } + + try { + Method method = bean.getClass().getMethod(methodName, new Class[0]); + return method.invoke(bean, new Object[0]); + } catch (Exception ignored) { + return null; + } +} + +private long faceAiUserId(Object user) { + Object value = faceAiInvoke(user, "getId_users"); + if (value instanceof Number) { + return ((Number) value).longValue(); + } + if (value != null) { + try { + return Long.parseLong(String.valueOf(value)); + } catch (NumberFormatException ignored) { + return 0L; + } + } + return 0L; +} + +private String faceAiUserString(Object user, String methodName) { + Object value = faceAiInvoke(user, methodName); + return value == null ? "" : String.valueOf(value).trim(); +} + +private boolean faceAiUserDaRinnovare(Object user) { + Object value = faceAiInvoke(user, "isDaRinnovare"); + return value instanceof Boolean ? ((Boolean) value).booleanValue() : false; +} + +private String faceAiCookieDisplayName(Object user) { + String nome = faceAiUserString(user, "getNome"); + String cognome = faceAiUserString(user, "getCognome"); + String displayName = (nome + " " + cognome).trim(); + if (displayName.length() > 0) { + return displayName; + } + + String email = faceAiUserString(user, "getEMail"); + if (email.length() > 0) { + return email; + } + + return String.valueOf(faceAiUserId(user)); +} + +private String faceAiIdentityToken(Object user, String secret, long expiresAt) throws Exception { + String email = faceAiUserString(user, "getEMail"); + String membershipStatus = faceAiUserDaRinnovare(user) ? "inactive" : "active"; + String payload = "{" + + "\"type\":\"legacy-identity\"," + + "\"userId\":\"" + faceAiJsonEscape(String.valueOf(faceAiUserId(user))) + "\"," + + "\"displayName\":\"" + faceAiJsonEscape(faceAiCookieDisplayName(user)) + "\"," + + "\"email\":\"" + faceAiJsonEscape(email) + "\"," + + "\"membershipStatus\":\"" + membershipStatus + "\"," + + "\"expiresAt\":" + expiresAt + + "}"; + + String body = faceAiBase64Url(payload.getBytes(StandardCharsets.UTF_8)); + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + String signature = faceAiBase64Url(mac.doFinal(body.getBytes(StandardCharsets.UTF_8))); + return body + "." + signature; +} + +private boolean faceAiRequestIsSecure(javax.servlet.http.HttpServletRequest request) { + if (request == null) { + return false; + } + if (request.isSecure()) { + return true; + } + + String forwardedProto = request.getHeader("X-Forwarded-Proto"); + if (forwardedProto != null && "https".equalsIgnoreCase(forwardedProto.trim())) { + return true; + } + + String frontEndHttps = request.getHeader("Front-End-Https"); + return frontEndHttps != null && "on".equalsIgnoreCase(frontEndHttps.trim()); +} + +private void faceAiWriteCookieHeader(javax.servlet.http.HttpServletResponse response, String cookieName, String cookieValue, int maxAgeSeconds, boolean secureCookie) { + StringBuilder headerValue = new StringBuilder(); + headerValue.append(cookieName).append('=').append(cookieValue == null ? "" : cookieValue); + headerValue.append("; Max-Age=").append(maxAgeSeconds); + headerValue.append("; Path=/; HttpOnly; SameSite=Lax"); + if (secureCookie) { + headerValue.append("; Secure"); + } + response.addHeader("Set-Cookie", headerValue.toString()); +} + +private Object faceAiResolveUser(javax.servlet.jsp.PageContext pageContext) { + if (pageContext == null) { + return null; + } + + Object[] candidates = new Object[] { + pageContext.findAttribute("user"), + pageContext.findAttribute("utenteLogon") + }; + + for (int index = 0; index < candidates.length; index++) { + Object candidate = candidates[index]; + if (candidate != null && faceAiUserId(candidate) > 0L) { + return candidate; + } + } + + return null; +} + +private Object faceAiResolveUserFromSession(javax.servlet.jsp.PageContext pageContext) { + if (pageContext == null || pageContext.getSession() == null) { + return null; + } + + Object loginUserId = pageContext.getSession().getAttribute("loginUser_id"); + long resolvedLoginUserId = 0L; + if (loginUserId instanceof Number) { + resolvedLoginUserId = ((Number) loginUserId).longValue(); + } else if (loginUserId != null) { + try { + resolvedLoginUserId = Long.parseLong(String.valueOf(loginUserId)); + } catch (NumberFormatException ignored) { + resolvedLoginUserId = 0L; + } + } + + if (resolvedLoginUserId <= 0L) { + return null; + } + + Object sessionUser = pageContext.findAttribute("utenteLogon"); + if (sessionUser == null) { + return null; + } + + if (faceAiUserId(sessionUser) == resolvedLoginUserId) { + return sessionUser; + } + + try { + Method findByPrimaryKey = sessionUser.getClass().getMethod("findByPrimaryKey", long.class); + findByPrimaryKey.invoke(sessionUser, Long.valueOf(resolvedLoginUserId)); + } catch (NoSuchMethodException missingPrimitiveOverload) { + try { + Method findByPrimaryKey = sessionUser.getClass().getMethod("findByPrimaryKey", Long.class); + findByPrimaryKey.invoke(sessionUser, new Long(resolvedLoginUserId)); + } catch (Exception ignored) { + return null; + } + } catch (Exception ignored) { + return null; + } + + return faceAiUserId(sessionUser) > 0L ? sessionUser : null; +} +%> +<% +String faceAiCookieName = faceAiCookieEnv("FACEAI_IDENTITY_COOKIE", "rus_faceai_identity"); +String faceAiCookieSecret = faceAiCookieEnv("FACEAI_SHARED_SECRET", "disagio-spaghetti-science-lol-boh"); +Object faceAiRequestUser = pageContext.findAttribute("user"); +Object faceAiSessionUser = pageContext.findAttribute("utenteLogon"); +long faceAiRequestUserId = faceAiUserId(faceAiRequestUser); +long faceAiSessionUserId = faceAiUserId(faceAiSessionUser); +Object faceAiCookieUser = faceAiRequestUserId > 0L ? faceAiRequestUser : (faceAiSessionUserId > 0L ? faceAiSessionUser : faceAiResolveUserFromSession(pageContext)); +boolean faceAiSecureCookie = faceAiRequestIsSecure(request); + +if (faceAiFeatureEnabled && faceAiCookieUser != null && faceAiUserId(faceAiCookieUser) > 0L) { + long faceAiExpiresAt = System.currentTimeMillis() + (30L * 60L * 1000L); + try { + String faceAiToken = faceAiIdentityToken(faceAiCookieUser, faceAiCookieSecret, faceAiExpiresAt); + faceAiWriteCookieHeader(response, faceAiCookieName, faceAiToken, 30 * 60, faceAiSecureCookie); + } catch (Exception faceAiIdentityError) { + faceAiWriteCookieHeader(response, faceAiCookieName, "", 0, faceAiSecureCookie); + log("Unable to mint FaceAI identity cookie", faceAiIdentityError); + } +} else { + faceAiWriteCookieHeader(response, faceAiCookieName, "", 0, faceAiSecureCookie); +} +%> \ No newline at end of file diff --git a/www/_js/lang.js b/www/_js/lang.js new file mode 100644 index 00000000..f6cb59e0 --- /dev/null +++ b/www/_js/lang.js @@ -0,0 +1,55 @@ +// JavaScript Document +//////////////////////////////////////////// +// gestione cambio lingua +//////////////////////////////////////////// +var userLang = navigator.language || navigator.userLanguage; +console.log(userLang); + +function changeLang(lang) { + var page = window.location.href; + var idx = page.lastIndexOf("."); + + if (idx > 0) { + var ext = page.substring(idx, page.length); + + if (ext.indexOf("eu") >= 0 || ext.indexOf("com") >= 0 || ext.indexOf("net") >= 0 || ext.indexOf("it") >= 0) { + ext = ""; + var page1 = page; + } + else + + var page1 = page.substring(0, idx); + } + else { + // caso di pagina root www.xxxx.com/ + var ext = ""; + var page1 = page; + } + // 1 se ho pagine del tipo xxx.html --> aggiungo -lang.html + // 2 se ho pagine del tipo xxx_xxx-xxx-xxx-.html --> sostituisco l'ultima parte con xxx-lang.html + // 3 se ho pagine del tipo xxx_xxx-xx-xx-lang.html --> sostituisco l'ultima parte + // 4 se non ho estensione sono nella root e finisce con /(www.xxxx.com/) --> vado su index-lang + // 5 altrimenti vado su index-lang.jsp + // 6 caso Ordine.abl --> ritorno alla home + + if (ext == ".abl") { + theSvlt = "index-" + lang + ".html"; + } + else if (ext == "") { + theSvlt = page1 + "index-" + lang + ".html"; + } + else if (page1.lastIndexOf("-") == (page1.length - 1)) { + theSvlt = page1 + lang + ext; + } + else if (page1.lastIndexOf("-") == (page1.length - 3)) { + theSvlt = page1.substring(0, page1.length - 2) + lang + ext; + } + else if (page1.substring(page1.length - 1, page1.length) != "-") { + theSvlt = page1 + "-" + lang + ext; + } + else { + theSvlt = "index-" + lang + ".jsp"; + } + + location.href = theSvlt; +} \ No newline at end of file diff --git a/www/fotoCR-en.jsp b/www/fotoCR-en.jsp index 17ad6e47..f275b270 100644 --- a/www/fotoCR-en.jsp +++ b/www/fotoCR-en.jsp @@ -8,7 +8,6 @@ <%@ taglib uri="/WEB-INF/cc.tld" prefix="cc" %> - @@ -57,6 +56,10 @@ if (faceAiFeatureEnabledValue == null || faceAiFeatureEnabledValue.trim().length } String faceAiFeatureEnabledNormalized = faceAiFeatureEnabledValue != null ? faceAiFeatureEnabledValue.trim() : ""; boolean faceAiFeatureEnabled = !("0".equals(faceAiFeatureEnabledNormalized) || "false".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "no".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "off".equalsIgnoreCase(faceAiFeatureEnabledNormalized)); +%> +<%@ include file="_inc_faceai_identity.jsp" %> + +<% java.util.Date faceAiRaceDate = CR.getGara().getDataGaraInizio(); String faceAiRacePathBase = CR.getGara().getPathBase() != null ? CR.getGara().getPathBase().trim() : ""; String faceAiRaceYear = ""; diff --git a/www/fotoCR.jsp b/www/fotoCR.jsp index 76b6aaf7..596c240f 100644 --- a/www/fotoCR.jsp +++ b/www/fotoCR.jsp @@ -8,7 +8,6 @@ <%@ taglib uri="/WEB-INF/cc.tld" prefix="cc" %> - @@ -57,6 +56,10 @@ if (faceAiFeatureEnabledValue == null || faceAiFeatureEnabledValue.trim().length } String faceAiFeatureEnabledNormalized = faceAiFeatureEnabledValue != null ? faceAiFeatureEnabledValue.trim() : ""; boolean faceAiFeatureEnabled = !("0".equals(faceAiFeatureEnabledNormalized) || "false".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "no".equalsIgnoreCase(faceAiFeatureEnabledNormalized) || "off".equalsIgnoreCase(faceAiFeatureEnabledNormalized)); +%> +<%@ include file="_inc_faceai_identity.jsp" %> + +<% java.util.Date faceAiRaceDate = CR.getGara().getDataGaraInizio(); String faceAiRacePathBase = CR.getGara().getPathBase() != null ? CR.getGara().getPathBase().trim() : ""; String faceAiRaceYear = ""; diff --git a/www_staged.tar b/www_staged.tar new file mode 100644 index 0000000000000000000000000000000000000000..4e6853edd0e41b435e91b7ad30b0d6ce8996e381 GIT binary patch literal 49152 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 literal 0 HcmV?d00001