Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions common/src/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ export const DEFAULT_MAJORITY = '18';
export const hashAlgos = ['sha512', 'sha384', 'sha256', 'sha224', 'sha1'];
export const saltLengths = [64, 48, 32];

/**
* Maximum number of countries in the forbidden countries list.
*
* IMPORTANT: This value must match in both backend and frontend SDK.
* Any mismatch will result in an INVALID_FORBIDDEN_COUNTRIES error.
*/
export const MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH = 40;

export const DEPLOYED_CIRCUITS_REGISTER = [
Expand Down
32 changes: 31 additions & 1 deletion common/src/utils/circuits/formatInputs.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
import { MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH } from "../../constants/constants";
import { commonNames } from "../../constants/countries";

/**
* Formats the list of country codes for use in verification circuits.
* Important: this list must exactly match the list in the backend.
*
* @param countries Array of three-letter country codes
* @returns Formatted byte array representing country codes
* @throws Error if the maximum list length is exceeded or if country codes are invalid
*/
export function formatCountriesList(countries: string[]) {
// Check maximum list length
if (countries.length > MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH) {
throw new Error(`Countries list must be inferior or equals to ${MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH}`);
}

// Validate country codes
for (const country of countries) {
if (!country || country.length !== 3) {
throw new Error(`Invalid country code: "${country}". Country codes must be exactly 3 characters long.`);
}

// Optional check for the country code existence in the list of valid codes
// This code can be uncommented if strict validation of country codes is needed
/*
const isValidCountry = Object.values(commonNames).some(
name => name === country || country in commonNames
);

if (!isValidCountry) {
throw new Error(`Unknown country code: "${country}". Please use valid 3-letter ISO country codes.`);
}
*/
}

const paddedCountries = countries.concat(Array(MAX_FORBIDDEN_COUNTRIES_LIST_LENGTH - countries.length).fill(''));
const result = paddedCountries.flatMap((country) => {
const chars = country
Expand Down Expand Up @@ -37,4 +67,4 @@ export function reverseCountryBytes(input: string): string {
}

return '0x' + reversedGroups.join('') + remainder;
}
}
7 changes: 7 additions & 0 deletions common/src/utils/contracts/formatCallData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ export function packForbiddenCountriesList(forbiddenCountries: string[]): string
const REQUIRED_CHUNKS = 4;
const bytes: number[] = [];

// Validate all country codes (3 characters)
for (const country of forbiddenCountries) {
if (!country || country.length !== 3) {
throw new Error(`Invalid country code: "${country}". Country codes must be exactly 3 characters long.`);
}
}

// Convert countries to bytes
for (const country of forbiddenCountries) {
const countryCode = country.padEnd(3, ' ').slice(0, 3);
Expand Down
35 changes: 33 additions & 2 deletions sdk/core/src/SelfBackendVerifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,13 @@ export class SelfBackendVerifier {
let result: any;
try {
result = await this.verifyAllContract.verifyAll(timestamp, vcAndDiscloseHubProof, types);
} catch (error) {
} catch (error: any) {
let errorMessage = error instanceof Error ? error.message : 'Unknown error';

if (error && typeof error === 'object' && error.message && error.message.includes('INVALID_FORBIDDEN_COUNTRIES')) {
errorMessage = 'The forbidden countries list in the backend does not match the list provided in the frontend SDK. Please ensure both lists are identical.';
}

return {
isValid: false,
isValidDetails: {
Expand All @@ -153,7 +159,7 @@ export class SelfBackendVerifier {
publicSignals: publicSignals,
},
},
error: error,
error: errorMessage,
};
}

Expand Down Expand Up @@ -220,10 +226,35 @@ export class SelfBackendVerifier {
return this;
}

/**
* Sets the list of countries to be excluded in the verification.
* This list must exactly match the list configured in the backend.
*
* @param countries Array of 3-letter country codes to exclude
* @returns This instance for method chaining
* @throws Error if more than 40 countries are provided or if any country code is invalid
*/
excludeCountries(...countries: Country3LetterCode[]): this {
if (countries.length > 40) {
throw new Error('Number of excluded countries cannot exceed 40');
}

// Validate country codes
for (const country of countries) {
if (!country || country.length !== 3) {
throw new Error(`Invalid country code: "${country}". Country codes must be exactly 3 characters long.`);
}

// Check if the country code exists in the list of valid codes (additional check)
const isValidCountry = Object.values(commonNames).some(
name => name === country || country in commonNames
);

if (!isValidCountry) {
throw new Error(`Unknown country code: "${country}". Please use valid 3-letter ISO country codes.`);
}
}

this.excludedCountries = { enabled: true, value: countries };
return this;
}
Expand Down