try
N3Util = require('n3').Util
catch e
try
N3Util = require('n3').Util
catch e
console.log(“expost n3 to browser”)
N3Util = {}
class HardenedNooDB
HardenedNooDB is a facade over NooDB so the underlying noodb need not be exposed
constructor: (noodb) ->
@get_new_id = () -> noodb.synthetic_key_factory_next()
@uniform_echo = (a) -> return a
@make_new_kb = (kbName) ->
noodb.socket.emit("make_new_kb", {kbName: kbName})
NoorVM =
func_src_predicate: 'http://nooron.com/_/NooronAppArchitecture.ttl#FNC'
default_prefix: 'http://nooron.com/_/NooronAppArchitecture.ttl#'
func_args_and_body_regex: /^\s*function\(([^\)]*)\)\s*{([\n\s\r\S]*)}\s*$/ # /m means multiline
make_vm: (settings, self, caching) ->
self ?= {}
settings ?= {}
settings.prefix ?= @default_prefix
settings.caching ?= false
settings.expose_noodb_safely ?= true
settings.expose_n3util ?= true
noodb = @
if settings.expose_noodb_safely
@facade = new HardenedNooDB(noodb)
self.noodb = @facade # FIXME can this be eliminated?
if settings.expose_n3util
self.n3util = N3Util
self._newline = String.fromCharCode(10)
announce = (msg, more) ->
console.log(msg, more)
throw new Error(msg + "()")
return null
notImplemented = ->
sadly this does not work
console.log("NAME", arguments.callee.name)
return null
make_handler = (settings, self) ->
get: (target, name) ->
noodb.log.info("Proxy_handler.get(target, '#{name}')")
if not (name of target)
console.log(“get(target,’#{name}’)”)
full_name = settings.prefix + name
err = null
try
retval = noodb.find_func(name)
catch e
err = 3
noodb.log.error(e)
retval = noodb.find_func(full_name)
if not retval
noodb.log.error("failed to find_func('#{name}') or find_func('#{full_name}')")
if err
throw err
if settings.caching
target[name] = retval
return retval
return target[name]
get: -> announce “get”, arguments
someRandomFunction: notImplemented # TODO it wold be great if this worked
getPrototypeOf: ->
announce("getPrototypeOf", arguments)
setPrototypeOf: ->
announce("setPrototypeOf", arguments)
isExtensible: ->
announce("isExtensible", arguments)
preventExtensions: ->
announce("preventExtensions", arguments)
getOwnPropertyDescriptor: ->
announce("getOwnPropertyDescriptor", arguments)
defineProperty: ->
announce("defineProperty", arguments)
has: ->
announce("has")
set: ->
announce("set")
deleteProperty: ->
announce("deleteProperty")
ownKeys: ->
announce("ownKeys")
apply: ->
announce("apply")
construct: ->
announce("construct")
return @new_Proxy(self, make_handler(settings, self))
new_Proxy: (target, handler) ->
if not @Proxy?
if window? and window.Proxy?
@Proxy = window.Proxy
else
try
@Proxy = require('harmony-proxy')
catch e
throw new Error("NoorVM not supported in this context: no Proxy! see 'proxy-polyfill'")
return new @Proxy(target, handler)
apply_by_name: (func_name, vm, args) ->
Call a function by name with a list of arguments; return a value. TODO(smurp) Shawn should figure out which version when he’s smarter
@method call_by_name @param {String} func_name @param {Object} vm The execution context in which the function will be applied. @param {Array} args An array of arguments to the function @return {Object} The return value of the named function.
@log.info("apply_by_name('#{func_name}',VM,#{args})")
if typeof func_name is 'undefined'
throw new Error('VM says apply_by_name() func_name should not be undefined')
func = vm[func_name]
if not func throw new Error(“could not find function #{func_name}”)
@log.debug "func",func
return func.apply(vm, args)
get_facade_func: (func_name, vm, args) ->
return @facade? and @facade[func_name] # facade might be disabled
find_func: (func_name) ->
A function body lives in the KB as an string literal on a predicate like nrn:ADD naa:FNC “””function(p1, p2){return p1 + p2;}””” . So @find_func(‘nrn:ADD’) ==> “function(p1,p2){return p1 + p2;}” @method find_func @param {String} func_name @return {String} Returns the javascript source for the named function or false
func = @get_facade_func(func_name)
if func
return func
func_src = @get_func_src(func_name) #or ""
@log.info("func_src:", func_src, typeof func_src , ", func_src[0]:", func_src)
func_a_and_b = @parse_func_args_and_body(func_src)
@log.info("func_a_and_b:", func_a_and_b)
if func_a_and_b
return @compile_func(func_a_and_b)
else
return false
get_func_src: (func_name) ->
@warn_once("get_func_src() always gets the latest version THIS IS A SECURITY HOLE")
@log.info("get_func_src(#{func_name})")
spogi = @query([{s: func_name}, {p: @func_src_predicate}], {which: "last"})
if spogi
retval = spogi.o.key()
return retval
else
throw new Error("VM says function #{func_name} can not be found by @get_func_src()")
parse_func_args_and_body: (func_src) ->
m = func_src.match(@func_args_and_body_regex)
@log.debug("parse_func_args_and_body()")
if m
retval =
args: (t.trim() for t in m[1].split(',')) # remove surrounding spaces
body: m[2]
while retval.args[0] is "" # drain [""] to []
retval.args.pop()
return retval
else
throw new Error("args and body not found in #{func_src}")
return false
compile_func: (func_args_and_body) ->
Return a Function specified by args and body on func_args_and_body It is assumed that func_src is already safe because it has been compiled on the server side by a trusted method. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
@method compile_func @param func_args_and_body A javascript function equivalent to: “function(p1,p2){return p1 + p2;}” but in the form: args: [‘p1’, ‘p2’] body: ‘return p1 + p2;’ @return {Function} The compiled version of the function.
args = func_args_and_body.args or []
body = func_args_and_body.body or "return;"
@log.debug("func_args_and_body", func_args_and_body)
return new Function(args, body)
(exports ? this).NoorVM = NoorVM