~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebKit/mac/Panels/WebAuthenticationPanel.m

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
Import upstream version 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "WebLocalizableStringsInternal.h"
 
32
#import <Foundation/NSURLAuthenticationChallenge.h>
 
33
#import <Foundation/NSURLProtectionSpace.h>
 
34
#import <Foundation/NSURLCredential.h>
 
35
#import <WebKit/WebKitNSStringExtras.h>
 
36
#import <WebKit/WebNSURLExtras.h>
 
37
#import <wtf/Assertions.h>
 
38
 
 
39
#import <WebKit/WebNSControlExtras.h>
 
40
 
 
41
#define WebAuthenticationPanelNibName @"WebAuthenticationPanel"
 
42
 
 
43
@implementation WebAuthenticationPanel
 
44
 
 
45
-(id)initWithCallback:(id)cb selector:(SEL)sel
 
46
{
 
47
    self = [self init];
 
48
    if (self != nil) {
 
49
        callback = [cb retain];
 
50
        selector = sel;
 
51
    }
 
52
    return self;
 
53
}
 
54
 
 
55
 
 
56
- (void)dealloc
 
57
{
 
58
    [panel release];
 
59
 
 
60
    [callback release];
 
61
    
 
62
    [super dealloc];
 
63
}
 
64
 
 
65
// IB actions
 
66
 
 
67
- (IBAction)cancel:(id)sender
 
68
{
 
69
    // This is required because the body of this method is going to
 
70
    // remove all of the panel's remaining refs, which can cause a
 
71
    // crash later when finishing button hit tracking.  So we make
 
72
    // sure it lives on a bit longer.
 
73
    [[panel retain] autorelease];
 
74
    
 
75
    // This is required as a workaround for AppKit issue 4118422
 
76
    [[self retain] autorelease];
 
77
 
 
78
    [panel close];
 
79
    if (usingSheet) {
 
80
        [[NSApplication sharedApplication] endSheet:panel returnCode:1];
 
81
    } else {
 
82
        [[NSApplication sharedApplication] stopModalWithCode:1];
 
83
    }
 
84
}
 
85
 
 
86
- (IBAction)logIn:(id)sender
 
87
{
 
88
    // This is required because the body of this method is going to
 
89
    // remove all of the panel's remaining refs, which can cause a
 
90
    // crash later when finishing button hit tracking.  So we make
 
91
    // sure it lives on a bit longer.
 
92
    [[panel retain] autorelease];
 
93
 
 
94
    [panel close];
 
95
    if (usingSheet) {
 
96
        [[NSApplication sharedApplication] endSheet:panel returnCode:0];
 
97
    } else {
 
98
        [[NSApplication sharedApplication] stopModalWithCode:0];
 
99
    }
 
100
}
 
101
 
 
102
- (BOOL)loadNib
 
103
{
 
104
    if (!nibLoaded) {
 
105
#pragma clang diagnostic push
 
106
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 
107
        if ([NSBundle loadNibNamed:WebAuthenticationPanelNibName owner:self]) {
 
108
#pragma clang diagnostic pop
 
109
            nibLoaded = YES;
 
110
            [imageView setImage:[NSImage imageNamed:@"NSApplicationIcon"]];
 
111
        } else {
 
112
            LOG_ERROR("couldn't load nib named '%@'", WebAuthenticationPanelNibName);
 
113
            return FALSE;
 
114
        }
 
115
    }
 
116
    return TRUE;
 
117
}
 
118
 
 
119
// Methods related to displaying the panel
 
120
 
 
121
-(void)setUpForChallenge:(NSURLAuthenticationChallenge *)chall
 
122
{
 
123
    [self loadNib];
 
124
 
 
125
    NSURLProtectionSpace *space = [chall protectionSpace];
 
126
 
 
127
    NSString *host;
 
128
    if ([space port] == 0) {
 
129
        host = [[space host] _web_decodeHostName];
 
130
    } else {
 
131
        host = [NSString stringWithFormat:@"%@:%ld", [[space host] _web_decodeHostName], (long)[space port]];
 
132
    }
 
133
 
 
134
    NSString *realm = [space realm];
 
135
    if (!realm)
 
136
        realm = @"";
 
137
    NSString *message;
 
138
 
 
139
    // Consider the realm name to be "simple" if it does not contain any whitespace or newline characters.
 
140
    // If the realm name is determined to be complex, we will use a slightly different sheet layout, designed
 
141
    // to keep a malicious realm name from spoofing the wording in the sheet text.
 
142
    BOOL realmNameIsSimple = [realm rangeOfCharacterFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]].location == NSNotFound;    
 
