-
Notifications
You must be signed in to change notification settings - Fork 27
Implement patching for Affinity.CloudServices to block analytics to api.canva.com #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -68,11 +68,28 @@ private static void PatchAffinity(DirectoryInfo directoryInfo, bool verbose, boo | |
| { | ||
| AnsiConsole.MarkupLine("[blue]Starting Affinity patching process...[/]"); | ||
|
|
||
| // Persona patching | ||
| var personaAssembly = FindAssembly("Serif.Interop.Persona.dll", directoryInfo); | ||
| if (personaAssembly == null) | ||
| throw new FileNotFoundException("Cannot find the required Affinity assembly (Serif.Interop.Persona.dll)."); | ||
| if (personaAssembly != null) | ||
| { | ||
| PatchAffinityAssembly(personaAssembly.FullName, verbose: verbose, keepOriginal: keepOriginal); | ||
| } | ||
| else | ||
| { | ||
| AnsiConsole.MarkupLine("[yellow]Warning: Serif.Interop.Persona.dll not found. Main patches skipped.[/]"); | ||
| } | ||
|
|
||
| PatchAffinityAssembly(personaAssembly.FullName, verbose: verbose, keepOriginal: keepOriginal); | ||
| // Patch CloudServices (fix for Issue #11) | ||
| var cloudServicesAssembly = FindAssembly("Affinity.CloudServices.dll", directoryInfo); | ||
| if (cloudServicesAssembly != null) | ||
| { | ||
| PatchCloudServicesAssembly(cloudServicesAssembly.FullName, verbose, keepOriginal); | ||
| } | ||
| else | ||
| { | ||
| // If no separate DLL exists, classes may be in Persona (older versions) | ||
| AnsiConsole.MarkupLine("[yellow]Affinity.CloudServices.dll not found. Skipping extra analytics patches.[/]"); | ||
| } | ||
| } | ||
|
|
||
| private static void PatchDxO(DirectoryInfo directoryInfo, bool verbose, bool keepOriginal) | ||
|
|
@@ -199,6 +216,68 @@ private static void PatchAffinityAssembly(string targetFile, bool verbose, bool | |
| FinalizeAssembly(targetFile, tempOutput); | ||
| } | ||
|
|
||
| private static void PatchCloudServicesAssembly(string targetFile, bool verbose, bool keepOriginal) | ||
| { | ||
| AnsiConsole.MarkupLine("[blue]Patching Affinity Cloud Services to block analytics...[/]"); | ||
|
|
||
| if (keepOriginal) | ||
| { | ||
| File.Copy(targetFile, targetFile + ".bak", overwrite: true); | ||
| AnsiConsole.MarkupLine("[green]Backed up Affinity CloudServices assembly.[/]"); | ||
| } | ||
|
|
||
| var moduleContext = ModuleDef.CreateModuleContext(); | ||
| var tempOutput = Path.GetTempFileName(); | ||
| var patchedList = new List<string>(); | ||
|
|
||
| using (var module = ModuleDefMD.Load(targetFile, moduleContext)) | ||
| { | ||
| // Search for analytics-related types | ||
| var analyticsTypes = module.GetTypes().Where(t => | ||
| t.FullName.Contains("Analytics") || | ||
| t.FullName.Contains("Telemetry") || | ||
| t.FullName.Contains("Snowplow")); | ||
|
|
||
| foreach (var type in analyticsTypes) | ||
| { | ||
| // Search for methods that appear to send or initialize data | ||
| var methodsToNeutralize = type.Methods.Where(m => | ||
| m.HasBody && | ||
| (m.Name.StartsWith("Upload") || | ||
| m.Name.StartsWith("Send") || | ||
| m.Name.StartsWith("Track") || | ||
| m.Name.StartsWith("Init") || | ||
| m.Name.Contains("Event"))); | ||
|
|
||
| foreach (var method in methodsToNeutralize) | ||
| { | ||
| // If it returns void, use a simple Ret | ||
| if (method.ReturnType.ElementType == ElementType.Void) | ||
| { | ||
| Patcher.PatchWithRetVerbose(method.FullName, method.Body, verbose); | ||
| patchedList.Add(method.FullName); | ||
| } | ||
| // If it returns bool, return false (0) | ||
| else if (method.ReturnType.ElementType == ElementType.Boolean) | ||
| { | ||
| Patcher.PatchWithLdcRetVerbose(method.FullName, method.Body, 0, verbose); | ||
| patchedList.Add(method.FullName); | ||
| } | ||
|
PGSCOM marked this conversation as resolved.
|
||
| // For other return types, do not patch but log when verbose is enabled | ||
| else if (verbose) | ||
| { | ||
| AnsiConsole.MarkupLine( | ||
| $"[yellow]Skipping method '{method.FullName}' with unsupported return type '{method.ReturnType.FullName}' (not void/bool).[/]"); | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+236
to
+273
|
||
|
|
||
| SaveAssembly(module, tempOutput, patchedList, "Affinity.CloudServices"); | ||
| } | ||
|
|
||
| FinalizeAssembly(targetFile, tempOutput); | ||
| } | ||
|
|
||
| private static void PatchDxOAssembly(string targetFile, bool verbose, bool keepOriginal) | ||
| { | ||
| if (keepOriginal) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The methods identified for neutralization use name-based heuristics (StartsWith/Contains) which could potentially match unrelated methods. For example, methods named "SendMessage" or "InitializeConfiguration" might be patched even if they're not analytics-related. Consider adding additional validation, such as checking method signatures, parameter types, or verifying that the method actually contains analytics-related code patterns before patching.