9
9
10
10
#include < ApplicationServices/ApplicationServices.h>
11
11
#import < AppKit/AppKit.h>
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
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>*/
23
34
{
24
- NSPanel * mPasswordPanel;
25
- NSSecureTextField * mPasswordField;
26
35
}
27
36
28
- -( NSPanel *) passwordPanel ;
37
+ @end
29
38
30
- -( IBAction ) doOKButton : ( id ) sender ;
31
- -( IBAction ) doCancelButton : ( id ) sender ;
39
+ NSString * url ;
40
+ OSStatus StorePasswordKeychain ( const char *url, UInt32 urlLength, void * password,UInt32 passwordLength) ;
32
41
33
- @end
34
42
43
+ @implementation GAPAppDelegate
35
44
36
- @implementation GAPAppDelegate
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
+ }
37
61
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];
62
+
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]);
52
94
}
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];
127
95
}
128
96
129
- return mPasswordPanel ;
97
+ [alert release ] ;
130
98
}
131
99
100
+ @end
101
+
102
+ void getproclline (pid_t pid, char *command_name);
132
103
133
- -( IBAction ) doOKButton : ( id ) sender
104
+ void getproclline ( pid_t pid, char *command_name)
134
105
{
135
- printf ( " %s \n " , [[mPasswordField stringValue ] UTF8String ] );
136
- [[NSApplication sharedApplication ] stopModalWithCode: 0 ];
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);
137
170
}
138
171
139
-
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
172
+ OSStatus StorePasswordKeychain (const char *url, UInt32 urlLength, void * password,UInt32 passwordLength)
144
173
{
145
- [[NSApplication sharedApplication ] stopModalWithCode: 1 ];
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);
146
186
}
147
187
148
- @end
149
-
188
+ OSStatus GetPasswordKeychain (const char *url, UInt32 urlLength ,void *passwordData,UInt32 *passwordLength,
189
+ SecKeychainItemRef *itemRef)
190
+ {
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);
203
+ }
150
204
151
205
152
- int main ( int argc, const char ** argv )
206
+ int main ( int argc, const char * argv[] )
153
207
{
154
- // close stderr to stop cocoa log messages from being picked up by GitX
155
- close (STDERR_FILENO);
156
-
157
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults ];
208
+ // close stderr to stop cocoa log messages from being picked up by GitX
209
+ close (STDERR_FILENO);
158
210
159
- ProcessSerialNumber myPSN = { 0 , kCurrentProcess };
160
- TransformProcessType ( &myPSN, kProcessTransformToForegroundApplication );
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];
161
217
162
- NSApplication *app = [ NSApplication sharedApplication ];
163
- GAPAppDelegate *appDel = [[GAPAppDelegate alloc ] init ];
164
- [app setDelegate: appDel] ;
165
- NSWindow *passPanel = [appDel passwordPanel ];
218
+
219
+ char args[ 4024 ];
220
+ getproclline ( getppid (),args) ;
221
+ NSString *cmd=[ NSString stringWithFormat: @" %@ " ,[ NSString stringWithUTF8String: args] ];
166
222
167
- [app activateIgnoringOtherApps: YES ];
168
- [passPanel makeKeyAndOrderFront: nil ];
169
- NSInteger code = [app runModalForWindow: passPanel];
223
+ NSLog (@" cmd: '%@ '" ,cmd);
170
224
171
- [defaults synchronize ];
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
+ }
172
249
173
- return code ;
174
- }
250
+ return 0 ;
251
+ }
0 commit comments