Skip to content

Instantly share code, notes, and snippets.

@rriemann
Last active January 14, 2023 22:06
Show Gist options
  • Save rriemann/fca8598a61ec91f5e06ff41198f53431 to your computer and use it in GitHub Desktop.
Save rriemann/fca8598a61ec91f5e06ff41198f53431 to your computer and use it in GitHub Desktop.
Jekyll Markdown source code for the Mastodon Privacy Policy Generator at https://blog.riemann.cc/projects/mastodon-privacy-policy-generator/
layout title date last_modified_at image links featured accent_color accent_image caption description keywords
project
Mastodon Privacy Policy Generator
13 Nov 2022
2022-11-22 11:15
path
/assets/img/projects/mastodon-privacy-policy-generator.jpg
true
#3f61cc
/assets/img/sidebar-bg-eu.jpg
GDPR compliance tool for Mastodon
The Mastodon Privacy Policy Generator helps Mastodon admins to adapt the pretty good privacy policy from https://eupolicy.social for the GDPR compliance of their instance. Give it a try!
Mastodon Privacy Policy Generator
GDPR
GDPR compliance
data protection notice
privacy policy
#mastoLegal

This page does not offer legal advice. For legal advice, ask a lawyer. I am just an expert. 😉 {:.note title="Disclaimer"}

GDPR Applicability and Mastodon

Even if your Mastodon instance is hosted outside of the European Union (EU), you may need to comply with its General Data Protection Regulation (GDPR). {:.note title="Attention"}

Make a quick test whether you need to comply with GDPR. If you do not have to comply with GDPR, I recommend you to comply anyway, because it helps you to be transparent about how you run your instance and offer users control over their data.

You do not have to comply with GDPR if you can tick all boxes (GDPR Art. 2(2)(c)):

  • My instance hosts only my account and of family and friends.
  • My instance does not contribute to a commercial activity.
  • My instance has "Allow unauthenticated access to public timeline" disabled in the admin settings.
  • My instance has "Enable profile directory" disabled in the admin settings.

You do need to comply with GDPR if you can tick one box (GDPR Art. 3):

  • My instance welcomes also accounts of natural persons residing in the EU.
  • My instance runs on a server hosted in the EU.
  • My instance federates with instances hosted in the EU.1

If you need to comply with GDPR, you need carry out a number of tasks, some of them regularly. One simple step is to upload already a comprehensive data protection notice to inform website visitors, users and other Fediverse participants about the data that your instance processes.

Generator

Most private-sector instances run the identical code of Mastodon and don't encourage any specific use beyond the generic user-controlled micro-blogging. In that case, I recommend you to use this Mastodon data protection notice generator to create a first draft and add, if necessary, anything that is missing. Most likely, national obligations (such as German TMG law) apply on top. Please check below how to help if you like to contribute. Ask a lawyer if you are not sure.

Credits:

<script src="/assets/js/vue.global.prod.js"></script> <script src="/assets/js/beautify.min.js"></script> <script src="/assets/js/beautify-html.min.js"></script>

{% comment %}eupolicy.social

{% raw %}

