GithubHelp home page GithubHelp logo

Comments (16)

nirinchev avatar nirinchev commented on May 28, 2024 2

Hey sorry for the delay, I had a family thing end of last week. The problem with nameof is that we don't have access to the field - the code I linked to is in the Realm library, whereas the code we're looking up is in your library, so we cannot reference members directly (at the time we build Realm, we don't have access to everyone's codebases). Additionally, since RealmSchema is a static property, we cannot add it as abstract interface member since Realm needs to support .NET Standard 2.0 and there this is not supported.

I'll try and update the generator to add [System.Reflection.Obfuscation] to the generated RealmSchema member and will send you a test build to see if that will solve the problem for you, since we don't have access to the Beebyte obfuscator.

from realm-dotnet.

nirinchev avatar nirinchev commented on May 28, 2024 2

Yes, we'd be happy to merge that PR - it's fairly trivial one and I don't see risks for regressions there.

from realm-dotnet.

nirinchev avatar nirinchev commented on May 28, 2024 2

Hey, thanks for the thorough testing done - I'll move forward and get that merged and ready for next official release. One thing I'm curious is if you're explicitly specifying the schema in your realm configuration - i.e. do you have something like:

var config = new RealmConfiguration
{
  schema = new[] { typeof(Foo), typeof(Bar) }
}

Based on some guesswork, I had assumed that without it, you would get an empty schema, but perhaps I've missed something.

As for the status of obfuscation support - we'll likely release as is and not explicitly document it as it's not a topic that has come up often enough. It's a best-effort type of support and we'd be happy to work with you and other members of the community to fix bugs and/or add annotations as long as they're general-purpose enough.

from realm-dotnet.

nirinchev avatar nirinchev commented on May 28, 2024 1

Hey, really sorry for the delay here - this fell a bit between the cracks. I've tried adding the attribute and built this package - can you give it a shot and see if that fixes the obfuscation problems:

https://drive.google.com/file/d/1qgu3YfUktWajHk_d9OWGkRYbmStPQF6J/view?usp=share_link

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024 1

Quick update... performed further tests on both Mono & IL2CPP (device) builds and so far so good. Zero issues to report.

Will test some more over the weekend, so by early next week I'll be able to report final results. But it's looking good.

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024 1

Yes that's exactly how I'm declaring Realm types. But once the codebase is obfuscated (during build) you'll end up with something like this...

var config = new RealmConfiguration
{
  schema = new[] { typeof(YWAKLCZP), typeof(QUVAPRTK) }
}

Realm proxy class method & property names will also be obfuscated (as above)

On-top of that, persisted properties are also decorated with MapTo attributes (set to equally obfuscated names)

Re obfuscation support, I think that's a very sensible way forward. To support the numerous obfuscation tools out there across all aspects of database management would be a big undertaking imo.

That's what I liked about the Obfuscation attribute approach as it's Dot Net generic, albeit obfuscators aren't obligated to support it.

Thanks again for everything and I'll post again if there's anything further to add.

from realm-dotnet.

sync-by-unito avatar sync-by-unito commented on May 28, 2024

➤ PM Bot commented:

Jira ticket: RNET-1134

from realm-dotnet.

nirinchev avatar nirinchev commented on May 28, 2024

What tool are you using for obfuscation? I guess the main question is if it's running before or after the Realm weaver, because if it's running after, I would expect things to work just fine. One thing we do use reflection for is the generated RealmSchema field - if you exclude just that from obfuscation, do you still experience the same problems?

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024

Hi Nikola,

