{"id":22496977,"url":"https://github.com/morebec/orkestra-privacy","last_synced_at":"2026-02-24T18:32:05.426Z","repository":{"id":49499699,"uuid":"359994077","full_name":"Morebec/orkestra-privacy","owner":"Morebec","description":"[READ ONLY] Orkestra Component providing Privacy utilities.","archived":false,"fork":false,"pushed_at":"2023-03-31T18:46:55.000Z","size":33,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"2.x","last_synced_at":"2025-04-09T03:51:09.434Z","etag":null,"topics":["gdpr","orkestra","php","privacy"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Morebec.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-21T01:09:40.000Z","updated_at":"2024-02-21T08:23:49.000Z","dependencies_parsed_at":"2024-12-06T20:25:17.022Z","dependency_job_id":null,"html_url":"https://github.com/Morebec/orkestra-privacy","commit_stats":{"total_commits":54,"total_committers":2,"mean_commits":27.0,"dds":0.01851851851851849,"last_synced_commit":"b4c8972e169351d0bad04751fdabb318688ae441"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/Morebec/orkestra-privacy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Morebec%2Forkestra-privacy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Morebec%2Forkestra-privacy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Morebec%2Forkestra-privacy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Morebec%2Forkestra-privacy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Morebec","download_url":"https://codeload.github.com/Morebec/orkestra-privacy/tar.gz/refs/heads/2.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Morebec%2Forkestra-privacy/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263099694,"owners_count":23413624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gdpr","orkestra","php","privacy"],"created_at":"2024-12-06T20:15:05.441Z","updated_at":"2026-02-24T18:32:05.388Z","avatar_url":"https://github.com/Morebec.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Privacy\nThe Privacy component proposes as set of interfaces to a `PersonalInformationStore` which can be used to centralise\nall Personally Identifiable Information (PII) of a user as well as storing additional data such as the reasons, the processing\noperations or the legal basis for storing such information.\n\nIt does not offer any implementation (other than an In Memory one for tests).\n\n\u003e For an actual implementation you can check out the official [PostgreSQLPersonalInformationStore]() which is a ready-made \nPostgreSQL implementation with support for encryption.\n\nOne of its primary goals is to provide a solution to Event Sourced Application to be able to remain immutable\nwhile allowing to have forgettable personal data.\n\n## Event Sourcing\nOne of the challenges regarding privacy regulation and Event Sourcing is that these privacy regulations allows\ndata subject to request to have their personal data removed from a system, where event sourced system are immutable in nature.\n\nThere are three common ways to solve this, with varying degrees of complexity and effectiveness:\n\n### Mutable Event Store\nOne possible way is to have a mutable event store, i.e. have an implementation of an event store that can have some of its events deleted.\nUsing a RDBMS or Mongo Db based event store technically allows one to do this quite easily.\nThe downside of this is that the \"audit for free\" promise of event sourcing is no longer possible as data\ncan be tempered with on a conceptual level, and from within the application.\n\nAnother downside of this strategy, is that it requires careful manipulation as changing the \"past\"\nmight have hard to predict side effects and render the application unstable or unusable.\n\n\n### Forgettable Event Payloads\nOne solution that tries to keep the event store immutable, is to avoid saving the data in the event store directly but instead, saving\nreferences to that data in another store secured with encryption:\n\n```javascript\nUserRegistered\n{\n    username: personal-data/x54tufojs536pzeqhelshvd7\n    fullname: personal-data/folshvd7js536pzeqhex54tu\n    password: personal-data/x134s5do6pzxqhelshvd8f\n}\n```\n\nThe challenges this strategy brings, is that the consumers of the events that requires access to the raw data,\nwill need to query the Personal Information Store, which adds complexity and might have an impact on performance.\n\n### Cryptographic Erasure\nCryptographic Erasure is a strategy where one encrypts the data before saving them in events\nand then stores the decryption key in another storage. When a user invokes the right to be forgotten, the\ndecryption key is simply discarded, rendering the information obsolete and no longer accessible.\nIt uses a similar mindset to the forgettable payloads the difference being that the actual data \nis kept in the event store in an encrypted form.\n\nIt has the same challenges as the *Forgettable Event Payloads* strategy as well as additional ones\nrelated to cryptography such as key rotation, or encryption weakening over time.\nIndeed, if a value was encrypted with an algorithm that is discovered to be weak or ineffective in the future\nthe data could still be recoverable.\n\nOne additional thing to note is that it is still unclear whether this is a legal measure since the data is\nnot technically deleted as required by the GDPR for example:\n\nEven in an encrypted form, personal information is still considered by the GDPR as Personal Data:\n\u003e \n\u003e *\"A confidentiality breach on personal data that were encrypted with a state-of-the-art algorithm is still a personal data breach, and has to be notified to the authority.\"*\n \n\n\n### Summary\nThe privacy component can be used to support both the Mutable Event Store and Cryptographic erasure\nas the Personal Information Store's API simply provides Find, Upsert and Delete operations.\nFrom a technical point of view it is advised to use the \"Forgettable Payload\" strategy as opposed \nto the other two mentioned as it is the one that provides the most future-proof and compliant solution.\n\nFor the performance hits it could present, multiple strategies can be performed to minimize this.\n\n## Installation\n\n```shell\ncomposer require morebec/orkestra-orkestra-privacy\n```\n\n## Usage\nIn order to fully use the component you will need an implementation of the `PersonalInformationStoreInterface`.\n\nThe official [PostgreSQLPersonalInformationStore]() is a ready-made implementation with support for encryption.\n\nThe storage works with some core concepts:\n- **Personal Data** represents a PII value such as a person's name, email address, phone number, birthdate etc as well as additional information regarding how the data was obtained, \n  for what purposes and for how long it should be retained.\n- **Personal Token** represents a token that is used internally by the application to identify a given person. Such as an internal UUID, in other words the owner of Personal Data. \n  For GDPR compliance this value should not be natural key and easily disposable, i.e. it should not be used to identify the natural person after an erasure of their data.\n  It serves as a namespace for a set of related values.\n- **Reference Token** Represents a reference to some given Personal Data that can be used in the application to reference the data contained in the store.\n- **Key** Corresponds to a key name associated with a piece personal data, e.g. email address, username, phone number etc.\n\n\n### Adding Personal Data\nTo add personal data to the store, one must use the `PersonalData` class or an implementation of the `PersonalDataInterface` and add it to the store:\n\n```php\nuse Morebec\\Orkestra\\Privacy\\PersonalData;\n \n$personalToken='usr123456';\n\n$data = new PersonalData($personalToken, 'emailAddress' /* key */, 'jane.doe@email.com' /* value */, 'registration_form' /* source */);\n$data-\u003edisposedAt($clock-\u003enow()-\u003eaddDays(15));\n\n// You can use this reference token to reference this personal data within the store in your application code.\n$referenceToken = $store-\u003eput($data);\n```\n\nThe value can be any PHP scalar primitive or array of scalar primitives.\n\n\u003e If an entry of Personal Data for the same `personal token` and `key` combination exists, it will be overwritten, \n\u003e see the Updating Data section for more information.\n\n### Retrieving Personal Data\nThe primary way of retrieving data is using the `reference token` of the data:\n```php\n$data = $store-\u003efindOneByReferenceToken($referenceToken);\n```\nThe returned value is an instance of `RecordedPersonalData` which is an immutable data structure around personal data.\n\nIf the data does not exist, `null` will be returned.\n\nIt is also possible to query the personal store for a specific `key` of a `personal token`:\n\n```php\n// Data can also be retrieved in an number of ways:\n$data = $store-\u003efindOneByKeyName('user123456', 'emailAddress'); \n```\n\nOne can also query by `personal token` to obtain all the related personal data present in the store: \n```php\n// Returns an array of all personal data related to a personal token.\n$data = $store-\u003efindByPersonalToken('user123456');\n\n```\n\nAgain, if the data does not exist, `null` will be returned.\n\n\n### Updating Data\nUpdating data can be performed simply by overwriting some personal data already existing data with the `put` method:\n\n```php\nuse Morebec\\Orkestra\\Privacy\\PersonalData;\n$data = new PersonalData('usr123456', 'emailAddress', 'jane.doe123@email.com', 'account_settings');\n\n$referenceToken = $store-\u003eput($data);\n```\n\u003e If the data did not exist, it will be equivalent to adding new data to the store.\n\nOr using the more explicit `replace` method:\n\n```php\nuse Morebec\\Orkestra\\Privacy\\PersonalData;\n$data = new PersonalData('usr123456', 'emailAddress', 'jane.doe123@email.com', 'account_settings');\n\n$referenceToken = $store-\u003ereplace($referenceToken, $data);\n```\n\n### Removing Data\nThere are two different ways to remove data form the store.\n\nThe first one is by specifying the `personal token` and the `key` combination:\n```php\n$store-\u003eremoveByKeyName('user123456', 'emailAddress');\n```\n\nThe other way is by specifying only the personal token with the `erase` method:\n```php\n// Deletes all records for a given personal token.\n$store-\u003eerase('user123456');\n```\n\nThis will have for effect of removing all personal information related to that `personal token`\n\n### Removing Disposable Data\nThe `PersonalDataInterface` has a value indicating the DateTime at which the data should be considered disposable.\nThis disposable nature is used in order not to store information indefinitely and without active use in the store.\nTo easily clean up the store from this expired data, this package contains a `DisposedPersonalDataRemoverInterface`:\n\n```php\n$remover-\u003erun(); // Will remove all disposable data as of the current date time.\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmorebec%2Forkestra-privacy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmorebec%2Forkestra-privacy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmorebec%2Forkestra-privacy/lists"}