<style> .output textarea { width: 100%; } </style> <script type="module"> const { createApp } = Vue; createApp({ data() { return { generatorVersion: 'v1.1 as of 22/11/2022', instanceName: 'instance.social', instanceMail: 'mail@instance.social', instanceDonationLink: 'https://donation-provider.com/your-instance', instanceCommunity: '[instance Community]', instanceTopic: 'mainly linked to [instance topic]', instanceAdminsLocation: 'Your_City', instanceServerProvider: 'Hosting_Provider, Provider_City', instanceServerProviderLink: 'https://hosting-provider.de', instanceMailProvider: 'Inbox_Provider, Provider_City', instanceMailProviderLink: 'https://inbox-provider.com', instanceDonationProviderWithStripe: false, instanceDonationProviderLink: 'https://donation-provider.com', instanceDonationProvider: 'Donation_Provider, Provider_City', instanceNotifications: 'Notifications_Provider, Provider_City', instanceNotificationsLink: 'https://www.notifications-provider.com', lastUpdated: new Date().toLocaleDateString("en-GB"), beautify_options: { "indent_size": "4", "indent_char": " ", "max_preserve_newlines": "5", "preserve_newlines": true, "keep_array_indentation": false, "break_chained_methods": false, "indent_scripts": "normal", "brace_style": "collapse", "space_before_conditional": true, "unescape_strings": false, "jslint_happy": false, "end_with_newline": false, "wrap_line_length": "80", "indent_inner_html": false, "comma_first": false, "e4x": false, "indent_empty_lines": false } } }, methods: { async updateOutput(event) { await this.$nextTick(); if(event) { if (event.target.type == 'checkbox') { localStorage?.setItem(event.target.id, event.target.checked); } else if (event.target.value) { localStorage?.setItem(event.target.id, event.target.value); } } this.$refs.outputTextarea.innerHTML = html_beautify(this.$refs.notice.innerHTML, this.beautify_options); }, resetForm() { this.$refs.form.reset(); localStorage.clear(); } }, async mounted() { this.$refs.form.querySelectorAll("input").forEach((input) => { this.$root[input.id] = localStorage?.getItem(input.id) || this.$root[input.id]; if (input.type == 'checkbox') { input.checked = localStorage?.getItem(input.id) || input.checked; } else if (input.value) { input.value = localStorage?.getItem(input.id) || input.value; } }); this.updateOutput(); } }).mount('#app') </script>
Instance Name
Instance Community
Instance Topic
…that our users typically employ for networking, socialising and discussing ideas…
Instance E-Mail
Instance Administrative Location
Instance Donation URL
Instance Donation Provider
based on Stripe
  <div class="form-group">
    <label class="form-control-label" for="instanceDonationProviderLink">Instance Donation Provider URL</label>
    <input type="text" class="form-control" id="instanceDonationProviderLink" v-model="instanceDonationProviderLink" v-on:keyup="updateOutput" placeholder="https://donation-provider.com">
  </div>

  <div class="form-group">
    <label class="form-control-label" for="instanceServerProvider">Instance Hosting Provider</label>
    <input type="text" class="form-control" id="instanceServerProvider" v-model="instanceServerProvider" v-on:keyup="updateOutput" placeholder="Hosting_Provider, Provider_City">
  </div>
  <div class="form-group">
    <label class="form-control-label" for="instanceServerProviderLink">Instance Hosting Provider URL</label>
    <input type="text" class="form-control" id="instanceServerProviderLink" v-model="instanceServerProviderLink" v-on:keyup="updateOutput" placeholder="https://hosting-provider.de">
  </div>
  <div class="form-group">
    <label class="form-control-label" for="instanceNotifications">Instance E-Mail Notifications Provider</label>
    <input type="text" class="form-control" id="instanceNotifications" v-model="instanceNotifications" v-on:keyup="updateOutput" placeholder="Notifications_Provider, Provider_City">
  </div>
  <div class="form-group">
    <label class="form-control-label" for="instanceNotificationsLink">Instance E-Mail Notifications Provider URL</label>
    <input type="text" class="form-control" id="instanceNotificationsLink" v-model="instanceNotificationsLink" v-on:keyup="updateOutput" placeholder="https://www.notifications-provider.com">
  </div>
  <div class="form-group">
    <label class="form-control-label" for="instanceMailProvider">Instance E-Mail Inbox Provider</label>
    <input type="text" class="form-control" id="instanceMailProvider" v-model="instanceMailProvider" v-on:keyup="updateOutput" placeholder="Inbox_Provider, Provider_City">
  </div>
  <div class="form-group">
    <label class="form-control-label" for="instanceMailProviderLink">Instance E-Mail Inbox Provider URL</label>
    <input type="text" class="form-control" id="instanceMailProviderLink" v-model="instanceMailProviderLink" v-on:keyup="updateOutput" placeholder="https://inbox-provider.com">
  </div>
  <div class="form-group">
    <button class="btn btn-primary" v-on:click.prevent="resetForm()">clear all values</button>
  </div>

  <p>You use the Mastodon Privacy Policy Generator in {{generatorVersion}}.</p>
</form>

Data Protection Notice

Last updated: {{lastUpdated}}
<h3>1. Who we are</h3>

<p>{{instanceName}} (hereafter “we”, “us” or “the service”) is a non-profit <a v-bind:href="instanceDonationLink" target="_blank">donation-based</a> service that provides Mastodon social media accounts to the {{instanceCommunity}} (“you”). For the purpose of connecting and interacting with other Mastodon or Fediverse accounts, {{instanceName}} processes personal data from its users and users of other instances with whom they interact. This data protection notice describes what kind of personal data we process and on what legal basis, how long we keep it and why, as well as your rights with respect to your data.</p>

<p>Please do not hesitate to <a v-bind:href="'mailto:'+instanceMail">contact us via email</a> to for any question you might have with regard to this document or the processing of your personal data.</p>

<h3>2. Data protection summary</h3>

<p>We dedicate our Mastodon instance {{instanceName}} to the {{instanceCommunity}}. Our small team in {{instanceAdminsLocation}} provides the non-profit <a v-bind:href="instanceDonationLink" target="_blank">donation-based</a> service  on a voluntary basis to offer privacy-friendly micro-blogging accounts that our users typically employ for networking, socialising and discussing ideas {{instanceTopic}}.</p>

<p>For the purpose of ensuring a secure interaction, the website of {{instanceName}} stores the cookie ‘_mastodon_session’ with an identifier in the browser of registered and unregistered website visitors until they close their browser. For registered website visitors, the cookie ‘_session_id’ stores their login status until logout. Based on user consent, the website stores as well push notification settings in the browser. For security and debugging purposes, our server logs and stores visitor IP addresses for a maximum of 14 days. After that time, all IP addresses are removed.</p>

<p>{{instanceName}} processes profile data in the form of posts (toots), subscriptions (following), subscribers (follower), content appreciations (likes) and promotions (boosts) for publication in the context of profile and post pages. For registered users we process your profile data to deliver the service. For users of other instances, we store and display public profile data and rely here on our legitimate interest until they object and in any case when they delete their post or other data (unsubscribe, unlike, unboost).</p>

<p>If you contact {{instanceName}} via email or a  (private) post, we use any personal data that your message may contain (such as your email address or name) only to respond to your message. We archive your message for at most 12 months. You are of course free to use a nickname and a pseudonymous email address. We process messages from our registered users to deliver the service and rely for users of other instances on their consent. We may also process messages to comply with our legal obligations.</p>

<p>The following information is provided according to Articles 12, 13 and 14 of the <a href="http://eur-lex.europa.eu/legal-content/EN/TXT/?uri=uriserv:OJ.L_.2016.119.01.0001.01.ENG&amp;toc=OJ:L:2016:119:TOC" target="_blank">GDPR</a>.</p>

<h3>3. Data protection notice</h3>

For the purposes of this notice:

<p><strong>“User”</strong> means the natural person who interacts with {{instanceName}} directly via the website or indirectly via third-party applications compatible with ActivityPub.</p>
<p><strong>“Registered user”</strong> means the users with a Mastodon/ActivityPub profile.</p>
<p><strong>“Profile data”</strong> means their posts (toots), subscriptions (following), subscribers (follower) content appreciations (likes) and promotions (boosts), bookmarks and profile settings.</p>
<p><strong>“Subscribers”</strong> mean the accounts who follow a registered user.</p>
<p><strong>“Subscriptions”</strong> mean the accounts followed by a registered user.</p>

<p><strong>Scope and purpose of the processing</strong> This data protection notice applies to the processing of personal data for the provision of the microblogging service {{instanceName}}. It offers information on what personal data is processed and how it is processed, and on your data subject rights.</p>

<p><strong>Responsible for the processing</strong> The data controller is {{instanceName}} in its capacity as the provider of the service.</p>

<h4>Processing of personal data</h4>

