diff --git a/.env.example b/.env.example index ed69ec1..945ffce 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,12 @@ VITE_PLIMI_REPO_URL=https://github.com/your-org/plimi +VITE_SITE_URL=https://plimi.example.com +VITE_LEGAL_NAME=Achraf ACHKARI-BEGDOURI +VITE_LEGAL_COUNTRY=France +VITE_PRIVACY_EMAIL=privacy@example.com +VITE_PRIVACY_EFFECTIVE_DATE=2026-06-07 +VITE_ANALYTICS_PROVIDER_NAME=Umami +VITE_ANALYTICS_SCRIPT_URL=https://u.achraf.app/script.js +VITE_ANALYTICS_WEBSITE_ID=89d0f8d2-5b59-438c-b1f6-ab2655e97f6e +VITE_ANALYTICS_HOST=u.achraf.app +VITE_ANALYTICS_HOST_COUNTRY=France +VITE_ANALYTICS_RETENTION_MONTHS=13 diff --git a/.gitignore b/.gitignore index ecb13c8..ab25981 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,9 @@ node_modules dist dist-ssr *.local +.env +.env.* +!.env.example # Editor directories and files .vscode/* @@ -23,4 +26,4 @@ dist-ssr *.sln *.sw? -ignored \ No newline at end of file +ignored diff --git a/Dockerfile b/Dockerfile index 4689fd3..67ba335 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,11 +9,9 @@ RUN pnpm install --frozen-lockfile FROM node:22-alpine AS build WORKDIR /app RUN corepack enable && corepack prepare pnpm@10.33.2 --activate -ARG VITE_PLIMI_REPO_URL=https://github.com/your-org/plimi -ENV VITE_PLIMI_REPO_URL=$VITE_PLIMI_REPO_URL COPY --from=deps /app/node_modules ./node_modules COPY . . -RUN pnpm build +RUN --mount=type=secret,id=vite_env,target=/app/.env,required=true pnpm build FROM nginx:1.27-alpine AS runtime COPY nginx.conf /etc/nginx/conf.d/default.conf diff --git a/README.md b/README.md index 86b4ad6..938102d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Plimi: Privacy-First Browser Toolbox -Plimi is a modern, modular, zero-backend utility suite that executes all tools directly inside your browser. No data ever leaves your device. +Plimi is a modern, modular utility suite that executes tool processing directly inside your browser. Tool inputs and outputs are not uploaded by Plimi. ## Features -- **Privacy-First Design**: Completely offline-capable. No data is sent to external servers. +- **Privacy-First Design**: Tool processing is offline-capable. Optional audience analytics load only after consent. - **Plugin Architecture**: Modular, strictly-typed plugin ecosystem supporting custom UI or generated UI based on schema. - **Web Workers & WASM**: Supports off-loading expensive operations (e.g. PDF manipulation, media processing) into separate threads. - **High Performance**: Built with React, Vite, and Tailwind CSS v4. @@ -36,9 +36,9 @@ npm run build Build and run the static production app with Nginx: ```bash -docker build \ - --build-arg VITE_PLIMI_REPO_URL=https://github.com/your-org/plimi \ - -t plimi:local . +cp .env.example .env +# Edit .env with the real deployment and legal values. +docker build --secret id=vite_env,src=.env -t plimi:local . docker run --rm -p 8080:80 --name plimi plimi:local ``` @@ -46,13 +46,33 @@ docker run --rm -p 8080:80 --name plimi plimi:local Or use Docker Compose: ```bash -VITE_PLIMI_REPO_URL=https://github.com/your-org/plimi PLIMI_PORT=8080 docker compose up --build +cp .env.example .env +# Edit .env, then: +docker compose up --build ``` Environment: - `VITE_PLIMI_REPO_URL`: build-time public repository URL shown on the Contribute page. +- `VITE_SITE_URL`: canonical public URL used to restrict analytics to the deployed hostname. +- `VITE_LEGAL_NAME`, `VITE_LEGAL_COUNTRY`: controller identity shown in the privacy notice. +- `VITE_PRIVACY_EMAIL`: contact address for privacy and data-subject requests. +- `VITE_PRIVACY_EFFECTIVE_DATE`: effective date displayed on the privacy notice. +- `VITE_ANALYTICS_SCRIPT_URL`, `VITE_ANALYTICS_WEBSITE_ID`: Umami tracker configuration. +- `VITE_ANALYTICS_HOST`, `VITE_ANALYTICS_HOST_COUNTRY`: analytics recipient and hosting location disclosed to visitors. +- `VITE_ANALYTICS_RETENTION_MONTHS`: disclosed analytics retention period. Configure Umami/database deletion to match it. - `PLIMI_PORT`: host port used by Docker Compose, default `8080`. +Analytics is consent-first. The tracker is injected only after acceptance and is +configured to exclude URL search parameters and hashes and honor Do Not Track. +The privacy page is available at `/privacy`; deployers must replace all example +controller and hosting values before publishing. + +Docker mounts `.env` as a BuildKit secret only while Vite builds the static +bundle. The file is ignored by Git and excluded from the regular Docker context. +Remember that `VITE_*` values are public build-time configuration and can be +read from the resulting browser JavaScript; do not put passwords or API secrets +in them. + --- ## How to Create a Tool (Plugin) diff --git a/docker-compose.yml b/docker-compose.yml index 913c26d..85b47e2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,10 +2,14 @@ services: plimi: build: context: . - args: - VITE_PLIMI_REPO_URL: ${VITE_PLIMI_REPO_URL:-https://github.com/your-org/plimi} + secrets: + - vite_env image: plimi:local container_name: plimi ports: - "${PLIMI_PORT:-8080}:80" restart: unless-stopped + +secrets: + vite_env: + file: ./.env diff --git a/index.html b/index.html index 9492f06..711b815 100644 --- a/index.html +++ b/index.html @@ -4,10 +4,6 @@ - - - -
+ With your permission, Plimi loads {privacyConfig.analyticsProvider} from{" "} + {privacyConfig.analyticsHost} to measure page visits and device/browser + categories. Tool inputs, files, and outputs are never included. +
+ +Plimi is a collection of small local utilities. The interface loads the tool, runs the - work in the browser, then hands the result back to you without a server round trip. + work in the browser, then hands the result back to you without uploading your tool + input. Optional audience analytics are separate and require your consent.
diff --git a/src/pages/PrivacyPage.tsx b/src/pages/PrivacyPage.tsx new file mode 100644 index 0000000..d5e8de5 --- /dev/null +++ b/src/pages/PrivacyPage.tsx @@ -0,0 +1,151 @@ +import { useAnalyticsConsent } from "../core/privacy/analytics-consent-context"; +import { privacyConfig } from "../core/privacy/privacy-config"; + +function Section({ + title, + children, +}: { + title: string; + children: React.ReactNode; +}) { + return ( ++ Effective {privacyConfig.policyEffectiveDate}. This notice explains + who operates Plimi, what data the website processes, and the choices + available to you. +
++ The data controller is{" "} + + {privacyConfig.controllerName} + + , based in {privacyConfig.controllerCountry}. +
++ Privacy requests:{" "} + + {privacyConfig.privacyEmail} + + . Website: {privacyConfig.siteUrl}. +
++ Text, files, images, PDFs, generated passwords, and tool outputs are + processed by code running in your browser. Plimi does not upload this + tool content to an application server or include it in analytics. +
++ Files you download remain under your control. Browser features such + as the clipboard or local file picker are used only when you invoke + them. +
++ Analytics are disabled until you consent. If accepted, the site loads{" "} + {privacyConfig.analyticsProvider} from {privacyConfig.analyticsHost}. + It may process the visited route, referrer, timestamp, browser, + operating system, device type, screen size, language, and an + approximate location derived from network information. +
++ Purpose: aggregate audience measurement and improvement of Plimi. + Legal basis: your consent under GDPR Article 6(1)(a). Analytics data + is configured for a retention period of{" "} + {privacyConfig.analyticsRetentionMonths} months and is hosted in{" "} + {privacyConfig.analyticsHostCountry}. +
++ Plimi does not send tool inputs, uploaded file contents, outputs, + names, email addresses, or account identifiers to analytics. The + tracker is configured to exclude URL search parameters and hashes and + to honor browser Do Not Track. +
++ Plimi stores your theme preference and analytics choice in browser + local storage. These values are necessary to remember the settings + you selected. Plimi does not use advertising cookies. +
++ When analytics are accepted, analytics metadata is received by the + operator of {privacyConfig.analyticsHost} and any infrastructure + providers used to host it. The controller must maintain appropriate + processor agreements and transfer safeguards where a provider + processes data outside the EEA. +
++ Depending on applicable law, you may request access, correction, + deletion, restriction, or portability of your personal data. You may + withdraw analytics consent at any time through Analytics settings; + withdrawal does not affect prior lawful processing. +
++ Contact {privacyConfig.privacyEmail} to exercise a right. You may also + lodge a complaint with the data-protection authority in your country + of residence, work, or the place of an alleged infringement. +
++ Plimi uses HTTPS and access controls appropriate to the services it + operates. No internet service can guarantee absolute security. This + notice may be updated when processing or providers change; the + effective date above identifies the current version. +
+- {pluginRegistry.length} utilities for files, text and code — running entirely in your browser. No upload. No account. No server. + {pluginRegistry.length} utilities for files, text and code — running entirely in your browser. No tool-data upload. No account.