Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #618

Merged
merged 29 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
82bbc25
added cloudflare images field
alimaktabi Aug 25, 2024
2d46d0c
update requirements.txt
alimaktabi Aug 25, 2024
6ce04cf
removed extra prints
alimaktabi Aug 25, 2024
c23e742
refactored string injection method
alimaktabi Aug 25, 2024
7b953cf
removed extra implementation of cloudflare image field to use a custo…
alimaktabi Aug 26, 2024
e26ca71
fixed arguments passing for is_valid
alimaktabi Aug 26, 2024
faacb84
fixed field typos
alimaktabi Aug 26, 2024
db05838
updated requirements
alimaktabi Aug 26, 2024
4a6303c
added migrations for image fields
alimaktabi Aug 26, 2024
5bbbeb6
Merge branch 'develop' into feature/add-cloudflare-image-field
alimaktabi Aug 26, 2024
4137c92
fixed migrations
alimaktabi Aug 26, 2024
30bd275
fixed testing image column name
alimaktabi Aug 27, 2024
3a8cf16
fixed migration issue
alimaktabi Aug 27, 2024
787b147
Add zora constraint
PooyaFekri Aug 28, 2024
ce00e5e
Merge pull request #611 from UnitapApp/feature/add-zora-constraint
PooyaFekri Aug 28, 2024
8335a1e
Add twitter_id filed to TwitterConnection
PooyaFekri Aug 30, 2024
14f3971
Merge pull request #612 from UnitapApp/feature/add-twitter-id-to-twit…
PooyaFekri Aug 30, 2024
41b8f20
Fix test in twitter constraint
PooyaFekri Aug 30, 2024
51a6fb0
Merge pull request #613 from UnitapApp/feature/add-twitter-id-to-twit…
PooyaFekri Aug 30, 2024
9fca870
Fix get_twitter_id
PooyaFekri Aug 30, 2024
56532fb
Merge pull request #614 from UnitapApp/feature/add-twitter-id-to-twit…
PooyaFekri Aug 30, 2024
0da60d8
added hcaptcha setup
alimaktabi Sep 1, 2024
62a4be9
Merge pull request #606 from UnitapApp/feature/add-cloudflare-image-f…
PooyaFekri Sep 3, 2024
49a3bd5
Merge pull request #615 from UnitapApp/feature/hcaptcha-implementation
PooyaFekri Sep 3, 2024
acde1fd
requirements
ShayanShiravani Sep 3, 2024
ed68b4a
bugfix
ShayanShiravani Sep 3, 2024
63505ed
Merge pull request #616 from UnitapApp/feature/unt-771-gitcoin-integr…
ShayanShiravani Sep 3, 2024
b89e323
fixed migrations
alimaktabi Sep 3, 2024
3ef8154
Merge pull request #617 from UnitapApp/fix/migrations-error
PooyaFekri Sep 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions authentication/migrations/0042_twitterconnection_twitter_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 4.0.4 on 2024-08-30 15:47

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('authentication', '0041_alter_brightidconnection_user_profile_and_more'),
]

operations = [
migrations.AddField(
model_name='twitterconnection',
name='twitter_id',
field=models.CharField(max_length=255, null=True, unique=True),
),
]
10 changes: 4 additions & 6 deletions authentication/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,11 @@ class TwitterConnection(BaseThirdPartyConnection):
access_token_secret = models.CharField(
max_length=255, unique=True, blank=True, null=True
)
twitter_id = models.CharField(max_length=255, unique=True, null=True)
driver = TwitterDriver()

def is_connected(self):
return bool(self.access_token and self.access_token_secret)
return bool(self.twitter_id)

@property
def tweet_count(self):
Expand All @@ -279,11 +280,8 @@ def follower_count(self):
def username(self):
return self.driver.get_username(self.access_token, self.access_token_secret)

@property
def twitter_id(self):
return self.driver.get_twitter_id(
self, self.access_token, self.access_token_secret
)
def get_twitter_id(self):
return self.driver.get_twitter_id(self.access_token, self.access_token_secret)

