Skip to content
Open
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
23 changes: 20 additions & 3 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,34 @@ jobs:
run: npm ci

- name: Run npm audit (production dependencies)
run: npm audit --omit=dev --audit-level=critical
run: npm audit --omit=dev --audit-level=high

- name: Check for known vulnerabilities in frontend (production dependencies)
run: npm audit --workspace=frontend --omit=dev --audit-level=critical
run: npm audit --workspace=frontend --omit=dev --audit-level=high

- name: Check for known vulnerabilities in backend (production dependencies)
run: npm audit --workspace=backend --omit=dev --audit-level=critical
run: npm audit --workspace=backend --omit=dev --audit-level=high

- name: Verify security setup
run: npm run verify-security

cargo-audit:
name: Cargo Dependency Vulnerability Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Rust stable
uses: dtolnay/rust-toolchain@stable

- name: Install cargo-audit
run: cargo install cargo-audit

- name: Run cargo audit on contracts
run: cargo audit
working-directory: contracts

codeql-analysis:
name: CodeQL Analysis
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"dependencies": {
"@prisma/adapter-pg": "^7.8.0",
"@prisma/client": "^7.8.0",
"@stellar/stellar-sdk": "^15.1.0",
"@stellar/stellar-sdk": "^17.0.1",
"cors": "^2.8.6",
"dotenv": "^17.4.2",
"express": "^5.2.1",
Expand Down
4 changes: 2 additions & 2 deletions backend/src/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,15 @@ export function verifyChallenge(req: Request, res: Response): void {

// Verify the manage_data op contains our nonce
const op = tx.operations[0] as StellarSdk.Operation.ManageData | undefined;
if (!op || op.type !== 'manageData' || op.value?.toString('hex') !== challenge.nonce) {
if (!op || op.type !== 'manageData' || Buffer.from(op.value ?? new Uint8Array()).toString('hex') !== challenge.nonce) {
res.status(401).json({ error: 'Invalid challenge nonce in transaction' });
return;
}

const keypair = StellarSdk.Keypair.fromPublicKey(publicKey);
const txHash = tx.hash();
const valid = tx.signatures.some((s) => {
try { return keypair.verify(txHash, s.signature()); } catch { return false; }
try { return keypair.verify(txHash, s.signature); } catch { return false; }
});

if (!valid) {
Expand Down
26 changes: 13 additions & 13 deletions backend/src/services/sorobanService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,25 +161,25 @@ export interface ChainStream {
}

export function decodeI128(val: xdr.ScVal): string {
const parts = val.i128();
const hi = BigInt.asIntN(64, BigInt(parts.hi().toString()));
const lo = BigInt.asUintN(64, BigInt(parts.lo().toString()));
const parts = (val as xdr.ScValI128).i128;
const hi = BigInt.asIntN(64, BigInt(parts.hi.toString()));
const lo = BigInt.asUintN(64, BigInt(parts.lo.toString()));
return ((hi << 64n) | lo).toString();
}

export function decodeAddress(val: xdr.ScVal): string {
const addr = val.address();
if (addr.switch().value === xdr.ScAddressType.scAddressTypeAccount().value) {
return StrKey.encodeEd25519PublicKey(addr.accountId().ed25519());
const addr = (val as xdr.ScValAddress).address;
if (addr.type === 'scAddressTypeAccount') {
return StrKey.encodeEd25519PublicKey((addr.accountId as xdr.PublicKeyEd25519).ed25519.value);
}
const hash = addr.contractId();
return StrKey.encodeContract(Buffer.from(hash as unknown as Uint8Array));
const hash = (addr as xdr.ScAddressContract).contractId;
return StrKey.encodeContract(Buffer.from(hash.value as unknown as Uint8Array));
}

function decodeMap(val: xdr.ScVal): Record<string, xdr.ScVal> {
const result: Record<string, xdr.ScVal> = {};
for (const entry of val.map() ?? []) {
result[entry.key().sym().toString()] = entry.val();
for (const entry of (val as xdr.ScValMap).map ?? []) {
result[(entry.key as xdr.ScValSymbol).sym.toString()] = entry.val;
}
return result;
}
Expand Down Expand Up @@ -271,8 +271,8 @@ export async function getStreamFromChain(streamId: bigint): Promise<ChainStream

const isActiveVal = fields['is_active']!;
const isActive =
isActiveVal.switch().value === xdr.ScValType.scvBool().value &&
isActiveVal.b() === true;
isActiveVal.type === 'scvBool' &&
isActiveVal.b === true;

return {
streamId,
Expand All @@ -282,7 +282,7 @@ export async function getStreamFromChain(streamId: bigint): Promise<ChainStream
ratePerSecond: decodeI128(fields['rate_per_second']!),
depositedAmount: decodeI128(fields['deposited_amount']!),
withdrawnAmount: decodeI128(fields['withdrawn_amount']!),
startTime: Number(fields['start_time']!.u64().toString()),
startTime: Number((fields['start_time']! as xdr.ScValU64).u64.toString()),
isActive,
};
} catch (err) {
Expand Down
28 changes: 14 additions & 14 deletions backend/src/workers/soroban-event-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ import "../lib/stream-id.js";

/** Decode an ScVal symbol to a string. */
export function decodeSymbol(val: xdr.ScVal): string {
return val.sym().toString();
return (val as xdr.ScValSymbol).sym.toString();
}

/**
* Decode an ScVal U64 to a JavaScript bigint.
* `xdr.UInt64` extends Long; `.toString()` gives the decimal representation.
*/
export function decodeU64(val: xdr.ScVal): bigint {
return BigInt(val.u64().toString());
return BigInt((val as xdr.ScValU64).u64.toString());
}

/** Decode an ScVal U32 to a JavaScript number. */
export function decodeU32(val: xdr.ScVal): number {
return val.u32();
return (val as xdr.ScValU32).u32;
}

/**
Expand All @@ -35,9 +35,9 @@ export function decodeU32(val: xdr.ScVal): number {
* Full value = hi * 2^64 + lo.
*/
export function decodeI128(val: xdr.ScVal): string {
const parts = val.i128();
const hi = BigInt.asIntN(64, BigInt(parts.hi().toString()));
const lo = BigInt.asUintN(64, BigInt(parts.lo().toString()));
const parts = (val as xdr.ScValI128).i128;
const hi = BigInt.asIntN(64, BigInt(parts.hi.toString()));
const lo = BigInt.asUintN(64, BigInt(parts.lo.toString()));
return ((hi << 64n) | lo).toString();
}

Expand All @@ -46,13 +46,13 @@ export function decodeI128(val: xdr.ScVal): string {
* string.
*/
export function decodeAddress(val: xdr.ScVal): string {
const addr = val.address();
if (addr.switch().value === xdr.ScAddressType.scAddressTypeAccount().value) {
return StrKey.encodeEd25519PublicKey(addr.accountId().ed25519());
const addr = (val as xdr.ScValAddress).address;
if (addr.type === 'scAddressTypeAccount') {
return StrKey.encodeEd25519PublicKey((addr.accountId as xdr.PublicKeyEd25519).ed25519.value);
}
// addr.contractId() returns a Hash (Opaque[]); cast to Uint8Array for encodeContract
const hash = addr.contractId();
return StrKey.encodeContract(Buffer.from(hash as unknown as Uint8Array));
// addr.contractId is a Hash (Opaque[]); cast to Uint8Array for encodeContract
const hash = (addr as xdr.ScAddressContract).contractId;
return StrKey.encodeContract(Buffer.from(hash.value as unknown as Uint8Array));
}

/**
Expand All @@ -61,10 +61,10 @@ export function decodeAddress(val: xdr.ScVal): string {
*/
export function decodeMap(val: xdr.ScVal): Record<string, xdr.ScVal> {
const result: Record<string, xdr.ScVal> = {};
const entries = val.map();
const entries = (val as xdr.ScValMap).map;
if (!entries) return result;
for (const entry of entries) {
result[entry.key().sym().toString()] = entry.val();
result[(entry.key as xdr.ScValSymbol).sym.toString()] = entry.val;
}
return result;
}
Expand Down
Loading
Loading