Skip to content

Commit

Permalink
Unify signing proceedure
Browse files Browse the repository at this point in the history
[#282 state:fixed milestone:1.4.3]
  • Loading branch information
Mento committed Jan 9, 2018
1 parent 5eeb6e8 commit b354238
Show file tree
Hide file tree
Showing 12 changed files with 758 additions and 227 deletions.
2 changes: 1 addition & 1 deletion Resources/Base.lproj/MainMenu.xib
Original file line number Diff line number Diff line change
Expand Up @@ -2538,7 +2538,7 @@ CA
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="1864"/>
<menuItem title="Sign…" keyEquivalent="s" id="1597">
<menuItem title="Sign…" tag="-1" keyEquivalent="s" id="1597">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="addSignature:" target="-1" id="1631"/>
Expand Down
557 changes: 406 additions & 151 deletions Resources/Base.lproj/ModalSheets.xib

Large diffs are not rendered by default.

17 changes: 17 additions & 0 deletions Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ RevokedSubkeyWantToUpload_Msg = "To make it easier for your friends and colleagu
RevokedSubkeyWantToUpload_Yes = "Upload Public Key";
RevokedSubkeyWantToUpload_No = "No, Thanks!";

UserIDsSignedWantToUpload_Title = "Signing successful";
UserIDsSignedWantToUpload_Msg = "To make it easier for your friends to learn about the new signature, it is recommended to upload the signed public key to the key servers.\n\nDo you want to upload your public key?";
UserIDsSignedWantToUpload_Yes = "Upload Public Key";
UserIDsSignedWantToUpload_No = "No, Thanks!";



Expand Down Expand Up @@ -262,6 +266,10 @@ UploadSuccess_Msg = "The following public keys have been sent to the key servers
ExportSuccess_Title = "Export successful";
ExportSuccess_Msg = "The following keys were successfully exported:\n\n%@";

SignSuccess_Title = "Signing successful";
SignSuccess_Msg = "The selected user IDs have been signed.";



/* For Import-Results */
IMPORT_RESULT_NEW_KEY = "The following key was successfully imported:\n\n%@";
Expand Down Expand Up @@ -398,3 +406,12 @@ SendPublicKeyToKeyserver_MenuItem = "Send Public Key to Key Server";
FilterNoResults = "The local search for '%@' has no results.";
FilterNoResultsSecOnly = "The local search for '%@' has no results.\nConsider disabling the option to 'Show secret keys only' to expand the search.";



SignKey_KeyClaimsMultipleIdentities = "The key:\n%@\nclaims more than one identity. Which ones have you verified?";
SignKey_PublishSingleIdentity = "If you choose to publish this signature, everyone in the world can see that you believe this key belongs to %@.";
SignKey_PublishMultipleIdentities = "If you choose to publish this signature, everyone in the world can see that you believe this key belongs to the identities you've checked.";
SignKey_MainMsg = "By signing this key you confirm the identity of the key owner and that the key with fingerprint %@ belongs to them.";



15 changes: 6 additions & 9 deletions Resources/en.lproj/ModalSheets.strings
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,13 @@
"254.title" = "Elgamal (encrypt only)";
"255.title" = "RSA (sign only)";
"256.title" = "DSA (sign only)";
"378.title" = "Generate Signature";
"378.title" = "Sign";
"379.title" = "Cancel";
"381.title" = "Expiration date:";
"389.title" = "I will not answer.";
"392.title" = "Signature expires";
"405.title" = "I have not checked at all.";
"406.title" = "I have done casual checking.";
"407.title" = "I have done very careful checking.";
"409.title" = "How carefully have you verified, that the key you are about to sign actually belongs to the person named above?";
"427.title" = "Change Expiration Date";
"428.title" = "Cancel";
"430.title" = "Expiration date:";
"441.title" = "Key expires";
"468.title" = "Local signature";
"481.title" = "Search";
"482.title" = "Cancel";
"485.title" = "Search for public key";
Expand Down Expand Up @@ -69,8 +62,12 @@
"1095.title" = "Cancel";
"1153.ibExternalAccessibilityDescription" = "Advanced options";
"1156.title" = "Advanced options";
"2JB-h4-xn9.title" = "Example: You signed Bob's key. Your friend Alice finds Bob's key on the key server, but she is unsure if the found key is really Bob's key. Alice sees your signature on Bob's key and since Alice knows the fingerprint of your key is trustworthy, she assumes that the found key for Bob is indeed his key.";
"8NR-sq-tyn.title" = "Move now";
"9R1-eW-2wX.title" = "Your secret key used to sign:";
"D2R-cV-2w2.title" = "This key claims more than one identity. Which ones have you verified?";
"Ebm-sP-X8A.title" = "Why Publish?";
"FWA-34-yOE.title" = "Cancel";
"FsT-ha-Sbf.ibShadowedIsNilPlaceholder" = "Search for name, email or fingerprint.";
"J0P-gR-G8d.title" = "Publish";
"c3R-Qv-JF7.title" = "GPG Keychain will move your secret keys to the selected location. gpg will find your keys as soon as the target volume is connected to this machine.\n\nIMPORTANT: After moving your secret keys, you will always need the new target volume to sign or decrypt mails or files.";
"eKE-tf-ktq.title" = "Do you want your signature to expire (recommended)?";
13 changes: 12 additions & 1 deletion Source/ActionController.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright © Roman Zechmeister, 2017
Copyright © Roman Zechmeister, 2018
Diese Datei ist Teil von GPG Keychain.
Expand All @@ -22,6 +22,16 @@

@class SheetController;

typedef enum {
DescriptionNoKeyID = 8,
DescriptionNoEmail = 16,
DescriptionNoName = 32,
DescriptionSingleLine = 64,
DescriptionIndent = 128,
DescriptionFingerprint = 256

} DescriptionOptions;


@interface ActionController : NSWindowController <GPGControllerDelegate, NSPopoverDelegate, GKMenuButtonDelegate> {
GPGController *gpgc;
Expand Down Expand Up @@ -82,5 +92,6 @@
- (IBAction)sendKeysPerMail:(id)sender;
- (BOOL)validateUserInterfaceItem:(id)anItem;

- (NSString *)descriptionForKeys:(NSObject <EnumerationList> *)keys maxLines:(NSUInteger)lines withOptions:(DescriptionOptions)options;

@end
149 changes: 114 additions & 35 deletions Source/ActionController.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright © Roman Zechmeister, 2017
Copyright © Roman Zechmeister, 2018
Diese Datei ist Teil von GPG Keychain.
Expand Down Expand Up @@ -1928,63 +1928,133 @@ - (IBAction)addSignature:(id)sender {
return;
}

GPGKey *key = [keys[0] primaryKey];
if (key.validity >= GPGValidityInvalid) {
// Only valid keys can be signed.
return;
}

GPGUserID *userID = nil;
if ([sender tag] == 1) {
if ([sender tag] == 1 || ([sender tag] == -1 && (mainWindow.firstResponder == userIDsTable || mainWindow.firstResponder == signaturesTable))) {
NSArray *objects = [self selectedObjectsOf:userIDsTable];
if (objects.count != 1) {
return;
if (objects.count == 1) {
// The user has selected a userID in the user ids tab.
// This userID will be pre-selected.
userID = objects[0];
}
userID = [objects objectAtIndex:0];
}

GPGKey *key = [keys[0] primaryKey];
if (key.validity >= GPGValidityInvalid) {
return;
}

// Get a sorted list of all secret keys, which could be used for signing.
NSSet *usableSecretKeys = [[KeychainController sharedInstance].secretKeys objectsPassingTest:^BOOL(GPGKey *secretKey, BOOL *stop) {
return secretKey.validity < GPGValidityInvalid && secretKey.canAnySign;
}];

if (usableSecretKeys.count == 0) {
[self.sheetController errorSheetWithMessageText:localized(@"NO_SECRET_KEY_TITLE") infoText:localized(@"NO_SECRET_KEY_MESSAGE")];
return;
}

NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSArray *secretKeys = [usableSecretKeys sortedArrayUsingDescriptors:@[descriptor]];


GPGKey *defaultKey = [KeychainController sharedInstance].defaultKey;
if (!defaultKey) {
if (!defaultKey || ![secretKeys containsObject:defaultKey]) {
// If the user haven't specified a default key, the first secret key is used.
defaultKey = secretKeys[0];
}


NSString *msgText;
if (userID) {
msgText = [NSString stringWithFormat:localized(@"GenerateUidSignature_Msg"), [NSString stringWithFormat:@"%@ (%@)", userID.userIDDescription, key.keyID.shortKeyID]];
} else {
msgText = [NSString stringWithFormat:localized(@"GenerateSignature_Msg"), key.userIDAndKeyID];
}

self.sheetController.msgText = msgText;
self.sheetController.secretKeys = secretKeys;
self.sheetController.secretKey = defaultKey;
self.sheetController.publicKey = key;
self.sheetController.selectedUserIDs = userID ? @[userID] : nil;
self.sheetController.msgText = localizedStringWithFormat(@"GenerateSignature_Msg", key.userIDAndKeyID);



__block int64_t runningTasks = 2;
__block BOOL keyExistsOnServer = NO;
void (^uploadBlock)() = ^() {
if (OSAtomicAdd64Barrier(-1, &runningTasks) == 0) {
// Run this code when uploadBlock is called the second time.

if (keyExistsOnServer) {
if ([self warningSheetWithDefault:YES string:@"UserIDsSignedWantToUpload"]) {
self.progressText = localizedStringWithFormat(@"SendKeysToServer_Progress", [self descriptionForKey:key]);
self.errorText = localized(@"SendKeysToServer_Error");
[gpgc sendKeysToServer:@[key]];
}
} else {
[self.sheetController alertSheetWithTitle:localized(@"SignSuccess_Title")
message:localized(@"SignSuccess_Msg")
defaultButton:nil
alternateButton:nil
otherButton:nil
suppressionButton:nil];
}
}
};
// Check if the key already exists on the server and only ask for upload after signing, if that's the case.
[gpgc keysExistOnServer:@[key] callback:^(NSArray *existingKeys, NSArray *nonExistingKeys) {
keyExistsOnServer = existingKeys.count == 1;
uploadBlock();
}];
actionCallback callback = [^(GPGController *gc, id value, NSDictionary *userInfo) {
if (gc.error) {
[self.sheetController endProgressSheet];
return;
}
if (self.sheetController.publish) {
uploadBlock();
} else {
// The user do not want to publish the signature.
// Do not offer upload, only show success message.
[self.sheetController alertSheetWithTitle:localized(@"SignSuccess_Title")
message:localized(@"SignSuccess_Msg")
defaultButton:nil
alternateButton:nil
otherButton:nil
suppressionButton:nil];
}
} copy];


// Show the sign dialog.
self.sheetController.sheetType = SheetTypeAddSignature;
if ([self.sheetController runModalForWindow:mainWindow] != NSOKButton) {
return;
}

// Get the selected userIDs. Only procced if the user selected a userID.
NSArray *userIDs = self.sheetController.selectedUserIDs;
if (userIDs.count == 0) {
return;
}


self.progressText = localized(@"AddSignature_Progress");
self.errorText = localized(@"AddSignature_Error");
[gpgc signUserID:[userID hashID]
ofKey:key
signKey:self.sheetController.secretKey
type:(int)self.sheetController.sigType
local:self.sheetController.localSig
daysToExpire:(int)self.sheetController.daysToExpire];
[self showProgressUntilKeyIsRefreshed:key];


gpgc.userInfo = @{@"action": @[callback]};

if ([gpgc respondsToSelector:@selector(signUserIDs:signerKey:local:daysToExpire:)]) {
[gpgc signUserIDs:userIDs
signerKey:self.sheetController.secretKey
local:!self.sheetController.publish
daysToExpire:(int)self.sheetController.daysToExpire];
} else {
// This is only a workaround for old Libmacgpg versions.
for (GPGUserID *uid in userIDs) {
[gpgc signUserID:uid.hashID
ofKey:key
signKey:self.sheetController.secretKey
type:0
local:!self.sheetController.publish
daysToExpire:(int)self.sheetController.daysToExpire];
}
}
}
- (IBAction)removeSignature:(id)sender {
NSArray *objects = [self selectedObjectsOf:signaturesTable];
Expand Down Expand Up @@ -2644,6 +2714,7 @@ - (NSString *)descriptionForKeys:(NSObject <EnumerationList> *)keys maxLines:(NS
NSMutableString *descriptions = [NSMutableString string];
Class gpgKeyClass = [GPGKey class];
Class dictionaryClass = [NSDictionary class];
Class userIDClass = [GPGUserID class];
NSUInteger i = 0, count = keys.count;
if (count == 0) {
return @"";
Expand All @@ -2657,6 +2728,7 @@ - (NSString *)descriptionForKeys:(NSObject <EnumerationList> *)keys maxLines:(NS
BOOL showEmail = !(options & DescriptionNoEmail);
BOOL singleLine = options & DescriptionSingleLine;
BOOL indent = options & DescriptionIndent;
BOOL showFingerprint = !!(options & DescriptionFingerprint);

NSString *lineBreak = indent ? @"\n\t" : @"\n";
if (indent) {
Expand All @@ -2673,7 +2745,7 @@ - (NSString *)descriptionForKeys:(NSObject <EnumerationList> *)keys maxLines:(NS
break;
}

if (![key isKindOfClass:gpgKeyClass] && ![key isKindOfClass:dictionaryClass]) {
if (![key isKindOfClass:gpgKeyClass] && ![key isKindOfClass:dictionaryClass] && ![key isKindOfClass:userIDClass]) {
GPGKeyManager *keyManager = [GPGKeyManager sharedInstance];
GPGKey *realKey = [[keyManager allKeysAndSubkeys] member:key];

Expand All @@ -2693,11 +2765,18 @@ - (NSString *)descriptionForKeys:(NSObject <EnumerationList> *)keys maxLines:(NS
}


BOOL isUserID = [key isKindOfClass:userIDClass];

if ([key isKindOfClass:gpgKeyClass] || [key isKindOfClass:dictionaryClass]) {
if ([key isKindOfClass:gpgKeyClass] || [key isKindOfClass:dictionaryClass] || isUserID) {
NSString *name = [key valueForKey:@"name"];
NSString *email = [key valueForKey:@"email"];
NSString *shortKeyID = [[key valueForKey:@"keyID"] shortKeyID];
NSString *keyID;
if (showFingerprint) {
keyID = isUserID ? [(GPGUserID *)key primaryKey].fingerprint : [key valueForKey:@"fingerprint"];
keyID = [[GKFingerprintTransformer sharedInstance] transformedValue:keyID];
} else {
keyID = isUserID ? [(GPGUserID *)key primaryKey].keyID : [key valueForKey:@"keyID"];
}

NSUInteger mailFlag = 0;
if (name.length == 0) {
Expand All @@ -2719,20 +2798,20 @@ - (NSString *)descriptionForKeys:(NSObject <EnumerationList> *)keys maxLines:(NS
[descriptions appendFormat:@"%@%@ <%@>", seperator, name, email];
break;
case 4:
[descriptions appendFormat:@"%@%@", seperator, shortKeyID];
[descriptions appendFormat:@"%@%@", seperator, keyID];
break;
case 5:
[descriptions appendFormat:@"%@%@ (%@)", seperator, name, shortKeyID];
[descriptions appendFormat:@"%@%@ (%@)", seperator, name, keyID];
break;
case 6:
[descriptions appendFormat:@"%@%@ (%@)", seperator, email, shortKeyID];
[descriptions appendFormat:@"%@%@ (%@)", seperator, email, keyID];
break;
default:
[descriptions appendFormat:@"%@%@ <%@> (%@)", seperator, name, email, shortKeyID];
[descriptions appendFormat:@"%@%@ <%@> (%@)", seperator, name, email, keyID];
break;
}
} else {
[descriptions appendFormat:@"%@%@", seperator, key.shortKeyID];
[descriptions appendFormat:@"%@%@", seperator, showFingerprint ? [[GKFingerprintTransformer sharedInstance] transformedValue:key.fingerprint] : key.keyID];
}


Expand Down
15 changes: 3 additions & 12 deletions Source/ActionController_Private.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright © Roman Zechmeister, 2017
Copyright © Roman Zechmeister, 2018
Diese Datei ist Teil von GPG Keychain.
Expand All @@ -19,20 +19,11 @@

#import "Globales.h"

@class GKPhotoPopoverController;
@class GKPhotoPopoverController, SheetController;


@interface ActionController ()

typedef enum {
DescriptionNoKeyID = 8,
DescriptionNoEmail = 16,
DescriptionNoName = 32,
DescriptionSingleLine = 64,
DescriptionIndent = 128

} DescriptionOptions;


@property (weak) IBOutlet NSArrayController *keysController;
@property (weak) IBOutlet NSArrayController *signaturesController;
Expand All @@ -46,13 +37,13 @@ typedef enum {
@property (weak) IBOutlet GKPhotoPopoverController *photoPopoverController;
@property (weak) IBOutlet NSPopover *photoPopover;

@property (readonly) SheetController *sheetController;

@property (strong) NSString *progressText, *errorText;
@property (strong, readonly) NSUndoManager *undoManager;
@property (strong) NSSet *revCertCache;

- (void)receiveKeysFromServer:(NSObject <EnumerationList> *)keys;
- (NSString *)descriptionForKeys:(NSObject <EnumerationList> *)keys maxLines:(NSUInteger)lines withOptions:(DescriptionOptions)options;

- (BOOL)warningSheetWithDefault:(BOOL)defaultValue string:(NSString *)string, ...;

Expand Down
Loading

0 comments on commit b354238

Please sign in to comment.