def is_replied(self, self_tweet_id, target_tweet_id):
return self.driver.get_is_replied(
Expand Down
12 changes: 6 additions & 6 deletions authentication/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class Meta:
fields = ["pk", "wallet_type", "address", "signature", "message"]

def is_valid(self, raise_exception=False):
super_is_validated = super().is_valid(raise_exception)
super_is_validated = super().is_valid(raise_exception=raise_exception)

address = self.validated_data.get("address")
message = self.validated_data.get("message")
Expand Down Expand Up @@ -208,8 +208,8 @@ class Meta:
]

def is_valid(self, raise_exception=False):
super_is_validated = super().is_valid(raise_exception)
is_address_valid = self.validate_address(raise_exception)
super_is_validated = super().is_valid(raise_exception=raise_exception)
is_address_valid = self.validate_address(raise_exception=raise_exception)

return is_address_valid and super_is_validated

Expand Down Expand Up @@ -237,7 +237,7 @@ class Meta:
]

def is_valid(self, raise_exception=False):
super_is_validated = super().is_valid(raise_exception)
super_is_validated = super().is_valid(raise_exception=raise_exception)
is_address_valid = self.validate_address(raise_exception)

return is_address_valid and super_is_validated
Expand All @@ -255,7 +255,7 @@ class Meta:
]

def is_valid(self, raise_exception=False):
super_is_validated = super().is_valid(raise_exception)
super_is_validated = super().is_valid(raise_exception=raise_exception)
is_address_valid = self.validate_address(raise_exception)

return is_address_valid and super_is_validated
Expand All @@ -273,7 +273,7 @@ class Meta:
]

def is_valid(self, raise_exception=False):
super_is_validated = super().is_valid(raise_exception)
super_is_validated = super().is_valid(raise_exception=raise_exception)
is_address_valid = self.validate_address(raise_exception)

return is_address_valid and super_is_validated
12 changes: 10 additions & 2 deletions authentication/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -738,7 +738,15 @@ def get(self, request, *args, **kwargs):

twitter_connection.access_token = access_token
twitter_connection.access_token_secret = access_token_secret
twitter_connection.twitter_id = twitter_connection.get_twitter_id()

twitter_connection.save(update_fields=("access_token", "access_token_secret"))

try:
twitter_connection.save(
update_fields=("access_token", "access_token_secret", "twitter_id")
)
except IntegrityError:
raise ValidationError(
"""We can not connect you twitter account,
may be your account is connected before"""
)
return Response({}, HTTP_200_OK)
15 changes: 15 additions & 0 deletions brightIDfaucet/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ def str2bool(v):
MEMCACHED_PASSWORD = os.environ.get("MEMCACHEDCLOUD_PASSWORD")
DEPLOYMENT_ENV = os.environ.get("DEPLOYMENT_ENV")

CLOUDFLARE_IMAGES_ACCOUNT_ID = os.environ.get("CLOUDFLARE_ACCOUNT_ID")
CLOUDFLARE_IMAGES_API_TOKEN = os.environ.get("CLOUDFLARE_API_TOKEN")
CLOUDFLARE_IMAGES_ACCOUNT_HASH = os.environ.get("CLOUDFLARE_ACCOUNT_HASH")

CLOUDFLARE_TURNSTILE_SECRET_KEY = os.environ.get("CLOUDFLARE_TURNSTILE_SECRET_KEY")
H_CAPTCHA_SECRET = os.environ.get("H_CAPTCHA_SECRET")

assert DEPLOYMENT_ENV in ["dev", "main"]

Expand Down Expand Up @@ -163,6 +168,16 @@ def before_send(event, hint):

WSGI_APPLICATION = "brightIDfaucet.wsgi.application"

STORAGES = {
"default": {
"BACKEND": "cloudflare_images.storage.CloudflareImagesStorage",
},
"staticfiles": { # default
"BACKEND": "django.contrib.staticfiles.storage.StaticFilesStorage",
},
}


# Database
DATABASES = {"default": dj_database_url.config(conn_max_age=600)}

