1

Suppose that you need to have a series of complex configuration for a series of different Objects. This configuration can be NSString like service's server address, NSNumber like timeout time and so on. I want to impose the following constraint:

  • Configuration must not be visible and/or editable to user so plist in the app bundle is not an acceptable solution
  • I need different configuration value for debug, AdHoc or release target (I will likely achieve this with a series of #ifdef but i write for sack of completeness)
  • All the object that i want to configure belongs to a Static Library and i want to inject the configuration from the code that use this static library (inject is in italic as my personal hint to a dependency injection)

My question is: what's the best way to achieve this? Have you ever faced a problem like this? how did you solve it?

Anh
  • 6,523
  • 7
  • 46
  • 59
Luca Bernardi
  • 4,191
  • 2
  • 31
  • 39
  • Platform configuration idioms are not Design Patterns. – Martin Spamer May 23 '12 at 11:27
  • "Configuration must not be visible and/or editable to user so plist in the app bundle is not an acceptable solution" plists in the bundle aren't visible to, or editable by, the user. Who is the user in this scenario? – jrturton May 23 '12 at 12:53
  • @MartinSpamer i've abused of Design Pattern term. I'm not speaking about gamma's design pattern. But thanks for pointing out this could help other people – Luca Bernardi May 23 '12 at 13:27
  • @jrturton it's not hard to a tech savvy user to open the app bundle and find inside the resource. For user i intend not all the app user but this kind of user – Luca Bernardi May 23 '12 at 13:29
  • 1
    So what if someone edited the plist, what harm could that do? Don't mean to assume the purpose but it sounds a lot like security via obscurity :) – Ja͢ck May 28 '12 at 06:21
  • then just get the plist from the web. store the config to a specific url (controlled by you) and download the plist from there at run time. – alinoz May 29 '12 at 16:17
  • @alinoz i can't understand how this solve my issue, if i store the plist in App sandbox directory the are accessible and editable more easily than have them in the bundle – Luca Bernardi May 30 '12 at 12:44
  • I would keep the files in the app sandbox (actually i do that with one of my projects). But if you don't want them there you can still have the file downloaded from the internet (using NSURLConnection) and you can process the content directly in memory. – alinoz May 30 '12 at 14:51
  • So, I'll add 2 cents. If you are truly trying to hide the configuration, then you could always add your own layer of encryption. This would mean that you would have to have the PList file, encrypt it, add it to your project pre-encrypted, then put the Key statically inside your code for decrypting, then decrypt prior to using. Problem with this method is that then a good hacker as they can get into your package will get your encryption key by looking at your binary code, and watching for when you decrypt the file. The BIGGEST question is, what are you truly trying to protect, and why? – trumpetlicks May 30 '12 at 15:37
  • I suppose you could always use an encrypt algorith like RSA so that you hold privately your private encrypt key and only store the public decrypt key within your software. This would give you at least decent protection against modification!!! – trumpetlicks May 30 '12 at 20:35

6 Answers6

2

Take advantage of Xcode build system. You can have Xcode configuration files for any build configuration (Debug, Release, etc) and target combination.

These files support inheritance to simplify sharing configuration. There is no a single way to define the options. A simple one is to use GCC_PREPROCESSOR_DEFINITIONS or CFLAGS or whatever your compiler will take.

TargetX.xcconfig:

GCC_PREPROCESSOR_DEFINITIONS = STAGE=2 SERVER_URL='www.wuonm.com'

With configured values is fairly trivial to build the required NSString or NSNumber objects. Tip: you will require some kind of stringification.

It's quite similar to using #define but IMHO it's much cleaner and structured if you invest some time understanding how xcconfig files work.

Community
  • 1
  • 1
djromero
  • 19,551
  • 4
  • 71
  • 68
0

If these values are constant for each build configuration, why not put them in your code as constants? I don't really see why you need to externalize these settings if they are constants that vary by config. Your ifdef selection of the settings would be just as effective (and faster) with these constants declared in a private header.

If these settings somehow change during the running of the app (not from build to build but within the confines of running a single build of the app) then externalizing these settings would be appropriate.

NSProgrammer
  • 2,387
  • 1
  • 24
  • 27
  • i want to externalize the settings because i want to set a class that belong to a static library (that i use to as a toolbox) from the actual App – Luca Bernardi May 25 '12 at 14:41
0

There are many questions that arise with this post:

  1. Why do you need this level of protection on your input configuration?
  2. Is the point that you dont wish the user to be able to modify your configuration, or is it that you dont wish them to be able to KNOW it at all?
  3. If you beleive the theory that SW cannot protect SW, then truly what level of pain are you willing to put yourself through in order to put the hacker through enough pain they dont want to hack your SW (because lets face it, thats all you are really going to get, see my comments above about encryption)
  4. I somewhat agree with getting your configuration from the internet, but this only will work IFF you are expecting an internet capability present in order to use your app. If you do this and you also want some level of protection then you are going to have to use some secure protocol (Like SSL) for downloading it.
  5. If you truly wish your app to be able to be used locally (without internet access), then I would say that true security of your configuration is simply immposible, as you dont control the OS, your dont control the HW your SW is running on, etc...
  6. Putting your app on the iPhone probably means that you are hoping for a fairly large amount of downloads. This means the amount of hands touching it and potentially being able to take a CRACK at it are also large. The only way to gain security in this case (as no SW really is), is to make the value of hacking it to get your configuration not worth all that much. If the value is low, then no hacker will care to try and crack it!
Ashley Mills
  • 50,474
  • 16
  • 129
  • 160
trumpetlicks
  • 7,033
  • 2
  • 19
  • 33
0

I faced this same issue with server URLs used in different classes and constant numbers like colors, sizes and pretty much any configuration needed to be easily changed. The best solution I found was creating a header file like Constants.h, the content of this header file was:

#define MAX_DIST 1000
#define MIN_DIST 300
#define ANIMATION_DURATION 0.010
#define PIXEL_MOVES 7
#define SENSITIVITY 14
#define VIEW_ANGLE 30 //Range of vision divided by 2
#define RAD_POS_X 415
#define RAD_POS_Y 15
#define BUTTON_VIEW_WIDTH PIXEL_MOVES*360
#define SCREEN_HEIGHT 480
#define BUTTON_WIDTH_CLOSE 180
#define BUTTON_HEIGHT_CLOSE 100
#define BUTTON_WIDTH_MEDIUM 100
#define BUTTON_HEIGHT_MEDIUM 60
#define BUTTON_WIDTH_FAR 60
#define BUTTON_HEIGHT_FAR 40
#define BUTTON_Y_POSITION_CLOSE 200
#define BUTTON_Y_POSITION_MEDIUM 135
#define BUTTON_Y_POSITION_FAR 90
#define SERVICE_URL @"http://my.server.com/SoapServer/SoapServiceWS"//

you can even define common functions like

#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)

This way i have been able to configure every aspect of my app from one single file and you can use #ifdef like you said to manage different compilations. Of course, you must import the file Constants.h in any class that will need to access any of these constants.

Christian
  • 318
  • 2
  • 17
0

Your static library should provide some interface to set current configuration that will be set in runtime.

SetCurrentConfiguration(Configuration config);

Then "client" can configure it with needed configuration in runtime. Second step is load configuration from specified source, let's say xml file and inject it to static library via method above.

If you don't want users to modify configuration files you can use some sort of encryption and then decrypt on the fly.

victor.t
  • 454
  • 4
  • 12
0

Require that for the first time use, an internet connection is present and download via HTTPS your config and keep it in memory (encrypted if you want).

Then take advantage of the keychain in iOS, and store your config as a string there (essentially serialize it).

NSString *serializedConfig = ...;
[keychain setObject:serializedConfig  forKey@"MyConfig"];

On subsequent use, retrieve the config stored in the keychain:

NSString *serializedConfig = [keychain objectForKey:@"MyConfig"];

You can find the keychain wrapper and documentation on the Apple Docs site.

Julien Lebot
  • 3,092
  • 20
  • 32