Пример #1
0
def _process_xml(request, doc, device):
    x_response = qxml.get_child(doc, 'response')
    x_items = qxml.get_child(x_response, 'items')
    if not x_items:
        return False

    was_updated = False

    # rewrite urls
    for x_item in qxml.list_children(x_items, 'item'):
        was_updated |= _filter_item(request, x_items, x_item)

    was_updated |= _consume_action_queue(request, device, x_items)
    was_updated |= _update_annotations(device, x_items)

    if features.download_updated_books:
        for book in calibre.books().values():
            if book.needs_update_on(device) and book.cde_content_type in (
                    'EBOK', ):  # PDOC updates are not supported ATM
                logging.warn(
                    "book %s updated in library, telling device %s to download it again",
                    book, device)
                _add_item(x_items,
                          'GET',
                          book.cde_content_type,
                          key=book.asin,
                          title=book.title,
                          forced=True)
                was_updated = True

    if was_updated:
        x_total_count = qxml.get_child(x_response, 'total_count')
        qxml.set_text(x_total_count, len(x_items.childNodes))

    return was_updated
Пример #2
0
def _call_and_process(handler, request, device):
	response = handler.call_upstream(request, device)
	cookie = None
	pkcs12 = None
	alias = None
	with minidom.parseString(response.body_text()) as doc:
		x_response = qxml.get_child(doc, 'response')
		x_alias = qxml.get_child(x_response, 'user_device_name')
		alias = qxml.get_text(x_alias)
		x_adp_token = qxml.get_child(x_response, 'adp_token')
		if x_adp_token:
			cookie = qxml.get_text(x_adp_token)
		else:
			x_cookie = qxml.get_child(x_response, 'store_authentication_cookie')
			cookie = qxml.get_text(x_cookie)
			x_key = qxml.get_child(x_response, 'device_private_key')
			pkcs12 = qxml.get_text(x_key)
	if pkcs12:
		try:
			pkcs12 = b64decode(bytes(pkcs12, 'ascii'))
		except:
			logging.exception("failed to decode incoming device key")
			pkcs12 = None
	devices.update(device, alias = alias, cookie = cookie, pkcs12_bytes = pkcs12)
	return response
Пример #3
0
def _process_xml(doc, device, reason):
	x_response = qxml.get_child(doc, 'response')
	x_items = qxml.get_child(x_response, 'items')
	if not x_items:
		return False

	was_updated = False

	# rewrite urls
	for x_item in qxml.list_children(x_items, 'item'):
		was_updated |= _filter_item(x_items, x_item)

	was_updated |= _consume_action_queue(device, x_items)
	was_updated |= _update_annotations(device, x_items)

	if features.download_updated_books:
		for book in calibre.books().values():
			if book.needs_update_on(device) and book.cde_content_type in ('EBOK', ): # PDOC updates are not supported ATM
				logging.warn("book %s updated in library, telling device %s to download it again", book, device)
				_add_item(x_items, 'GET', book.cde_content_type, key = book.asin, title = book.title, forced = True)
				was_updated = True

	if was_updated:
		x_total_count = qxml.get_child(x_response, 'total_count')
		qxml.set_text(x_total_count, len(x_items.childNodes))

	return was_updated
Пример #4
0
def _call_and_process(handler, request, device):
    response = handler.call_upstream(request, device)
    cookie = None
    pkcs12 = None
    alias = None
    with minidom.parseString(response.body_text()) as doc:
        x_response = qxml.get_child(doc, 'response')
        x_alias = qxml.get_child(x_response, 'user_device_name')
        alias = qxml.get_text(x_alias)
        x_adp_token = qxml.get_child(x_response, 'adp_token')
        if x_adp_token:
            cookie = qxml.get_text(x_adp_token)
        else:
            x_cookie = qxml.get_child(x_response,
                                      'store_authentication_cookie')
            cookie = qxml.get_text(x_cookie)
            x_key = qxml.get_child(x_response, 'device_private_key')
            pkcs12 = qxml.get_text(x_key)
    if pkcs12:
        try:
            pkcs12 = b64decode(bytes(pkcs12, 'ascii'))
        except:
            logging.exception("failed to decode incoming device key")
            pkcs12 = None
    devices.update(device, alias=alias, cookie=cookie, pkcs12_bytes=pkcs12)
    return response
