Add stealth invoices (#210)

* Add stealth invoice switch to profile

* Add stealth invoice including only order uuid

* Add explanatory tooltip for stealth invoices and fix code smells
This commit is contained in:
ShatteredBunny 2022-08-12 19:41:06 +02:00 committed by GitHub
parent 6090e21f6a
commit eff58dc91d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 99 additions and 11 deletions

View File

@ -1043,7 +1043,10 @@ class Logics:
order.last_satoshis_time = timezone.now()
bond_satoshis = int(order.last_satoshis * order.bond_size/100)
description = f"RoboSats - Publishing '{str(order)}' - Maker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
if user.profile.wants_stealth:
description = f"This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally. Payment reference: {order.reference}"
else:
description = f"RoboSats - Publishing '{str(order)}' - Maker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
# Gen hold Invoice
try:
@ -1155,11 +1158,14 @@ class Logics:
order.last_satoshis_time = timezone.now()
bond_satoshis = int(order.last_satoshis * order.bond_size/100)
pos_text = "Buying" if cls.is_buyer(order, user) else "Selling"
description = (
f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + Currency.currency_dict[str(order.currency.currency)]}"
+
" - Taker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
)
if user.profile.wants_stealth:
description = f"This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally. Payment reference: {order.reference}"
else:
description = (
f"RoboSats - Taking 'Order {order.id}' {pos_text} BTC for {str(float(order.amount)) + Currency.currency_dict[str(order.currency.currency)]}"
+
" - Taker bond - This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally."
)
# Gen hold Invoice
try:
@ -1247,7 +1253,10 @@ class Logics:
# If there was no taker_bond object yet, generate one
escrow_satoshis = cls.escrow_amount(order, user)[1]["escrow_amount"] # Amount was fixed when taker bond was locked, fee applied here
description = f"RoboSats - Escrow amount for '{str(order)}' - It WILL FREEZE IN YOUR WALLET. It will be released to the buyer once you confirm you received the fiat. It will automatically return if buyer does not confirm the payment."
if user.profile.wants_stealth:
description = f"This payment WILL FREEZE IN YOUR WALLET, check on the website if it was successful. It will automatically return unless you cheat or cancel unilaterally. Payment reference: {order.reference}"
else:
description = f"RoboSats - Escrow amount for '{str(order)}' - It WILL FREEZE IN YOUR WALLET. It will be released to the buyer once you confirm you received the fiat. It will automatically return if buyer does not confirm the payment."
# Gen hold Invoice
try:

View File

@ -297,6 +297,7 @@ class Order(models.Model):
NESINV = 4, "Neither escrow locked or invoice submitted"
# order info
reference = models.UUIDField(default = uuid.uuid4, editable = False)
status = models.PositiveSmallIntegerField(choices=Status.choices,
null=False,
default=Status.WFB)
@ -652,6 +653,10 @@ class Profile(models.Model):
default=None,
blank=True)
# Stealth invoices
wants_stealth = models.BooleanField(default=False,
null=False)
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:

View File

@ -146,4 +146,7 @@ class TickSerializer(serializers.ModelSerializer):
"premium",
"fee",
)
depth = 1
depth = 1
class StealthSerializer(serializers.Serializer):
wantsStealth = serializers.BooleanField()

View File

@ -1,5 +1,5 @@
from django.urls import path
from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView, PriceView, LimitView, HistoricalView, TickView
from .views import MakerView, OrderView, UserView, BookView, InfoView, RewardView, PriceView, LimitView, HistoricalView, TickView, StealthView
urlpatterns = [
path("make/", MakerView.as_view()),
@ -16,4 +16,5 @@ urlpatterns = [
path("reward/", RewardView.as_view()),
path("historical/", HistoricalView.as_view()),
path("ticks/", TickView.as_view()),
path("stealth/", StealthView.as_view()),
]

View File

@ -2,7 +2,7 @@ import os
from re import T
from django.db.models import Sum, Q
from rest_framework import status, viewsets
from rest_framework.generics import CreateAPIView, ListAPIView
from rest_framework.generics import CreateAPIView, ListAPIView, UpdateAPIView
from rest_framework.views import APIView
from rest_framework.response import Response
@ -11,7 +11,7 @@ from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.models import User
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer, ClaimRewardSerializer, PriceSerializer, UserGenSerializer, TickSerializer
from api.serializers import ListOrderSerializer, MakeOrderSerializer, UpdateOrderSerializer, ClaimRewardSerializer, PriceSerializer, UserGenSerializer, TickSerializer, StealthSerializer
from api.models import LNPayment, MarketTick, OnchainPayment, Order, Currency, Profile
from control.models import AccountingDay, BalanceLog
from api.logics import Logics
@ -740,10 +740,13 @@ class UserView(APIView):
user.profile.is_referred = True
user.profile.referred_by = queryset[0]
user.profile.wants_stealth = False
user.profile.save()
context["public_key"] = user.profile.public_key
context["encrypted_private_key"] = user.profile.encrypted_private_key
context["wants_stealth"] = user.profile.wants_stealth
return Response(context, status=status.HTTP_201_CREATED)
# log in user and return pub/priv keys if existing
@ -755,6 +758,7 @@ class UserView(APIView):
context["encrypted_private_key"] = user.profile.encrypted_private_key
context["earned_rewards"] = user.profile.earned_rewards
context["referral_code"] = str(user.profile.referral_code)
context["wants_stealth"] = user.profile.wants_stealth
# return active order or last made order if any
has_no_active_order, _, order = Logics.validate_already_maker_or_taker(request.user)
@ -1026,3 +1030,29 @@ class HistoricalView(ListAPIView):
}
return Response(payload, status.HTTP_200_OK)
class StealthView(UpdateAPIView):
serializer_class = StealthSerializer
def put(self, request):
serializer = self.serializer_class(data=request.data)
if not request.user.is_authenticated:
return Response(
{
"bad_request":
"Woops! It seems you do not have a robot avatar"
},
status.HTTP_400_BAD_REQUEST,
)
if not serializer.is_valid():
return Response(status=status.HTTP_400_BAD_REQUEST)
stealth = serializer.data.get("wantsStealth")
request.user.profile.wants_stealth = stealth
request.user.profile.save()
return Response({"wantsStealth": stealth})