Expand Down
3 changes: 2 additions & 1 deletion core/constraints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
BrightIDAuraVerification,
BrightIDMeetVerification,
)
from core.constraints.captcha import HasVerifiedCloudflareCaptcha, HasVerifiedHCaptcha
from core.constraints.EAS import Attest, BeAttestedBy
from core.constraints.ens import HasENSVerification
from core.constraints.farcaster import (
Expand Down Expand Up @@ -63,7 +64,7 @@
IsFollowingTwitterBatch,
IsFollowinTwitterUser,
)
from core.constraints.captcha import HasVerifiedCloudflareCaptcha
from core.constraints.zora import DidMintZoraNFT


def get_constraint(constraint_label: str) -> ConstraintVerification:
Expand Down
4 changes: 3 additions & 1 deletion core/constraints/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class ConstraintApp(Enum):
MUON = "muon"
OPTIMISM = "optimism"
OCTANT = "octant"
ZORA = "zora"

@classmethod
def choices(cls):
Expand Down Expand Up @@ -59,9 +60,10 @@ class ConstraintVerification(ABC):
invalid_cache_until = 60
valid_cache_until = 60 * 60

def __init__(self, user_profile) -> None:
def __init__(self, user_profile, *, obj=None) -> None:
self.user_profile = user_profile
self._param_values = {}
self.obj = obj

def get_info(self, *args, **kwargs):
pass
Expand Down
2 changes: 1 addition & 1 deletion core/constraints/arbitrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def has_bridged(self, from_time=None):
}

res = subgraph.send_post_request(
subgraph.path.get("arb_bridge_mainnet"), query=query, vars=vars
subgraph.paths.get("arb_bridge_mainnet"), query=query, vars=vars
)
match res:
case None:
Expand Down
30 changes: 30 additions & 0 deletions core/constraints/captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import logging

from core.thirdpartyapp.hcaptcha import HCaptchaUtil
from core.utils import RequestContextExtractor


Expand Down Expand Up @@ -35,3 +36,32 @@ def is_observed(self, *args, **kwargs) -> bool:
return request_context.ip is not None and turnstile_token is not None and cloudflare.is_verified(
turnstile_token, request_context.ip
)




class HasVerifiedHCaptcha(ConstraintVerification):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Consider extracting common captcha verification logic

The is_observed method in HasVerifiedHCaptcha is very similar to the one in HasVerifiedCloudflareCaptcha. Consider extracting common functionality to a base class or utility function to reduce code duplication.

class BaseCaptchaVerification(ConstraintVerification):
    _param_keys = []
    app_name = ConstraintApp.GENERAL.value

class HasVerifiedHCaptcha(BaseCaptchaVerification):
    pass

_param_keys = []
app_name = ConstraintApp.GENERAL.value
is_cachable = True
valid_cache_until = 2 * 60
invalid_cache_until = 0

def is_observed(self, *args, **kwargs) -> bool:

context = kwargs.get("context")

if context is None or context.get("request") is None:
return False

hcaptcha = HCaptchaUtil()

request_context: RequestContextExtractor = RequestContextExtractor(
context["request"]
)

turnstile_token = request_context.data.get("cf-turnstile-response")

return request_context.ip is not None and turnstile_token is not None and hcaptcha.is_verified(
turnstile_token, request_context.ip
)
33 changes: 33 additions & 0 deletions core/constraints/zora.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from datetime import datetime

from core.constraints.abstract import (
ConstraintApp,
ConstraintParam,
ConstraintVerification,
)
from core.thirdpartyapp import ZoraUtil


class DidMintZoraNFT(ConstraintVerification):
app_name = ConstraintApp.ZORA.value
_param_keys = [ConstraintParam.ADDRESS]

def __init__(self, user_profile) -> None:
super().__init__(user_profile)

