From d08f2aa368237462c84d354412bee668f0fd487f Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 29 Mar 2024 14:47:29 -0400 Subject: [PATCH 1/3] Support account name, comment, description, service when adding items to the keychain --- security-framework-sys/src/item.rs | 1 + security-framework/src/item.rs | 47 ++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/security-framework-sys/src/item.rs b/security-framework-sys/src/item.rs index 9fbfc128..005d464c 100644 --- a/security-framework-sys/src/item.rs +++ b/security-framework-sys/src/item.rs @@ -66,6 +66,7 @@ extern "C" { pub static kSecAttrAccessGroupToken: CFStringRef; pub static kSecAttrAuthenticationType: CFStringRef; + pub static kSecAttrDescription: CFStringRef; pub static kSecAttrPath: CFStringRef; pub static kSecAttrPort: CFStringRef; pub static kSecAttrProtocol: CFStringRef; diff --git a/security-framework/src/item.rs b/security-framework/src/item.rs index b23c170b..7bd30e47 100644 --- a/security-framework/src/item.rs +++ b/security-framework/src/item.rs @@ -536,8 +536,16 @@ impl SearchResult { pub struct ItemAddOptions { /// The value (by ref or data) of the item to add, required. pub value: ItemAddValue, + /// Optional kSecAttrAccount attribute. + pub account_name: Option, + /// Optional kSecAttrComment attribute. + pub comment: Option, + /// Optional kSecAttrDescription attribute. + pub description: Option, /// Optional kSecAttrLabel attribute. pub label: Option, + /// Optional kSecAttrService attribute. + pub service: Option, /// Optional keychain location. pub location: Option, } @@ -545,7 +553,22 @@ pub struct ItemAddOptions { impl ItemAddOptions { /// Specifies the item to add. #[must_use] pub fn new(value: ItemAddValue) -> Self { - Self{ value, label: None, location: None } + Self{ value, label: None, location: None, service: None, account_name: None, comment: None, description: None } + } + /// Specifies the `kSecAttrAccount` attribute. + pub fn set_account_name(&mut self, account_name: impl Into) -> &mut Self { + self.account_name = Some(account_name.into()); + self + } + /// Specifies the `kSecAttrComment` attribute. + pub fn set_comment(&mut self, comment: impl Into) -> &mut Self { + self.comment = Some(comment.into()); + self + } + /// Specifies the `kSecAttrDescription` attribute. + pub fn set_description(&mut self, description: impl Into) -> &mut Self { + self.description = Some(description.into()); + self } /// Specifies the `kSecAttrLabel` attribute. pub fn set_label(&mut self, label: impl Into) -> &mut Self { @@ -557,6 +580,11 @@ impl ItemAddOptions { self.location = Some(location); self } + /// Specifies the `kSecAttrService` attribute. + pub fn set_service(&mut self, service: impl Into) -> &mut Self { + self.service = Some(service.into()); + self + } /// Populates a `CFDictionary` to be passed to pub fn to_dictionary(&self) -> CFDictionary { let mut dict = CFMutableDictionary::from_CFType_pairs(&[]); @@ -592,11 +620,26 @@ impl ItemAddOptions { }, } } - + let account_name = self.account_name.as_deref().map(CFString::from); + if let Some(account_name) = &account_name { + dict.add(&unsafe { kSecAttrAccount }.to_void(), &account_name.to_void()); + } + let comment = self.comment.as_deref().map(CFString::from); + if let Some(comment) = &comment { + dict.add(&unsafe { kSecAttrDescription }.to_void(), &comment.to_void()); + } + let description = self.description.as_deref().map(CFString::from); + if let Some(description) = &description { + dict.add(&unsafe { kSecAttrDescription }.to_void(), &description.to_void()); + } let label = self.label.as_deref().map(CFString::from); if let Some(label) = &label { dict.add(&unsafe { kSecAttrLabel }.to_void(), &label.to_void()); } + let service = self.service.as_deref().map(CFString::from); + if let Some(service) = &service { + dict.add(&unsafe { kSecAttrService }.to_void(), &service.to_void()); + } dict.to_immutable() } From 9ce85c276f740eee05436159e206c266578585aa Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Fri, 29 Mar 2024 22:12:49 -0400 Subject: [PATCH 2/3] Add support for searching by access groups. --- security-framework/src/item.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/security-framework/src/item.rs b/security-framework/src/item.rs index 7bd30e47..b57ef9de 100644 --- a/security-framework/src/item.rs +++ b/security-framework/src/item.rs @@ -240,6 +240,12 @@ impl ItemSearchOptions { self } + /// Search for an item with a specific access group. + pub fn access_group(&mut self, access_group: &str) -> &mut Self { + self.access_group = Some(CFString::new(access_group)); + self + } + /// Sets `kSecAttrAccessGroup` to `kSecAttrAccessGroupToken` #[inline(always)] pub fn access_group_token(&mut self) -> &mut Self { @@ -538,6 +544,8 @@ pub struct ItemAddOptions { pub value: ItemAddValue, /// Optional kSecAttrAccount attribute. pub account_name: Option, + /// Optional kSecAttrAccessGroup attribute. + pub access_group: Option, /// Optional kSecAttrComment attribute. pub comment: Option, /// Optional kSecAttrDescription attribute. @@ -553,13 +561,18 @@ pub struct ItemAddOptions { impl ItemAddOptions { /// Specifies the item to add. #[must_use] pub fn new(value: ItemAddValue) -> Self { - Self{ value, label: None, location: None, service: None, account_name: None, comment: None, description: None } + Self{ value, label: None, location: None, service: None, account_name: None, comment: None, description: None, access_group: None } } /// Specifies the `kSecAttrAccount` attribute. pub fn set_account_name(&mut self, account_name: impl Into) -> &mut Self { self.account_name = Some(account_name.into()); self } + /// Specifies the `kSecAttrAccessGroup` attribute. + pub fn set_access_group(&mut self, access_group: impl Into) -> &mut Self { + self.access_group = Some(access_group.into()); + self + } /// Specifies the `kSecAttrComment` attribute. pub fn set_comment(&mut self, comment: impl Into) -> &mut Self { self.comment = Some(comment.into()); @@ -624,6 +637,10 @@ impl ItemAddOptions { if let Some(account_name) = &account_name { dict.add(&unsafe { kSecAttrAccount }.to_void(), &account_name.to_void()); } + let access_group = self.access_group.as_deref().map(CFString::from); + if let Some(access_group) = &access_group { + dict.add(&unsafe { kSecAttrAccessGroup }.to_void(), &access_group.to_void()); + } let comment = self.comment.as_deref().map(CFString::from); if let Some(comment) = &comment { dict.add(&unsafe { kSecAttrDescription }.to_void(), &comment.to_void()); From 92fcf0d8b31a01e0ab10cc0806ea97bf65584b77 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Sat, 30 Mar 2024 09:13:20 -0400 Subject: [PATCH 3/3] fixup: kSecAttrDescription -> kSecAttrComment for comment --- security-framework-sys/src/item.rs | 1 + security-framework/src/item.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/security-framework-sys/src/item.rs b/security-framework-sys/src/item.rs index 005d464c..4b4c52ed 100644 --- a/security-framework-sys/src/item.rs +++ b/security-framework-sys/src/item.rs @@ -66,6 +66,7 @@ extern "C" { pub static kSecAttrAccessGroupToken: CFStringRef; pub static kSecAttrAuthenticationType: CFStringRef; + pub static kSecAttrComment: CFStringRef; pub static kSecAttrDescription: CFStringRef; pub static kSecAttrPath: CFStringRef; pub static kSecAttrPort: CFStringRef; diff --git a/security-framework/src/item.rs b/security-framework/src/item.rs index b57ef9de..0c17e154 100644 --- a/security-framework/src/item.rs +++ b/security-framework/src/item.rs @@ -643,7 +643,7 @@ impl ItemAddOptions { } let comment = self.comment.as_deref().map(CFString::from); if let Some(comment) = &comment { - dict.add(&unsafe { kSecAttrDescription }.to_void(), &comment.to_void()); + dict.add(&unsafe { kSecAttrComment }.to_void(), &comment.to_void()); } let description = self.description.as_deref().map(CFString::from); if let Some(description) = &description {