Updating plists and versioning to release 1.5.1.
[MenuTunes.git] / MTeSerialNumber.m
1 #import "MTeSerialNumber.h"
2 #import "validate.h"
3 #import <openssl/sha.h>
4
5 @interface MTeSerialNumber (Private)
6 - (short)validate;
7 - (eSellerate_String)eSellerateStringForString:(NSString *)string;
8 @end
9
10 @implementation MTeSerialNumber
11
12 /*************************************************************************/
13 #pragma mark -
14 #pragma mark INITIALIZATION METHODS
15 /*************************************************************************/
16
17 - (id)initWithSerialNumber:(NSString *)serial
18                       name:(NSString *)name
19                      extra:(NSString *)extra
20                  publisher:(NSString *)publisher
21 {
22     if ( (self = [super init]) ) {
23         _serialNumber = serial;
24         _nameBasedKey = name;
25         _extraDataKey = nil;       //extra data is currently unused.
26         _publisherKey = publisher;
27         _deadSerials  = nil;
28     }
29     return self;
30 }
31
32 - (id)initWithDictionary:(NSDictionary *)dict
33 {
34     return [self initWithSerialNumber:[dict objectForKey:@"Key"]
35                                  name:[dict objectForKey:@"Owner"]
36                                 extra:[dict objectForKey:@"Extra"]
37                             publisher:[dict objectForKey:@"Publisher"]];
38 }
39
40 - (id)initWithContentsOfFile:(NSString *)path
41                        extra:(NSString *)extra
42                    publisher:(NSString *)publisher
43 {
44     NSDictionary *fileDict = [[[NSDictionary alloc] initWithContentsOfFile:path] autorelease];
45     
46     if ( fileDict ) {
47         NSMutableDictionary *dict = [[[NSMutableDictionary alloc] initWithCapacity:4] autorelease];
48
49         [dict setObject:[fileDict objectForKey:@"Key"] forKey:@"Key"];
50         [dict setObject:[fileDict objectForKey:@"Owner"] forKey:@"Owner"];
51         [dict setObject:extra forKey:@"Extra"];
52         [dict setObject:publisher forKey:@"Publisher"];
53
54         return [self initWithDictionary:dict];
55     } else {
56         return nil;
57     }
58 }
59
60
61 /*************************************************************************/
62 #pragma mark -
63 #pragma mark ACCESSOR METHODS
64 /*************************************************************************/
65
66 - (NSString *)serialNumber
67 {
68     return _serialNumber;
69 }
70
71 - (void)setSerialNumber:(NSString *)newSerial
72 {
73     [_serialNumber autorelease];
74     _serialNumber = [newSerial copy];
75 }
76
77 - (NSString *)nameBasedKey
78 {
79     return _nameBasedKey;
80 }
81
82 - (void)setNameBasedKey:(NSString *)newName
83 {
84     [_nameBasedKey autorelease];
85     _nameBasedKey = [newName copy];
86 }
87
88 - (NSString *)extraDataKey
89 {
90     return _extraDataKey;
91 }
92
93 - (void)setExtraDataKey:(NSString *)newData
94 {
95     [_extraDataKey autorelease];
96     _extraDataKey = [newData copy];
97 }
98
99 - (NSString *)publisherKey
100 {
101     return _publisherKey;
102 }
103
104 - (void)setPublisherKey:(NSString *)newPublisher
105 {
106     [_publisherKey autorelease];
107     _publisherKey = [newPublisher copy];
108 }
109
110 - (NSArray *)deadSerials
111 {
112     return _deadSerials;
113 }
114
115 - (void)setDeadSerials:(NSArray *)newList
116 {
117     [_deadSerials autorelease];
118     _deadSerials = [newList copy];
119 }
120
121
122 /*************************************************************************/
123 #pragma mark -
124 #pragma mark INSTANCE METHODS
125 /*************************************************************************/
126
127 - (MTeSerialNumberValidationResult)isValid
128 {
129     if ( _serialNumber ) {
130
131         BOOL dead = NO;
132         unsigned char *result = SHA1([[_serialNumber stringByAppendingString:@"-h4x0r"] UTF8String], [_serialNumber length] + 5, NULL);
133                 if ([[[NSData dataWithBytes:result length:strlen(result)] description] isEqualToString:@"<db7ea71c 2919ff4b 520b6491 8d6813db b70647>"]) {
134                         dead = YES;
135                 }
136                 
137         if ( [_deadSerials count] )  {
138             NSEnumerator *deadEnum = [_deadSerials objectEnumerator];
139             id            aDeadSerial;
140             
141             while ( (aDeadSerial = [deadEnum nextObject]) ) {
142                 if ( [aDeadSerial isEqualToString:_serialNumber] ) {
143                     dead = YES;
144                 }
145             }
146         }
147
148         if ( dead ) {
149             return ITeSerialNumberIsDead;
150         } else {
151             return ( ( [self validate] > 0 ) ? ITeSerialNumberIsValid : ITeSerialNumberIsInvalid );
152         }
153     } else {
154         return nil;
155     }
156 }
157
158 - (MTeSerialNumberExpirationResult)isExpired;
159 {
160     return ( ! [self secondsRemaining] > 0 );
161 }
162
163 - (NSDate *)storedDate
164 {
165     NSCalendarDate *refDate = [NSCalendarDate dateWithYear:2000 month:1 day:1
166                                                       hour:0 minute:0 second:0
167                                                   timeZone:[NSTimeZone systemTimeZone]];
168
169     NSTimeInterval secondsFromRefToExp = ([self validate] * 86400);
170
171     return [[[NSDate alloc] initWithTimeInterval:secondsFromRefToExp
172                                        sinceDate:refDate] autorelease];
173 }
174
175 - (NSTimeInterval)secondsRemaining
176 {
177     return [[self storedDate] timeIntervalSinceDate:[NSDate date]];
178 }
179
180 - (NSDictionary *)infoDictionary
181 {
182     NSString *prefix        = [[_serialNumber componentsSeparatedByString:@"-"] objectAtIndex:0];
183     NSString *appIdentifier = nil;
184     NSString *version       = nil;
185     NSString *typeCode      = nil;
186     NSString *quantity      = nil;
187     
188     if ( ( [prefix length] == 10 ) || ( [prefix length] == 7 ) ) {
189         appIdentifier = [_serialNumber substringWithRange:NSMakeRange(0,2)];
190         version       = [_serialNumber substringWithRange:NSMakeRange(2,3)];
191         typeCode      = [_serialNumber substringWithRange:NSMakeRange(5,2)];
192     } else {
193         return nil;
194     }
195
196     if ( [prefix length] == 10 ) {
197         quantity = [_serialNumber substringWithRange:NSMakeRange(7,3)];
198     }
199
200     return [NSDictionary dictionaryWithObjectsAndKeys:
201         appIdentifier, @"appIdentifier",
202         version,       @"version",
203         typeCode,      @"typeCode",
204         quantity,      @"quantity",   nil];
205 }
206
207
208 /*************************************************************************/
209 #pragma mark -
210 #pragma mark PRIVATE IMPLEMENTATIONS
211 /*************************************************************************/
212
213 - (short)validate
214 {
215     eSellerate_String pSerial    = [self eSellerateStringForString:_serialNumber];
216     eSellerate_String pName      = [self eSellerateStringForString:_nameBasedKey];
217     eSellerate_String pExtraData = [self eSellerateStringForString:_extraDataKey];
218     eSellerate_String pPublisher = [self eSellerateStringForString:_publisherKey];
219     
220     return eSellerate_ValidateSerialNumber(pSerial,
221                                            pName,
222                                            pExtraData,
223                                            pPublisher);
224 }
225
226 - (eSellerate_String)eSellerateStringForString:(NSString *)string
227 {
228     if ( string ) {
229         NSMutableData *buffer = [[[NSMutableData alloc] initWithCapacity:256] autorelease];
230         
231         CFStringGetPascalString( (CFStringRef)string,
232                                  [buffer mutableBytes],
233                                  256,
234                                  CFStringGetSystemEncoding());
235                                  
236         return (eSellerate_String)[buffer bytes];
237     } else {
238         return nil;
239     }
240 }
241
242
243 @end