def is_observed(self, *args, **kwargs) -> bool:
zora_util = ZoraUtil()
user_addresses = self.user_addresses
nft_address = self.param_values[ConstraintParam.ADDRESS.name]
for address in user_addresses:
res = zora_util.get_tx(nft_address=nft_address, address=address)
if res is None:
continue
for tx in res.values:
if (
tx.get("method") == "mint"
and datetime.strptime(tx.get("timestamp"), "%Y-%m-%dT%H:%M:%S.%fZ")
> self.obj.start_at
):
return True
return False
30 changes: 30 additions & 0 deletions core/fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
Contains all the fields related classes to support custom features
such as variants in Cloudflare Images
"""

from django.db import models


class BigNumField(models.Field):
empty_strings_allowed = False

def __init__(self, *args, **kwargs):
kwargs["max_length"] = 200 # or some other number
super().__init__(*args, **kwargs)

def db_type(self, connection):
return "numeric"

def get_internal_type(self):
return "BigNumField"

def to_python(self, value):
if isinstance(value, str):
return int(value)

return value
Comment on lines +23 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): We've found these issues:

Suggested change
if isinstance(value, str):
return int(value)
return value
return int(value) if isinstance(value, str) else value


def get_prep_value(self, value):
return str(value)

6 changes: 5 additions & 1 deletion core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
from django.contrib.postgres.fields import ArrayField
from django.db import models
from django.utils.translation import gettext_lazy as _
from core.constraints.captcha import HasVerifiedCloudflareCaptcha
from encrypted_model_fields.fields import EncryptedCharField
from rest_framework.exceptions import ValidationError
from solders.keypair import Keypair
from solders.pubkey import Pubkey

from core.constraints.captcha import HasVerifiedCloudflareCaptcha, HasVerifiedHCaptcha

from .constraints import (
AllowListVerification,
Attest,
Expand All @@ -28,6 +29,7 @@
DidDelegateArbToAddress,
DidDelegateOPToAddress,
DidLikedFarcasterCast,
DidMintZoraNFT,
DidMirrorOnLensPublication,
DidQuoteTweet,
DidRecastFarcasterCast,
Expand Down Expand Up @@ -157,6 +159,8 @@ class Type(models.TextChoices):
IsFollowingTwitterBatch,
IsFollowingFarcasterBatch,
HasVerifiedCloudflareCaptcha,
DidMintZoraNFT,
HasVerifiedHCaptcha
]

name = models.CharField(
Expand Down
1 change: 1 addition & 0 deletions core/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ def setUp(self):
oauth_token_secret=oauth_token_secret,
access_token="test",
access_token_secret="test",
twitter_id="1",
)

self.not_connected_user_profile = UserProfile.objects.create(
Expand Down
1 change: 1 addition & 0 deletions core/thirdpartyapp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
from .lens import LensUtil # noqa: F401
from .subgraph import Subgraph
from .twitter import RapidTwitter, TwitterUtils
from .zora import ZoraUtil
1 change: 1 addition & 0 deletions core/thirdpartyapp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
),
}
SUBGRAPH_BASE_URL = os.getenv("SUBGRAPH_BASE_URL", "https://api.studio.thegraph.com")
ZORA_BASE_URL = os.getenv("ZORA_BASE_URL", "https://explorer.zora.energy")
24 changes: 24 additions & 0 deletions core/thirdpartyapp/hcaptcha.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import logging
from django.conf import settings
import requests


logger = logging.getLogger(__name__)


class HCaptchaUtil:
secret_key = settings.H_CAPTCHA_SECRET
api_url = "https://api.hcaptcha.com"

def is_verified(self, token: str, ip: str) -> bool:
try:
res = requests.post(
f"{self.api_url}/siteverify",
data={"secret": self.secret_key, "response": token, "remoteip": ip},
)

return res.ok and res.json()["success"]
except Exception as e:
logger.info(f"Error occurred during hcaptcha verification {str(e)}")

return False
4 changes: 2 additions & 2 deletions core/thirdpartyapp/subgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

class Subgraph:
requests = RequestHelper(config.SUBGRAPH_BASE_URL)
path = {
paths = {
"unitap_pass": "query/73675/unitap-pass-eth/version/latest",
"arb_bridge_mainnet": "query/21879/unitap-arb-bridge-mainnet/version/latest",
}
Expand Down Expand Up @@ -53,7 +53,7 @@ def get_unitap_pass_holders(
while True:
vars["skip"] = count
res = self.send_post_request(
self.path.get("unitap_pass"), query=query, vars=vars
self.paths.get("unitap_pass"), query=query, vars=vars
)
match res:
case None:
Expand Down
Loading
Loading