SlideShare a Scribd company logo
1 of 94
Download to read offline
How to go serverless and
not violate the GDPR
Sebastian Schmidt and Rachel Myers
Berlin | November 20 - 21, 2018
GDPR
11 Chapters that regulate:
● Rights of data subjects
● Responsibilities for data controllers/processors
● Data transfers
● Penalties
GDPR
11 Chapters that regulate:
● Rights of data subjects
● Responsibilities for data controllers/processors
● Data transfers
● Penalties
Your users!
You!
Not giving
legal advice
Global Privacy Regulations
Global Privacy Regulations
Global Privacy Regulations
Develop
Grow
Realtime
Database
Authentication
Cloud Storage
Cloud
Firestore
Hosting
Cloud
Functions
Crashlytics
Performance
Test Lab
Analytics
Dynamic Links
Invites
App Indexing
Cloud
Messaging
Remote
Config
AdMob
AdWords
Predictions
Serverless
Concerns
Privacy
Concerns
Serverless
Concerns
Privacy
Concerns
User privacy
built on Serverless
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
Read your Horoscope!
(You have to be an EU citizen and 18+)
Username
Birthday
Country
sebastian
April 28th, 1990
Czech Republic
Read your Horoscope!
(You have to be an EU citizen and 18+)
Username
Birthday
Country
sebastian
April 28th, 1990
Czech Republic
← Open source
1. Account
information
1. Account
information
2. Photos
1. Account
information
2. Photos
3. Social data
Save only what you need.
Only as long as you
need.
SELECT COUNT(*)
FROM users
WHERE age BETWEEN (18, 25)
Keep the count. Don’t keep the data!
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
Delete user data
● When your app no longer needs the data
● When a user deletes their account
Not in
your
control
Not in
your
control
Cloud Functions for Firebase
programmatically connect
Firebase and Cloud
How does it work?
Event
emitted
Your code
executed
Function
triggered
How does it work?
Event
emitted
Your code
executed
Function
triggered
firestore.document(‘posts/a’).delete(
)
deleteData() function
We only
display the
top five!
No need to
save the
rest!
Delete the
rest!
Manage User Data
Privacy with Cloud
Functions
link.firebase.events/h1
App Engine lets you
invoke Cloud Functions
periodically!
link.firebase.events/h2
Remove user data
● When your app no longer needs the data
● When a user deletes their account
link.firebase.events/h
3
// functions/index.js
// Paths to user data to export or delete
exports.clearData = functions.auth.user().onDelete((event) => {
const uid = event.data.uid;
const dbPromise = clearDatabaseData(uid);
const storagePromise = clearStorageData(uid);
const firestorePromise = clearFirestoreData(uid);
const promises = [dbPromise, storagePromise, firestorePromise];
return Promise.all(promises).then(() =>
console.log(`Successfully removed data for user ${uid}.`)
);
});
link.firebase.events/h4
// functions/index.js
// Paths to user data to export or delete
exports.clearData = functions.auth.user().onDelete((event) => {
const uid = event.data.uid;
const dbPromise = clearDatabaseData(uid);
const storagePromise = clearStorageData(uid);
const firestorePromise = clearFirestoreData(uid);
const promises = [dbPromise, storagePromise, firestorePromise];
return Promise.all(promises).then(() =>
console.log(`Successfully removed data for user ${uid}.`)
);
});
link.firebase.events/h4
// functions/user_privacy.json
// Paths to user data to export or delete
{
"storage": {
"clearData": [
["myproject.appspot.com", "UID/sample_data.json"],
["myproject.appspot.com", "UID/avatar"]
],
},
"firestore": {
"clearData": [
{"collection": "users", "doc": "UID", "field": "last_name"},
{"collection": "admins", "doc": "UID"}
]
}
}
link.firebase.events/h4
// functions/index.js
// Paths to user data to export or delete
exports.clearData = functions.auth.user().onDelete((event) => {
const uid = event.data.uid;
const dbPromise = clearDatabaseData(uid);
const storagePromise = clearStorageData(uid);
const firestorePromise = clearFirestoreData(uid);
const promises = [dbPromise, storagePromise, firestorePromise];
return Promise.all(promises).then(() =>
console.log(`Successfully removed data for user ${uid}.`)
);
});
link.firebase.events/h4
// functions/user_privacy.json
// Paths to user data to export or delete
exports.clearData = functions.auth.user().onDelete((event) => {
const uid = event.data.uid;
const dbPromise = clearDatabaseData(uid);
const storagePromise = clearStorageData(uid);
const firestorePromise = clearFirestoreData(uid);
const promises = [dbPromise, storagePromise, firestorePromise];
return Promise.all(promises).then(() =>
console.log(`Successfully removed data for user ${uid}.`)
);
});
link.firebase.events/h4
// functions/index.js
// Deletes user data from the RealTime Database
const clearDatabaseData = (uid) => {
const paths = userPrivacyPaths.database.clearData;
const promises = [];
for (let i = 0; i < paths.length; i++) {
const path = replaceUID(paths[i], uid);
promises.push(db.ref(path).remove().catch((error) => {
// Avoid execution interuption.
console.error('Error deleting data at ', path, error);
}));
}
return Promise.all(promises).then(() => uid);
};
link.firebase.events/h4
// functions/index.js
// Deletes user data from the RealTime Database
const clearDatabaseData = (uid) => {
const paths = userPrivacyPaths.database.clearData;
const promises = [];
for (let i = 0; i < paths.length; i++) {
const path = replaceUID(paths[i], uid);
promises.push(db.ref(path).remove().catch((error) => {
// Avoid execution interuption.
console.error('Error deleting data at ', path, error);
}));
}
return Promise.all(promises).then(() => uid);
};
link.firebase.events/h4
// functions/index.js
// Deletes user data from the RealTime Database
const clearDatabaseData = (uid) => {
const paths = userPrivacyPaths.database.clearData;
const promises = [];
for (let i = 0; i < paths.length; i++) {
const path = replaceUID(paths[i], uid);
promises.push(db.ref(path).remove().catch((error) => {
// Avoid execution interuption.
console.error('Error deleting data at ', path, error);
}));
}
return Promise.all(promises).then(() => uid);
};
link.firebase.events/h4
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
// functions/index.js
// Exports user data
exports.exportData = functions.https.onRequest((req, res) => {
const uid = JSON.parse(req.body).uid;
const exportData = {};
const dbProm = exportDatabaseData(uid).then((dbData) => {
exportData.database = dbData;
});
const fsProm = exportFirestoreData(uid).then((fsData) => {
exportData.firestore = fsData;
});
const storageProm = exportStorageData(uid).then((storageRefs) => {
exportData.storage = storageRefs;
});
return Promise.all([dbProm, fsProm, storageProm]).then(() => {
console.log(`Success! Completed export for user ${uid}.`);
return uploadToStorage(uid, exportData);
}).then(() => res.json({exportComplete: true}));
});
link.firebase.events/h4
// functions/index.js
// Exports user data
exports.exportData = functions.https.onRequest((req, res) => {
const uid = JSON.parse(req.body).uid;
const exportData = {};
const dbProm = exportDatabaseData(uid).then((dbData) => {
exportData.database = dbData;
});
const fsProm = exportFirestoreData(uid).then((fsData) => {
exportData.firestore = fsData;
});
const storageProm = exportStorageData(uid).then((storageRefs) => {
exportData.storage = storageRefs;
});
return Promise.all([dbProm, fsProm, storageProm]).then(() => {
console.log(`Success! Completed export for user ${uid}.`);
return uploadToStorage(uid, exportData);
}).then(() => res.json({exportComplete: true}));
});
link.firebase.events/h4
// functions/index.js
// Exports user data
exports.exportData = functions.https.onRequest((req, res) => {
const uid = JSON.parse(req.body).uid;
const exportData = {};
const dbProm = exportDatabaseData(uid).then((dbData) => {
exportData.database = dbData;
});
const fsProm = exportFirestoreData(uid).then((fsData) => {
exportData.firestore = fsData;
});
const storageProm = exportStorageData(uid).then((storageRefs) => {
exportData.storage = storageRefs;
});
return Promise.all([dbProm, fsProm, storageProm]).then(() => {
console.log(`Success! Completed export for user ${uid}.`);
return uploadToStorage(uid, exportData);
}).then(() => res.json({exportComplete: true}));
});
link.firebase.events/h4
// functions/index.js
// Helper function that exports user data from RealTime Database.
const exportDatabaseData = (uid) => {
const paths = userPrivacyPaths.database.exportData;
const promises = [];
const exportData = {};
for (let i = 0; i < paths.length; i++) {
const path = replaceUID(paths[i], uid);
promises.push(db.ref(path).once('value').then((snapshot) => {
const read = snapshot.val();
if (read !== null) {
exportData[snapshot.key] = read;
}
}).catch((err) => {
console.error('Error exporting data: ', err);
}));
};
return Promise.all(promises).then(() => exportData);
};
link.firebase.events/h4
// functions/index.js
// Helper function that exports user data from RealTime Database.
const exportDatabaseData = (uid) => {
const paths = userPrivacyPaths.database.exportData;
const promises = [];
const exportData = {};
for (let i = 0; i < paths.length; i++) {
const path = replaceUID(paths[i], uid);
promises.push(db.ref(path).once('value').then((snapshot) => {
const read = snapshot.val();
if (read !== null) {
exportData[snapshot.key] = read;
}
}).catch((err) => {
console.error('Error exporting data: ', err);
}));
};
return Promise.all(promises).then(() => exportData);
};
firebase.events/q4
// functions/index.js
// Exports user data
exports.exportData = functions.https.onRequest((req, res) => {
const uid = JSON.parse(req.body).uid;
const exportData = {};
const dbProm = exportDatabaseData(uid).then((dbData) => {
exportData.database = dbData;
});
const fsProm = exportFirestoreData(uid).then((fsData) => {
exportData.firestore = fsData;
});
const storageProm = exportStorageData(uid).then((storageRefs) => {
exportData.storage = storageRefs;
});
return Promise.all([dbProm, fsProm, storageProm]).then(() => {
console.log(`Success! Completed export for user ${uid}.`);
return uploadToStorage(uid, exportData);
}).then(() => res.json({exportComplete: true}));
});
link.firebase.events/h4
service firebase.storage {
match /b/{bucket}/o {
match /exportData {
// Only allow access to exported data by the user
// who requested an export
match /{uid} {
allow read, write: if request.auth.uid == uid
}
match /{uid}/{path=**} {
allow read, write: if request.auth.uid == uid
}
}
}
}
firebase.events/q4
Remember that rules are ORed together.
✔
Simulated data access allowed
Delete and export are easier when
data’s nested under a user’s UID
$ firebase deploy ...
Done.
Manage User Data
Privacy with Cloud
Functions
link.firebase.events/h4
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
Client Application Storage
Client Application Storage
Client Storage
Client Storage
Security Rules
Security Rules Simulator
Security Rules
Emulators
link.firebase.events/h5
Security Rules Schema
Messages
PUBLIC
USER 2USER 1
Friends
Private
Messages
Friends
Private
ACTIVITY
USER 2USER 1
Log Log
Entry EntryEntry Entry
Messages
Rules Takeaways
● Never trust data from client apps
● Write rules with the Security Simulator
● Test rules with the Security Rules Emulator
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
Take a look at our data
retention policies
link.firebase.events/h6
Take a look at our data
retention policies
link.firebase.events/h7
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
Instance IDs
Unique for each app installation
123 234 345
Instance IDs
Same ID across restarts
123123 123
MON TUE
3rd 4th 5th
WED
Delete Instance ID data
with the Admin SDKs
link.firebase.events/h8
Backend stores data
for 2 weeks
Client keeps
data for 1 week
Backend keeps
backup for 2 weeks
Client keeps
data for 1 week
We will keep your data for 2 weeks.
AGREEDISAGREE
Unchecked
boxes
Comments
enabled
Comments
disabled
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
Separate Public
from
Private Dataservice cloud.firestore {
match /databases/{database}/documents {
match /users/{uid}/public {
allow read, write;
}
match /users/{uid}/private {
allow read, write:
if request.auth.uid == uid;
}
}
}
service cloud.firestore {
match /databases/{database}/documents {
match /public/{uid} {
allow read, write;
}
match /private/{uid} {
allow read, write:
if request.auth.uid == uid;
}
}
}
Separate Public
from
Private Data
Reduce the user data that you store
Manage user data with Cloud Functions:
Delete data you no longer need
Export data on request
Security Rules!
Inform users about data collection:
Storage Retention Policies
Firebase Instance IDs
Storing Privacy Settings
Keeping an Activity Log
const firestore = admin.firestore();
exports.activityLog = functions.firestore
.document('privacy/{uid}').onWrite(snap => {
const uid = context.params.uid;
const settings = snap.data();
settings['udpate_time'] =
admin.firestore.FieldValue.serverTimestamp();
firestore.collection(
`activity_log/${uid}/entries`
).add(settings);
});
link.firebase.events/h8
const firestore = admin.firestore();
exports.activityLog = functions.firestore
.document('privacy/{uid}').onWrite(snap => {
const uid = context.params.uid;
const settings = snap.data();
settings['udpate_time'] =
admin.firestore.FieldValue.serverTimestamp();
firestore.collection(
`activity_log/${uid}/entries`
).add(settings);
});
link.firebase.events/h8
match /activity_log/{uid} {
allow create: if request.auth.uid == uid;
allow update: if request.auth.uid == uid && resource == null;
allow delete: if false;
}
link.firebase.events/h9
Storing Privacy
Settings
with Firebaselink.firebase.events/h9
Let’s treat our users well!
● Respect user data
● Offer clear data policies
● Limit data intake
● Let users decide how to handle data
Thank you!
Rachel Myers, Firebase
GitHub & Twitter: @rachelmyers
Sebastian Schmidt, Firebase
GitHub: @schmidt-sebastian

More Related Content

What's hot

Engage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 TagEngage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 Tag
Webtrends
 

What's hot (20)

Event-Driven Systems With MongoDB
Event-Driven Systems With MongoDBEvent-Driven Systems With MongoDB
Event-Driven Systems With MongoDB
 
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
Michael Hackstein - NoSQL meets Microservices - NoSQL matters Dublin 2015
 
Users' Data Security in iOS Applications
Users' Data Security in iOS ApplicationsUsers' Data Security in iOS Applications
Users' Data Security in iOS Applications
 
google drive and the google drive sdk
google drive and the google drive sdkgoogle drive and the google drive sdk
google drive and the google drive sdk
 
APIs, APIs Everywhere!
APIs, APIs Everywhere!APIs, APIs Everywhere!
APIs, APIs Everywhere!
 
Utilizing Microsoft Graph API and Office 365 Management Activity API during s...
Utilizing Microsoft Graph API and Office 365 Management Activity API during s...Utilizing Microsoft Graph API and Office 365 Management Activity API during s...
Utilizing Microsoft Graph API and Office 365 Management Activity API during s...
 
Git as NoSQL
Git as NoSQLGit as NoSQL
Git as NoSQL
 
CQRS & event sourcing in the wild
CQRS & event sourcing in the wildCQRS & event sourcing in the wild
CQRS & event sourcing in the wild
 
