1/* 2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (C) 2006 James G. Speth (speth@end.com) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*/ 26 27#import "config.h" 28#import "ObjCPlugin.h" 29 30#import <WebKit/WebKit.h> 31#import <objc/objc-runtime.h> 32 33// === NSObject category to expose almost everything to JavaScript === 34 35// Warning: this class introduces huge security weaknesses, and should only be used 36// for testing inside of DumpRenderTree, and only with trusted code. By default, it has 37// the same restrictive behavior as the standard WebKit setup. However, scripts can use the 38// plugin's removeBridgeRestrictions: method to open up almost total access to the Cocoa 39// frameworks. 40 41static BOOL _allowsScriptsFullAccess = NO; 42 43@interface NSObject (ObjCScriptAccess) 44 45+ (void)setAllowsScriptsFullAccess:(BOOL)value; 46+ (BOOL)allowsScriptsFullAccess; 47 48@end 49 50@implementation NSObject (ObjCScriptAccess) 51 52+ (void)setAllowsScriptsFullAccess:(BOOL)value 53{ 54 _allowsScriptsFullAccess = value; 55} 56 57+ (BOOL)allowsScriptsFullAccess 58{ 59 return _allowsScriptsFullAccess; 60} 61 62+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector 63{ 64 return !_allowsScriptsFullAccess; 65} 66 67+ (NSString *)webScriptNameForSelector:(SEL)selector 68{ 69 return nil; 70} 71 72@end 73 74@interface JSObjC : NSObject { 75} 76 77// expose some useful objc functions to the scripting environment 78- (id)lookUpClass:(NSString *)name; 79- (void)log:(NSString *)message; 80- (id)retainObject:(id)obj; 81- (id)classOfObject:(id)obj; 82- (NSString *)classNameOfObject:(id)obj; 83 84@end 85 86@implementation JSObjC 87 88+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector 89{ 90 return NO; 91} 92 93+ (NSString *)webScriptNameForSelector:(SEL)selector 94{ 95 return nil; 96} 97 98- (id)invokeDefaultMethodWithArguments:(NSArray *)args 99{ 100 // this is a useful shortcut for accessing objective-c classes from the scripting 101 // environment, e.g. 'var myObject = objc("NSObject").alloc().init();' 102 if ([args count] == 1) 103 return [self lookUpClass:[args objectAtIndex:0]]; 104 return nil; 105} 106 107- (id)lookUpClass:(NSString *)name 108{ 109 return NSClassFromString(name); 110} 111 112- (void)log:(NSString *)message 113{ 114 NSLog(@"%@", message); 115} 116 117- (id)retainObject:(id)obj 118{ 119 return [obj retain]; 120} 121 122- (id)classOfObject:(id)obj 123{ 124 return (id)[obj class]; 125} 126 127- (NSString *)classNameOfObject:(id)obj 128{ 129 return [obj className]; 130} 131 132@end 133 134@implementation ObjCPlugin 135 136+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector 137{ 138 if (aSelector == @selector(removeBridgeRestrictions:)) 139 return NO; 140 141 if (aSelector == @selector(echo:)) 142 return NO; 143 144 if (aSelector == @selector(throwIfArgumentIsNotHello:)) 145 return NO; 146 147 return YES; 148} 149 150+ (NSString *)webScriptNameForSelector:(SEL)aSelector 151{ 152 if (aSelector == @selector(echo:)) 153 return @"echo"; 154 155 if (aSelector == @selector(throwIfArgumentIsNotHello:)) 156 return @"throwIfArgumentIsNotHello"; 157 158 return nil; 159} 160 161+ (NSString *)webScriptNameForKey:(const char *)key 162{ 163 if (strcmp(key, "throwOnDealloc") == 0) 164 return @"throwOnDealloc"; 165 166 return nil; 167} 168 169+ (BOOL)isKeyExcludedFromWebScript:(const char *)key 170{ 171 if (strcmp(key, "throwOnDealloc") == 0) 172 return NO; 173 174 return YES; 175} 176 177- (void)removeBridgeRestrictions:(id)container 178{ 179 // let scripts invoke any selector 180 [NSObject setAllowsScriptsFullAccess:YES]; 181 182 // store a JSObjC instance into the provided container 183 JSObjC *objc = [[JSObjC alloc] init]; 184 [container setValue:objc forKey:@"objc"]; 185 [objc release]; 186} 187 188- (id)echo:(id)obj 189{ 190 return obj; 191} 192 193- (void)throwIfArgumentIsNotHello:(NSString *)str 194{ 195 if (![str isEqualToString:@"Hello"]) 196 [WebScriptObject throwException:[NSString stringWithFormat:@"%@ != Hello", str]]; 197} 198 199- (void)dealloc 200{ 201 if (throwOnDealloc) 202 [WebScriptObject throwException:@"Throwing exception on dealloc of ObjCPlugin"]; 203 204 [super dealloc]; 205} 206 207@end 208