# @selfxyz/core

SDK for verifying passport proofs from Self.

## Installation

You can install with this command:

```bash
npm install @selfxyz/core
# or
yarn add @selfxyz/core
```

## Initialization

Initialize the verifier with your RPC URL and application scope:

```typescript
import { SelfBackendVerifier } from '@selfxyz/core';

const selfBackendVerifier = new SelfBackendVerifier(
  process.env.CELO_RPC_URL as string, // e.g., 'https://forno.celo.org'
  process.env.SCOPE as string // Your application's unique scope. Should be the same as when initializing SelfApp
);
```

## Configuration

You can configure which verification rules to apply:

```typescript
// Set minimum age verification (must be between 10-100)
selfBackendVerifier.setMinimumAge(20);

// Set nationality verification
selfBackendVerifier.setNationality('France');

// Set excluded countries verification (max 40 countries)
selfBackendVerifier.excludeCountries('Iran', 'North Korea', 'Russia', 'Syria');

// Enable passport number OFAC check (default: false)
selfBackendVerifier.enablePassportNoOfacCheck();

// Enable name and date of birth OFAC check (default: false)
selfBackendVerifier.enableNameAndDobOfacCheck();

// Enable name and year of birth OFAC check (default: false)
selfBackendVerifier.enableNameAndYobOfacCheck();
```

## Verification

Verify a proof with the received proof and public signals:

```typescript
const result = await selfBackendVerifier.verify(proof, publicSignals);
```

## Extracting User Identifier

You can extract the user identifier from the public signals:

```typescript
import { getUserIdentifier } from '@selfxyz/core';

const userId = await getUserIdentifier(publicSignals);
```

This allows linking proofs with verification requests generated by `@selfxyz/qrcode`.

## Verification Result

The `verify` method returns a detailed verification result:

```typescript
export interface SelfVerificationResult {
  // Overall verification status
  isValid: boolean;

  // Detailed validation statuses
  isValidDetails: {
    isValidScope: boolean; // Proof was generated for the expected scope
    isValidAttestationId: boolean; // Attestation ID matches expected value
    isValidProof: boolean; // Cryptographic validity of the proof
    isValidNationality: boolean; // Nationality check (when enabled)
  };

  // User identifier from the proof
  userId: string;

  // Application scope
  application: string;

  // Cryptographic nullifier to prevent reuse
  nullifier: string;

  // Revealed data from the passport
  credentialSubject: {
    merkle_root?: string; // Merkle root used for proof generation
    attestation_id?: string; // Identity type (1 for passport)
    current_date?: string; // Proof generation timestamp
    issuing_state?: string; // Passport issuing country
    name?: string; // User's name
    passport_number?: string; // Passport number
    nationality?: string; // User's nationality
    date_of_birth?: string; // Date of birth
    gender?: string; // Gender
    expiry_date?: string; // Passport expiry date
    older_than?: string; // Age verification result
    passport_no_ofac?: boolean; // Passport OFAC check result.
    // Gives true if the user passed the check (is not on the list),
    // false if the check was not requested or if the user is in the list
    name_and_dob_ofac?: boolean; // Name and DOB OFAC check result
    name_and_yob_ofac?: boolean; // Name and birth year OFAC check result
  };

  // Original proof data
  proof: {
    value: {
      proof: any;
      publicSignals: any;
    };
  };

  // Error information if verification failed
  error?: any;
}
```

## API Implementation Example

Here's an example of implementing an API endpoint that uses the SDK:

```typescript
import { NextApiRequest, NextApiResponse } from 'next';
import { getUserIdentifier, SelfBackendVerifier, countryCodes } from '@selfxyz/core';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    try {
      const { proof, publicSignals } = req.body;

      if (!proof || !publicSignals) {
        return res.status(400).json({ message: 'Proof and publicSignals are required' });
      }

      // Extract user ID from the proof
      const userId = await getUserIdentifier(publicSignals);
      console.log('Extracted userId:', userId);

      // Initialize and configure the verifier
      const selfBackendVerifier = new SelfBackendVerifier(
        'https://forno.celo.org',
        'my-application-scope'
      );

      // Configure verification options
      selfBackendVerifier.setMinimumAge(18);
      selfBackendVerifier.excludeCountries(
        countryCodes.IRN, // Iran
        countryCodes.PRK // North Korea
      );
      selfBackendVerifier.enableNameAndDobOfacCheck();

      // Verify the proof
      const result = await selfBackendVerifier.verify(proof, publicSignals);

      if (result.isValid) {
        // Return successful verification response
        return res.status(200).json({
          status: 'success',
          result: true,
          credentialSubject: result.credentialSubject,
        });
      } else {
        // Return failed verification response
        return res.status(400).json({
          status: 'error',
          result: false,
          message: 'Verification failed',
          details: result.isValidDetails,
        });
      }
    } catch (error) {
      console.error('Error verifying proof:', error);
      return res.status(500).json({
        status: 'error',
        result: false,
        message: error instanceof Error ? error.message : 'Unknown error',
      });
    }
  } else {
    return res.status(405).json({ message: 'Method not allowed' });
  }
}
```

## Working with Country Codes

The SDK provides a `countryCodes` object for referencing ISO country codes:

```typescript
import { countryCodes } from '@selfxyz/core';

// Examples of usage
const iranCode = countryCodes.IRN; // "Iran"
const northKoreaCode = countryCodes.PRK; // "North Korea"

// Use in excludeCountries
selfBackendVerifier.excludeCountries(countryCodes.IRN, countryCodes.PRK, countryCodes.SYR);
```

## Integration with SelfQRcode

This backend SDK is designed to work with the `@selfxyz/qrcode` package. When configuring your QR code, set the verification endpoint to point to your API that uses this SDK:

```typescript
import { SelfAppBuilder } from '@selfxyz/qrcode';

const selfApp = new SelfAppBuilder({
  appName: 'My Application',
  scope: 'my-application-scope',
  endpoint: 'https://my-api.com/api/verify', // Your API using SelfBackendVerifier
  logoBase64: myLogoBase64,
  userId,
  disclosures: {
    name: true,
    nationality: true,
    date_of_birth: true,
    passport_number: true,
    minimumAge: 20,
    excludedCountries: ['IRN', 'PRK'],
    ofac: true,
  },
}).build();
```

## Example

For a more advanced implementation example, see the [playground](https://github.com/selfxyz/playground/blob/main/pages/api/verify.ts).