Many thanks for the reply. The tool (that I'm currently evaluating) is the Beebyte obfuscator. There are others under consideration, but let's stick with this one for now.

If I extract the woven 'proxy' from the Mono DLL, the class & property names are clearly obfuscated, which I had assumed to mean the obfuscation was occurring after weaving (during build)

If it helps, I can send the 'proxy' of a test Realm object before (i.e., weaved in the Unity editor) and after (i.e., weaved during build). If so, let me know where to E-mail it to.

As for RealmSchema, I don't believe that would be the issue. The Realm package is (from what I can tell) stored in a separate assembly that is currently un-obfuscated. I wanted to get the basics working before turning to obfuscating third party tools.

Looking at the obfuscation translation table, the only reference to Realm (other than my own classes) is RealmModuleInitializer

from realm-dotnet.

nirinchev avatar nirinchev commented on May 28, 2024

Yeah, it'd be helpful if you could share those dlls to [email protected].

I'm assuming you're using the source generator based models - i.e. your models implement IRealmObject rather than inherit from RealmObject. If that's the case, then in the generated class, there'll be a RealmSchema static property, which we're getting using reflection:

var schemaField = type.GetField("RealmSchema", BindingFlags.Public | BindingFlags.Static);
. I can't seem to find docs for Beebyte, but if it has the option to configure members that should be skipped, you could try and annotate the RealmSchema property. This is not a real solution as regenerating the file will remove your changes, but we could at least try and see if it works.

One thing I can see that won't work correctly is property change notifications. Those use strings generated at compile time, so if you take advantage of it, after obfuscation, the names in the property change event handler won't match the obfuscated names of the class.

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024

OK, let me do some more research (with RealmSchema) and I'll message back in the next day or two.

In answer to your question, yes I'm using IRealmObject and not inheriting from RealmObject

I quickly looked at the Realm "C:\Users<user>\AppData\Local\Temp\VSGeneratedDocuments<id>\ClassName_generated.cs" proxy file and could not find the code you posted above.

I found the below though, is that what you're referring to?

public static Realms.Schema.ObjectSchema RealmSchema = new Realms.Schema.ObjectSchema.Builder("MappedClassName", ObjectSchema.ObjectType.RealmObject)
{
    Realms.Schema.Property.Primitive("MappedProperty1Name", Realms.RealmValueType.String, isPrimaryKey: true, indexType: IndexType.None, isNullable: true, managedName: "Property1Name"),
    Realms.Schema.Property.Primitive("MappedProperty2Nam>", Realms.RealmValueType.Data, isPrimaryKey: false, indexType: IndexType.None, isNullable: true, managedName: "Property2Name"),
}.Build();

That was from an IRealmObject decorated with MapTo attributes (for the obfuscated names)

As for the property change events, that may not be an issue here. I'm using mapped names that would otherwise match the obfuscated names. That said, I'm not using those events (yet) so haven't proved that theory.

Thanks again for the rapid response, it's much appreciated.

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024

Hi Nikola,

I've looked a little deeper into the RealmSchema suggestion and I think you're right, this could be the issue.

Going on your code link above, Realm is looking for a field called "RealmSchema" by means of a magic string.

I rebuilt the app in question with Realm obfuscation enabled and the static property now looks like this (extracted from a Mono build using dotPeek)...

static PLHAHHKPCAB()
{
  ObjectSchema.Builder builder = new ObjectSchema.Builder("MappedClassName", (ObjectSchema.ObjectType) 0);
  builder.Add(Property.Primitive("MappedProperty1Name", (RealmValueType) 3, true, (IndexType) 0, true, nameof (NDNBBOCIAKN)));
  builder.Add(Property.Primitive("MappedProperty2Name", (RealmValueType) 4, false, (IndexType) 0, true, nameof (HHPHLHLODFC)));
  PLHAHHKPCAB.MPCIFIMONMC = builder.Build();
}

We can see the obfuscator has renamed "RealmSchema" to "MPCIFIMONMC" therefore triggering the exception at line 283 from the code link you posted above.

Ok, so to test the theory I need to compile the app and somehow exclude the "RealmSchema" field from obfuscation.

The obfuscator allows classes to be excluded by means of an editor setting or an attribute. Class members can only be excluded by means of an attribute. So the only way to exclude "RealmSchema" from obfuscation is by using an attribute. Unfortunately custom attributes don't carry across to the woven proxies and even if they did, the "RealmSchema" field is not something under control of the app.

Assuming the attribute could somehow be added, the obfuscator supports custom attributes [Skip] & [SkipRename] that do similar things. So one of those could be added, but obviously they couldn't exist in Realm production. It might be possible to inject one via code in the build pipeline, but I think that'll be a huge amount of work for a simple test. However the obfuscator also supports the standard dot net obfuscation attributes...

[System.Reflection.Obfuscation]
[System.Reflection.Obfuscation(ApplyToMembers=false)]
[System.Reflection.Obfuscation(Exclude=false)]

So Realm could theoretically decorate the "RealmSchema" field with a [System.Reflection.Obfuscation] attribute (that defaults to exclude true) and it'll work for everyone.

During the build process, Realm weaving certainly appears to run before obfuscation (according to the console). So even if I could add it before building, I expect it'll be overwritten during build weaving?

On-top of that, if I "Find All References" to MyRealmObject in Visual Studio, it shows the generated Realm proxy file, but it's marked as auto generated and is zero bytes. So it looks like there's some VS magic going on there and doesn't appear to be editable.

Other possibilities are maybe using nameof() instead of a magic string (to lookup the field) or allowing the magic string value to be customisable somehow.

Hopefully this all helps, but if there's anything else you need just say and I'll do what I can.

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024

Hey @nirinchev

Many thanks for the update.

Understood about using nameof(). I dived deeper into the code yesterday and see what you mean. You're just dealing with Type at that point and trying to have even minimal strong typing, would likely involve substantial changes.

Thanks so much for taking the time to implement a potential workaround, it's really appreciated. I'm using the tarball package (V12.0.0) so not sure if it's possible to send an updated version of that? It might be easier to send the relevant updated DLL (i.e., in the library package cache) but have a feeling Unity will restore any cache files (from the package) if they detect hash deltas.

Either way, I'll send you a mail and include some extra obfuscator info that may be of help.

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024

Hey @nirinchev

No problems at all, assumed this was low priority.

So I've just run a very quick test and it appears to have addressed the issue above...

  1. The above package was installed via the UPM without issue.
  2. I removed one Realm record type from the Obfuscators skip obfuscation list (so it would be go through the obfuscation process)
  3. The weaving process ran without issue
  4. The woven proxy (for the specified record type) now included the [System.Reflection.Obfuscation] attribute on the RealmSchema static property.
  5. Performed a Mono build (without issue)
  6. Extracted the relevant class from the assembly (using dotPeek) and can see that the proxy is now fully obfuscated
  7. Performed an IL2CPP build (without issue)
  8. Installed the APK on a device and ran it (without issue)

So far so good :-)

