Totally Objects - TOScript - Version 5.5 [1.0]

Introduction

This document explains how to use the TOScript product from Totally Objects for IBM's VisualAge for Smalltalk. Due to licensing restrictions from IBM on some versions of VisualAge for Smalltalk, developers are not able to include the compiler in packaged application. This product is a Smalltalk interpreter so enables packaged applications to evaluate arbitrary Smalltalk source code.

Installing the TOScript (Smalltalk Interpreter) Product

This Totally Objects product has been packaged in configuration maps. To import them into your library select 'Browse Configuration Maps' from the 'Tools' menu of the 'System Transcript'. In the 'Configuration Maps Browser' select 'Import...' from the 'Names' menu and select the file tobsi5-5_1-0-*.dat. You should then select the three configuration maps contained within this file: 'Totally Objects, Smalltalk Interpreter', Version 5.5 [1.0.*] and 'Totally Objects, Smalltalk Interpreter - Extensions', Version 5.5 [1.0.*]

The configuration maps you have imported contains five applications.

In 'Totally Objects, Smalltalk Interpreter'

In 'Totally Objects, Smalltalk Interpreter - Extensions'

To load an application select the version of the appropriate configuration map in the 'Configuration Maps Browser' and select 'Load' (or 'Load With Required Map') from the 'Editions' menu.

The API

To use the Interpreter you must first create an instance of the class TobSiInterpreter using #new. To evaluate a String containing your Smalltalk code you then should use the method #evaluate:for:arguments:imageInterface: (or one of the three similar methods that call this method with default arguments). The arguments are described in the table below.

Keyword

Description

evaluate:

The String containing the Smalltalk code to be evaluated.

for:

The object that should be adopted by self. If this is unspecified then self is nil.

arguments:

A Dictionary with Strings for keys and Objects for values. The Smalltalk code can then use the key names as if they were arguments. If this is unspecified then an empty Dictionary is used.

imageInterface:

This identifies a instance of a subclass of TobSiImageInterface that specifies an interface to your Smalltalk image. The basic product has only one such concrete subclass 'TobSiFullImageInterface'. This provided a direct one-to-one mapping between the names of globals and methods in your image and in the interpreted code. If the TobSmalltalkInterpreterRestrictedImageInterfaceApp is loaded then the mapping can be more tightly configured using the class TobSiRestrictedImageInterface. For a further explanation see Restricted Image Interface.

The above method (and its variants) will answer the object answered from the last message interpreted.

For example:

will answer with the Integer 3.

If the Smalltalk in the String contains any syntactical errors then an exception is signalled. This exception can be accessed using the expression

The signal will have two arguments; a String describing the error, and a position in the offending String.

If the Smalltalk in the String contains no syntactical errors it will be executed (and may signal its own exceptions!)

The interpreter can be switched into a mode that will enable you to check your Smalltalk for syntax errors without actually executing. To switch this mode on use the method #sendMessages: with the argument false.

Example

Answers 123. If the 'evaluate' String is changed to 'self + y + 3' the the answer is nil and 'undefined' is displayed in the Transcript.

Packaging Applications

Because this version of the product requires a direct one-to-one mapping between the names of globals and methods in your image and those in the interpreted code, it is necessary that any classes or methods that you want to be available to the interpreter need to be included in your packaged image. This means that you will probably wish to make a 'packaging application' to force particular applications, classes and methods to be included.

Integrity Checking

The extension to the Smalltalk Interpreter provides a mechanism for you to attach a cryptographic 'hash' to the beginning of Smalltalk code to be interpreted. Such a hash is produce by feeding a cryptographic key and the Smalltalk code to be protected throught a message digest algorithm. When the interpreter is about to evaluate the Smalltalk code it will first calculate the expected hash value (because it has access to the cryptographic key) and compare this to the hash attached to the code. The message digest algorithm used is MD5 (for more information about this consult the Internet Request For Comments 1321) which is implemented in AbtMD5AlgorithmApp (which is included in the VAST Web Connect Feature). AbtMD5AlgorithmApp has only one prerequisite, Kernel, so does not require any parts 'baggage'.

Adding a Hash

Before you create a hash you must first generate a ByteArray that contains random data that will be your cryptographic key. To do this you should consult a text that deals with the subject in more detail (such as 'Applied Cryptography - 2nd Edition' by Bruce Schneier - ISBN 0-471-11709-9). A typical key would be 16 bytes in length. This key should be made available only to those developers with the authority to write Smalltalk that may be executed by the interpreter and to the interpreter itself. You should next select an algorithm that you wish to use; currently the only available algorithm is MD5.

