1 /* 2 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved. 3 * Copyright (C) 2006 James G. Speth (speth (at) 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 41 static 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