/core/externals/update-engine/Core/KSTicket.m

http://macfuse.googlecode.com/ · Objective C · 490 lines · 401 code · 59 blank · 30 comment · 82 complexity · 9fa0c4d0ca1752584f33e4100c80b7a6 MD5 · raw file

  1. // Copyright 2008 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #import "KSTicket.h"
  15. #import "KSExistenceChecker.h"
  16. // When reading a plist file pointed to by a tag, brandcode, or version
  17. // path, don't bother reading files over this size. Chances are
  18. // someone is trying to feed us a bad file and forcing a crash. The
  19. // largest plist found on my Leopard system was 4 megs.
  20. #define MAX_DATA_FILE_SIZE (5 * 1024 * 1024)
  21. // If we are getting the tag, brandcode, or version from a path/tag
  22. // combination, make sure that the tag itself isn't unreasonably huge.
  23. #define MAX_PATHTAG_SIZE 1024
  24. @implementation KSTicket
  25. + (KSTicket *)ticketWithParameters:(NSDictionary *)args {
  26. return [[[self alloc] initWithParameters:args] autorelease];
  27. }
  28. + (id)ticketWithProductID:(NSString *)productid
  29. version:(NSString *)version
  30. existenceChecker:(KSExistenceChecker *)xc
  31. serverURL:(NSURL *)serverURL {
  32. return [[[self alloc] initWithProductID:productid
  33. version:version
  34. existenceChecker:xc
  35. serverURL:serverURL
  36. trustedTesterToken:nil] autorelease];
  37. }
  38. + (id)ticketWithProductID:(NSString *)productid
  39. version:(NSString *)version
  40. existenceChecker:(KSExistenceChecker *)xc
  41. serverURL:(NSURL *)serverURL
  42. trustedTesterToken:(NSString *)trustedTesterToken {
  43. return [[[self alloc] initWithProductID:productid
  44. version:version
  45. existenceChecker:xc
  46. serverURL:serverURL
  47. trustedTesterToken:trustedTesterToken] autorelease];
  48. }
  49. + (id)ticketWithProductID:(NSString *)productid
  50. version:(NSString *)version
  51. existenceChecker:(KSExistenceChecker *)xc
  52. serverURL:(NSURL *)serverURL
  53. trustedTesterToken:(NSString *)trustedTesterToken
  54. creationDate:(NSDate *)creationDate {
  55. return [[[self alloc] initWithProductID:productid
  56. version:version
  57. existenceChecker:xc
  58. serverURL:serverURL
  59. trustedTesterToken:trustedTesterToken
  60. creationDate:creationDate] autorelease];
  61. }
  62. + (id)ticketWithProductID:(NSString *)productid
  63. version:(NSString *)version
  64. existenceChecker:(KSExistenceChecker *)xc
  65. serverURL:(NSURL *)serverURL
  66. trustedTesterToken:(NSString *)trustedTesterToken
  67. creationDate:(NSDate *)creationDate
  68. tag:(NSString *)tag {
  69. return [[[self alloc] initWithProductID:productid
  70. version:version
  71. existenceChecker:xc
  72. serverURL:serverURL
  73. trustedTesterToken:trustedTesterToken
  74. creationDate:creationDate
  75. tag:tag] autorelease];
  76. }
  77. - (id)initWithParameters:(NSDictionary *)args {
  78. if ((self = [super init])) {
  79. productID_ = [[args objectForKey:KSTicketProductIDKey] copy];
  80. version_ = [[args objectForKey:KSTicketVersionKey] copy];
  81. existenceChecker_ =
  82. [[args objectForKey:KSTicketExistenceCheckerKey] retain];
  83. serverURL_ = [[args objectForKey:KSTicketServerURLKey] retain];
  84. trustedTesterToken_ =
  85. [[args objectForKey:KSTicketTrustedTesterTokenKey] copy];
  86. creationDate_ = [[args objectForKey:KSTicketCreationDateKey] retain];
  87. tag_ = [[args objectForKey:KSTicketTagKey] copy];
  88. tagPath_ = [[args objectForKey:KSTicketTagPathKey] copy];
  89. tagKey_ = [[args objectForKey:KSTicketTagKeyKey] copy];
  90. brandPath_ = [[args objectForKey:KSTicketBrandPathKey] copy];
  91. brandKey_ = [[args objectForKey:KSTicketBrandKeyKey] copy];
  92. versionPath_ = [[args objectForKey:KSTicketVersionPathKey] copy];
  93. versionKey_ = [[args objectForKey:KSTicketVersionKeyKey] copy];
  94. if (creationDate_ == nil) creationDate_ = [[NSDate alloc] init];
  95. // Ensure that these ivars are not nil.
  96. if (productID_ == nil || version_ == nil ||
  97. existenceChecker_ == nil || serverURL_ == nil) {
  98. [self release];
  99. return nil;
  100. }
  101. }
  102. return self;
  103. }
  104. - (id)init {
  105. return [self initWithParameters:[NSDictionary dictionary]];
  106. }
  107. - (NSDictionary *)parametersForProductID:(NSString *)productid
  108. version:(NSString *)version
  109. existenceChecker:(KSExistenceChecker *)xc
  110. serverURL:(NSURL *)serverURL
  111. trustedTesterToken:(NSString *)ttt
  112. creationDate:(NSDate *)creationDate
  113. tag:(NSString *)tag {
  114. NSMutableDictionary *args = [NSMutableDictionary dictionary];
  115. if (productid) [args setObject:productid forKey:KSTicketProductIDKey];
  116. if (version) [args setObject:version forKey:KSTicketVersionKey];
  117. if (xc) [args setObject:xc forKey:KSTicketExistenceCheckerKey];
  118. if (serverURL) [args setObject:serverURL forKey:KSTicketServerURLKey];
  119. if (ttt) [args setObject:ttt forKey:KSTicketTrustedTesterTokenKey];
  120. if (creationDate) [args setObject:creationDate
  121. forKey:KSTicketCreationDateKey];
  122. if (tag) [args setObject:tag forKey:KSTicketTagKey];
  123. return args;
  124. }
  125. - (id)initWithProductID:(NSString *)productid
  126. version:(NSString *)version
  127. existenceChecker:(KSExistenceChecker *)xc
  128. serverURL:(NSURL *)serverURL {
  129. NSDictionary *args = [self parametersForProductID:productid
  130. version:version
  131. existenceChecker:xc
  132. serverURL:serverURL
  133. trustedTesterToken:nil
  134. creationDate:nil
  135. tag:nil];
  136. return [self initWithParameters:args];
  137. }
  138. - (id)initWithProductID:(NSString *)productid
  139. version:(NSString *)version
  140. existenceChecker:(KSExistenceChecker *)xc
  141. serverURL:(NSURL *)serverURL
  142. trustedTesterToken:(NSString *)ttt {
  143. NSDictionary *args = [self parametersForProductID:productid
  144. version:version
  145. existenceChecker:xc
  146. serverURL:serverURL
  147. trustedTesterToken:ttt
  148. creationDate:nil
  149. tag:nil];
  150. return [self initWithParameters:args];
  151. }
  152. - (id)initWithProductID:(NSString *)productid
  153. version:(NSString *)version
  154. existenceChecker:(KSExistenceChecker *)xc
  155. serverURL:(NSURL *)serverURL
  156. trustedTesterToken:(NSString *)ttt
  157. creationDate:(NSDate *)creationDate {
  158. NSDictionary *args = [self parametersForProductID:productid
  159. version:version
  160. existenceChecker:xc
  161. serverURL:serverURL
  162. trustedTesterToken:ttt
  163. creationDate:creationDate
  164. tag:nil];
  165. return [self initWithParameters:args];
  166. }
  167. - (id)initWithProductID:(NSString *)productid
  168. version:(NSString *)version
  169. existenceChecker:(KSExistenceChecker *)xc
  170. serverURL:(NSURL *)serverURL
  171. trustedTesterToken:(NSString *)ttt
  172. creationDate:(NSDate *)creationDate
  173. tag:(NSString *)tag {
  174. NSDictionary *args = [self parametersForProductID:productid
  175. version:version
  176. existenceChecker:xc
  177. serverURL:serverURL
  178. trustedTesterToken:ttt
  179. creationDate:creationDate
  180. tag:tag];
  181. return [self initWithParameters:args];
  182. }
  183. - (id)initWithCoder:(NSCoder *)coder {
  184. if ((self = [super init])) {
  185. productID_ = [[coder decodeObjectForKey:@"product_id"] retain];
  186. version_ = [[coder decodeObjectForKey:@"version"] retain];
  187. existenceChecker_ =
  188. [[coder decodeObjectForKey:@"existence_checker"] retain];
  189. serverURL_ = [[coder decodeObjectForKey:@"server_url"] retain];
  190. creationDate_ = [[coder decodeObjectForKey:@"creation_date"] retain];
  191. if ([coder containsValueForKey:@"trusted_tester_token"]) {
  192. trustedTesterToken_ =
  193. [[coder decodeObjectForKey:@"trusted_tester_token"] retain];
  194. }
  195. if ([coder containsValueForKey:@"tag"]) {
  196. tag_ = [[coder decodeObjectForKey:@"tag"] retain];
  197. }
  198. if ([coder containsValueForKey:@"tagPath"]) {
  199. tagPath_ = [[coder decodeObjectForKey:@"tagPath"] retain];
  200. }
  201. if ([coder containsValueForKey:@"tagKey"]) {
  202. tagKey_ = [[coder decodeObjectForKey:@"tagKey"] retain];
  203. }
  204. if ([coder containsValueForKey:@"brandPath"]) {
  205. brandPath_ = [[coder decodeObjectForKey:@"brandPath"] retain];
  206. }
  207. if ([coder containsValueForKey:@"brandKey"]) {
  208. brandKey_ = [[coder decodeObjectForKey:@"brandKey"] retain];
  209. }
  210. if ([coder containsValueForKey:@"versionPath"]) {
  211. versionPath_ = [[coder decodeObjectForKey:@"versionPath"] retain];
  212. }
  213. if ([coder containsValueForKey:@"versionKey"]) {
  214. versionKey_ = [[coder decodeObjectForKey:@"versionKey"] retain];
  215. }
  216. }
  217. return self;
  218. }
  219. - (void)dealloc {
  220. [productID_ release];
  221. [version_ release];
  222. [existenceChecker_ release];
  223. [serverURL_ release];
  224. [creationDate_ release];
  225. [trustedTesterToken_ release];
  226. [tag_ release];
  227. [tagPath_ release];
  228. [tagKey_ release];
  229. [brandPath_ release];
  230. [brandKey_ release];
  231. [versionPath_ release];
  232. [versionKey_ release];
  233. [super dealloc];
  234. }
  235. - (void)encodeWithCoder:(NSCoder *)coder {
  236. [coder encodeObject:productID_ forKey:@"product_id"];
  237. [coder encodeObject:version_ forKey:@"version"];
  238. [coder encodeObject:existenceChecker_ forKey:@"existence_checker"];
  239. [coder encodeObject:serverURL_ forKey:@"server_url"];
  240. [coder encodeObject:creationDate_ forKey:@"creation_date"];
  241. if (trustedTesterToken_)
  242. [coder encodeObject:trustedTesterToken_ forKey:@"trusted_tester_token"];
  243. if (tag_) [coder encodeObject:tag_ forKey:@"tag"];
  244. if (tagPath_) [coder encodeObject:tagPath_ forKey:@"tagPath"];
  245. if (tagKey_) [coder encodeObject:tagKey_ forKey:@"tagKey"];
  246. if (brandPath_) [coder encodeObject:brandPath_ forKey:@"brandPath"];
  247. if (brandKey_) [coder encodeObject:brandKey_ forKey:@"brandKey"];
  248. if (versionPath_) [coder encodeObject:versionPath_ forKey:@"versionPath"];
  249. if (versionKey_) [coder encodeObject:versionKey_ forKey:@"versionKey"];
  250. }
  251. // The trustedTesterToken_, tag, and brand are intentionally excluded from hash.
  252. - (unsigned)hash {
  253. return [productID_ hash] + [version_ hash] + [existenceChecker_ hash]
  254. + [serverURL_ hash] + [creationDate_ hash];
  255. }
  256. - (BOOL)isEqual:(id)other {
  257. if (other == self)
  258. return YES;
  259. if (!other || ![other isKindOfClass:[self class]])
  260. return NO;
  261. return [self isEqualToTicket:other];
  262. }
  263. - (BOOL)isEqualToTicket:(KSTicket *)ticket {
  264. if (ticket == self)
  265. return YES;
  266. if (![productID_ isEqualToString:[ticket productID]])
  267. return NO;
  268. if (![version_ isEqualToString:[ticket version]])
  269. return NO;
  270. if (![existenceChecker_ isEqual:[ticket existenceChecker]])
  271. return NO;
  272. if (![serverURL_ isEqual:[ticket serverURL]])
  273. return NO;
  274. if (![creationDate_ isEqual:[ticket creationDate]])
  275. return NO;
  276. if (trustedTesterToken_ &&
  277. ![trustedTesterToken_ isEqual:[ticket trustedTesterToken]])
  278. return NO;
  279. if (tag_ && ![tag_ isEqual:[ticket tag]])
  280. return NO;
  281. if (tagPath_ && ![tagPath_ isEqual:[ticket tagPath]])
  282. return NO;
  283. if (tagKey_ && ![tagKey_ isEqual:[ticket tagKey]])
  284. return NO;
  285. if (brandPath_ && ![brandPath_ isEqual:[ticket brandPath]])
  286. return NO;
  287. if (brandKey_ && ![brandKey_ isEqual:[ticket brandKey]])
  288. return NO;
  289. if (versionPath_ && ![versionPath_ isEqual:[ticket versionPath]])
  290. return NO;
  291. if (versionKey_ && ![versionKey_ isEqual:[ticket versionKey]])
  292. return NO;
  293. return YES;
  294. }
  295. - (NSString *)description {
  296. // Please keep the description stable. Clients may depend on the output.
  297. NSString *tttokenString = @"";
  298. if (trustedTesterToken_) {
  299. tttokenString = [NSString stringWithFormat:@"\n\ttrustedTesterToken=%@",
  300. trustedTesterToken_];
  301. }
  302. NSString *tagString = @"";
  303. if (tag_) {
  304. tagString = [NSString stringWithFormat:@"\n\ttag=%@", tag_];
  305. }
  306. NSString *tagPathString = @"";
  307. if (tagPath_ && tagKey_) {
  308. tagPathString = [NSString stringWithFormat:@"\n\ttagPath=%@\n\ttagKey=%@",
  309. tagPath_, tagKey_];
  310. }
  311. NSString *brandPathString = @"";
  312. if (brandPath_ && brandKey_) {
  313. brandPathString =
  314. [NSString stringWithFormat:@"\n\tbrandPath=%@\n\tbrandKey=%@",
  315. brandPath_, brandKey_];
  316. }
  317. NSString *versionPathString = @"";
  318. if (versionPath_ && versionKey_) {
  319. versionPathString =
  320. [NSString stringWithFormat:@"\n\tversionPath=%@\n\tversionKey=%@",
  321. versionPath_, versionKey_];
  322. }
  323. return [NSString stringWithFormat:
  324. @"<%@:%p\n\tproductID=%@\n\tversion=%@\n\t"
  325. @"xc=%@\n\turl=%@\n\tcreationDate=%@%@%@%@%@%@\n>",
  326. [self class], self, productID_,
  327. version_, existenceChecker_, serverURL_, creationDate_,
  328. tttokenString, tagString, tagPathString, brandPathString,
  329. versionPathString];
  330. }
  331. - (id)plistForPath:(NSString *)path {
  332. NSString *fullPath = [path stringByExpandingTildeInPath];
  333. // Make sure it exists.
  334. NSFileManager *fm = [NSFileManager defaultManager];
  335. if (![fm fileExistsAtPath:fullPath]) return nil;
  336. // Make sure file is not too big.
  337. NSDictionary *fileAttrs = [fm fileAttributesAtPath:fullPath traverseLink:YES];
  338. NSNumber *sizeNumber = [fileAttrs valueForKey:NSFileSize];
  339. if (sizeNumber == nil) return nil;
  340. long fileSize = [sizeNumber longValue];
  341. if (fileSize > MAX_DATA_FILE_SIZE) return nil;
  342. // Use NSPropertyListSerialization to read the file.
  343. NSData *data = [NSData dataWithContentsOfFile:fullPath];
  344. if (data == nil) return nil;
  345. id plist = [NSPropertyListSerialization
  346. propertyListFromData:data
  347. mutabilityOption:NSPropertyListImmutable
  348. format:NULL
  349. errorDescription:NULL];
  350. if (![plist isKindOfClass:[NSDictionary class]]) return nil;
  351. return plist;
  352. }
  353. - (NSString *)productID {
  354. return productID_;
  355. }
  356. - (NSString *)version {
  357. return version_;
  358. }
  359. - (NSString *)versionPath {
  360. return versionPath_;
  361. }
  362. - (NSString *)versionKey {
  363. return versionKey_;
  364. }
  365. // Common code for determining the brand, tag, or version given a file system
  366. // path to a plist, a key within that plist, and an optional default value.
  367. - (NSString *)determineThingForPath:(NSString *)path
  368. key:(NSString *)key
  369. defaultValue:(NSString *)defaultValue {
  370. NSString *thing = defaultValue;
  371. if (path && key) {
  372. id plist = [self plistForPath:path];
  373. if (plist) {
  374. thing = [plist objectForKey:key];
  375. // Only strings allowed.
  376. if (![thing isKindOfClass:[NSString class]]) thing = nil;
  377. // Empty string means no thing.
  378. if ([thing isEqualToString:@""]) thing = nil;
  379. if ([thing length] > MAX_PATHTAG_SIZE) thing = nil;
  380. }
  381. }
  382. return thing;
  383. }
  384. - (NSString *)determineVersion {
  385. NSString *version = [self determineThingForPath:versionPath_
  386. key:versionKey_
  387. defaultValue:nil];
  388. // No such thing as no version.
  389. if (!version) version = version_;
  390. return version;
  391. }
  392. - (KSExistenceChecker *)existenceChecker {
  393. return existenceChecker_;
  394. }
  395. - (NSURL *)serverURL {
  396. return serverURL_;
  397. }
  398. - (NSDate *)creationDate {
  399. return creationDate_;
  400. }
  401. - (NSString *)trustedTesterToken {
  402. return trustedTesterToken_;
  403. }
  404. - (NSString *)tag {
  405. return tag_;
  406. }
  407. - (NSString *)tagPath {
  408. return tagPath_;
  409. }
  410. - (NSString *)tagKey {
  411. return tagKey_;
  412. }
  413. - (NSString *)determineTag {
  414. NSString *tag = [self determineThingForPath:tagPath_
  415. key:tagKey_
  416. defaultValue:tag_];
  417. return tag;
  418. }
  419. - (NSString *)brandPath {
  420. return brandPath_;
  421. }
  422. - (NSString *)brandKey {
  423. return brandKey_;
  424. }
  425. - (NSString *)determineBrand {
  426. NSString *brand = [self determineThingForPath:brandPath_
  427. key:brandKey_
  428. defaultValue:nil];
  429. return brand;
  430. }
  431. @end