zlicenser-server 0.1.2

Server library for the zlicenser hardware-bound software licensing framework.
Documentation
pub mod types;
pub use types::*;

#[cfg(feature = "storage-sqlite")]
pub mod sqlite;
#[cfg(feature = "storage-sqlite")]
pub use sqlite::SqliteStorage;

#[cfg(feature = "storage-postgres")]
pub mod postgres;
#[cfg(feature = "storage-postgres")]
pub use postgres::PostgresStorage;

use async_trait::async_trait;
use uuid::Uuid;

#[async_trait]
pub trait VendorStore: Send + Sync {
    async fn get_vendor_config(&self) -> crate::Result<Option<VendorConfig>>;
    async fn upsert_vendor_config(&self, config: &VendorConfig) -> crate::Result<()>;
    async fn rotate_vendor_key(
        &self,
        new_public_key: &[u8],
        new_fingerprint: &str,
        rotated_from: &[u8],
        rotated_at: i64,
    ) -> crate::Result<()>;

    async fn create_product(&self, p: &Product) -> crate::Result<()>;
    async fn get_product(&self, id: Uuid) -> crate::Result<Option<Product>>;
    async fn list_products(&self) -> crate::Result<Vec<Product>>;
    async fn update_product(&self, p: &Product) -> crate::Result<()>;

    async fn upsert_term_declaration(&self, d: &ProductTermDeclaration) -> crate::Result<()>;
    async fn get_term_declaration(
        &self,
        product_id: Uuid,
    ) -> crate::Result<Option<ProductTermDeclaration>>;

    async fn create_terms_document(&self, d: &ProductTermsDocument) -> crate::Result<()>;
    async fn get_terms_document(&self, id: Uuid) -> crate::Result<Option<ProductTermsDocument>>;
    async fn get_active_terms_document(
        &self,
        product_id: Uuid,
    ) -> crate::Result<Option<ProductTermsDocument>>;
    async fn list_terms_documents(
        &self,
        product_id: Uuid,
    ) -> crate::Result<Vec<ProductTermsDocument>>;
    async fn update_terms_document_validation(
        &self,
        id: Uuid,
        status: TermsValidationStatus,
        findings: &str,
    ) -> crate::Result<()>;
    async fn acknowledge_terms_findings(
        &self,
        id: Uuid,
        acknowledged_at: i64,
        findings: &str,
    ) -> crate::Result<()>;
    async fn activate_terms_document(&self, id: Uuid, activated_at: i64) -> crate::Result<()>;

    async fn replace_customer_fields(
        &self,
        product_id: Uuid,
        fields: &[ProductCustomerField],
    ) -> crate::Result<()>;
    async fn get_customer_fields(
        &self,
        product_id: Uuid,
    ) -> crate::Result<Vec<ProductCustomerField>>;

    async fn create_upgrade_policy(&self, p: &UpgradePolicyRow) -> crate::Result<()>;
    async fn get_upgrade_policy(&self, id: Uuid) -> crate::Result<Option<UpgradePolicyRow>>;
    async fn find_upgrade_policy(
        &self,
        product_id: Uuid,
        from_version: &str,
        to_version: &str,
    ) -> crate::Result<Option<UpgradePolicyRow>>;
    async fn list_upgrade_policies(&self, product_id: Uuid)
    -> crate::Result<Vec<UpgradePolicyRow>>;
    async fn delete_upgrade_policy(&self, id: Uuid) -> crate::Result<()>;
}

#[async_trait]
pub trait CustomerStore: Send + Sync {
    async fn create_customer(&self, c: &Customer) -> crate::Result<()>;
    async fn get_customer(&self, id: Uuid) -> crate::Result<Option<Customer>>;
    async fn find_customer_by_email(
        &self,
        product_id: Uuid,
        email: &str,
    ) -> crate::Result<Option<Customer>>;
    async fn update_customer(&self, c: &Customer) -> crate::Result<()>;
}

#[async_trait]
pub trait LicenseStore: Send + Sync {
    async fn create_license(&self, l: &License) -> crate::Result<()>;
    async fn get_license(&self, id: Uuid) -> crate::Result<Option<License>>;
    async fn list_licenses_for_customer(&self, customer_id: Uuid) -> crate::Result<Vec<License>>;
    async fn update_license_status(
        &self,
        id: Uuid,
        status: LicenseStatus,
        revoked_at: Option<i64>,
        revocation_reason: Option<&str>,
        superseded_by: Option<Uuid>,
    ) -> crate::Result<()>;
    async fn update_license_email_sent(&self, id: Uuid, sent_at: i64) -> crate::Result<()>;

    async fn create_consent_record(&self, r: &ConsentRecord) -> crate::Result<()>;
    async fn get_consent_record(&self, id: Uuid) -> crate::Result<Option<ConsentRecord>>;
    async fn get_consent_records_for_license(
        &self,
        license_id: Uuid,
    ) -> crate::Result<Vec<ConsentRecord>>;
}

#[async_trait]
pub trait SeatStore: Send + Sync {
    async fn create_seat_binding(&self, b: &FingerprintSeatBinding) -> crate::Result<()>;
    async fn get_seat_binding(&self, id: Uuid) -> crate::Result<Option<FingerprintSeatBinding>>;
    async fn find_seat_binding_by_commitment(
        &self,
        license_id: Uuid,
        commitment: &[u8],
    ) -> crate::Result<Option<FingerprintSeatBinding>>;
    async fn list_seat_bindings(
        &self,
        license_id: Uuid,
    ) -> crate::Result<Vec<FingerprintSeatBinding>>;
    async fn count_active_seat_bindings(&self, license_id: Uuid) -> crate::Result<u32>;
    async fn revoke_seat_binding(&self, id: Uuid, revoked_at: i64) -> crate::Result<()>;
    async fn update_seat_binding_verified(&self, id: Uuid, verified_at: i64) -> crate::Result<()>;

