Update OSIRIS engine with signatory access control and Freezone examples
This commit is contained in:
360
examples/freezone/freezone copy 2.rhai
Normal file
360
examples/freezone/freezone copy 2.rhai
Normal file
@@ -0,0 +1,360 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
flow = registration_flow();
|
||||
|
||||
public_key_registration_step = step.new()
|
||||
.title("Public Key Registration")
|
||||
.description("Register your public key")
|
||||
.add_action("Register");
|
||||
|
||||
|
||||
public_key_registration_step.complete()
|
||||
|
||||
public_key =
|
||||
print("Public key <>registered.");
|
||||
print("Now user needs to submit email");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public_key_registration_step.continue()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
user_profile_creation_step = user_profile_creation();
|
||||
flow.add_step(user_profile_creation_step);
|
||||
|
||||
step = email_verification();
|
||||
flow.add_step(step);
|
||||
|
||||
step = terms_and_conditions();
|
||||
flow.add_step(step);
|
||||
|
||||
step = crypto_wallet_creation();
|
||||
flow.add_step(payment_processing());
|
||||
flow.add_step(kyc_verification());
|
||||
|
||||
flow.execute();
|
||||
|
||||
print("Step 1: Public Key Registration");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// User (Timur) provides their public key
|
||||
print("User public key received: " + timur_pubkey);
|
||||
print("✓ Public key validated and stored\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 2: User Profile Creation & Email Verification
|
||||
// ============================================================================
|
||||
|
||||
print("Step 2: User Profile Creation & Email Verification");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Collect basic user information
|
||||
let user_name = "Timur Gordon";
|
||||
let user_email = "timur@freezone.example";
|
||||
print("Collecting user information:");
|
||||
print(" Name: " + user_name);
|
||||
print(" Email: " + user_email);
|
||||
|
||||
// Create user profile
|
||||
let user_profile = new_user()
|
||||
.username(user_name)
|
||||
.pubkey(timur_pubkey)
|
||||
.add_email(user_email);
|
||||
|
||||
print("✓ User profile created");
|
||||
freezone_ctx.save(user_profile);
|
||||
print("✓ Profile saved");
|
||||
|
||||
// Email Verification
|
||||
print("\nInitiating email verification...");
|
||||
let verification = new_verification("user_1", user_email);
|
||||
|
||||
print("✓ Email verification created");
|
||||
print(" Verification code: " + verification.get_code());
|
||||
print(" Nonce: " + verification.get_nonce());
|
||||
|
||||
// Prepare verification email
|
||||
let verification_link = "https://freezone.example/verify?nonce=" + verification.get_nonce();
|
||||
|
||||
// Create verification mail with template parameters
|
||||
let verification_mail = new_mail()
|
||||
.to(user_email)
|
||||
.template(verification_mail_template.get_id())
|
||||
.parameter("url", verification_link)
|
||||
.parameter("code", verification.get_code());
|
||||
|
||||
print("✓ Verification email prepared");
|
||||
print(" To: " + user_email);
|
||||
print(" Template: " + verification_mail_template.get_id());
|
||||
print(" Link: " + verification_link);
|
||||
print(" Code: " + verification.get_code());
|
||||
|
||||
// Send verification email using template
|
||||
// Note: In production, configure real SMTP credentials
|
||||
// For now, we'll simulate sending (actual SMTP would fail with example.com)
|
||||
print("✓ Verification email would be sent to: " + user_email);
|
||||
print(" (Skipping actual SMTP send - configure real server in production)");
|
||||
|
||||
// Simulate user clicking verification link and verifying
|
||||
print("\n✓ User clicks verification link and verifies email");
|
||||
verification.verify_nonce(verification.get_nonce());
|
||||
print("✓ Email verified: " + verification.get_status());
|
||||
|
||||
freezone_ctx.save(verification);
|
||||
print("✓ Verification saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 3: Terms & Conditions Signing
|
||||
// ============================================================================
|
||||
|
||||
print("Step 3: Terms & Conditions Signing");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Create Terms & Conditions contract
|
||||
let terms_contract = new_contract(1)
|
||||
.title("Freezone Membership Terms & Conditions")
|
||||
.content("By signing this agreement, you agree to abide by all freezone rules and regulations...")
|
||||
.creator_id(999); // Freezone admin
|
||||
|
||||
print("✓ Terms & Conditions contract created");
|
||||
print(" Title: " + terms_contract.title());
|
||||
|
||||
// User signs the contract (add their signature ID)
|
||||
let user_signature_id = 1001;
|
||||
terms_contract = terms_contract.add_signature(user_signature_id);
|
||||
print("✓ User signature added (ID: " + user_signature_id + ")");
|
||||
|
||||
// Activate contract once signed
|
||||
if terms_contract.is_fully_signed(1) {
|
||||
terms_contract = terms_contract.activate();
|
||||
print("✓ Contract activated: " + terms_contract.status());
|
||||
}
|
||||
|
||||
freezone_ctx.save(terms_contract);
|
||||
print("✓ Signed contract saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 4: Crypto Wallet Creation
|
||||
// ============================================================================
|
||||
|
||||
print("Step 4: Crypto Wallet Creation");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Create TFT crypto account for user
|
||||
let tft_account = new_account()
|
||||
.owner_id(1)
|
||||
.currency("TFT") // ThreeFold Token
|
||||
.balance(0.0);
|
||||
|
||||
print("✓ TFT account created");
|
||||
print(" Owner ID: 1");
|
||||
print(" Currency: TFT");
|
||||
print(" Initial balance: 0");
|
||||
|
||||
freezone_ctx.save(tft_account);
|
||||
|
||||
// Create Ethereum wallet for user
|
||||
print("\nCreating Ethereum wallet...");
|
||||
let eth_wallet = new_ethereum_wallet()
|
||||
.owner_id(1)
|
||||
.network("mainnet");
|
||||
|
||||
print("✓ Ethereum wallet created");
|
||||
print(" Address: " + eth_wallet.get_address());
|
||||
print(" Network: mainnet");
|
||||
print(" Balance: 0 ETH");
|
||||
|
||||
// Save as account
|
||||
let eth_account = new_account()
|
||||
.owner_id(1)
|
||||
.address(eth_wallet.get_address())
|
||||
.currency("ETH")
|
||||
.balance(0.0);
|
||||
|
||||
freezone_ctx.save(eth_account);
|
||||
print("✓ Ethereum account saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 5: Payment Processing
|
||||
// ============================================================================
|
||||
|
||||
print("Step 5: Payment Processing");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
print("Using configured Pesapal payment client...");
|
||||
|
||||
// Create payment request for registration fee
|
||||
print("\nCreating payment session...");
|
||||
let payment_request = new_payment_request()
|
||||
.amount(100.0)
|
||||
.currency("USD")
|
||||
.description("Freezone Registration Fee")
|
||||
.callback_url("https://freezone.example/payment/callback")
|
||||
.merchant_reference("REG_USER_1_" + timestamp());
|
||||
|
||||
print("✓ Payment request created");
|
||||
print(" Amount: $100 USD");
|
||||
print(" Description: Freezone Registration Fee");
|
||||
|
||||
// Initiate payment with Pesapal - creates real payment link
|
||||
print("\nInitiating payment session with Pesapal...");
|
||||
let payment_response = freezone_payment_client.create_payment_link(payment_request);
|
||||
|
||||
let payment_url = payment_response.get_payment_url();
|
||||
let order_tracking_id = payment_response.get_order_tracking_id();
|
||||
|
||||
print("✓ Payment session created");
|
||||
print(" Payment URL: " + payment_url);
|
||||
print(" Order Tracking ID: " + order_tracking_id);
|
||||
print(" (User would be redirected to Pesapal payment page)");
|
||||
|
||||
// In production, you would:
|
||||
// 1. Redirect user to payment_url
|
||||
// 2. User completes payment on Pesapal
|
||||
// 3. Pesapal calls your callback_url
|
||||
// 4. You verify payment status with get_payment_status(order_tracking_id)
|
||||
|
||||
// For demo purposes, check payment status
|
||||
print("\nChecking payment status...");
|
||||
let payment_status = freezone_payment_client.get_payment_status(order_tracking_id);
|
||||
|
||||
print("✓ Payment status retrieved");
|
||||
print(" Status: " + payment_status.get_payment_status_description());
|
||||
print(" Amount: " + payment_status.get_amount() + " " + payment_status.get_currency());
|
||||
print(" Transaction ID: " + order_tracking_id);
|
||||
|
||||
// Create payment transaction record
|
||||
let payment_tx = new_transaction()
|
||||
.source(0) // External payment
|
||||
.destination(1) // Freezone account
|
||||
.amount(100.0)
|
||||
.assetid(1);
|
||||
|
||||
print("✓ Payment transaction recorded");
|
||||
|
||||
freezone_ctx.save(payment_tx);
|
||||
print("✓ Transaction saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 6: KYC Verification
|
||||
// ============================================================================
|
||||
|
||||
print("Step 6: KYC Verification");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Pre-fill KYC form with already collected info (first name, last name)
|
||||
// User will fill in the rest at Idenfy (DOB, address, nationality, etc.)
|
||||
print("\nPreparing KYC session with pre-filled data...");
|
||||
let kyc_info = new_kyc_info()
|
||||
.client_id("user_1")
|
||||
.first_name("Timur") // From user profile
|
||||
.last_name("Gordon") // From user profile
|
||||
.email(user_email); // From user profile
|
||||
|
||||
print("✓ Pre-fill data prepared");
|
||||
print(" Name: Timur Gordon (pre-filled)");
|
||||
print(" Email: " + user_email + " (pre-filled)");
|
||||
print(" User will provide: DOB, address, nationality, ID document");
|
||||
|
||||
// Create KYC session
|
||||
let kyc_session = new_kyc_session("user_1", "idenfy")
|
||||
.callback_url("https://freezone.example/kyc/callback")
|
||||
.success_url("https://freezone.example/kyc/success")
|
||||
.error_url("https://freezone.example/kyc/error")
|
||||
.locale("en");
|
||||
|
||||
print("✓ KYC session created");
|
||||
print(" Client ID: " + kyc_session.get_client_id());
|
||||
print(" Provider: " + kyc_session.get_provider());
|
||||
|
||||
// Create verification session with Idenfy - generates real verification URL
|
||||
print("\nCreating Idenfy verification session...");
|
||||
let verification_url = freezone_kyc_client.create_verification_session(kyc_info, kyc_session);
|
||||
|
||||
print("✓ Idenfy verification session created");
|
||||
print(" Verification URL: " + verification_url);
|
||||
print(" (User redirected to Idenfy to complete verification)");
|
||||
|
||||
// Production flow:
|
||||
// 1. Redirect user to verification_url
|
||||
// 2. User fills in remaining info (DOB, address, nationality)
|
||||
// 3. User uploads ID document (Passport/ID/Driver's License)
|
||||
// 4. User takes selfie for liveness check
|
||||
// 5. Idenfy performs automated verification
|
||||
// 6. Idenfy calls callback_url with VERIFIED data from ID document
|
||||
// 7. Callback handler stores verified KYC info
|
||||
|
||||
print("\n✓ User completes verification at Idenfy:");
|
||||
print(" - Fills in DOB, address, nationality");
|
||||
print(" - Uploads identity document");
|
||||
print(" - Takes selfie for liveness check");
|
||||
print(" - Idenfy extracts and verifies data from ID");
|
||||
|
||||
print("\n✓ Idenfy callback will provide VERIFIED data:");
|
||||
print(" - All personal info extracted from ID document");
|
||||
print(" - Document number, issue date, expiry date");
|
||||
print(" - Verification status (APPROVED/DENIED)");
|
||||
print(" - Liveness check result");
|
||||
|
||||
// For demo purposes, simulate what callback would receive
|
||||
print("\nSimulating callback data (in production, this comes from Idenfy)...");
|
||||
let kyc_info_verified = new_kyc_info()
|
||||
.client_id("user_1")
|
||||
.first_name("Timur") // Verified from ID
|
||||
.last_name("Gordon") // Verified from ID
|
||||
.email(user_email)
|
||||
.date_of_birth("1990-05-15") // Extracted from ID
|
||||
.nationality("US") // Extracted from ID
|
||||
.document_type("passport") // From verification
|
||||
.document_number("P123456789") // Extracted from ID
|
||||
.provider("idenfy")
|
||||
.verified(true); // Only if status == "APPROVED"
|
||||
|
||||
freezone_ctx.save(kyc_info_verified);
|
||||
freezone_ctx.save(kyc_session);
|
||||
print("✓ KYC verification data saved");
|
||||
print("✓ KYC verification completed\n");
|
||||
|
||||
// ============================================================================
|
||||
// SUMMARY
|
||||
// ============================================================================
|
||||
|
||||
print("═══════════════════════════════════════════════════════════════");
|
||||
print("REGISTRATION COMPLETE");
|
||||
print("═══════════════════════════════════════════════════════════════");
|
||||
print("\nUser Summary:");
|
||||
print(" Name: " + user_name);
|
||||
print(" Email: " + user_email);
|
||||
print(" Public Key: " + timur_pubkey);
|
||||
print(" TFT Account: Created");
|
||||
print(" ETH Account: Created");
|
||||
print(" KYC Status: Verified");
|
||||
print(" Payment Status: Completed ($100 USD)");
|
||||
print(" Contract: Signed and Active");
|
||||
print("\nRegistration Flow:");
|
||||
print(" ✓ Freezone initialization (Email, Payment, KYC providers configured)");
|
||||
print(" ✓ Freezone Ethereum wallet created");
|
||||
print(" ✓ Public key registration");
|
||||
print(" ✓ User profile creation & email verification");
|
||||
print(" ✓ Terms & Conditions signed");
|
||||
print(" ✓ Crypto wallets created (TFT + ETH)");
|
||||
print(" ✓ Payment processed ($100 USD)");
|
||||
print(" ✓ KYC verification completed with verified info");
|
||||
print("\n" + user_name + " is now a verified Freezone member!");
|
||||
print("═══════════════════════════════════════════════════════════════\n");
|
||||
370
examples/freezone/freezone copy.rhai
Normal file
370
examples/freezone/freezone copy.rhai
Normal file
@@ -0,0 +1,370 @@
|
||||
registration_flow = flow.new();
|
||||
|
||||
public_key_registration_step = step.new()
|
||||
.title("Public Key Registration")
|
||||
.description("Register your public key")
|
||||
.add_action("Register");
|
||||
|
||||
flow_id = registration_flow.start()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public_key_registration_step.complete()
|
||||
|
||||
public_key =
|
||||
print("Public key <>registered.");
|
||||
print("Now user needs to submit email");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public_key_registration_step.continue()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
user_profile_creation_step = user_profile_creation();
|
||||
flow.add_step(user_profile_creation_step);
|
||||
|
||||
step = email_verification();
|
||||
flow.add_step(step);
|
||||
|
||||
step = terms_and_conditions();
|
||||
flow.add_step(step);
|
||||
|
||||
step = crypto_wallet_creation();
|
||||
flow.add_step(payment_processing());
|
||||
flow.add_step(kyc_verification());
|
||||
|
||||
flow.execute();
|
||||
|
||||
print("Step 1: Public Key Registration");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// User (Timur) provides their public key
|
||||
print("User public key received: " + timur_pubkey);
|
||||
print("✓ Public key validated and stored\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 2: User Profile Creation & Email Verification
|
||||
// ============================================================================
|
||||
|
||||
print("Step 2: User Profile Creation & Email Verification");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Collect basic user information
|
||||
let user_name = "Timur Gordon";
|
||||
let user_email = "timur@freezone.example";
|
||||
print("Collecting user information:");
|
||||
print(" Name: " + user_name);
|
||||
print(" Email: " + user_email);
|
||||
|
||||
// Create user profile
|
||||
let user_profile = new_user()
|
||||
.username(user_name)
|
||||
.pubkey(timur_pubkey)
|
||||
.add_email(user_email);
|
||||
|
||||
print("✓ User profile created");
|
||||
freezone_ctx.save(user_profile);
|
||||
print("✓ Profile saved");
|
||||
|
||||
// Email Verification
|
||||
print("\nInitiating email verification...");
|
||||
let verification = new_verification("user_1", user_email);
|
||||
|
||||
print("✓ Email verification created");
|
||||
print(" Verification code: " + verification.get_code());
|
||||
print(" Nonce: " + verification.get_nonce());
|
||||
|
||||
// Prepare verification email
|
||||
let verification_link = "https://freezone.example/verify?nonce=" + verification.get_nonce();
|
||||
|
||||
// Create verification mail with template parameters
|
||||
let verification_mail = new_mail()
|
||||
.to(user_email)
|
||||
.template(verification_mail_template.get_id())
|
||||
.parameter("url", verification_link)
|
||||
.parameter("code", verification.get_code());
|
||||
|
||||
print("✓ Verification email prepared");
|
||||
print(" To: " + user_email);
|
||||
print(" Template: " + verification_mail_template.get_id());
|
||||
print(" Link: " + verification_link);
|
||||
print(" Code: " + verification.get_code());
|
||||
|
||||
// Send verification email using template
|
||||
// Note: In production, configure real SMTP credentials
|
||||
// For now, we'll simulate sending (actual SMTP would fail with example.com)
|
||||
print("✓ Verification email would be sent to: " + user_email);
|
||||
print(" (Skipping actual SMTP send - configure real server in production)");
|
||||
|
||||
// Simulate user clicking verification link and verifying
|
||||
print("\n✓ User clicks verification link and verifies email");
|
||||
verification.verify_nonce(verification.get_nonce());
|
||||
print("✓ Email verified: " + verification.get_status());
|
||||
|
||||
freezone_ctx.save(verification);
|
||||
print("✓ Verification saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 3: Terms & Conditions Signing
|
||||
// ============================================================================
|
||||
|
||||
print("Step 3: Terms & Conditions Signing");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Create Terms & Conditions contract
|
||||
let terms_contract = new_contract(1)
|
||||
.title("Freezone Membership Terms & Conditions")
|
||||
.content("By signing this agreement, you agree to abide by all freezone rules and regulations...")
|
||||
.creator_id(999); // Freezone admin
|
||||
|
||||
print("✓ Terms & Conditions contract created");
|
||||
print(" Title: " + terms_contract.title());
|
||||
|
||||
// User signs the contract (add their signature ID)
|
||||
let user_signature_id = 1001;
|
||||
terms_contract = terms_contract.add_signature(user_signature_id);
|
||||
print("✓ User signature added (ID: " + user_signature_id + ")");
|
||||
|
||||
// Activate contract once signed
|
||||
if terms_contract.is_fully_signed(1) {
|
||||
terms_contract = terms_contract.activate();
|
||||
print("✓ Contract activated: " + terms_contract.status());
|
||||
}
|
||||
|
||||
freezone_ctx.save(terms_contract);
|
||||
print("✓ Signed contract saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 4: Crypto Wallet Creation
|
||||
// ============================================================================
|
||||
|
||||
print("Step 4: Crypto Wallet Creation");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Create TFT crypto account for user
|
||||
let tft_account = new_account()
|
||||
.owner_id(1)
|
||||
.currency("TFT") // ThreeFold Token
|
||||
.balance(0.0);
|
||||
|
||||
print("✓ TFT account created");
|
||||
print(" Owner ID: 1");
|
||||
print(" Currency: TFT");
|
||||
print(" Initial balance: 0");
|
||||
|
||||
freezone_ctx.save(tft_account);
|
||||
|
||||
// Create Ethereum wallet for user
|
||||
print("\nCreating Ethereum wallet...");
|
||||
let eth_wallet = new_ethereum_wallet()
|
||||
.owner_id(1)
|
||||
.network("mainnet");
|
||||
|
||||
print("✓ Ethereum wallet created");
|
||||
print(" Address: " + eth_wallet.get_address());
|
||||
print(" Network: mainnet");
|
||||
print(" Balance: 0 ETH");
|
||||
|
||||
// Save as account
|
||||
let eth_account = new_account()
|
||||
.owner_id(1)
|
||||
.address(eth_wallet.get_address())
|
||||
.currency("ETH")
|
||||
.balance(0.0);
|
||||
|
||||
freezone_ctx.save(eth_account);
|
||||
print("✓ Ethereum account saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 5: Payment Processing
|
||||
// ============================================================================
|
||||
|
||||
print("Step 5: Payment Processing");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
print("Using configured Pesapal payment client...");
|
||||
|
||||
// Create payment request for registration fee
|
||||
print("\nCreating payment session...");
|
||||
let payment_request = new_payment_request()
|
||||
.amount(100.0)
|
||||
.currency("USD")
|
||||
.description("Freezone Registration Fee")
|
||||
.callback_url("https://freezone.example/payment/callback")
|
||||
.merchant_reference("REG_USER_1_" + timestamp());
|
||||
|
||||
print("✓ Payment request created");
|
||||
print(" Amount: $100 USD");
|
||||
print(" Description: Freezone Registration Fee");
|
||||
|
||||
// Initiate payment with Pesapal - creates real payment link
|
||||
print("\nInitiating payment session with Pesapal...");
|
||||
let payment_response = freezone_payment_client.create_payment_link(payment_request);
|
||||
|
||||
let payment_url = payment_response.get_payment_url();
|
||||
let order_tracking_id = payment_response.get_order_tracking_id();
|
||||
|
||||
print("✓ Payment session created");
|
||||
print(" Payment URL: " + payment_url);
|
||||
print(" Order Tracking ID: " + order_tracking_id);
|
||||
print(" (User would be redirected to Pesapal payment page)");
|
||||
|
||||
// In production, you would:
|
||||
// 1. Redirect user to payment_url
|
||||
// 2. User completes payment on Pesapal
|
||||
// 3. Pesapal calls your callback_url
|
||||
// 4. You verify payment status with get_payment_status(order_tracking_id)
|
||||
|
||||
// For demo purposes, check payment status
|
||||
print("\nChecking payment status...");
|
||||
let payment_status = freezone_payment_client.get_payment_status(order_tracking_id);
|
||||
|
||||
print("✓ Payment status retrieved");
|
||||
print(" Status: " + payment_status.get_payment_status_description());
|
||||
print(" Amount: " + payment_status.get_amount() + " " + payment_status.get_currency());
|
||||
print(" Transaction ID: " + order_tracking_id);
|
||||
|
||||
// Create payment transaction record
|
||||
let payment_tx = new_transaction()
|
||||
.source(0) // External payment
|
||||
.destination(1) // Freezone account
|
||||
.amount(100.0)
|
||||
.assetid(1);
|
||||
|
||||
print("✓ Payment transaction recorded");
|
||||
|
||||
freezone_ctx.save(payment_tx);
|
||||
print("✓ Transaction saved\n");
|
||||
|
||||
// ============================================================================
|
||||
// STEP 6: KYC Verification
|
||||
// ============================================================================
|
||||
|
||||
print("Step 6: KYC Verification");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Pre-fill KYC form with already collected info (first name, last name)
|
||||
// User will fill in the rest at Idenfy (DOB, address, nationality, etc.)
|
||||
print("\nPreparing KYC session with pre-filled data...");
|
||||
let kyc_info = new_kyc_info()
|
||||
.client_id("user_1")
|
||||
.first_name("Timur") // From user profile
|
||||
.last_name("Gordon") // From user profile
|
||||
.email(user_email); // From user profile
|
||||
|
||||
print("✓ Pre-fill data prepared");
|
||||
print(" Name: Timur Gordon (pre-filled)");
|
||||
print(" Email: " + user_email + " (pre-filled)");
|
||||
print(" User will provide: DOB, address, nationality, ID document");
|
||||
|
||||
// Create KYC session
|
||||
let kyc_session = new_kyc_session("user_1", "idenfy")
|
||||
.callback_url("https://freezone.example/kyc/callback")
|
||||
.success_url("https://freezone.example/kyc/success")
|
||||
.error_url("https://freezone.example/kyc/error")
|
||||
.locale("en");
|
||||
|
||||
print("✓ KYC session created");
|
||||
print(" Client ID: " + kyc_session.get_client_id());
|
||||
print(" Provider: " + kyc_session.get_provider());
|
||||
|
||||
// Create verification session with Idenfy - generates real verification URL
|
||||
print("\nCreating Idenfy verification session...");
|
||||
let verification_url = freezone_kyc_client.create_verification_session(kyc_info, kyc_session);
|
||||
|
||||
print("✓ Idenfy verification session created");
|
||||
print(" Verification URL: " + verification_url);
|
||||
print(" (User redirected to Idenfy to complete verification)");
|
||||
|
||||
// Production flow:
|
||||
// 1. Redirect user to verification_url
|
||||
// 2. User fills in remaining info (DOB, address, nationality)
|
||||
// 3. User uploads ID document (Passport/ID/Driver's License)
|
||||
// 4. User takes selfie for liveness check
|
||||
// 5. Idenfy performs automated verification
|
||||
// 6. Idenfy calls callback_url with VERIFIED data from ID document
|
||||
// 7. Callback handler stores verified KYC info
|
||||
|
||||
print("\n✓ User completes verification at Idenfy:");
|
||||
print(" - Fills in DOB, address, nationality");
|
||||
print(" - Uploads identity document");
|
||||
print(" - Takes selfie for liveness check");
|
||||
print(" - Idenfy extracts and verifies data from ID");
|
||||
|
||||
print("\n✓ Idenfy callback will provide VERIFIED data:");
|
||||
print(" - All personal info extracted from ID document");
|
||||
print(" - Document number, issue date, expiry date");
|
||||
print(" - Verification status (APPROVED/DENIED)");
|
||||
print(" - Liveness check result");
|
||||
|
||||
// For demo purposes, simulate what callback would receive
|
||||
print("\nSimulating callback data (in production, this comes from Idenfy)...");
|
||||
let kyc_info_verified = new_kyc_info()
|
||||
.client_id("user_1")
|
||||
.first_name("Timur") // Verified from ID
|
||||
.last_name("Gordon") // Verified from ID
|
||||
.email(user_email)
|
||||
.date_of_birth("1990-05-15") // Extracted from ID
|
||||
.nationality("US") // Extracted from ID
|
||||
.document_type("passport") // From verification
|
||||
.document_number("P123456789") // Extracted from ID
|
||||
.provider("idenfy")
|
||||
.verified(true); // Only if status == "APPROVED"
|
||||
|
||||
freezone_ctx.save(kyc_info_verified);
|
||||
freezone_ctx.save(kyc_session);
|
||||
print("✓ KYC verification data saved");
|
||||
print("✓ KYC verification completed\n");
|
||||
|
||||
// ============================================================================
|
||||
// SUMMARY
|
||||
// ============================================================================
|
||||
|
||||
print("═══════════════════════════════════════════════════════════════");
|
||||
print("REGISTRATION COMPLETE");
|
||||
print("═══════════════════════════════════════════════════════════════");
|
||||
print("\nUser Summary:");
|
||||
print(" Name: " + user_name);
|
||||
print(" Email: " + user_email);
|
||||
print(" Public Key: " + timur_pubkey);
|
||||
print(" TFT Account: Created");
|
||||
print(" ETH Account: Created");
|
||||
print(" KYC Status: Verified");
|
||||
print(" Payment Status: Completed ($100 USD)");
|
||||
print(" Contract: Signed and Active");
|
||||
print("\nRegistration Flow:");
|
||||
print(" ✓ Freezone initialization (Email, Payment, KYC providers configured)");
|
||||
print(" ✓ Freezone Ethereum wallet created");
|
||||
print(" ✓ Public key registration");
|
||||
print(" ✓ User profile creation & email verification");
|
||||
print(" ✓ Terms & Conditions signed");
|
||||
print(" ✓ Crypto wallets created (TFT + ETH)");
|
||||
print(" ✓ Payment processed ($100 USD)");
|
||||
print(" ✓ KYC verification completed with verified info");
|
||||
print("\n" + user_name + " is now a verified Freezone member!");
|
||||
print("═══════════════════════════════════════════════════════════════\n");
|
||||
@@ -15,11 +15,7 @@ print("=== FREEZONE REGISTRATION FLOW ===\n");
|
||||
// ============================================================================
|
||||
// KEYPAIRS AND IDENTITIES
|
||||
// ============================================================================
|
||||
|
||||
// Freezone Organization (Keypair 1)
|
||||
let freezone_pubkey = "04d0aea7f0a48bcab4389753ddc2e61623dd89d800652b11d0a383eb3ea74561d730bdd06e0ca8f4cd4013907d95782a0a584313e1d91ae5ad09b663de36bfac44";
|
||||
|
||||
// User: Timur (Keypair 2)
|
||||
let freezone_pubkey = "04e58314c13ea3f9caed882001a5090797b12563d5f9bbd7f16efe020e060c780b446862311501e2e9653416527d2634ff8a8050ff3a085baccd7ddcb94185ff56";
|
||||
let timur_pubkey = "04090636d0a15854c4c0b73f65b6de5f6a27a7b22d6fbf5f6d97c45476a0384fe50781444c33f5af577e017599e4b432373fbcdcd844d8783c5e52240a14b63dc3";
|
||||
|
||||
print("Identities:");
|
||||
@@ -40,35 +36,77 @@ print("✓ Freezone context created");
|
||||
print(" Context ID: " + freezone_ctx.context_id());
|
||||
print(" Signatory: Freezone (" + freezone_pubkey + ")");
|
||||
|
||||
// Configure Email Client
|
||||
print("\nConfiguring Email Client...");
|
||||
// Configure email client for sending verification emails
|
||||
// Common SMTP providers:
|
||||
// - Gmail: smtp.gmail.com:587 (requires app password)
|
||||
// - Outlook: smtp-mail.outlook.com:587
|
||||
// - SendGrid: smtp.sendgrid.net:587
|
||||
// - Mailgun: smtp.mailgun.org:587
|
||||
// - AWS SES: email-smtp.us-east-1.amazonaws.com:587
|
||||
|
||||
let freezone_email_client = new_email_client()
|
||||
.smtp_host("smtp.freezone.example")
|
||||
.smtp_port(587)
|
||||
.from_email("noreply@freezone.example")
|
||||
.from_name("Freezone Platform");
|
||||
.smtp_host("smtp-relay.brevo.com") // Change to your SMTP server
|
||||
.smtp_port(587) // 587 for TLS, 465 for SSL
|
||||
.username("timur@incubaid.com") // Your SMTP username/email
|
||||
.password("xsmtpsib-a470d3fffa3f3b0f66800fe065f339067a07066d6a7df405fa465759418285ee-ojLWpd4oIShqIr6X") // Your SMTP password or app password
|
||||
.from_email("registrar@ourworldfreezone.com") // From address
|
||||
.from_name("Zanzibar Digital Free Zone")
|
||||
.use_tls(true);
|
||||
|
||||
print("✓ Email client configured");
|
||||
print(" SMTP Host: smtp.freezone.example");
|
||||
freezone_ctx.save(freezone_email_client);
|
||||
|
||||
// Create verification email template
|
||||
let verification_mail_template = new_mail_template()
|
||||
.id("verification_email")
|
||||
.name("Email Verification Template")
|
||||
.subject("Verify your email address - Freezone")
|
||||
.body("Hello,\n\nPlease verify your email address by clicking the link below:\n\n${url}\n\nOr use this verification code: ${code}\n\nThis link will expire in 24 hours.\n\nIf you didn't request this, please ignore this email.\n\nBest regards,\nFreezone Team")
|
||||
.html_body("<!DOCTYPE html><html><head><style>body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; } .container { max-width: 600px; margin: 0 auto; padding: 20px; } .button { display: inline-block; padding: 12px 24px; background-color: #007bff; color: white; text-decoration: none; border-radius: 4px; margin: 20px 0; } .code { font-size: 24px; font-weight: bold; letter-spacing: 4px; padding: 10px; background-color: #f5f5f5; display: inline-block; margin: 10px 0; }</style></head><body><div class=\"container\"><h2>Verify your email address</h2><p>Hello,</p><p>Please verify your email address by clicking the button below:</p><a href=\"${url}\" class=\"button\">Verify Email</a><p>Or enter this verification code:</p><div class=\"code\">${code}</div><p>This link will expire in 24 hours.</p><p>If you didn't request this, please ignore this email.</p><p>Best regards,<br>Freezone Team</p></div></body></html>");
|
||||
|
||||
print("✓ Verification email template created");
|
||||
freezone_ctx.save(verification_mail_template);
|
||||
print(" From: noreply@freezone.example");
|
||||
|
||||
// Configure Payment Provider (Pesapal)
|
||||
// Get your credentials from: https://developer.pesapal.com/
|
||||
// Sandbox: https://demo.pesapal.com/
|
||||
// Production: https://www.pesapal.com/
|
||||
print("\nConfiguring Payment Provider...");
|
||||
|
||||
// For SANDBOX testing (demo environment):
|
||||
let freezone_payment_client = new_payment_client_pesapal_sandbox(
|
||||
1,
|
||||
"qkio1BGGYAXTu2JOfm7XSXNruoZsrqEW",
|
||||
"osGQ364R49cXKeOYSpaOnT++rHs="
|
||||
"qkio1BGGYAXTu2JOfm7XSXNruoZsrqEW", // Your Pesapal Consumer Key
|
||||
"osGQ364R49cXKeOYSpaOnT++rHs=" // Your Pesapal Consumer Secret
|
||||
);
|
||||
|
||||
// For PRODUCTION (real payments), use:
|
||||
// let freezone_payment_client = new_payment_client_pesapal(
|
||||
// 1,
|
||||
// "your-production-consumer-key",
|
||||
// "your-production-consumer-secret"
|
||||
// );
|
||||
|
||||
print("✓ Payment provider configured (Pesapal Sandbox)");
|
||||
print(" Provider: Pesapal");
|
||||
print(" Environment: Sandbox");
|
||||
print(" Note: Real payment links will be generated");
|
||||
|
||||
// Configure KYC Provider
|
||||
// Configure KYC Provider (Idenfy)
|
||||
// Get your credentials from: https://www.idenfy.com/
|
||||
// Dashboard: https://dashboard.idenfy.com/
|
||||
print("\nConfiguring KYC Provider...");
|
||||
print("✓ KYC provider configured");
|
||||
print(" Provider: Freezone KYC");
|
||||
print(" Callback URL: https://freezone.example/kyc/callback");
|
||||
|
||||
// Create Idenfy KYC client
|
||||
let freezone_kyc_client = new_kyc_client_idenfy(
|
||||
"your-idenfy-api-key", // Your Idenfy API Key
|
||||
"your-idenfy-api-secret" // Your Idenfy API Secret
|
||||
);
|
||||
|
||||
print("✓ KYC provider configured (Idenfy)");
|
||||
print(" Provider: Idenfy");
|
||||
print(" Note: Real KYC verification sessions will be created");
|
||||
|
||||
// Create Freezone's own Ethereum wallet
|
||||
print("\nCreating Freezone Ethereum Wallet...");
|
||||
@@ -155,8 +193,25 @@ print(" Nonce: " + verification.get_nonce());
|
||||
|
||||
// Prepare verification email
|
||||
let verification_link = "https://freezone.example/verify?nonce=" + verification.get_nonce();
|
||||
print(" Verification link: " + verification_link);
|
||||
print(" (Email sent to: " + user_email + ")");
|
||||
|
||||
// Create verification mail with template parameters
|
||||
let verification_mail = new_mail()
|
||||
.to(user_email)
|
||||
.template(verification_mail_template.get_id())
|
||||
.parameter("url", verification_link)
|
||||
.parameter("code", verification.get_code());
|
||||
|
||||
print("✓ Verification email prepared");
|
||||
print(" To: " + user_email);
|
||||
print(" Template: " + verification_mail_template.get_id());
|
||||
print(" Link: " + verification_link);
|
||||
print(" Code: " + verification.get_code());
|
||||
|
||||
// Send verification email using template
|
||||
// Note: In production, configure real SMTP credentials
|
||||
// For now, we'll simulate sending (actual SMTP would fail with example.com)
|
||||
print("✓ Verification email would be sent to: " + user_email);
|
||||
print(" (Skipping actual SMTP send - configure real server in production)");
|
||||
|
||||
// Simulate user clicking verification link and verifying
|
||||
print("\n✓ User clicks verification link and verifies email");
|
||||
@@ -259,15 +314,32 @@ print("✓ Payment request created");
|
||||
print(" Amount: $100 USD");
|
||||
print(" Description: Freezone Registration Fee");
|
||||
|
||||
// Initiate payment with Pesapal (this would return a payment URL)
|
||||
// Initiate payment with Pesapal - creates real payment link
|
||||
print("\nInitiating payment session with Pesapal...");
|
||||
print(" Payment URL: https://pay.pesapal.com/iframe/PesapalIframe3/Index/?OrderTrackingId=abc123");
|
||||
let payment_response = freezone_payment_client.create_payment_link(payment_request);
|
||||
|
||||
let payment_url = payment_response.get_payment_url();
|
||||
let order_tracking_id = payment_response.get_order_tracking_id();
|
||||
|
||||
print("✓ Payment session created");
|
||||
print(" Payment URL: " + payment_url);
|
||||
print(" Order Tracking ID: " + order_tracking_id);
|
||||
print(" (User would be redirected to Pesapal payment page)");
|
||||
|
||||
// Simulate user completing payment
|
||||
print("\n✓ User clicks payment link and completes payment");
|
||||
print(" Payment Status: COMPLETED");
|
||||
print(" Transaction ID: TXN_" + timestamp());
|
||||
// In production, you would:
|
||||
// 1. Redirect user to payment_url
|
||||
// 2. User completes payment on Pesapal
|
||||
// 3. Pesapal calls your callback_url
|
||||
// 4. You verify payment status with get_payment_status(order_tracking_id)
|
||||
|
||||
// For demo purposes, check payment status
|
||||
print("\nChecking payment status...");
|
||||
let payment_status = freezone_payment_client.get_payment_status(order_tracking_id);
|
||||
|
||||
print("✓ Payment status retrieved");
|
||||
print(" Status: " + payment_status.get_payment_status_description());
|
||||
print(" Amount: " + payment_status.get_amount() + " " + payment_status.get_currency());
|
||||
print(" Transaction ID: " + order_tracking_id);
|
||||
|
||||
// Create payment transaction record
|
||||
let payment_tx = new_transaction()
|
||||
@@ -288,48 +360,73 @@ print("✓ Transaction saved\n");
|
||||
print("Step 6: KYC Verification");
|
||||
print("─────────────────────────────────────────────────────────────");
|
||||
|
||||
// Pre-fill KYC form with already collected info (first name, last name)
|
||||
// User will fill in the rest at Idenfy (DOB, address, nationality, etc.)
|
||||
print("\nPreparing KYC session with pre-filled data...");
|
||||
let kyc_info = new_kyc_info()
|
||||
.client_id("user_1")
|
||||
.first_name("Timur") // From user profile
|
||||
.last_name("Gordon") // From user profile
|
||||
.email(user_email); // From user profile
|
||||
|
||||
print("✓ Pre-fill data prepared");
|
||||
print(" Name: Timur Gordon (pre-filled)");
|
||||
print(" Email: " + user_email + " (pre-filled)");
|
||||
print(" User will provide: DOB, address, nationality, ID document");
|
||||
|
||||
// Create KYC session
|
||||
let kyc_session = new_kyc_session("user_1", "freezone_kyc")
|
||||
let kyc_session = new_kyc_session("user_1", "idenfy")
|
||||
.callback_url("https://freezone.example/kyc/callback")
|
||||
.success_url("https://freezone.example/kyc/success")
|
||||
.error_url("https://freezone.example/kyc/error");
|
||||
.error_url("https://freezone.example/kyc/error")
|
||||
.locale("en");
|
||||
|
||||
print("✓ KYC session created");
|
||||
print(" Client ID: " + kyc_session.get_client_id());
|
||||
print(" Provider: " + kyc_session.get_provider());
|
||||
|
||||
// Generate KYC verification URL
|
||||
print("\nKYC Verification URL generated:");
|
||||
print(" https://kyc.provider.com/verify?session=kyc_session_" + timestamp());
|
||||
print(" (User would be redirected to KYC provider)");
|
||||
// Create verification session with Idenfy - generates real verification URL
|
||||
print("\nCreating Idenfy verification session...");
|
||||
let verification_url = freezone_kyc_client.create_verification_session(kyc_info, kyc_session);
|
||||
|
||||
// Simulate user clicking KYC link and completing verification
|
||||
print("\n✓ User clicks KYC link and completes verification");
|
||||
print(" - Uploads identity document (Passport)");
|
||||
print("✓ Idenfy verification session created");
|
||||
print(" Verification URL: " + verification_url);
|
||||
print(" (User redirected to Idenfy to complete verification)");
|
||||
|
||||
// Production flow:
|
||||
// 1. Redirect user to verification_url
|
||||
// 2. User fills in remaining info (DOB, address, nationality)
|
||||
// 3. User uploads ID document (Passport/ID/Driver's License)
|
||||
// 4. User takes selfie for liveness check
|
||||
// 5. Idenfy performs automated verification
|
||||
// 6. Idenfy calls callback_url with VERIFIED data from ID document
|
||||
// 7. Callback handler stores verified KYC info
|
||||
|
||||
print("\n✓ User completes verification at Idenfy:");
|
||||
print(" - Fills in DOB, address, nationality");
|
||||
print(" - Uploads identity document");
|
||||
print(" - Takes selfie for liveness check");
|
||||
print(" - Provides address proof");
|
||||
print(" - Idenfy extracts and verifies data from ID");
|
||||
|
||||
// Simulate KYC callback with verification results
|
||||
print("\n✓ KYC Provider callback received:");
|
||||
print(" - Identity verification: PASSED");
|
||||
print(" - Liveness check: PASSED");
|
||||
print(" - Address verification: PASSED");
|
||||
print(" - Sanctions screening: CLEAR");
|
||||
print(" - PEP check: NOT FOUND");
|
||||
print(" - Overall Status: VERIFIED");
|
||||
print("\n✓ Idenfy callback will provide VERIFIED data:");
|
||||
print(" - All personal info extracted from ID document");
|
||||
print(" - Document number, issue date, expiry date");
|
||||
print(" - Verification status (APPROVED/DENIED)");
|
||||
print(" - Liveness check result");
|
||||
|
||||
// Create KYC info with verified data from callback
|
||||
print("\nStoring verified KYC information...");
|
||||
// For demo purposes, simulate what callback would receive
|
||||
print("\nSimulating callback data (in production, this comes from Idenfy)...");
|
||||
let kyc_info_verified = new_kyc_info()
|
||||
.first_name("Timur")
|
||||
.last_name("Gordon")
|
||||
.client_id("user_1")
|
||||
.first_name("Timur") // Verified from ID
|
||||
.last_name("Gordon") // Verified from ID
|
||||
.email(user_email)
|
||||
.phone("+1-555-0123")
|
||||
.country("US")
|
||||
.date_of_birth("1990-05-15")
|
||||
.document_type("passport")
|
||||
.document_number("P123456789")
|
||||
.verified(true);
|
||||
.date_of_birth("1990-05-15") // Extracted from ID
|
||||
.nationality("US") // Extracted from ID
|
||||
.document_type("passport") // From verification
|
||||
.document_number("P123456789") // Extracted from ID
|
||||
.provider("idenfy")
|
||||
.verified(true); // Only if status == "APPROVED"
|
||||
|
||||
freezone_ctx.save(kyc_info_verified);
|
||||
freezone_ctx.save(kyc_session);
|
||||
|
||||
@@ -100,6 +100,10 @@ def_package! {
|
||||
.set_into_module(module, |ctx: &mut OsirisContext, flow_instance: crate::objects::FlowInstance| ctx.save_object(flow_instance));
|
||||
FuncRegistration::new("save")
|
||||
.set_into_module(module, |ctx: &mut OsirisContext, verification: crate::objects::Verification| ctx.save_object(verification));
|
||||
FuncRegistration::new("save")
|
||||
.set_into_module(module, |ctx: &mut OsirisContext, email_client: crate::objects::communication::email::EmailClient| ctx.save_object(email_client));
|
||||
FuncRegistration::new("save")
|
||||
.set_into_module(module, |ctx: &mut OsirisContext, mail_template: crate::objects::communication::email::MailTemplate| ctx.save_object(mail_template));
|
||||
FuncRegistration::new("save")
|
||||
.set_into_module(module, |ctx: &mut OsirisContext, account: crate::objects::Account| ctx.save_object(account));
|
||||
FuncRegistration::new("save")
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use super::verification::Verification;
|
||||
use crate::store::{BaseData, Object, Storable};
|
||||
use lettre::{
|
||||
Message, SmtpTransport, Transport,
|
||||
message::{header::ContentType, MultiPart, SinglePart},
|
||||
@@ -11,8 +12,11 @@ use lettre::{
|
||||
};
|
||||
|
||||
/// Email client with SMTP configuration
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, crate::DeriveObject)]
|
||||
pub struct EmailClient {
|
||||
#[serde(flatten)]
|
||||
pub base_data: BaseData,
|
||||
|
||||
/// SMTP server hostname
|
||||
pub smtp_host: String,
|
||||
|
||||
@@ -35,9 +39,64 @@ pub struct EmailClient {
|
||||
pub use_tls: bool,
|
||||
}
|
||||
|
||||
/// Mail template with placeholders
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, crate::DeriveObject)]
|
||||
pub struct MailTemplate {
|
||||
#[serde(flatten)]
|
||||
pub base_data: BaseData,
|
||||
|
||||
/// Template ID
|
||||
pub id: String,
|
||||
|
||||
/// Template name
|
||||
pub name: String,
|
||||
|
||||
/// Email subject (can contain placeholders like ${name})
|
||||
pub subject: String,
|
||||
|
||||
/// Email body (can contain placeholders like ${code}, ${url})
|
||||
pub body: String,
|
||||
|
||||
/// HTML body (optional, can contain placeholders)
|
||||
pub html_body: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for MailTemplate {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseData::new(),
|
||||
id: String::new(),
|
||||
name: String::new(),
|
||||
subject: String::new(),
|
||||
body: String::new(),
|
||||
html_body: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Email message created from a template
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct Mail {
|
||||
/// Recipient email address
|
||||
pub to: String,
|
||||
|
||||
/// Template ID to use
|
||||
pub template_id: Option<String>,
|
||||
|
||||
/// Parameters to replace in template
|
||||
pub parameters: std::collections::HashMap<String, String>,
|
||||
|
||||
/// Direct subject (if not using template)
|
||||
pub subject: Option<String>,
|
||||
|
||||
/// Direct body (if not using template)
|
||||
pub body: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for EmailClient {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
base_data: BaseData::new(),
|
||||
smtp_host: "localhost".to_string(),
|
||||
smtp_port: 587,
|
||||
username: String::new(),
|
||||
@@ -49,6 +108,105 @@ impl Default for EmailClient {
|
||||
}
|
||||
}
|
||||
|
||||
impl MailTemplate {
|
||||
/// Create a new mail template
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Builder: Set template ID
|
||||
pub fn id(mut self, id: String) -> Self {
|
||||
self.id = id;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Set template name
|
||||
pub fn name(mut self, name: String) -> Self {
|
||||
self.name = name;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Set subject
|
||||
pub fn subject(mut self, subject: String) -> Self {
|
||||
self.subject = subject;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Set body
|
||||
pub fn body(mut self, body: String) -> Self {
|
||||
self.body = body;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Set HTML body
|
||||
pub fn html_body(mut self, html_body: String) -> Self {
|
||||
self.html_body = Some(html_body);
|
||||
self
|
||||
}
|
||||
|
||||
/// Replace placeholders in text
|
||||
fn replace_placeholders(&self, text: &str, parameters: &std::collections::HashMap<String, String>) -> String {
|
||||
let mut result = text.to_string();
|
||||
for (key, value) in parameters {
|
||||
let placeholder = format!("${{{}}}", key);
|
||||
result = result.replace(&placeholder, value);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Render subject with parameters
|
||||
pub fn render_subject(&self, parameters: &std::collections::HashMap<String, String>) -> String {
|
||||
self.replace_placeholders(&self.subject, parameters)
|
||||
}
|
||||
|
||||
/// Render body with parameters
|
||||
pub fn render_body(&self, parameters: &std::collections::HashMap<String, String>) -> String {
|
||||
self.replace_placeholders(&self.body, parameters)
|
||||
}
|
||||
|
||||
/// Render HTML body with parameters
|
||||
pub fn render_html_body(&self, parameters: &std::collections::HashMap<String, String>) -> Option<String> {
|
||||
self.html_body.as_ref().map(|html| self.replace_placeholders(html, parameters))
|
||||
}
|
||||
}
|
||||
|
||||
impl Mail {
|
||||
/// Create a new mail
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Builder: Set recipient
|
||||
pub fn to(mut self, to: String) -> Self {
|
||||
self.to = to;
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Set template ID
|
||||
pub fn template(mut self, template_id: String) -> Self {
|
||||
self.template_id = Some(template_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Add a parameter
|
||||
pub fn parameter(mut self, key: String, value: String) -> Self {
|
||||
self.parameters.insert(key, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Set subject (for non-template emails)
|
||||
pub fn subject(mut self, subject: String) -> Self {
|
||||
self.subject = Some(subject);
|
||||
self
|
||||
}
|
||||
|
||||
/// Builder: Set body (for non-template emails)
|
||||
pub fn body(mut self, body: String) -> Self {
|
||||
self.body = Some(body);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl EmailClient {
|
||||
/// Create a new email client
|
||||
pub fn new() -> Self {
|
||||
@@ -198,6 +356,21 @@ impl EmailClient {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Send a mail using a template
|
||||
pub fn send_mail(&self, mail: &Mail, template: &MailTemplate) -> Result<(), String> {
|
||||
// Render subject and body with parameters
|
||||
let subject = template.render_subject(&mail.parameters);
|
||||
let body_text = template.render_body(&mail.parameters);
|
||||
let html_body = template.render_html_body(&mail.parameters);
|
||||
|
||||
// Send email
|
||||
if let Some(html) = html_body {
|
||||
self.send_html_email(&mail.to, &subject, &html, Some(&body_text))
|
||||
} else {
|
||||
self.send_email(&mail.to, &subject, &body_text)
|
||||
}
|
||||
}
|
||||
|
||||
/// Send a verification email with code
|
||||
pub fn send_verification_code_email(
|
||||
&self,
|
||||
|
||||
@@ -4,7 +4,7 @@ use ::rhai::plugin::*;
|
||||
use ::rhai::{CustomType, Dynamic, Engine, EvalAltResult, Module, TypeBuilder};
|
||||
|
||||
use super::verification::{Verification, VerificationStatus, VerificationTransport};
|
||||
use super::email::EmailClient;
|
||||
use super::email::{EmailClient, MailTemplate, Mail};
|
||||
|
||||
// ============================================================================
|
||||
// Verification Module
|
||||
@@ -107,6 +107,129 @@ mod rhai_verification_module {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Mail Template Module
|
||||
// ============================================================================
|
||||
|
||||
type RhaiMailTemplate = MailTemplate;
|
||||
|
||||
#[export_module]
|
||||
mod rhai_mail_template_module {
|
||||
use super::RhaiMailTemplate;
|
||||
use super::super::email::MailTemplate;
|
||||
use ::rhai::EvalAltResult;
|
||||
|
||||
#[rhai_fn(name = "new_mail_template", return_raw)]
|
||||
pub fn new_mail_template() -> Result<RhaiMailTemplate, Box<EvalAltResult>> {
|
||||
Ok(MailTemplate::new())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "id", return_raw)]
|
||||
pub fn set_id(
|
||||
template: &mut RhaiMailTemplate,
|
||||
id: String,
|
||||
) -> Result<RhaiMailTemplate, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(template);
|
||||
*template = owned.id(id);
|
||||
Ok(template.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "name", return_raw)]
|
||||
pub fn set_name(
|
||||
template: &mut RhaiMailTemplate,
|
||||
name: String,
|
||||
) -> Result<RhaiMailTemplate, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(template);
|
||||
*template = owned.name(name);
|
||||
Ok(template.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "subject", return_raw)]
|
||||
pub fn set_subject(
|
||||
template: &mut RhaiMailTemplate,
|
||||
subject: String,
|
||||
) -> Result<RhaiMailTemplate, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(template);
|
||||
*template = owned.subject(subject);
|
||||
Ok(template.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "body", return_raw)]
|
||||
pub fn set_body(
|
||||
template: &mut RhaiMailTemplate,
|
||||
body: String,
|
||||
) -> Result<RhaiMailTemplate, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(template);
|
||||
*template = owned.body(body);
|
||||
Ok(template.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "html_body", return_raw)]
|
||||
pub fn set_html_body(
|
||||
template: &mut RhaiMailTemplate,
|
||||
html_body: String,
|
||||
) -> Result<RhaiMailTemplate, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(template);
|
||||
*template = owned.html_body(html_body);
|
||||
Ok(template.clone())
|
||||
}
|
||||
|
||||
// Getters
|
||||
#[rhai_fn(name = "get_id")]
|
||||
pub fn get_id(template: &mut RhaiMailTemplate) -> String {
|
||||
template.id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Mail Module
|
||||
// ============================================================================
|
||||
|
||||
type RhaiMail = Mail;
|
||||
|
||||
#[export_module]
|
||||
mod rhai_mail_module {
|
||||
use super::RhaiMail;
|
||||
use super::super::email::Mail;
|
||||
use ::rhai::EvalAltResult;
|
||||
|
||||
#[rhai_fn(name = "new_mail", return_raw)]
|
||||
pub fn new_mail() -> Result<RhaiMail, Box<EvalAltResult>> {
|
||||
Ok(Mail::new())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "to", return_raw)]
|
||||
pub fn set_to(
|
||||
mail: &mut RhaiMail,
|
||||
to: String,
|
||||
) -> Result<RhaiMail, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(mail);
|
||||
*mail = owned.to(to);
|
||||
Ok(mail.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "template", return_raw)]
|
||||
pub fn set_template(
|
||||
mail: &mut RhaiMail,
|
||||
template_id: String,
|
||||
) -> Result<RhaiMail, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(mail);
|
||||
*mail = owned.template(template_id);
|
||||
Ok(mail.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "parameter", return_raw)]
|
||||
pub fn add_parameter(
|
||||
mail: &mut RhaiMail,
|
||||
key: String,
|
||||
value: String,
|
||||
) -> Result<RhaiMail, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(mail);
|
||||
*mail = owned.parameter(key, value);
|
||||
Ok(mail.clone())
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Email Client Module
|
||||
// ============================================================================
|
||||
@@ -116,7 +239,9 @@ type RhaiEmailClient = EmailClient;
|
||||
#[export_module]
|
||||
mod rhai_email_module {
|
||||
use super::RhaiEmailClient;
|
||||
use super::super::email::EmailClient;
|
||||
use super::RhaiMail;
|
||||
use super::RhaiMailTemplate;
|
||||
use super::super::email::{EmailClient, Mail, MailTemplate};
|
||||
use super::super::verification::Verification;
|
||||
use ::rhai::EvalAltResult;
|
||||
|
||||
@@ -125,6 +250,86 @@ mod rhai_email_module {
|
||||
Ok(EmailClient::new())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "smtp_host", return_raw)]
|
||||
pub fn set_smtp_host(
|
||||
client: &mut RhaiEmailClient,
|
||||
host: String,
|
||||
) -> Result<RhaiEmailClient, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(client);
|
||||
*client = owned.smtp_host(host);
|
||||
Ok(client.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "smtp_port", return_raw)]
|
||||
pub fn set_smtp_port(
|
||||
client: &mut RhaiEmailClient,
|
||||
port: i64,
|
||||
) -> Result<RhaiEmailClient, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(client);
|
||||
*client = owned.smtp_port(port as u16);
|
||||
Ok(client.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "username", return_raw)]
|
||||
pub fn set_username(
|
||||
client: &mut RhaiEmailClient,
|
||||
username: String,
|
||||
) -> Result<RhaiEmailClient, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(client);
|
||||
*client = owned.username(username);
|
||||
Ok(client.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "password", return_raw)]
|
||||
pub fn set_password(
|
||||
client: &mut RhaiEmailClient,
|
||||
password: String,
|
||||
) -> Result<RhaiEmailClient, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(client);
|
||||
*client = owned.password(password);
|
||||
Ok(client.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "from_email", return_raw)]
|
||||
pub fn set_from_email(
|
||||
client: &mut RhaiEmailClient,
|
||||
email: String,
|
||||
) -> Result<RhaiEmailClient, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(client);
|
||||
*client = owned.from_address(email);
|
||||
Ok(client.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "from_name", return_raw)]
|
||||
pub fn set_from_name(
|
||||
client: &mut RhaiEmailClient,
|
||||
name: String,
|
||||
) -> Result<RhaiEmailClient, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(client);
|
||||
*client = owned.from_name(name);
|
||||
Ok(client.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "use_tls", return_raw)]
|
||||
pub fn set_use_tls(
|
||||
client: &mut RhaiEmailClient,
|
||||
use_tls: bool,
|
||||
) -> Result<RhaiEmailClient, Box<EvalAltResult>> {
|
||||
let owned = std::mem::take(client);
|
||||
*client = owned.use_tls(use_tls);
|
||||
Ok(client.clone())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "send_mail", return_raw)]
|
||||
pub fn send_mail(
|
||||
client: &mut RhaiEmailClient,
|
||||
mail: RhaiMail,
|
||||
template: RhaiMailTemplate,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
client.send_mail(&mail, &template)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "send_verification_code", return_raw)]
|
||||
pub fn send_verification_code(
|
||||
client: &mut RhaiEmailClient,
|
||||
@@ -152,15 +357,25 @@ mod rhai_email_module {
|
||||
pub fn register_communication_modules(parent_module: &mut Module) {
|
||||
// Register custom types
|
||||
parent_module.set_custom_type::<Verification>("Verification");
|
||||
parent_module.set_custom_type::<MailTemplate>("MailTemplate");
|
||||
parent_module.set_custom_type::<Mail>("Mail");
|
||||
parent_module.set_custom_type::<EmailClient>("EmailClient");
|
||||
|
||||
// Merge verification functions
|
||||
let verification_module = exported_module!(rhai_verification_module);
|
||||
parent_module.merge(&verification_module);
|
||||
parent_module.combine_flatten(verification_module);
|
||||
|
||||
// Merge mail template functions
|
||||
let mail_template_module = exported_module!(rhai_mail_template_module);
|
||||
parent_module.combine_flatten(mail_template_module);
|
||||
|
||||
// Merge mail functions
|
||||
let mail_module = exported_module!(rhai_mail_module);
|
||||
parent_module.combine_flatten(mail_module);
|
||||
|
||||
// Merge email client functions
|
||||
let email_module = exported_module!(rhai_email_module);
|
||||
parent_module.merge(&email_module);
|
||||
parent_module.combine_flatten(email_module);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -173,6 +388,18 @@ impl CustomType for Verification {
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomType for MailTemplate {
|
||||
fn build(mut builder: TypeBuilder<Self>) {
|
||||
builder.with_name("MailTemplate");
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomType for Mail {
|
||||
fn build(mut builder: TypeBuilder<Self>) {
|
||||
builder.with_name("Mail");
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomType for EmailClient {
|
||||
fn build(mut builder: TypeBuilder<Self>) {
|
||||
builder.with_name("EmailClient");
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
use ::rhai::plugin::*;
|
||||
use ::rhai::{CustomType, Dynamic, Engine, EvalAltResult, Module, TypeBuilder};
|
||||
use std::mem;
|
||||
|
||||
use super::info::{KycInfo, VerificationStatus};
|
||||
use super::session::{KycSession, SessionStatus};
|
||||
use super::client::KycClient;
|
||||
|
||||
// ============================================================================
|
||||
// KYC Info Module
|
||||
@@ -290,6 +290,45 @@ mod rhai_kyc_session_module {
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// KYC Client Module
|
||||
// ============================================================================
|
||||
|
||||
type RhaiKycClient = KycClient;
|
||||
|
||||
#[export_module]
|
||||
mod rhai_kyc_client_module {
|
||||
use super::RhaiKycClient;
|
||||
use super::RhaiKycInfo;
|
||||
use super::RhaiKycSession;
|
||||
use ::rhai::EvalAltResult;
|
||||
|
||||
#[rhai_fn(name = "new_kyc_client_idenfy", return_raw)]
|
||||
pub fn new_idenfy_client(
|
||||
api_key: String,
|
||||
api_secret: String,
|
||||
) -> Result<RhaiKycClient, Box<EvalAltResult>> {
|
||||
Ok(KycClient::idenfy(api_key, api_secret))
|
||||
}
|
||||
|
||||
#[rhai_fn(name = "create_verification_session", return_raw)]
|
||||
pub fn create_verification_session(
|
||||
client: &mut RhaiKycClient,
|
||||
kyc_info: RhaiKycInfo,
|
||||
session: RhaiKycSession,
|
||||
) -> Result<String, Box<EvalAltResult>> {
|
||||
// Need to use tokio runtime for async call
|
||||
let rt = tokio::runtime::Runtime::new()
|
||||
.map_err(|e| format!("Failed to create runtime: {}", e))?;
|
||||
|
||||
let mut session_mut = session.clone();
|
||||
let url = rt.block_on(client.create_verification_session(&kyc_info, &mut session_mut))
|
||||
.map_err(|e| format!("Failed to create verification session: {}", e))?;
|
||||
|
||||
Ok(url)
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Registration Functions
|
||||
// ============================================================================
|
||||
@@ -299,6 +338,7 @@ pub fn register_kyc_modules(parent_module: &mut Module) {
|
||||
// Register custom types
|
||||
parent_module.set_custom_type::<KycInfo>("KycInfo");
|
||||
parent_module.set_custom_type::<KycSession>("KycSession");
|
||||
parent_module.set_custom_type::<KycClient>("KycClient");
|
||||
|
||||
// Merge KYC info functions
|
||||
let info_module = exported_module!(rhai_kyc_info_module);
|
||||
@@ -307,6 +347,10 @@ pub fn register_kyc_modules(parent_module: &mut Module) {
|
||||
// Merge KYC session functions
|
||||
let session_module = exported_module!(rhai_kyc_session_module);
|
||||
parent_module.merge(&session_module);
|
||||
|
||||
// Merge KYC client functions
|
||||
let client_module = exported_module!(rhai_kyc_client_module);
|
||||
parent_module.merge(&client_module);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -324,3 +368,9 @@ impl CustomType for KycSession {
|
||||
builder.with_name("KycSession");
|
||||
}
|
||||
}
|
||||
|
||||
impl CustomType for KycClient {
|
||||
fn build(mut builder: TypeBuilder<Self>) {
|
||||
builder.with_name("KycClient");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user