diff --git a/src/ageAssurance/data.tsx b/src/ageAssurance/data.tsx index c7610569d1..9cf6703dfc 100644 --- a/src/ageAssurance/data.tsx +++ b/src/ageAssurance/data.tsx @@ -6,7 +6,6 @@ import { type AppBskyAgeassuranceGetState, AtpAgent, type ChatBskyActorDeclaration, - getAgeAssuranceRegionConfig, } from '@atproto/api' import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister' import {focusManager, QueryClient, useQuery} from '@tanstack/react-query' @@ -32,6 +31,7 @@ import { } from '#/ageAssurance/types' import { createRegionKey, + getAgeAssuranceRegionConfigForGeolocation, getBirthdateStringFromAge, isLegacyBirthdateBug, } from '#/ageAssurance/util' @@ -317,10 +317,7 @@ export function useServerStateQuery() { const isAArequired = Boolean( config && geolocation && - !!getAgeAssuranceRegionConfig(config, { - countryCode: geolocation?.countryCode ?? '', - regionCode: geolocation?.regionCode, - }), + getAgeAssuranceRegionConfigForGeolocation(config, geolocation), ) // only refetch when needed @@ -626,10 +623,7 @@ export function useDeviceSignalsQuery() { * geolocation matches no AA region there's no device grant to surface. */ const regionConfig = config - ? getAgeAssuranceRegionConfig(config, { - countryCode: geolocation.countryCode ?? '', - regionCode: geolocation.regionCode, - }) + ? getAgeAssuranceRegionConfigForGeolocation(config, geolocation) : undefined const regionKey = regionConfig ? createRegionKey(regionConfig) : undefined diff --git a/src/ageAssurance/state.ts b/src/ageAssurance/state.ts index eb3ca0c7dc..2a0b76446b 100644 --- a/src/ageAssurance/state.ts +++ b/src/ageAssurance/state.ts @@ -3,7 +3,6 @@ import type * as AgeRange from 'expo-age-range' import { type AppBskyAgeassuranceDefs, computeAgeAssuranceRegionAccess, - getAgeAssuranceRegionConfig, } from '@atproto/api' import {getAge} from '#/lib/strings/time' @@ -27,6 +26,7 @@ import { import { computeAgeAssuranceFlags, getAgeAssuranceDataFromDeviceSignals, + getAgeAssuranceRegionConfigForGeolocation, getAgeAssuranceRegionConfigWithFallback, } from '#/ageAssurance/util' import {type Geolocation, useGeolocation} from '#/geolocation' @@ -159,10 +159,10 @@ export function unsafeGetAndComputeAgeAssurance({did}: {did: string}) { * skip the lookup rather than keying off FALLBACK_REGION_CONFIG. This keeps * the read key symmetric with the write (see `setDeviceSignalsForRegion`). */ - const deviceRegion = getAgeAssuranceRegionConfig(config, { - countryCode: geolocation.countryCode ?? '', - regionCode: geolocation.regionCode, - }) + const deviceRegion = getAgeAssuranceRegionConfigForGeolocation( + config, + geolocation, + ) const deviceSignals = deviceRegion ? getDeviceSignalsFromCacheForRegion({did, region: deviceRegion}) : undefined diff --git a/src/ageAssurance/util.ts b/src/ageAssurance/util.ts index 4917c3b8ef..ecd6468339 100644 --- a/src/ageAssurance/util.ts +++ b/src/ageAssurance/util.ts @@ -25,23 +25,41 @@ import { import {type Geolocation, useGeolocation} from '#/geolocation' import {USRegionNameToRegionCode} from '#/geolocation/util' +/** + * Resolves a geolocation to its matched age assurance region config, or + * undefined when the geolocation matches no AA region. + * + * This is the single source of truth for geolocation -> region resolution. + * Device signals are written and read back under a key derived from the + * matched region (see `createRegionKey`), so every site that resolves a region + * for that purpose MUST go through this helper - independent re-implementations + * risk desyncing the write and read keys and silently losing grants. + */ +export function getAgeAssuranceRegionConfigForGeolocation( + config: AppBskyAgeassuranceDefs.Config, + geolocation: Geolocation, +): AppBskyAgeassuranceDefs.ConfigRegion | undefined { + return getAgeAssuranceRegionConfig(config, { + countryCode: geolocation.countryCode ?? '', + regionCode: geolocation.regionCode, + }) +} + /** * Get age assurance region config based on geolocation, with fallback to * app defaults if no region config is found. * - * See {@link getAgeAssuranceRegionConfig} for the generic option, which can - * return undefined if the geolocation does not match any AA region. + * See {@link getAgeAssuranceRegionConfigForGeolocation} for the generic option, + * which can return undefined if the geolocation does not match any AA region. */ export function getAgeAssuranceRegionConfigWithFallback( config: AppBskyAgeassuranceDefs.Config, geolocation: Geolocation, ): AppBskyAgeassuranceDefs.ConfigRegion { - const region = getAgeAssuranceRegionConfig(config, { - countryCode: geolocation.countryCode ?? '', - regionCode: geolocation.regionCode, - }) - - return region || FALLBACK_REGION_CONFIG + return ( + getAgeAssuranceRegionConfigForGeolocation(config, geolocation) || + FALLBACK_REGION_CONFIG + ) } /** @@ -225,10 +243,7 @@ export function useAgeAssuranceRegionConfig() { return useMemo(() => { if (!config) return // use generic helper, we want to potentially return undefined - return getAgeAssuranceRegionConfig(config, { - countryCode: geolocation.countryCode ?? '', - regionCode: geolocation.regionCode, - }) + return getAgeAssuranceRegionConfigForGeolocation(config, geolocation) }, [config, geolocation]) }