PistonHead's use of MongoDB for Analytics
PistonHead's use of MongoDB for AnalyticsPistonHead's use of MongoDB for Analytics
PistonHead's use of MongoDB for Analytics
 
Engage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 TagEngage 2013 - Why Upgrade to v10 Tag
Engage 2013 - Why Upgrade to v10 Tag
 
SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!SharePoint Conference 2018 - APIs, APIs everywhere!
SharePoint Conference 2018 - APIs, APIs everywhere!
 
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
MongoDB .local Munich 2019: New Encryption Capabilities in MongoDB 4.2: A Dee...
 
Form1.vb
Form1.vbForm1.vb
Form1.vb
 
SwiftUI and Combine All the Things
SwiftUI and Combine All the ThingsSwiftUI and Combine All the Things
SwiftUI and Combine All the Things
 
Mongo db for C# Developers
Mongo db for C# DevelopersMongo db for C# Developers
Mongo db for C# Developers
 
Docker & Azure
Docker & AzureDocker & Azure
Docker & Azure
 
Mongo db updatedocumentusecases
Mongo db updatedocumentusecasesMongo db updatedocumentusecases
Mongo db updatedocumentusecases
 
HTML5 Gaming Payment Platforms
HTML5 Gaming Payment PlatformsHTML5 Gaming Payment Platforms
HTML5 Gaming Payment Platforms
 