Пример #5
0
def get_query_params(req):
	_, _, query = req.path.partition('?')
	if query:
		return query_params(query)
	q = {}
	if is_signed(req) and req.command == 'POST' and req.body and req.headers['Content-Type'] == 'text/xml':
		try:
			with minidom.parseString(req.body) as doc:
				x_request = qxml.get_child(doc, 'request')
				x_parameters = qxml.get_child(x_request, 'parameters')
				for p in qxml.list_children(x_parameters):
					q[p.nodeName] = qxml.get_text(p)
		except: pass
	return q
Пример #6
0
def get_query_params(req):
    _, _, query = req.path.partition('?')
    if query:
        return query_params(query)
    q = {}
    if is_signed(req) and req.command == 'POST' and req.body and req.headers[
            'Content-Type'] == 'text/xml':
        try:
            with minidom.parseString(req.body) as doc:
                x_request = qxml.get_child(doc, 'request')
                x_parameters = qxml.get_child(x_request, 'parameters')
                for p in qxml.list_children(x_parameters):
                    q[p.nodeName] = qxml.get_text(p)
        except:
            pass
    return q
Пример #7
0
def _process_xml(request, doc, device):
	books_on_device = set()
	book_nodes = []
	was_modified = False

	x_annotations = qxml.get_child(doc, 'annotations')

	for x_book in qxml.list_children(x_annotations, 'book'):
		asin = x_book.getAttribute('key')
		if is_uuid(asin, x_book.getAttribute('type')):
			books_on_device.add(asin)
			x_annotations.removeChild(x_book)
			book_nodes.append(x_book)
			was_modified = True

	for x_collection in qxml.iter_children(x_annotations, 'collection'):
		for x_book in qxml.iter_children(x_collection, 'book'):
			asin = x_book.getAttribute('id')
			if is_uuid(asin, x_book.getAttribute('type')) and 'add' == x_book.getAttribute('action'):
				books_on_device.add(asin)

	if books_on_device or book_nodes:
		postprocess.enqueue(_process_sidecar_upload, device, books_on_device, book_nodes)

	if was_modified:
		qxml.remove_whitespace(x_annotations)
		if not len(x_annotations.childNodes):
			doc.removeChild(x_annotations)
		if not len(doc.childNodes):
			# there's no more content relevant to Amazon, just reply with an empty 200
			raise ExceptionResponse()

	return was_modified
Пример #8
0
def _process_xml(doc, device, reason):
	x_response = qxml.get_child(doc, 'response')
	x_items = qxml.get_child(x_response, 'items')
	if not x_items:
		return False

	was_updated = False

	# rewrite urls
	for x_item in qxml.list_children(x_items, 'item'):
		was_updated |= _filter_item(x_items, x_item)

	if features.download_updated_books:
		for book in calibre.books().values():
			if book.needs_update_on(device) and book.cde_content_type in ('EBOK', ): # PDOC updates are not supported ATM
				logging.warn("book %s updated in library, telling device %s to download it again", book, device)
				# <item action="GET" is_incremental="false" key="asin" priority="600" sequence="0" type="EBOK">title</item>
				_add_item(x_items, 'GET', book.cde_content_type, key = book.asin, text = book.title, forced = True) # book.title)
				was_updated = True

	while device.actions_queue:
		action = device.actions_queue.pop()
		# logging.debug("checking action %s", action)
		if list(qxml.filter(x_items, 'item', action = action[0], type = action[1])):
			# logging.debug("action %s already found in %s, skipping", action, x_items)
			continue
		if action == ('SET', 'SCFG'):
			_add_item(x_items, 'SET', 'SCFG', text = _servers_config(device), key = 'KSP.set.scfg', priority = 100)
			was_updated = True
		elif action == ('UPLOAD', 'SNAP'):
			_add_item(x_items, 'UPLOAD', 'SNAP', key = 'KSP.upload.snap', priority = 1000, url = config.server_url + 'FionaCDEServiceEngine/UploadSnapshot')
			was_updated = True
		# elif action == ('GET', 'NAMS'):
		# 	_add_item(x_items, 'GET', 'NAMS', key = 'NameChange' if device.is_kindle() else 'AliasChange')
		# 	was_updated = True
		elif action == ('UPLOAD', 'SCFG'):
			_add_item(x_items, 'UPLOAD', 'SCFG', key = 'KSP.upload.scfg', priority = 50, url = config.server_url + 'ksp/scfg')
			was_updated = True
		else:
			logging.warn("unknown action %s", action)

	if was_updated:
		x_total_count = qxml.get_child(x_response, 'total_count')
		qxml.set_text(x_total_count, len(x_items.childNodes))

	return was_updated
