diff --git a/.env.sample b/.env.sample index 73669b1d4..cbcf1ca6f 100644 --- a/.env.sample +++ b/.env.sample @@ -7,14 +7,18 @@ SUPABASE_JWT_SECRET= // Please specify your Supabase jwt secret API_GATEWAY_PROTOCOL=http API_GATEWAY_HOST='0.0.0.0' API_GATEWAY_PORT=5000 +API_GATEWAY_PROTOCOL_SECURE=http ## PLATFORM_NAME= // Please specify your paltform name +PLATFORM_LOGO= // Please specify your paltform logo url PUBLIC_PLATFORM_SUPPORT_EMAIL= // Please specify your support email POWERED_BY= // Please specify your powered by org name PLATFORM_WEB_URL= // Please specify your platform web URL POWERED_BY_URL= // Please specify your support URL +UPLOAD_LOGO_HOST= // Please specify your logo host or domain url + PUBLIC_LOCALHOST_URL= // Please specify your localhost URL PUBLIC_DEV_API_URL= // Please specify your DEV environment api URL PUBLIC_QA_API_URL= // Please specify your your QA environment api URL @@ -33,14 +37,46 @@ API_ENDPOINT_PORT=5000 SOCKET_HOST=http://localhost:5000 +AWS_PUBLIC_ACCESS_KEY= // Please provide your aws bucket access key +AWS_PUBLIC_SECRET_KEY= // Please provide your aws secret key +AWS_PUBLIC_REGION= // Please provide your aws region +AWS_PUBLIC_BUCKET_NAME= // Please provide your aws bucket name + +AWS_ORG_LOGO_BUCKET_NAME= // Please provide your aws org bucket name + +AWS_S3_STOREOBJECT_ACCESS_KEY= // Please provide your aws bucket access key +AWS_S3_STOREOBJECT_SECRET_KEY= // Please provide your aws bucket secret key +AWS_S3_STOREOBJECT_REGION= // Please provide your aws region +AWS_S3_STOREOBJECT_BUCKET= // Please provide your aws bucket +AWS_ACCESS_KEY= // Please provide your access key +AWS_SECRET_KEY= // Please provide your secret key +AWS_REGION= // Please provide your aws region +AWS_BUCKET= // Please provide your aws bucket + +PLATFORM_ADMIN_EMAIL= // Please provide admin email Id + NATS_HOST='0.0.0.0' NATS_PORT=4222 NATS_URL=nats://0.0.0.0:4222 +REDIS_HOST='0.0.0.0' +REDIS_PORT=6379 + +POSTGRES_HOST=0.0.0.0 +POSTGRES_PORT=5432 +POSTGRES_USER='postgres' +POSTGRES_PASSWORD='xxxxx' +POSTGRES_DATABASE= // Please provide your DB name + SENDGRID_API_KEY=xxxxxxxxxxxxxx // Please provide your sendgrid API key FRONT_END_URL=http://localhost:3000 +FILE_SERVER= // Please provide your file server +FILE_SERVER_PORT=8081 +FILE_SERVER_USER=credebl +FILE_SERVER_HOST=0.0.0.0 + AFJ_AGENT_SPIN_UP=/apps/agent-provisioning/AFJ/scripts/start_agent.sh WALLET_STORAGE_HOST=localhost # Use IP Address @@ -59,6 +95,10 @@ PLATFORM_WALLET_PASSWORD= // Please provide encrypt password using crypto-j PLATFORM_SEED= // The seed should consist of 32 characters. PLATFORM_ID= +PLATFORM_PROFILE_MODE= // Please provide your environment name + +OOB_BATCH_SIZE=10 + AFJ_AGENT_ENDPOINT_PATH=/apps/agent-provisioning/AFJ/endpoints/ DATABASE_URL="postgresql://postgres:xxxxxx@localhost:5432/postgres?schema=public" #Provide supabase postgres URL and Use the correct user/pwd, IP Address POOL_DATABASE_URL="" #Provide pooler supabase postgres URL @@ -68,6 +108,22 @@ AGENT_PROTOCOL=http GEO_LOCATION_MASTER_DATA_IMPORT_SCRIPT=/prisma/scripts/geo_location_data_import.sh UPDATE_CLIENT_CREDENTIAL_SCRIPT=/prisma/scripts/update_client_credential_data.sh +USER_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for user service +API_GATEWAY_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for api-gateway +ORGANIZATION_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for organization service +AGENT_PROVISIONING_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for agent provisioning service +AGENT_SERVICE_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for agent service +VERIFICATION_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for verification service +ISSUANCE_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for issuance service +CONNECTION_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for connection service +ECOSYSTEM_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for ecosystem service +CREDENTAILDEFINITION_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for credential-definition service +SCHEMA_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for schema service +UTILITIES_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for utilities service +GEOLOCATION_NKEY_SEED= xxxxxxxxxxx // Please provide Nkeys secret for geo-location service + +AFJ_AGENT_TOKEN_PATH=/apps/agent-provisioning/AFJ/token/ + # This was inserted by prisma init: # Environment variables declared in this file are automatically made available to Prisma. # See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema @@ -92,4 +148,10 @@ KEYCLOAK_MANAGEMENT_CLIENT_ID=xxxxxxx KEYCLOAK_MANAGEMENT_CLIENT_SECRET=xxxxxxx KEYCLOAK_REALM=xxxxxxx -ENABLE_CORS_IP_LIST="" # Provide a list of domains that are allowed to use this server \ No newline at end of file +ENABLE_CORS_IP_LIST="" # Provide a list of domains that are allowed to use this server +SCHEMA_FILE_SERVER_URL= // Please provide schema URL +SCHEMA_FILE_SERVER_TOKEN=xxxxxxxx // Please provide schema file server token for polygon + +FILEUPLOAD_CACHE_TTL= //Provide file upload cache ttl + +FIELD_UPLOAD_SIZE= //Provide field upload size \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/DMP_2024.yml b/.github/ISSUE_TEMPLATE/DMP_2024.yml new file mode 100644 index 000000000..f0eabd7b3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/DMP_2024.yml @@ -0,0 +1,264 @@ +name: DMP 2024 Project Template +description: List a new project for Dedicated Mentoring Program (DMP) 2024 +title: '[DMP 2024]: ' +labels: ['DMP 2024'] +body: + - type: textarea + id: ticket-description + validations: + required: true + attributes: + label: Ticket Contents + value: | + ## Description + [Provide a brief description of the feature, including why it is needed and what it will accomplish.] + + - type: textarea + id: ticket-goals + validations: + required: true + attributes: + label: Goals & Mid-Point Milestone + description: List the goals of the feature. Please add the goals that must be achieved by Mid-point check-in i.e 1.5 months into the coding period. + value: | + ## Goals + - [ ] [Goal 1] + - [ ] [Goal 2] + - [ ] [Goal 3] + - [ ] [Goal 4] + - [ ] [Goals Achieved By Mid-point Milestone] + + - type: textarea + id: ticket-setup + attributes: + label: Setup/Installation + description: Please list or link setup or installation guide (if any) + + - type: textarea + id: ticket-expected-outcome + attributes: + label: Expected Outcome + description: Describe in detail what the final product or result should look like and how it should behave. + + - type: textarea + id: ticket-acceptance-criteria + attributes: + label: Acceptance Criteria + description: List the acceptance criteria for this feature. + + - type: textarea + id: ticket-implementation-details + validations: + required: true + attributes: + label: Implementation Details + description: List any technical details about the proposed implementation, including any specific technologies that will be used. + + - type: textarea + id: ticket-mockups + attributes: + label: Mockups/Wireframes + description: Include links to any visual aids, mockups, wireframes, or diagrams that help illustrate what the final product should look like. This is not always necessary, but can be very helpful in many cases. + + - type: input + id: ticket-product + attributes: + label: Product Name + placeholder: Enter Product Name + validations: + required: true + + - type: dropdown + id: ticket-organisation + attributes: + label: Organisation Name + description: Enter Organisation Name + multiple: false + options: + - Bandhu + - Blockster Labs (CREDEBL) + - Civis + - Dhwani + - Dhiway + - EGov + - EkShop Marketplace + - FIDE + - If Me + - Key Education Foundation + - Norwegian Meteorological Institute + - Planet Read + - Project Second Chance + - Reap Benefit + - SamagraX + - ShikshaLokam + - Tech4Dev + - Tekdi + - The Mifos Initiative + - Tibil + - Ushahidi + - Arghyam + - Piramal Swasthya Management Research Institute + validations: + required: true + + - type: dropdown + id: ticket-governance-domain + attributes: + label: Domain + options: + - Healthcare + - Education + - Financial Inclusion + - Livelihoods + - Skilling + - Learning & Development + - Agriculture + - Service Delivery + - Open Source Library + - Water + - Identity & Digital Credentialing + validations: + required: true + + - type: dropdown + id: ticket-technical-skills-required + attributes: + label: Tech Skills Needed + description: Select the technologies needed for this ticket (use Ctrl or Command to select multiple) + multiple: true + options: + - .NET + - Angular + - Artificial Intelligence + - ASP.NET + - Astro.js + - AWS + - Babel + - Bootstrap + - C# + - Chart.js + - CI/CD + - Computer Vision + - CORS + - cURL + - Cypress + - D3.js + - Database + - Debugging + - Deno + - Design + - DevOps + - Django + - Docker + - Electron + - ESLint + - Express.js + - Feature + - Flask + - Go + - GraphQL + - HTML + - Ionic + - Jest + - Java + - JavaScript + - Jenkins + - JWT + - Kubernetes + - Laravel + - Machine Learning + - Maintenance + - Markdown + - Material-UI + - Microservices + - MongoDB + - Mobile + - Mockups + - Mocha + - Natural Language Processing + - NATS Messaging + - NestJS + - Next.js + - Node.js + - NUnit + - OAuth + - Performance Improvement + - Prettier + - Python + - Question + - React + - React Native + - Redux + - RESTful APIs + - Ruby + - Ruby on Rails + - Rust + - Scala + - Security + - Selenium + - SEO + - Serverless + - Solidity + - Spring Boot + - SQL + - Swagger + - Tailwind CSS + - Test + - Testing Library + - Three.js + - TypeScript + - UI/UX/Design + - Virtual Reality + - Vue.js + - WebSockets + - Webpack + - Other + validations: + required: true + + - type: textarea + id: ticket-mentors + attributes: + label: Mentor(s) + description: Please tag relevant mentors for the ticket + validations: + required: true + + - type: dropdown + id: ticket-category + attributes: + label: Category + description: Choose the categories that best describe your ticket + multiple: true + options: + - API + - Analytics + - Accessibility + - Backend + - Breaking Change + - Beginner Friendly + - Configuration + - CI/CD + - Database + - Data Science + - Deprecation + - Documentation + - Deployment + - Frontend + - Internationalization + - Localization + - Machine Learning + - Maintenance + - Mobile + - Performance Improvement + - Question + - Refactoring + - Research + - Needs Reproduction + - SEO + - Security + - Testing + - AI + - Other + validations: + required: true diff --git a/Dockerfiles/Dockerfile.verification b/Dockerfiles/Dockerfile.verification index 85524a381..99771b8db 100644 --- a/Dockerfiles/Dockerfile.verification +++ b/Dockerfiles/Dockerfile.verification @@ -33,4 +33,4 @@ COPY --from=build /app/libs/ ./libs/ COPY --from=build /app/node_modules ./node_modules # Set the command to run the microservice -CMD ["sh", "-c", "cd libs/prisma-service && npx prisma migrate deploy && cd ../.. && node dist/apps/verification/main.js"] \ No newline at end of file +CMD ["sh", "-c", "cd libs/prisma-service && npx prisma migrate deploy && cd ../.. && node dist/apps/verification/main.js"] diff --git a/apps/agent-provisioning/AFJ/scripts/on_premises_agent.sh b/apps/agent-provisioning/AFJ/scripts/on_premises_agent.sh new file mode 100644 index 000000000..54084f000 --- /dev/null +++ b/apps/agent-provisioning/AFJ/scripts/on_premises_agent.sh @@ -0,0 +1,341 @@ +#!/bin/bash + +START_TIME=$(date +%s) + +# Check if Docker is installed +if ! command -v docker &> /dev/null; then + echo "Docker is not installed. Installing Docker..." + + # Install Docker + curl -fsSL https://get.docker.com -o get-docker.sh + sudo sh get-docker.sh + + # Add the current user to the docker group + sudo usermod -aG docker $USER + + # Start and enable the Docker service + sudo systemctl start docker + sudo systemctl enable docker + + echo "Docker has been installed." +else + echo "Docker is already installed." +fi + +# Function to prompt user for input +prompt_input() { + local prompt_message=$1 + local input_variable=$2 + read -p "$prompt_message" $input_variable +} + +prompt_input_with_tenant_validation() { + local prompt_message=$1 + local input_variable=$2 + local validation_message=$3 + + while true; do + read -p "$prompt_message" $input_variable + case "${!input_variable}" in + true | false) + break + ;; + *) + echo "$validation_message" + ;; + esac + done +} + +prompt_input_with_webhook_host_validation() { + local prompt_message=$1 + local input_variable=$2 + local validation_message=$3INDY_LEDGER_FORMATTED + + while true; do + read -p "$prompt_message" $input_variable + local input_value="${!input_variable}" + local ip_address=$(echo "$input_value" | cut -d ':' -f 1 | sed 's/http:\/\///;s/https:\/\///') + local port=$(echo "$input_value" | cut -d ':' -f 3) + + if [[ "$input_value" =~ ^http:\/\/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+$ && "$port" =~ ^[0-9]+$ ]]; then + break + elif [[ "$input_value" =~ ^https:\/\/[a-zA-Z0-9.-]+$ ]]; then + break + else + echo "$validation_message" + fi + done +} + +# Function to validate INDY_LEDGER input against the provided options +validate_indy_ledger() { + local input_ledger=$1 + case "$input_ledger" in + 1) echo 'No ledger' ;; # Option for "no ledger" + 2) echo 'Polygon' ;; # Option for "polygon" + 3) echo '{"genesisTransactions":"http://test.bcovrin.vonx.io/genesis","indyNamespace":"bcovrin:testnet"}' ;; + 4) echo '{"genesisTransactions":"https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_testnet_genesis","indyNamespace":"indicio:testnet"}' ;; + 5) echo '{"genesisTransactions":"https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_demonet_genesis","indyNamespace":"indicio:demonet"}' ;; + 6) echo '{"genesisTransactions":"https://raw.githubusercontent.com/Indicio-tech/indicio-network/main/genesis_files/pool_transactions_mainnet_genesis","indyNamespace":"indicio:mainnet"}' ;; + *) echo "Invalid choice" ;; + esac +} + +# Prompt user for input +prompt_input "Enter ORGANIZATION_ID: " ORGANIZATION_ID +prompt_input "Enter WALLET_NAME: " WALLET_NAME +prompt_input "Enter WALLET_PASSWORD: " WALLET_PASSWORD + +# Prompt user for RANDOM_SEED input and validate it +while true; do + prompt_input "Enter RANDOM_SEED: " RANDOM_SEED + if [ ${#RANDOM_SEED} -eq 32 ]; then + break + else + echo "Error: RANDOM_SEED must be exactly 32 characters." + fi +done + +echo "RANDOM_SEED accepted: $RANDOM_SEED" + +# Display options to the user for INDY_LEDGER +echo "Choose INDY_LEDGER option(s) (comma-separated, e.g., 1):" +echo "1) No ledger" +echo "2) Polygon" +echo "3) bcovrin:testnet" +echo "4) indicio:testnet" +echo "5) indicio:demonet" +echo "6) indicio:mainnet" + +# Prompt user to choose INDY_LEDGER option(s) +INDY_LEDGER=() +read -r INDY_LEDGER_INPUT + +# Split the input by commas and process each choice +IFS=',' read -ra CHOICES <<<"$INDY_LEDGER_INPUT" +for choice in "${CHOICES[@]}"; do + choice=$(echo "$choice" | tr -d ' ') # Remove any spaces + case $choice in + 1 | 2 | 3 | 4 | 5 | 6) + if [ -n "${INDY_LEDGER}" ]; then + echo "Error: Only one INDY_LEDGER option can be selected." + exit 1 + fi + INDY_LEDGER=$(validate_indy_ledger $choice) + ;; + *) + echo "Invalid choice: $choice" + ;; + esac +done + +# Check if "No ledger" or "Polygon" is selected and set INDY_LEDGER_FORMATTED accordingly +if [ "$INDY_LEDGER" = "No ledger" ] || [ "$INDY_LEDGER" = "Polygon" ]; then + INDY_LEDGER_FORMATTED="[]" +else + # Set INDY_LEDGER_FORMATTED based on selected option + INDY_LEDGER_FORMATTED="[$INDY_LEDGER]" +fi + +echo "INDY_LEDGER chosen: $INDY_LEDGER" +echo "Formatted INDY_LEDGER: $INDY_LEDGER_FORMATTED" + +# Proceed to prompt for other parameters +prompt_input_with_webhook_host_validation "Enter WEBHOOK_HOST (host/domain): " WEBHOOK_HOST "Error: WEBHOOK_HOST must be in the format http://host:port or https://domain." +prompt_input "Enter WALLET_STORAGE_HOST: " WALLET_STORAGE_HOST +prompt_input "Enter WALLET_STORAGE_PORT: " WALLET_STORAGE_PORT +prompt_input "Enter WALLET_STORAGE_USER: " WALLET_STORAGE_USER +prompt_input "Enter WALLET_STORAGE_PASSWORD: " WALLET_STORAGE_PASSWORD +prompt_input "Enter AGENT_NAME: " AGENT_NAME +prompt_input "Enter PROTOCOL: " PROTOCOL +prompt_input_with_tenant_validation "Enter TENANT (true/false): " TENANT "Error: TENANT must be either 'true' or 'false'." +prompt_input "Enter CREDO_IMAGE: " CREDO_IMAGE +prompt_input "Enter INBOUND_ENDPOINT: " INBOUND_ENDPOINT +prompt_input "Enter ADMIN_PORT: " ADMIN_PORT +prompt_input "Enter INBOUND_PORT: " INBOUND_PORT + +# Run the command using user input +on_premises_agent.sh --ORGANIZATION_ID "$ORGANIZATION_ID" --WALLET_NAME "$WALLET_NAME" --WALLET_PASSWORD "$WALLET_PASSWORD" --RANDOM_SEED "$RANDOM_SEED" --WEBHOOK_HOST "$WEBHOOK_HOST" --WALLET_STORAGE_HOST "$WALLET_STORAGE_HOST" --WALLET_STORAGE_PORT "$WALLET_STORAGE_PORT" --WALLET_STORAGE_USER "$WALLET_STORAGE_USER" --WALLET_STORAGE_PASSWORD "$WALLET_STORAGE_PASSWORD" --AGENT_NAME "$AGENT_NAME" --PROTOCOL "$PROTOCOL" --TENANT "$TENANT" --CREDO_IMAGE "$CREDO_IMAGE" --INDY_LEDGER "$INDY_LEDGER" --INBOUND_ENDPOINT "$INBOUND_ENDPOINT" --ADMIN_PORT "$ADMIN_PORT" --INBOUND_PORT "$INBOUND_PORT" + +echo "admin port: $ADMIN_PORT" +echo "inbound port: $INBOUND_PORT" + +echo "AGENT SPIN-UP STARTED" + +if [ -d "${PWD}/agent-config" ]; then + echo "agent-config directory exists." +else + echo "Error: agent-config directory does not exists." + mkdir ${PWD}/agent-config +fi + +# Define a regular expression pattern for IP address +IP_REGEX="^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$" + +# Check if the input is a domain +if echo "$INBOUND_ENDPOINT" | grep -qP "^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"; then + echo "INBOUND_ENDPOINT is a domain: $INBOUND_ENDPOINT" + AGENT_ENDPOINT=$INBOUND_ENDPOINT +else + # Check if the input is an IP address + if [[ $INBOUND_ENDPOINT =~ $IP_REGEX ]]; then + echo "INBOUND_ENDPOINT is an IP address: $INBOUND_ENDPOINT" + AGENT_ENDPOINT="${PROTOCOL}://${INBOUND_ENDPOINT}:${INBOUND_PORT}" + else + echo "Invalid input for INBOUND_ENDPOINT: $INBOUND_ENDPOINT" + fi +fi + +echo "-----$AGENT_ENDPOINT----" +CONFIG_FILE="${PWD}/agent-config/${ORGANIZATION_ID}_${AGENT_NAME}.json" + +# Check if the file exists +if [ -f "$CONFIG_FILE" ]; then + # If it exists, remove the file + rm "$CONFIG_FILE" +fi + +cat <${CONFIG_FILE} +{ + "label": "${ORGANIZATION_ID}_${AGENT_NAME}", + "walletId": "$WALLET_NAME", + "walletKey": "$WALLET_PASSWORD", + "walletType": "postgres", + "walletUrl": "$WALLET_STORAGE_HOST:$WALLET_STORAGE_PORT", + "walletAccount": "$WALLET_STORAGE_USER", + "walletPassword": "$WALLET_STORAGE_PASSWORD", + "walletAdminAccount": "$WALLET_STORAGE_USER", + "walletAdminPassword": "$WALLET_STORAGE_PASSWORD", + "walletScheme": "DatabasePerWallet", + "indyLedger": $INDY_LEDGER_FORMATTED, + "endpoint": [ + "$AGENT_ENDPOINT" + ], + "autoAcceptConnections": true, + "autoAcceptCredentials": "contentApproved", + "autoAcceptProofs": "contentApproved", + "logLevel": 5, + "inboundTransport": [ + { + "transport": "$PROTOCOL", + "port": "$INBOUND_PORT" + } + ], + "outboundTransport": [ + "$PROTOCOL" + ], + "webhookUrl": "$WEBHOOK_HOST/wh/$ORGANIZATION_ID", + "adminPort": "$ADMIN_PORT", + "tenancy": $TENANT +} +EOF + +FILE_NAME="docker-compose_${ORGANIZATION_ID}_${AGENT_NAME}.yaml" + +DOCKER_COMPOSE="${PWD}/${FILE_NAME}" + +# Check if the file exists +if [ -f "$DOCKER_COMPOSE" ]; then + # If it exists, remove the file + rm "$DOCKER_COMPOSE" +fi +cat <${DOCKER_COMPOSE} +version: '3' + +services: + agent: + image: $CREDO_IMAGE + + container_name: ${ORGANIZATION_ID}_${AGENT_NAME} + restart: always + environment: + AFJ_REST_LOG_LEVEL: 1 + ports: + - ${INBOUND_PORT}:${INBOUND_PORT} + - ${ADMIN_PORT}:${ADMIN_PORT} + + volumes: + - ./agent-config/${ORGANIZATION_ID}_${AGENT_NAME}.json:/config.json + + command: --auto-accept-connections --config /config.json + +volumes: + pgdata: + agent-indy_client: + agent-tmp: +EOF + +if [ $? -eq 0 ]; then + cd ${PWD} + echo "docker-compose generated successfully!" + echo "=================" + echo "spinning up the container" + echo "=================" + echo "container-name::::::${AGENT_NAME}" + echo "file-name::::::$FILE_NAME" + + docker compose -p "${ORGANIZATION_ID}_${AGENT_NAME}" -f $FILE_NAME up -d + if [ $? -eq 0 ]; then + + echo "Creating agent config" + # Capture the logs from the container + container_id=$(docker ps -q --filter "name=${ORGANIZATION_ID}_${AGENT_NAME}") + + if [ -z "$container_id" ]; then + echo "Error: No container found with name ${ORGANIZATION_ID}_${AGENT_NAME}" + exit 1 + fi + + # Wait for the container to generate logs + retries=5 + delay=10 + while [ $retries -gt 0 ]; do + container_logs=$(docker logs "$container_id" 2>/dev/null) + if [ -n "$container_logs" ]; then + break + else + echo "Waiting for logs to be generated..." + sleep $delay + retries=$((retries - 1)) + fi + done + + if [ -z "$container_logs" ]; then + echo "Error: No logs found for container ${ORGANIZATION_ID}_${AGENT_NAME} after waiting" + exit 1 + fi + + # Extract the token from the logs using sed + token=$(echo "$container_logs" | sed -nE 's/.*API Token: ([^ ]+).*/\1/p') + + if [ -z "$token" ]; then + echo "Error: Failed to extract API token from logs" + exit 1 + fi + + # Highlight the token line when printing + highlighted_token="Token: \x1b[1;31m$token\x1b[0m" + + # Print the extracted token with highlighting + echo -e "$highlighted_token" + echo "Agent config created" + + # Check if the token exists to determine if the agent is running + if [ -n "$token" ]; then + echo "Agent is running" + else + echo "Agent is not running" + exit 1 + fi + + else + echo "===============" + echo "ERROR : Failed to spin up the agent!" + echo "===============" && exit 125 + fi +else + echo "ERROR : Failed to execute!" && exit 125 +fi + +echo "Total time elapsed: $(date -ud "@$(($(date +%s) - $START_TIME))" +%T) (HH:MM:SS)" diff --git a/apps/agent-service/src/repositories/agent-service.repository.ts b/apps/agent-service/src/repositories/agent-service.repository.ts index 81c82d1ea..09529b573 100644 --- a/apps/agent-service/src/repositories/agent-service.repository.ts +++ b/apps/agent-service/src/repositories/agent-service.repository.ts @@ -220,6 +220,7 @@ export class AgentServiceRepository { } } + /** * Get agent details * @param orgId diff --git a/apps/api-gateway/src/authz/jwt.strategy.ts b/apps/api-gateway/src/authz/jwt.strategy.ts index 5ea90b943..a7bac5265 100644 --- a/apps/api-gateway/src/authz/jwt.strategy.ts +++ b/apps/api-gateway/src/authz/jwt.strategy.ts @@ -91,7 +91,7 @@ export class JwtStrategy extends PassportStrategy(Strategy) { if (!userDetails) { throw new NotFoundException(ResponseMessages.user.error.notFound); } - + //TODO patch to QA if (userInfo && userInfo?.['attributes'] && userInfo?.['attributes']?.userRole) { userDetails['userRole'] = userInfo?.['attributes']?.userRole; } diff --git a/apps/api-gateway/src/issuance/issuance.controller.ts b/apps/api-gateway/src/issuance/issuance.controller.ts index f5d80615e..27bfb0477 100644 --- a/apps/api-gateway/src/issuance/issuance.controller.ts +++ b/apps/api-gateway/src/issuance/issuance.controller.ts @@ -42,6 +42,7 @@ import { ForbiddenErrorDto } from '../dtos/forbidden-error.dto'; import { Response } from 'express'; import IResponseType, { IResponse } from '@credebl/common/interfaces/response.interface'; import { IssuanceService } from './issuance.service'; +import { CommonConstants } from '../../../../libs/common/src/common.constant'; import { ClientDetails, CredentialQuery, @@ -400,7 +401,9 @@ async downloadBulkIssuanceCSVTemplate( }, required: true }) - @UseInterceptors(FileInterceptor('file')) + @UseInterceptors(FileInterceptor('file', { + limits: { fieldSize: Number(process.env.FIELD_UPLOAD_SIZE) || CommonConstants.DEFAULT_FIELD_UPLOAD_SIZE } + })) async issueBulkCredentials( @Body() clientDetails: ClientDetails, diff --git a/apps/api-gateway/src/main.ts b/apps/api-gateway/src/main.ts index 39d6c4010..1f9430331 100644 --- a/apps/api-gateway/src/main.ts +++ b/apps/api-gateway/src/main.ts @@ -45,7 +45,6 @@ async function bootstrap(): Promise { } next(); }); - const options = new DocumentBuilder() .setTitle(`${process.env.PLATFORM_NAME}`) .setDescription(`${process.env.PLATFORM_NAME} Platform APIs`) diff --git a/apps/api-gateway/src/user/dto/share-certificate.dto.ts b/apps/api-gateway/src/user/dto/share-certificate.dto.ts index 802b849d9..ca82fd844 100644 --- a/apps/api-gateway/src/user/dto/share-certificate.dto.ts +++ b/apps/api-gateway/src/user/dto/share-certificate.dto.ts @@ -8,24 +8,19 @@ interface Attribute { value: string; } export class CreateCertificateDto { + @ApiProperty() - @IsNotEmpty({ message: 'Please provide valid schemaId' }) + @IsNotEmpty({ message: 'Please provide valid credentialId' }) @Transform(({ value }) => trim(value)) @IsString({ message: 'credentialId should be string' }) credentialId: string; - @ApiProperty({ example: 'SchemaId' }) + @ApiProperty({ example: 'schemaId' }) @IsNotEmpty({ message: 'Please provide valid schemaId' }) @Transform(({ value }) => trim(value)) @IsString({ message: 'schemaId should be string' }) schemaId: string; - @ApiProperty({ example: 'CredDefId' }) - @IsNotEmpty({ message: 'Please provide valid schemaId' }) - @Transform(({ value }) => trim(value)) - @IsString({ message: 'credDefId should be string' }) - credDefId?: string; - @ApiProperty({ example: [ { diff --git a/apps/issuance/src/issuance.repository.ts b/apps/issuance/src/issuance.repository.ts index 092637b2e..96d491321 100644 --- a/apps/issuance/src/issuance.repository.ts +++ b/apps/issuance/src/issuance.repository.ts @@ -183,8 +183,13 @@ export class IssuanceRepository { let schemaId = ''; - if (issueCredentialDto?.metadata?.['_anoncreds/credential']?.schemaId) { - schemaId = issueCredentialDto?.metadata?.['_anoncreds/credential']?.schemaId; + if ( + (issueCredentialDto?.metadata?.['_anoncreds/credential']?.schemaId || + issueCredentialDto?.['credentialData']?.offer?.jsonld?.credential?.['@context'][1]) || + (issueCredentialDto?.state && + issueCredentialDto?.['credentialData']?.proposal?.jsonld?.credential?.['@context'][1]) + ) { + schemaId = issueCredentialDto?.metadata?.['_anoncreds/credential']?.schemaId || issueCredentialDto?.['credentialData']?.offer?.jsonld?.credential?.['@context'][1] || issueCredentialDto?.['credentialData']?.proposal?.jsonld?.credential?.['@context'][1]; } let credDefId = ''; @@ -201,7 +206,9 @@ export class IssuanceRepository { createDateTime: issueCredentialDto?.createDateTime, threadId: issueCredentialDto?.threadId, connectionId: issueCredentialDto?.connectionId, - state: issueCredentialDto?.state + state: issueCredentialDto?.state, + schemaId, + credDefId }, create: { createDateTime: issueCredentialDto?.createDateTime, @@ -216,6 +223,7 @@ export class IssuanceRepository { orgId: organisationId } }); + return credentialDetails; } catch (error) { this.logger.error(`Error in get saveIssuedCredentialDetails: ${error.message} `); diff --git a/apps/issuance/src/issuance.service.ts b/apps/issuance/src/issuance.service.ts index b0fd67d98..05dba9184 100644 --- a/apps/issuance/src/issuance.service.ts +++ b/apps/issuance/src/issuance.service.ts @@ -28,7 +28,7 @@ import { FileUploadStatus, FileUploadType } from 'apps/api-gateway/src/enum'; import { AwsService } from '@credebl/aws'; import { io } from 'socket.io-client'; import { IIssuedCredentialSearchParams, IssueCredentialType } from 'apps/api-gateway/src/issuance/interfaces'; -import { ICredentialOfferResponse, IDeletedIssuanceRecords, IIssuedCredential, IJsonldCredential, IPrettyVc } from '@credebl/common/interfaces/issuance.interface'; +import { ICredentialOfferResponse, IDeletedIssuanceRecords, IIssuedCredential, IJsonldCredential, IPrettyVc, ISchemaObject } from '@credebl/common/interfaces/issuance.interface'; import { OOBIssueCredentialDto } from 'apps/api-gateway/src/issuance/dtos/issuance.dto'; import { RecordType, agent_invitations, organisation, user } from '@prisma/client'; import { createOobJsonldIssuancePayload, validateAndUpdateIssuanceDates, validateEmail } from '@credebl/common/cast.helper'; @@ -48,12 +48,12 @@ export class IssuanceService { private readonly commonService: CommonService, private readonly issuanceRepository: IssuanceRepository, private readonly userActivityRepository: UserActivityRepository, - @Inject(CACHE_MANAGER) private cacheManager: Cache, + @Inject(CACHE_MANAGER) private readonly cacheManager: Cache, private readonly outOfBandIssuance: OutOfBandIssuance, private readonly emailData: EmailDto, private readonly awsService: AwsService, - @InjectQueue('bulk-issuance') private bulkIssuanceQueue: Queue, - @Inject(CACHE_MANAGER) private cacheService: Cache + @InjectQueue('bulk-issuance') private readonly bulkIssuanceQueue: Queue, + @Inject(CACHE_MANAGER) private readonly cacheService: Cache ) { } async getIssuanceRecords(orgId: string): Promise { @@ -253,8 +253,7 @@ export class IssuanceService { attributesArray.forEach((attribute) => { if (attribute.attributeName && attribute.isRequired) { - - payload.attributes.map((attr) => { + payload.attributes.forEach((attr) => { if (attr.name === attribute.attributeName && attribute.isRequired && !attr.value) { schemadetailsResponseError.push( `Attribute '${attribute.attributeName}' is required but has an empty value.` @@ -456,6 +455,30 @@ export class IssuanceService { orgId, issuedCredentialsSearchCriteria ); + + const getSchemaIds = getIssuedCredentialsList?.issuedCredentialsList?.map((schema) => schema?.schemaId); + + const getSchemaDetails = await this._getSchemaDetails(getSchemaIds); + + let responseWithSchemaName; + if (getSchemaDetails) { + responseWithSchemaName = getIssuedCredentialsList?.issuedCredentialsList.map(file => { + const schemaDetail = getSchemaDetails?.find(schema => schema.schemaLedgerId === file.schemaId); + return { + ...file, + schemaName: schemaDetail?.name + }; + }); + } else { + const getSchemaUrlDetails = await this.getSchemaUrlDetails(getSchemaIds); + responseWithSchemaName = getIssuedCredentialsList?.issuedCredentialsList.map(file => { + const schemaDetail = getSchemaUrlDetails?.find(schema => schema.title); + return { + ...file, + schemaName: schemaDetail?.title + }; + }); + } const issuedCredentialsResponse: IIssuedCredential = { totalItems: getIssuedCredentialsList.issuedCredentialsCount, hasNextPage: @@ -464,7 +487,7 @@ export class IssuanceService { nextPage: Number(issuedCredentialsSearchCriteria.pageNumber) + 1, previousPage: issuedCredentialsSearchCriteria.pageNumber - 1, lastPage: Math.ceil(getIssuedCredentialsList.issuedCredentialsCount / issuedCredentialsSearchCriteria.pageSize), - data: getIssuedCredentialsList.issuedCredentialsList + data: responseWithSchemaName }; if (0 === getIssuedCredentialsList?.issuedCredentialsCount) { @@ -478,6 +501,22 @@ export class IssuanceService { } } + async getSchemaUrlDetails(schemaUrls: string[]): Promise { + const results = []; + + for (const schemaUrl of schemaUrls) { + const schemaRequest = await this.commonService.httpGet(schemaUrl); + if (!schemaRequest) { + throw new NotFoundException(ResponseMessages.schema.error.W3CSchemaNotFOund, { + cause: new Error(), + description: ResponseMessages.errorMessages.notFound + }); + } + results.push(schemaRequest); + } + return results; +} + async _getIssueCredentials(url: string, apiKey: string): Promise<{ response: string; }> { @@ -816,7 +855,9 @@ async sendEmailForCredentialOffer(sendEmailCredentialOffer: SendEmailCredentialO } const invitationUrl: string = credentialCreateOfferDetails.response?.invitationUrl; + const shortenUrl: string = await this.storeIssuanceObjectReturnUrl(invitationUrl); + const deeplLinkURL = convertUrlToDeepLinkUrl(shortenUrl); if (!invitationUrl) { @@ -1131,9 +1172,10 @@ async sendEmailForCredentialOffer(sendEmailCredentialOffer: SendEmailCredentialO credentialPayload.fileName = fileName; const newCacheKey = uuidv4(); - await this.cacheManager.set(requestId ? requestId : newCacheKey, JSON.stringify(credentialPayload), 60000); - -return newCacheKey; + const cacheTTL = Number(process.env.FILEUPLOAD_CACHE_TTL) || CommonConstants.DEFAULT_CACHE_TTL; + await this.cacheManager.set(requestId || newCacheKey, JSON.stringify(credentialPayload), cacheTTL); + + return newCacheKey; } catch (error) { this.logger.error(`error in validating credentials : ${error.response}`); @@ -1333,6 +1375,7 @@ return newCacheKey; // Execute the batched jobs with limited concurrency await Promise.all(queueJobsArray.map(job => limit(() => job))); + return queueJobsArray; }; diff --git a/apps/ledger/src/schema/repositories/schema.repository.ts b/apps/ledger/src/schema/repositories/schema.repository.ts index 0f6199193..40c83c21c 100644 --- a/apps/ledger/src/schema/repositories/schema.repository.ts +++ b/apps/ledger/src/schema/repositories/schema.repository.ts @@ -238,35 +238,71 @@ export class SchemaRepository { async getAllSchemaDetails(payload: ISchemaSearchCriteria): Promise { try { const { ledgerId, schemaType, searchByText, sortField, sortBy, pageSize, pageNumber } = payload; - const schemasResult = await this.prisma.schema.findMany({ - where: { - ledgerId, - type: schemaType, - OR: [ - { name: { contains: searchByText, mode: 'insensitive' } }, - { version: { contains: searchByText, mode: 'insensitive' } }, - { schemaLedgerId: { contains: searchByText, mode: 'insensitive' } }, - { issuerId: { contains: searchByText, mode: 'insensitive' } } - ] - }, - select: { - createDateTime: true, - name: true, - version: true, - attributes: true, - schemaLedgerId: true, - createdBy: true, - publisherDid: true, - orgId: true, // This field can be null - issuerId: true, - type: true - }, - orderBy: { - [sortField]: SortValue.DESC === sortBy ? SortValue.DESC : SortValue.ASC - }, - take: Number(pageSize), - skip: (pageNumber - 1) * pageSize - }); + let schemaResult; + /** + * This is made so because the default pageNumber is set to 1 in DTO, + * If there is any 'searchByText' field, we ignore the pageNumbers and search + * in all available records. + * + * Because in that case pageNumber would be insignificant. + */ + if (searchByText) { + schemaResult = await this.prisma.schema.findMany({ + where: { + ledgerId, + type: schemaType, + OR: [ + { name: { contains: searchByText, mode: 'insensitive' } }, + { version: { contains: searchByText, mode: 'insensitive' } }, + { schemaLedgerId: { contains: searchByText, mode: 'insensitive' } }, + { issuerId: { contains: searchByText, mode: 'insensitive' } } + ] + }, + select: { + createDateTime: true, + name: true, + version: true, + attributes: true, + schemaLedgerId: true, + createdBy: true, + publisherDid: true, + orgId: true, // This field can be null + issuerId: true, + type: true + }, + orderBy: { + [sortField]: SortValue.DESC === sortBy ? SortValue.DESC : SortValue.ASC + }, + take: Number(pageSize) + }); + } else { + /** + * Queries apart from the one containing searchText would go here + */ + schemaResult = await this.prisma.schema.findMany({ + where: { + ledgerId, + type: schemaType + }, + select: { + createDateTime: true, + name: true, + version: true, + attributes: true, + schemaLedgerId: true, + createdBy: true, + publisherDid: true, + orgId: true, // This field can be null + issuerId: true, + type: true + }, + orderBy: { + [sortField]: SortValue.DESC === sortBy ? SortValue.DESC : SortValue.ASC + }, + take: Number(pageSize), + skip: (pageNumber - 1) * pageSize + }); + } const schemasCount = await this.prisma.schema.count({ where: { @@ -276,7 +312,7 @@ export class SchemaRepository { }); // Handle null orgId in the response - const schemasWithDefaultOrgId = schemasResult.map(schema => ({ + const schemasWithDefaultOrgId = schemaResult.map(schema => ({ ...schema, orgId: schema.orgId || null // Replace null orgId with 'N/A' or any default value })); diff --git a/apps/user/src/user.service.ts b/apps/user/src/user.service.ts index 2186617ab..6a04821a0 100644 --- a/apps/user/src/user.service.ts +++ b/apps/user/src/user.service.ts @@ -64,6 +64,9 @@ import { AddPasskeyDetailsDto } from 'apps/api-gateway/src/user/dto/add-user.dto import { URLUserResetPasswordTemplate } from '../templates/reset-password-template'; import { toNumber } from '@credebl/common/cast.helper'; import * as jwt from 'jsonwebtoken'; +import { EventPinnacle } from '../templates/event-pinnacle'; +import { EventCertificate } from '../templates/event-certificates'; +import * as QRCode from 'qrcode'; @Injectable() export class UserService { @@ -893,6 +896,7 @@ export class UserService { async shareUserCertificate(shareUserCertificate: IShareUserCertificate): Promise { + let template; const attributeArray = []; let attributeJson = {}; const attributePromises = shareUserCertificate.attributes.map(async (iterator: Attribute) => { @@ -902,8 +906,6 @@ export class UserService { attributeArray.push(attributeJson); }); await Promise.all(attributePromises); - let template; - switch (shareUserCertificate.schemaId.split(':')[2]) { case UserCertificateId.WINNER: // eslint-disable-next-line no-case-declarations @@ -925,22 +927,35 @@ export class UserService { const userWorldRecordTemplate = new WorldRecordTemplate(); template = await userWorldRecordTemplate.getWorldRecordTemplate(attributeArray); break; + case UserCertificateId.AYANWORKS_EVENT: + // eslint-disable-next-line no-case-declarations + const QRDetails = await this.getShorteningURL(shareUserCertificate, attributeArray); + + if (shareUserCertificate.attributes.some(item => item.value.toLocaleLowerCase().includes("pinnacle"))) { + const userPinnacleTemplate = new EventPinnacle(); + template = await userPinnacleTemplate.getPinnacleWinner(attributeArray, QRDetails); + } else { + const userCertificateTemplate = new EventCertificate(); + template = await userCertificateTemplate.getCertificateWinner(attributeArray, QRDetails); + } + break; default: throw new NotFoundException('error in get attributes'); } - const option: IPuppeteerOption = {height: 0, width: 1000}; + //Need to handle the option for all type of certificate + const option: IPuppeteerOption = {height: 974, width: 1606}; const imageBuffer = await this.convertHtmlToImage(template, shareUserCertificate.credentialId, option); - const verifyCode = uuidv4(); const imageUrl = await this.awsService.uploadUserCertificate( imageBuffer, 'svg', 'certificates', process.env.AWS_PUBLIC_BUCKET_NAME, - 'base64' + 'base64', + 'certificates' ); const existCredentialId = await this.userRepository.getUserCredentialsById(shareUserCertificate.credentialId); @@ -966,7 +981,7 @@ export class UserService { const browser = await puppeteer.launch({ executablePath: '/usr/bin/google-chrome', args: ['--no-sandbox', '--disable-setuid-sandbox'], - protocolTimeout: 200000, + protocolTimeout: 800000, //initial - 200000 headless: true }); @@ -980,6 +995,22 @@ export class UserService { return screenshot; } + //Need to add interface + async getShorteningURL(shareUserCertificate, attributeArray): Promise { + const urlObject = { + schemaId: shareUserCertificate.schemaId, + credDefId: shareUserCertificate.credDefId, + attribute: attributeArray, + credentialId:shareUserCertificate.credentialId, + email:attributeArray.find((attr) => "email" in attr).email + }; + + const qrCodeOptions = { type: 'image/png' }; + const encodedData = Buffer.from(JSON.stringify(shareUserCertificate)).toString('base64'); + const qrCode = await QRCode.toDataURL(`https://credebl.id/c_v?${encodedData}`, qrCodeOptions); + + return qrCode; + } /** * * @param acceptRejectInvitation diff --git a/apps/user/templates/event-certificates.ts b/apps/user/templates/event-certificates.ts new file mode 100644 index 000000000..bed44507c --- /dev/null +++ b/apps/user/templates/event-certificates.ts @@ -0,0 +1,82 @@ +import { Attribute } from '../interfaces/user.interface'; + +export class EventCertificate { + findAttributeByName(attributes: Attribute[], name: string): Attribute { + return attributes.find((attr) => name in attr); + } + + async getCertificateWinner(attributes: Attribute[], QRDetails): Promise { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [name, description, category] = await Promise.all(attributes).then((attributes) => { + const name = this.findAttributeByName(attributes, 'name').name ?? ''; + const description = this.findAttributeByName(attributes, 'description').description ?? ''; + const category = this.findAttributeByName(attributes, 'category').category ?? ''; + return [name, description, category]; + }); + return ` + + + + + + + + Document + + + +
+
+ +
+
+
+ +
+
+
+ +
+