Getting Started with Combine And SwiftUI
Getting Started with Combine And SwiftUIGetting Started with Combine And SwiftUI
Getting Started with Combine And SwiftUI
 
Ajax for dummies, and not only.
Ajax for dummies, and not only.Ajax for dummies, and not only.
Ajax for dummies, and not only.
 

Similar to Sebastian Schmidt, Rachel Myers - How To Go Serverless And Not Violate The GDPR - Codemotion Berlin 2018

Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
Anton Narusberg
 
BlackBerry DevCon 2011 - PhoneGap and WebWorks
BlackBerry DevCon 2011 - PhoneGap and WebWorksBlackBerry DevCon 2011 - PhoneGap and WebWorks
BlackBerry DevCon 2011 - PhoneGap and WebWorks
mwbrooks
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of us
OSCON Byrum
 
Introducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverIntroducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and server
Spike Brehm
 
#NewMeetup Performance
#NewMeetup Performance#NewMeetup Performance
#NewMeetup Performance
Justin Cataldo
 
JavaScript para Graficos y Visualizacion de Datos
JavaScript para Graficos y Visualizacion de DatosJavaScript para Graficos y Visualizacion de Datos
JavaScript para Graficos y Visualizacion de Datos
philogb
 
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
philogb
 
Evolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB StitchEvolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB Stitch
MongoDB
 

Similar to Sebastian Schmidt, Rachel Myers - How To Go Serverless And Not Violate The GDPR - Codemotion Berlin 2018 (20)

Android Froyo
Android FroyoAndroid Froyo
Android Froyo
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web Apps
 
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
SharePoint Saturday Belgium 2018 - APIs, APIs everywhere!
 
