Skip to main content

keygen_rs/
lib.rs

1use client::{Client, ClientOptions};
2use config::get_config;
3use errors::Error;
4use license::{License, SchemeCode};
5use serde::{Deserialize, Serialize};
6
7use crate::config::KeygenConfig;
8
9pub(crate) mod certificate;
10pub(crate) mod client;
11pub(crate) mod decryptor;
12pub(crate) mod verifier;
13
14pub mod component;
15pub mod config;
16pub mod entitlement;
17pub mod errors;
18pub mod group;
19pub mod license;
20pub mod license_file;
21pub mod machine;
22pub mod machine_file;
23pub mod service;
24
25// Management features only available with "token" feature flag
26#[cfg(feature = "token")]
27pub mod environment;
28#[cfg(feature = "token")]
29pub mod policy;
30#[cfg(feature = "token")]
31pub mod product;
32#[cfg(feature = "token")]
33pub mod release;
34#[cfg(feature = "token")]
35pub mod token;
36#[cfg(feature = "token")]
37pub mod user;
38#[cfg(feature = "token")]
39pub mod webhook;
40
41// Distribution modules (only available with "token" feature flag)
42#[cfg(feature = "token")]
43pub mod arch;
44#[cfg(feature = "token")]
45pub mod artifact;
46#[cfg(feature = "token")]
47pub mod channel;
48#[cfg(feature = "token")]
49pub mod package;
50#[cfg(feature = "token")]
51pub mod platform;
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub(crate) struct KeygenRelationshipData {
55    pub r#type: String,
56    pub id: String,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub(crate) struct KeygenRelationship {
61    #[serde(default)]
62    pub data: Option<KeygenRelationshipData>,
63    #[serde(default)]
64    pub links: Option<serde_json::Value>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize, Default)]
68pub(crate) struct KeygenRelationships {
69    #[serde(default)]
70    pub policy: Option<KeygenRelationship>,
71    #[serde(default)]
72    pub account: Option<KeygenRelationship>,
73    #[serde(default)]
74    pub product: Option<KeygenRelationship>,
75    #[serde(default)]
76    pub group: Option<KeygenRelationship>,
77    #[serde(default)]
78    pub owner: Option<KeygenRelationship>,
79    #[serde(default)]
80    pub users: Option<KeygenRelationship>,
81    #[serde(default)]
82    pub machines: Option<KeygenRelationship>,
83    #[serde(default)]
84    pub environment: Option<KeygenRelationship>,
85    #[serde(default)]
86    pub license: Option<KeygenRelationship>,
87    #[serde(default)]
88    pub release: Option<KeygenRelationship>,
89    // Use flatten to capture any other relationship fields we don't explicitly handle
90    #[serde(flatten)]
91    pub other: std::collections::HashMap<String, serde_json::Value>,
92}
93
94impl KeygenRelationships {
95    /// Extracts the ID from a relationship field
96    pub(crate) fn extract_id(rel: &Option<KeygenRelationship>) -> Option<String> {
97        rel.as_ref()
98            .and_then(|r| r.data.as_ref().map(|d| d.id.clone()))
99    }
100
101    pub(crate) fn policy_id(&self) -> Option<String> {
102        Self::extract_id(&self.policy)
103    }
104
105    pub(crate) fn account_id(&self) -> Option<String> {
106        Self::extract_id(&self.account)
107    }
108
109    pub(crate) fn product_id(&self) -> Option<String> {
110        Self::extract_id(&self.product)
111    }
112
113    pub(crate) fn group_id(&self) -> Option<String> {
114        Self::extract_id(&self.group)
115    }
116
117    pub(crate) fn owner_id(&self) -> Option<String> {
118        Self::extract_id(&self.owner)
119    }
120
121    pub(crate) fn environment_id(&self) -> Option<String> {
122        Self::extract_id(&self.environment)
123    }
124
125    pub(crate) fn license_id(&self) -> Option<String> {
126        Self::extract_id(&self.license)
127    }
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub(crate) struct KeygenResponseData<T> {
132    pub id: String,
133    pub r#type: String,
134    pub attributes: T,
135    pub relationships: KeygenRelationships,
136}
137
138/// Validates a license key
139///
140/// # Example
141/// ```
142/// #[tokio::main]
143/// async fn main() -> Result<(), Error> {
144///     dotenv().ok();
145///     config::set_config(KeygenConfig {
146///         api_url: env::var("KEYGEN_API_URL").expect("KEYGEN_API_URL must be set"),
147///         account: env::var("KEYGEN_ACCOUNT").expect("KEYGEN_ACCOUNT must be set"),
148///         product: env::var("KEYGEN_PRODUCT").expect("KEYGEN_PRODUCT must be set"),
149///         license_key: Some(env::var("KEYGEN_LICENSE_KEY").expect("KEYGEN_LICENSE_KEY must be set")),
150///         public_key: Some(env::var("KEYGEN_PUBLIC_KEY").expect("KEYGEN_PUBLIC_KEY must be set")),
151///         ..KeygenConfig::default()
152///     });
153///
154///     let fingerprint = machine_uid::get().unwrap_or("".into());
155///     let license = keygen_rs::validate(&[fingerprint]).await?;
156///     println!("License validated successfully: {:?}", license);
157///     Ok(())
158/// }
159/// ```
160pub async fn validate(fingerprints: &[String], entitlements: &[String]) -> Result<License, Error> {
161    let config = get_config()?;
162    validate_with_config(config, fingerprints, entitlements).await
163}
164
165pub async fn validate_with_config(
166    config: KeygenConfig,
167    fingerprints: &[String],
168    entitlements: &[String],
169) -> Result<License, Error> {
170    let client = Client::new(ClientOptions::from(config.clone()))?;
171    let response = client.get("me", None::<&()>).await?;
172    let profile: license::LicenseResponse<()> = serde_json::from_value(response.body)?;
173    License::from(profile.data)
174        .with_config(config)
175        .validate_key(fingerprints, entitlements)
176        .await
177}
178
179/// Verifies a signed key based on a given scheme
180///
181/// Supported schemes are:
182/// - Ed25519Sign
183///
184/// # Example
185/// ```
186/// #[tokio::main]
187/// async fn main() {
188///     dotenv().ok();
189///     let (public_key, signed_key) =
190///         generate_signed_license_key("4F5D3B-0FB8B2-6871BC-5D3EB3-4885B7-V3".to_string());
191///     config::set_config(KeygenConfig {
192///         api_url: env::var("KEYGEN_API_URL").expect("KEYGEN_API_URL must be set"),
193///         account: env::var("KEYGEN_ACCOUNT").expect("KEYGEN_ACCOUNT must be set"),
194///         product: env::var("KEYGEN_PRODUCT").expect("KEYGEN_PRODUCT must be set"),
195///         license_key: Some(env::var("KEYGEN_LICENSE_KEY").expect("KEYGEN_LICENSE_KEY must be set")),
196///         public_key: Some(public_key.clone()),
197///         ..KeygenConfig::default()
198///     });
199///
200///     println!("Signed key: {:?}", signed_key);
201///     if let Ok(data) = keygen_rs::verify(SchemeCode::Ed25519Sign, &signed_key) {
202///       println!("License verified: {:?}", String::from_utf8_lossy(&data));
203///     } else {
204///       println!("License verification failed");
205///     }
206/// }
207#[must_use = "verification result should be checked"]
208pub fn verify(scheme: SchemeCode, signed_key: &str) -> Result<Vec<u8>, Error> {
209    let config = get_config()?;
210    verify_with_config(&config, scheme, signed_key)
211}
212
213#[must_use = "verification result should be checked"]
214pub fn verify_with_config(
215    config: &config::KeygenConfig,
216    scheme: SchemeCode,
217    signed_key: &str,
218) -> Result<Vec<u8>, Error> {
219    License::from_signed_key(scheme, signed_key)
220        .with_config(config.clone())
221        .verify()
222}