diff --git a/itests/tests/util.py b/itests/tests/util.py index dd2fd7a5..b899fef2 100644 --- a/itests/tests/util.py +++ b/itests/tests/util.py @@ -30,8 +30,8 @@ from contextlib import contextmanager from squeak.core.elliptic import scalar_difference from squeak.core.elliptic import scalar_from_bytes from squeak.core.elliptic import scalar_to_bytes -from squeak.core.signing import SqueakPrivateKey -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey from proto import lnd_pb2 from proto import squeak_admin_pb2 diff --git a/requirements-itest.txt b/requirements-itest.txt index ddce1449..64baa555 100644 --- a/requirements-itest.txt +++ b/requirements-itest.txt @@ -3,4 +3,4 @@ grpcio==1.39.0 grpcio-tools==1.39.0 importlib_resources==1.4.0 pytest==6.2.5 -squeaklib==0.9.1 +squeaklib==0.10.2 diff --git a/requirements.txt b/requirements.txt index 480d04c9..58dd95dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,5 +14,5 @@ python-bitcoinlib==0.11.0 pyzmq==22.3.0 requests==2.26.0 SQLAlchemy==1.4.25 -squeaklib==0.9.1 +squeaklib==0.10.2 typed-config==0.2.5 diff --git a/squeaknode/admin/messages.py b/squeaknode/admin/messages.py index e5710301..ed23e281 100644 --- a/squeaknode/admin/messages.py +++ b/squeaknode/admin/messages.py @@ -22,7 +22,7 @@ import logging from typing import Optional -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPublicKey from proto import squeak_admin_pb2 from squeaknode.admin.profile_image_util import bytes_to_base64_string @@ -218,6 +218,7 @@ def message_to_squeak_entry(msg: squeak_admin_pb2.SqueakDisplayEntry) -> SqueakE public_key=SqueakPublicKey.from_bytes( bytes.fromhex(msg.author_pubkey), ), + recipient_public_key=None, # TODO: maybe implement this. block_height=msg.block_height, block_hash=bytes.fromhex(msg.block_hash), block_time=msg.block_time, @@ -226,6 +227,7 @@ def message_to_squeak_entry(msg: squeak_admin_pb2.SqueakDisplayEntry) -> SqueakE is_unlocked=msg.is_unlocked, secret_key=secret_key, squeak_profile=None, # TODO: message to squeak profile + recipient_squeak_profile=None, # TODO: message to squeak profile liked_time_ms=like_time_ms, content=content_str, ) diff --git a/squeaknode/admin/squeak_admin_server_handler.py b/squeaknode/admin/squeak_admin_server_handler.py index 7843f027..d33d1aea 100644 --- a/squeaknode/admin/squeak_admin_server_handler.py +++ b/squeaknode/admin/squeak_admin_server_handler.py @@ -21,8 +21,8 @@ # SOFTWARE. import logging -from squeak.core.signing import SqueakPrivateKey -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey from proto import squeak_admin_pb2 from squeaknode.admin.messages import connected_peer_to_message diff --git a/squeaknode/core/profiles.py b/squeaknode/core/profiles.py index e3d33c57..310347d0 100644 --- a/squeaknode/core/profiles.py +++ b/squeaknode/core/profiles.py @@ -21,8 +21,8 @@ # SOFTWARE. from typing import Optional -from squeak.core.signing import SqueakPrivateKey -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey from squeaknode.core.squeak_profile import SqueakProfile diff --git a/squeaknode/core/squeak_entry.py b/squeaknode/core/squeak_entry.py index 43505d1b..e37421e9 100644 --- a/squeaknode/core/squeak_entry.py +++ b/squeaknode/core/squeak_entry.py @@ -22,7 +22,7 @@ from typing import NamedTuple from typing import Optional -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPublicKey from squeaknode.core.squeak_profile import SqueakProfile @@ -31,6 +31,7 @@ class SqueakEntry(NamedTuple): squeak_hash: bytes serialized_squeak: bytes public_key: SqueakPublicKey + recipient_public_key: Optional[SqueakPublicKey] block_height: int block_hash: bytes block_time: int @@ -39,5 +40,6 @@ class SqueakEntry(NamedTuple): is_unlocked: bool secret_key: Optional[bytes] squeak_profile: Optional[SqueakProfile] + recipient_squeak_profile: Optional[SqueakProfile] liked_time_ms: Optional[int] = None content: Optional[str] = None diff --git a/squeaknode/core/squeak_profile.py b/squeaknode/core/squeak_profile.py index be77642e..257c0cd9 100644 --- a/squeaknode/core/squeak_profile.py +++ b/squeaknode/core/squeak_profile.py @@ -22,8 +22,8 @@ from typing import NamedTuple from typing import Optional -from squeak.core.signing import SqueakPrivateKey -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey class SqueakProfile(NamedTuple): diff --git a/squeaknode/core/squeaks.py b/squeaknode/core/squeaks.py index 49253742..9767a3f1 100644 --- a/squeaknode/core/squeaks.py +++ b/squeaknode/core/squeaks.py @@ -27,7 +27,8 @@ from squeak.core import CheckSqueak from squeak.core import CSqueak from squeak.core import MakeSqueakFromStr from squeak.core.elliptic import payment_point_bytes_from_scalar_bytes -from squeak.core.signing import SqueakPrivateKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey DATA_KEY_LENGTH = 32 @@ -58,6 +59,7 @@ def make_squeak_with_block( block_height: int, block_hash: bytes, replyto_hash: Optional[bytes] = None, + recipient_public_key: Optional[SqueakPublicKey] = None, ) -> Tuple[CSqueak, bytes]: """Create a new squeak. @@ -79,7 +81,8 @@ def make_squeak_with_block( block_height, block_hash, timestamp, - replyto_hash, + reply_to=replyto_hash, + recipient=recipient_public_key, ) diff --git a/squeaknode/db/alembic.ini b/squeaknode/db/alembic.ini index 172c899e..f38d2ce3 100644 --- a/squeaknode/db/alembic.ini +++ b/squeaknode/db/alembic.ini @@ -37,7 +37,7 @@ version_locations = %(here)s/alembic/versions # are written from script.py.mako # output_encoding = utf-8 -sqlalchemy.url = sqlite://///home/yzernik/.sqk/data/testnet/data-v2.db +sqlalchemy.url = sqlite://///home/yzernik/.sqk/data/testnet/data-v3.db [post_write_hooks] diff --git a/squeaknode/db/alembic/versions/c0760e8ce4ba_add_recipient_public_key_column_to_.py b/squeaknode/db/alembic/versions/c0760e8ce4ba_add_recipient_public_key_column_to_.py new file mode 100644 index 00000000..a77c43a1 --- /dev/null +++ b/squeaknode/db/alembic/versions/c0760e8ce4ba_add_recipient_public_key_column_to_.py @@ -0,0 +1,51 @@ +# MIT License +# +# Copyright (c) 2020 Jonathan Zernik +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +"""Add recipient public key column to squeaks table. + +Revision ID: c0760e8ce4ba +Revises: b78f8169d063 +Create Date: 2021-12-26 14:13:00.159229 + +""" +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision = 'c0760e8ce4ba' +down_revision = 'b78f8169d063' +branch_labels = None +depends_on = None + + +def upgrade(): + with op.batch_alter_table('squeak', schema=None) as batch_op: + batch_op.add_column(sa.Column('recipient_public_key', + sa.LargeBinary(length=33), nullable=True)) + batch_op.create_index(batch_op.f('ix_squeak_recipient_public_key'), [ + 'recipient_public_key'], unique=False) + + +def downgrade(): + with op.batch_alter_table('squeak', schema=None) as batch_op: + batch_op.drop_index(batch_op.f('ix_squeak_recipient_public_key')) + batch_op.drop_column('recipient_public_key') diff --git a/squeaknode/db/db_engine.py b/squeaknode/db/db_engine.py index e83261dc..40e7ee29 100644 --- a/squeaknode/db/db_engine.py +++ b/squeaknode/db/db_engine.py @@ -24,6 +24,9 @@ from pathlib import Path from sqlalchemy import create_engine +DB_FILE = "data-v3.db" + + def get_engine(connection_string): return create_engine(connection_string) @@ -31,8 +34,9 @@ def get_engine(connection_string): def get_sqlite_connection_string(sqk_dir, network): data_dir = Path(sqk_dir).joinpath("data").joinpath(network) data_dir.mkdir(parents=True, exist_ok=True) - return "sqlite:////{}/data-v2.db".format( + return "sqlite:////{}/{}".format( data_dir, + DB_FILE, ) diff --git a/squeaknode/db/models.py b/squeaknode/db/models.py index 5fb9497d..4aa3fdd8 100644 --- a/squeaknode/db/models.py +++ b/squeaknode/db/models.py @@ -76,6 +76,8 @@ class Models: Column("time_s", Integer, nullable=False), Column("author_public_key", LargeBinary( 33), index=True, nullable=False), + Column("recipient_public_key", LargeBinary( + 33), index=True, nullable=True), Column("secret_key", LargeBinary(32), nullable=True), Column("block_time_s", Integer, nullable=False), Column("liked_time_ms", SLBigInteger, default=None, nullable=True), diff --git a/squeaknode/db/squeak_db.py b/squeaknode/db/squeak_db.py index f7a46fc6..40203f53 100644 --- a/squeaknode/db/squeak_db.py +++ b/squeaknode/db/squeak_db.py @@ -35,8 +35,8 @@ from sqlalchemy import or_ from sqlalchemy.sql import select from sqlalchemy.sql import tuple_ from squeak.core import CSqueak -from squeak.core.signing import SqueakPrivateKey -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey from squeaknode.core.lightning_address import LightningAddressHostPort from squeaknode.core.peer_address import Network @@ -84,6 +84,10 @@ class SqueakDb: logger.debug("SqlAlchemy version: {}".format(sqlalchemy.__version__)) run_migrations(self.engine) + # Create aliases for profiles + self.author_profiles = self.profiles.alias() + self.recipient_profiles = self.profiles.alias() + def init_with_retries( self, num_retries=INIT_NUM_RETRIES, @@ -153,13 +157,11 @@ class SqueakDb: return self.timestamp_now_ms > \ self.squeaks.c.created_time_ms + interval_s * 1000 - @property - def profile_has_private_key(self): - return self.profiles.c.private_key != None # noqa: E711 + def profile_has_private_key(self, profiles_table): + return profiles_table.c.private_key != None # noqa: E711 - @property - def profile_is_following(self): - return self.profiles.c.following == True # noqa: E711 + def profile_is_following(self, profiles_table): + return profiles_table.c.following == True # noqa: E711 @property def timestamp_now_ms(self): @@ -214,11 +216,16 @@ class SqueakDb: created_time_ms=self.timestamp_now_ms, hash=get_hash(squeak), squeak=squeak.serialize(), - reply_hash=squeak.hashReplySqk if squeak.is_reply else None, + reply_hash=(squeak.hashReplySqk + if squeak.is_reply + else None), block_hash=squeak.hashBlock, block_height=squeak.nBlockHeight, time_s=squeak.nTime, author_public_key=squeak.GetPubKey().to_bytes(), + recipient_public_key=(squeak.GetRecipientPubKey().to_bytes() + if squeak.is_private_message + else None), secret_key=None, block_time_s=block_header.nTime, ) @@ -255,12 +262,20 @@ class SqueakDb: def get_squeak_entry(self, squeak_hash: bytes) -> Optional[SqueakEntry]: """ Get a squeak with the author profile. """ + # author_profiles = self.profiles.alias() + # recipient_profiles = self.profiles.alias() + s = ( - select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( - self.squeaks.outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + self.squeaks + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) .where(self.squeaks.c.hash == squeak_hash) @@ -270,7 +285,11 @@ class SqueakDb: row = result.fetchone() if row is None: return None - return self._parse_squeak_entry(row) + return self._parse_squeak_entry( + row, + # author_profiles_table=author_profiles, + # recipient_profiles_table=recipient_profiles, + ) def get_timeline_squeak_entries( self, @@ -293,14 +312,24 @@ class SqueakDb: last_squeak_hash.hex(), )) s = ( - select([self.squeaks, self.profiles]) + # select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( - self.squeaks.outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + # self.squeaks.outerjoin( + # self.profiles, + # self.profiles.c.public_key == self.squeaks.c.author_public_key, + # ) + self.squeaks + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) - .where(self.profile_is_following) + .where(self.profile_is_following(self.author_profiles)) .where( tuple_( self.squeaks.c.block_height, @@ -342,11 +371,21 @@ class SqueakDb: last_squeak_hash.hex(), )) s = ( - select([self.squeaks, self.profiles]) + # select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( - self.squeaks.outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + # self.squeaks.outerjoin( + # self.profiles, + # self.profiles.c.public_key == self.squeaks.c.author_public_key, + # ) + self.squeaks + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) .where( @@ -396,11 +435,21 @@ class SqueakDb: last_squeak_hash.hex(), )) s = ( - select([self.squeaks, self.profiles]) + # select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( - self.squeaks.outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + # self.squeaks.outerjoin( + # self.profiles, + # self.profiles.c.public_key == self.squeaks.c.author_public_key, + # ) + self.squeaks + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) .where(self.squeaks.c.author_public_key == public_key.to_bytes()) @@ -451,11 +500,21 @@ class SqueakDb: last_squeak_hash.hex(), )) s = ( - select([self.squeaks, self.profiles]) + # select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( - self.squeaks.outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + # self.squeaks.outerjoin( + # self.profiles, + # self.profiles.c.public_key == self.squeaks.c.author_public_key, + # ) + self.squeaks + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) .where(self.squeaks.c.content.ilike(f'%{search_text}%')) @@ -508,14 +567,23 @@ class SqueakDb: ) s = ( - select([self.squeaks, self.profiles]) + # select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( self.squeaks.join( ancestors, ancestors.c.hash == self.squeaks.c.hash, - ).outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + # ).outerjoin( + # self.profiles, + # self.profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) .order_by( @@ -570,11 +638,21 @@ class SqueakDb: last_squeak_hash.hex(), )) s = ( - select([self.squeaks, self.profiles]) + # select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( - self.squeaks.outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + # self.squeaks.outerjoin( + # self.profiles, + # self.profiles.c.public_key == self.squeaks.c.author_public_key, + # ) + self.squeaks + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) .where(self.squeaks.c.reply_hash == squeak_hash) @@ -694,15 +772,25 @@ class SqueakDb: criteria for deletion. """ s = ( - select([self.squeaks, self.profiles]) + # select([self.squeaks, self.profiles]) + select([self.squeaks, self.author_profiles, self.recipient_profiles]) .select_from( - self.squeaks.outerjoin( - self.profiles, - self.profiles.c.public_key == self.squeaks.c.author_public_key, + # self.squeaks.outerjoin( + # self.profiles, + # self.profiles.c.public_key == self.squeaks.c.author_public_key, + # ) + self.squeaks + .outerjoin( + self.author_profiles, + self.author_profiles.c.public_key == self.squeaks.c.author_public_key, + ) + .outerjoin( + self.recipient_profiles, + self.recipient_profiles.c.public_key == self.squeaks.c.recipient_public_key, ) ) .where(self.squeak_is_older_than_retention(interval_s)) - .where(not_(self.profile_has_private_key)) + .where(not_(self.profile_has_private_key(self.author_profiles))) .where(not_(self.squeak_is_liked)) ) with self.get_connection() as connection: @@ -737,7 +825,10 @@ class SqueakDb: def get_signing_profiles(self) -> List[SqueakProfile]: """ Get all signing profiles. """ - s = select([self.profiles]).where(self.profile_has_private_key) + s = ( + select([self.profiles]) + .where(self.profile_has_private_key(self.profiles)) + ) with self.get_connection() as connection: result = connection.execute(s) rows = result.fetchall() @@ -746,7 +837,10 @@ class SqueakDb: def get_contact_profiles(self) -> List[SqueakProfile]: """ Get all contact profiles. """ - s = select([self.profiles]).where(not_(self.profile_has_private_key)) + s = ( + select([self.profiles]) + .where(not_(self.profile_has_private_key(self.profiles))) + ) with self.get_connection() as connection: result = connection.execute(s) rows = result.fetchall() @@ -1445,17 +1539,25 @@ class SqueakDb: def _parse_squeak(self, row) -> CSqueak: return CSqueak.deserialize(row["squeak"]) + # def _parse_squeak_entry(self, row, author_profiles_table=None, recipient_profiles_table=None) -> SqueakEntry: def _parse_squeak_entry(self, row) -> SqueakEntry: + public_key_bytes = row["author_public_key"] + recipient_public_key_bytes = row["recipient_public_key"] secret_key_column = row["secret_key"] is_locked = bool(secret_key_column) reply_to = ( row["reply_hash"]) if row["reply_hash"] else None liked_time_ms = row["liked_time_ms"] - profile = self._try_parse_squeak_profile(row) + profile = self._try_parse_squeak_profile( + row, profiles_table=self.author_profiles) + recipient_profile = self._try_parse_squeak_profile( + row, profiles_table=self.recipient_profiles) return SqueakEntry( squeak_hash=(row["hash"]), serialized_squeak=(row["squeak"]), - public_key=SqueakPublicKey.from_bytes(row["author_public_key"]), + public_key=SqueakPublicKey.from_bytes(public_key_bytes), + recipient_public_key=SqueakPublicKey.from_bytes( + recipient_public_key_bytes) if recipient_public_key_bytes else None, block_height=row["block_height"], block_hash=(row["block_hash"]), block_time=row["block_time_s"], @@ -1466,25 +1568,33 @@ class SqueakDb: liked_time_ms=liked_time_ms, content=row["content"], squeak_profile=profile, + recipient_squeak_profile=recipient_profile, ) - def _parse_squeak_profile(self, row) -> SqueakProfile: - private_key_bytes = row["private_key"] + def _parse_squeak_profile(self, row, profiles_table=None) -> SqueakProfile: + profiles_table = profiles_table if ( + profiles_table is not None) else self.profiles + + private_key_bytes = row[profiles_table.c.private_key] private_key = SqueakPrivateKey.from_bytes( private_key_bytes) if private_key_bytes else None return SqueakProfile( - profile_id=row["profile_id"], - profile_name=row["profile_name"], + profile_id=row[profiles_table.c.profile_id], + profile_name=row[profiles_table.c.profile_name], private_key=private_key, - public_key=SqueakPublicKey.from_bytes(row["public_key"]), - following=row["following"], - profile_image=row["profile_image"], + public_key=SqueakPublicKey.from_bytes( + row[profiles_table.c.public_key]), + following=row[profiles_table.c.following], + profile_image=row[profiles_table.c.profile_image], ) - def _try_parse_squeak_profile(self, row) -> Optional[SqueakProfile]: - if row["profile_id"] is None: + def _try_parse_squeak_profile(self, row, profiles_table=None) -> Optional[SqueakProfile]: + profiles_table = profiles_table if ( + profiles_table is not None) else self.profiles + + if row[profiles_table.c.profile_id] is None: return None - return self._parse_squeak_profile(row) + return self._parse_squeak_profile(row, profiles_table=profiles_table) def _parse_squeak_peer(self, row) -> SqueakPeer: return SqueakPeer( diff --git a/squeaknode/node/network_handler.py b/squeaknode/node/network_handler.py index ec0035c7..b4e03378 100644 --- a/squeaknode/node/network_handler.py +++ b/squeaknode/node/network_handler.py @@ -24,7 +24,7 @@ from typing import List from typing import Optional from squeak.core import CSqueak -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPublicKey from squeak.messages import msg_getdata from squeak.messages import MSG_SECRET_KEY from squeak.messages import MSG_SQUEAK diff --git a/squeaknode/node/squeak_controller.py b/squeaknode/node/squeak_controller.py index e634866b..b246452b 100644 --- a/squeaknode/node/squeak_controller.py +++ b/squeaknode/node/squeak_controller.py @@ -27,8 +27,8 @@ from typing import Optional import squeak.params from squeak.core import CSqueak -from squeak.core.signing import SqueakPrivateKey -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey from squeak.messages import msg_getdata from squeak.messages import MsgSerializable from squeak.net import CInterested diff --git a/squeaknode/node/squeak_store.py b/squeaknode/node/squeak_store.py index 16a2ebf5..ab570775 100644 --- a/squeaknode/node/squeak_store.py +++ b/squeaknode/node/squeak_store.py @@ -26,8 +26,8 @@ from typing import List from typing import Optional from squeak.core import CSqueak -from squeak.core.signing import SqueakPrivateKey -from squeak.core.signing import SqueakPublicKey +from squeak.core.keys import SqueakPrivateKey +from squeak.core.keys import SqueakPublicKey from squeak.net import CInterested from squeak.net import CSqueakLocator diff --git a/tests/admin/test_messages.py b/tests/admin/test_messages.py index 18d89162..7f7417aa 100644 --- a/tests/admin/test_messages.py +++ b/tests/admin/test_messages.py @@ -65,7 +65,10 @@ def test_message_to_squeak_entry(squeak_entry_locked, squeak_entry_msg_locked): entry = message_to_squeak_entry(squeak_entry_msg_locked) # TODO: remove this line after implementing "message_to_squeak_profile" - entry_with_null_profile = squeak_entry_locked._replace(squeak_profile=None) + entry_with_null_profile = squeak_entry_locked\ + ._replace(squeak_profile=None)\ + ._replace(recipient_public_key=None)\ + ._replace(recipient_squeak_profile=None) assert entry == entry_with_null_profile diff --git a/tests/conftest.py b/tests/conftest.py index db31bdc3..943d261a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,7 +22,7 @@ import pytest from bitcoin.core import CBlockHeader from squeak.core.elliptic import payment_point_bytes_from_scalar_bytes -from squeak.core.signing import SqueakPrivateKey +from squeak.core.keys import SqueakPrivateKey from squeaknode.bitcoin.block_info import BlockInfo from squeaknode.core.connected_peer import ConnectedPeer @@ -65,6 +65,16 @@ def public_key(private_key): yield private_key.get_public_key() +@pytest.fixture +def recipient_private_key(): + yield SqueakPrivateKey.generate() + + +@pytest.fixture +def recipient_public_key(recipient_private_key): + yield recipient_private_key.get_public_key() + + @pytest.fixture def block_count(): yield 555 @@ -142,6 +152,17 @@ def reply_squeak_and_secret_key(private_key, reply_squeak_content, block_info, s ) +@pytest.fixture +def private_squeak_and_secret_key(private_key, squeak_content, block_info, recipient_public_key): + yield make_squeak_with_block( + private_key, + squeak_content, + block_info.block_height, + block_info.block_hash, + recipient_public_key=recipient_public_key, + ) + + @pytest.fixture def squeak(squeak_and_secret_key): squeak, _ = squeak_and_secret_key @@ -190,6 +211,12 @@ def reply_squeak_hash(reply_squeak): yield get_hash(reply_squeak) +@pytest.fixture +def private_squeak(private_squeak_and_secret_key): + squeak, _ = private_squeak_and_secret_key + yield squeak + + @pytest.fixture def peer_address(): yield PeerAddress( @@ -209,6 +236,11 @@ def contact_profile_name(): yield "fake_contact_profile_name" +@pytest.fixture +def recipient_contact_profile_name(): + yield "recipient_contact_profile_name" + + @pytest.fixture def signing_profile(signing_profile_name, private_key): yield gen_signing_profile( @@ -225,23 +257,34 @@ def contact_profile(contact_profile_name, public_key): ) +@pytest.fixture +def recipient_contact_profile(recipient_contact_profile_name, recipient_public_key): + yield gen_contact_profile( + recipient_contact_profile_name, + recipient_public_key, + ) + + @pytest.fixture def squeak_entry_locked( squeak, squeak_bytes, squeak_hash, public_key, + recipient_public_key, block_count, block_hash, block_time, squeak_time, squeak_reply_to_hash, signing_profile, + recipient_contact_profile, ): yield SqueakEntry( squeak_hash=squeak_hash, serialized_squeak=squeak_bytes, public_key=public_key, + recipient_public_key=recipient_public_key, block_height=block_count, block_hash=block_hash, block_time=block_time, @@ -250,6 +293,7 @@ def squeak_entry_locked( is_unlocked=False, secret_key=None, squeak_profile=signing_profile, + recipient_squeak_profile=recipient_contact_profile, liked_time_ms=None, content=None, ) diff --git a/tests/core/test_squeaks.py b/tests/core/test_squeaks.py index 547f939b..20b134f2 100644 --- a/tests/core/test_squeaks.py +++ b/tests/core/test_squeaks.py @@ -23,6 +23,7 @@ from squeaknode.core.squeaks import check_squeak from squeaknode.core.squeaks import get_decrypted_content from squeaknode.core.squeaks import get_hash from squeaknode.core.squeaks import get_payment_point_of_secret_key +from squeaknode.core.squeaks import make_squeak_with_block def test_get_hash(squeak, squeak_hash): @@ -46,3 +47,14 @@ def test_get_decrypted_content(squeak, secret_key, squeak_content): def test_get_payment_point_of_secret_key(squeak, secret_key): assert get_payment_point_of_secret_key( secret_key) == squeak.paymentPoint + + +def test_make_private_squeak(private_key, squeak_content, block_info): + squeak, _ = make_squeak_with_block( + private_key, + squeak_content, + block_info.block_height, + block_info.block_hash, + ) + + assert squeak.GetRecipientPubKey() is None diff --git a/tests/db/test_squeak_db.py b/tests/db/test_squeak_db.py index abcc0e5c..ef4ba421 100644 --- a/tests/db/test_squeak_db.py +++ b/tests/db/test_squeak_db.py @@ -486,13 +486,52 @@ def test_get_missing_squeak(squeak_db, squeak, squeak_hash): assert retrieved_squeak is None -def test_get_squeak_entry(squeak_db, squeak, block_header, public_key, inserted_squeak_hash): +def test_get_squeak_entry( + squeak_db, + squeak, + block_header, + public_key, + signing_profile, + inserted_squeak_hash, + inserted_signing_profile_id, +): retrieved_squeak_entry = squeak_db.get_squeak_entry(inserted_squeak_hash) assert retrieved_squeak_entry.squeak_hash == inserted_squeak_hash assert retrieved_squeak_entry.public_key == public_key assert retrieved_squeak_entry.content is None assert retrieved_squeak_entry.block_time == block_header.nTime + assert retrieved_squeak_entry.squeak_profile._replace( + profile_id=None) == signing_profile + + +def test_get_private_squeak_entry( + squeak_db, + private_squeak, + recipient_public_key, + block_header, + public_key, + signing_profile, + recipient_contact_profile, + inserted_signing_profile_id, +): + inserted_private_squeak_hash = squeak_db.insert_squeak( + private_squeak, block_header) + squeak_db.insert_profile( + recipient_contact_profile) + + retrieved_squeak_entry = squeak_db.get_squeak_entry( + inserted_private_squeak_hash) + + assert retrieved_squeak_entry.squeak_hash == inserted_private_squeak_hash + assert retrieved_squeak_entry.public_key == public_key + assert retrieved_squeak_entry.content is None + assert retrieved_squeak_entry.block_time == block_header.nTime + assert retrieved_squeak_entry.squeak_profile._replace( + profile_id=None) == signing_profile + assert retrieved_squeak_entry.recipient_public_key == recipient_public_key + assert retrieved_squeak_entry.recipient_squeak_profile._replace( + profile_id=None) == recipient_contact_profile def test_get_missing_squeak_entry(squeak_db, squeak, squeak_hash): diff --git a/tests/utils.py b/tests/utils.py index 5f7fbb3c..80f41db6 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -25,7 +25,7 @@ import random import uuid from bitcoin.core import CBlockHeader -from squeak.core.signing import SqueakPrivateKey +from squeak.core.keys import SqueakPrivateKey from squeaknode.core.peer_address import Network from squeaknode.core.peer_address import PeerAddress @@ -96,10 +96,10 @@ def gen_squeak_with_block_header(private_key, block_height, replyto_hash=None): return squeak, block_info -def gen_signing_profile(profile_name, signing_key): +def gen_signing_profile(profile_name, private_key): return create_signing_profile( profile_name, - signing_key, + private_key, )