Add javascript bindings using emscripten
This commit is contained in:
parent
f10c04d62d
commit
07072912cd
3 changed files with 317 additions and 0 deletions
247
javascript/axolotl_post.js
Normal file
247
javascript/axolotl_post.js
Normal file
|
@ -0,0 +1,247 @@
|
|||
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};
|
||||
}();
|
1
javascript/axolotl_pre.js
Normal file
1
javascript/axolotl_pre.js
Normal file
|
@ -0,0 +1 @@
|
|||
Axolotl = function() {
|
69
javascript/build.py
Normal file
69
javascript/build.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
#! /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])
|
||||
|
Loading…
Reference in a new issue