Initially dont encrypt communication, allows for efficient transmission of large blobs

This commit is contained in:
Kovid Goyal 2016-03-25 11:35:24 +05:30
parent e15f53cdf2
commit 7c050209e5
3 changed files with 63 additions and 36 deletions

View File

@ -6,9 +6,9 @@ from read_book.globals import set_boss
class Boss: class Boss:
def __init__(self, gcm): def __init__(self):
self.gcm = gcm
self.ready_sent = False self.ready_sent = False
self.encrypted_communications = False
window.addEventListener('message', self.handle_message.bind(self), False) window.addEventListener('message', self.handle_message.bind(self), False)
window.addEventListener('load', def(): window.addEventListener('load', def():
if not self.ready_sent: if not self.ready_sent:
@ -16,27 +16,37 @@ class Boss:
self.ready_sent = True self.ready_sent = True
) )
set_boss(self) set_boss(self)
self.handlers = {
'keys':self.create_gcm.bind(self),
}
def handle_message(self, event): def handle_message(self, event):
if event.source is not window.parent: if event.source is not window.parent:
return return
try: data = event.data
data = JSON.parse(self.gcm.decrypt(event.data)) if self.encrypted_communications:
except Exception as e: try:
print('Could not process message from parent:') data = JSON.parse(self.gcm_from_parent.decrypt(data))
console.log(e) except Exception as e:
if data.action is 'load': print('Could not process message from parent:')
pass console.log(e)
return
func = self.handlers[data.action]
if func:
func(data)
else:
print('Unknown action in message to iframe from parent: ' + data.action)
def create_gcm(self, data):
self.gcm_from_parent, self.gcm_to_parent = GCM(data.secret.subarray(0, 32)), GCM(data.secret.subarray(32))
def send_message(self, data): def send_message(self, data):
data = self.gcm.encrypt(JSON.stringify(data)) if self.encrypted_communications:
data = self.gcm_to_parent.encrypt(JSON.stringify(data))
window.parent.postMessage(data, '*') window.parent.postMessage(data, '*')
def init(): def init():
script = document.getElementById('bootstrap') script = document.getElementById('bootstrap')
gcm = GCM(eval(script.getAttribute('data-key'))) script.parentNode.removeChild(script) # free up some memory
script.removeAttribute('data-key') Boss()
script.parentNode.removeChild(script)
script = None
Boss(gcm)

View File

@ -11,18 +11,16 @@ def decode_url(x):
parts = x.split(',,') parts = x.split(',,')
return decode_component(parts[0]), decode_component(parts[1] or '') return decode_component(parts[0]), decode_component(parts[1] or '')
secret_key = Uint8Array(32) secret = Uint8Array(64)
window.crypto.getRandomValues(secret_key) window.crypto.getRandomValues(secret)
secret_key_as_js = repr(secret_key) gcm_to_iframe, gcm_from_iframe = GCM(secret.subarray(0, 32)), GCM(secret.subarray(32))
gcm = GCM(secret_key)
iframe_id = 'read-book-iframe' iframe_id = 'read-book-iframe'
def send_message(data): def encrypt_message(data):
data = gcm.encrypt(JSON.stringify(data)) return gcm_to_iframe.encrypt(JSON.stringify(data))
document.getElementById(iframe_id).contentWindow.postMessage(data, '*')
def decrypt_message(data): def decrypt_message(data):
return JSON.parse(gcm.decrypt(data)) return JSON.parse(gcm_from_iframe.decrypt(data))
class Resource: class Resource:

View File

@ -3,13 +3,13 @@
from elementmaker import E from elementmaker import E
from gettext import gettext as _ from gettext import gettext as _
from read_book.resources import ResourceManager, secret_key_as_js, iframe_id, decrypt_message from read_book.resources import ResourceManager, encrypt_message, iframe_id, decrypt_message, secret
LOADING_DOC = ''' LOADING_DOC = '''
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script type="text/javascript" id="bootstrap" data-key="__KEY__"> <script type="text/javascript" id="bootstrap">
__SCRIPT__ __SCRIPT__
end_script end_script
</head> </head>
@ -35,8 +35,12 @@ class View:
self.src_doc = None self.src_doc = None
self.iframe_ready = False self.iframe_ready = False
self.pending_spine_load = None self.pending_spine_load = None
self.encrypted_communications = False
self.create_src_doc() self.create_src_doc()
window.addEventListener('message', self.handle_message.bind(self), False) window.addEventListener('message', self.handle_message.bind(self), False)
self.handlers = {
'ready': self.on_iframe_ready.bind(self),
}
@property @property
def iframe(self): def iframe(self):
@ -47,24 +51,39 @@ class View:
self.ui.interface_data.main_js = None self.ui.interface_data.main_js = None
self.src_doc = self.iframe.srcdoc = LOADING_DOC.replace( self.src_doc = self.iframe.srcdoc = LOADING_DOC.replace(
'__SCRIPT__', iframe_script).replace( '__SCRIPT__', iframe_script).replace(
'__BS__', _('Bootstrapping book reader...')).replace( '__BS__', _('Bootstrapping book reader...'))
'__KEY__', 'new ' + secret_key_as_js)
def init_iframe(self, iframe_script): def init_iframe(self, iframe_script):
self.encrypted_communications = False
self.iframe.srcdoc = self.src_doc self.iframe.srcdoc = self.src_doc
def send_message(self, data):
if self.encrypted_communications:
data = encrypt_message(data)
self.iframe.contentWindow.postMessage(data, '*')
def handle_message(self, event): def handle_message(self, event):
if event.source is not self.iframe.contentWindow: if event.source is not self.iframe.contentWindow:
return return
try: data = event.data
data = decrypt_message(event.data) if self.encrypted_communications:
except Exception as e: try:
print('Could not process message from iframe:') data = decrypt_message(data)
console.log(e) except Exception as e:
if data.action is 'ready': print('Could not process message from iframe:')
self.iframe_ready = True console.log(e)
if self.pending_spine_load: return
self.show_spine_item_stage2() func = self.handlers[data.action]
if func:
func(data)
else:
print('Unknown action in message from iframe to parent: ' + data.action)
def on_iframe_ready(self, data):
self.send_message({'action':'keys', 'secret':secret})
self.iframe_ready = True
if self.pending_spine_load:
self.show_spine_item_stage2()
def show_loading(self, title): def show_loading(self, title):
return # TODO: Implement this return # TODO: Implement this