Skip to content

Commit

Permalink
Initial bitwise RPC authorization-permission system
Browse files Browse the repository at this point in the history
  • Loading branch information
KaffinPX committed Nov 13, 2024
1 parent ba3ca33 commit 167a1c3
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 1 deletion.
4 changes: 4 additions & 0 deletions consensus/core/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ pub struct Config {

/// A scale factor to apply to memory allocation bounds
pub ram_scale: f64,

/// Bitwise flag for configuring allowed RPC calls
pub rpc_flags: u128,
}

impl Config {
Expand Down Expand Up @@ -95,6 +98,7 @@ impl Config {
initial_utxo_set: Default::default(),
disable_upnp: false,
ram_scale: 1.0,
rpc_flags: u128::MAX,
}
}

Expand Down
4 changes: 4 additions & 0 deletions rpc/core/src/api/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ pub enum RpcApiOps {
}

impl RpcApiOps {
pub fn bitmask(&self) -> u128 {
1 << (*self as u128 - 110) // Only applies for RPC methods -- means it covers all calls up to 237.
}

pub fn is_subscription(&self) -> bool {
matches!(
self,
Expand Down
3 changes: 3 additions & 0 deletions rpc/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ pub enum RpcError {
#[error("Transaction {0} not found")]
TransactionNotFound(TransactionId),

#[error("Method unavailable. Disabled through RPC flags.")]
UnauthorizedMethod,

#[error("Method unavailable. Run the node with the --utxoindex argument.")]
NoUtxoIndex,

Expand Down
1 change: 1 addition & 0 deletions rpc/macros/src/core/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod service;
19 changes: 19 additions & 0 deletions rpc/macros/src/core/service.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn, Path};

pub fn auth(attr: TokenStream, item: TokenStream) -> TokenStream {
let api_op = parse_macro_input!(attr as Path);
let mut func = parse_macro_input!(item as ItemFn);

let check = syn::parse2(quote! {
if !self.flags.has_enabled(#api_op) {
// As macro processing happens after async_trait processing its wrapped with async_trait return type
return std::boxed::Box::pin(std::future::ready(Err(RpcError::UnauthorizedMethod)));
}
})
.unwrap();

func.block.stmts.insert(0, check);
quote!(#func).into()
}
6 changes: 6 additions & 0 deletions rpc/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
mod core;
mod grpc;
mod handler;
mod wrpc;
Expand Down Expand Up @@ -45,3 +46,8 @@ pub fn build_grpc_server_interface(input: TokenStream) -> TokenStream {
pub fn test_wrpc_serializer(input: TokenStream) -> TokenStream {
wrpc::test::build_test(input)
}

#[proc_macro_attribute]
pub fn auth(attr: TokenStream, item: TokenStream) -> TokenStream {
core::service::auth(attr, item)
}
1 change: 1 addition & 0 deletions rpc/service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ kaspa-p2p-flows.workspace = true
kaspa-p2p-lib.workspace = true
kaspa-perf-monitor.workspace = true
kaspa-rpc-core.workspace = true
kaspa-rpc-macros.workspace = true
kaspa-txscript.workspace = true
kaspa-utils.workspace = true
kaspa-utils-tower.workspace = true
Expand Down
44 changes: 44 additions & 0 deletions rpc/service/src/flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use kaspa_rpc_core::api::ops::RpcApiOps;

// Struct to manage flags as a combined bitmask
#[derive(Debug)]
pub struct Flags {
bitmask: u128,
}

impl Flags {
// Create an empty flag set
pub fn new() -> Self {
Flags { bitmask: 0 }
}

// Adds a flag
pub fn add(&mut self, op: RpcApiOps) {
self.bitmask |= op.bitmask();
}

// Removes a flag
pub fn remove(&mut self, op: RpcApiOps) {
self.bitmask &= !op.bitmask();
}

// Check if a flag is enabled
pub fn has_enabled(&self, op: RpcApiOps) -> bool {
(self.bitmask & op.bitmask()) != 0
}

// Create a flag set from a slice of operations
pub fn from_ops(ops: &[RpcApiOps]) -> Self {
let mut permissions = Flags::new();
for &op in ops {
permissions.add(op);
}
permissions
}
}

impl From<u128> for Flags {
fn from(bitmask: u128) -> Self {
Flags { bitmask }
}
}
1 change: 1 addition & 0 deletions rpc/service/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod collector;
pub mod converter;
pub mod flags;
pub mod service;
Loading

0 comments on commit 167a1c3

Please sign in to comment.