Skip to content

Commit

Permalink
Merge pull request #1 from voxmedia/simplified
Browse files Browse the repository at this point in the history
Version 1!
  • Loading branch information
Brian Anderson authored Jun 29, 2020
2 parents 8e0dfe4 + 798f657 commit de51abb
Show file tree
Hide file tree
Showing 15 changed files with 524 additions and 94 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: Tests

on: [push]

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Install modules
run: yarn
- name: Run tests
run: yarn test
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 80
"printWidth": 120,
"arrowParens": "avoid"
}
85 changes: 43 additions & 42 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,51 @@
This code is responsible for supporting the legislation and implementing the frameworks concerning user privacy.



## Rough Diagram

_Initial sketch._


╔════════════════════════════════════════════════╗
║ CAPABILITIES ║
║ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we drop cookies? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we store a user-id? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we personalize content? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we personalize ads? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we use (e.g.) Permutive? │ ║
║ └──────────────────────────────────────┘ ║
║ ║
╚════════════════════════╦═══════════════════════╝
┌────────────────────────▼───────────────────────┐
│ <COMMON "CONCERT ADS PRIVACY" INTERFACE> │
└───────┬────────────────┬───────────────┬───────┘
│ │ │
┌───────▼──────┐ ┌───────▼──────┐ ┌──────▼───────┐
│ │ │ │ │ │
│ │ │ │ │Future Privacy│
│ CCPA │ │ GDPR │ │ Framework │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
└───────┬──────┘ └───────┬──────┘ └──────┬───────┘
│ │ │
│ │ │
┌───────▼──────┐ ┌───────▼──────┐ ┌──────▼───────┐
│ │ │ │ │ │
│Implementation│ │Implementation│ │Implementation│
│ Details │ │ Details │ │ Details │
│ │ │ │ │ │
│ │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
╔════════════════════════════════════════════════╗
║ CAPABILITIES ║
║ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we drop cookies? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we store a user-id? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we personalize content? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we personalize ads? │ ║
║ └──────────────────────────────────────┘ ║
║ ┌──────────────────────────────────────┐ ║
║ │ Can we use (e.g.) Permutive? │ ║
║ └──────────────────────────────────────┘ ║
║ ║
╚════════════════════════╦═══════════════════════╝
┌────────────────────────▼───────────────────────┐
│ <COMMON "CONCERT ADS PRIVACY" INTERFACE> │
└───────┬────────────────┬───────────────┬───────┘
│ │ │
┌───────▼──────┐ ┌───────▼──────┐ ┌──────▼───────┐
│ │ │ │ │ │
│ │ │ │ │Future Privacy│
│ CCPA │ │ GDPR │ │ Framework │
│ │ │ │ │ │
│ │ │ │ │ │
│ │ │ │ │ │
└───────┬──────┘ └───────┬──────┘ └──────┬───────┘
│ │ │
│ │ │
┌───────▼──────┐ ┌───────▼──────┐ ┌──────▼───────┐
│ │ │ │ │ │
│Implementation│ │Implementation│ │Implementation│
│ Details │ │ Details │ │ Details │
│ │ │ │ │ │
│ │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.0",
"description": "Vox Media's library for implementing data privacy frameworks",
"main": "index.js",
"license": "Apache",
"license": "Apache-2.0",
"url": "https://github.com/voxmedia/data-privacy-compliance",
"private": false,
"devDependencies": {
Expand Down
27 changes: 27 additions & 0 deletions src/frameworks/base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class FrameworkBase {
constructor() {}

get name() {
return this.constructor.name;
}

static isAutoLoaded() {
return true;
}

isApplicable() {
return true;
}

useConfig(someConfigs = {}) {}

supportedCapabilities() {
return [];
}

canAnswerCapability(capability) {
return this.supportedCapabilities().includes(capability);
}
}

module.exports = FrameworkBase;
51 changes: 51 additions & 0 deletions src/frameworks/ccpa_from_us_privacy_string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const FrameworkBase = require('./base');

/**
* Implements usprivacy string framework
* for more information on the US Privacy string see:
* https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/US%20Privacy%20String.md#us-privacy-string-format
*/
class CCPAFromUSPrivacyString extends FrameworkBase {
constructor() {
super();
this.usPrivacyString = '';
}

useConfig({ usp }) {
if (usp) {
this.usPrivacyString = ('' + usp).toUpperCase();
}
}

isApplicable() {
return !!this.usPrivacyString;
}

supportedCapabilities() {
return ['canUsePersonalInformationForTargeting', 'hasBeenNotifiedOfRights'];
}

canUsePersonalInformationForTargeting() {
return this.consentStringAllowsPersonalDataSale();
}

hasBeenNotifiedOfRights() {
return this.consentStringAcknowledgesUserHasBeenNotifiedOfRights();
}

consentStringAllowsPersonalDataSale() {
if (!this.supportedUsPrivacyStringVersion()) return true;
if (!this.consentStringAcknowledgesUserHasBeenNotifiedOfRights()) return true;
return this.usPrivacyString[2] !== 'Y';
}

consentStringAcknowledgesUserHasBeenNotifiedOfRights() {
return this.supportedUsPrivacyStringVersion() && this.usPrivacyString[1] === 'Y';
}

supportedUsPrivacyStringVersion() {
return this.usPrivacyString.length === 4 && this.usPrivacyString[0] === '1';
}
}

module.exports = CCPAFromUSPrivacyString;
23 changes: 23 additions & 0 deletions src/frameworks/ccpa_on_chorus.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const Cookie = require('../lib/cookie');
const FrameworkBase = require('./base');

class CcpaOnChorus extends FrameworkBase {
isApplicable() {
return !!window && !!window.Chorus;
}

supportedCapabilities() {
return ['canUsePersonalInformationForTargeting', 'hasBeenNotifiedOfRights'];
}

canUsePersonalInformationForTargeting() {
return !Cookie.hasCookie('_chorus_ccpa_consent_donotsell');
}

hasBeenNotifiedOfRights() {
// see https://github.com/voxmedia/sbn/commit/ce74ab006c89afe799afffa2a31137454d9e5bb3
return Cookie.hasCookie('_chorus_ccpa_consent');
}
}

module.exports = CcpaOnChorus;
6 changes: 6 additions & 0 deletions src/frameworks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const CcpaOnChorus = require('./ccpa_on_chorus');
const CcpaFromUsPrivacyString = require('./ccpa_from_us_privacy_string');

const defaultFrameworks = [CcpaOnChorus, CcpaFromUsPrivacyString];

module.exports = defaultFrameworks;
53 changes: 3 additions & 50 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,5 @@
class FrameworkBase {
canPersonalizeContent() {
return true;
}
canSendMetrics() {
return true;
}
canSendThirdPartyMetrics() {
return true;
}
}
const PrivacyCompliance = require('./privacy_compliance');

class GDPRFramework extends FrameworkBase {
canPersonalizeContent() {
return false;
}
}

class CCPAFramework extends FrameworkBase {
canPerformPersonalizedAdvertiserTargeting() {
return true;
}
}

const areAllTrue = (collection) => {
return collection.filter((capability) => !capability).length == 0;
module.exports = {
PrivacyCompliance,
};

class PrivacyCompliance {
constructor() {
this.frameworks = [];
this.frameworks.push(new CCPAFramework());
this.frameworks.push(new GDPRFramework());
}

canPerform(functionalities = []) {
return areAllTrue(
this.frameworks.map((f) => f.canPerform(functionalities))
);
}

canPerformPersonalizedAdvertiserTargeting() {
return areAllTrue(
this.frameworks.map((f) => f.canPerformPersonalizedAdvertiserTargeting())
);
}
canPersonalizeContent() {}
canSendMetrics() {}
canSendThirdPartyMetrics() {}
}

export default new PrivacyCompliance();
34 changes: 34 additions & 0 deletions src/lib/cookie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Gets all the cookies as a Map
*
* @returns Map of cookie values
*/
function getAllCookies() {
return new Map(document.cookie.split(';').map(cookie => cookie.trim().split('=')));
}

/**
* Checks if cookie exists
*
* @param {String} name name of cookie
* @return {Boolean} true of cookie is present
*/
function hasCookie(name) {
return getAllCookies().has(name);
}

/**
* Gets the cookie value
*
* @param {String} name name of cookie
* @return {String} the value of the cookie
*/
function getCookie(name) {
return getAllCookies().get(name);
}

module.exports = {
getAllCookies,
hasCookie,
getCookie,
};
Loading

0 comments on commit de51abb

Please sign in to comment.