private void HandlePushNotificationRecords(GDPRContentContext context, MobileContactPart part) { foreach (var pnRecord in part.MobileRecord) { pnRecord.UUIdentifier = pnRecord.UUIdentifier.GenerateUniqueString(); _pushNotificationRepository.Update(pnRecord); } }
private void HandleSmsRecords(GDPRContentContext context, SmsContactPart part) { foreach (var smsRecord in part.SmsRecord) { // Clear the phone number smsRecord.Sms = smsRecord.Sms.GenerateUniqueString(); _smsRecordRepository.Update(smsRecord); } }
// We cannot replace neither the email address nor the mobile phone number with default // strings. This is because the drivers will verify that those are unique when editing // the contacts. Any update there would then fail. // Thus we will hash a combination of the personal information and the UTC DateTime of the // anonymization/erasure. This should ensure that the resulting strings are unique. Since // the DateTime of the process may be logged somewhere, to prevent bruteforce discovery of // the original string (which would be comparatively simple in the case of the phone number) // rather than using a contant key, we generate a new one each time. private void HandleEmailRecords(GDPRContentContext context, EmailContactPart part) { foreach (var emailRecord in part.EmailRecord) { // Clear the email address emailRecord.Email = emailRecord.Email.GenerateUniqueString(); _emailRecordRepository.Update(emailRecord); } }
public bool ProcessIsAllowed(GDPRContentContext context) { if (context.GDPRPart == null) { // do nothing if the item is not configured for GDPR processing return(false); } // do nothing for protected items return(!context.GDPRPart.IsProtected); }
private void HandleMobilePushPart(GDPRContentContext context, MobilePushPart mpPart) { // clear the RecipientsList in all versions of the content. var partVersions = context.AllVersions // all the versions of the ContentItem being processed .Select(civ => civ .Parts .FirstOrDefault(pa => pa is MobilePushPart)) .Where(pa => pa != null) .Cast <MobilePushPart>(); foreach (var part in partVersions) { part.RecipientList = string.Empty; } }
private void HandlePart(GDPRContentContext context, SmsGatewayPart smsGatewayPart) { // clear the RecipientsList in all versions of the content. var partVersions = context.AllVersions // all the versions of the ContentItem .Select(civ => civ .Parts .FirstOrDefault(pa => pa is SmsGatewayPart)) .Where(pa => pa != null) .Cast <SmsGatewayPart>(); foreach (var part in partVersions) { part.RecipientList = string.Empty; } }
private void HandlerPart(GDPRContentContext context, UserPwdRecoveryPart part) { // clear the phone number from all versions var partVersions = context.AllVersions .Select(civ => civ .Parts .FirstOrDefault(pa => pa is UserPwdRecoveryPart)) .Where(pa => pa != null) .Cast <UserPwdRecoveryPart>(); foreach (var pv in partVersions) { pv.PhoneNumber = string.Empty; } }
private void HandleProviders(GDPRContentContext context, UserProvidersPart userProvidersPart) { // fetch the records directly, because the part does not contain them (rather, it contains // some "derived" objects) var providerRecords = _userProviderRepository .Fetch(x => x.UserId == context.ContentItem.Id); foreach (var record in providerRecords) { // ProviderUserId is the identifier for the user in the provider record.ProviderUserId = string.Empty; // ProviderUserData contains any additional information related to the user. This usually // is personal identifiable information. record.ProviderUserData = string.Empty; } }
private void HandleLatestUUID(GDPRContentContext context, UserPart part) { // the record may not exist var userRecord = part.Record; if (userRecord != null) // sanity check { var latestRecord = _latestUUIDForUserRepository .Fetch(luu => luu.UserPartRecord == userRecord) .FirstOrDefault(); if (latestRecord != null) { // we had recorded the UUID, so now we clear it latestRecord.UUID = latestRecord.UUID.GenerateUniqueString(); _latestUUIDForUserRepository.Update(latestRecord); } } }
private void HandleUser(GDPRContentContext context, UserPart userPart) { // Given the user, we should process every MobilePushPart ever, including // eventually deleted ones. We should check whether in its RecipientList there // is either the username or the email of the current user, and remove it if // that is the case. var comparisonArray = new string[] { userPart.UserName?.Trim(), userPart.Email?.Trim() }.Where(str => !string.IsNullOrWhiteSpace(str)); if (comparisonArray.Any()) // sanity check { var mpParts = _contentManager.Query <MobilePushPart>(VersionOptions.AllVersions) .Where <MobilePushPartRecord>(mppr => // this predicate replaces mppr.RecipientList != null && // !string.IsNullOrWhiteSpace(str) mppr.RecipientList != "") .List() // here the IContentQuery ends and the IEnumerable begins .Where(mpp => { // only those that may contain either username or email foreach (var compare in comparisonArray) { if (mpp.RecipientList .Contains(compare, StringComparison.OrdinalIgnoreCase)) { return(true); } } return(false); }); foreach (var mpPart in mpParts) { // RecipientList is a string of usernames or email addresses separated by // a new line. var split = mpPart.RecipientList .Split(new string[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); mpPart.RecipientList = string.Join(Environment.NewLine, split.Select(str => str.Trim()) // get rid of spare whitespace .Except(comparisonArray, StringComparer.OrdinalIgnoreCase)); } } }
private void HandleContact(GDPRContentContext context, SmsContactPart smsContactPart) { // Get all the phone numbers we'll have to process var numbers = smsContactPart.SmsRecord .Select(csr => new PhoneNumber(csr)) .Where(pn => !string.IsNullOrWhiteSpace(pn.Number)); // sanity check if (numbers.Any()) // sanity check { var sgParts = _contentManager.Query <SmsGatewayPart>(VersionOptions.AllVersions) .Where <SmsGatewayPartRecord>(sgpr => // this predicate replaces sgpr.RecipientList != null && //!string.IsNullOrWhitespace sgpr.RecipientList != "") .List() // here IContentQuery ends and IEnumerable begins .Where(sgp => { foreach (var pn in numbers) { if (sgp.RecipientList .Contains(pn.Number, StringComparison.OrdinalIgnoreCase)) { return(true); } } return(false); }); // Each phone number in the RecipientLists should be prefix+number, but we check // also for the case where it is just number var comparisonArray = numbers.Select(pn => pn.Number).ToList(); comparisonArray.AddRange(numbers.Select(pn => pn.FullNumber)); foreach (var sgPart in sgParts) { // RecipientList is a string of phone numbers separated by newline. var split = sgPart.RecipientList .Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); sgPart.RecipientList = string.Join(Environment.NewLine, split.Select(str => str.Trim()) .Except(comparisonArray, StringComparer.OrdinalIgnoreCase)); } } }
/// <summary> /// These operations should all happen before the Anonymized/Erased event is raised. Otherwise /// we may end up deleting the item in a Workflow there, and preventing all other handlers /// to run as they should. /// </summary> /// <param name="context"></param> private void PostProcessing(GDPRContentContext context) { var updateCtx = new UpdateContentContext(context.ContentItem); ContentHandlers.Invoke(handler => handler.Updated(updateCtx), Logger); // Re-publish the published version of the ContentItem, if it exists. // This way, all its handlers are launched again, synchronizing information as needed. // For example, this is sufficient to propagate anonymization onto the Alias, when // AutoroutePart is subject to anonymization/erasure, and onto the FieldIndexRecords // for fields that we processed above. var publishedVersion = context.AllVersions .FirstOrDefault(v => v.VersionRecord.Published); if (publishedVersion != null) { var civr = publishedVersion.Record.Versions.FirstOrDefault(v => v.Published); civr.Published = false; _contentManager.Publish(publishedVersion); } }
private void HandleDeviceRecords(GDPRContentContext context, UserPart part) { var userRecord = part.Record; if (userRecord != null) // sanity check { var deviceRecords = _userDeviceRepository .Fetch(ud => ud.UserPartRecord == userRecord) .ToList(); foreach (var deviceRecord in deviceRecords) { // clear this UUID deviceRecord.UUIdentifier = deviceRecord.UUIdentifier.GenerateUniqueString(); _userDeviceRepository.Update(deviceRecord); // These records we are processing here will be deleted elsewhere if // the user is deleted. However, here we cannot know if the user is going // to be deleted, and we cannot assume it will be. For this reason we // are putting the unique string there. } } }
public void Anonymize(ContentItem contentItem, GDPRContentContext previousContext) { Anonymize(new AnonymizeContentContext(contentItem, previousContext)); }
public void Erase(ContentItem contentItem, GDPRContentContext previousContext) { Erase(new EraseContentContext(contentItem, previousContext)); }
public bool ProcessIsAllowed(GDPRContentContext context) { return(context != null && ProcessIsAllowed(context.ContentItem)); }