auth.rs
Overview
This file implements a token-based authorization mechanism designed to authenticate external messages within the system. It provides the creation, verification, and authorization of cryptographic tokens tied to specific token issuers, which represent wallet owners of certain blockchain-related contracts (BM and BK wallets). The tokens use ed25519 signatures to ensure integrity and authenticity. The file also manages caching of signing public keys to optimize performance and includes runtime flags to enable or disable authentication dynamically.
The core components include:
Definition of
TokenIssuerandTokenstructs.Token generation and verification routines using ed25519 signatures.
Async methods to retrieve signing public keys by interacting with blockchain contracts.
Caching and expiration logic for signing keys.
Runtime control of authorization requirements.
Test cases for token lifecycle and verification scenarios.
Entities and Structures
TokenIssuer
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)]
#[serde(rename_all = "snake_case")]
pub enum TokenIssuer {
Bm(String),
Bk(String),
}
Purpose: Represents the originator of a token. It is either a Block Manager (BM) or Block Keeper (BK) wallet owner, identified by their public key string.
Serialization: Uses
snake_casenaming convention for JSON.
Token
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Token {
pub unsigned: String, // UNIX timestamp in ms until which the token remains valid
pub signature: String, // Hex-encoded ed25519 signature of `unsigned`
pub issuer: TokenIssuer,
}
Fields:
unsigned: The expiration timestamp (in ms) of the token.signature: Hex-encoded ed25519 signature over theunsignedstring.issuer: TheTokenIssuerthat issued the token.
TokenVerificationResult
#[derive(Debug, PartialEq, Eq)]
pub enum TokenVerificationResult {
Ok,
TokenMalformed,
InvalidSignature,
Expired,
}
Represents possible outcomes of token verification.
AccountRequest
pub struct AccountRequest {
pub address: String,
pub response: oneshot::Sender<anyhow::Result<Option<tvm_block::Account>>>,
}
Used to asynchronously request blockchain account information.
Contains the
addressto query and aoneshotchannel to send back the result.
WalletAddress
#[derive(Deserialize)]
struct WalletAddress {
wallet: String,
}
Deserialization struct for extracting wallet address from contract responses.
Constants and Globals
TOKEN_TTL: Token time-to-live in seconds (default 300), read from environment variable.EXT_MESSAGE_AUTH_REQUIRED: Atomic boolean flag indicating if external message authorization is enabled.SIGN_KEY_CACHE: Cache mappingTokenIssuerto a tuple of (signing public key string, expiration time).SIGN_KEY_CACHE_TTL: Duration for caching signing keys (60 seconds).
Key Functions and Methods
Token::new(secret: &str, issuer: TokenIssuer) -> Result<Self, anyhow::Error>
Creates a new Token by signing the expiration timestamp with the provided secret key.
Parameters:
secret: Hex-encoded 32-byte secret key for signing.issuer: The issuingTokenIssuer.
Returns: A
Tokeninstance with a freshly signed expiration timestamp.Errors: Returns an error if the secret key hex decoding or signing fails.
Usage Example:
let token = Token::new(&secret_hex_key, TokenIssuer::Bm("bm_pubkey".to_string()))?;
Token::verify(&self, signing_pubkey: Option<String>) -> TokenVerificationResult
Verifies the token's signature and validity against the provided signing public key.
Parameters:
signing_pubkey: Optional hex-encoded 32-byte public key string.
Returns: One of the
TokenVerificationResultvariants.Verification Steps:
Decode signature and public key from hex.
Parse
unsignedtimestamp and check expiration.Verify signature over the
unsignedtimestamp.
Notes: Returns
TokenMalformedif decoding fails orunsignedis not a valid timestamp.Usage Example:
let result = token.verify(Some(public_hex_key));
match result {
TokenVerificationResult::Ok => println!("Valid token"),
_ => println!("Invalid token"),
}
Token::authorize(&self, account_request_tx: mpsc::Sender<AccountRequest>) -> TokenVerificationResult
Performs asynchronous authorization by retrieving the signing public key for the issuer and verifying the token.
Parameters:
account_request_tx: Tokio mpsc sender channel to request account data.
Returns:
TokenVerificationResultafter verification.Behavior:
If authorization is disabled (
is_auth_required()returns false), returnsOk.Otherwise, fetches signing public key via
get_signing_pubkey.Verifies the token with the obtained public key.
Usage: Used in async contexts for validating tokens requiring blockchain data.
async fn request_account(address: &str, account_request_tx: mpsc::Sender<AccountRequest>) -> anyhow::Result<Option<tvm_block::Account>>
Asynchronously requests a blockchain account for a given address via the provided channel.
Parameters:
address: Blockchain address string.account_request_tx: Channel to sendAccountRequest.
Returns: Result wrapping an optional
tvm_block::Accountinstance.Usage: Internal utility for fetching account state.
async fn get_signing_pubkey(issuer: &TokenIssuer, account_request_tx: mpsc::Sender<AccountRequest>) -> anyhow::Result<Option<String>>
Retrieves and caches the signing public key associated with a TokenIssuer.
Parameters:
issuer: The token issuer (BM or BK).account_request_tx: Channel to send account requests.
Returns: Optional hex-encoded signing public key string.
Process:
Checks the cache for a valid signing key.
If absent or expired, calls the appropriate contract root ABI to get the wallet address.
Fetches the wallet account and decodes the signing public key.
Updates the cache on success.
Interaction: Uses blockchain client context and contracts defined in
root_contractsmodule.Errors: Propagates errors using
anyhow.
Authentication Control Functions
is_auth_required() -> bool
Returns whether external message authorization is currently enabled.force_auth()
Enables authorization enforcement.disable_auth()
Disables authorization enforcement.update_ext_message_auth_flag_from_files()
Reads specific files in/workdirto enable or disable the authorization flag dynamically.
Implementation Details and Algorithms
Token Expiration: Tokens are valid until a UNIX timestamp (in milliseconds) stored as a string in
unsigned. The timestamp is signed by the issuer's secret key.Signature Scheme: Uses ed25519 signatures (ed25519_dalek crate) over the expiration timestamp string.
Caching: Signing keys are cached with expiration to reduce blockchain queries, stored in a concurrent
RwLock<HashMap>.Blockchain Interaction: Uses
tvm_clientandsdk_wrapperto call smart contract functions that return wallet addresses, then fetches wallet accounts to extract signing keys.Atomic Flag: Authorization requirement is controlled via an atomic boolean, which can be toggled at runtime or via presence of specific files.
Async Design: Blockchain account requests and signing key retrieval are asynchronous, using Tokio's channels and async/await.
Error Handling: Uses
anyhow::Resultfor error propagation, logging traces for diagnostic purposes.
Interaction with Other Modules
Depends on:
root_contractsmodule for contract ABIs and addresses (BK_CONTRACT_ROOT_ABI,BM_CONTRACT_ROOT_ABI, etc.)owner_walletmodule for decoding signing keys (decode_signing_pubkey).tvm_blockcrate for blockchain account representation.tvm_clientcrate for blockchain client context and ABI interaction.sdk_wrapperfor managing contract accounts and local function execution.Utilities like
normalize_addressandnow_plus_n_secsfrom the local crate.
Provides token authorization logic used by components handling external messages requiring authentication.
Visual Diagram
classDiagram
class TokenIssuer {
<<enum>>
+Bm(pubkey: String)
+Bk(pubkey: String)
}
class Token {
+unsigned: String
+signature: String
+issuer: TokenIssuer
+new(secret: &str, issuer: TokenIssuer) Token
+verify(signing_pubkey: Option<String>) TokenVerificationResult
+authorize(account_request_tx: Sender<AccountRequest>) async TokenVerificationResult
}
class AccountRequest {
+address: String
+response: oneshot::Sender<Result<Option<Account>>>
}
class TokenVerificationResult {
<<enum>>
+Ok
+TokenMalformed
+InvalidSignature
+Expired
}
Token *-- TokenIssuer: uses
Token ..> TokenVerificationResult: returns
Token --> AccountRequest: interacts via
AccountRequest ..> "tvm_block::Account": async fetch
This diagram illustrates the relationships between key structs and enums in this file, showing how Token depends on TokenIssuer, produces TokenVerificationResult, and interacts asynchronously with AccountRequest to fetch blockchain account data.
Testing
Contains multiple async tests verifying:
Token creation and valid verification.
Token expiration handling.
Invalid signature detection.
Behavior when authorization is disabled.
Handling of malformed token signatures.
Uses mutex locking to serialize test execution.
Generates ephemeral ed25519 keypairs for signing and verification tests.
Environment Variables and Runtime Flags
TOKEN_TTL: Controls the token expiration duration in seconds.EXT_MESSAGE_AUTH_REQUIRED: Enables or disables external message authorization.Runtime flags can also be toggled by presence of /workdir/ext_message_auth.enable or /workdir/ext_message_auth.disable files.