Plugins/Purple Service/AIFacebookXMPPOAuthWebViewWindowController.m
branchadium-1.5.11-merge
changeset 6013 f8d0dc659e3f
parent 5941 307f53385811
parent 6012 200a01709ba4
child 6014 fcb71cb71a3d
child 6015 2b01cc935b7c
equal deleted inserted replaced
5941:307f53385811 6013:f8d0dc659e3f
     1 //
       
     2 //  AIFacebookXMPPOAuthWebViewWindowController.m
       
     3 //  Adium
       
     4 //
       
     5 //  Created by Colin Barrett on 11/19/10.
       
     6 //  Copyright 2010 __MyCompanyName__. All rights reserved.
       
     7 //
       
     8 //
       
     9 
       
    10 #import "AIFacebookXMPPOAuthWebViewWindowController.h"
       
    11 #import "AIFacebookXMPPAccountViewController.h"
       
    12 #import "AIFacebookXMPPAccount.h"
       
    13 #import "JSONKit.h"
       
    14 
       
    15 @interface AIFacebookXMPPOAuthWebViewWindowController ()
       
    16 - (void)addCookiesFromResponse:(NSHTTPURLResponse *)response;
       
    17 - (void)addCookiesToRequest:(NSMutableURLRequest *)request;
       
    18 @end
       
    19 
       
    20 @implementation AIFacebookXMPPOAuthWebViewWindowController
       
    21 
       
    22 @synthesize account;
       
    23 @synthesize cookies;
       
    24 @synthesize webView, spinner;
       
    25 @synthesize autoFillPassword, autoFillUsername;
       
    26 @synthesize isMigrating;
       
    27 
       
    28 - (id)init
       
    29 {
       
    30     if ((self = [super initWithWindowNibName:@"AIFacebookXMPPOauthWebViewWindow"])) {
       
    31         self.cookies = [[[NSMutableDictionary alloc] init] autorelease];
       
    32     }
       
    33     return self;
       
    34 }
       
    35 
       
    36 - (void)dealloc
       
    37 {
       
    38 	self.account = nil;
       
    39 	self.cookies = nil;
       
    40 	
       
    41 	[self.webView close];
       
    42 	self.webView = nil;
       
    43 	self.spinner = nil;
       
    44     
       
    45     [super dealloc];
       
    46 }
       
    47 
       
    48 - (NSString *)adiumFrameAutosaveName
       
    49 {
       
    50     return @"Facebook OAuth Window Frame";
       
    51 }
       
    52 
       
    53 - (void)showWindow:(id)sender
       
    54 {
       
    55     [super showWindow:sender];
       
    56 
       
    57     [webView setMainFrameURL:@"https://graph.facebook.com/oauth/authorize?"
       
    58      @"client_id=" ADIUM_APP_ID "&"
       
    59      @"redirect_uri=http%3A%2F%2Fwww.facebook.com%2Fconnect%2Flogin_success.html&"
       
    60 	 @"scope=xmpp_login,offline_access&"
       
    61      @"type=user_agent&"
       
    62      @"display=popup"];
       
    63 	
       
    64 	[spinner startAnimation:self];
       
    65     
       
    66     [self.window setTitle:AILocalizedString(@"Facebook Account Setup", nil)];
       
    67 }
       
    68 
       
    69 - (void)windowWillClose:(id)sender
       
    70 {
       
    71     [super windowWillClose:sender];
       
    72 
       
    73     /* The user closed; notify the account of failure */
       
    74     if (!notifiedAccount)
       
    75         [self.account oAuthWebViewControllerDidFail:self];
       
    76 }
       
    77 
       
    78 - (NSDictionary*)parseURLParams:(NSString *)query {
       
    79 	NSArray *pairs = [query componentsSeparatedByString:@"&"];
       
    80 	NSMutableDictionary *params = [[[NSMutableDictionary alloc] init] autorelease];
       
    81 	for (NSString *pair in pairs) {
       
    82 		NSArray *kv = [pair componentsSeparatedByString:@"="];
       
    83 		NSString *val = [[kv objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
       
    84 		
       
    85 		[params setObject:val forKey:[kv objectAtIndex:0]];
       
    86 	}
       
    87 	return params;
       
    88 }
       
    89 
       
    90 
       
    91 - (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame
       
    92 {
       
    93 	[spinner startAnimation:self];
       
    94 	[sender display];
       
    95 }
       
    96 
       
    97 - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
       
    98 {
       
    99 	if ([sender mainFrame] == frame) {
       
   100 		[spinner stopAnimation:self];
       
   101 		[sender display];
       
   102 		
       
   103 		if ([frame.dataSource.request.URL.host isEqual:@"www.facebook.com"] && [frame.dataSource.request.URL.path isEqual:@"/login.php"]) {
       
   104 			//Set email and password
       
   105 			DOMDocument *domDoc = [frame DOMDocument];
       
   106             
       
   107             if (self.isMigrating) {
       
   108                 NSString *text = domDoc.body.innerHTML;
       
   109                 text = [text stringByReplacingOccurrencesOfString:@"Log in to use your Facebook account"
       
   110                                                        withString:@"The new version of Adium has a much more reliable Facebook Chat service. Log in to use your Facebook account"];
       
   111                 domDoc.body.innerHTML = text;
       
   112             }
       
   113 
       
   114             
       
   115 			[[domDoc getElementById:@"email"] setValue:self.autoFillUsername];
       
   116 			[[domDoc getElementById:@"pass"] setValue:self.autoFillPassword];
       
   117 			
       
   118 			DOMElement *checkbox = [domDoc getElementById:@"persistent_inputcheckbox"];
       
   119 			if ([checkbox isKindOfClass:[NSClassFromString(@"DOMHTMLInputElement") class]] &&
       
   120 				[checkbox respondsToSelector:@selector(setChecked:)]) {
       
   121 				[((DOMHTMLInputElement *)checkbox) setChecked:YES];
       
   122 			}
       
   123 		}
       
   124 	}
       
   125 }
       
   126 
       
   127 - (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource;
       
   128 {    
       
   129     if (redirectResponse) {
       
   130         [self addCookiesFromResponse:(id)redirectResponse];
       
   131     }
       
   132     NSMutableURLRequest *mutableRequest = [[request mutableCopy] autorelease];
       
   133     [mutableRequest setHTTPShouldHandleCookies:NO];
       
   134     [self addCookiesToRequest:mutableRequest];
       
   135 	
       
   136     if ([[[mutableRequest URL] host] isEqual:@"www.facebook.com"] && [[[mutableRequest URL] path] isEqual:@"/connect/login_success.html"]) {
       
   137 		NSDictionary *urlParamDict = [self parseURLParams:[[mutableRequest URL] fragment]];
       
   138 		
       
   139 		NSString *token = [urlParamDict objectForKey:@"access_token"];
       
   140 		if (token && ![token isEqualToString:@""]) {
       
   141     		[self.account oAuthWebViewController:self didSucceedWithToken:token];
       
   142 		} else {
       
   143 			/* Got a bad token, or the user canceled */
       
   144 			[self.account oAuthWebViewControllerDidFail:self];
       
   145 
       
   146 		}		
       
   147 
       
   148         notifiedAccount = YES;
       
   149 		[self closeWindow:nil];
       
   150 	}
       
   151 	
       
   152 	return mutableRequest;
       
   153 }
       
   154 
       
   155 
       
   156 - (void)webView:(WebView *)sender resource:(id)identifier didReceiveResponse:(NSURLResponse *)response fromDataSource:(WebDataSource *)dataSource;
       
   157 {
       
   158     if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
       
   159         [self addCookiesFromResponse:(NSHTTPURLResponse *)response];
       
   160     }
       
   161 }
       
   162 
       
   163 - (void)addCookiesFromResponse:(NSHTTPURLResponse *)response
       
   164 {
       
   165     NSArray *newCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:[response URL]];
       
   166 	
       
   167 	for (NSHTTPCookie *newCookie in newCookies) {
       
   168 		[cookies setObject:newCookie forKey:newCookie.name];
       
   169 	}
       
   170 }
       
   171 
       
   172 - (void)addCookiesToRequest:(NSMutableURLRequest *)request
       
   173 {
       
   174     NSURL *requestURL = [request URL];
       
   175     //NSLog(@"requestURL: %@", requestURL);
       
   176     NSMutableArray *sentCookies = [NSMutableArray array];
       
   177     
       
   178     // same origin: domain, port, path.
       
   179     for (NSHTTPCookie *cookie in cookies.allValues) {
       
   180         if ([[cookie expiresDate] timeIntervalSinceNow] < 0) {
       
   181             //NSLog(@"****** expired: %@", cookie);
       
   182             continue;
       
   183         }
       
   184         
       
   185         if ([cookie isSecure] && ![[requestURL scheme] isEqualToString:@"https"]) {
       
   186             //NSLog(@"****** secure not https: %@", cookie);
       
   187             continue;
       
   188         }
       
   189         
       
   190         if ([[cookie domain] hasPrefix:@"."]) { // ".example.com" should match "foo.example.com" and "example.com"            
       
   191             if (!([[requestURL host] hasSuffix:[cookie domain]] ||
       
   192                   [[@"." stringByAppendingString:[requestURL host]] isEqualToString:[cookie domain]])) {
       
   193                 //NSLog(@"****** dot prefix host mismatch: %@", cookie);
       
   194                 continue;
       
   195             }
       
   196         } else {
       
   197             if (![[requestURL host] isEqualToString:[cookie domain]]) {
       
   198                 //NSLog(@"****** host mismatch: %@", cookie);
       
   199                 continue;
       
   200             }
       
   201         }
       
   202         
       
   203         if ([[cookie portList] count] && ([requestURL port] != NULL) && ![[cookie portList] containsObject:[requestURL port]]) {
       
   204             //NSLog(@"****** port mismatch: %@ (%@ doesn't have %@)", cookie, cookie.portList, requestURL.port);
       
   205             continue;
       
   206         }
       
   207         
       
   208         if (![[requestURL path] hasPrefix:[cookie path]]) {
       
   209             //NSLog(@"****** path mismatch: %@", cookie);
       
   210             continue;
       
   211         }
       
   212         
       
   213         //NSLog(@"adding cookie: %@", cookie);
       
   214         [sentCookies addObject:cookie];
       
   215     }
       
   216     
       
   217     NSMutableDictionary *headers = [[[request allHTTPHeaderFields] mutableCopy] autorelease];
       
   218     [headers setValuesForKeysWithDictionary:[NSHTTPCookie requestHeaderFieldsWithCookies:sentCookies]];
       
   219     [request setAllHTTPHeaderFields:headers];
       
   220 }
       
   221 
       
   222 @end