Certificate of Appreciation

+

- ${category} -

+
+

this certificate is proudly presented to

+

${name}

+

${description}

+

~ 23rd March 2024 ~

+
+
+ QR Code +
+
+
+ +
+

Kirankalyan Kulkarni

+

CEO & Co-Founder

+
+
+
+ +
+

Ajay Jadhav

+

CTO & Co-Founder

+
+
+
+
+
+
+ + + `; + } catch { } + } +} \ No newline at end of file diff --git a/apps/user/templates/event-pinnacle.ts b/apps/user/templates/event-pinnacle.ts new file mode 100644 index 000000000..236478765 --- /dev/null +++ b/apps/user/templates/event-pinnacle.ts @@ -0,0 +1,80 @@ +import { Attribute } from '../interfaces/user.interface'; + +export class EventPinnacle { + findAttributeByName(attributes: Attribute[], name: string): Attribute { + return attributes.find((attr) => name in attr); + } + + async getPinnacleWinner(attributes: Attribute[], qrCode): Promise { + try { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [name, description] = await Promise.all(attributes).then((attributes) => { + const name = this.findAttributeByName(attributes, 'name').name ?? ''; + const description = this.findAttributeByName(attributes, 'description').description ?? ''; + return [name, description]; + }); + return ` + + + + + + + + Document + + + +
+
+ +
+
+
+ +
+ +
+ +
+
+
+ +
+