Android architecture components with cloud firestore
Android architecture components with cloud firestoreAndroid architecture components with cloud firestore
Android architecture components with cloud firestore
 
Android app development basics
Android app development basicsAndroid app development basics
Android app development basics
 
The Best Way to Become an Android Developer Expert with Android Jetpack
The Best Way to Become an Android Developer Expert  with Android JetpackThe Best Way to Become an Android Developer Expert  with Android Jetpack
The Best Way to Become an Android Developer Expert with Android Jetpack
 
BlackBerry DevCon 2011 - PhoneGap and WebWorks
BlackBerry DevCon 2011 - PhoneGap and WebWorksBlackBerry DevCon 2011 - PhoneGap and WebWorks
BlackBerry DevCon 2011 - PhoneGap and WebWorks
 
MongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDBMongoDB.local Atlanta: Introduction to Serverless MongoDB
MongoDB.local Atlanta: Introduction to Serverless MongoDB
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of us
 
Build Location Based App on bada
Build Location Based App on badaBuild Location Based App on bada
Build Location Based App on bada
 
Reduxing like a pro
Reduxing like a proReduxing like a pro
Reduxing like a pro
 
BP204 - Take a REST and put your data to work with APIs!
BP204 - Take a REST and put your data to work with APIs!BP204 - Take a REST and put your data to work with APIs!
BP204 - Take a REST and put your data to work with APIs!
 
Introducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverIntroducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and server
 
Introduction to Firebase on Android
Introduction to Firebase on AndroidIntroduction to Firebase on Android
Introduction to Firebase on Android
 
#NewMeetup Performance
#NewMeetup Performance#NewMeetup Performance
#NewMeetup Performance
 
JavaScript para Graficos y Visualizacion de Datos
JavaScript para Graficos y Visualizacion de DatosJavaScript para Graficos y Visualizacion de Datos
JavaScript para Graficos y Visualizacion de Datos
 
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJSJavaScript para Graficos y Visualizacion de Datos - BogotaJS
JavaScript para Graficos y Visualizacion de Datos - BogotaJS
 
Data Binding: Is It the Next Big Thing?
Data Binding: Is It the Next Big Thing?Data Binding: Is It the Next Big Thing?
Data Binding: Is It the Next Big Thing?
 
SOLID Principles
SOLID PrinciplesSOLID Principles
SOLID Principles
 
Evolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB StitchEvolving your Data Access with MongoDB Stitch
Evolving your Data Access with MongoDB Stitch
 

More from Codemotion

More from Codemotion (20)

Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
Fuzz-testing: A hacker's approach to making your code more secure | Pascal Ze...
 
Pompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending storyPompili - From hero to_zero: The FatalNoise neverending story
Pompili - From hero to_zero: The FatalNoise neverending story
 
Pastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storiaPastore - Commodore 65 - La storia
Pastore - Commodore 65 - La storia
 
Pennisi - Essere Richard Altwasser
Pennisi - Essere Richard AltwasserPennisi - Essere Richard Altwasser
Pennisi - Essere Richard Altwasser
 
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
Michel Schudel - Let's build a blockchain... in 40 minutes! - Codemotion Amst...
 
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
Richard Süselbeck - Building your own ride share app - Codemotion Amsterdam 2019
 
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
Eward Driehuis - What we learned from 20.000 attacks - Codemotion Amsterdam 2019
 
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 - Francesco Baldassarri  - Deliver Data at Scale - Codemotion Amsterdam 2019 -
Francesco Baldassarri - Deliver Data at Scale - Codemotion Amsterdam 2019 -
 
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
Martin Förtsch, Thomas Endres - Stereoscopic Style Transfer AI - Codemotion A...
 
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
Melanie Rieback, Klaus Kursawe - Blockchain Security: Melting the "Silver Bul...
 
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
Angelo van der Sijpt - How well do you know your network stack? - Codemotion ...
 
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
Lars Wolff - Performance Testing for DevOps in the Cloud - Codemotion Amsterd...
 
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
Sascha Wolter - Conversational AI Demystified - Codemotion Amsterdam 2019
 
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
Michele Tonutti - Scaling is caring - Codemotion Amsterdam 2019
 
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
Pat Hermens - From 100 to 1,000+ deployments a day - Codemotion Amsterdam 2019
 
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
James Birnie - Using Many Worlds of Compute Power with Quantum - Codemotion A...
 
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
Don Goodman-Wilson - Chinese food, motor scooters, and open source developmen...
 
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
Pieter Omvlee - The story behind Sketch - Codemotion Amsterdam 2019
 
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
Dave Farley - Taking Back “Software Engineering” - Codemotion Amsterdam 2019
 
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
Joshua Hoffman - Should the CTO be Coding? - Codemotion Amsterdam 2019
 