To add a hash to a String containing Smalltalk. You should first create a checker by executing

or,

Send the checker the message #addIntegrityHashTo:key: with your Smalltalk code (a String) and key (a ByteArray) as arguments. The message will answer a new String containing the 'hash' (in hex) followed by '#' followed by the Smalltalk code.

Example:

Answers the String 'B55311167B5E02803230ED1196E4EF63#Time now'

Evaluating Hashed Smalltalk

To evaluate and check Smalltalk prefixed with a hash use the TobSiInterpreter instance method #checkIntegrityKey:evaluate:for:arguments:imageInterface: (or one or the variants). This is similar to #evaluate:for:arguments:imageInterface: but has an additional first argument, the key (a ByteArray). Before evaluating the Smalltalk code the hash will be checked, if the check fails then the method will answer an instance of TobSiicError and the Smalltalk will not be interpreted.

Example (valid code):

Answers the time now.

Example (invalid code):

Answers a TobSiicError.

Further Information about Keyed Hashing using MD5

This product employes a simple method for using MD5 as a keyed hashing function, it prepends the key to the data so that the key is fed through the algorithm first. This is not necessarily the best way to do this. Totally Objects make no claims as to levels of security acheived by using this product, and recommend that it is first evaluated to see if it meets the security requirements of your system.

Restricted Image Interface

The extension to the product provides a mechanism contolling the visibility that the interpreter has of your image. It enables classes and other globals to be hidden and other virtual globals to be created. Simlarly, individual methods can also be hidden and virtual methods created. This mechanism is useful if you do not want developers writing Smalltalk at runtime to have complete access to your image. In many situations the interpreter will not be used for overall image maintainance but for doing very specific tasks. In these case the only core Smalltalk classes and a few applicaiton level classes will be needed.

To evaluate code with a TobSiInterpreter while adopting a custom interface to the image use the method #evaluate:for:arguments:imageInterface:. The last argument will need to be a instance of TobSiRestrictedImageInterface which can be configured using the following methods:

Method

Description

addConstant:value:

This identifies a String-value pair that can be accessed like a global from the interpreter.

unmapConstant:

This removes any constants added using #addConstant:value: by taking a String as its argument.

clientObject, clientObject:

These get and set an object that is passed as an argument to 'handler' methods.

The default value is 'nil'.

classMethodMapSelector:

This sets a selector for a 'handler' class method (to be understood by all classes) that identifies virtual class methods. These handler methods should expect two arguments, the first a selector identifying a method executed by the interpreter and the second the clientObject described above. The handler method should answer a selector to a real class method (with the same number of arguments) or 'nil' if #doesNotUnderstand: should be called.

The default selector is #tobSiClassMethodMap:for: which is defined only in Object and answers 'nil'.

classMethodVisibilitySelector:

This sets a selector for a 'handler' class method (to be understood by all classes) that identifies which real class methods are visible to the interpreter. These handler methods should expect two arguments, the first a selector identifying a method executed by the interpreter and the second the clientObject described above. The handler method should called.a Boolean indicating whether the method is visible.

The default selector is #tobSiClassMethodVisible:for: which is defined in many 'core' classes. The implementors of the method should be viewed to see which class methods are visible by default.

classVisibilitySelector:

This sets a selector for a 'handler' class method (to be understood by all classes) that identifies if the receiver is visible to the interpreter. These handler methods will have one argument, the clientObject described above. The handler method should answer a Boolean indicating whether the Class can be reference directly by the interpreter.

The default selector is #tobSiClassVisibleFor: which is defined in Object to answer 'false' but overridden in other 'core' classes to answer 'true'. The implementors of the method should be viewed to see which classes are visible by default.

instanceMethodMapSelector:

This sets a selector for a 'handler' class method (to be understood by all classes) that identifies virtual instance methods. These handler methods should expect two arguments, the first a selector identifying a method executed by the interpreter and the second the clientObject described above. The handler method should answer a selector to a real instance method (with the same number of arguments) or 'nil' if #doesNotUnderstand: should be called.

The default selector is tobSiInstanceMethodMap:for: which is defined only in Object and answers 'nil'.

instanceMethodVisibilitySelector:

This sets a selector for a 'handler' class method (to be understood by all classes) that identifies which real instance methods are visible to the interpreter. These handler methods should expect two arguments, the first a selector identifying a method executed by the interpreter and the second the clientObject described above. The handler method should answer a Boolean indicating whether the method is visible.

The default selector is #tobSiInstanceMethodVisible:for: which is defined in many 'core' classes. The implementors of the method should be viewed to see which instance methods are visible by default.


Further Information