Certificate of Appreciation

+

- Pinnacle Performer -

+
+

this certificate is proudly presented to

+

${name}

+

${description}

+

~ 23rd March 2024 ~

+
+
+
+ +
+

Kirankalyan Kulkarni

+

CEO & Co-Founder

+
+
+
+ +
+

Ajay Jadhav

+

CTO & Co-Founder

+
+
+
+
+
+
+ + + `; + } catch { } + } +} \ No newline at end of file diff --git a/apps/verification/src/verification.service.ts b/apps/verification/src/verification.service.ts index 5e89ded5a..9c3b702d3 100644 --- a/apps/verification/src/verification.service.ts +++ b/apps/verification/src/verification.service.ts @@ -812,7 +812,6 @@ export class VerificationService { } }); } - // For Indy format if (getProofPresentationById?.response?.request?.indy) { const requestedAttributes = getProofPresentationById?.response?.request?.indy?.requested_attributes; diff --git a/libs/aws/src/aws.service.ts b/libs/aws/src/aws.service.ts index f9c7cb7e4..01e8b985a 100644 --- a/libs/aws/src/aws.service.ts +++ b/libs/aws/src/aws.service.ts @@ -42,14 +42,14 @@ export class AwsService { try { await putObjectAsync({ - Bucket: `${process.env.AWS_ORG_LOGO_BUCKET_NAME}`, - Key: `${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.png`, + Bucket: `${bucketName}`, + Key: `${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.${ext}`, Body: fileBuffer, ContentEncoding: encoding, ContentType: `image/png` }); - const imageUrl = `https://${process.env.AWS_ORG_LOGO_BUCKET_NAME}.s3.${process.env.AWS_PUBLIC_REGION}.amazonaws.com/${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.${ext}`; + const imageUrl = `https://${bucketName}.s3.${process.env.AWS_PUBLIC_REGION}.amazonaws.com/${pathAWS}/${encodeURIComponent(filename)}-${timestamp}.${ext}`; return imageUrl; } catch (error) { throw new HttpException(error, HttpStatus.SERVICE_UNAVAILABLE); diff --git a/libs/common/src/common.constant.ts b/libs/common/src/common.constant.ts index 9a9d8ad6e..fab631e47 100644 --- a/libs/common/src/common.constant.ts +++ b/libs/common/src/common.constant.ts @@ -38,6 +38,9 @@ export enum CommonConstants { URL_WALLET_SET_TAGGING_POLICY = '/wallet/tag-policy/#', URL_WALLET_PROVISION = '/wallet/provision', + DEFAULT_CACHE_TTL = 60000, + DEFAULT_FIELD_UPLOAD_SIZE = 10485760, + // LEDGER SERVICES URL_LEDG_GET_DID_VERKEY = '/ledger/did-verkey?did=#', URL_LEDG_REGISTER_NYM = '/ledger/register-nym?did=#&verkey=@&role=$', @@ -345,7 +348,8 @@ BATCH_SIZE = 100, MAX_CONCURRENT_OPERATIONS = 50, ISSUANCE_BATCH_SIZE = 2000, ISSUANCE_MAX_CONCURRENT_OPERATIONS = 1000, -ISSUANCE_BATCH_DELAY = 60000, //Intially 60000 +// eslint-disable-next-line @typescript-eslint/no-duplicate-enum-values +ISSUANCE_BATCH_DELAY = 60000, // MICROSERVICES NAMES diff --git a/libs/common/src/dtos/pagination.dto.ts b/libs/common/src/dtos/pagination.dto.ts index c141c961b..34995e612 100644 --- a/libs/common/src/dtos/pagination.dto.ts +++ b/libs/common/src/dtos/pagination.dto.ts @@ -23,4 +23,4 @@ export class PaginationDto { @Max(100, { message: 'Page size must be less than 100' }) pageSize: number = 10; -} +} \ No newline at end of file diff --git a/libs/common/src/interfaces/issuance.interface.ts b/libs/common/src/interfaces/issuance.interface.ts index ea8192510..593e0d1d8 100644 --- a/libs/common/src/interfaces/issuance.interface.ts +++ b/libs/common/src/interfaces/issuance.interface.ts @@ -112,4 +112,18 @@ export interface IIssuedCredential { credential?: ICredential; options?: IOptions; } - \ No newline at end of file + + export interface ISchemaObject { + '$schema': string; + '$id': string; + type: string; + required: string[]; + properties: { + [key: string]: object; + }; + definitions: { + [key: string]: object; + }; + title: string; + description: string; + } \ No newline at end of file diff --git a/libs/common/src/interfaces/schema.interface.ts b/libs/common/src/interfaces/schema.interface.ts index 68372ae15..0da8565f3 100644 --- a/libs/common/src/interfaces/schema.interface.ts +++ b/libs/common/src/interfaces/schema.interface.ts @@ -111,4 +111,4 @@ export interface ISchemasWithPagination extends IPaginationDetails{ title: string; type: string; } - \ No newline at end of file + diff --git a/libs/common/src/response-messages/index.ts b/libs/common/src/response-messages/index.ts index a2b044dcd..189590adb 100644 --- a/libs/common/src/response-messages/index.ts +++ b/libs/common/src/response-messages/index.ts @@ -554,3 +554,4 @@ export const ResponseMessages = { } } }; + diff --git a/libs/enum/src/enum.ts b/libs/enum/src/enum.ts index 0361694e9..ca8569ea2 100644 --- a/libs/enum/src/enum.ts +++ b/libs/enum/src/enum.ts @@ -100,11 +100,13 @@ export enum AgentSpinUpStatus { COMPLETED = 2 } + export enum UserCertificateId { - WINNER = 'Winner', - PARTICIPANT = 'Participant', - ARBITER = 'Arbiter', - WORLD_RECORD = 'WorldRecord' + WINNER = 'Winner', + PARTICIPANT = 'Participant', + ARBITER = 'Arbiter', + WORLD_RECORD = 'WorldRecord', + AYANWORKS_EVENT ='Appreciation Certificate' } export enum NodeEnvironment { @@ -256,4 +258,4 @@ export enum UserRole { export enum ProofType { POLYGON_PROOFTYPE = 'EcdsaSecp256k1Signature2019', NO_LEDGER_PROOFTYPE = 'Ed25519Signature2018' -} \ No newline at end of file +} diff --git a/libs/prisma-service/prisma/seed.ts b/libs/prisma-service/prisma/seed.ts index 2267f5fe1..a9910c101 100644 --- a/libs/prisma-service/prisma/seed.ts +++ b/libs/prisma-service/prisma/seed.ts @@ -409,9 +409,13 @@ const migrateOrgAgentDids = async (): Promise => { } }); + const filteredOrgAgents = orgAgents.filter( + (agent) => null !== agent.orgDid && '' !== agent.orgDid + ); + // If there are org DIDs that do not exist in org_dids table if (orgDids.length !== existingDids.length) { - const newOrgAgents = orgAgents.filter( + const newOrgAgents = filteredOrgAgents.filter( (agent) => !existingDids.some((did) => did.did === agent.orgDid) ); diff --git a/taskdef/agent-provisioning-taskdef.json b/scripts/taskdef/agent-provisioning-taskdef.json similarity index 93% rename from taskdef/agent-provisioning-taskdef.json rename to scripts/taskdef/agent-provisioning-taskdef.json index a96542327..292b15c74 100644 --- a/taskdef/agent-provisioning-taskdef.json +++ b/scripts/taskdef/agent-provisioning-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_AGENT-PROVISIONING_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "agent_provisioning", @@ -33,7 +33,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_AGENT-PROVISIONING_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/agent-service-taskdef.json b/scripts/taskdef/agent-service-taskdef.json similarity index 90% rename from taskdef/agent-service-taskdef.json rename to scripts/taskdef/agent-service-taskdef.json index 6f334aa4b..0fb698780 100644 --- a/taskdef/agent-service-taskdef.json +++ b/scripts/taskdef/agent-service-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_AGENT_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "agent", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_AGENT_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" } diff --git a/taskdef/api-gateway-taskdef.json b/scripts/taskdef/api-gateway-taskdef.json similarity index 93% rename from taskdef/api-gateway-taskdef.json rename to scripts/taskdef/api-gateway-taskdef.json index b32ae3605..34435749e 100644 --- a/taskdef/api-gateway-taskdef.json +++ b/scripts/taskdef/api-gateway-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_API-GATEWAY_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "api_gateway", @@ -34,7 +34,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_API-GATEWAY_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/connection-taskdef.json b/scripts/taskdef/connection-taskdef.json similarity index 89% rename from taskdef/connection-taskdef.json rename to scripts/taskdef/connection-taskdef.json index 228efd128..452d8fcff 100644 --- a/taskdef/connection-taskdef.json +++ b/scripts/taskdef/connection-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_CONNECTION_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "connection", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_CONNECTION_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/ecosystem-taskdef.json b/scripts/taskdef/ecosystem-taskdef.json similarity index 89% rename from taskdef/ecosystem-taskdef.json rename to scripts/taskdef/ecosystem-taskdef.json index ec8c9c853..a44912426 100644 --- a/taskdef/ecosystem-taskdef.json +++ b/scripts/taskdef/ecosystem-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_ECOSYSTEM_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "ecosystem", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_ECOSYSTEM_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/issuance-service-taskdef.json b/scripts/taskdef/issuance-service-taskdef.json similarity index 92% rename from taskdef/issuance-service-taskdef.json rename to scripts/taskdef/issuance-service-taskdef.json index 73414c4df..8d4832f22 100644 --- a/taskdef/issuance-service-taskdef.json +++ b/scripts/taskdef/issuance-service-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_ISSUANCE_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "issuance", @@ -28,7 +28,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_ISSUANCE_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/ledger-taskdef.json b/scripts/taskdef/ledger-taskdef.json similarity index 89% rename from taskdef/ledger-taskdef.json rename to scripts/taskdef/ledger-taskdef.json index aa090642f..23c9950a7 100644 --- a/taskdef/ledger-taskdef.json +++ b/scripts/taskdef/ledger-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_LEDGER_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "ledger", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_LEDGER_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/notification-taskdef.json b/scripts/taskdef/notification-taskdef.json similarity index 89% rename from taskdef/notification-taskdef.json rename to scripts/taskdef/notification-taskdef.json index 3c378b619..3ab1d2157 100644 --- a/taskdef/notification-taskdef.json +++ b/scripts/taskdef/notification-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_NOTIFICATION_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "notification", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_NOTIFICATION_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" } diff --git a/taskdef/organization-taskdef.json b/scripts/taskdef/organization-taskdef.json similarity index 88% rename from taskdef/organization-taskdef.json rename to scripts/taskdef/organization-taskdef.json index 70ae500d5..1738b09da 100644 --- a/taskdef/organization-taskdef.json +++ b/scripts/taskdef/organization-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_ORGANIZATION_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "organization", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_ORGANIZATION_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/user-taskdef.json b/scripts/taskdef/user-taskdef.json similarity index 89% rename from taskdef/user-taskdef.json rename to scripts/taskdef/user-taskdef.json index 61d9a3b23..bf291d698 100644 --- a/taskdef/user-taskdef.json +++ b/scripts/taskdef/user-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_USER_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "user", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_USER_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/utility-taskdef.json b/scripts/taskdef/utility-taskdef.json similarity index 89% rename from taskdef/utility-taskdef.json rename to scripts/taskdef/utility-taskdef.json index d8d640368..240cdb1a5 100644 --- a/taskdef/utility-taskdef.json +++ b/scripts/taskdef/utility-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_UTILITY_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "utility", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_UTILITY_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/verfication-taskdef.json b/scripts/taskdef/verfication-taskdef.json similarity index 88% rename from taskdef/verfication-taskdef.json rename to scripts/taskdef/verfication-taskdef.json index 2c7608541..e9aedf8cd 100644 --- a/taskdef/verfication-taskdef.json +++ b/scripts/taskdef/verfication-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_VERIFICATION_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "verification", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_VERIFICATION_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" }, diff --git a/taskdef/webhook-taskdef.json b/scripts/taskdef/webhook-taskdef.json similarity index 89% rename from taskdef/webhook-taskdef.json rename to scripts/taskdef/webhook-taskdef.json index ef536d63e..f831f8de3 100644 --- a/taskdef/webhook-taskdef.json +++ b/scripts/taskdef/webhook-taskdef.json @@ -1,5 +1,5 @@ { - "family": "DEV_WEBHOOK_SERVICE_TASKDEFINITION", + "family": "${FAMILY}", "containerDefinitions": [ { "name": "webhook", @@ -22,7 +22,7 @@ "logDriver": "awslogs", "options": { "awslogs-create-group": "true", - "awslogs-group": "/ecs/DEV_WEBHOOK_SERVICE_TASKDEFINITION", + "awslogs-group": "/ecs/${FAMILY}", "awslogs-region": "${AWS_REGION}", "awslogs-stream-prefix": "ecs" },