blob: 18b174c32cd8678f851c167b26df7d8d7328e771 [file] [log] [blame]
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006 James G. Speth (speth@end.com)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "ObjCPlugin.h"
#import <objc/objc-runtime.h>
#import <WebKit/WebKit.h>
// === NSObject category to expose almost everything to JavaScript ===
// Warning: this class introduces huge security weaknesses, and should only be used
// for testing inside of DumpRenderTree, and only with trusted code. By default, it has
// the same restrictive behavior as the standard WebKit setup. However, scripts can use the
// plugin's removeBridgeRestrictions: method to open up almost total access to the Cocoa
// frameworks.
static BOOL _allowsScriptsFullAccess = NO;
@interface NSObject (ObjCScriptAccess)
+ (void)setAllowsScriptsFullAccess:(BOOL)value;
+ (BOOL)allowsScriptsFullAccess;
@end
@implementation NSObject (ObjCScriptAccess)
+ (void)setAllowsScriptsFullAccess:(BOOL)value
{
_allowsScriptsFullAccess = value;
}
+ (BOOL)allowsScriptsFullAccess
{
return _allowsScriptsFullAccess;
}
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
{
return !_allowsScriptsFullAccess;
}
+ (NSString *)webScriptNameForSelector:(SEL)selector
{
return nil;
}
@end
@interface JSObjC : NSObject {
}
// expose some useful objc functions to the scripting environment
- (id)lookUpClass:(NSString *)name;
- (void)log:(NSString *)message;
- (id)retainObject:(id)obj;
- (id)classOfObject:(id)obj;
- (NSString *)classNameOfObject:(id)obj;
@end
@implementation JSObjC
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector
{
return NO;
}
+ (NSString *)webScriptNameForSelector:(SEL)selector
{
return nil;
}
- (id)invokeDefaultMethodWithArguments:(NSArray *)args
{
// this is a useful shortcut for accessing objective-c classes from the scripting
// environment, e.g. 'var myObject = objc("NSObject").alloc().init();'
if ([args count] == 1)
return [self lookUpClass:[args objectAtIndex:0]];
return nil;
}
- (id)lookUpClass:(NSString *)name
{
return NSClassFromString(name);
}
- (void)log:(NSString *)message
{
NSLog(message);
}
- (id)retainObject:(id)obj
{
return [obj retain];
}
- (id)classOfObject:(id)obj
{
return (id)[obj class];
}
- (NSString *)classNameOfObject:(id)obj
{
return [obj className];
}
@end
@implementation ObjCPlugin
+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
{
if (aSelector == @selector(removeBridgeRestrictions:))
return NO;
if (aSelector == @selector(echo:))
return NO;
if (aSelector == @selector(throwIfArgumentIsNotHello:))
return NO;
return YES;
}
+ (NSString *)webScriptNameForSelector:(SEL)aSelector
{
if (aSelector == @selector(echo:))
return @"echo";
if (aSelector == @selector(throwIfArgumentIsNotHello:))
return @"throwIfArgumentIsNotHello";
return nil;
}
+ (NSString *)webScriptNameForKey:(const char *)key
{
if (strcmp(key, "throwOnDealloc") == 0)
return @"throwOnDealloc";
return nil;
}
+ (BOOL)isKeyExcludedFromWebScript:(const char *)key
{
if (strcmp(key, "throwOnDealloc") == 0)
return NO;
return YES;
}
- (void)removeBridgeRestrictions:(id)container
{
// let scripts invoke any selector
[NSObject setAllowsScriptsFullAccess:YES];
// store a JSObjC instance into the provided container
JSObjC *objc = [[JSObjC alloc] init];
[container setValue:objc forKey:@"objc"];
[objc release];
}
- (id)echo:(id)obj
{
return obj;
}
- (void)throwIfArgumentIsNotHello:(NSString *)str
{
if (![str isEqualToString:@"Hello"])
[WebScriptObject throwException:[NSString stringWithFormat:@"%@ != Hello", str]];
}
- (void)dealloc
{
if (throwOnDealloc)
[WebScriptObject throwException:@"Throwing exception on dealloc of ObjCPlugin"];
[super dealloc];
}
@end