Skip to content

Commit

Permalink
3851 Fix ability to make server side API calls from privacy-center (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
eastandwestwind authored Aug 17, 2023
1 parent 7bbd002 commit 80958ee
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 47 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The types of changes are:
### Fixed
- Fix datamap zoom for low system counts [#3835](https://github.com/ethyca/fides/pull/3835)
- Fixed connector forms with external dataset reference fields [#3873](https://github.com/ethyca/fides/pull/3873)
- Fix ability to make server side API calls from privacy-center [#3895](https://github.com/ethyca/fides/pull/3895)

### Changed

Expand Down
2 changes: 2 additions & 0 deletions clients/fides-js/src/fides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,14 @@ _Fides = {
options: {
debug: true,
isOverlayEnabled: false,
isPrefetchEnabled: false,
isGeolocationEnabled: false,
geolocationApiUrl: "",
overlayParentId: null,
modalLinkId: null,
privacyCenterUrl: "",
fidesApiUrl: "",
serverSideFidesApiUrl: "",
tcfEnabled: false,
},
fides_meta: {},
Expand Down
6 changes: 6 additions & 0 deletions clients/fides-js/src/lib/consent-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ export type FidesOptions = {
// Whether or not the banner should be globally enabled
isOverlayEnabled: boolean;

// Whether we should pre-fetch geolocation and experience server-side
isPrefetchEnabled: boolean;

// Whether user geolocation should be enabled. Requires geolocationApiUrl
isGeolocationEnabled: boolean;

Expand All @@ -36,6 +39,9 @@ export type FidesOptions = {
// URL for the Fides API, used to fetch and save consent preferences. Required.
fidesApiUrl: string;

// URL for Server-side Fides API, used to fetch geolocation and consent preference. Optional.
serverSideFidesApiUrl: string;

// Whether we should show the TCF modal
tcfEnabled: boolean;
};
Expand Down
41 changes: 0 additions & 41 deletions clients/privacy-center/__tests__/common/geolocation.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import { createRequest } from "node-mocks-http";

import { lookupGeolocation } from "~/common/geolocation";
import { PrivacyCenterClientSettings } from "~/app/server-environment";

describe("getGeolocation", () => {
const privacyCenterSettings: PrivacyCenterClientSettings = {
FIDES_API_URL: "",
DEBUG: false,
GEOLOCATION_API_URL: "",
IS_GEOLOCATION_ENABLED: false,
IS_OVERLAY_ENABLED: false,
TCF_ENABLED: false,
OVERLAY_PARENT_ID: null,
MODAL_LINK_ID: null,
PRIVACY_CENTER_URL: "privacy.example.com",
};
describe("when using geolocation headers", () => {
it("returns geolocation data from country & region headers", async () => {
const req = createRequest({
Expand Down Expand Up @@ -117,33 +105,4 @@ describe("getGeolocation", () => {
expect(geolocation).toBeNull();
});
});

describe("when using geolocation URL", () => {
it.skip("fetches data from geolocation URL", async () => {
privacyCenterSettings.IS_GEOLOCATION_ENABLED = true;
privacyCenterSettings.GEOLOCATION_API_URL = "some-geolocation-api.com";
privacyCenterSettings.IS_OVERLAY_ENABLED = true;
global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
json: () =>
Promise.resolve({
country: "US",
location: "US-CA",
region: "CA",
}),
})
) as jest.Mock;
const req = createRequest({
url: "https://privacy.example.com/fides.js",
});

const geolocation = await lookupGeolocation(req);
expect(geolocation).toEqual({
country: "US",
location: "US-CA",
region: "CA",
});
});
});
});
12 changes: 12 additions & 0 deletions clients/privacy-center/app/server-environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
export interface PrivacyCenterSettings {
// Privacy center settings
FIDES_API_URL: string; // e.g. http://localhost:8080/api/v1
SERVER_SIDE_FIDES_API_URL: string | null; // e.g. http://fides:8080/api/v1
CONFIG_CSS_URL: string; // e.g. file:///app/config/config.css
CONFIG_JSON_URL: string; // e.g. file:///app/config/config.json

Expand All @@ -42,6 +43,7 @@ export interface PrivacyCenterSettings {
GEOLOCATION_API_URL: string; // e.g. http://location-cdn.com
IS_GEOLOCATION_ENABLED: boolean; // whether we should use geolocation to drive privacy experience
IS_OVERLAY_ENABLED: boolean; // whether we should render privacy-experience-driven components
IS_PREFETCH_ENABLED: boolean | false; // (optional) whether we should pre-fetch geolocation and experience server-side
OVERLAY_PARENT_ID: string | null; // (optional) ID of the parent DOM element where the overlay should be inserted
MODAL_LINK_ID: string | null; // (optional) ID of the DOM element that should trigger the consent modal
PRIVACY_CENTER_URL: string; // e.g. http://localhost:3000
Expand All @@ -56,10 +58,12 @@ export interface PrivacyCenterSettings {
export type PrivacyCenterClientSettings = Pick<
PrivacyCenterSettings,
| "FIDES_API_URL"
| "SERVER_SIDE_FIDES_API_URL"
| "DEBUG"
| "GEOLOCATION_API_URL"
| "IS_GEOLOCATION_ENABLED"
| "IS_OVERLAY_ENABLED"
| "IS_PREFETCH_ENABLED"
| "OVERLAY_PARENT_ID"
| "MODAL_LINK_ID"
| "PRIVACY_CENTER_URL"
Expand Down Expand Up @@ -250,6 +254,8 @@ export const loadPrivacyCenterEnvironment =
FIDES_API_URL:
process.env.FIDES_PRIVACY_CENTER__FIDES_API_URL ||
"http://localhost:8080/api/v1",
SERVER_SIDE_FIDES_API_URL:
process.env.FIDES_PRIVACY_CENTER__SERVER_SIDE_FIDES_API_URL || null,
CONFIG_JSON_URL:
process.env.FIDES_PRIVACY_CENTER__CONFIG_JSON_URL ||
"file:///app/config/config.json",
Expand All @@ -264,6 +270,9 @@ export const loadPrivacyCenterEnvironment =
IS_OVERLAY_ENABLED: process.env.FIDES_PRIVACY_CENTER__IS_OVERLAY_ENABLED
? process.env.FIDES_PRIVACY_CENTER__IS_OVERLAY_ENABLED === "true"
: false,
IS_PREFETCH_ENABLED: process.env.FIDES_PRIVACY_CENTER__IS_PREFETCH_ENABLED
? process.env.FIDES_PRIVACY_CENTER__IS_PREFETCH_ENABLED === "true"
: false,
IS_GEOLOCATION_ENABLED: process.env
.FIDES_PRIVACY_CENTER__IS_GEOLOCATION_ENABLED
? process.env.FIDES_PRIVACY_CENTER__IS_GEOLOCATION_ENABLED === "true"
Expand All @@ -290,8 +299,11 @@ export const loadPrivacyCenterEnvironment =
// Load client settings (ensuring we only pass-along settings that are safe for the client)
const clientSettings: PrivacyCenterClientSettings = {
FIDES_API_URL: settings.FIDES_API_URL,
SERVER_SIDE_FIDES_API_URL:
settings.SERVER_SIDE_FIDES_API_URL || settings.FIDES_API_URL,
DEBUG: settings.DEBUG,
IS_OVERLAY_ENABLED: settings.IS_OVERLAY_ENABLED,
IS_PREFETCH_ENABLED: settings.IS_PREFETCH_ENABLED,
IS_GEOLOCATION_ENABLED: settings.IS_GEOLOCATION_ENABLED,
GEOLOCATION_API_URL: settings.GEOLOCATION_API_URL,
OVERLAY_PARENT_ID: settings.OVERLAY_PARENT_ID,
Expand Down
3 changes: 0 additions & 3 deletions clients/privacy-center/common/geolocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,5 @@ export const lookupGeolocation = async (
};
}
}

// DEFER: read headers to determine & return the request's IP address
// Get geolocation if settings.IS_OVERLAY_ENABLED && settings.IS_GEOLOCATION_ENABLED && settings.GEOLOCATION_API_URL
return null;
};
48 changes: 45 additions & 3 deletions clients/privacy-center/pages/api/fides-js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import { promises as fsPromises } from "fs";
import type { NextApiRequest, NextApiResponse } from "next";
import { CacheControl, stringify } from "cache-control-parser";

import { ConsentOption, FidesConfig } from "fides-js";
import {
ConsentOption,
FidesConfig,
constructFidesRegionString,
CONSENT_COOKIE_NAME,
fetchExperience,
} from "fides-js";
import { loadPrivacyCenterEnvironment } from "~/app/server-environment";
import { lookupGeolocation, LOCATION_HEADERS } from "~/common/geolocation";

Expand Down Expand Up @@ -63,10 +69,41 @@ export default async function handler(
}));
}

// Check if a geolocation was provided via headers, query param, or obtainable via a geolocation URL;
// if so, inject into the bundle, along with privacy experience
// Check if a geolocation was provided via headers or query param
const geolocation = await lookupGeolocation(req);

// If a geolocation can be determined, "prefetch" the experience from the Fides API immediately.
// This allows the bundle to be fully configured server-side, so that the Fides.js bundle can initialize instantly!

let experience;
if (
geolocation &&
environment.settings.IS_OVERLAY_ENABLED &&
environment.settings.IS_PREFETCH_ENABLED
) {
const fidesRegionString = constructFidesRegionString(geolocation);
if (fidesRegionString) {
let fidesUserDeviceId = "";
if (Object.keys(req.cookies).length) {
const fidesCookie = req.cookies[CONSENT_COOKIE_NAME];
if (fidesCookie) {
fidesUserDeviceId =
JSON.parse(fidesCookie)?.identity?.fides_user_device_id;
}
}
if (environment.settings.DEBUG) {
console.log("Fetching relevant experiences from server-side...");
}
experience = await fetchExperience(
fidesRegionString,
environment.settings.SERVER_SIDE_FIDES_API_URL ||
environment.settings.FIDES_API_URL,
fidesUserDeviceId,
environment.settings.DEBUG
);
}
}

// Create the FidesConfig JSON that will be used to initialize fides.js
const fidesConfig: FidesConfig = {
consent: {
Expand All @@ -77,12 +114,17 @@ export default async function handler(
geolocationApiUrl: environment.settings.GEOLOCATION_API_URL,
isGeolocationEnabled: environment.settings.IS_GEOLOCATION_ENABLED,
isOverlayEnabled: environment.settings.IS_OVERLAY_ENABLED,
isPrefetchEnabled: environment.settings.IS_PREFETCH_ENABLED,
overlayParentId: environment.settings.OVERLAY_PARENT_ID,
modalLinkId: environment.settings.MODAL_LINK_ID,
privacyCenterUrl: environment.settings.PRIVACY_CENTER_URL,
fidesApiUrl: environment.settings.FIDES_API_URL,
serverSideFidesApiUrl:
environment.settings.SERVER_SIDE_FIDES_API_URL ||
environment.settings.FIDES_API_URL,
tcfEnabled: environment.settings.TCF_ENABLED,
},
experience: experience || undefined,
geolocation: geolocation || undefined,
};
const fidesConfigJSON = JSON.stringify(fidesConfig);
Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/fides/data/sample_project/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ services:
- ${FIDES_DEPLOY_ENV_FILE:-sample.env}
environment:
- FIDES_PRIVACY_CENTER__FIDES_API_URL=http://localhost:8080/api/v1
- FIDES_PRIVACY_CENTER__SERVER_SIDE_FIDES_API_URL=http://fides:8080/api/v1
- FIDES_PRIVACY_CENTER__PRIVACY_CENTER_URL=http://localhost:3001
ports:
- "3001:3000"
Expand Down

0 comments on commit 80958ee

Please sign in to comment.