SEL-56: Setup Yarn Workspaces (#584)

This commit is contained in:
Aaron DeRuvo
2025-06-04 11:37:32 +02:00
committed by GitHub
parent 0c8c87362b
commit 0e9c59c0fb
203 changed files with 16353 additions and 23226 deletions

View File

@@ -1,10 +0,0 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[*.{js,json,yml}]
charset = utf-8
indent_style = space
indent_size = 2

View File

@@ -1,4 +0,0 @@
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated

13
sdk/common/.gitignore vendored
View File

@@ -1,13 +0,0 @@
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
# Swap the comments on the following lines if you wish to use zero-installs
# In that case, don't forget to run `yarn config set enableGlobalCache false`!
# Documentation here: https://yarnpkg.com/features/caching#zero-installs
#!.yarn/cache
.pnp.*

View File

@@ -1 +0,0 @@
# common

View File

@@ -1,9 +0,0 @@
import { CertificateData, PublicKeyDetailsECDSA, PublicKeyDetailsRSA } from "../../common/src/utils/certificate_parsing/dataStructure";
import { parseCertificate } from "../../common/src/utils/certificate_parsing/parseCertificate";
import { parseCertificateSimple } from "../../common/src/utils/certificate_parsing/parseCertificateSimple";
import { findStartPubKeyIndex } from "../../common/src/utils/passports/passport";
import { parseDscCertificateData } from "../../common/src/utils/passports/passport_parsing/parseDscCertificateData";
import { getLeafCscaTree, getLeafDscTree } from "../../common/src/utils/trees";
import { genMockIdDoc } from "../../common/src/utils/passports/genMockIdDoc";
export { CertificateData, findStartPubKeyIndex, getLeafCscaTree, getLeafDscTree, parseCertificate, parseCertificateSimple, parseDscCertificateData, PublicKeyDetailsECDSA, PublicKeyDetailsRSA, genMockIdDoc };

View File

@@ -1,51 +0,0 @@
{
"name": "@openpassport/common",
"version": "0.0.11",
"packageManager": "yarn@4.5.0",
"files": [
"dist"
],
"main": "dist/sdk/common/index.js",
"types": "dist/sdk/common/index.d.ts",
"scripts": {
"clean": "rm -rf dist",
"build:ts": "tsc -b",
"copy-certs": "mkdir -p dist && cp -R ../../common/src/mock_certificates ./dist/",
"build": "yarn clean && yarn build:ts && yarn copy-certs",
"prepublishOnly": "yarn build"
},
"dependencies": {
"@babel/runtime": "^7.23.4",
"@openpassport/zk-kit-imt": "^0.0.5",
"@openpassport/zk-kit-lean-imt": "^0.0.6",
"@openpassport/zk-kit-smt": "^0.0.1",
"asn1.js": "^5.4.1",
"asn1js": "^3.0.5",
"axios": "^1.7.2",
"buffer": "^6.0.3",
"chai": "^4.3.8",
"country-emoji": "^1.5.6",
"country-iso-3-to-2": "^1.1.1",
"elliptic": "^6.5.5",
"fs": "^0.0.1-security",
"i18n-iso-countries": "^7.13.0",
"js-sha1": "^0.7.0",
"js-sha256": "^0.11.0",
"js-sha512": "^0.9.0",
"json-to-ts": "^2.1.0",
"jsrsasign": "^11.1.0",
"mocha": "^10.7.3",
"node-forge": "https://github.com/remicolin/forge",
"path": "^0.12.7",
"pkijs": "^3.2.4",
"poseidon-lite": "^0.2.0",
"snarkjs": "^0.7.5",
"ts-mocha": "^10.0.0",
"typescript-parser": "^2.6.1",
"uuid": "^11.0.5"
},
"devDependencies": {
"@types/node-forge": "^1.3.10",
"prettier": "^3.3.3"
}
}

View File

@@ -1,29 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"declaration": true,
"declarationDir": "./dist",
"outDir": "./dist",
"strict": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"jsx": "react",
"moduleResolution": "node",
"baseUrl": ".",
"paths": {
"@common/*": ["../../common/src/*"]
}
},
"include": [
"index.ts",
"src/**/*",
"../../common/src/**/*",
"circuits/**/*",
"circuits/**/*.json",
"utils/utils.ts"
],
"exclude": ["node_modules", "**/__tests__/*", "dist", "common/src/utils/csca.ts"]
}

View File

