Skip to content
This repository
Browse code

first commit

  • Loading branch information...
commit e93446a121d0448c83ec7974e2a97b93df466188 0 parents
Yann Lechelle authored

Showing 2 changed files with 222 additions and 0 deletions. Show diff stats Hide diff stats

  1. +44 0 OpenUDID.h
  2. +178 0 OpenUDID.m
44 OpenUDID.h
... ... @@ -0,0 +1,44 @@
  1 +//
  2 +// OpenUDID.h
  3 +// openudid
  4 +//
  5 +// Created by Yann Lechelle (cofounder Appsfire) on 8/28/11.
  6 +// Copyright 2011 OpenUDID.com
  7 +//
  8 +
  9 +/*
  10 + Permission is hereby granted, free of charge, to any person obtaining a copy of
  11 + this software and associated documentation files (the "Software"), to deal in
  12 + the Software without restriction, including without limitation the rights to
  13 + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  14 + of the Software, and to permit persons to whom the Software is furnished to do
  15 + so, subject to the following conditions:
  16 +
  17 + The above copyright notice and this permission notice shall be included in all
  18 + copies or substantial portions of the Software.
  19 +
  20 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26 + SOFTWARE.
  27 + */
  28 +
  29 +#import <Foundation/Foundation.h>
  30 +#import <Security/Security.h>
  31 +
  32 +
  33 +// README
  34 +//
  35 +// Requirement: add Security.framework to your project
  36 +// Usage:
  37 +// #include "OpenUDID.h"
  38 +// NSString* openUDID = [OpenUDID value];
  39 +
  40 +
  41 +@interface OpenUDID : NSObject {
  42 +}
  43 ++ (NSString*) value;
  44 +@end