That said, I've only tested very limited functionality (e.g., reading, writing, deleting, compacting) for one record type, not multiple types and not property change events etc.

So I need to perform wider tests, but this is a step in the right direction.

Going forward (and assuming this does resolve the issue) is this something that Realm would be comfortable committing to production? At the very least, it would be nice if another external developer (either using the same or another Obfuscator) could confirm these findings.

Thanks so much for all your efforts so far, it's greatly appreciated.

PS: When I have time in the next week, I'll post an example of an obfuscated RealmSchema property.

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024

Great, thanks!

I have a (full) Realm obfuscated build on a device now and will test it over the next week and report back.

from realm-dotnet.

peachypixels avatar peachypixels commented on May 28, 2024

Hey @nirinchev

Testing over the weekend uncovered zero issues with obfuscated Realms (Mono & IL2CPP builds) but with some caveats...

  1. Only CRUD operations have been tested, along with compacting & copying databases, database encryption & MapTo attributes (no property change events, no database syncing etc)
  2. Only basic data types were tested, strings, ints, floats, bools, byte[]
  3. Only Android has been tested, not iOS or Windows etc

So with that in mind, this change gets the thumbs up from me. That said, I would personally label obfuscation support as experimental for the time being (if at all). But it's a great step in the right direction (and a very worthwhile feature addition to Realm imho)

Anything else you need, please just ask and I'll try and help out as best as possible.

Thanks again for all your time & effort with this, it's greatly appreciated :-)

from realm-dotnet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.