def get_new_doc(enc_json): doc = ServerDocument(doc_id=str(uuid.uuid4())) doc.content = { 'incoming': True, ENC_SCHEME_KEY: EncryptionSchemes.PUBKEY, ENC_JSON_KEY: enc_json } return doc
def _put_legacy(self, doc_id, scheme, db, request): try: doc = ServerDocument(doc_id) content = request.content.read() doc.content = self.formatter.format(content, scheme) db.put_doc(doc) self._finish(request) except Exception as e: self._error(e, request)
def __parse_doc_from_couch(self, result, doc_id, check_for_conflicts=False, decode=True): # restrict to u1db documents if 'u1db_rev' not in result: return None doc = ServerDocument(doc_id, result['u1db_rev']) # set contents or make tombstone if '_attachments' not in result \ or 'u1db_content' not in result['_attachments']: doc.make_tombstone() elif decode: doc.content = json.loads( binascii.a2b_base64( result['_attachments']['u1db_content']['data'])) else: doc._json = result['_attachments']['u1db_content']['data'] # determine if there are conflicts if check_for_conflicts \ and '_attachments' in result \ and 'u1db_conflicts' in result['_attachments']: if decode: conflicts = binascii.a2b_base64( result['_attachments']['u1db_conflicts']['data']) else: conflicts = result['_attachments']['u1db_conflicts']['data'] conflicts = json.loads(conflicts) doc.set_conflicts(self._build_conflicts(doc.doc_id, conflicts)) # store couch revision doc.couch_rev = result['_rev'] return doc
def __parse_doc_from_couch(self, result, doc_id, check_for_conflicts=False): # restrict to u1db documents if 'u1db_rev' not in result: return None doc = ServerDocument(doc_id, result['u1db_rev']) # set contents or make tombstone if '_attachments' not in result \ or 'u1db_content' not in result['_attachments']: doc.make_tombstone() else: doc.content = json.loads( result['_attachments']['u1db_content']) # determine if there are conflicts if check_for_conflicts \ and '_attachments' in result \ and 'u1db_conflicts' in result['_attachments']: doc.set_conflicts( self._build_conflicts( doc.doc_id, result['_attachments']['u1db_conflicts'])) # store couch revision doc.couch_rev = result['_rev'] # store transactions doc.transactions = result['u1db_transactions'] return doc
def _encrypt_message(self, pubkey, message): """ Given a public key and a message, it encrypts the message to that public key. :param pubkey: public key for the owner of the message :type pubkey: str :param message: message contents :type message: str :return: doc to sync with Soledad or None, None if something went wrong. :rtype: ServerDocument """ if pubkey is None or len(pubkey) == 0: log.msg("_encrypt_message: Something went wrong, here's all " "I know: %r" % (pubkey,)) raise Exception('Not valid key') doc = ServerDocument(doc_id=str(pyuuid.uuid4())) # store plain text if pubkey is not available data = {'incoming': True, 'content': message} json_dump = json.dumps(data, ensure_ascii=False) try: key, _ = PGPKey.from_blob(pubkey) if key.expires_at and key.expires_at < datetime.now(): log.msg("_encrypt_message: the key is expired (%s)" % str(key.expires_at)) message = PGPMessage.new(json_dump) encryption_result = key.encrypt(message) except (ValueError, PGPEncryptionError) as e: log.msg("_encrypt_message: Encryption failed with status: %s" % (e,)) doc.content = { self.INCOMING_KEY: True, self.ERROR_DECRYPTING_KEY: False, ENC_SCHEME_KEY: EncryptionSchemes.NONE, ENC_JSON_KEY: json_dump } return doc doc.content = { self.INCOMING_KEY: True, self.ERROR_DECRYPTING_KEY: False, ENC_SCHEME_KEY: EncryptionSchemes.PUBKEY, ENC_JSON_KEY: str(encryption_result) } return doc
def post_put( self, id, rev, content, gen, trans_id, number_of_docs, doc_idx): """ Put one incoming document into the server replica. :param id: The id of the incoming document. :type id: str :param rev: The revision of the incoming document. :type rev: str :param content: The content of the incoming document. :type content: dict :param gen: The source replica generation corresponding to the revision of the incoming document. :type gen: int :param trans_id: The source replica transaction id corresponding to the revision of the incoming document. :type trans_id: str :param number_of_docs: The total amount of documents sent on this sync session. :type number_of_docs: int :param doc_idx: The index of the current document. :type doc_idx: int """ doc = ServerDocument(id, rev, json=content) self._staging_size += len(content or '') self._staging.append((doc, gen, trans_id, number_of_docs, doc_idx)) if self._staging_size > ENTRY_CACHE_SIZE or doc_idx == number_of_docs: self.sync_exch.batched_insert_from_source(self._staging, self._sync_id) self._staging = [] self._staging_size = 0
def _build_conflicts(self, doc_id, attached_conflicts): """ Build the conflicted documents list from the conflicts attachment fetched from a couch document. :param attached_conflicts: The document's conflicts as fetched from a couch document attachment. :type attached_conflicts: dict """ conflicts = [] for doc_rev, content in attached_conflicts: doc = ServerDocument(doc_id, doc_rev) if content is None: doc.make_tombstone() else: doc.content = content conflicts.append(doc) return conflicts
def render_PUT(self, request): uuid, doc_id = request.postpath scheme = EncryptionSchemes.PUBKEY db = self.factory.open_database(uuid) if uses_legacy(db): doc = ServerDocument(doc_id) doc.content = self.formatter.format(request.content.read(), scheme) db.put_doc(doc) self._finish(request) else: raw_content = request.content.read() preamble = self.formatter.preamble(raw_content, doc_id) request.content = BytesIO(preamble + ' ' + raw_content) d = db.write_blob(uuid, doc_id, request, namespace='MX') # FIXME: We really need to decouple request handling from the # backend! This is very ugly, but will change when this refactor # is done. flagsReq = DummyRequest(['']) flagsReq.content = BytesIO(json.dumps([Flags.PENDING])) d.addCallback(lambda _: db.set_flags(uuid, doc_id, flagsReq, 'MX')) d.addCallback(lambda _: self._finish(request)) return NOT_DONE_YET
def make_document_for_test(test, doc_id, rev, content, has_conflicts=False): return ServerDocument(doc_id, rev, content, has_conflicts=has_conflicts)