@@ -1,10 +1,10 @@
import { SelfBackendVerifier } from './src/SelfBackendVerifier';
import { getUserIdentifier } from './src/utils/utils';
import { countryCodes } from '../../common/src/constants/constants';
import { SelfApp, getUniversalLink, SelfAppBuilder } from '../../common/src/utils/appType';
import { countries } from '../../common/src/constants/countries';
import { hashEndpointWithScope } from '../../common/src/utils/scope';
import { getPackedForbiddenCountries } from '../../common/src/utils/contracts/forbiddenCountries';
import { countryCodes } from '@selfxyz/common/constants/constants';
import { SelfApp, getUniversalLink, SelfAppBuilder } from '@selfxyz/common/utils/appType';
import { countries } from '@selfxyz/common';
import { hashEndpointWithScope } from '@selfxyz/common/utils/scope';
import { getPackedForbiddenCountries } from '@selfxyz/common/utils/contracts/forbiddenCountries';
export {
SelfBackendVerifier,
@@ -15,5 +15,5 @@ export {
countries,
hashEndpointWithScope,
SelfAppBuilder,
getPackedForbiddenCountries
getPackedForbiddenCountries,
};

View File

@@ -15,23 +15,23 @@
"circuits/**/*.json"
],
"scripts": {
"build": "tsc",
"build": "tsc -build",
"build:deps": "yarn workspaces foreach --from @selfxyz/core --topological-dev --recursive run build",
"types": "yarn build",
"copy-abi": "bash scripts/copyAbi.sh",
"format": "prettier --write .",
"install-sdk": "cd ../common && yarn && cd ../sdk && yarn",
"install-sdk": "yarn workspaces focus @selfxyz/core",
"lint": "prettier --check .",
"prepublishOnly": "npm run build",
"publish": "npm publish --access public"
"publish": "yarn npm publish --access public"
},
"dependencies": {
"@types/react": "^18.3.4",
"@types/react-dom": "^18.3.0",
"@selfxyz/common": "workspace:^",
"@types/uuid": "^10.0.0",
"ethers": "^6.13.5",
"js-sha1": "^0.7.0",
"js-sha256": "^0.11.0",
"js-sha512": "^0.9.0",
"next": "^14.2.8",
"node-forge": "^1.3.1",
"poseidon-lite": "^0.3.0",
"snarkjs": "^0.7.4",
@@ -53,9 +53,6 @@
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
},
"peerDependencies": {
"react": ">=16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"publishConfig": {
"access": "public"
}

View File

@@ -8,19 +8,19 @@ import {
} from './constants/contractAddresses';
import { ethers } from 'ethers';
import { PublicSignals } from 'snarkjs';
import type { SelfVerificationResult } from '../../../common/src/utils/selfAttestation';
import type { SelfVerificationResult } from '@selfxyz/common/utils/selfAttestation';
import { castToUserIdentifier, UserIdType } from '@selfxyz/common/utils/circuits/uuid';
import {
castToScope,
castToUserIdentifier,
UserIdType,
} from '../../../common/src/utils/circuits/uuid';
import { CIRCUIT_CONSTANTS, revealedDataTypes } from '../../../common/src/constants/constants';
import { packForbiddenCountriesList } from '../../../common/src/utils/contracts/formatCallData';
import { Country3LetterCode, commonNames } from '../../../common/src/constants/countries';
import { hashEndpointWithScope } from '../../../common/src/utils/scope';
CIRCUIT_CONSTANTS,
revealedDataTypes,
Country3LetterCode,
commonNames,
} from '@selfxyz/common';
import { packForbiddenCountriesList } from '@selfxyz/common/utils/contracts/formatCallData';
import { hashEndpointWithScope } from '@selfxyz/common/utils/scope';
const CELO_MAINNET_RPC_URL = "https://forno.celo.org";
const CELO_TESTNET_RPC_URL = "https://alfajores-forno.celo-testnet.org";
const CELO_MAINNET_RPC_URL = 'https://forno.celo.org';
const CELO_TESTNET_RPC_URL = 'https://alfajores-forno.celo-testnet.org';
export class SelfBackendVerifier {
protected scope: string;
@@ -35,9 +35,9 @@ export class SelfBackendVerifier {
enabled: boolean;
value: Country3LetterCode;
} = {
enabled: false,
value: '' as Country3LetterCode,
};
enabled: false,
value: '' as Country3LetterCode,
};
protected minimumAge: { enabled: boolean; value: string } = {
enabled: false,
value: '18',
@@ -46,9 +46,9 @@ export class SelfBackendVerifier {
enabled: boolean;
value: Country3LetterCode[];
} = {
enabled: false,
value: [],
};
enabled: false,
value: [],
};
protected passportNoOfac: boolean = false;
protected nameAndDobOfac: boolean = false;
protected nameAndYobOfac: boolean = false;
@@ -140,9 +140,14 @@ export class SelfBackendVerifier {
result = await this.verifyAllContract.verifyAll(timestamp, vcAndDiscloseHubProof, types);
} 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.';
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 {
@@ -233,7 +238,7 @@ export class SelfBackendVerifier {
/**
* 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
@@ -242,23 +247,23 @@ export class SelfBackendVerifier {
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.`);
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
(name) => name === country || country in commonNames
);
if (!isValidCountry) {
throw new Error(`Unknown country code: "${country}". Please use valid 3-letter ISO country codes.`);
throw new Error(
`Unknown country code: "${country}". Please use valid 3-letter ISO country codes.`
);
}
}
this.excludedCountries = { enabled: true, value: countries };
return this;
}

View File

@@ -1,5 +1,5 @@
import { CIRCUIT_CONSTANTS } from '../../../../common/src/constants/constants';
import { castToUserIdentifier, UserIdType } from '../../../../common/src/utils/circuits/uuid';
import { CIRCUIT_CONSTANTS } from '@selfxyz/common';
import { castToUserIdentifier, UserIdType } from '@selfxyz/common/utils/circuits/uuid';
import { BigNumberish } from 'ethers';
import { PublicSignals } from 'snarkjs';

View File

@@ -1,7 +1,7 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"module": "NodeNext",
"declaration": true,
"declarationDir": "./dist",
"outDir": "./dist",
@@ -10,20 +10,9 @@
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"jsx": "react",
"moduleResolution": "node",
"baseUrl": ".",
"paths": {
"@common/*": ["../../common/src/*"]
}
"moduleResolution": "node16",
"baseUrl": "."
},
"include": [
"index.ts",
"src/**/*",
"../../common/src/**/*",
"circuits/**/*",
"circuits/**/*.json",
"utils/utils.ts"
],
"exclude": ["node_modules", "**/__tests__/*", "dist", "common/src/utils/csca.ts"]
"include": ["index.ts", "src/**/*", "circuits/**/*", "circuits/**/*.json", "utils/utils.ts"],
"exclude": ["node_modules", "**/__tests__/*", "dist"]
}