Пример #9
0
def _process_xml_response(doc, device):
	x_request = qxml.get_child(doc, 'request')
	x_items = qxml.get_child(x_request, 'items')
	was_updated = False

	for x_item in qxml.list_children(x_items, 'item'):
		action = x_item.getAttribute('action')
		cde_type = x_item.getAttribute('type')
		key = x_item.getAttribute('key')
		complete_status = x_item.getAttribute('complete_status')

		if _process_item(device, action, cde_type, key, complete_status):
			x_items.removeChild(x_item)
			was_updated = True
			continue

	if was_updated and not len(x_items.childNodes):
		raise ExceptionResponse(data = _DUMMY_BODY)

	return was_updated
Пример #10
0
def _process_xml_response(doc, device):
    x_request = qxml.get_child(doc, 'request')
    x_items = qxml.get_child(x_request, 'items')
    was_updated = False

    for x_item in qxml.list_children(x_items, 'item'):
        action = x_item.getAttribute('action')
        cde_type = x_item.getAttribute('type')
        key = x_item.getAttribute('key')
        complete_status = x_item.getAttribute('complete_status')

        if _process_item(device, action, cde_type, key, complete_status):
            x_items.removeChild(x_item)
            was_updated = True
            continue

    if was_updated and not len(x_items.childNodes):
        raise ExceptionResponse(data=_DUMMY_BODY)

    return was_updated
Пример #11
0
def _process_xml(doc, device):
	x_response = qxml.get_child(doc, 'response')
	x_add_update_list = qxml.get_child(x_response, 'add_update_list')
	x_removal_list = qxml.get_child(x_response, 'removal_list')
	if not x_add_update_list or not x_removal_list:
		return False

	sync_type = x_response.getAttribute('syncType')
	logging.info("sync (%s) for device %s", sync_type, device)

	# a full sync is always done just after the proxy started
	# also, a full sync is usually done when the device just restarted
	last_sync = 0 if sync_type == 'full' else device.last_sync

	calibre_books = calibre.books(True) # since we're doing a sync, reload the library

	was_updated = False
	for book in calibre_books.values():
		if not book.file_path:
			continue
		if book.cde_content_type == 'PDOC' and not device.supports_pdoc():
			# desktop clients do not handle PDOCs
			continue
		if book.last_modified > last_sync or not book.is_known_to(device) or book.needs_update_on(device):
			if last_sync != 0:
				logging.warn("book %s newer in library than on %s", book, device)
			book.mark_known_to(device)
			x_add_update_list.appendChild(_book_node(doc, book))
			was_updated = True

	for asin, last_downloaded in list(device.books.items()):
		book = calibre_books.get(asin)
		if not book or not book.file_path:
			logging.warn("%s has book %s, but it's not in the library", device, asin)
			calibre.missing_from_library(asin, device)
			x_removal_list.appendChild(_slim_book_node(doc, asin, 'EBOK')) # may have been PDOC, who knows? let's see how this works
			was_updated = True

	# we could parse the response's sync_time value, but the difference should be under a few seconds in the worst case scenario
	return was_updated