Skip to content

Commit

Permalink
#50 ready for release
Browse files Browse the repository at this point in the history
  • Loading branch information
dsietz committed Sep 17, 2023
1 parent c9a6f77 commit e96433c
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 164 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,19 @@ For software development teams who implement Privacy by Design practices, this P
Here's whats new in 0.5.0:

We've made breaking changes in this newest version 0.5.0!
1. Due to the following reasons, we have dropped the `extractor` and `middleware` features for the Data Tracker Chain and Data Usage Agreement features. (Resolves Isses [#45](https://github.com/dsietz/pbd/issues/45), [#46](https://github.com/dsietz/pbd/issues/46), and [#49](https://github.com/dsietz/pbd/issues/49))
1. For the following reasons, we have dropped the `extractor` and `middleware` functionality for the Data Tracker Chain and Data Usage Agreement features. (Resolves Isses [#45](https://github.com/dsietz/pbd/issues/45), [#46](https://github.com/dsietz/pbd/issues/46), and [#49](https://github.com/dsietz/pbd/issues/49))
- focus on remaining a light-weight and flexible SDK
- incompatibility issues with `actix-web version ~4`
- High vulnerability found in `actix-web version 3.3.3`
- https://rustsec.org/advisories/RUSTSEC-2023-0034
- High vulnerability found in `actix-rt version 1.1.1`
- https://rustsec.org/advisories/RUSTSEC-2021-0124
- improved Mean Time To Resolve (MTTR) issues
- improved Mean Time To Resolve (MTTR) of issues
> NOTE: The examples will still provide demonstration of how to implement these features using `actix-web` without axtractors or middleware.
2. Updated `regex` version to fix security vulnerability
3. :boom: _New Feature_
Introduced the concept of a `Data Usage Policy` as part of the DUA feature. The DUP provides the extended detail that supports a DUA and implements the [FidesLang Taxonomy](https://ethyca.github.io/fideslang/).
(Delivers [#50](https://github.com/dsietz/pbd/issues/50))

## Features

Expand Down
13 changes: 9 additions & 4 deletions src/dua/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//! >
//! > *HTTP Header*
//! >
//! > Data-Usage-Agreement: [{"agreement_name":"billing","location":"www.dua.org/billing.pdf","agreed_dtm": 1553988607}]
//! > Data-Usage-Agreement: [{"agreement_name":"billing","location":"https://iStore.example.org/dup/v2/billing.pdf","agreed_dtm": 1553988607}]
//!
//!
//!
Expand All @@ -39,15 +39,20 @@
//! use pbd::dua::DUA;
//!
//! fn main() {
//! let serialized = r#"{ "agreement_name": "For Billing Purpose", "location": "www.dua.org/billing.pdf", "agreed_dtm": 1553988607 }"#;
//! let serialized = r#"{ "agreement_name": "For Billing Purpose", "location": "https://iStore.example.org/dup/v2/billing.pdf", "agreed_dtm": 1553988607 }"#;
//! let dua = DUA::from_serialized(&serialized);
//!
//! match dua.agreement_name.as_ref() {
//! "For Billing Purpose" => println!("We can use the data for sending a bill."),
//! _ => println!("Oops: We can't use the data this way!")
//! }
//!
//! // Addtionally, check which version of the agreement aligns with the agreed_dtm (if the agreement is under version control).
//! // Additionally, retrieve the Data Usage Policy that was agreed to using the DUA `location` attribute and
//! // check how the Data Usage Policy allows the processor (Actor) to use the data,
//! // (e.g.: The DUP may have only an associated usage of `essential.service.payment_processing`
//! // with an associated category of `user.financial.credit_card`, so the bank account information
//! // sent to the processor cannot be used to process a payment because the customer never agreed
//! // to have their bank account data used in that manner).
//! }
//! ```
//!
Expand All @@ -60,7 +65,7 @@ pub static DUA_HEADER: &str = "Data-Usage-Agreement";
pub struct DUA {
/// The common name of the Data Usage Agreement, (e.g.: For Billing Purpose)
pub agreement_name: String,
/// The URI where the version of the DUA (the signed Data Usage Policy) can be found, (e.g.: https://iStore.example.org/dua/v2/billing.pdf)
/// The URI where the version of the DUP (the agreed upon Data Usage Policy) can be found, (e.g.: https://iStore.example.org/dup/v2/billing.pdf)
pub location: String,
/// The Unix Epoch time when the DUA was agreed to
pub agreed_dtm: u64,
Expand Down
253 changes: 96 additions & 157 deletions src/dua/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,84 @@ impl DUP {
self.uses.insert(usage.get_key().clone(), usage);
}

/// Converts the policy to a human readable format as text
fn readable_description(&mut self, mut policy: String, line_feed: &str) -> String {
// Data Subjects
policy.push_str("Data will be collected from ");
match self.get_subjects().len() {
0 => {
policy.push_str("all types of users.");
}
_ => {
policy.push_str("the following types of users: ");
let count = self.get_subjects().len();
for (idx, subject) in self.get_subjects().iter().enumerate() {
policy.push_str(&subject.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

// Data Categories
policy.push_str("The data being collected will be ");
match self.get_categories().len() {
0 => {
policy.push_str("include all types of data.");
}
_ => {
policy.push_str("limited to the following data: ");
let count = self.get_categories().len();
for (idx, category) in self.get_categories().iter().enumerate() {
policy.push_str(&category.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

// Data Uses
policy.push_str("The data collected can be used for ");
match self.get_uses().len() {
0 => {
policy.push_str("various purposes.");
}
_ => {
policy.push_str("the following purposes: ");
let count = self.get_uses().len();
for (idx, usage) in self.get_uses().iter().enumerate() {
policy.push_str(&usage.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

return policy;
}

/// Converts the policy to a human readable format as html
/// _NOTE:_ You can apply custom styling by referencing the `class` attribute of the elements.
///
/// #Example
///
Expand Down Expand Up @@ -313,29 +390,29 @@ impl DUP {
/// .unwrap(),
/// );
///
/// print!("{}", dup.as_text());
///
/// /* General Marketing Policy
/// * (version: 1.0.0)
/// *
/// * This policy explains the manner in which your data will be used for marketing purposes.
/// *
/// * Data will be collected from the following types of users: Customer and Prospect.
/// * The data being collected will be limited to the following data: Browsing History and Media Consumption.
/// * The data collected can be used for the following purposes: Profiling for Advertising, Essential for Serving Ads and Marketing Email Communications.
/// print!("{}", dup.as_html());
///
/// /* <div class='dup' name='General Policy'>General Policy</div></br>
/// * <div class='dup-verion' name='1.0.1'>(version: 1.0.1)</div></br></br>
/// * <div class='dup-description' name='General Policy Description'><b>This is a high-level policy.</b></br></br>
/// * <p>
/// * Data will be collected from the following types of users: Customer and Prospect.</br>
/// * The data being collected will be limited to the following data: Browsing History and Media Consumption.</br>
/// * The data collected can be used for the following purposes: Profiling for Advertising, Essential for Serving Ads and Marketing Email Communications.</br>
/// * </p></div>
/// */
/// }
/// ```
pub fn as_html(&mut self) -> String {
let line_feed = "</br>";
let mut policy = String::new();
policy.push_str("<div className='dup' name='");
policy.push_str("<div class='dup' name='");
policy.push_str(&self.name);
policy.push_str("'>");
policy.push_str(&self.name);
policy.push_str("</div>");
policy.push_str(line_feed);
policy.push_str("<div className='dup-verion' name='");
policy.push_str("<div class='dup-verion' name='");
policy.push_str(&self.version);
policy.push_str("'>");
policy.push_str("(version: ");
Expand All @@ -344,87 +421,19 @@ impl DUP {
policy.push_str("</div>");
policy.push_str(line_feed);
policy.push_str(line_feed);
policy.push_str("<div className='dup-description' name='");
policy.push_str("<div class='dup-description' name='");
policy.push_str(&self.name);
policy.push_str(" Description'><b>");
policy.push_str(&self.description);
policy.push_str("</b>");
policy.push_str(line_feed);
policy.push_str(line_feed);
policy.push_str("<p>");

// Data Subjects
policy.push_str("Data will be collected from ");
match self.get_subjects().len() {
0 => {
policy.push_str("all types of users.");
}
_ => {
policy.push_str("the following types of users: ");
let count = self.get_subjects().len();
for (idx, subject) in self.get_subjects().iter().enumerate() {
policy.push_str(&subject.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

// Data Categories
policy.push_str("The data being collected will be ");
match self.get_categories().len() {
0 => {
policy.push_str("include all types of data.");
}
_ => {
policy.push_str("limited to the following data: ");
let count = self.get_categories().len();
for (idx, category) in self.get_categories().iter().enumerate() {
policy.push_str(&category.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

// Data Uses
policy.push_str("The data collected can be used for ");
match self.get_uses().len() {
0 => {
policy.push_str("various purposes.");
}
_ => {
policy.push_str("the following purposes: ");
let count = self.get_uses().len();
for (idx, usage) in self.get_uses().iter().enumerate() {
policy.push_str(&usage.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

policy = self.readable_description(policy, line_feed);
policy.push_str("</p>");
policy.push_str("</div>");

policy
}

Expand Down Expand Up @@ -506,77 +515,7 @@ impl DUP {
policy.push_str(line_feed);
policy.push_str(line_feed);

// Data Subjects
policy.push_str("Data will be collected from ");
match self.get_subjects().len() {
0 => {
policy.push_str("all types of users.");
}
_ => {
policy.push_str("the following types of users: ");
let count = self.get_subjects().len();
for (idx, subject) in self.get_subjects().iter().enumerate() {
policy.push_str(&subject.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

// Data Categories
policy.push_str("The data being collected will be ");
match self.get_categories().len() {
0 => {
policy.push_str("include all types of data.");
}
_ => {
policy.push_str("limited to the following data: ");
let count = self.get_categories().len();
for (idx, category) in self.get_categories().iter().enumerate() {
policy.push_str(&category.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}

// Data Uses
policy.push_str("The data collected can be used for ");
match self.get_uses().len() {
0 => {
policy.push_str("various purposes.");
}
_ => {
policy.push_str("the following purposes: ");
let count = self.get_uses().len();
for (idx, usage) in self.get_uses().iter().enumerate() {
policy.push_str(&usage.name);
let delimiter = match idx < count - 2 {
true => ", ",
false => match idx == count - 1 {
true => ".",
false => " and ",
},
};
policy.push_str(delimiter);
}
policy.push_str(line_feed);
}
}
policy = self.readable_description(policy, line_feed);

policy
}
Expand Down
2 changes: 1 addition & 1 deletion tests/output/policy.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<div className='dup' name='General Policy'>General Policy</div></br><div className='dup-verion' name='1.0.1'>(version: 1.0.1)</div></br></br><div className='dup-description' name='General Policy Description'><b>This is a high-level policy.</b></br></br>Data will be collected from the following types of users: Customer and Prospect.</br>The data being collected will be limited to the following data: Browsing History and Media Consumption.</br>The data collected can be used for the following purposes: Profiling for Advertising, Essential for Serving Ads and Marketing Email Communications.</br></div>
<div class='dup' name='General Policy'>General Policy</div></br><div class='dup-verion' name='1.0.1'>(version: 1.0.1)</div></br></br><div class='dup-description' name='General Policy Description'><b>This is a high-level policy.</b></br></br><p>Data will be collected from the following types of users: Customer and Prospect.</br>The data being collected will be limited to the following data: Browsing History and Media Consumption.</br>The data collected can be used for the following purposes: Profiling for Advertising, Essential for Serving Ads and Marketing Email Communications.</br></p></div>

0 comments on commit e96433c

Please sign in to comment.