2025-05-28 18:33:04 +02:00

880 lines
27 KiB
Lua
Executable File

-- libolm ffi wrapper for Lua(JIT)
--[[
-- Copyright 2015-2016 Tor Hveem <tor@hveem.no>
--
/* Copyright 2016 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.
*/
--]]
local ffi = require'ffi'
ffi.cdef[[
typedef struct {
void * memory;
} OlmAccount ;
size_t olm_account_size();
size_t olm_create_account(
OlmAccount * account,
void const * random, size_t random_length
);
OlmAccount * olm_account(
void * memory
);
size_t olm_create_account_random_length(
OlmAccount * account
);
size_t olm_account_identity_keys(
OlmAccount * account,
void * identity_keys, size_t identity_key_length
);
size_t olm_account_identity_keys_length(
OlmAccount * account
);
size_t olm_account_signature_length(
OlmAccount * account
);
size_t olm_account_sign(
OlmAccount * account,
void const * message, size_t message_length,
void * signature, size_t signature_length
);
typedef struct {
void * memory;
} OlmSession ;
OlmSession * olm_session(
void * memory
);
size_t olm_session_size();
size_t olm_account_generate_one_time_keys_random_length(
OlmAccount * account,
size_t number_of_keys
);
size_t olm_account_generate_one_time_keys(
OlmAccount * account,
size_t number_of_keys,
void const * random, size_t random_length
);
size_t olm_account_one_time_keys_length(
OlmAccount * account
);
size_t olm_account_one_time_keys(
OlmAccount * account,
void * one_time_keys, size_t one_time_keys_length
);
size_t olm_create_outbound_session_random_length(
OlmSession * session
);
size_t olm_create_outbound_session(
OlmSession * session,
OlmAccount * account,
void const * their_identity_key, size_t their_identity_key_length,
void const * their_one_time_key, size_t their_one_time_key_length,
void const * random, size_t random_length
);
size_t olm_encrypt_random_length(
OlmSession * session
);
size_t olm_encrypt_message_type(
OlmSession * session
);
size_t olm_encrypt_message_length(
OlmSession * session,
size_t plaintext_length
);
size_t olm_encrypt(
OlmSession * session,
void const * plaintext, size_t plaintext_length,
void const * random, size_t random_length,
void * message, size_t message_length
);
size_t olm_create_inbound_session(
OlmSession * session,
OlmAccount * account,
void * one_time_key_message, size_t message_length
);
size_t olm_create_inbound_session_from(
OlmSession * session,
OlmAccount * account,
void const * their_identity_key, size_t their_identity_key_length,
void * one_time_key_message, size_t message_length
);
size_t olm_decrypt_max_plaintext_length(
OlmSession * session,
size_t message_type,
void * message, size_t message_length
);
size_t olm_decrypt(
OlmSession * session,
size_t message_type,
void * message, size_t message_length,
void * plaintext, size_t max_plaintext_length
);
size_t olm_pickle_account_length(
OlmAccount * account
);
size_t olm_pickle_session_length(
OlmSession * session
);
size_t olm_pickle_account(
OlmAccount * account,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_pickle_session(
OlmSession * session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_unpickle_account(
OlmAccount * account,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_unpickle_session(
OlmSession * session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_matches_inbound_session(
OlmSession * session,
void * one_time_key_message, size_t message_length
);
size_t olm_error();
const char * olm_session_last_error(
OlmSession * session
);
const char * olm_account_last_error(
OlmAccount * account
);
size_t olm_clear_account(
OlmAccount * account
);
size_t olm_clear_session(
OlmSession * session
);
size_t olm_session_id_length(
OlmSession * session
);
size_t olm_session_id(
OlmSession * session,
void * id, size_t id_length
);
size_t olm_account_mark_keys_as_published(
OlmAccount * account
);
size_t olm_remove_one_time_keys(
OlmAccount * account,
OlmSession * session
);
typedef struct OlmOutboundGroupSession OlmOutboundGroupSession;
size_t olm_outbound_group_session_size();
OlmOutboundGroupSession * olm_outbound_group_session(
void *memory
);
const char *olm_outbound_group_session_last_error(
const OlmOutboundGroupSession *session
);
size_t olm_pickle_outbound_group_session_length(
const OlmOutboundGroupSession *session
);
size_t olm_pickle_outbound_group_session(
OlmOutboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_unpickle_outbound_group_session(
OlmOutboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_init_outbound_group_session_random_length(
const OlmOutboundGroupSession *session
);
size_t olm_init_outbound_group_session(
OlmOutboundGroupSession *session,
uint8_t const * random, size_t random_length
);
size_t olm_group_encrypt_message_length(
OlmOutboundGroupSession *session,
size_t plaintext_length
);
size_t olm_group_encrypt(
OlmOutboundGroupSession *session,
uint8_t const * plaintext, size_t plaintext_length,
uint8_t * message, size_t message_length
);
size_t olm_outbound_group_session_id_length(
const OlmOutboundGroupSession *session
);
size_t olm_outbound_group_session_id(
OlmOutboundGroupSession *session,
uint8_t * id, size_t id_length
);
uint32_t olm_outbound_group_session_message_index(
OlmOutboundGroupSession *session
);
size_t olm_outbound_group_session_key_length(
const OlmOutboundGroupSession *session
);
size_t olm_outbound_group_session_key(
OlmOutboundGroupSession *session,
uint8_t * key, size_t key_length
);
typedef struct OlmInboundGroupSession OlmInboundGroupSession;
size_t olm_inbound_group_session_size();
OlmInboundGroupSession * olm_inbound_group_session(
void *memory
);
const char *olm_inbound_group_session_last_error(
const OlmInboundGroupSession *session
);
size_t olm_clear_inbound_group_session(
OlmInboundGroupSession *session
);
size_t olm_pickle_inbound_group_session_length(
const OlmInboundGroupSession *session
);
size_t olm_pickle_inbound_group_session(
OlmInboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_unpickle_inbound_group_session(
OlmInboundGroupSession *session,
void const * key, size_t key_length,
void * pickled, size_t pickled_length
);
size_t olm_init_inbound_group_session(
OlmInboundGroupSession *session,
uint32_t message_index,
uint8_t const * session_key, size_t session_key_length
);
size_t olm_group_decrypt_max_plaintext_length(
OlmInboundGroupSession *session,
uint8_t * message, size_t message_length
);
size_t olm_group_decrypt(
OlmInboundGroupSession *session,
/* input; note that it will be overwritten with the base64-decoded
message. */
uint8_t * message, size_t message_length,
/* output */
uint8_t * plaintext, size_t max_plaintext_length
);
]]
local olm = ffi.load('libolm')
local ERR = olm.olm_error()
local function create_string_buffer(obj, arg)
-- most of the API calls return ULL which is of type cdata, we can convert to lua numbers using tonumber
-- with regular Lua FFI type is userdata
if type(arg) == 'number' or type(arg) == 'cdata' or type(arg) == 'userdata' then
local buf = ffi.new("uint8_t[?]", tonumber(arg))
table.insert(obj.strings, buf)
return buf
end
return arg
end
local function create_string(str, size)
if not size then
size = #str
end
local msg = ffi.new('uint8_t[?]', size)
ffi.copy(msg, str, size)
return msg
end
local function len(arg)
-- Helper for porting from olm.py
return #arg
end
local function read_random(n)
local fd = io.open('/dev/urandom', 'rb')
local rnd = fd:read(tonumber(n))
fd:close()
return rnd
end
local Account = {}
Account.__index = Account
Account.new = function()
local account = {}
setmetatable(account, Account)
local size = tonumber(olm.olm_account_size())
-- Save C string buffer to a table so the garbage collector does not clean
-- the buffers before the olm library is done reading and writing to them
-- TODO: check why this is needed
account.strings = {}
account.ptr = olm.olm_account(create_string_buffer(account, size))
return account
end
function Account:clear()
local ret = olm.olm_clear_account(self.ptr)
self.strings = {}
return ret
end
function Account:last_error()
return ffi.string(olm.olm_account_last_error(self.ptr))
end
function Account:errcheck(val)
if val == ERR then
local err = self:last_error()
return val, err
end
return val, nil
end
function Account:create()
local random_length = tonumber(olm.olm_create_account_random_length(self.ptr))
local random = create_string(read_random(random_length), random_length)
olm.olm_create_account(self.ptr, random, random_length)
end
function Account:identity_keys()
local out_length, err = self:errcheck(olm.olm_account_identity_keys_length(self.ptr))
if err then
return out_length, err
end
out_length = tonumber(out_length)
local out_buffer = create_string_buffer(self, out_length)
local _, ierr = self:errcheck(olm.olm_account_identity_keys(self.ptr, out_buffer, out_length))
if ierr then
return '', ierr
end
local identity_keys = ffi.string(out_buffer, out_length)
return identity_keys
end
function Account:sign(message)
local out_length = tonumber(olm.olm_account_signature_length(self.ptr))
local message_buffer = create_string_buffer(self, message)
local out_buffer = create_string_buffer(self, out_length)
olm.olm_account_sign(
self.ptr, message_buffer, len(message), out_buffer, out_length
)
return ffi.string(out_buffer, out_length)
end
function Account:one_time_keys()
local out_length = tonumber(olm.olm_account_one_time_keys_length(self.ptr))
local out_buffer = create_string_buffer(self, out_length)
local _, err = olm.olm_account_one_time_keys(self.ptr, out_buffer, out_length)
if err then return '', err end
local out = ffi.string(out_buffer, out_length)
return out
end
function Account:generate_one_time_keys(count)
local random_length = tonumber(olm.olm_account_generate_one_time_keys_random_length(self.ptr, count))
local random = create_string(read_random(random_length), random_length)
return self:errcheck(olm.olm_account_generate_one_time_keys(
self.ptr, count, random, random_length
))
end
function Account:pickle(key)
local key_buffer = create_string_buffer(self, key)
local pickle_length = tonumber(olm.olm_pickle_account_length(self.ptr))
local pickle_buffer = create_string_buffer(self, pickle_length)
local _, err = olm.olm_pickle_account(
self.ptr, key_buffer, #key, pickle_buffer, pickle_length
)
if err then
return nil, err
end
return ffi.string(pickle_buffer, pickle_length)
end
function Account:unpickle(key, pickle)
local pickle_buffer = create_string(pickle, #pickle)
local ret, err = self:errcheck(olm.olm_unpickle_account(
self.ptr, key, #key, pickle_buffer, #pickle
))
return ret, err
end
function Account:mark_keys_as_published()
return self:errcheck(olm.olm_account_mark_keys_as_published(self.ptr))
end
function Account:remove_one_time_keys(session)
return self:errcheck(olm.olm_remove_one_time_keys(self.ptr, session.ptr))
end
local Session = {}
Session.__index = Session
Session.new = function()
local session = {}
setmetatable(session, Session)
session.strings = {}
local buf = create_string_buffer(session, tonumber(olm.olm_session_size()))
session.ptr = olm.olm_session(buf)
return session
end
function Session:clear()
local ret, err = self:errcheck(olm.olm_clear_session(self.ptr))
if err then return nil, err end
-- Save C string buffer to a table so the garbage collector does not clean
-- the buffers before the olm library is done reading and writing to them
-- TODO: check why this is needed
self.strings = {}
return ret
end
function Session:errcheck(val)
if val == ERR then
local err = self:last_error()
return val, err
end
return val, nil
end
function Session:last_error()
return ffi.string(olm.olm_session_last_error(self.ptr))
end
function Session:create_outbound(account, identity_key, one_time_key)
local r_length = olm.olm_create_outbound_session_random_length(self.ptr)
local random = read_random(r_length)
return self:errcheck(olm.olm_create_outbound_session(
self.ptr,
account.ptr,
identity_key, #identity_key,
one_time_key, #one_time_key,
random, r_length
))
end
function Session:create_inbound(account, one_time_key_message)
local msg = create_string(one_time_key_message)
olm.olm_create_inbound_session(
self.ptr,
account.ptr,
msg, #one_time_key_message
)
end
function Session:create_inbound_from(account, identity_key, one_time_key_message)
local one_time_key_message_buffer = create_string(one_time_key_message)
return self:errcheck(olm.olm_create_inbound_session_from(
self.ptr,
account.ptr,
identity_key, #identity_key,
one_time_key_message_buffer, #one_time_key_message
))
end
function Session:matches_inbound(one_time_key_message)
local one_time_key_message_buffer = create_string(one_time_key_message)
local matches = olm.olm_matches_inbound_session(
self.ptr,
one_time_key_message_buffer, len(one_time_key_message)
)
if tonumber(matches) == 1 then
return true
end
return false
end
function Session:session_id()
local id_length = tonumber(olm.olm_session_id_length(self.ptr))
local id_buffer = create_string_buffer(self, id_length)
local ret, err = self:errcheck(olm.olm_session_id(self.ptr, id_buffer, id_length))
if err then return ret, err end
return ffi.string(id_buffer, id_length)
end
function Session:encrypt(plaintext)
local r_length = olm.olm_encrypt_random_length(self.ptr)
local random = read_random(r_length)
local message_type = tonumber(olm.olm_encrypt_message_type(self.ptr))
local message_length = tonumber(olm.olm_encrypt_message_length(
self.ptr, #plaintext
))
local message_buffer = create_string_buffer(self, message_length)
olm.olm_encrypt(
self.ptr,
plaintext, #plaintext,
random, r_length,
message_buffer, message_length
)
message_buffer = ffi.string(message_buffer, message_length)
return message_type, message_buffer
end
function Session:decrypt(message_type, message)
local maxlen_message_buffer = create_string(message)
local max_plaintext_length, err = self:errcheck(olm.olm_decrypt_max_plaintext_length(
self.ptr, message_type, maxlen_message_buffer, #message
))
if err then return nil, err end
max_plaintext_length = tonumber(max_plaintext_length)
local plaintext_buffer = create_string_buffer(self, max_plaintext_length)
local message_buffer = create_string(message)
local plaintext_length, perr = self:errcheck(olm.olm_decrypt(
self.ptr, message_type, message_buffer, #message,
plaintext_buffer, max_plaintext_length
))
if perr then return nil, perr end
local plaintext = ffi.string(plaintext_buffer, tonumber(plaintext_length))
return plaintext
end
function Session:pickle(key)
local key_buffer = create_string_buffer(self, key)
local pickle_length = tonumber(olm.olm_pickle_session_length(self.ptr))
local pickle_buffer = create_string_buffer(self, pickle_length)
olm.olm_pickle_session(
self.ptr, key_buffer, len(key), pickle_buffer, pickle_length
)
return ffi.string(pickle_buffer, pickle_length)
end
function Session:unpickle(key, pickle)
local pickle_buffer = create_string(pickle, #pickle)
local ret = olm.olm_unpickle_session(
self.ptr, key, #key, pickle_buffer, #pickle
)
return self:errcheck(ret)
end
local OutboundGroupSession = {}
OutboundGroupSession.__index = OutboundGroupSession
OutboundGroupSession.new = function()
local session = {}
setmetatable(session, OutboundGroupSession)
session.strings = {}
local buf = create_string_buffer(session, tonumber(olm.olm_outbound_group_session_size()))
session.ptr = olm.olm_outbound_group_session(buf)
local random_length = tonumber(olm.olm_init_outbound_group_session_random_length(session.ptr))
local random = create_string(read_random(random_length), random_length)
olm.olm_init_outbound_group_session(session.ptr, random, random_length)
return session
end
function OutboundGroupSession:pickle(key)
local key_buffer = create_string_buffer(self, key)
local pickle_length = tonumber(olm.olm_pickle_outbound_group_session_length(self.ptr))
local pickle_buffer = create_string_buffer(self, pickle_length)
olm.olm_pickle_outbound_group_session(
self.ptr, key_buffer, len(key), pickle_buffer, pickle_length
)
return ffi.string(pickle_buffer, pickle_length)
end
function OutboundGroupSession:unpickle(key, pickle)
local pickle_buffer = create_string(pickle, #pickle)
local ret = olm.olm_unpickle_outbound_group_session(
self.ptr, key, #key, pickle_buffer, #pickle
)
return self:errcheck(ret)
end
function OutboundGroupSession:session_id()
local id_length = tonumber(olm.olm_outbound_group_session_id_length(self.ptr))
local id_buffer = create_string_buffer(self, id_length)
local ret, err = self:errcheck(olm.olm_outbound_group_session_id(self.ptr, id_buffer, id_length))
if err then return ret, err end
return ffi.string(id_buffer, id_length)
end
function OutboundGroupSession:encrypt(plaintext)
local message_length = tonumber(olm.olm_group_encrypt_message_length(
self.ptr, #plaintext
))
local message_buffer = create_string_buffer(self, message_length)
olm.olm_group_encrypt(
self.ptr,
plaintext, #plaintext,
message_buffer, message_length
)
message_buffer = ffi.string(message_buffer, message_length)
return message_buffer
end
function OutboundGroupSession:message_index()
local index = olm.olm_outbound_group_session_message_index(self.ptr)
return index
end
function OutboundGroupSession:session_key()
local key_length = olm.olm_outbound_group_session_key_length(self.ptr)
local key_buffer = create_string_buffer(self, key_length)
olm.olm_outbound_group_session_key(self.ptr, key_buffer, key_length)
return ffi.string(key_buffer, key_length)
end
function OutboundGroupSession:clear()
--local ret, err = self:errcheck(olm.olm_clear_session(self.ptr))
--if err then return nil, err end
-- Save C string buffer to a table so the garbage collector does not clean
-- the buffers before the olm library is done reading and writing to them
-- TODO: check why this is needed
self.strings = {}
--return ret
end
function OutboundGroupSession:errcheck(val)
if val == ERR then
local err = self:last_error()
return val, err
end
return val, nil
end
function OutboundGroupSession:last_error()
return ffi.string(olm.olm_outbound_group_session_last_error(self.ptr))
end
local InboundGroupSession = {}
InboundGroupSession.__index = InboundGroupSession
InboundGroupSession.new = function()
local session = {}
setmetatable(session, InboundGroupSession)
session.strings = {}
local buf = create_string_buffer(session, tonumber(olm.olm_inbound_group_session_size()))
session.ptr = olm.olm_inbound_group_session(buf)
return session
end
function InboundGroupSession:pickle(key)
local key_buffer = create_string_buffer(self, key)
local pickle_length = tonumber(olm.olm_pickle_inbound_group_session_length(self.ptr))
local pickle_buffer = create_string_buffer(self, pickle_length)
olm.olm_pickle_inbound_group_session(
self.ptr, key_buffer, len(key), pickle_buffer, pickle_length
)
return ffi.string(pickle_buffer, pickle_length)
end
function InboundGroupSession:unpickle(key, pickle)
local pickle_buffer = create_string(pickle, #pickle)
local ret = olm.olm_unpickle_inbound_group_session(
self.ptr, key, #key, pickle_buffer, #pickle
)
return self:errcheck(ret)
end
function InboundGroupSession:init(message_index, session_key)
local key_buffer = create_string_buffer(self, session_key)
return self:errcheck(olm.olm_init_inbound_group_session(self.ptr, message_index, key_buffer, #session_key))
end
function InboundGroupSession:decrypt(message)
local maxlen_message_buffer = create_string(message)
local max_plaintext_length, err = self:errcheck(olm.olm_group_decrypt_max_plaintext_length(
self.ptr, maxlen_message_buffer, #message
))
if err then return nil, err end
max_plaintext_length = tonumber(max_plaintext_length)
local plaintext_buffer = create_string_buffer(self, max_plaintext_length)
local message_buffer = create_string(message)
local plaintext_length, perr = self:errcheck(olm.olm_group_decrypt(
self.ptr, message_buffer, #message,
plaintext_buffer, max_plaintext_length
))
if perr then return nil, err end
local plaintext = ffi.string(plaintext_buffer, tonumber(plaintext_length))
return plaintext
end
function InboundGroupSession:clear()
--local ret, err = self:errcheck(olm.olm_clear_session(self.ptr))
--if err then return nil, err end
-- Save C string buffer to a table so the garbage collector does not clean
-- the buffers before the olm library is done reading and writing to them
-- TODO: check why this is needed
self.strings = {}
--return ret
end
function InboundGroupSession:errcheck(val)
if val == ERR then
local err = self:last_error()
return val, err
end
return val, nil
end
function InboundGroupSession:last_error()
return ffi.string(olm.olm_inbound_group_session_last_error(self.ptr))
end
-- Invoke program with --test to run tests
local test = arg and arg[1] and arg[1] == '--test'
if test then
local json = require'cjson'
local key = 'test'
local err
local _
local alice
local bob
alice = Account.new()
local a_session = Session.new()
bob = Account.new()
local b_session = Session.new()
alice:create()
local pickle = alice:pickle(key)
local a_keys = json.decode(alice:identity_keys())
alice = Account.new()
alice:unpickle(key, pickle)
local a_keys_2 = json.decode(alice:identity_keys())
assert(a_keys.curve25519 == a_keys_2.curve25519)
_, err = alice:unpickle('invalid key', pickle)
assert(err, 'BAD_ACCOUNT_KEY')
pickle = a_session:pickle(key)
a_session:unpickle(key, pickle)
_, err = a_session:unpickle(key, 'invalid base64')
assert(err, 'BAD_ACCOUNT_KEY')
_, err = a_session:unpickle('invalid key', pickle)
assert(err, 'BAD_ACCOUNT_KEY')
_, err = a_session:unpickle('invalid key', 'invalid bad64')
assert(err, 'INVALID_BASE64')
local sign_message = 'yepyepyep'
local signed = alice:sign(sign_message)
print('signed', signed)
bob:create()
-- luacheck: ignore
local bobs_id_keys = json.decode(bob:identity_keys())
bob:generate_one_time_keys(50)
local bobs_id_keys = json.decode(bob:identity_keys())
local bobs_id_key = bobs_id_keys.curve25519
local bobs_ot_keys = json.decode(bob:one_time_keys())
local bobs_ot_key
for _,k in pairs(bobs_ot_keys.curve25519) do
bobs_ot_key = k
end
a_session:create_outbound(alice, bobs_id_key, bobs_ot_key)
bob:remove_one_time_keys(b_session)
local secret_message = 'why not zoidberg?'
message_1_type, message_1_body = a_session:encrypt(secret_message)
b_session:create_inbound(bob, message_1_body)
print('Matches inbound:', assert(b_session:matches_inbound(message_1_body)))
local decrypted = b_session:decrypt(message_1_type, message_1_body)
print( 'Decrypted message: ', decrypted)
assert(secret_message == decrypted)
b_session:create_inbound_from(bob, a_keys.curve25519, message_1_body)
bob:mark_keys_as_published()
print('A session id: ', a_session:session_id())
for i=1,10000 do
Account.new():clear()
end
print('*** GROUP TESTS *** ')
local g_session = OutboundGroupSession.new()
local pickle = g_session:pickle(key)
local _ = g_session:unpickle(key, pickle)
local message_index = g_session:message_index()
local session_key = g_session:session_key()
print('Group session id:', g_session:session_id())
print('Group session index:', g_session:message_index())
print('Group session key:', g_session:session_key())
local i_session = InboundGroupSession.new()
i_session:init(message_index, session_key)
print('Group decrypt', assert(secret_message == i_session:decrypt(g_session:encrypt(secret_message))))
alice:clear()
bob:clear()
a_session:clear()
b_session:clear()
g_session:clear()
i_session:clear()
--print('Temp strings: '.. tostring(#strings))
--strings = {}
end
local test2 = arg and arg[1] and arg[1] == '--decrypt'
if test2 then
local body = ''
local alice
local bob
local OLM_KEY = ''
local json = require'cjson'
local fread = function(fname)
local fd = io.open(fname, 'r')
local data = fd:read('*a')
fd:close()
return data
end
alice = Account.new()
--print(json.encode(arg))
alice:unpickle(OLM_KEY, fread(arg[2]))
local sessions = json.decode(fread(arg[3]))
for id, pickle in pairs(sessions) do
local session = Session.new()
session:unpickle(OLM_KEY, pickle)
print('matches', session:matches_inbound(body))
local matches = session:matches_inbound(body)
if matches then
local cleartext, err = session:decrypt(0, body)
print(session:decrypt(0, body))
end
end
--bob = Account.new()
--local b_session = Session.new()
end
return {
Account=Account,
Session=Session,
OutboundGroupSession=OutboundGroupSession,
InboundGroupSession=InboundGroupSession,
}