    async fn create_issuance_secret(&self, s: &IssuanceSecret) -> crate::Result<()>;
    async fn get_issuance_secret(&self, license_id: Uuid) -> crate::Result<Option<IssuanceSecret>>;
    async fn delete_issuance_secret(&self, license_id: Uuid) -> crate::Result<()>;

    async fn create_session(&self, s: &ActiveSession) -> crate::Result<()>;
    async fn get_session(&self, id: Uuid) -> crate::Result<Option<ActiveSession>>;
    async fn get_active_session_for_binding(
        &self,
        binding_id: Uuid,
    ) -> crate::Result<Option<ActiveSession>>;
    async fn update_session_heartbeat(
        &self,
        id: Uuid,
        heartbeat_at: i64,
        seq_no: i64,
    ) -> crate::Result<()>;
    async fn update_session_status(&self, id: Uuid, status: SessionStatus) -> crate::Result<()>;
    async fn expire_sessions_before(&self, expires_at: i64) -> crate::Result<u64>;
}

#[async_trait]
pub trait PaymentStore: Send + Sync {
    async fn create_payment_transaction(&self, t: &PaymentTransaction) -> crate::Result<()>;
    async fn get_payment_transaction(&self, id: Uuid) -> crate::Result<Option<PaymentTransaction>>;
    async fn get_payment_transaction_for_license(
        &self,
        license_id: Uuid,
    ) -> crate::Result<Option<PaymentTransaction>>;
    async fn update_payment_status(
        &self,
        id: Uuid,
        status: PaymentStatus,
        confirmed_at: Option<i64>,
    ) -> crate::Result<()>;

    async fn create_transfer_request(&self, r: &TransferRequest) -> crate::Result<()>;
    async fn get_transfer_request(&self, id: Uuid) -> crate::Result<Option<TransferRequest>>;
    async fn list_transfer_requests_for_license(
        &self,
        license_id: Uuid,
    ) -> crate::Result<Vec<TransferRequest>>;
    async fn resolve_transfer_request(
        &self,
        id: Uuid,
        status: TransferStatus,
        vendor_note: Option<&str>,
        resolved_at: i64,
    ) -> crate::Result<()>;
}

#[async_trait]
pub trait SecurityStore: Send + Sync {
    async fn create_quarantine_case(&self, c: &QuarantineCase) -> crate::Result<()>;
    async fn get_quarantine_case(&self, id: Uuid) -> crate::Result<Option<QuarantineCase>>;
    async fn get_quarantine_case_by_case_id(
        &self,
        case_id: Uuid,
    ) -> crate::Result<Option<QuarantineCase>>;
    async fn resolve_quarantine_case(
        &self,
        id: Uuid,
        status: QuarantineStatus,
        resolution: Option<&str>,
        resolved_at: i64,
        vendor_note: Option<&str>,
    ) -> crate::Result<()>;

    async fn create_security_event(&self, e: &SecurityEvent) -> crate::Result<()>;
    async fn get_security_events_for_license(
        &self,
        license_id: Uuid,
    ) -> crate::Result<Vec<SecurityEvent>>;
    async fn mark_security_event_reviewed(
        &self,
        id: i64,
        reviewed_by: &str,
        reviewed_at: i64,
    ) -> crate::Result<()>;

    async fn create_revocation_record(&self, r: &RevocationRecord) -> crate::Result<()>;
    async fn get_revocation_record(
        &self,
        license_id: Uuid,
    ) -> crate::Result<Option<RevocationRecord>>;

    async fn create_email_log_entry(&self, e: &EmailLogEntry) -> crate::Result<()>;
    async fn list_email_log_for_license(
        &self,
        license_id: Uuid,
    ) -> crate::Result<Vec<EmailLogEntry>>;
}

#[async_trait]
pub trait EnrollmentStore: Send + Sync {
    async fn count_transferable_seat_bindings(&self, product_id: Uuid) -> crate::Result<u32>;
    async fn set_seat_binding_transfer_pending(
        &self,
        id: Uuid,
        pending_at: Option<i64>,
    ) -> crate::Result<()>;
    async fn create_enrollment_session(&self, s: &EnrollmentSession) -> crate::Result<()>;
    async fn get_enrollment_session(&self, id: Uuid) -> crate::Result<Option<EnrollmentSession>>;
    async fn get_session_by_payment_intent(
        &self,
        intent_id: &str,
    ) -> crate::Result<Option<EnrollmentSession>>;
    async fn update_enrollment_session(
        &self,
        id: Uuid,
        expected_updated_at: i64,
        update: EnrollmentSessionUpdate,
    ) -> crate::Result<()>;
    async fn list_grant_ready_sessions(&self) -> crate::Result<Vec<EnrollmentSession>>;
}

pub trait Storage:
    VendorStore
    + CustomerStore
    + LicenseStore
    + SeatStore
    + PaymentStore
    + SecurityStore
    + EnrollmentStore
{
}

impl<T> Storage for T where
    T: VendorStore
        + CustomerStore
        + LicenseStore
        + SeatStore
        + PaymentStore
        + SecurityStore
        + EnrollmentStore
{
}