|
1 /* |
|
2 * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. |
|
3 * |
|
4 * Redistribution and use in source and binary forms, with or without |
|
5 * modification, are permitted provided that the following conditions |
|
6 * are met: |
|
7 * |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
|
14 * its contributors may be used to endorse or promote products derived |
|
15 * from this software without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
|
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
|
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #import <WebKit/WebAuthenticationPanel.h> |
|
30 |
|
31 #import <Foundation/NSURLAuthenticationChallenge.h> |
|
32 #import <Foundation/NSURLProtectionSpace.h> |
|
33 #import <Foundation/NSURLCredential.h> |
|
34 #import <JavaScriptCore/Assertions.h> |
|
35 #import <WebKit/WebLocalizableStrings.h> |
|
36 #import <WebKit/WebNSURLExtras.h> |
|
37 |
|
38 #import <WebKit/WebNSControlExtras.h> |
|
39 |
|
40 #define WebAuthenticationPanelNibName @"WebAuthenticationPanel" |
|
41 |
|
42 @implementation WebAuthenticationPanel |
|
43 |
|
44 -(id)initWithCallback:(id)cb selector:(SEL)sel |
|
45 { |
|
46 self = [self init]; |
|
47 if (self != nil) { |
|
48 callback = [cb retain]; |
|
49 selector = sel; |
|
50 } |
|
51 return self; |
|
52 } |
|
53 |
|
54 |
|
55 - (void)dealloc |
|
56 { |
|
57 [panel release]; |
|
58 |
|
59 [callback release]; |
|
60 |
|
61 [super dealloc]; |
|
62 } |
|
63 |
|
64 // IB actions |
|
65 |
|
66 - (IBAction)cancel:(id)sender |
|
67 { |
|
68 // This is required because the body of this method is going to |
|
69 // remove all of the panel's remaining refs, which can cause a |
|
70 // crash later when finishing button hit tracking. So we make |
|
71 // sure it lives on a bit longer. |
|
72 [[panel retain] autorelease]; |
|
73 |
|
74 // This is required as a workaround for AppKit issue 4118422 |
|
75 [[self retain] autorelease]; |
|
76 |
|
77 [panel close]; |
|
78 if (usingSheet) { |
|
79 [[NSApplication sharedApplication] endSheet:panel returnCode:1]; |
|
80 } else { |
|
81 [[NSApplication sharedApplication] stopModalWithCode:1]; |
|
82 } |
|
83 } |
|
84 |
|
85 - (IBAction)logIn:(id)sender |
|
86 { |
|
87 // This is required because the body of this method is going to |
|
88 // remove all of the panel's remaining refs, which can cause a |
|
89 // crash later when finishing button hit tracking. So we make |
|
90 // sure it lives on a bit longer. |
|
91 [[panel retain] autorelease]; |
|
92 |
|
93 [panel close]; |
|
94 if (usingSheet) { |
|
95 [[NSApplication sharedApplication] endSheet:panel returnCode:0]; |
|
96 } else { |
|
97 [[NSApplication sharedApplication] stopModalWithCode:0]; |
|
98 } |
|
99 } |
|
100 |
|
101 - (BOOL)loadNib |
|
102 { |
|
103 if (!nibLoaded) { |
|
104 if ([NSBundle loadNibNamed:WebAuthenticationPanelNibName owner:self]) { |
|
105 nibLoaded = YES; |
|
106 [imageView setImage:[NSImage imageNamed:@"NSApplicationIcon"]]; |
|
107 } else { |
|
108 LOG_ERROR("couldn't load nib named '%@'", WebAuthenticationPanelNibName); |
|
109 return FALSE; |
|
110 } |
|
111 } |
|
112 return TRUE; |
|
113 } |
|
114 |
|
115 // Methods related to displaying the panel |
|
116 |
|
117 -(void)setUpForChallenge:(NSURLAuthenticationChallenge *)chall |
|
118 { |
|
119 [self loadNib]; |
|
120 |
|
121 NSURLProtectionSpace *space = [chall protectionSpace]; |
|
122 |
|
123 NSString *host; |
|
124 if ([space port] == 0) { |
|
125 host = [space host]; |
|
126 } else { |
|
127 host = [NSString stringWithFormat:@"%@:%u", [space host], [space port]]; |
|
128 } |
|
129 |
|
130 NSString *realm = [space realm]; |
|
131 NSString *message; |
|
132 |
|
133 if ([chall previousFailureCount] == 0) { |
|
134 if ([space isProxy]) { |
|
135 message = [NSString stringWithFormat:UI_STRING("To view this page, you need to log in to the %@ proxy server %@.", |
|
136 "prompt string in authentication panel"), |
|
137 [space proxyType], host]; |
|
138 } else { |
|
139 message = [NSString stringWithFormat:UI_STRING("To view this page, you need to log in to area “%@” on %@.", |
|
140 "prompt string in authentication panel"), |
|
141 realm, host]; |
|
142 } |
|
143 } else { |
|
144 if ([space isProxy]) { |
|
145 message = [NSString stringWithFormat:UI_STRING("The name or password entered for the %@ proxy server %@ was incorrect. Please try again.", |
|
146 "prompt string in authentication panel"), |
|
147 [space proxyType], host]; |
|
148 } else { |
|
149 message = [NSString stringWithFormat:UI_STRING("The name or password entered for area “%@” on %@ was incorrect. Please try again.", |
|
150 "prompt string in authentication panel"), |
|
151 realm, host]; |
|
152 } |
|
153 } |
|
154 |
|
155 [mainLabel setStringValue:message]; |
|
156 [mainLabel sizeToFitAndAdjustWindowHeight]; |
|
157 |
|
158 if ([space receivesCredentialSecurely]) { |
|
159 [smallLabel setStringValue: |
|
160 UI_STRING("Your log-in information will be sent securely.", |
|
161 "message in authentication panel")]; |
|
162 } else { |
|
163 [smallLabel setStringValue: |
|
164 UI_STRING("Your password will be sent in the clear.", |
|
165 "message in authentication panel")]; |
|
166 } |
|
167 |
|
168 if ([[chall proposedCredential] user] != nil) { |
|
169 [username setStringValue:[[chall proposedCredential] user]]; |
|
170 [panel setInitialFirstResponder:password]; |
|
171 } else { |
|
172 [username setStringValue:@""]; |
|
173 [password setStringValue:@""]; |
|
174 [panel setInitialFirstResponder:username]; |
|
175 } |
|
176 } |
|
177 |
|
178 - (void)runAsModalDialogWithChallenge:(NSURLAuthenticationChallenge *)chall |
|
179 { |
|
180 [self setUpForChallenge:chall]; |
|
181 usingSheet = FALSE; |
|
182 NSURLCredential *credential = nil; |
|
183 |
|
184 if ([[NSApplication sharedApplication] runModalForWindow:panel] == 0) { |
|
185 credential = [[NSURLCredential alloc] initWithUser:[username stringValue] password:[password stringValue] persistence:([remember state] == NSOnState) ? NSURLCredentialPersistencePermanent : NSURLCredentialPersistenceForSession]; |
|
186 } |
|
187 |
|
188 [callback performSelector:selector withObject:chall withObject:credential]; |
|
189 [credential release]; |
|
190 } |
|
191 |
|
192 - (void)runAsSheetOnWindow:(NSWindow *)window withChallenge:(NSURLAuthenticationChallenge *)chall |
|
193 { |
|
194 ASSERT(!usingSheet); |
|
195 |
|
196 [self setUpForChallenge:chall]; |
|
197 |
|
198 usingSheet = TRUE; |
|
199 challenge = [chall retain]; |
|
200 |
|
201 [[NSApplication sharedApplication] beginSheet:panel modalForWindow:window modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:NULL]; |
|
202 } |
|
203 |
|
204 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo |
|
205 { |
|
206 NSURLCredential *credential = nil; |
|
207 NSURLAuthenticationChallenge *chall; |
|
208 |
|
209 ASSERT(usingSheet); |
|
210 ASSERT(challenge != nil); |
|
211 |
|
212 if (returnCode == 0) { |
|
213 credential = [[NSURLCredential alloc] initWithUser:[username stringValue] password:[password stringValue] persistence:([remember state] == NSOnState) ? NSURLCredentialPersistencePermanent : NSURLCredentialPersistenceForSession]; |
|
214 } |
|
215 |
|
216 // We take this tricky approach to nilling out and releasing the challenge |
|
217 // because the callback below might remove our last ref. |
|
218 chall = challenge; |
|
219 challenge = nil; |
|
220 [callback performSelector:selector withObject:chall withObject:credential]; |
|
221 [credential release]; |
|
222 [chall release]; |
|
223 } |
|
224 |
|
225 @end |
|
226 |
|
227 @implementation NonBlockingPanel |
|
228 |
|
229 - (BOOL)_blocksActionWhenModal:(SEL)theAction |
|
230 { |
|
231 // This override of a private AppKit method allows the user to quit when a login dialog |
|
232 // is onscreen, which is nice in general but in particular prevents pathological cases |
|
233 // like 3744583 from requiring a Force Quit. |
|
234 // |
|
235 // It would be nice to allow closing the individual window as well as quitting the app when |
|
236 // a login sheet is up, but this _blocksActionWhenModal: mechanism doesn't support that. |
|
237 // This override matches those in NSOpenPanel and NSToolbarConfigPanel. |
|
238 if (theAction == @selector(terminate:)) { |
|
239 return NO; |
|
240 } |
|
241 return YES; |
|
242 } |
|
243 |
|
244 @end |