143
    
 
144
    if ([chall previousFailureCount] == 0) {
 
145
        if ([space isProxy]) {
 
146
            message = [NSString stringWithFormat:UI_STRING_INTERNAL("To view this page, you must log in to the %@ proxy server %@.",
 
147
                                                           "prompt string in authentication panel"),
 
148
                [space proxyType], host];
 
149
        } else {
 
150
            if (realmNameIsSimple)
 
151
                message = [NSString stringWithFormat:UI_STRING_INTERNAL("To view this page, you must log in to area “%@” on %@.",
 
152
                                                               "prompt string in authentication panel"), realm, host];
 
153
            else
 
154
                message = [NSString stringWithFormat:UI_STRING_INTERNAL("To view this page, you must log in to this area on %@:",
 
155
                                                               "prompt string in authentication panel"), host];
 
156
        }
 
157
    } else {
 
158
        if ([space isProxy]) {
 
159
            message = [NSString stringWithFormat:UI_STRING_INTERNAL("The user name or password you entered for the %@ proxy server %@ was incorrect. Make sure you’re entering them correctly, and then try again.",
 
160
                                                           "prompt string in authentication panel"),
 
161
                [space proxyType], host];
 
162
        } else {
 
163
            if (realmNameIsSimple)
 
164
                message = [NSString stringWithFormat:UI_STRING_INTERNAL("The user name or password you entered for area “%@” on %@ was incorrect. Make sure you’re entering them correctly, and then try again.",
 
165
                                                               "prompt string in authentication panel"), realm, host];
 
166
            else
 
167
                message = [NSString stringWithFormat:UI_STRING_INTERNAL("The user name or password you entered for this area on %@ was incorrect. Make sure you’re entering them correctly, and then try again.",
 
168
                                                               "prompt string in authentication panel"), host];
 
169
        }
 
170
    }
 
171
    
 
172
    if (![space isProxy] && !realmNameIsSimple) {
 
173
        [separateRealmLabel setHidden:NO];
 
174
        [separateRealmLabel setStringValue:realm];
 
175
        [separateRealmLabel setAutoresizingMask:NSViewMinYMargin];
 
176
        [separateRealmLabel sizeToFitAndAdjustWindowHeight];
 
177
        [separateRealmLabel setAutoresizingMask:NSViewMaxYMargin];
 
178
    } else {
 
179
        // In the proxy or "simple" realm name case, we need to hide the 'separateRealmLabel'
 
180
        // and move the rest of the contents up appropriately to fill the space.
 
181
        NSRect mainLabelFrame = [mainLabel frame];
 
182
        NSRect realmFrame = [separateRealmLabel frame];
 
183
        NSRect smallLabelFrame = [smallLabel frame];
 
184
 
 
185
        // Find the distance between the 'smallLabel' and the label above it, initially the 'separateRealmLabel'.
 
186
        // Then, find the current distance between 'smallLabel' and 'mainLabel'.  The difference between
 
187
        // these two is how much shorter the panel needs to be after hiding the 'separateRealmLabel'.
 
188
        CGFloat smallLabelMargin = NSMinY(realmFrame) - NSMaxY(smallLabelFrame);
 
189
        CGFloat smallLabelToMainLabel = NSMinY(mainLabelFrame) - NSMaxY(smallLabelFrame);
 
190
        CGFloat deltaMargin = smallLabelToMainLabel - smallLabelMargin;
 
191
        
 
192
        [separateRealmLabel setHidden:YES];
 
193
        NSRect windowFrame = [panel frame];
 
194
        windowFrame.size.height -= deltaMargin;
 
195
        [panel setFrame:windowFrame display:NO];
 
196
    }
 
197
    
 
198
    [mainLabel setStringValue:message];
 
199
    [mainLabel sizeToFitAndAdjustWindowHeight];
 
