mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-09-02 09:09:17 +00:00
Honor credential reusable flag (#2157)
- propagate reusable through credential storage, CLI, RPC, routing, and tests - enforce reusable=false owner election with current topology - preserve proof-backed groups when refreshing credential ACL groups
This commit is contained in:
@@ -318,6 +318,7 @@ message GenerateCredentialRequest {
|
||||
int64 ttl_seconds = 4; // must be > 0: credential TTL in seconds (0 / omitted is invalid)
|
||||
optional string credential_id = 5; // optional: user-specified credential id, reused if already exists
|
||||
InstanceIdentifier instance = 6; // target network instance
|
||||
optional bool reusable = 7; // default true: allow multiple peers to reuse this credential
|
||||
}
|
||||
|
||||
message GenerateCredentialResponse {
|
||||
@@ -344,6 +345,7 @@ message CredentialInfo {
|
||||
bool allow_relay = 3;
|
||||
int64 expiry_unix = 4;
|
||||
repeated string allowed_proxy_cidrs = 5;
|
||||
optional bool reusable = 6;
|
||||
}
|
||||
|
||||
message ListCredentialsResponse {
|
||||
|
||||
@@ -11,6 +11,7 @@ message TrustedCredentialPubkey {
|
||||
bool allow_relay = 3; // whether this credential node can relay data
|
||||
int64 expiry_unix = 4; // expiry time (Unix timestamp)
|
||||
repeated string allowed_proxy_cidrs = 5; // allowed proxy_cidrs ranges
|
||||
optional bool reusable = 6; // whether multiple peers may use the same credential concurrently
|
||||
}
|
||||
|
||||
message TrustedCredentialPubkeyProof {
|
||||
|
||||
@@ -40,17 +40,24 @@ impl PeerGroupInfo {
|
||||
}
|
||||
|
||||
impl TrustedCredentialPubkeyProof {
|
||||
pub fn generate_credential_hmac(
|
||||
credential: &TrustedCredentialPubkey,
|
||||
pub fn generate_credential_hmac_from_bytes(
|
||||
credential_bytes: &[u8],
|
||||
network_secret: &str,
|
||||
) -> Vec<u8> {
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(network_secret.as_bytes())
|
||||
.expect("HMAC can take key of any size");
|
||||
mac.update(b"easytier credential proof");
|
||||
mac.update(&credential.encode_to_vec());
|
||||
mac.update(credential_bytes);
|
||||
mac.finalize().into_bytes().to_vec()
|
||||
}
|
||||
|
||||
pub fn generate_credential_hmac(
|
||||
credential: &TrustedCredentialPubkey,
|
||||
network_secret: &str,
|
||||
) -> Vec<u8> {
|
||||
Self::generate_credential_hmac_from_bytes(&credential.encode_to_vec(), network_secret)
|
||||
}
|
||||
|
||||
pub fn new_signed(credential: TrustedCredentialPubkey, network_secret: &str) -> Self {
|
||||
let credential_hmac = Self::generate_credential_hmac(&credential, network_secret);
|
||||
Self {
|
||||
@@ -63,6 +70,14 @@ impl TrustedCredentialPubkeyProof {
|
||||
let Some(credential) = self.credential.as_ref() else {
|
||||
return false;
|
||||
};
|
||||
self.verify_credential_hmac_with_bytes(&credential.encode_to_vec(), network_secret)
|
||||
}
|
||||
|
||||
pub fn verify_credential_hmac_with_bytes(
|
||||
&self,
|
||||
credential_bytes: &[u8],
|
||||
network_secret: &str,
|
||||
) -> bool {
|
||||
if self.credential_hmac.is_empty() {
|
||||
return false;
|
||||
}
|
||||
@@ -70,7 +85,7 @@ impl TrustedCredentialPubkeyProof {
|
||||
let mut mac = Hmac::<Sha256>::new_from_slice(network_secret.as_bytes())
|
||||
.expect("HMAC can take key of any size");
|
||||
mac.update(b"easytier credential proof");
|
||||
mac.update(&credential.encode_to_vec());
|
||||
mac.update(credential_bytes);
|
||||
mac.verify_slice(&self.credential_hmac).is_ok()
|
||||
}
|
||||
}
|
||||
@@ -300,6 +315,7 @@ mod tests {
|
||||
allow_relay: true,
|
||||
expiry_unix: 123456,
|
||||
allowed_proxy_cidrs: vec!["10.0.0.0/24".to_string()],
|
||||
reusable: Some(true),
|
||||
};
|
||||
let tc = TrustedCredentialPubkeyProof::new_signed(credential, "sec-1");
|
||||
|
||||
@@ -315,6 +331,7 @@ mod tests {
|
||||
allow_relay: false,
|
||||
expiry_unix: 1,
|
||||
allowed_proxy_cidrs: vec![],
|
||||
reusable: Some(true),
|
||||
};
|
||||
let tc = TrustedCredentialPubkeyProof::new_signed(credential, "sec-1");
|
||||
|
||||
@@ -322,4 +339,35 @@ mod tests {
|
||||
tampered.credential.as_mut().unwrap().allow_relay = true;
|
||||
assert!(!tampered.verify_credential_hmac("sec-1"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_trusted_credential_pubkey_hmac_with_raw_bytes() {
|
||||
let credential = TrustedCredentialPubkey {
|
||||
pubkey: vec![9u8; 32],
|
||||
groups: vec!["raw".to_string()],
|
||||
allow_relay: true,
|
||||
expiry_unix: 123456,
|
||||
allowed_proxy_cidrs: vec![],
|
||||
reusable: Some(true),
|
||||
};
|
||||
|
||||
let mut raw_credential_bytes = credential.encode_to_vec();
|
||||
prost::encoding::encode_key(
|
||||
9999,
|
||||
prost::encoding::WireType::Varint,
|
||||
&mut raw_credential_bytes,
|
||||
);
|
||||
prost::encoding::encode_varint(42, &mut raw_credential_bytes);
|
||||
|
||||
let proof = TrustedCredentialPubkeyProof {
|
||||
credential: Some(credential),
|
||||
credential_hmac: TrustedCredentialPubkeyProof::generate_credential_hmac_from_bytes(
|
||||
&raw_credential_bytes,
|
||||
"sec-1",
|
||||
),
|
||||
};
|
||||
|
||||
assert!(proof.verify_credential_hmac_with_bytes(&raw_credential_bytes, "sec-1"));
|
||||
assert!(!proof.verify_credential_hmac("sec-1"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user