View File

@@ -0,0 +1,6 @@
dist
node_modules
.yarn/**
*.json

11
sdk/qrcode/.prettierrc Normal file
View File

@@ -0,0 +1,11 @@
{
"arrowParens": "avoid",
"bracketSameLine": false,
"bracketSpacing": true,
"singleQuote": true,
"trailingComma": "all",
"tabWidth": 2,
"useTabs": false,
"semi": true,
"endOfLine": "auto"
}

View File

@@ -0,0 +1,26 @@
[
{
"path": "./dist/index.js",
"name": "import SelfQRcodeWrapper from '@selfxyz/qrcode'",
"import": "{ default }",
"limit": "800 ms"
},
{
"path": "./dist/index.js",
"name": "import { SelfAppBuilder } from '@selfxyz/qrcode'",
"import": "{ SelfAppBuilder }",
"limit": "800 ms"
},
{
"path": "./dist/index.js",
"name": "import { SelfQRcode } from '@selfxyz/qrcode'",
"import": "{ SelfQRcode }",
"limit": "800 ms"
},
{
"path": "./dist/index.js",
"name": "import { countries } from '@selfxyz/qrcode'",
"import": "{ countries }",
"limit": "800 ms"
}
]

View File

@@ -27,10 +27,10 @@ const userId = uuidv4();
// Create a SelfApp instance using the builder pattern
const selfApp = new SelfAppBuilder({
appName: "My App",
scope: "my-app-scope",
endpoint: "https://myapp.com/api/verify",
logoBase64: "base64EncodedLogo", // Optional
appName: 'My App',
scope: 'my-app-scope',
endpoint: 'https://myapp.com/api/verify',
logoBase64: 'base64EncodedLogo', // Optional
userId,
// Optional disclosure requirements
disclosures: {
@@ -44,7 +44,7 @@ const selfApp = new SelfAppBuilder({
expiry_date: true,
// Custom verification rules
minimumAge: 18,
excludedCountries: ["IRN", "PRK"],
excludedCountries: ['IRN', 'PRK'],
ofac: true,
},
}).build();
@@ -74,44 +74,44 @@ function MyComponent() {
The `SelfAppBuilder` allows you to configure your application's verification requirements:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `appName` | string | Yes | The name of your application |
| `scope` | string | Yes | A unique identifier for your application |
| `endpoint` | string | Yes | The endpoint that will verify the proof |
| `logoBase64` | string | No | Base64-encoded logo to display in the Self app |
| `userId` | string | Yes | Unique identifier for the user |
| `disclosures` | object | No | Disclosure and verification requirements |
| Parameter | Type | Required | Description |
| ------------- | ------ | -------- | ---------------------------------------------- |
| `appName` | string | Yes | The name of your application |
| `scope` | string | Yes | A unique identifier for your application |
| `endpoint` | string | Yes | The endpoint that will verify the proof |
| `logoBase64` | string | No | Base64-encoded logo to display in the Self app |
| `userId` | string | Yes | Unique identifier for the user |
| `disclosures` | object | No | Disclosure and verification requirements |
### Disclosure Options
The `disclosures` object can include the following options:
| Option | Type | Description |
|--------|------|-------------|
| `issuing_state` | boolean | Request disclosure of passport issuing state |
| `name` | boolean | Request disclosure of the user's name |
| `nationality` | boolean | Request disclosure of nationality |
| `date_of_birth` | boolean | Request disclosure of birth date |
| `passport_number` | boolean | Request disclosure of passport number |
| `gender` | boolean | Request disclosure of gender |
| `expiry_date` | boolean | Request disclosure of passport expiry date |
| `minimumAge` | number | Verify the user is at least this age |
| `excludedCountries` | string[] | Array of country codes to exclude |
| `ofac` | boolean | Enable OFAC compliance check |
| Option | Type | Description |
| ------------------- | -------- | -------------------------------------------- |
| `issuing_state` | boolean | Request disclosure of passport issuing state |
| `name` | boolean | Request disclosure of the user's name |
| `nationality` | boolean | Request disclosure of nationality |
| `date_of_birth` | boolean | Request disclosure of birth date |
| `passport_number` | boolean | Request disclosure of passport number |
| `gender` | boolean | Request disclosure of gender |
| `expiry_date` | boolean | Request disclosure of passport expiry date |
| `minimumAge` | number | Verify the user is at least this age |
| `excludedCountries` | string[] | Array of country codes to exclude |
| `ofac` | boolean | Enable OFAC compliance check |
## Component Props
The `SelfQRcodeWrapper` component accepts the following props:
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `selfApp` | SelfApp | Yes | - | The SelfApp configuration object |
| `onSuccess` | () => void | Yes | - | Callback function executed on successful verification |
| `websocketUrl` | string | No | WS_DB_RELAYER | Custom WebSocket URL for verification |
| `size` | number | No | 300 | QR code size in pixels |
| `darkMode` | boolean | No | false | Enable dark mode styling |
| `children` | React.ReactNode | No | - | Custom children to render |
| Prop | Type | Required | Default | Description |
| -------------- | --------------- | -------- | ------------- | ----------------------------------------------------- |
| `selfApp` | SelfApp | Yes | - | The SelfApp configuration object |
| `onSuccess` | () => void | Yes | - | Callback function executed on successful verification |
| `websocketUrl` | string | No | WS_DB_RELAYER | Custom WebSocket URL for verification |
| `size` | number | No | 300 | QR code size in pixels |
| `darkMode` | boolean | No | false | Enable dark mode styling |
| `children` | React.ReactNode | No | - | Custom children to render |
## Complete Example
@@ -136,19 +136,19 @@ function VerificationPage() {
// Create the SelfApp configuration
const selfApp = new SelfAppBuilder({
appName: "My Application",
scope: "my-application-scope",
endpoint: "https://myapp.com/api/verify",
appName: 'My Application',
scope: 'my-application-scope',
endpoint: 'https://myapp.com/api/verify',
userId,
disclosures: {
// Request passport information
name: true,
nationality: true,
date_of_birth: true,
// Set verification rules
minimumAge: 18,
excludedCountries: ["IRN", "PRK", "RUS"],
excludedCountries: ['IRN', 'PRK', 'RUS'],
ofac: true,
},
}).build();
@@ -157,17 +157,17 @@ function VerificationPage() {
<div className="verification-container">
<h1>Verify Your Identity</h1>
<p>Scan this QR code with the Self app to verify your identity</p>
<SelfQRcodeWrapper
selfApp={selfApp}
onSuccess={() => {
// Handle successful verification
console.log("Verification successful!");
console.log('Verification successful!');
// Redirect or update UI
}}
size={350}
/>
<p className="text-sm text-gray-500">
User ID: {userId.substring(0, 8)}...
</p>
@@ -190,4 +190,4 @@ For a more comprehensive and interactive example, please refer to the [playgroun
4. The proof is generated and sent to your verification endpoint
5. Upon successful verification, the `onSuccess` callback is triggered
The QR code component displays the current verification status with an LED indicator and changes its appearance based on the verification state.
The QR code component displays the current verification status with an LED indicator and changes its appearance based on the verification state.

View File

@@ -1,5 +1,5 @@
import React from 'react';
import { QRcodeSteps } from '../utils/utils';
import { QRcodeSteps } from '../utils/utils.js';
interface LEDProps {
size?: number;
connectionStatus?: number;
@@ -9,7 +9,10 @@ const green = '#31F040';
const blue = '#424AD8';
const gray = '#95a5a6';
const LED: React.FC<LEDProps> = ({ size = 8, connectionStatus = QRcodeSteps.DISCONNECTED }) => {
const LED: React.FC<LEDProps> = ({
size = 8,
connectionStatus = QRcodeSteps.DISCONNECTED,
}) => {
const getColor = () => {
if (connectionStatus >= QRcodeSteps.MOBILE_CONNECTED) {
return green;

View File

@@ -1,21 +1,31 @@
import React, { useEffect, useState, useRef } from 'react';
import { BounceLoader } from 'react-spinners';
import Lottie from 'lottie-react';
import CHECK_ANIMATION from './animations/check_animation.json';
import X_ANIMATION from './animations/x_animation.json';
import LED from './components/LED';
import { REDIRECT_URL, WS_DB_RELAYER } from '../../common/src/constants/constants';
import CHECK_ANIMATION from '../animations/check_animation.json';
import X_ANIMATION from '../animations/x_animation.json';
import LED from './LED.js';
import {
REDIRECT_URL,
WS_DB_RELAYER,
} from '@selfxyz/common/constants/constants';
import { v4 as uuidv4 } from 'uuid';
import { QRcodeSteps } from './utils/utils';
import { containerStyle, ledContainerStyle, qrContainerStyle } from './utils/styles';
import { QRcodeSteps } from '../utils/utils.js';
import {
containerStyle,
ledContainerStyle,
qrContainerStyle,
} from '../utils/styles.js';
import { QRCodeSVG } from 'qrcode.react';
import { initWebSocket } from './utils/websocket';
import { getUniversalLink, SelfApp, SelfAppBuilder } from '../../common/src/utils/appType';
import { initWebSocket } from '../utils/websocket.js';
import {
getUniversalLink,
SelfApp,
SelfAppBuilder,
} from '@selfxyz/common/utils/appType';
interface SelfQRcodeProps {
selfApp: SelfApp;
onSuccess: () => void;
onError: (data: {error_code?: string, reason?: string}) => void;
onError: (data: { error_code?: string; reason?: string }) => void;
type?: 'websocket' | 'deeplink';
websocketUrl?: string;
size?: number;
@@ -60,7 +70,7 @@ const SelfQRcode = ({
websocketUrl,
{
...selfApp,
sessionId: sessionId
sessionId: sessionId,
},
type,
setProofStep,
@@ -95,7 +105,7 @@ const SelfQRcode = ({
return <BounceLoader loading={true} size={200} color="#94FBAB" />;
case QRcodeSteps.PROOF_GENERATION_FAILED:
return (
<Lottie
<Lottie.default
animationData={X_ANIMATION}
style={{ width: 200, height: 200 }}
onComplete={() => {
@@ -106,7 +116,7 @@ const SelfQRcode = ({
);
case QRcodeSteps.PROOF_VERIFIED:
return (
<Lottie
<Lottie.default
animationData={CHECK_ANIMATION}
style={{ width: 200, height: 200 }}
onComplete={() => {
@@ -118,10 +128,14 @@ const SelfQRcode = ({
default:
return (
<QRCodeSVG
value={type === 'websocket' ? `${REDIRECT_URL}?sessionId=${sessionId}` : getUniversalLink({
...selfApp,
sessionId: sessionId
})}
value={
type === 'websocket'
? `${REDIRECT_URL}?sessionId=${sessionId}`
: getUniversalLink({
...selfApp,
sessionId: sessionId,
})
}
size={size}
bgColor={darkMode ? '#000000' : '#ffffff'}
fgColor={darkMode ? '#ffffff' : '#000000'}
@@ -139,4 +153,4 @@ const SelfQRcode = ({
export default SelfQRcodeWrapper;
// Also export other components/types that might be needed
export { SelfQRcode, SelfApp, SelfAppBuilder };
export { SelfQRcode, SelfApp, SelfAppBuilder };

View File

@@ -1,8 +1,12 @@
import SelfQRcodeWrapper, { SelfQRcode, SelfApp, SelfAppBuilder } from './SelfQRcode';
import { WebAppInfo } from './utils/websocket';
import { countries } from '../../common/src/constants/countries';
import SelfQRcodeWrapper, {
SelfQRcode,
SelfApp,
SelfAppBuilder,
} from './components/SelfQRcode.js';
import { WebAppInfo } from './utils/websocket.js';
import { countries } from '@selfxyz/common/constants/countries';
export default SelfQRcodeWrapper;
export { SelfQRcode, SelfApp, SelfAppBuilder, countries };
export { SelfQRcodeWrapper, SelfQRcode, SelfApp, SelfAppBuilder, countries };
export type { WebAppInfo };

View File

@@ -7,46 +7,51 @@
},
"license": "MIT",
"author": "turnoffthiscomputer",
"main": "dist/sdk/qrcode/index.js",
"types": "dist/sdk/qrcode/index.d.ts",
"main": "dist/index.js",
"type": "module",
"exports": {
".": "./dist/index.js"
},
"types": "dist/index.d.ts",
"files": [
"dist",
"common",
"circuits/**/*.json",
"src/QRcode"
"dist"
],
"scripts": {
"build": "tsc",
"build": "tsc --build",
"build:deps": "yarn workspaces foreach --from @selfxyz/qrcode --topological-dev --recursive run build",
"types": "yarn build",
"format": "prettier --write .",
"install-sdk": "cd ../common && yarn && cd ../sdk && yarn",
"install-sdk": "yarn workspace focus @selfxyz/qrcode",
"lint": "prettier --check .",
"prepublishOnly": "npm run build",
"test": "yarn ts-mocha -p ./tsconfig.json tests/openPassportVerifier.test.ts --exit",
"publish": "npm publish --access public"
"prepublishOnly": "yarn build",
"test": "echo 'no tests found'",
"publish": "yarn npm publish --access public"
},
"dependencies": {
"@types/react": "^18.3.4",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^10.0.0",
"@selfxyz/common": "workspace:^",
"js-sha1": "^0.7.0",
"js-sha256": "^0.11.0",
"js-sha512": "^0.9.0",
"lottie-react": "^2.4.0",
"next": "^14.2.8",
"node-forge": "^1.3.1",
"poseidon-lite": "^0.3.0",
"qrcode.react": "^4.1.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-spinners": "^0.14.1",
"socket.io-client": "^4.8.1",
"uuid": "^10.0.0"
},
"devDependencies": {
"@size-limit/preset-big-lib": "^11.2.0",
"@types/node": "^20.11.19",
"@types/node-forge": "^1",
"@types/react": "^18.3.4",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^10.0.0",
"mocha": "^10.3.0",
"prettier": "^3.3.3",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"size-limit": "^11.2.0",
"ts-loader": "^9.5.1",
"ts-mocha": "^10.0.0",
"ts-node": "^10.9.2",
@@ -60,4 +65,4 @@
"publishConfig": {
"access": "public"
}
}
}