200
 
 
201
    if ([space receivesCredentialSecurely] || [[space protocol] _webkit_isCaseInsensitiveEqualToString:@"https"]) {
 
202
        [smallLabel setStringValue:
 
203
            UI_STRING_INTERNAL("Your login information will be sent securely.",
 
204
                "message in authentication panel")];
 
205
    } else {
 
206
        // Use this scary-sounding phrase only when using basic auth with non-https servers. In this case the password
 
207
        // could be sniffed by intercepting the network traffic.
 
208
        [smallLabel setStringValue:
 
209
            UI_STRING_INTERNAL("Your password will be sent unencrypted.",
 
210
                "message in authentication panel")];
 
211
    }
 
212
 
 
213
    if ([[chall proposedCredential] user] != nil) {
 
214
        [username setStringValue:[[chall proposedCredential] user]];
 
215
        [panel setInitialFirstResponder:password];
 
216
    } else {
 
217
        [username setStringValue:@""];
 
218
        [password setStringValue:@""];
 
219
        [panel setInitialFirstResponder:username];
 
220
    }
 
221
}
 
222
 
 
223
- (void)runAsModalDialogWithChallenge:(NSURLAuthenticationChallenge *)chall
 
224
{
 
225
    [self setUpForChallenge:chall];
 
226
 
 
227
    usingSheet = FALSE;
 
228
    [chall retain];
 
229
    NSURLCredential *credential = nil;
 
230
 
 
231
    if ([[NSApplication sharedApplication] runModalForWindow:panel] == 0) {
 
232
        credential = [[NSURLCredential alloc] initWithUser:[username stringValue] password:[password stringValue] persistence:([remember state] == NSOnState) ? NSURLCredentialPersistencePermanent : NSURLCredentialPersistenceForSession];
 
233
    }
 
234
 
 
235
    [callback performSelector:selector withObject:chall withObject:credential];
 
236
    [credential release];
 
237
    [chall release];
 
238
}
 
239
 
 
240
- (void)runAsSheetOnWindow:(NSWindow *)window withChallenge:(NSURLAuthenticationChallenge *)chall
 
241
{
 
242
    ASSERT(!usingSheet);
 
243
 
 
244
    [self setUpForChallenge:chall];
 
245
 
 
246
    usingSheet = TRUE;
 
247
    challenge = [chall retain];
 
248
    
 
249
    [[NSApplication sharedApplication] beginSheet:panel modalForWindow:window modalDelegate:self didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:) contextInfo:NULL];
 
250
}
 
251
 
 
252
- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void  *)contextInfo
 
253
{
 
254
    NSURLCredential *credential = nil;
 
255
    NSURLAuthenticationChallenge *chall;
 
256
 
 
257
    ASSERT(usingSheet);
 
258
    ASSERT(challenge != nil);
 
259
 
 
260
    if (returnCode == 0) {
 
261
        credential = [[NSURLCredential alloc] initWithUser:[username stringValue] password:[password stringValue] persistence:([remember state] == NSOnState) ? NSURLCredentialPersistencePermanent : NSURLCredentialPersistenceForSession];
 
262
    }
 
263
 
 
264
    // We take this tricky approach to nilling out and releasing the challenge
 
265
    // because the callback below might remove our last ref.
 
266
    chall = challenge;
 
267
    challenge = nil;
 
268
    [callback performSelector:selector withObject:chall withObject:credential];
 
269
    [credential release];
 
270
    [chall release];
 
271
}
 
272
 
 
273
@end
 
274
 
 
275
@implementation WebNonBlockingPanel
 
276
 
 
277
- (BOOL)_blocksActionWhenModal:(SEL)theAction
 
278
{
 
279
    // This override of a private AppKit method allows the user to quit when a login dialog
 
280
    // is onscreen, which is nice in general but in particular prevents pathological cases
 
281
    // like 3744583 from requiring a Force Quit.
 
282
    //
 
283
    // It would be nice to allow closing the individual window as well as quitting the app when
 
284
    // a login sheet is up, but this _blocksActionWhenModal: mechanism doesn't support that.
 
285
    // This override matches those in NSOpenPanel and NSToolbarConfigPanel.
 
286
    if (theAction == @selector(terminate:)) {
 
287
        return NO;
 
288
    }
 
289
    return YES;
 
290
}
 
291
 
 
292
@end