View File

@ -124,6 +124,17 @@ class BottomBar extends Component {
e.preventDefault();
}
handleSetStealthInvoice = (wantsStealth) => {
const requestOptions = {
method: 'PUT',
headers: {'Content-Type':'application/json', 'X-CSRFToken': getCookie('csrftoken')},
body: JSON.stringify({wantsStealth: wantsStealth}),
};
fetch('/api/stealth/', requestOptions)
.then((response) => response.json())
.then((data) => this.props.setAppState({stealthInvoices: data.wantsStealth}));
}
getHost(){
var url = (window.location != window.parent.location) ? this.getHost(document.referrer) : document.location.href;
return url.split('/')[2]
@ -488,6 +499,8 @@ bottomBarPhone =()=>{
badInvoice={this.state.badInvoice}
earnedRewards={this.props.earnedRewards}
setAppState={this.props.setAppState}
stealthInvoices={this.props.stealthInvoices}
handleSetStealthInvoice={this.handleSetStealthInvoice}
/>
<StatsDialog

View File

@ -48,6 +48,8 @@ type Props = {
withdrawn: boolean;
badInvoice: boolean | string;
earnedRewards: number;
stealthInvoices: boolean;
handleSetStealthInvoice: (stealth: boolean) => void;
setAppState: (state: any) => void; // TODO: move to a ContextProvider
}
@ -65,6 +67,8 @@ const ProfileDialog = ({
badInvoice,
earnedRewards,
setAppState,
stealthInvoices,
handleSetStealthInvoice,
}: Props): JSX.Element => {
const { t } = useTranslation();
@ -206,6 +210,24 @@ const ProfileDialog = ({
<Divider/>
<Grid container>
<Tooltip placement="top" enterTouchDelay={0} title={t("stealth_invoice_explaination")}>
<Grid item>
<FormControlLabel
labelPlacement="start"
label={`${t("Use stealth invoices")}`}
control={
<Switch
checked={stealthInvoices}
onChange={() => handleSetStealthInvoice(!stealthInvoices)
}
/>
}
/>
</Grid>
</Tooltip>
</Grid>
<Grid container>
<Grid item>
<FormControlLabel

View File

@ -86,6 +86,7 @@ class UserGenPage extends Component {
bad_request: data.bad_request,
found: data.found,
loadingRobot:false,
stealthInvoices: data.wants_stealth,
})
&
// Add nick and token to App state (token only if not a bad request)
@ -96,6 +97,7 @@ class UserGenPage extends Component {
referralCode: data.referral_code,
earnedRewards: data.earned_rewards,
lastOrderId: data.last_order_id ? data.last_order_id : null,
stealthInvoices: data.wants_stealth,
})
:
(this.props.setAppState({
@ -106,6 +108,7 @@ class UserGenPage extends Component {
lastOrderId: data.last_order_id ? data.last_order_id : null,
referralCode: data.referral_code,
earnedRewards: data.earned_rewards,
stealthInvoices: data.wants_stealth,
})) & writeCookie("robot_token",token)
& writeCookie("pub_key",data.public_key.split('\n').join('\\'))
& writeCookie("enc_priv_key",data.encrypted_private_key.split('\n').join('\\')))

View File

@ -227,6 +227,8 @@
"Join RoboSats' Subreddit":"Join RoboSats' Subreddit",
"RoboSats in Reddit":"RoboSats in Reddit",
"Current onchain payout fee":"Current onchain payout fee",
"Use stealth invoices":"Use stealth invoices",
"stealth_invoice_explaination":"Stealth invoices do not contain details about the trade except a payment reference. Enable this setting if you don't want to disclose details to a custodial lightning wallet.",
"ORDER PAGE - OrderPage.js": "Order details page",
"Order Box":"Order Box",