View File

@@ -1,7 +1,7 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"module": "Node16",
"declaration": true,
"declarationDir": "./dist",
"outDir": "./dist",
@@ -11,22 +11,17 @@
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"jsx": "react",
"moduleResolution": "node"
"moduleResolution": "node16"
},
"include": [
"animations",
"index.ts",
"src/**/*",
"SelfQRcode.tsx",
"common/**/*",
"circuits/**/*",
"circuits/**/*.json",
"utils/utils.ts",
"../../common/src/utils/openPassportAttestation.ts"
"components/**.tsx",
"utils/*.ts"
],
"exclude": [
"node_modules",
"**/__tests__/*",
"dist",
"common/src/utils/csca.ts"
]
}
}

View File

@@ -1,19 +1,21 @@
import io, { Socket } from 'socket.io-client';
import { QRcodeSteps } from './utils';
import { SelfApp } from '../../../common/src/utils/appType';
import { QRcodeSteps } from './utils.js';
import { SelfApp } from '@selfxyz/common/utils/appType';
export interface WebAppInfo {
appName: string;
userId: string;
logoBase64: string;
};
}
// Log once when this module loads
console.log('[WebSocket] Initializing websocket module.');
const newSocket = (websocketUrl: string, sessionId: string) => {
const fullUrl = `${websocketUrl}/websocket`;
console.log(`[WebSocket] Creating new socket. URL: ${fullUrl}, sessionId: ${sessionId}`);
console.log(
`[WebSocket] Creating new socket. URL: ${fullUrl}, sessionId: ${sessionId}`,
);
return io(fullUrl, {
path: '/',
query: { sessionId, clientType: 'web' },
@@ -29,46 +31,54 @@ const handleWebSocketMessage =
type: 'websocket' | 'deeplink',
setProofStep: (step: number) => void,
onSuccess: () => void,
onError: (data: {error_code?: string, reason?: string}) => void
onError: (data: { error_code?: string; reason?: string }) => void,
) =>
async (data: any) => {
console.log('[WebSocket] Received mobile status:', data.status, 'for session:', sessionId);
switch (data.status) {
case 'mobile_connected':
console.log('[WebSocket] Mobile device connected. Emitting self_app event with payload:', selfApp);
setProofStep(QRcodeSteps.MOBILE_CONNECTED);
if (type === 'websocket') {
socket.emit('self_app', { ...selfApp, sessionId });
}
break;
case 'mobile_disconnected':
console.log('[WebSocket] Mobile device disconnected.');
setProofStep(QRcodeSteps.WAITING_FOR_MOBILE);
break;
case 'proof_generation_started':
console.log('[WebSocket] Proof generation started.');
setProofStep(QRcodeSteps.PROOF_GENERATION_STARTED);
break;
case 'proof_generated':
console.log('[WebSocket] Proof generated.');
setProofStep(QRcodeSteps.PROOF_GENERATED);
break;
case 'proof_generation_failed':
console.log('[WebSocket] Proof generation failed.');
setProofStep(QRcodeSteps.PROOF_GENERATION_FAILED);
onError(data);
break;
case 'proof_verified':
console.log('[WebSocket] Proof verified.');
console.log('ws data', data);
setProofStep(QRcodeSteps.PROOF_VERIFIED);
onSuccess();
break;
default:
console.log('[WebSocket] Unhandled mobile status:', data.status);
break;
}
};
async (data: any) => {
console.log(
'[WebSocket] Received mobile status:',
data.status,
'for session:',
sessionId,
);
switch (data.status) {
case 'mobile_connected':
console.log(
'[WebSocket] Mobile device connected. Emitting self_app event with payload:',
selfApp,
);
setProofStep(QRcodeSteps.MOBILE_CONNECTED);
if (type === 'websocket') {
socket.emit('self_app', { ...selfApp, sessionId });
}
break;
case 'mobile_disconnected':
console.log('[WebSocket] Mobile device disconnected.');
setProofStep(QRcodeSteps.WAITING_FOR_MOBILE);
break;
case 'proof_generation_started':
console.log('[WebSocket] Proof generation started.');
setProofStep(QRcodeSteps.PROOF_GENERATION_STARTED);
break;
case 'proof_generated':
console.log('[WebSocket] Proof generated.');
setProofStep(QRcodeSteps.PROOF_GENERATED);
break;
case 'proof_generation_failed':
console.log('[WebSocket] Proof generation failed.');
setProofStep(QRcodeSteps.PROOF_GENERATION_FAILED);
onError(data);
break;
case 'proof_verified':
console.log('[WebSocket] Proof verified.');
console.log('ws data', data);
setProofStep(QRcodeSteps.PROOF_VERIFIED);
onSuccess();
break;
default:
console.log('[WebSocket] Unhandled mobile status:', data.status);
break;
}
};
export function initWebSocket(
websocketUrl: string,
@@ -76,21 +86,25 @@ export function initWebSocket(
type: 'websocket' | 'deeplink',
setProofStep: (step: number) => void,
onSuccess: () => void,
onError: (data: {error_code?: string, reason?: string}) => void,
onError: (data: { error_code?: string; reason?: string }) => void,
) {
const sessionId = selfApp.sessionId;
console.log(`[WebSocket] Initializing WebSocket connection for sessionId: ${sessionId}`);
console.log(
`[WebSocket] Initializing WebSocket connection for sessionId: ${sessionId}`,
);
const socket = newSocket(websocketUrl, sessionId);
socket.on('connect', () => {
console.log(`[WebSocket] Connected with id: ${socket.id}, transport: ${socket.io.engine.transport.name}`);
console.log(
`[WebSocket] Connected with id: ${socket.id}, transport: ${socket.io.engine.transport.name}`,
);
});
socket.on('connect_error', (error) => {
socket.on('connect_error', error => {
console.error('[WebSocket] Connection error:', error);
});
socket.on('mobile_status', (data) => {
socket.on('mobile_status', data => {
console.log('[WebSocket] Raw mobile_status event received:', data);
handleWebSocketMessage(
socket,
@@ -99,16 +113,20 @@ export function initWebSocket(
type,
setProofStep,
onSuccess,
onError
onError,
)(data);
});
socket.on('disconnect', (reason: string) => {
console.log(`[WebSocket] Disconnected. Reason: ${reason}, Last transport: ${socket.io.engine.transport?.name}`);
console.log(
`[WebSocket] Disconnected. Reason: ${reason}, Last transport: ${socket.io.engine.transport?.name}`,
);
});
return () => {
console.log(`[WebSocket] Cleaning up connection for sessionId: ${sessionId}`);
console.log(
`[WebSocket] Cleaning up connection for sessionId: ${sessionId}`,
);
if (socket) {
socket.disconnect();
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,15 +4,16 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "bun run --watch src/app.ts",
"types": "tsc --noEmit",
"init": "bash scripts/copy_abi.sh && bash scripts/copy_deployedAddress.sh",
"start:daemon": "bun run src/app.ts > app.log 2>&1 &",
"stop:daemon": "pkill -f 'bun run src/app.ts'"
},
"dependencies": {
"@elysiajs/swagger": "^1.2.0",
"@selfxyz/core": "^0.0.3",
"@openpassport/zk-kit-imt": "^0.0.5",
"@openpassport/zk-kit-lean-imt": "^0.0.6",
"@selfxyz/core": "^0.0.3",
"dotenv": "^16.4.7",
"elysia": "latest",
"logixlysia": "^4.1.1",
@@ -24,7 +25,8 @@
},
"devDependencies": {
"@types/pg": "^8.11.11",
"bun-types": "latest"
"bun-types": "latest",
"typescript": "^5.8.3"
},
"module": "index.ts"
}
}

View File

@@ -1,6 +1,5 @@
import Elysia, { t } from 'elysia';
// import { SelfBackendVerifier } from "@selfxyz/core";
import { SelfBackendVerifier } from "../../../../../core/src/SelfBackendVerifier";
import { SelfBackendVerifier } from "@selfxyz/core";
export const ContractsController = new Elysia()
.post(
@@ -51,4 +50,3 @@ export const ContractsController = new Elysia()
},
},
);

View File

@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "ES2021",
"module": "ES2022",
"moduleResolution": "node",
"module": "NodeNext",
"moduleResolution": "nodenext",
"types": [
"bun-types"
],
@@ -12,4 +12,4 @@
"skipLibCheck": true,
"resolveJsonModule": true
}
}
}

View File

@@ -1,68 +0,0 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';
import { groth16 } from 'snarkjs';
import { genAndInitMockPassportData } from '../../common/src/utils/genMockPassportData';
import {
buildAttestation,
OpenPassportDynamicAttestation,
} from '../../common/src/utils/openPassportAttestation';
import { OpenPassportVerifier } from '../src/OpenPassportVerifier';
import { OpenPassportVerifierReport } from '../src/OpenPassportVerifierReport';
import { generateCircuitInputsInSdk } from './utils/generateInputsInSdk';
import {
alphaCode,
dateOfBirth,
dateOfExpiry,
getCountryName,
majority,
scope,
TestCase,
testCases,
} from './utils/testCases';
const runTest = async (testCase: TestCase) => {
const { circuitType, algorithm, wasmPath, zkeyPath } = testCase;
const passportData = genAndInitMockPassportData(algorithm, alphaCode, dateOfBirth, dateOfExpiry);
const inputs = generateCircuitInputsInSdk(passportData, circuitType);
const { proof, publicSignals } = await groth16.fullProve(inputs, wasmPath, zkeyPath);
const openPassportVerifier = new OpenPassportVerifier({
scope: scope,
olderThan: majority,
nationality: getCountryName(),
dev_mode: true,
circuit: circuitType,
});
const attestation = buildAttestation({
proof: proof as any,
publicSignals: publicSignals,
dsc: passportData.dsc as string,
});
console.log('\x1b[34mattestation: \x1b[0m', attestation);
const result = await openPassportVerifier.verify(attestation);
return { result, attestation };
};
const verifyResult = (
result: OpenPassportVerifierReport,
attestation: OpenPassportDynamicAttestation
) => {
if (!result.valid) {
console.log(result);
}
console.log('\x1b[34mnullifier: \x1b[0m', attestation.getNullifier());
expect(result.valid).to.be.true;
};
describe('\x1b[35mOpenPassportVerifier\x1b[0m', function () {
this.timeout(0);
testCases.forEach((testCase) => {
const { circuitType, algorithm } = testCase;
it(`${circuitType} - ${algorithm}`, async function () {
const { result, attestation } = await runTest(testCase);
verifyResult(result, attestation);
});
});
});

View File

@@ -1,35 +0,0 @@
import { PassportData } from '../../../common/src/utils/types';
import { CircuitName } from '../../../common/src/utils/appType';
import { k_dsc, n_dsc, PASSPORT_ATTESTATION_ID } from '../../../common/src/constants/constants';
import { generateCircuitInputsProve } from '../../../common/src/utils/generateInputs';
import { majority, scope } from './testCases';
export const generateCircuitInputsInSdk = (
passportData: PassportData,
circuit: CircuitName
): any => {
switch (circuit) {
case 'prove':
const selector_dg1 = Array(88).fill('1');
const selector_older_than = 1;
const selector_mode = 0;
const secret = 0;
const dsc_secret = 0;
// import missing
const user_identifier = crypto.randomUUID();
return generateCircuitInputsProve(
selector_mode,
secret,
dsc_secret,
passportData,
scope,
selector_dg1,
selector_older_than,
majority,
user_identifier
);
default:
throw new Error('Invalid circuit');
}
};

View File

@@ -1,45 +0,0 @@
import { countryCodes, DEFAULT_MAJORITY } from '../../../common/src/constants/constants';
type CircuitType = 'prove';
type AlgorithmType = 'rsa_sha256' | 'rsa_sha1' | 'rsapss_sha256';
export const scope = '@spaceShips';
export const majority = DEFAULT_MAJORITY;
export const alphaCode = 'FRA';
export const dateOfBirth = '000101';
export const dateOfExpiry = '300101';
export const getCountryName = () => {
const countryName = countryCodes[alphaCode as keyof typeof countryCodes];
if (!countryName) {
throw new Error(`Country name not found for alpha code: ${alphaCode}`);
}
return countryName;
};
export interface TestCase {
circuitType: CircuitType;
algorithm: AlgorithmType;
wasmPath: string;
zkeyPath: string;
}
export const testCases: TestCase[] = [
{
circuitType: 'prove',
algorithm: 'rsa_sha256',
wasmPath: '../circuits/build/fromAWS/prove_rsa_65537_sha256.wasm',
zkeyPath: '../circuits/build/fromAWS/prove_rsa_65537_sha256.zkey',
},
{
circuitType: 'prove',
algorithm: 'rsa_sha1',
wasmPath: '../circuits/build/fromAWS/prove_rsa_65537_sha1.wasm',
zkeyPath: '../circuits/build/fromAWS/prove_rsa_65537_sha1.zkey',
},
{
circuitType: 'prove',
algorithm: 'rsapss_sha256',
wasmPath: '../circuits/build/fromAWS/prove_rsapss_65537_sha256.wasm',
zkeyPath: '../circuits/build/fromAWS/prove_rsapss_65537_sha256.zkey',
},
];

View File

@@ -1,9 +1,11 @@
{
"name": "web-app",
"name": "test-web-app",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"build": "next build",
"types": "yarn build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
@@ -12,6 +14,8 @@
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/material": "^6.0.2",
"@selfxyz/common": "workspace:^",
"@selfxyz/qrcode": "workspace:^",
"axios": "^1.7.7",
"next": "14.2.8",
"react": "^18",

View File

@@ -1,7 +1,6 @@
import { SelfBackendVerifier } from '../../../../../../core';
import { SelfBackendVerifier } from '@selfxyz/core';
import { NextResponse } from 'next/server';
import { countries } from '../../../../../../../common/src/constants/countries';
import { count } from 'console';
import { countries } from '@selfxyz/common/constants/countries';
export async function POST(request: Request) {
try {
@@ -19,7 +18,6 @@ export async function POST(request: Request) {
'https://forno.celo.org',
"self-workshop",
'uuid',
false
)
.setMinimumAge(18)
.excludeCountries(

View File

@@ -1,13 +1,12 @@
'use client';
import { SelfAppBuilder } from '../../../../../qrcode/SelfQRcode';
import SelfQRcodeWrapper from '../../../../../qrcode/SelfQRcode';
import SelfQRcodeWrapper, { SelfAppBuilder } from '@selfxyz/qrcode';
import { v4 } from 'uuid';
import {logo} from './logo';
export default function Prove() {
const userId = v4();
const selfApp = new SelfAppBuilder({
appName: "Mock App2",
scope: "test-scope",
@@ -36,6 +35,7 @@ export default function Prove() {
onSuccess={() => {
window.location.href = '/success';
}}
onError={console.error}
/>
</div>
);

View File

@@ -1,8 +1,6 @@
'use client';
import { SelfAppBuilder } from '../../../../qrcode/SelfQRcode';
import SelfQRcodeWrapper from '../../../../qrcode/SelfQRcode';
import { countries } from '../../../../../common/src/constants/countries';
import SelfQRcodeWrapper, { SelfAppBuilder, countries } from '@selfxyz/qrcode';
import { v4 } from 'uuid';
export default function Home() {
@@ -36,6 +34,7 @@ export default function Home() {
onSuccess={() => {
window.location.href = '/verified';
}}
onError={console.error}
/>
</div>
);

View File

@@ -21,6 +21,6 @@
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "./src/**/*.ts", "./src/**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

File diff suppressed because it is too large Load Diff