From 53db2fd48e6af08c09a16d76a4f2cc0b64584de8 Mon Sep 17 00:00:00 2001 From: C Fraire Date: Sat, 19 May 2012 12:41:58 -0400 Subject: [PATCH] Verification logic moves to GPGServices: now cancelable and growled - decryptFiles now growls any signatures if possible, instead of opening a window - adjust parameter so growl windows show GPGServices icon - additional thread-safety in DummyVerificationController - FileVerificationController now thread-safe for calls from workers (though actually now deprecated and unused) --- Resources/en.lproj/InProgressWindow.xib | 7 +- Source/DummyVerificationController.h | 5 +- Source/DummyVerificationController.m | 15 ++- Source/FileVerificationController.h | 9 +- Source/FileVerificationController.m | 124 +++---------------- Source/GPGServices.m | 157 ++++++++++++++++++++++-- 6 files changed, 191 insertions(+), 126 deletions(-) diff --git a/Resources/en.lproj/InProgressWindow.xib b/Resources/en.lproj/InProgressWindow.xib index fafc856..82fdfa6 100644 --- a/Resources/en.lproj/InProgressWindow.xib +++ b/Resources/en.lproj/InProgressWindow.xib @@ -216,7 +216,7 @@ 268 - {{434, 8}, {26, 32}} + {{434, 13}, {26, 20}} @@ -233,13 +233,12 @@ _NS:9 - -933478145 + 106709247 34 - + NSImage NSStopProgressTemplate - 400 diff --git a/Source/DummyVerificationController.h b/Source/DummyVerificationController.h index 19b88ca..f4d5f8a 100644 --- a/Source/DummyVerificationController.h +++ b/Source/DummyVerificationController.h @@ -17,10 +17,11 @@ IBOutlet NSProgressIndicator* indicator; IBOutlet FileVerificationDataSource* dataSource; - BOOL isActive; + BOOL _isActive; } -@property(assign) BOOL isActive; +// thread-safe +@property (assign, nonatomic) BOOL isActive; // thread-safe - (void)showWindow:(id)sender; diff --git a/Source/DummyVerificationController.m b/Source/DummyVerificationController.m index c7f07c3..87a80c4 100644 --- a/Source/DummyVerificationController.m +++ b/Source/DummyVerificationController.m @@ -11,6 +11,7 @@ @interface DummyVerificationController (ThreadSafety) +- (void)setIsActiveOnMain:(NSNumber *)isActive; - (void)showWindowOnMain:(id)sender; - (void)addResultsOnMain:(NSDictionary *)results; - (void)addResultFromSigOnMain:(NSArray *)args; @@ -20,7 +21,7 @@ - (void)runModalOnMain:(NSMutableArray *)resHolder; @implementation DummyVerificationController -@synthesize isActive; +@synthesize isActive = _isActive; - (id)initWithWindowNibName:(NSString *)windowNibName { self = [super initWithWindowNibName:windowNibName]; @@ -28,6 +29,18 @@ - (id)initWithWindowNibName:(NSString *)windowNibName { return self; } +- (void)setIsActive:(BOOL)isActive { + [self performSelectorOnMainThread:@selector(setIsActiveOnMain:) + withObject:[NSNumber numberWithBool:isActive] waitUntilDone:NO]; +} + +// called by setIsActive +- (void)setIsActiveOnMain:(NSNumber *)isActive { + [self willChangeValueForKey:@"isActive"]; + _isActive = [isActive boolValue]; + [self didChangeValueForKey:@"isActive"]; +} + - (void)windowDidLoad { [self bind:@"isActive" toObject:dataSource withKeyPath:@"isActive" options:nil]; } diff --git a/Source/FileVerificationController.h b/Source/FileVerificationController.h index 8610480..d833c39 100644 --- a/Source/FileVerificationController.h +++ b/Source/FileVerificationController.h @@ -25,14 +25,13 @@ @property(retain) NSArray* filesToVerify; @property(readonly) NSOperationQueue* verificationQueue; +// threadSafe - (NSInteger)runModal; -- (IBAction)okClicked:(id)sender; -//Callback contains all successfully checked files -- (void)startVerification:(void(^)(NSArray*))callback; +- (IBAction)okClicked:(id)sender; #pragma mark - Helper Methods -- (NSString*)searchFileForSignatureFile:(NSString*)file; -- (NSString*)searchSignatureFileForFile:(NSString*)sigFile; ++ (NSString*)searchFileForSignatureFile:(NSString*)file; ++ (NSString*)searchSignatureFileForFile:(NSString*)sigFile; @end diff --git a/Source/FileVerificationController.m b/Source/FileVerificationController.m index 8732f79..56e02c9 100644 --- a/Source/FileVerificationController.m +++ b/Source/FileVerificationController.m @@ -12,6 +12,12 @@ #import "FileVerificationDataSource.h" +@interface FileVerificationController () + +- (void)runModalOnMain:(NSMutableArray *)resHolder; + +@end + @implementation FileVerificationController @synthesize filesToVerify, verificationQueue; @@ -44,123 +50,33 @@ - (void)windowDidLoad { } - (NSInteger)runModal { + NSMutableArray *resHolder = [NSMutableArray arrayWithCapacity:1]; + [self performSelectorOnMainThread:@selector(runModalOnMain:) withObject:resHolder waitUntilDone:YES]; + return [[resHolder lastObject] integerValue]; +} + +- (void)runModalOnMain:(NSMutableArray *)resHolder { [NSApp activateIgnoringOtherApps:YES]; - [self showWindow:self]; + [self showWindow:nil]; NSInteger ret = [NSApp runModalForWindow:self.window]; [self.window close]; - return ret; + [resHolder addObject:[NSNumber numberWithInteger:ret]]; } - (IBAction)okClicked:(id)sender { [NSApp stopModalWithCode:0]; } -- (void)startVerification:(void(^)(NSArray*))callback { - //Load window to setup bindings - [self performSelectorOnMainThread:@selector(window) withObject:nil waitUntilDone:NO]; - [indicator performSelectorOnMainThread:@selector(startAnimation:) withObject:self waitUntilDone:NO]; - - for(NSString* serviceFile in self.filesToVerify) { - - //Do the file stuff here to be able to check if file is already in verification - NSString* signatureFile = serviceFile; - NSString* signedFile = [self searchFileForSignatureFile:signatureFile]; - if(signedFile == nil) { - NSString* tmp = [self searchSignatureFileForFile:signatureFile]; - signedFile = signatureFile; - signatureFile = tmp; - } - - if(signatureFile != nil) { - if([filesInVerification containsObject:signatureFile]) { - continue; - } else { - //Probably a problem with restarting of validation when files are missing - [filesInVerification addObject:signatureFile]; - } - } - - [verificationQueue addOperationWithBlock:^(void) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSFileManager* fmgr = [[[NSFileManager alloc] init] autorelease]; - - NSException* firstException = nil; - NSException* secondException = nil; - - NSArray* sigs = nil; - - if([fmgr fileExistsAtPath:signedFile] && [fmgr fileExistsAtPath:signatureFile]) { - @try { - GPGController* ctx = [GPGController gpgController]; - NSData* signatureFileData = [[[NSData alloc] initWithContentsOfFile:signatureFile] autorelease]; - NSData* signedFileData = [[[NSData alloc] initWithContentsOfFile:signedFile] autorelease]; - sigs = [ctx verifySignature:signatureFileData originalData:signedFileData]; - } @catch (NSException *exception) { - firstException = exception; - sigs = nil; - } - } - - //Try to verify the file itself without a detached sig - if(sigs == nil || sigs.count == 0) { - @try { - GPGController* ctx = [GPGController gpgController]; - NSData* signedFileData = [[[NSData alloc] initWithContentsOfFile:serviceFile] autorelease]; - sigs = [ctx verifySignedData:signedFileData]; - } @catch (NSException *exception) { - secondException = exception; - sigs = nil; - } - } - - if(sigs != nil) { - if(sigs.count == 0) { - id verificationResult = nil; //NSString or NSAttributedString - verificationResult = @"Verification FAILED: No signatures found"; - - NSColor* bgColor = [NSColor colorWithCalibratedRed:0.8 green:0.0 blue:0.0 alpha:0.7]; - - NSRange range = [verificationResult rangeOfString:@"FAILED"]; - verificationResult = [[NSMutableAttributedString alloc] - initWithString:verificationResult]; - - [verificationResult addAttribute:NSFontAttributeName - value:[NSFont boldSystemFontOfSize:[NSFont systemFontSize]] - range:range]; - [verificationResult addAttribute:NSBackgroundColorAttributeName - value:bgColor - range:range]; - - NSDictionary* result = [NSDictionary dictionaryWithObjectsAndKeys: - [signedFile lastPathComponent], @"filename", - verificationResult, @"verificationResult", - nil]; - [dataSource addResults:result]; - } else if(sigs.count > 0) { - for(GPGSignature* sig in sigs) { - [dataSource addResultFromSig:sig forFile:signedFile]; - } - } - } else { - [dataSource addResults:[NSDictionary dictionaryWithObjectsAndKeys: - [signedFile lastPathComponent], @"filename", - @"No verifiable data found", @"verificationResult", - nil]]; - } - - [pool release]; - }]; - } -} - // Who invokes this and what does it do? - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if([keyPath isEqualToString:@"operationCount"]) { - if([object operationCount] == 0) - [indicator stopAnimation:self]; + if([object operationCount] == 0) { + [indicator performSelectorOnMainThread:@selector(stopAnimation:) + withObject:self waitUntilDone:NO]; + } } } @@ -172,7 +88,7 @@ - (void)doubleClickAction:(id)sender { #pragma mark - Helper Methods -- (NSString*)searchFileForSignatureFile:(NSString*)sigFile { ++ (NSString*)searchFileForSignatureFile:(NSString*)sigFile { NSFileManager* fmgr = [[[NSFileManager alloc] init] autorelease]; NSString* file = [sigFile stringByDeletingPathExtension]; @@ -183,7 +99,7 @@ - (NSString*)searchFileForSignatureFile:(NSString*)sigFile { return nil; } -- (NSString*)searchSignatureFileForFile:(NSString*)sigFile { ++ (NSString*)searchSignatureFileForFile:(NSString*)sigFile { NSFileManager* fmgr = [[[NSFileManager alloc] init] autorelease]; NSSet* exts = [NSSet setWithObjects:@".sig", @".asc", nil]; diff --git a/Source/GPGServices.m b/Source/GPGServices.m index 9823cd6..e4f043d 100644 --- a/Source/GPGServices.m +++ b/Source/GPGServices.m @@ -48,6 +48,10 @@ - (void)encryptFilesWrapped:(ServiceWrappedArgs *)wrappedArgs; - (void)decryptFilesWrapped:(ServiceWrappedArgs *)wrappedArgs; - (void)verifyFilesWrapped:(ServiceWrappedArgs *)wrappedArgs; - (void)importFilesWrapped:(ServiceWrappedArgs *)wrappedArgs; + +// If growl is active, produce one for a file's signatures +- (void)growlVerificationResultsFor:(NSString *)file signatures:(NSArray *)signatures; + @end @implementation GPGServices @@ -980,14 +984,21 @@ - (void)decryptFilesWrapped:(ServiceWrappedArgs *)wrappedArgs { if (ctx.error) @throw ctx.error; - if(ctx.signatures && ctx.signatures.count > 0) { + // + // Show any signatures encountered + // + if ([GrowlApplicationBridge isGrowlRunning]) { + if ([ctx.signatures count] > 0) + [self growlVerificationResultsFor:file signatures:ctx.signatures]; + } + else if(ctx.signatures && ctx.signatures.count > 0) { GPGDebugLog(@"found signatures: %@", ctx.signatures); if(dummyController == nil) { dummyController = [[DummyVerificationController alloc] initWithWindowNibName:@"VerificationResultsWindow"]; [dummyController showWindow:self]; // now thread-safe - dummyController.isActive = YES; + dummyController.isActive = YES; // now thread-safe } for(GPGSignature* sig in ctx.signatures) { @@ -1075,14 +1086,140 @@ - (void)verifyFilesWrapped:(ServiceWrappedArgs *)wrappedArgs { // because it's retained by NSOperation that is wrapping the process NSArray *files = wrappedArgs.arg1; - // all thread-safe - FileVerificationController* fvc = [[FileVerificationController alloc] init]; - fvc.filesToVerify = files; - [fvc startVerification:nil]; - [fvc runModal]; - [fvc release]; + NSMutableSet *filesInVerification = [NSMutableSet set]; + NSFileManager* fmgr = [[[NSFileManager alloc] init] autorelease]; + + // has thread-safe methods as used here + DummyVerificationController* fvc = nil; + if ([GrowlApplicationBridge isGrowlRunning] == NO) { + fvc = [[[DummyVerificationController alloc] + initWithWindowNibName:@"VerificationResultsWindow"] autorelease]; + [fvc showWindow:self]; // now thread-safe + fvc.isActive = YES; // now thread-safe + } + + for (NSString* serviceFile in files) { + // check before operation + if (wrappedArgs.worker.amCanceling) + return; + + //Do the file stuff here to be able to check if file is already in verification + NSString* signatureFile = serviceFile; + NSString* signedFile = [FileVerificationController searchFileForSignatureFile:signatureFile]; + if(signedFile == nil) { + NSString* tmp = [FileVerificationController searchSignatureFileForFile:signatureFile]; + signedFile = signatureFile; + signatureFile = tmp; + } + + if(signatureFile != nil) { + if([filesInVerification containsObject:signatureFile]) + continue; + + //Probably a problem with restarting of validation when files are missing + [filesInVerification addObject:signatureFile]; + } + + NSException* firstException = nil; + NSException* secondException = nil; + + NSArray* sigs = nil; + + if([fmgr fileExistsAtPath:signedFile] && [fmgr fileExistsAtPath:signatureFile]) { + @try { + GPGController* ctx = [GPGController gpgController]; + NSData* signatureFileData = [[[NSData alloc] initWithContentsOfFile:signatureFile] autorelease]; + NSData* signedFileData = [[[NSData alloc] initWithContentsOfFile:signedFile] autorelease]; + sigs = [ctx verifySignature:signatureFileData originalData:signedFileData]; + } @catch (NSException *exception) { + firstException = exception; + sigs = nil; + } + + // check after operation + if (wrappedArgs.worker.amCanceling) + return; + } + + //Try to verify the file itself without a detached sig + if(sigs == nil || sigs.count == 0) { + @try { + GPGController* ctx = [GPGController gpgController]; + NSData* signedFileData = [[[NSData alloc] initWithContentsOfFile:serviceFile] autorelease]; + sigs = [ctx verifySignedData:signedFileData]; + + } @catch (NSException *exception) { + secondException = exception; + sigs = nil; + } + + // check after operation + if (wrappedArgs.worker.amCanceling) + return; + } + + if ([GrowlApplicationBridge isGrowlRunning]) { + [self growlVerificationResultsFor:serviceFile signatures:sigs]; + } + else if(sigs != nil) { + if(sigs.count == 0) { + id verificationResult = nil; //NSString or NSAttributedString + verificationResult = @"Verification FAILED: No signatures found"; + + NSColor* bgColor = [NSColor colorWithCalibratedRed:0.8 green:0.0 blue:0.0 alpha:0.7]; + + NSRange range = [verificationResult rangeOfString:@"FAILED"]; + verificationResult = [[NSMutableAttributedString alloc] + initWithString:verificationResult]; + + [verificationResult addAttribute:NSFontAttributeName + value:[NSFont boldSystemFontOfSize:[NSFont systemFontSize]] + range:range]; + [verificationResult addAttribute:NSBackgroundColorAttributeName + value:bgColor + range:range]; + + NSDictionary* result = [NSDictionary dictionaryWithObjectsAndKeys: + [signedFile lastPathComponent], @"filename", + verificationResult, @"verificationResult", + nil]; + [fvc addResults:result]; + } else if(sigs.count > 0) { + for(GPGSignature* sig in sigs) { + [fvc addResultFromSig:sig forFile:signedFile]; + } + } + } else { + [fvc addResults:[NSDictionary dictionaryWithObjectsAndKeys: + [signedFile lastPathComponent], @"filename", + @"No verifiable data found", @"verificationResult", + nil]]; + } + } + + [fvc runModal]; // thread-safe } +- (void)growlVerificationResultsFor:(NSString *)file signatures:(NSArray *)signatures +{ + if ([GrowlApplicationBridge isGrowlRunning] != YES) + return; + + NSString *title = [NSString stringWithFormat:@"Verification for %@", + [self quoteOneFilesName:[NSArray arrayWithObject:file]]]; + + NSMutableString *summary = [NSMutableString string]; + if ([signatures count] > 0) { + for (GPGSignature *gpgSig in signatures) { + [summary appendFormat:@"%@\n", [gpgSig humanReadableDescription]]; + } + } + else { + [summary appendString:@"No signatures found"]; + } + + [self displayOperationFinishedNotificationWithTitle:title message:summary]; +} //Skip fixing this for now. We need better handling of imports in libmacgpg. /* @@ -1468,7 +1605,7 @@ - (void)displayOperationFinishedNotificationWithTitleOnMain:(NSArray *)args { [GrowlApplicationBridge notifyWithTitle:title description:body notificationName:gpgGrowlOperationSucceededName - iconData:[NSData data] + iconData:nil priority:0 isSticky:NO clickContext:NULL]; @@ -1491,7 +1628,7 @@ - (void)displayOperationFailedNotificationWithTitleOnMain:(NSArray *)args { [GrowlApplicationBridge notifyWithTitle:title description:body notificationName:gpgGrowlOperationFailedName - iconData:[NSData data] + iconData:nil priority:0 isSticky:NO clickContext:NULL];