Skip to content

Commit

Permalink
[ECO-2612] Fix geoblocking logic (#471)
Browse files Browse the repository at this point in the history
Co-authored-by: Matt <[email protected]>
  • Loading branch information
CRBl69 and xbtmatt authored Dec 20, 2024
1 parent 9af3c84 commit f09c3a8
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 13 deletions.
31 changes: 25 additions & 6 deletions src/typescript/frontend/src/configs/local-storage-keys.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { parseJSON, stringifyJSON } from "utils";
import packages from "../../package.json";
import { MS_IN_ONE_DAY } from "components/charts/const";
import { satisfies, type SemVer, parse } from "semver";

const LOCAL_STORAGE_KEYS = {
theme: `${packages.name}_theme`,
Expand All @@ -9,7 +10,18 @@ const LOCAL_STORAGE_KEYS = {
settings: `${packages.name}_settings`,
};

export const LOCAL_STORAGE_CACHE_TIME = {
const LOCAL_STORAGE_VERSIONS: {
[Property in keyof typeof LOCAL_STORAGE_KEYS]: SemVer;
} = {
theme: parse("1.0.0")!,
language: parse("1.0.0")!,
geoblocking: parse("2.0.0")!,
settings: parse("1.0.0")!,
};

export const LOCAL_STORAGE_CACHE_TIME: {
[Property in keyof typeof LOCAL_STORAGE_KEYS]: number;
} = {
theme: Infinity,
language: Infinity,
geoblocking: MS_IN_ONE_DAY,
Expand All @@ -19,20 +31,26 @@ export const LOCAL_STORAGE_CACHE_TIME = {
export type LocalStorageCache<T> = {
expiry: number;
data: T | null;
version: string | undefined;
};

/**
* Note that this data is not validated and any change in data type returned from this function
* should be validated to ensure that persisted cache data between multiple builds can cause errors
* with unexpected data types.
*/
export function readLocalStorageCache<T>(key: keyof typeof LOCAL_STORAGE_KEYS): T | null {
const str = localStorage.getItem(LOCAL_STORAGE_KEYS[key]);
if (str === null) {
return null;
}
try {
const cache = parseJSON<LocalStorageCache<T>>(str);
const range = `~${LOCAL_STORAGE_VERSIONS[key].major}`;
// Check for no breaking changes.
if (!satisfies(cache.version ?? "1.0.0", range)) {
console.warn(
`${key} cache version not satisfied (needs to satisfy ${range}, but ${cache.version} is present). Purging...`
);
localStorage.delete(LOCAL_STORAGE_KEYS[key]);
return null;
}
// Check for staleness.
if (new Date(cache.expiry) > new Date()) {
return cache.data;
}
Expand All @@ -46,6 +64,7 @@ export function writeLocalStorageCache<T>(key: keyof typeof LOCAL_STORAGE_KEYS,
const cache: LocalStorageCache<T> = {
expiry: new Date().getTime() + LOCAL_STORAGE_CACHE_TIME[key],
data,
version: LOCAL_STORAGE_VERSIONS[key].version,
};
localStorage.setItem(LOCAL_STORAGE_KEYS[key], stringifyJSON<LocalStorageCache<T>>(cache));
}
28 changes: 21 additions & 7 deletions src/typescript/frontend/src/utils/geolocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,31 @@ import { GEOBLOCKED, GEOBLOCKING_ENABLED } from "lib/server-env";
import { headers } from "next/headers";

export type Location = {
countryCode: string;
regionCode: string;
countryCode: string | null;
regionCode: string | null;
};

const isDisallowedLocation = ({ countryCode, regionCode }: Location) => {
if (GEOBLOCKED.countries.includes(countryCode)) {
if (countryCode && GEOBLOCKED.countries.includes(countryCode)) {
return true;
}
const isoCode = `${countryCode}-${regionCode}`;
if (GEOBLOCKED.regions.includes(isoCode)) {
return true;
if (regionCode) {
const isoCode = `${countryCode}-${regionCode}`;
if (GEOBLOCKED.regions.includes(isoCode)) {
return true;
}
}
if (countryCode && !regionCode) {
if (GEOBLOCKED.regions.map((r) => r.split("-")[0]).includes(countryCode)) {
return true;
}
}
if (!countryCode && regionCode) {
// Note that even if the `regionCode` is `XX`, and `XX` is a banned country, this will return
// `true` and thus block the user, because "XX".split("-")[0] is just "XX".
if (GEOBLOCKED.countries.includes(regionCode.split("-")[0])) {
return true;
}
}
return false;
};
Expand All @@ -23,7 +37,7 @@ export const isUserGeoblocked = async () => {
if (!GEOBLOCKING_ENABLED) return false;
const country = headers().get("x-vercel-ip-country");
const region = headers().get("x-vercel-ip-country-region");
if (typeof country !== "string" || typeof region !== "string") {
if (typeof country !== "string" && typeof region !== "string") {
return true;
}
return isDisallowedLocation({
Expand Down

0 comments on commit f09c3a8

Please sign in to comment.