Recently uploaded

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
WSO2
 

Recently uploaded (20)

Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
Apidays Singapore 2024 - Scalable LLM APIs for AI and Generative AI Applicati...
 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
 
Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024Manulife - Insurer Transformation Award 2024
Manulife - Insurer Transformation Award 2024
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot ModelNavi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Navi Mumbai Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu SubbuApidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
Apidays Singapore 2024 - Modernizing Securities Finance by Madhu Subbu
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024FWD Group - Insurer Innovation Award 2024
FWD Group - Insurer Innovation Award 2024
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Architecting Cloud Native Applications
Architecting Cloud Native ApplicationsArchitecting Cloud Native Applications
Architecting Cloud Native Applications
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 

Sebastian Schmidt, Rachel Myers - How To Go Serverless And Not Violate The GDPR - Codemotion Berlin 2018

  • 1. How to go serverless and not violate the GDPR Sebastian Schmidt and Rachel Myers Berlin | November 20 - 21, 2018
  • 2.
  • 3. GDPR 11 Chapters that regulate: ● Rights of data subjects ● Responsibilities for data controllers/processors ● Data transfers ● Penalties
  • 4. GDPR 11 Chapters that regulate: ● Rights of data subjects ● Responsibilities for data controllers/processors ● Data transfers ● Penalties Your users! You!
  • 9.
  • 10.
  • 15.
  • 16. User privacy built on Serverless
  • 17. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 18. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 19. Read your Horoscope! (You have to be an EU citizen and 18+) Username Birthday Country sebastian April 28th, 1990 Czech Republic
  • 20. Read your Horoscope! (You have to be an EU citizen and 18+) Username Birthday Country sebastian April 28th, 1990 Czech Republic
  • 25. Save only what you need. Only as long as you need.
  • 26. SELECT COUNT(*) FROM users WHERE age BETWEEN (18, 25) Keep the count. Don’t keep the data!
  • 27. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 28. Delete user data ● When your app no longer needs the data ● When a user deletes their account
  • 29.
  • 32. Cloud Functions for Firebase programmatically connect Firebase and Cloud
  • 33. How does it work? Event emitted Your code executed Function triggered
  • 34. How does it work? Event emitted Your code executed Function triggered firestore.document(‘posts/a’).delete( ) deleteData() function
  • 35. We only display the top five! No need to save the rest!
  • 37. Manage User Data Privacy with Cloud Functions link.firebase.events/h1
  • 38. App Engine lets you invoke Cloud Functions periodically! link.firebase.events/h2
  • 39. Remove user data ● When your app no longer needs the data ● When a user deletes their account
  • 41. // functions/index.js // Paths to user data to export or delete exports.clearData = functions.auth.user().onDelete((event) => { const uid = event.data.uid; const dbPromise = clearDatabaseData(uid); const storagePromise = clearStorageData(uid); const firestorePromise = clearFirestoreData(uid); const promises = [dbPromise, storagePromise, firestorePromise]; return Promise.all(promises).then(() => console.log(`Successfully removed data for user ${uid}.`) ); }); link.firebase.events/h4
  • 42. // functions/index.js // Paths to user data to export or delete exports.clearData = functions.auth.user().onDelete((event) => { const uid = event.data.uid; const dbPromise = clearDatabaseData(uid); const storagePromise = clearStorageData(uid); const firestorePromise = clearFirestoreData(uid); const promises = [dbPromise, storagePromise, firestorePromise]; return Promise.all(promises).then(() => console.log(`Successfully removed data for user ${uid}.`) ); }); link.firebase.events/h4
  • 43. // functions/user_privacy.json // Paths to user data to export or delete { "storage": { "clearData": [ ["myproject.appspot.com", "UID/sample_data.json"], ["myproject.appspot.com", "UID/avatar"] ], }, "firestore": { "clearData": [ {"collection": "users", "doc": "UID", "field": "last_name"}, {"collection": "admins", "doc": "UID"} ] } } link.firebase.events/h4
  • 44. // functions/index.js // Paths to user data to export or delete exports.clearData = functions.auth.user().onDelete((event) => { const uid = event.data.uid; const dbPromise = clearDatabaseData(uid); const storagePromise = clearStorageData(uid); const firestorePromise = clearFirestoreData(uid); const promises = [dbPromise, storagePromise, firestorePromise]; return Promise.all(promises).then(() => console.log(`Successfully removed data for user ${uid}.`) ); }); link.firebase.events/h4
  • 45. // functions/user_privacy.json // Paths to user data to export or delete exports.clearData = functions.auth.user().onDelete((event) => { const uid = event.data.uid; const dbPromise = clearDatabaseData(uid); const storagePromise = clearStorageData(uid); const firestorePromise = clearFirestoreData(uid); const promises = [dbPromise, storagePromise, firestorePromise]; return Promise.all(promises).then(() => console.log(`Successfully removed data for user ${uid}.`) ); }); link.firebase.events/h4
  • 46. // functions/index.js // Deletes user data from the RealTime Database const clearDatabaseData = (uid) => { const paths = userPrivacyPaths.database.clearData; const promises = []; for (let i = 0; i < paths.length; i++) { const path = replaceUID(paths[i], uid); promises.push(db.ref(path).remove().catch((error) => { // Avoid execution interuption. console.error('Error deleting data at ', path, error); })); } return Promise.all(promises).then(() => uid); }; link.firebase.events/h4
  • 47. // functions/index.js // Deletes user data from the RealTime Database const clearDatabaseData = (uid) => { const paths = userPrivacyPaths.database.clearData; const promises = []; for (let i = 0; i < paths.length; i++) { const path = replaceUID(paths[i], uid); promises.push(db.ref(path).remove().catch((error) => { // Avoid execution interuption. console.error('Error deleting data at ', path, error); })); } return Promise.all(promises).then(() => uid); }; link.firebase.events/h4
  • 48. // functions/index.js // Deletes user data from the RealTime Database const clearDatabaseData = (uid) => { const paths = userPrivacyPaths.database.clearData; const promises = []; for (let i = 0; i < paths.length; i++) { const path = replaceUID(paths[i], uid); promises.push(db.ref(path).remove().catch((error) => { // Avoid execution interuption. console.error('Error deleting data at ', path, error); })); } return Promise.all(promises).then(() => uid); }; link.firebase.events/h4
  • 49. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 50. // functions/index.js // Exports user data exports.exportData = functions.https.onRequest((req, res) => { const uid = JSON.parse(req.body).uid; const exportData = {}; const dbProm = exportDatabaseData(uid).then((dbData) => { exportData.database = dbData; }); const fsProm = exportFirestoreData(uid).then((fsData) => { exportData.firestore = fsData; }); const storageProm = exportStorageData(uid).then((storageRefs) => { exportData.storage = storageRefs; }); return Promise.all([dbProm, fsProm, storageProm]).then(() => { console.log(`Success! Completed export for user ${uid}.`); return uploadToStorage(uid, exportData); }).then(() => res.json({exportComplete: true})); }); link.firebase.events/h4
  • 51. // functions/index.js // Exports user data exports.exportData = functions.https.onRequest((req, res) => { const uid = JSON.parse(req.body).uid; const exportData = {}; const dbProm = exportDatabaseData(uid).then((dbData) => { exportData.database = dbData; }); const fsProm = exportFirestoreData(uid).then((fsData) => { exportData.firestore = fsData; }); const storageProm = exportStorageData(uid).then((storageRefs) => { exportData.storage = storageRefs; }); return Promise.all([dbProm, fsProm, storageProm]).then(() => { console.log(`Success! Completed export for user ${uid}.`); return uploadToStorage(uid, exportData); }).then(() => res.json({exportComplete: true})); }); link.firebase.events/h4
  • 52. // functions/index.js // Exports user data exports.exportData = functions.https.onRequest((req, res) => { const uid = JSON.parse(req.body).uid; const exportData = {}; const dbProm = exportDatabaseData(uid).then((dbData) => { exportData.database = dbData; }); const fsProm = exportFirestoreData(uid).then((fsData) => { exportData.firestore = fsData; }); const storageProm = exportStorageData(uid).then((storageRefs) => { exportData.storage = storageRefs; }); return Promise.all([dbProm, fsProm, storageProm]).then(() => { console.log(`Success! Completed export for user ${uid}.`); return uploadToStorage(uid, exportData); }).then(() => res.json({exportComplete: true})); }); link.firebase.events/h4
  • 53. // functions/index.js // Helper function that exports user data from RealTime Database. const exportDatabaseData = (uid) => { const paths = userPrivacyPaths.database.exportData; const promises = []; const exportData = {}; for (let i = 0; i < paths.length; i++) { const path = replaceUID(paths[i], uid); promises.push(db.ref(path).once('value').then((snapshot) => { const read = snapshot.val(); if (read !== null) { exportData[snapshot.key] = read; } }).catch((err) => { console.error('Error exporting data: ', err); })); }; return Promise.all(promises).then(() => exportData); }; link.firebase.events/h4
  • 54. // functions/index.js // Helper function that exports user data from RealTime Database. const exportDatabaseData = (uid) => { const paths = userPrivacyPaths.database.exportData; const promises = []; const exportData = {}; for (let i = 0; i < paths.length; i++) { const path = replaceUID(paths[i], uid); promises.push(db.ref(path).once('value').then((snapshot) => { const read = snapshot.val(); if (read !== null) { exportData[snapshot.key] = read; } }).catch((err) => { console.error('Error exporting data: ', err); })); }; return Promise.all(promises).then(() => exportData); }; firebase.events/q4
  • 55. // functions/index.js // Exports user data exports.exportData = functions.https.onRequest((req, res) => { const uid = JSON.parse(req.body).uid; const exportData = {}; const dbProm = exportDatabaseData(uid).then((dbData) => { exportData.database = dbData; }); const fsProm = exportFirestoreData(uid).then((fsData) => { exportData.firestore = fsData; }); const storageProm = exportStorageData(uid).then((storageRefs) => { exportData.storage = storageRefs; }); return Promise.all([dbProm, fsProm, storageProm]).then(() => { console.log(`Success! Completed export for user ${uid}.`); return uploadToStorage(uid, exportData); }).then(() => res.json({exportComplete: true})); }); link.firebase.events/h4
  • 56. service firebase.storage { match /b/{bucket}/o { match /exportData { // Only allow access to exported data by the user // who requested an export match /{uid} { allow read, write: if request.auth.uid == uid } match /{uid}/{path=**} { allow read, write: if request.auth.uid == uid } } } } firebase.events/q4
  • 57. Remember that rules are ORed together. ✔ Simulated data access allowed
  • 58. Delete and export are easier when data’s nested under a user’s UID
  • 59. $ firebase deploy ... Done.
  • 60. Manage User Data Privacy with Cloud Functions link.firebase.events/h4
  • 61. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 69. Security Rules Schema Messages PUBLIC USER 2USER 1 Friends Private Messages Friends Private ACTIVITY USER 2USER 1 Log Log Entry EntryEntry Entry Messages
  • 70. Rules Takeaways ● Never trust data from client apps ● Write rules with the Security Simulator ● Test rules with the Security Rules Emulator
  • 71. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 72. Take a look at our data retention policies link.firebase.events/h6
  • 73. Take a look at our data retention policies link.firebase.events/h7
  • 74. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 75. Instance IDs Unique for each app installation 123 234 345
  • 76. Instance IDs Same ID across restarts 123123 123 MON TUE 3rd 4th 5th WED
  • 77. Delete Instance ID data with the Admin SDKs link.firebase.events/h8
  • 78. Backend stores data for 2 weeks Client keeps data for 1 week
  • 79. Backend keeps backup for 2 weeks Client keeps data for 1 week We will keep your data for 2 weeks. AGREEDISAGREE
  • 82. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 83. Separate Public from Private Dataservice cloud.firestore { match /databases/{database}/documents { match /users/{uid}/public { allow read, write; } match /users/{uid}/private { allow read, write: if request.auth.uid == uid; } } }
  • 84. service cloud.firestore { match /databases/{database}/documents { match /public/{uid} { allow read, write; } match /private/{uid} { allow read, write: if request.auth.uid == uid; } } } Separate Public from Private Data
  • 85.
  • 86.
  • 87. Reduce the user data that you store Manage user data with Cloud Functions: Delete data you no longer need Export data on request Security Rules! Inform users about data collection: Storage Retention Policies Firebase Instance IDs Storing Privacy Settings Keeping an Activity Log
  • 88. const firestore = admin.firestore(); exports.activityLog = functions.firestore .document('privacy/{uid}').onWrite(snap => { const uid = context.params.uid; const settings = snap.data(); settings['udpate_time'] = admin.firestore.FieldValue.serverTimestamp(); firestore.collection( `activity_log/${uid}/entries` ).add(settings); }); link.firebase.events/h8
  • 89. const firestore = admin.firestore(); exports.activityLog = functions.firestore .document('privacy/{uid}').onWrite(snap => { const uid = context.params.uid; const settings = snap.data(); settings['udpate_time'] = admin.firestore.FieldValue.serverTimestamp(); firestore.collection( `activity_log/${uid}/entries` ).add(settings); }); link.firebase.events/h8
  • 90. match /activity_log/{uid} { allow create: if request.auth.uid == uid; allow update: if request.auth.uid == uid && resource == null; allow delete: if false; } link.firebase.events/h9
  • 92. Let’s treat our users well!
  • 93. ● Respect user data ● Offer clear data policies ● Limit data intake ● Let users decide how to handle data
  • 94. Thank you! Rachel Myers, Firebase GitHub & Twitter: @rachelmyers Sebastian Schmidt, Firebase GitHub: @schmidt-sebastian