Skip to content

Commit eac0c1a

Browse files
author
Lars Steiger
committed
Merge pull request #5 from blackpixel/master
* Added support for /checkout/ * The ability to retrieve SSL certificates for the pages in the webview * Allows the delegate to dictate whether the height of the content div should get fixed * Nicer handling of javascript alerts
2 parents a830c87 + 59d5441 commit eac0c1a

7 files changed

Lines changed: 156 additions & 11 deletions

File tree

Example1/Example1.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
467BEE3D113AFA1600C21AFE /* OrderViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 467BEE17113AF88000C21AFE /* OrderViewController.h */; };
3737
467BEE3E113AFA1700C21AFE /* OrderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 467BEE18113AF88000C21AFE /* OrderViewController.m */; };
3838
4684D95D114A323500CFE920 /* APPL.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4684D95C114A323500CFE920 /* APPL.icns */; };
39+
5F6C91BA1717AB5200241303 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F6C91B91717AB5200241303 /* Security.framework */; };
3940
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
4041
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
4142
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
@@ -93,6 +94,7 @@
9394
467BEE17113AF88000C21AFE /* OrderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OrderViewController.h; sourceTree = "<group>"; };
9495
467BEE18113AF88000C21AFE /* OrderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OrderViewController.m; sourceTree = "<group>"; };
9596
4684D95C114A323500CFE920 /* APPL.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = APPL.icns; sourceTree = "<group>"; };
97+
5F6C91B91717AB5200241303 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = ../../../../../../../System/Library/Frameworks/Security.framework; sourceTree = "<group>"; };
9698
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9799
8D1107320486CEB800E47090 /* Example1.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example1.app; sourceTree = BUILT_PRODUCTS_DIR; };
98100
/* End PBXFileReference section */
@@ -102,6 +104,7 @@
102104
isa = PBXFrameworksBuildPhase;
103105
buildActionMask = 2147483647;
104106
files = (
107+
5F6C91BA1717AB5200241303 /* Security.framework in Frameworks */,
105108
464D984114EC055B00F30753 /* WebKit.framework in Frameworks */,
106109
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
107110
467BEDEA113AF50200C21AFE /* AddressBook.framework in Frameworks */,
@@ -153,6 +156,7 @@
153156
29B97314FDCFA39411CA2CEA /* Example1 */ = {
154157
isa = PBXGroup;
155158
children = (
159+
5F6C91B91717AB5200241303 /* Security.framework */,
156160
080E96DDFE201D6D7F000001 /* Classes */,
157161
29B97315FDCFA39411CA2CEA /* Other Sources */,
158162
29B97317FDCFA39411CA2CEA /* Resources */,
@@ -399,6 +403,7 @@
399403
C01FCF4F08A954540054247B /* Debug */ = {
400404
isa = XCBuildConfiguration;
401405
buildSettings = {
406+
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
402407
GCC_WARN_ABOUT_RETURN_TYPE = YES;
403408
GCC_WARN_UNUSED_VARIABLE = YES;
404409
};
@@ -407,6 +412,7 @@
407412
C01FCF5008A954540054247B /* Release */ = {
408413
isa = XCBuildConfiguration;
409414
buildSettings = {
415+
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
410416
GCC_WARN_ABOUT_RETURN_TYPE = YES;
411417
GCC_WARN_UNUSED_VARIABLE = YES;
412418
};

Example2/Example2.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
46A64B141148FE8300B31C85 /* jquery-1.4.2.js in Resources */ = {isa = PBXBuildFile; fileRef = 46A64AFC1148FC2900B31C85 /* jquery-1.4.2.js */; };
5656
46A64BDA114903BD00B31C85 /* MGTemplateEngine README.txt in Resources */ = {isa = PBXBuildFile; fileRef = 46A64BD8114903BD00B31C85 /* MGTemplateEngine README.txt */; };
5757
46A64BDB114903BD00B31C85 /* Source Code License.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 46A64BD9114903BD00B31C85 /* Source Code License.rtf */; };
58+
5F6C91BC1717ABFE00241303 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5F6C91BB1717ABFE00241303 /* Security.framework */; };
5859
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
5960
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
6061
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
@@ -131,6 +132,7 @@
131132
46A64AFC1148FC2900B31C85 /* jquery-1.4.2.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "jquery-1.4.2.js"; sourceTree = SOURCE_ROOT; };
132133
46A64BD8114903BD00B31C85 /* MGTemplateEngine README.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "MGTemplateEngine README.txt"; sourceTree = SOURCE_ROOT; };
133134
46A64BD9114903BD00B31C85 /* Source Code License.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = "Source Code License.rtf"; sourceTree = SOURCE_ROOT; };
135+
5F6C91BB1717ABFE00241303 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = ../../../../../../../System/Library/Frameworks/Security.framework; sourceTree = "<group>"; };
134136
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
135137
8D1107320486CEB800E47090 /* Example2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example2.app; sourceTree = BUILT_PRODUCTS_DIR; };
136138
/* End PBXFileReference section */
@@ -140,6 +142,7 @@
140142
isa = PBXFrameworksBuildPhase;
141143
buildActionMask = 2147483647;
142144
files = (
145+
5F6C91BC1717ABFE00241303 /* Security.framework in Frameworks */,
143146
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
144147
46A64A081148DE6600B31C85 /* WebKit.framework in Frameworks */,
145148
46A64AAE1148EB1300B31C85 /* libicucore.dylib in Frameworks */,
@@ -190,6 +193,7 @@
190193
29B97314FDCFA39411CA2CEA /* Example2 */ = {
191194
isa = PBXGroup;
192195
children = (
196+
5F6C91BB1717ABFE00241303 /* Security.framework */,
193197
080E96DDFE201D6D7F000001 /* Classes */,
194198
29B97315FDCFA39411CA2CEA /* Other Sources */,
195199
29B97317FDCFA39411CA2CEA /* Resources */,
@@ -498,6 +502,7 @@
498502
C01FCF4F08A954540054247B /* Debug */ = {
499503
isa = XCBuildConfiguration;
500504
buildSettings = {
505+
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
501506
GCC_WARN_ABOUT_RETURN_TYPE = YES;
502507
GCC_WARN_UNUSED_VARIABLE = YES;
503508
};
@@ -506,6 +511,7 @@
506511
C01FCF5008A954540054247B /* Release */ = {
507512
isa = XCBuildConfiguration;
508513
buildSettings = {
514+
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
509515
GCC_WARN_ABOUT_RETURN_TYPE = YES;
510516
GCC_WARN_UNUSED_VARIABLE = YES;
511517
};

FsprgEmbeddedStore/FsprgEmbeddedStoreController.h

100644100755
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,16 @@
6464
*/
6565
- (BOOL)isSecure;
6666

67+
/**
68+
*
69+
* @result NSArray containing SecCertificateRef objects for the host of the main frame, if it was loaded via https.
70+
*/
71+
- (NSArray *)securityCertificates;
72+
6773
/*!
6874
* Host that delivers the store (e.g. sites.fastspring.com).
6975
* @result <code>nil</code> until the store has been loaded.
7076
*/
7177
- (NSString *)storeHost;
7278

73-
@end
79+
@end

FsprgEmbeddedStore/FsprgEmbeddedStoreController.m

100644100755
Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,28 @@
1010
#import "FsprgOrderView.h"
1111
#import "FsprgOrderDocumentRepresentation.h"
1212

13+
@interface FsprgEmbeddedStoreController ()
14+
15+
@property (nonatomic, retain) NSMutableDictionary *hostCertificates;
16+
@property (nonatomic, retain) NSMapTable *connectionsToRequests;
17+
18+
@end
1319

1420
@interface FsprgEmbeddedStoreController (Private)
21+
1522
- (void)setIsLoading:(BOOL)aFlag;
1623
- (void)setEstimatedLoadingProgress:(double)aProgress;
1724
- (void)setIsSecure:(BOOL)aFlag;
1825
- (void)setStoreHost:(NSString *)aHost;
1926
- (void)resizeContentDivE;
2027
- (void)webViewFrameChanged:(NSNotification *)aNotification;
28+
2129
@end
2230

2331
@implementation FsprgEmbeddedStoreController
2432

33+
@synthesize hostCertificates=_hostCertificates;
34+
2535
+ (void)initialize
2636
{
2737
[WebView registerViewClass:[FsprgOrderView class]
@@ -36,10 +46,23 @@ - (id) init
3646
[self setWebView:nil];
3747
[self setDelegate:nil];
3848
[self setStoreHost:nil];
49+
self.hostCertificates = [NSMutableDictionary dictionary];
50+
self.connectionsToRequests = [NSMapTable mapTableWithStrongToStrongObjects];
3951
}
4052
return self;
4153
}
4254

55+
- (void)dealloc
56+
{
57+
[self setWebView:nil];
58+
[self setDelegate:nil];
59+
[self setStoreHost:nil];
60+
[_hostCertificates release];
61+
[_connectionsToRequests release];
62+
63+
[super dealloc];
64+
}
65+
4366
- (WebView *)webView
4467
{
4568
return [[webView retain] autorelease];
@@ -51,6 +74,7 @@ - (void)setWebView:(WebView *)aWebView
5174
[webView setPostsFrameChangedNotifications:FALSE];
5275
[webView setFrameLoadDelegate:nil];
5376
[webView setUIDelegate:nil];
77+
[webView setResourceLoadDelegate:nil];
5478
[webView setApplicationNameForUserAgent:nil];
5579
[[NSNotificationCenter defaultCenter] removeObserver:self];
5680

@@ -61,6 +85,7 @@ - (void)setWebView:(WebView *)aWebView
6185
[webView setPostsFrameChangedNotifications:TRUE];
6286
[webView setFrameLoadDelegate:self];
6387
[webView setUIDelegate:self];
88+
[webView setResourceLoadDelegate:self];
6489
[webView setApplicationNameForUserAgent:@"FSEmbeddedStore/2.0"];
6590
[[NSNotificationCenter defaultCenter] addObserver:self
6691
selector:@selector(webViewFrameChanged:)
@@ -96,6 +121,8 @@ - (void)setDelegate:(id <FsprgEmbeddedStoreDelegate>)aDelegate
96121
- (void)loadWithParameters:(FsprgStoreParameters *)parameters
97122
{
98123
NSURLRequest *urlRequest = [parameters toURLRequest];
124+
if (urlRequest == nil)
125+
return;
99126

100127
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[urlRequest URL]];
101128
NSUInteger i, count = [cookies count];
@@ -151,6 +178,15 @@ - (void)setIsSecure:(BOOL)aFlag
151178
// just triggering change observer
152179
}
153180

181+
- (NSArray *)securityCertificates
182+
{
183+
if ([self isSecure] == NO)
184+
return nil;
185+
NSString *mainFrameURL = [[self webView] mainFrameURL];
186+
NSString *host = [[NSURL URLWithString:mainFrameURL] host];
187+
return [self.hostCertificates objectForKey:host];
188+
}
189+
154190
- (NSString *)storeHost
155191
{
156192
return [[storeHost retain] autorelease];
@@ -165,13 +201,22 @@ - (void)setStoreHost:(NSString *)aHost
165201
}
166202

167203
- (void)resizeContentDivE {
204+
if ([self.delegate respondsToSelector:@selector(shouldStoreControllerFixContentDivHeight:)])
205+
{
206+
if ([self.delegate shouldStoreControllerFixContentDivHeight:self] == NO)
207+
return;
208+
}
209+
168210
DOMElement *resizableContentE = [[[[self webView] mainFrame] DOMDocument] getElementById:@"FsprgResizableContent"];
169211
if(resizableContentE == nil) {
170212
return;
171213
}
172214

173215
float windowHeight = [[self webView] frame].size.height;
174-
float pageNavigationHeight = [[[[self webView] windowScriptObject] evaluateWebScript:@"document.getElementsByClassName('store-page-navigation')[0].clientHeight"] floatValue];
216+
id result = [[[self webView] windowScriptObject] evaluateWebScript:@"document.getElementsByClassName('store-page-navigation')[0].clientHeight"];
217+
if (result == [WebUndefined undefined])
218+
return;
219+
float pageNavigationHeight = [(NSString *)result floatValue];
175220

176221
DOMCSSStyleDeclaration *cssStyle = [[self webView] computedStyleForElement:resizableContentE pseudoElement:nil];
177222
float paddingTop = [[[cssStyle paddingBottom] substringToIndex:[[cssStyle paddingTop] length]-2] floatValue];
@@ -237,7 +282,14 @@ - (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame
237282

238283
- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame
239284
{
240-
NSRunAlertPanel(@"Alert", message, @"OK", nil, nil);
285+
NSString *title = [sender mainFrameTitle];
286+
NSAlert *alertPanel = [NSAlert alertWithMessageText:title defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"%@", message];
287+
[alertPanel beginSheetModalForWindow:[sender window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
288+
}
289+
290+
- (NSUInteger)webView:(WebView *)sender dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
291+
{
292+
return WebDragDestinationActionNone;
241293
}
242294

243295
- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request
@@ -254,13 +306,68 @@ - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)
254306
return subWebView;
255307
}
256308

257-
- (void)dealloc
309+
#pragma mark - WebResourceLoadDelegate
310+
311+
- (NSURLRequest *)webView:(WebView *)sender resource:(id)identifier willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse fromDataSource:(WebDataSource *)dataSource
258312
{
259-
[self setWebView:nil];
260-
[self setDelegate:nil];
261-
[self setStoreHost:nil];
313+
NSURL *URL = [request URL];
314+
NSString *host = [URL host];
315+
if ([self.hostCertificates objectForKey:host] == nil)
316+
{
317+
NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
318+
[self.connectionsToRequests setObject:request forKey:connection];
319+
}
320+
return request;
321+
}
322+
323+
#pragma mark - NURLConnection delegate
324+
325+
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
326+
{
327+
return cachedResponse;
328+
}
329+
330+
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
331+
{
332+
}
333+
334+
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
335+
{
336+
}
337+
338+
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse
339+
{
340+
return request;
341+
}
342+
343+
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
344+
{
345+
[self.connectionsToRequests setObject:nil forKey:connection];
346+
}
347+
348+
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
349+
{
350+
return YES;
351+
}
352+
353+
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge;
354+
{
355+
SecTrustRef trustRef = [[challenge protectionSpace] serverTrust];
356+
SecTrustResultType resultType;
357+
SecTrustEvaluate(trustRef, &resultType);
358+
CFIndex count = SecTrustGetCertificateCount(trustRef);
262359

263-
[super dealloc];
360+
NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:count];
361+
for (CFIndex idx = 0; idx < count; idx++)
362+
{
363+
SecCertificateRef certificateRef = SecTrustGetCertificateAtIndex(trustRef, idx);
364+
[certificates addObject:(id)certificateRef];
365+
}
366+
367+
NSURLRequest *request = [self.connectionsToRequests objectForKey:connection];
368+
NSURL *URL = [request URL];
369+
NSString *host = [URL host];
370+
[self.hostCertificates setObject:certificates forKey:host];
264371
}
265372

266373
@end

FsprgEmbeddedStore/FsprgEmbeddedStoreDelegate.h

100644100755
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ typedef enum {
1818
FsprgPageUnknown
1919
} FsprgPageType;
2020

21+
@class FsprgEmbeddedStoreController;
2122

2223
/*!
2324
* Delegate protocol for FsprgEmbeddedStoreController.
@@ -51,6 +52,16 @@ typedef enum {
5152
*/
5253
- (NSView *)viewWithFrame:(NSRect)frame forOrder:(FsprgOrder *)order;
5354

55+
/*!
56+
* Gets called after loading the page and upon resizing the window.
57+
* The default embedded store layout assumes that the content div's height will get shortened
58+
* to make room for the navigation bar. If your layout doesn't require that assumption, you can
59+
* return NO here to avoid this manual height fixing.
60+
* @param controller The store controller in question
61+
* @result YES if you'd like the store controller to fix the content div's height, NO otherwise.
62+
*/
63+
- (BOOL)shouldStoreControllerFixContentDivHeight:(FsprgEmbeddedStoreController *)controller;
64+
5465
/*!
5566
* Invoked if an error occurs when starting to load data for a page.
5667
* @param sender The web view containing the frame.

FsprgEmbeddedStore/FsprgStoreParameters.h

100644100755
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
/*! Constants for setOrderProcessType: */
1212
extern NSString * const kFsprgOrderProcessDetail;
1313
extern NSString * const kFsprgOrderProcessInstant;
14+
extern NSString * const kFsprgOrderProcessCheckout;
1415

1516
/*! Constants for setMode: */
1617
extern NSString * const kFsprgModeActive;

FsprgEmbeddedStore/FsprgStoreParameters.m

100644100755
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
NSString * const kFsprgOrderProcessDetail = @"detail";
1212
NSString * const kFsprgOrderProcessInstant = @"instant";
13+
NSString * const kFsprgOrderProcessCheckout = @"checkout";
1314

1415
NSString * const kFsprgModeActive = @"active";
1516
NSString * const kFsprgModeActiveTest = @"active.test";
@@ -103,7 +104,10 @@ - (void)setRaw:(NSMutableDictionary *)aRaw
103104

104105
- (NSURLRequest *)toURLRequest
105106
{
106-
return [NSMutableURLRequest requestWithURL:[self toURL]];
107+
NSURL *toURL = [self toURL];
108+
if (toURL)
109+
return [NSMutableURLRequest requestWithURL:toURL];
110+
return nil;
107111
}
108112

109113
- (NSURL *)toURL
@@ -126,8 +130,12 @@ - (NSURL *)toURL
126130
urlAsStr = [NSString stringWithFormat:@"%@://sites.fastspring.com/%@/product/%@", protocol, storeIdEncoded, productIdEncoded];
127131
} else if([kFsprgOrderProcessInstant isEqualTo:[self orderProcessType]]) {
128132
urlAsStr = [NSString stringWithFormat:@"https://sites.fastspring.com/%@/instant/%@", storeIdEncoded, productIdEncoded];
129-
} else {
133+
} else if ([kFsprgOrderProcessCheckout isEqualTo:[self orderProcessType]]) {
134+
urlAsStr = [NSString stringWithFormat:@"https://sites.fastspring.com/%@/checkout/%@", storeIdEncoded, productIdEncoded];
135+
}
136+
else {
130137
NSAssert1(FALSE, @"OrderProcessType '%@' unknown.", [self orderProcessType]);
138+
return nil;
131139
}
132140

133141
NSMutableArray *keys = [NSMutableArray arrayWithArray:[[self raw] allKeys]];
@@ -324,4 +332,4 @@ - (void)dealloc
324332
[super dealloc];
325333
}
326334

327-
@end
335+
@end

0 commit comments

Comments
 (0)