<p>Personal data processed by {{instanceName}} is accessible to its administration team and, where necessary, to moderators on a need-to-know basis to ensure a secure operation. User content is published or delivered according to the user settings.
For the provision of the service, {{instanceName}} employs the data processors listed below that process personal data linked to the service solely on the written instruction from {{instanceName}}:</p>

<ul>
  <li>Server hosting from <a v-bind:href="instanceServerProviderLink" target="_blank">{{instanceServerProvider}}</a></li>
  <li>Email notifications delivery from <a v-bind:href="instanceNotificationsLink" target="_blank">{{instanceNotifications}}</a></li>
  <li>Email mailbox from <a v-bind:href="instanceMailProviderLink" target="_blank">{{instanceMailProvider}}</a></li>
  <li>Donations processing from <a v-bind:href="instanceDonationProviderLink" target="_blank">{{instanceDonationProvider}}</a><span v-if="instanceDonationProviderWithStripe"> together with <a href="https://stripe.com" target="_blank">Stripe Inc, Ireland</a></span></li>
</ul>

<strong>(a) Website Visitors</strong>

<p>The {{instanceName}} website and APIs process the IP addresses and other metadata (as specified below) of its visitors. When accessing the service, an encrypted connection to its web server is established. To display the content correctly on the visitor’s computer or other terminal devices, the following data is processed in accordance with the HTTP and TCP/IP protocol:</p>

<ul>
<li>IP address of the visitor’s internet connection</li>
<li>Operating system and operating system version of the visitor’s terminal</li>
<li>Web browser and browser version</li>
<li>Date of access to the website</li>
<li>HTTP cookie ‘_mastodon_session’ (for the duration of the website visit)</li>
</ul>

<p>This is required for the request, processing, and display of profile data and other content on the service. After each page visit, some of the data are stored in the account profile (if logged in) and server logs. These logs serve the purpose of maintenance and security of the server and personal data herein is deleted after 14 days. Furthermore, the website employs the cookie ‘_session_id’ to store the login status of registered users until logout or until a year after the last website visit. The website also stores the notifications settings in the browser. This processing is based on Article 6 (1) (b) of the  GDPR (‘processing is necessary for the performance of a contract’). This includes processing carried out in order to comply with the necessary technical and organisational protection measures.</p><p>

<strong>(b) Contributors from third-party services</strong>

</p><p>{{instanceName}} processes personal data when users of third-party services with ActivityPub support interact with its accounts. To enrich public profile pages with profile data, the following data is processed in accordance with the requirements of the ActivityPub protocol:</p>

<ul>
<li>IP address of the third-party service</li>
<li>Name of the user’s terminal software</li>
<li>Display name, account name, and profile picture</li>
<li>Current date and time</li>
<li>Profile data</li>
</ul>

<p>Private messages are not end-to-end encrypted and are therefore in principle accessible to the {{instanceName}} administrators.</p>

<p>This processing is necessary to provide a federated Mastodon instance and therefore based on Article 6 (1) (f) GDPR (‘processing is in our legitimate interest’) with the exception of personal data that is not required such as the display name and profile picture, the processing of which is based on Article 6 (1) (a) GDPR (‘consent’). {{instanceName}} stores profile data from subscriptions from compatible third-party services until it receives via that service or directly from the user a request for deletion or objection (unsubscribe, unlike, unboost).</p>

<strong>(c) Registered users</strong>

<p>{{instanceName}} limits registrations to users it assumes to be part of the {{instanceCommunity}}. {{instanceName}} reserves the right to refuse the provision of the service to any given user for any reason. To set up accounts and manage them subsequently, the following data from registered users is processed:</p>

<ul>
<li>Display name, account name, profile picture and header image </li>
<li>Login credentials consisting of an email address </li>
<li>Account description/biography </li>
<li>Content (toots), promoted, and appreciated content </li>
<li>Private messages (sent and received) </li>
<li>Subscriptions and their recent content </li>
<li>Logged-in sessions (terminal software, time and date, IP address) </li>
</ul>

<p>If registered users post profile data, the previous section applies accordingly. Note that updating subscribers and posting profile data (including profile mentions) requires disclosure of personal data to the service of the recipients. Depending on their Mastodon server’s geographic location, the disclosure can possibly involve international data transfers that are outside of {{instanceName}}’s control.</p>

