Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,28 @@ concurrency:
cancel-in-progress: true

jobs:
changes:
runs-on: ubuntu-latest
outputs:
frontend: ${{ steps.filter.outputs.frontend }}
backend: ${{ steps.filter.outputs.backend }}
contracts: ${{ steps.filter.outputs.contracts }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
frontend:
- 'frontend/**'
backend:
- 'backend/**'
contracts:
- 'stellar-contracts/**'

frontend:
needs: changes
if: needs.changes.outputs.frontend == 'true'
runs-on: ubuntu-latest
defaults:
run:
Expand All @@ -33,6 +54,8 @@ jobs:
run: npm run build

backend:
needs: changes
if: needs.changes.outputs.backend == 'true'
runs-on: ubuntu-latest
defaults:
run:
Expand All @@ -54,6 +77,8 @@ jobs:
run: npm run build

contracts:
needs: changes
if: needs.changes.outputs.contracts == 'true'
runs-on: ubuntu-latest
defaults:
run:
Expand Down
67 changes: 21 additions & 46 deletions stellar-contracts/src/crl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env, String, Vec};
use soroban_sdk::{contract, contractimpl, contracttype, Address, Env, IntoVal, String, Vec};

const DEFAULT_UPDATE_WINDOW_SECONDS: u64 = 7 * 24 * 60 * 60;

Expand Down Expand Up @@ -43,14 +43,15 @@ enum DataKey {
Info,
Revocation(String),
RevokedCertificates,
CertContract,
}

#[contract]
pub struct CRLContract;

#[contractimpl]
impl CRLContract {
pub fn initialize(env: Env, issuer: Address) {
pub fn initialize(env: Env, issuer: Address, certificate_contract: Address) {
if env.storage().instance().has(&DataKey::Issuer) {
panic!("CRL already initialized");
}
Expand All @@ -68,6 +69,9 @@ impl CRLContract {
};

env.storage().instance().set(&DataKey::Issuer, &issuer);
env.storage()
.instance()
.set(&DataKey::CertContract, &certificate_contract);
env.storage()
.instance()
.set(&DataKey::RevokedCertificates, &Vec::<String>::new(&env));
Expand All @@ -83,6 +87,21 @@ impl CRLContract {
let issuer = Self::get_issuer(&env);
issuer.require_auth();

// Verify the certificate exists in the CertificateContract (#414)
let cert_contract: Address = env
.storage()
.instance()
.get(&DataKey::CertContract)
.expect("CRL not initialized");
let cert_exists: bool = env.invoke_contract(
&cert_contract,
&soroban_sdk::Symbol::new(&env, "certificate_exists"),
soroban_sdk::vec![&env, certificate_id.clone().into_val(&env)],
);
if !cert_exists {
panic!("Certificate does not exist");
}

let revocation_key = DataKey::Revocation(certificate_id.clone());
if env.storage().instance().has(&revocation_key) {
panic!("Certificate already revoked");
Expand Down Expand Up @@ -112,37 +131,6 @@ impl CRLContract {
env.storage().instance().set(&DataKey::Info, &crl_info);
}

pub fn unrevoke_certificate(env: Env, certificate_id: String) {
let issuer = Self::get_issuer(&env);
issuer.require_auth();

let revocation_key = DataKey::Revocation(certificate_id.clone());
let revocation_info: RevocationInfo = env
.storage()
.instance()
.get(&revocation_key)
.expect("Certificate not found in revocation list");

if revocation_info.issuer != issuer {
panic!("Only the original issuer can unrevoke");
}

env.storage().instance().remove(&revocation_key);

let mut revoked_certificates = Self::get_revoked_certificate_ids(&env);
Self::remove_certificate_id(&mut revoked_certificates, &certificate_id);
env.storage()
.instance()
.set(&DataKey::RevokedCertificates, &revoked_certificates);

let mut crl_info = Self::get_crl_info_internal(&env);
if crl_info.revoked_count > 0 {
crl_info.revoked_count -= 1;
}
Self::refresh_crl_info(&env, &mut crl_info);
env.storage().instance().set(&DataKey::Info, &crl_info);
}

pub fn is_revoked(env: Env, certificate_id: String) -> bool {
env.storage()
.instance()
Expand Down Expand Up @@ -247,19 +235,6 @@ impl CRLContract {
}
}

fn remove_certificate_id(revoked_certificates: &mut Vec<String>, certificate_id: &String) {
let mut index = 0;
while index < revoked_certificates.len() {
if let Some(existing_id) = revoked_certificates.get(index) {
if existing_id == certificate_id.clone() {
revoked_certificates.remove(index);
break;
}
}
index += 1;
}
}

fn refresh_crl_info(env: &Env, crl_info: &mut CRLInfo) {
crl_info.crl_number += 1;
crl_info.this_update = env.ledger().timestamp();
Expand Down
14 changes: 13 additions & 1 deletion stellar-contracts/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ impl CertificateContract {
);
}

/// Check if a certificate exists
pub fn certificate_exists(env: Env, id: String) -> bool {
env.storage()
.instance()
.has(&DataKey::Certificate(id))
}

/// Get certificate details
pub fn get_certificate(env: Env, id: String) -> Option<Certificate> {
env.storage().instance().get(&DataKey::Certificate(id))
Expand Down Expand Up @@ -580,9 +587,14 @@ impl CertificateContract {
.instance()
.get::<_, Certificate>(&DataKey::Certificate(id.clone()))
{
let is_expired_by_time = cert
.expires_at
.map_or(false, |exp| env.ledger().timestamp() >= exp);

let is_revoked = cert.status == CertificateStatus::Revoked
|| cert.status == CertificateStatus::Suspended
|| cert.status == CertificateStatus::Expired;
|| cert.status == CertificateStatus::Expired
|| is_expired_by_time;

if !is_revoked {
successful += 1;
Expand Down
6 changes: 4 additions & 2 deletions stellar-contracts/src/storage.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use soroban_sdk::{contracttype, Address};

/// Storage keys for the admin multisig contract.
/// Named `StorageKey` to avoid conflict with the `DataKey` enum in `types.rs`.
#[contracttype]
#[derive(Clone)]
pub enum DataKey {
pub enum StorageKey {
Core(CoreDataKey),
Admin(AdminDataKey),
}
Expand All @@ -19,4 +21,4 @@ pub enum CoreDataKey {
pub enum AdminDataKey {
Owners,
Threshold,
}
}
8 changes: 4 additions & 4 deletions stellar-contracts/src/storage_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
use soroban_sdk::{Env, Address};
use crate::storage::{DataKey, CoreDataKey, AdminDataKey};
use crate::storage::{StorageKey, CoreDataKey, AdminDataKey};

pub fn set_admin(env: &Env, admin: &Address) {
env.storage().set(
&DataKey::Core(CoreDataKey::Admin),
&StorageKey::Core(CoreDataKey::Admin),
admin,
);
}

pub fn get_admin(env: &Env) -> Address {
env.storage()
.get(&DataKey::Core(CoreDataKey::Admin))
.get(&StorageKey::Core(CoreDataKey::Admin))
.unwrap()
}

pub fn set_owners(env: &Env, owners: &Vec<Address>) {
env.storage().set(
&DataKey::Admin(AdminDataKey::Owners),
&StorageKey::Admin(AdminDataKey::Owners),
owners,
);
}
Loading