Skip to content
Snippets Groups Projects
Commit 07072912 authored by Mark Haines's avatar Mark Haines
Browse files

Add javascript bindings using emscripten

parent f10c04d6
No related branches found
No related tags found
No related merge requests found
var runtime = Module['Runtime'];
var malloc = Module['_malloc'];
var free = Module['_free'];
var Pointer_stringify = Module['Pointer_stringify'];
var AXOLOTL_ERROR = Module['_axolotl_error']();
function stack(size_or_array) {
return Module['allocate'](size_or_array, 'i8', Module['ALLOC_STACK']);
}
function array_from_string(string) {
return Module['intArrayFromString'](string, true);
}
function random_stack(size) {
var ptr = stack(size);
var array = new Uint8Array(Module['HEAPU8'].buffer, ptr, size);
window.crypto.getRandomValues(array);
}
function restore_stack(wrapped) {
return function() {
var sp = runtime.stackSave();
try {
return wrapped.apply(this, arguments);
} finally {
runtime.stackRestore(sp);
}
}
}
function Account() {
var size = Module['_axolotl_account_size']();
this.buf = malloc(size);
this.ptr = Module['_axolotl_account'](this.buf);
}
function account_method(wrapped) {
return function() {
var result = wrapped.apply(this, arguments);
if (result === AXOLOTL_ERROR) {
var message = Pointer_stringify(
Module['_axolotl_account_last_error'](arguments[0])
);
throw "AXOLOTL." + message;
}
return result;
}
}
Account.prototype['free'] = function() {
free(this.ptr);
}
Account.prototype['create'] = restore_stack(function() {
var random_length = account_method(
Module['_axolotl_create_account_random_length']
)(this.ptr);
var random = random_stack(random_length);
account_method(Module['_axolotl_create_account'])(
this.ptr, random, random_length
);
});
Account.prototype['identity_keys'] = restore_stack(function() {
var keys_length = account_method(
Module['_axolotl_account_identity_keys_length']
)(this.ptr);
var keys = stack(keys_length);
account_method(Module['_axolotl_account_identity_keys'])(
this.ptr, keys, keys_length
);
return Pointer_stringify(keys, keys_length);
});
Account.prototype['one_time_keys'] = restore_stack(function() {
var keys_length = account_method(
Module['_axolotl_account_one_time_keys_length']
)(this.ptr);
var keys = stack(keys_length);
account_method(Module['_axolotl_account_one_time_keys'])(
this.ptr, keys, keys_length
);
return Pointer_stringify(keys, keys_length);
});
Account.prototype['pickle'] = restore_stack(function(key) {
var key_array = array_from_string(key);
var pickle_length = account_method(
Module['_axolotl_pickle_account_length']
)(this.ptr);
var key_buffer = stack(key_array);
var pickle_buffer = stack(pickle_length);
account_method(Module['_axolotl_pickle_account'])(
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
);
return Pointer_stringify(pickle_buffer, pickle_length);
});
Account.prototype['unpickle'] = restore_stack(function(key, pickle) {
var key_array = array_from_string(key);
var key_buffer = stack(key_array);
var pickle_array = array_from_string(pickle);
var pickle_buffer = stack(pickle_length);
account_method(Module['_axolotl_unpickle_account'])(
this.ptr, key_buffer, key_array.length, pickle_buffer,
pickle_array.length
);
});
function Session() {
var size = Module['_axolotl_session_size']();
this.buf = malloc(size);
this.ptr = Module['_axolotl_session'](this.buf);
}
function session_method(wrapped) {
return function() {
var result = wrapped.apply(this, arguments);
if (result === AXOLOTL_ERROR) {
var message = Pointer_stringify(
Module['_axolotl_session_last_error'](arguments[0])
);
throw "AXOLOTL." + message;
}
return result;
}
}
Session.prototype['free'] = function() {
free(this.ptr);
}
Session.prototype['pickle'] = restore_stack(function(key) {
var key_array = array_from_string(key);
var pickle_length = session_method(
Module['_axolotl_pickle_session_length']
)(this.ptr);
var key_buffer = stack(key_array);
var pickle_buffer = stack(pickle_length);
session_method(Module['_axolotl_pickle_session'])(
this.ptr, key_buffer, key_array.length, pickle_buffer, pickle_length
);
return Pointer_stringify(pickle_buffer, pickle_length);
});
Session.prototype['unpickle'] = restore_stack(function(key, pickle) {
var key_array = array_from_string(key);
var key_buffer = stack(key_array);
var pickle_array = array_from_string(pickle);
var pickle_buffer = stack(pickle_array);
session_method(Module['_axolotl_unpickle_session'])(
this.ptr, key_buffer, key_array.length, pickle_buffer,
pickle_array.length
);
});
Session.prototype['create_outbound'] = restore_stack(function(
account, their_identity_key, their_one_time_key_id, their_one_time_key
) {
var random_length = session_method(
Module['_axolotl_create_outbound_session_random_length']
)(this.ptr);
var random = random_stack(random_length);
var identity_key_array = array_from_string(their_identity_key);
var one_time_key_array = array_from_string(their_one_time_key);
var identity_key_buffer = stack(identity_key_array);
var one_time_key_buffer = stack(one_time_key_array);
session_method(Module['_axolotl_create_outbound_session'])(
this.ptr, account.ptr,
identity_key_buffer, identity_key_array.length,
their_one_time_key_id,
one_time_key_buffer, one_time_key_array.length,
random, random_length
);
});
Session.prototype['create_inbound'] = restore_stack(function(
account, one_time_key_message
) {
var message_array = array_from_string(one_time_key_message);
var message_buffer = stack(message_array);
session_method(Module['_axolotl_create_inbound_session'])(
this.ptr, account.ptr, message_buffer, message_array.length
);
});
Session.prototype['matches_inbound'] = restore_stack(function(
account, one_time_key_message
) {
var message_array = array_from_string(one_time_key_message);
var message_buffer = stack(message_array);
return session_method(Module['_axolotl_matches_inbound_session'])(
this.ptr, account.ptr, message_buffer, message_array.length
) ? true : false;
});
Session.prototype['encrypt'] = restore_stack(function(
plaintext
) {
var random_length = session_method(
Module['_axolotl_encrypt_random_length']
)(this.ptr);
var message_type = session_method(
Module['_axolotl_encrypt_message_type']
)(this.ptr);
var plaintext_array = array_from_string(plaintext);
var message_length = session_method(
Module['_axolotl_encrypt_message_length']
)(this.ptr, plaintext_array.length);
var random = random_stack(random_length);
var plaintext_buffer = stack(plaintext_array);
var message_buffer = stack(message_length);
session_method(Module['_axolotl_encrypt'])(
this.ptr,
plaintext_buffer, plaintext_array.length,
random, random_length,
message_buffer, message_length
);
return {
"type": message_type,
"body": Pointer_stringify(message_buffer, message_length)
};
});
Session.prototype['decrypt'] = restore_stack(function(
message_type, message
) {
var message_array = array_from_string(message);
var message_buffer = stack(message_array);
var max_plaintext_length = session_method(
Module['_axolotl_decrypt_max_plaintext_length']
)(this.ptr, message_type, message_buffer, message_array.length);
// caculating the length destroys the input buffer.
// So we copy the array to a new buffer
var message_buffer = stack(message_array);
var plaintext_buffer = stack(max_plaintext_length);
var plaintext_length = session_method(Module["_axolotl_decrypt"])(
this.ptr, message_type,
message_buffer, message.length,
plaintext_buffer, max_plaintext_length
);
return Pointer_stringify(plaintext_buffer, plaintext_length);
});
return {"Account": Account, "Session": Session};
}();
Axolotl = function() {
#! /usr/bin/python
# Copyright 2015 OpenMarket Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import subprocess
import glob
import os
import sys
import re
import json
source_files = glob.glob("src/*.cpp")
pre_js, = glob.glob("javascript/*pre.js")
post_js, = glob.glob("javascript/*post.js")
functions = set()
RE_FUNCTION=re.compile("(axolotl_[^( ]*)\\(")
with open("include/axolotl/axolotl.hh") as header:
for line in header:
match = RE_FUNCTION.search(line)
if match:
functions.add(match.groups()[0])
exported_functions = os.path.abspath("build/exported_functions.json")
with open(exported_functions, "w") as json_file:
json.dump(["_" + function for function in functions], json_file)
emcc = os.environ.get("EMCC", "emcc")
compile_args = [emcc]
compile_args += """
-O3
-Iinclude
-Ilib
-std=c++11
--closure 1
--memory-init-file 0
-s NO_FILESYSTEM=1
-s NO_BROWSER=1
-s INVOKE_RUN=0
""".split()
compile_args += source_files
compile_args += ("--pre-js", pre_js)
compile_args += ("--post-js", post_js)
compile_args += ("-s", "EXPORTED_FUNCTIONS=@" + exported_functions)
library = "build/axolotl.js"
def run(args):
print args
print " ".join(args)
subprocess.check_call(args)
run(compile_args + ["-o", library])
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment