mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-13 12:33:25 +02:00
Update squeaklib to support private messages (#1897)
* Update squeaklib and update import from keys module * Rename signing key variable to private key in test util * Fix calling make squeak function * Update db data file to v3 * Add recipient public key column to squeak table * Got squeak entry db query working with alias for profiles table * Add test for make squeak with recipient * Add test case for get profile from squeak entry query * Got outer join with recipient profile working * Use outer join to get recipient profile for all squeak entry db queries
This commit is contained in:
parent
1a159a5f10
commit
51f412d75f
22 changed files with 357 additions and 85 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue