Remove hard-coded upstream tracking
This commit is contained in:
@@ -15,6 +15,8 @@ RUN --mount=type=cache,target=/root/.npm npm ci
|
|||||||
|
|
||||||
COPY upstream/HubFrontend/ ./
|
COPY upstream/HubFrontend/ ./
|
||||||
COPY docker/hcaptcha-sitekey.patch /tmp/hcaptcha-sitekey.patch
|
COPY docker/hcaptcha-sitekey.patch /tmp/hcaptcha-sitekey.patch
|
||||||
|
COPY docker/remove-analytics.mjs /tmp/remove-analytics.mjs
|
||||||
|
COPY docker/replace-fallback-avatar.mjs /tmp/replace-fallback-avatar.mjs
|
||||||
|
|
||||||
RUN if grep -q 'sitekey="1788882d-3695-4807-abac-7d7166ec6325"' src/routes/auth/login.js; then \
|
RUN if grep -q 'sitekey="1788882d-3695-4807-abac-7d7166ec6325"' src/routes/auth/login.js; then \
|
||||||
patch -p1 < /tmp/hcaptcha-sitekey.patch; \
|
patch -p1 < /tmp/hcaptcha-sitekey.patch; \
|
||||||
@@ -25,6 +27,9 @@ RUN if grep -q 'sitekey="1788882d-3695-4807-abac-7d7166ec6325"' src/routes/auth/
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
RUN node /tmp/remove-analytics.mjs
|
||||||
|
RUN node /tmp/replace-fallback-avatar.mjs
|
||||||
|
|
||||||
ARG ASSETS_BASE=""
|
ARG ASSETS_BASE=""
|
||||||
ARG VITE_USE_MULTIHUB=false
|
ARG VITE_USE_MULTIHUB=false
|
||||||
ARG VITE_MULTIHUB_DISCOVERY=""
|
ARG VITE_MULTIHUB_DISCOVERY=""
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ example, use `"abbr": "api"` with `"prefix": "/api"`.
|
|||||||
The frontend uses the Vite values during the image build. Rebuild the image after
|
The frontend uses the Vite values during the image build. Rebuild the image after
|
||||||
you change `.env`, including the hCaptcha site key.
|
you change `.env`, including the hCaptcha site key.
|
||||||
|
|
||||||
|
The build removes the hard-coded upstream Google Analytics integration and its
|
||||||
|
consent dialog. If upstream removes the known integration, the build skips this
|
||||||
|
step. If an unknown Analytics implementation remains, the build stops instead
|
||||||
|
of publishing it.
|
||||||
|
|
||||||
|
The build also replaces the hard-coded external login avatar with the bundled
|
||||||
|
`/logo.png` file. If upstream removes the known avatar URL, the build skips this
|
||||||
|
step.
|
||||||
|
|
||||||
## Start the deployment
|
## Start the deployment
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { readFileSync, writeFileSync } from "node:fs";
|
||||||
|
|
||||||
|
const appPath = "src/App.js";
|
||||||
|
let source = readFileSync(appPath, "utf8");
|
||||||
|
|
||||||
|
const analyticsStart = " const [cookieSettings, setCookieSettings] = useState(localStorage.getItem(\"cookie-settings\"));";
|
||||||
|
const analyticsEnd = " const hasSpeedDial =";
|
||||||
|
const consentStart = " {!window.isElectron && cookieSettings === null && !sidebarForceHidden && (";
|
||||||
|
const consentEnd = " <SimpleBar ";
|
||||||
|
|
||||||
|
const hasKnownAnalytics = source.includes("G-SLZ5TY9MVN");
|
||||||
|
const hasKnownState = source.includes(analyticsStart);
|
||||||
|
const hasKnownConsent = source.includes(consentStart);
|
||||||
|
|
||||||
|
if (hasKnownState && hasKnownConsent) {
|
||||||
|
const analyticsStartIndex = source.indexOf(analyticsStart);
|
||||||
|
const analyticsEndIndex = source.indexOf(analyticsEnd, analyticsStartIndex);
|
||||||
|
const consentStartIndex = source.indexOf(consentStart);
|
||||||
|
const consentEndIndex = source.indexOf(consentEnd, consentStartIndex);
|
||||||
|
|
||||||
|
if (analyticsEndIndex === -1 || consentEndIndex === -1) {
|
||||||
|
throw new Error("Cannot locate the complete upstream Analytics implementation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
source = source.slice(0, analyticsStartIndex) + source.slice(analyticsEndIndex);
|
||||||
|
|
||||||
|
const updatedConsentStartIndex = source.indexOf(consentStart);
|
||||||
|
const updatedConsentEndIndex = source.indexOf(consentEnd, updatedConsentStartIndex);
|
||||||
|
source = source.slice(0, updatedConsentStartIndex) + source.slice(updatedConsentEndIndex);
|
||||||
|
|
||||||
|
const materialImport = "Typography, Button, Grid";
|
||||||
|
if (!source.includes(materialImport)) {
|
||||||
|
throw new Error("Cannot remove the Button import used by the upstream consent dialog.");
|
||||||
|
}
|
||||||
|
source = source.replace(materialImport, "Typography, Grid");
|
||||||
|
|
||||||
|
console.log("Removed the upstream Google Analytics integration and consent dialog.");
|
||||||
|
} else if (hasKnownAnalytics || hasKnownState || hasKnownConsent) {
|
||||||
|
throw new Error("Unsupported upstream Analytics implementation.");
|
||||||
|
} else {
|
||||||
|
console.log("Upstream does not contain the known Analytics implementation; skip removal.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsupportedAnalytics = [
|
||||||
|
/googletagmanager\.com/i,
|
||||||
|
/google-analytics\.com/i,
|
||||||
|
/\bgtag\s*\(/,
|
||||||
|
/\bdataLayer\b/,
|
||||||
|
/cookie-settings/,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (unsupportedAnalytics.some(pattern => pattern.test(source))) {
|
||||||
|
throw new Error("An unsupported Analytics implementation remains in src/App.js.");
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(appPath, source);
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
||||||
|
import { extname, join } from "node:path";
|
||||||
|
|
||||||
|
const sourceRoot = "src";
|
||||||
|
const upstreamAvatar = "https://charlws.com/me.gif";
|
||||||
|
const localAvatar = "/logo.png";
|
||||||
|
const sourceExtensions = new Set([".js", ".jsx", ".ts", ".tsx"]);
|
||||||
|
let replacementCount = 0;
|
||||||
|
|
||||||
|
function updateDirectory(directory) {
|
||||||
|
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
||||||
|
const path = join(directory, entry.name);
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
updateDirectory(path);
|
||||||
|
} else if (sourceExtensions.has(extname(entry.name))) {
|
||||||
|
const source = readFileSync(path, "utf8");
|
||||||
|
const occurrences = source.split(upstreamAvatar).length - 1;
|
||||||
|
if (occurrences > 0) {
|
||||||
|
writeFileSync(path, source.replaceAll(upstreamAvatar, localAvatar));
|
||||||
|
replacementCount += occurrences;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDirectory(sourceRoot);
|
||||||
|
|
||||||
|
if (replacementCount === 0) {
|
||||||
|
console.log("Upstream does not contain the known fallback avatar; skip replacement.");
|
||||||
|
} else {
|
||||||
|
console.log(`Replaced ${replacementCount} upstream fallback avatar reference(s).`);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user