178 OpenUDID.m
... ... @@ -0,0 +1,178 @@
  1 +//
  2 +// OpenUDID.m
  3 +// openudid
  4 +//
  5 +// Created by Yann Lechelle (cofounder Appsfire) on 8/28/11.
  6 +// Copyright 2011 OpenUDID.com
  7 +//
  8 +
  9 +/*
  10 + Permission is hereby granted, free of charge, to any person obtaining a copy of
  11 + this software and associated documentation files (the "Software"), to deal in
  12 + the Software without restriction, including without limitation the rights to
  13 + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  14 + of the Software, and to permit persons to whom the Software is furnished to do
  15 + so, subject to the following conditions:
  16 +
  17 + The above copyright notice and this permission notice shall be included in all
  18 + copies or substantial portions of the Software.
  19 +
  20 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26 + SOFTWARE.
  27 +*/
  28 +
  29 +
  30 +#import "OpenUDID.h"
  31 +#import <CommonCrypto/CommonDigest.h> // Need to import for CC_MD5 access
  32 +
  33 +static NSString * const kOpenUDID = @"com.OpenUDID";
  34 +
  35 +@interface OpenUDID (Private)
  36 ++ (BOOL) _writeToKeychainValue:(NSString*)value forKey:(NSString*)key;
  37 ++ (NSString*) _getUDID;
  38 +@end
  39 +
  40 +@implementation OpenUDID
  41 +
  42 +// private method to write to the keychain
  43 +//
  44 ++ (BOOL) _writeToKeychainValue:(NSString*)value forKey:(NSString*)key {
  45 + NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  46 + (id) kSecClassGenericPassword, (id) kSecClass,
  47 + kOpenUDID, kSecAttrService,
  48 + kOpenUDID, kSecAttrLabel,
  49 + key, kSecAttrAccount,
  50 + [value dataUsingEncoding: NSUTF8StringEncoding], kSecValueData,
  51 + nil];
  52 + if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.0) {
  53 + [dict setObject:(id)kSecAttrAccessibleAlwaysThisDeviceOnly forKey:(id)kSecAttrAccessible];
  54 + }
  55 +
  56 + OSStatus s = SecItemAdd((CFDictionaryRef) dict, NULL);
  57 + return (s == noErr);
  58 +}
  59 +
  60 +// private method to return
  61 +//
  62 ++ (NSString*) _getUDID {
  63 +
  64 + NSString* _openUDID = nil;
  65 +
  66 + // One day, this may no longer be allowed. When that is, just comment this line out.
  67 + //
  68 + _openUDID = [[UIDevice currentDevice] uniqueIdentifier];
  69 +
  70 +
  71 + // Take this opportunity to give the simulator a proper UDID (i.e. nullify UDID and create an OpenUDID)
  72 + //
  73 +#if TARGET_IPHONE_SIMULATOR
  74 + _openUDID = nil;
  75 +#endif
  76 +
  77 + // Next we try to use an alternative method which uses the host name, process ID, and a time stamp
  78 + // We then hash it with md5 to get 32 bytes, and then add 4 extra random bytes
  79 + // Collision is possible of course, but unlikely and suitable for most industry needs (i.e. aggregating conversion for example)
  80 + //
  81 + if (_openUDID==nil) {
  82 + unsigned char result[16];
  83 + const char *cStr = [[[NSProcessInfo processInfo] globallyUniqueString] UTF8String];
  84 + CC_MD5( cStr, strlen(cStr), result );
  85 + _openUDID = [NSString stringWithFormat:
  86 + @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%08x",
  87 + result[0], result[1], result[2], result[3],
  88 + result[4], result[5], result[6], result[7],
  89 + result[8], result[9], result[10], result[11],
  90 + result[12], result[13], result[14], result[15],
  91 + arc4random() % 4294967295];
  92 + }
  93 +
  94 + // Call to other developers in the Open Source community:
  95 + // feel free to add better or alternative "UDID" methods here.
  96 +
  97 + return _openUDID;
  98 +}
  99 +
  100 +
  101 +// Main public method that returns the OpenUDID
  102 +// This method will generate and store the OpenUDID if it doesn't exist
  103 +// It will return the null udid (forty zeros) if the user has somehow opted-out this app (this is subject to 3rd party implementation)
  104 +// Otherwise, it will register the current app and return the OpenUDID
  105 +//
  106 ++ (NSString*) value {
  107 + OSStatus status;
  108 + NSMutableDictionary *item = nil;
  109 + NSDictionary *attributeResult = nil;
  110 + NSMutableDictionary *query = nil;
  111 + NSData *resultData = nil;
  112 + NSString* resultString = nil;
  113 + NSString *bundleid = [[NSBundle mainBundle] bundleIdentifier];
  114 +
  115 + // First check if the current bundleid is registered
  116 + //
  117 + item = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  118 + (id)kSecClassGenericPassword, (id) kSecClass,
  119 + bundleid,kSecAttrAccount,
  120 + kOpenUDID, kSecAttrService, nil];
  121 + attributeResult = nil;
  122 + query = [[item mutableCopy] autorelease];
  123 + [query setObject: (id) kCFBooleanTrue forKey:(id) kSecReturnAttributes];
  124 + status = SecItemCopyMatching((CFDictionaryRef) query, (CFTypeRef *) &attributeResult);
  125 + [attributeResult release];
  126 +
  127 + if (status != noErr) {
  128 + // bundleid could not be found, so let's register it
  129 + // R is for registered, O is for opted-out...
  130 + [OpenUDID _writeToKeychainValue:@"R" forKey:bundleid];
  131 + NSLog(@"Writing OpenUDID");
  132 + } else {
  133 + // bundleid found, let's find the value
  134 + resultData = nil;
  135 + query = [[item mutableCopy] autorelease];
  136 + [query setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnData];
  137 + status = SecItemCopyMatching((CFDictionaryRef) query, (CFTypeRef *) &resultData);
  138 + resultString = [[[NSString alloc] initWithData: [resultData autorelease] encoding: NSUTF8StringEncoding] autorelease];
  139 +
  140 + // if the value is O, then the user has opted out, we return the null UDID...
  141 + if ([resultString isEqualToString:@"O"])
  142 + return [NSString stringWithFormat:@"%040x",0];
  143 + }
  144 +
  145 + // Now, let's access the OpenUDID
  146 + item = [NSMutableDictionary dictionaryWithObjectsAndKeys:
  147 + (id)kSecClassGenericPassword, (id) kSecClass,
  148 + kOpenUDID,kSecAttrAccount,
  149 + kOpenUDID, kSecAttrService, nil];
  150 + attributeResult = nil;
  151 + query = [[item mutableCopy] autorelease];
  152 + [query setObject: (id) kCFBooleanTrue forKey:(id) kSecReturnAttributes];
  153 + status = SecItemCopyMatching((CFDictionaryRef) query, (CFTypeRef *) &attributeResult);
  154 + [attributeResult release];
  155 +
  156 + if (status != noErr) {
  157 + // Could not find the UDID, so let's generate it and store it, persistently.
  158 + resultString = [OpenUDID _getUDID];
  159 + [OpenUDID _writeToKeychainValue:resultString forKey:kOpenUDID];
  160 + return resultString;
  161 + }
  162 +
  163 + // Let's fetch the value of the stored OpenUDID
  164 + resultData = nil;
  165 + query = [[item mutableCopy] autorelease];
  166 + [query setObject: (id) kCFBooleanTrue forKey: (id) kSecReturnData];
  167 + status = SecItemCopyMatching((CFDictionaryRef) query, (CFTypeRef *) &resultData);
  168 + resultString = [[[NSString alloc] initWithData: [resultData autorelease] encoding: NSUTF8StringEncoding] autorelease];
  169 +
  170 + // Found the key and obtained a value
  171 + if (status == noErr && resultData)
  172 + return resultString;
  173 +
  174 + // Error, let's return nil
  175 + return nil;
  176 +}
  177 +
  178 +@end

0 comments on commit e93446a

Please sign in to comment.
Something went wrong with that request. Please try again.