<p>The registered user’s name and display name, profile picture and header, description, subscriptions, the own and promoted content, the content of their subscriptions, as well as their given feedback is published on their profile page.</p>

<p>This processing is based on Article 6 (1) (b) of the  GDPR (‘processing is necessary for the performance of a contract’) with the exception of personal data that is not required such as the display name and profile picture, the processing of which is based on Article 6 (1) (a) GDPR (‘consent’). Profile data is retained until the account is deleted.</p>

<p>Registered users are responsible for the use of their accounts and their own compliance with the GDPR as separate controllers when they post personal data of other people.</p>

<strong>(d) Contacting us by email</strong>

<p>If you contact {{instanceName}} via email or a Mastodon private message, any personal data that your message may contain (such as your email address or name) will only be used to respond to your message and may be stored as part of an email archive. You are of course free to use a nickname and a pseudonymous email address. Such personal data will be deleted after 12 months.</p>


<strong v-if="instanceDonationProvider">(e) Donations via {{instanceDonationProvider}}</strong>

<p v-if="instanceDonationProvider">Users can make donations for the operation of {{instanceName}} via {{instanceDonationProvider}}, which processes personal data according to their own data protection notice.</p>

<h4>Exercise your rights</h4>

<p>You have the right to request from us access to and rectification or erasure of your personal data or restriction of processing concerning you or, where applicable, the right to object to processing or the right to data portability. Where applicable, you also have the right to withdraw your consent at any time. Please note that withdrawing your consent does not affect the lawfulness of processing based on consent before its withdrawal.</p>

<p>Please find more information on your rights on the website of the <a href="https://ec.europa.eu/info/law/law-topic/data-protection/reform/rights-citizens/my-rights/what-are-my-rights_en" target="_blank">European Commission</a>.</p>

<p>You have, in any case, the right to lodge a complaint with the <a href="https://edpb.europa.eu/about-edpb/about-edpb/members_en" target="_blank">data protection authority</a> as a supervisory authority.</p>


<h3>Acknowledgments</h3>

<p>These terms are based on the <a href="https://eupolicy.social/terms" target="_blank">terms initially published by eupolicy.social</a> and made more accessible by the <a href="http://blog.riemann.cc/projects/mastodon-privacy-policy-generator/" target="_blank">Mastodon Privacy Policy Generator</a> in its version {{generatorVersion}}. This text is free to be adapted and remixed under the terms of the <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank">CC-BY (Attribution 4.0 International) license</a>.
</p>

Output

Notice in HTML format for Copy'n'Paste <textarea class="form-control" id="outputTextarea" ref="outputTextarea" rows="10"> </textarea>

{% endraw %}

How to Help {#how-to-help}

If you want to offer help, such as proposing an amendment, please reach out using the following means (by priority):

  1. Use Mastodon and make sure to tag me @rriemann@chaos.social AND use the hashtags #mastoLegal #MastodonPrivacyPolicyGenerator
  2. Use the Matrix channel #mastodon_admin:matrix.org (we may have a specific room for legal support later)
  3. Write me an email to robert-mastolegal@riemann.cc

Find the Jekyll Markdown source code for this page at https://gist.github.com/rriemann/fca8598a61ec91f5e06ff41198f53431.

TODO

  • find out the minimum necessary information to identify the controller (tip)
  • do not include bullet points on processors (mails, donation service, etc.) if form fields are empty (tip)
  • update regularly the template 😉

Changelog

  • 2023-01-14 v1.2 – use form data in section "Processing of personal data" subsection donation. Hide subsection if respective form field is empty.
  • 2022-11-22 v1.1 – change EDPS to Commission link (know your rights), replace "EU Policy Bubble" in the text by the respective form value
  • 2022-11-21 v1.0 – public release

Footnotes

  1. This is a tricky one. I assume that basically everyone would need to choose the cautious approach and tick this box and consequently be obliged to comply with GDPR. That's the price of a network that connects people across the globe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment