9
9
10
10
#include < ApplicationServices/ApplicationServices.h>
11
11
#import < AppKit/AppKit.h>
12
- #include < errno.h>
13
- #include < string.h>
14
- #include < sys/sysctl.h>
15
- #include < Security/Security.h>
16
- #include < CoreServices/CoreServices.h>
17
- #include < Security/SecKeychain.h>
18
- #include < Security/SecKeychainItem.h>
19
- #include < Security/SecAccess.h>
20
- #include < Security/SecTrustedApplication.h>
21
- #include < Security/SecACL.h>
22
- #include < CoreFoundation/CoreFoundation.h>
23
-
24
- #define OKBUTTONWIDTH 100.0
25
- #define OKBUTTONHEIGHT 24.0
26
- #define CANCELBUTTONWIDTH 100.0
27
- #define CANCELBUTTONHEIGHT 24.0
28
- #define PASSHEIGHT 22.0
29
- #define PASSLABELHEIGHT 16.0
30
- #define WINDOWAUTOSAVENAME @" GitXAskPasswordWindowFrame"
31
-
32
-
33
- @interface GAPAppDelegate : NSObject /* <NSApplicationDelegate>*/
12
+
13
+ #define OKBUTTONWIDTH 100.0
14
+ #define OKBUTTONHEIGHT 24.0
15
+ #define CANCELBUTTONWIDTH 100.0
16
+ #define CANCELBUTTONHEIGHT 24.0
17
+ #define PASSHEIGHT 22.0
18
+ #define PASSLABELHEIGHT 16.0
19
+ #define WINDOWAUTOSAVENAME @" GitXAskPasswordWindowFrame"
20
+
21
+
22
+ @interface GAPAppDelegate : NSObject
34
23
{
24
+ NSPanel * mPasswordPanel;
25
+ NSSecureTextField * mPasswordField;
35
26
}
36
27
37
- @end
38
-
39
- NSString * url;
40
- OSStatus StorePasswordKeychain (const char *url, UInt32 urlLength, void * password,UInt32 passwordLength);
28
+ -(NSPanel *) passwordPanel ;
41
29
30
+ -(IBAction ) doOKButton : (id )sender ;
31
+ -(IBAction ) doCancelButton : (id )sender ;
42
32
43
- @implementation GAPAppDelegate
33
+ @end
44
34
45
- -(void )yesNo : (NSString *)prompt url : (NSString *)url {
46
- NSAlert *alert = [[NSAlert alloc ] init ];
47
- [alert addButtonWithTitle: @" YES" ];
48
- [alert addButtonWithTitle: @" NO" ];
49
- [alert setMessageText: [NSString stringWithFormat: @" %@ ?" ,url]];
50
- [alert setInformativeText: prompt];
51
- [alert setAlertStyle: NSWarningAlertStyle ];
52
- NSInteger result = [alert runModal ];
53
-
54
- Boolean yes=NO ;
55
- if ( result == NSAlertFirstButtonReturn ) {
56
- yes=YES ;
57
- }
58
- [alert release ];
59
- printf (" %s " ,yes?" yes" :" no" );
60
- }
61
35
36
+ @implementation GAPAppDelegate
62
37
63
- - (void )pasword : (NSString *)prompt url : (NSString *)url {
64
-
65
- NSRect box = NSMakeRect (0 , 0 , 200 , 24 );
66
-
67
- NSSecureTextField * passView = [[NSSecureTextField alloc ] initWithFrame: box];
68
- [passView setSelectable: YES ];
69
- [passView setEditable: YES ];
70
- [passView setBordered: YES ];
71
- [passView setBezeled: YES ];
72
- [passView setBezelStyle: NSTextFieldSquareBezel];
73
- [passView selectText: self ];
74
-
75
-
76
- NSAlert *alert = [[NSAlert alloc ] init ];
77
- [alert addButtonWithTitle: @" Ok" ];
78
- [alert addButtonWithTitle: @" cancel" ];
79
- [alert setMessageText: [NSString stringWithFormat: @" %@ ?" ,url]];
80
- [alert setInformativeText: prompt];
81
- [alert setAlertStyle: NSWarningAlertStyle ];
82
- [alert setAccessoryView: passView];
83
- [alert setShowsSuppressionButton: YES ];
84
- [[alert suppressionButton ] setTitle: @" Save on keychain" ];
85
- NSInteger result = [alert runModal ];
86
- if ( result == NSAlertFirstButtonReturn ) {
87
- NSString *pas=[passView stringValue ];
88
- printf ( " %s " , [pas UTF8String ] );
89
- if ([[alert suppressionButton ] state ] == NSOnState ) {
90
- StorePasswordKeychain ([url cStringUsingEncoding: NSASCIIStringEncoding],
91
- [url lengthOfBytesUsingEncoding: NSASCIIStringEncoding],
92
- (void *)[pas cStringUsingEncoding: NSASCIIStringEncoding],
93
- [pas lengthOfBytesUsingEncoding: NSASCIIStringEncoding]);
38
+ -(NSPanel *) passwordPanel
39
+ {
40
+ if ( !mPasswordPanel )
41
+ {
42
+ NSRect box = NSMakeRect ( 100 , 100 , 400 , 134 );
43
+ mPasswordPanel = [[NSPanel alloc ] initWithContentRect: box
44
+ styleMask: NSTitledWindowMask
45
+ backing: NSBackingStoreBuffered defer: NO ];
46
+ [mPasswordPanel setHidesOnDeactivate: NO ];
47
+ [mPasswordPanel setLevel: NSFloatingWindowLevel ];
48
+ [mPasswordPanel setTitle: @" GitX SSH Remote Login" ];
49
+ if (![mPasswordPanel setFrameUsingName: WINDOWAUTOSAVENAME]) {
50
+ [mPasswordPanel center ];
51
+ [mPasswordPanel setFrameAutosaveName: WINDOWAUTOSAVENAME];
94
52
}
53
+
54
+ box.origin = NSZeroPoint ; // Only need local coords from now on.
55
+
56
+ // OK:
57
+ NSRect okBox = box;
58
+ okBox.origin .x = NSMaxX ( box ) -OKBUTTONWIDTH -20 ;
59
+ okBox.size .width = OKBUTTONWIDTH;
60
+ okBox.origin .y += 20 ;
61
+ okBox.size .height = OKBUTTONHEIGHT;
62
+ NSButton *okButton = [[NSButton alloc ] initWithFrame: okBox];
63
+ [okButton setTarget: self ];
64
+ [okButton setAction: @selector (doOKButton: )];
65
+ [okButton setTitle: @" OK" ]; // +++ Localize.
66
+ [okButton setKeyEquivalent: @" \r " ];
67
+ [okButton setBordered: YES ];
68
+ [okButton setBezelStyle: NSRoundedBezelStyle ];
69
+ [[mPasswordPanel contentView ] addSubview: okButton];
70
+
71
+ // Cancel:
72
+ NSRect cancelBox = box;
73
+ cancelBox.origin .x = NSMinX ( okBox ) -CANCELBUTTONWIDTH -6 ;
74
+ cancelBox.size .width = CANCELBUTTONWIDTH;
75
+ cancelBox.origin .y += 20 ;
76
+ cancelBox.size .height = CANCELBUTTONHEIGHT;
77
+ NSButton *cancleButton = [[NSButton alloc ] initWithFrame: cancelBox];
78
+ [cancleButton setTarget: self ];
79
+ [cancleButton setAction: @selector (doCancelButton: )];
80
+ [cancleButton setTitle: @" Cancel" ]; // +++ Localize.
81
+ [cancleButton setBordered: YES ];
82
+ [cancleButton setBezelStyle: NSRoundedBezelStyle ];
83
+ [[mPasswordPanel contentView ] addSubview: cancleButton];
84
+
85
+ // Password field:
86
+ NSRect passBox = box;
87
+ passBox.origin .y = NSMaxY (okBox) + 24 ;
88
+ passBox.size .height = PASSHEIGHT;
89
+ passBox.origin .x += 104 ;
90
+ passBox.size .width -= 104 + 20 ;
91
+ mPasswordField = [[NSSecureTextField alloc ] initWithFrame: passBox];
92
+ [mPasswordField setSelectable: YES ];
93
+ [mPasswordField setEditable: YES ];
94
+ [mPasswordField setBordered: YES ];
95
+ [mPasswordField setBezeled: YES ];
96
+ [mPasswordField setBezelStyle: NSTextFieldSquareBezel];
97
+ [mPasswordField selectText: self ];
98
+ [[mPasswordPanel contentView ] addSubview: mPasswordField];
99
+
100
+ // Password label:
101
+ NSRect passLabelBox = box;
102
+ passLabelBox.origin .y = NSMaxY (passBox) + 8 ;
103
+ passLabelBox.size .height = PASSLABELHEIGHT;
104
+ passLabelBox.origin .x += 100 ;
105
+ passLabelBox.size .width -= 100 + 20 ;
106
+ NSTextField *passwordLabel = [[NSTextField alloc ] initWithFrame: passLabelBox];
107
+ [passwordLabel setSelectable: YES ];
108
+ [passwordLabel setEditable: NO ];
109
+ [passwordLabel setBordered: NO ];
110
+ [passwordLabel setBezeled: NO ];
111
+ [passwordLabel setDrawsBackground: NO ];
112
+ [passwordLabel setStringValue: @" Please enter your password:" ]; // +++ Localize.
113
+ [[mPasswordPanel contentView ] addSubview: passwordLabel];
114
+
115
+ // GitX icon:
116
+ NSRect gitxIconBox = box;
117
+ gitxIconBox.origin .y = NSMaxY (box) - 78 ;
118
+ gitxIconBox.size .height = 64 ;
119
+ gitxIconBox.origin .x += 20 ;
120
+ gitxIconBox.size .width = 64 ;
121
+ NSImageView *gitxIconView = [[NSImageView alloc ] initWithFrame: gitxIconBox];
122
+ [gitxIconView setEditable: NO ];
123
+ NSString *gitxIconPath = [[[NSBundle mainBundle ] bundlePath ] stringByAppendingPathComponent: @" gitx.icns" ];
124
+ NSImage *gitxIcon = [[NSImage alloc ] initWithContentsOfFile: gitxIconPath];
125
+ [gitxIconView setImage: gitxIcon];
126
+ [[mPasswordPanel contentView ] addSubview: gitxIconView];
95
127
}
96
128
97
- [alert release ] ;
129
+ return mPasswordPanel ;
98
130
}
99
131
100
- @end
101
-
102
- void getproclline (pid_t pid, char *command_name);
103
132
104
- void getproclline ( pid_t pid, char *command_name)
133
+ -( IBAction ) doOKButton : ( id ) sender
105
134
{
106
- int mib[3 ], argmax, nargs, c = 0 ;
107
- size_t size;
108
- char *procargs, *sp, *np, *cp;
109
-
110
- mib[0 ] = CTL_KERN;
111
- mib[1 ] = KERN_ARGMAX;
112
-
113
- size = sizeof (argmax);
114
- if (sysctl (mib, 2 , &argmax, &size, NULL , 0 ) == -1 ) {
115
- return ;
116
- }
117
-
118
- /* Allocate space for the arguments. */
119
- procargs = (char *)malloc (argmax);
120
- if (procargs == NULL ) {
121
- return ;
122
- }
123
-
124
- mib[0 ] = CTL_KERN;
125
- mib[1 ] = KERN_PROCARGS2;
126
- mib[2 ] = pid;
127
-
128
- size = (size_t )argmax;
129
- if (sysctl (mib, 3 , procargs, &size, NULL , 0 ) == -1 ) {
130
- return ;
131
- }
132
-
133
- memcpy (&nargs, procargs, sizeof (nargs));
134
- cp = procargs + sizeof (nargs);
135
-
136
- /* Skip the saved exec_path. */
137
- for (; cp < &procargs[size]; cp++) {
138
- if (*cp == ' \0 ' ) {
139
- /* End of exec_path reached. */
140
- break ;
141
- }
142
- }
143
- if (cp == &procargs[size]) {
144
- return ;
145
- }
146
-
147
- /* Skip trailing '\0' characters. */
148
- for (; cp < &procargs[size]; cp++) {
149
- if (*cp != ' \0 ' ) {
150
- /* Beginning of first argument reached. */
151
- break ;
152
- }
153
- }
154
- if (cp == &procargs[size]) {
155
- return ;
156
- }
157
- /* Save where the argv[0] string starts. */
158
- sp = cp;
159
-
160
- for (np = NULL ; c < nargs && cp < &procargs[size]; cp++) {
161
- if (*cp == ' \0 ' ) {
162
- c++;
163
- if (np != NULL ) {
164
- *np = ' ' ;
165
- }
166
- np = cp;
167
- }
168
- }
169
- sprintf (command_name, " %s " ,sp);
135
+ printf ( " %s \n " , [[mPasswordField stringValue ] UTF8String ] );
136
+ [[NSApplication sharedApplication ] stopModalWithCode: 0 ];
170
137
}
171
138
172
- OSStatus StorePasswordKeychain (const char *url, UInt32 urlLength, void * password,UInt32 passwordLength)
173
- {
174
- OSStatus status;
175
- status = SecKeychainAddGenericPassword (
176
- NULL , // default keychain
177
- 4 , // length of service name
178
- " GitX" , // service name
179
- urlLength, // length of account name
180
- url, // account name
181
- passwordLength, // length of password
182
- password, // pointer to password data
183
- NULL // the item reference
184
- );
185
- return (status);
186
- }
187
139
188
- OSStatus GetPasswordKeychain (const char *url, UInt32 urlLength ,void *passwordData,UInt32 *passwordLength,
189
- SecKeychainItemRef *itemRef)
140
+ // TODO: Need to find out how to get SSH to cancel.
141
+ // When the user cancels the window it is opened again for however
142
+ // many times the remote server allows failed attempts.
143
+ -(IBAction ) doCancelButton : (id )sender
190
144
{
191
- OSStatus status ;
192
- status = SecKeychainFindGenericPassword (
193
- NULL , // default keychain
194
- 4 , // length of service name
195
- " GitX" , // service name
196
- urlLength, // length of account name
197
- url, // account name
198
- passwordLength, // length of password
199
- passwordData, // pointer to password data
200
- itemRef // the item reference
201
- );
202
- return (status);
145
+ [[NSApplication sharedApplication ] stopModalWithCode: 1 ];
203
146
}
204
147
148
+ @end
149
+
205
150
206
- int main ( int argc, const char * argv[] )
151
+
152
+ int main ( int argc, const char ** argv )
207
153
{
208
- // close stderr to stop cocoa log messages from being picked up by GitX
209
- close (STDERR_FILENO);
154
+ // close stderr to stop cocoa log messages from being picked up by GitX
155
+ close (STDERR_FILENO);
210
156
211
- ProcessSerialNumber myPSN = { 0 , kCurrentProcess };
212
- TransformProcessType ( &myPSN, kProcessTransformToForegroundApplication );
213
-
214
- NSApplication *app = [NSApplication sharedApplication ];
215
- GAPAppDelegate *appDel = [[GAPAppDelegate alloc ] init ];
216
- [app setDelegate: appDel];
157
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults ];
217
158
218
-
219
- char args[4024 ];
220
- getproclline (getppid (),args);
221
- NSString *cmd=[NSString stringWithFormat: @" %@ " ,[NSString stringWithUTF8String: args]];
159
+ ProcessSerialNumber myPSN = { 0 , kCurrentProcess };
160
+ TransformProcessType ( &myPSN, kProcessTransformToForegroundApplication );
222
161
223
- NSLog (@" cmd: '%@ '" ,cmd);
162
+ NSApplication *app = [NSApplication sharedApplication ];
163
+ GAPAppDelegate *appDel = [[GAPAppDelegate alloc ] init ];
164
+ [app setDelegate: appDel];
165
+ NSWindow *passPanel = [appDel passwordPanel ];
224
166
225
- if ([cmd hasPrefix: @" git-remote" ]){
226
- NSArray *args=[cmd componentsSeparatedByString: @" " ];
227
- NSString *url=[args objectAtIndex: [args count ]-1 ];
228
-
229
- void *passwordData = nil ;
230
- SecKeychainItemRef itemRef = nil ;
231
- UInt32 passwordLength = 0 ;
232
-
233
- OSStatus status = GetPasswordKeychain ([url cStringUsingEncoding: NSASCIIStringEncoding],[url lengthOfBytesUsingEncoding: NSASCIIStringEncoding],&passwordData,&passwordLength,&itemRef);
234
- if (status == noErr) {
235
- SecKeychainItemFreeContent (NULL ,passwordData);
236
- NSString *pas=[[NSString stringWithCString: passwordData encoding: NSASCIIStringEncoding] substringToIndex: passwordLength];
237
- printf ( " %s " , [pas UTF8String ] );
238
- return 0 ;
239
- }
240
-
241
- NSString *prompt=[NSString stringWithFormat: @" %@ " ,[NSString stringWithCString: argv[1 ] encoding: NSASCIIStringEncoding]];
242
- [appDel pasword: prompt url: url];
243
- }else { // yes/no?
244
- NSString *prompt=[NSString stringWithFormat: @" %@ " ,[NSString stringWithCString: argv[1 ] encoding: NSASCIIStringEncoding]];
245
- NSArray *args=[cmd componentsSeparatedByString: @" " ];
246
- NSString *url=[args objectAtIndex: 1 ];
247
- [appDel yesNo: prompt url: url];
248
- }
167
+ [app activateIgnoringOtherApps: YES ];
168
+ [passPanel makeKeyAndOrderFront: nil ];
169
+ NSInteger code = [app runModalForWindow: passPanel];
249
170
250
- return 0 ;
251
- }
171
+ [defaults synchronize ];
172
+
173
+ return code;
174
+ }
0 commit comments