Add a warning once per bot on payment.

This commit is contained in:
John Preston 2021-04-02 16:59:54 +04:00
parent 62684ab9bb
commit e106bd143e
12 changed files with 123 additions and 18 deletions

View file

@ -86,12 +86,12 @@ void BotGameUrlClickHandler::onClick(ClickContext context) const {
open(); open();
} else if (!_bot } else if (!_bot
|| _bot->isVerified() || _bot->isVerified()
|| _bot->session().local().isBotTrusted(_bot)) { || _bot->session().local().isBotTrustedOpenGame(_bot->id)) {
open(); open();
} else { } else {
const auto callback = [=, bot = _bot] { const auto callback = [=, bot = _bot] {
Ui::hideLayer(); Ui::hideLayer();
bot->session().local().markBotTrusted(bot); bot->session().local().markBotTrustedOpenGame(bot->id);
open(); open();
}; };
Ui::show(Box<ConfirmBox>( Ui::show(Box<ConfirmBox>(

View file

@ -166,6 +166,12 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
}, [&](const TmpPasswordRequired &) { }, [&](const TmpPasswordRequired &) {
_submitState = SubmitState::Validated; _submitState = SubmitState::Validated;
requestPassword(); requestPassword();
}, [&](const BotTrustRequired &data) {
_submitState = SubmitState::Validated;
_panel->showWarning(data.bot->name, data.provider->name);
if (const auto box = _enterPasswordBox.data()) {
box->closeBox();
}
}, [&](const VerificationNeeded &data) { }, [&](const VerificationNeeded &data) {
auto bottomText = tr::lng_payments_processed_by( auto bottomText = tr::lng_payments_processed_by(
lt_provider, lt_provider,
@ -366,6 +372,11 @@ void CheckoutProcess::panelSubmit() {
} }
} }
void CheckoutProcess::panelTrustAndSubmit() {
_form->trustBot();
panelSubmit();
}
void CheckoutProcess::panelWebviewMessage( void CheckoutProcess::panelWebviewMessage(
const QJsonDocument &message, const QJsonDocument &message,
bool saveInformation) { bool saveInformation) {

View file

@ -87,7 +87,6 @@ private:
void editPaymentMethod(); void editPaymentMethod();
void requestSetPassword(); void requestSetPassword();
void requestSetPasswordSure(QPointer<Ui::GenericBox> old);
void requestPassword(); void requestPassword();
void getPasswordState( void getPasswordState(
Fn<void(const Core::CloudPasswordState&)> callback); Fn<void(const Core::CloudPasswordState&)> callback);
@ -97,6 +96,7 @@ private:
void panelRequestClose() override; void panelRequestClose() override;
void panelCloseSure() override; void panelCloseSure() override;
void panelSubmit() override; void panelSubmit() override;
void panelTrustAndSubmit() override;
void panelWebviewMessage( void panelWebviewMessage(
const QJsonDocument &message, const QJsonDocument &message,
bool saveInformation) override; bool saveInformation) override;

View file

@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "stripe/stripe_error.h" #include "stripe/stripe_error.h"
#include "stripe/stripe_token.h" #include "stripe/stripe_token.h"
#include "stripe/stripe_card_validator.h" #include "stripe/stripe_card_validator.h"
#include "storage/storage_account.h"
#include "ui/image/image.h" #include "ui/image/image.h"
#include "apiwrap.h" #include "apiwrap.h"
#include "core/core_cloud_password.h" #include "core/core_cloud_password.h"
@ -478,6 +479,12 @@ void Form::submit() {
if (!_paymentMethod.newCredentials && password.isEmpty()) { if (!_paymentMethod.newCredentials && password.isEmpty()) {
_updates.fire(TmpPasswordRequired{}); _updates.fire(TmpPasswordRequired{});
return; return;
} else if (!_session->local().isBotTrustedPayment(_details.botId)) {
_updates.fire(BotTrustRequired{
.bot = _session->data().user(_details.botId),
.provider = _session->data().user(_details.providerId),
});
return;
} }
using Flag = MTPpayments_SendPaymentForm::Flag; using Flag = MTPpayments_SendPaymentForm::Flag;
@ -773,6 +780,10 @@ void Form::setTips(int64 value) {
_invoice.tipsSelected = std::min(value, _invoice.tipsMax); _invoice.tipsSelected = std::min(value, _invoice.tipsMax);
} }
void Form::trustBot() {
_session->local().markBotTrustedPayment(_details.botId);
}
void Form::processShippingOptions(const QVector<MTPShippingOption> &data) { void Form::processShippingOptions(const QVector<MTPShippingOption> &data) {
const auto currency = _invoice.currency; const auto currency = _invoice.currency;
_shippingOptions = Ui::ShippingOptions{ currency, ranges::views::all( _shippingOptions = Ui::ShippingOptions{ currency, ranges::views::all(

View file

@ -118,6 +118,10 @@ struct VerificationNeeded {
QString url; QString url;
}; };
struct TmpPasswordRequired {}; struct TmpPasswordRequired {};
struct BotTrustRequired {
not_null<UserData*> bot;
not_null<UserData*> provider;
};
struct PaymentFinished { struct PaymentFinished {
MTPUpdates updates; MTPUpdates updates;
}; };
@ -148,6 +152,7 @@ struct FormUpdate : std::variant<
PaymentMethodUpdate, PaymentMethodUpdate,
VerificationNeeded, VerificationNeeded,
TmpPasswordRequired, TmpPasswordRequired,
BotTrustRequired,
PaymentFinished, PaymentFinished,
Error> { Error> {
using variant::variant; using variant::variant;
@ -187,6 +192,7 @@ public:
void setHasPassword(bool has); void setHasPassword(bool has);
void setShippingOption(const QString &id); void setShippingOption(const QString &id);
void setTips(int64 value); void setTips(int64 value);
void trustBot();
void submit(); void submit();
void submit(const Core::CloudPasswordResult &result); void submit(const Core::CloudPasswordResult &result);

View file

@ -79,6 +79,10 @@ paymentsIconPhone: icon {{ "payments/payment_phone", menuIconFg }};
paymentsIconShippingMethod: icon {{ "payments/payment_shipping", menuIconFg }}; paymentsIconShippingMethod: icon {{ "payments/payment_shipping", menuIconFg }};
paymentsField: defaultInputField; paymentsField: defaultInputField;
paymentsMoneyField: InputField(paymentsField) {
textMargins: margins(0px, 4px, 0px, 4px);
heightMin: 30px;
}
paymentsFieldAdditional: FlatLabel(defaultFlatLabel) { paymentsFieldAdditional: FlatLabel(defaultFlatLabel) {
style: boxTextStyle; style: boxTextStyle;
} }

View file

@ -289,7 +289,7 @@ struct SimpleFieldState {
}; };
const auto state = wrap->lifetime().make_state<State>(State{ const auto state = wrap->lifetime().make_state<State>(State{
.rule = LookupCurrencyRule(config.currency), .rule = LookupCurrencyRule(config.currency),
.st = st::paymentsField, .st = st::paymentsMoneyField,
}); });
const auto &rule = state->rule; const auto &rule = state->rule;
state->currencySkip = rule.space ? state->st.font->spacew : 0; state->currencySkip = rule.space ? state->st.font->spacew : 0;

View file

@ -409,6 +409,29 @@ void Panel::showCloseConfirm() {
})); }));
} }
void Panel::showWarning(const QString &bot, const QString &provider) {
showBox(Box([=](not_null<GenericBox*> box) {
box->setTitle(tr::lng_payments_warning_title());
box->addRow(object_ptr<FlatLabel>(
box.get(),
tr::lng_payments_warning_body(
lt_bot1,
rpl::single(bot),
lt_provider,
rpl::single(provider),
lt_bot2,
rpl::single(bot),
lt_bot3,
rpl::single(bot)),
st::boxLabel));
box->addButton(tr::lng_continue(), [=] {
_delegate->panelTrustAndSubmit();
box->closeBox();
});
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
}));
}
void Panel::showEditCard( void Panel::showEditCard(
const NativeMethodDetails &native, const NativeMethodDetails &native,
CardField field) { CardField field) {

View file

@ -69,6 +69,7 @@ public:
void choosePaymentMethod(const PaymentMethodDetails &method); void choosePaymentMethod(const PaymentMethodDetails &method);
void askSetPassword(); void askSetPassword();
void showCloseConfirm(); void showCloseConfirm();
void showWarning(const QString &bot, const QString &provider);
bool showWebview( bool showWebview(
const QString &url, const QString &url,

View file

@ -28,6 +28,7 @@ public:
virtual void panelRequestClose() = 0; virtual void panelRequestClose() = 0;
virtual void panelCloseSure() = 0; virtual void panelCloseSure() = 0;
virtual void panelSubmit() = 0; virtual void panelSubmit() = 0;
virtual void panelTrustAndSubmit() = 0;
virtual void panelWebviewMessage( virtual void panelWebviewMessage(
const QJsonDocument &message, const QJsonDocument &message,
bool saveInformation) = 0; bool saveInformation) = 0;

View file

@ -2509,8 +2509,12 @@ void Account::writeTrustedBots() {
quint32 size = sizeof(qint32) + _trustedBots.size() * sizeof(quint64); quint32 size = sizeof(qint32) + _trustedBots.size() * sizeof(quint64);
EncryptedDescriptor data(size); EncryptedDescriptor data(size);
data.stream << qint32(_trustedBots.size()); data.stream << qint32(_trustedBots.size());
for_const (auto botId, _trustedBots) { for (const auto &[peerId, mask] : _trustedBots) {
data.stream << quint64(botId); // value: 8 bit mask, 56 bit bot peer_id.
auto value = quint64(peerId);
Assert((value >> 56) == 0);
value |= (quint64(mask) << 56);
data.stream << value;
} }
FileWriteDescriptor file(_trustedBotsKey, _basePath); FileWriteDescriptor file(_trustedBotsKey, _basePath);
@ -2531,25 +2535,61 @@ void Account::readTrustedBots() {
qint32 size = 0; qint32 size = 0;
trusted.stream >> size; trusted.stream >> size;
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
quint64 botId = 0; auto value = quint64();
trusted.stream >> botId; trusted.stream >> value;
_trustedBots.insert(botId); const auto mask = base::flags<BotTrustFlag>::from_raw(
uchar(value >> 56));
const auto peerId = value & ~(0xFFULL << 56);
_trustedBots.emplace(peerId, mask);
} }
} }
void Account::markBotTrusted(not_null<UserData*> bot) { void Account::markBotTrustedOpenGame(PeerId botId) {
if (!isBotTrusted(bot)) { if (isBotTrustedOpenGame(botId)) {
_trustedBots.insert(bot->id); return;
writeTrustedBots();
} }
const auto i = _trustedBots.find(botId);
if (i == end(_trustedBots)) {
_trustedBots.emplace(botId, BotTrustFlag());
} else {
i->second &= ~BotTrustFlag::NoOpenGame;
}
writeTrustedBots();
} }
bool Account::isBotTrusted(not_null<UserData*> bot) { bool Account::isBotTrustedOpenGame(PeerId botId) {
if (!_trustedBotsRead) { if (!_trustedBotsRead) {
readTrustedBots(); readTrustedBots();
_trustedBotsRead = true; _trustedBotsRead = true;
} }
return _trustedBots.contains(bot->id); const auto i = _trustedBots.find(botId);
return (i != end(_trustedBots))
&& ((i->second & BotTrustFlag::NoOpenGame) == 0);
}
void Account::markBotTrustedPayment(PeerId botId) {
if (isBotTrustedPayment(botId)) {
return;
}
const auto i = _trustedBots.find(botId);
if (i == end(_trustedBots)) {
_trustedBots.emplace(
botId,
BotTrustFlag::NoOpenGame | BotTrustFlag::Payment);
} else {
i->second |= BotTrustFlag::Payment;
}
writeTrustedBots();
}
bool Account::isBotTrustedPayment(PeerId botId) {
if (!_trustedBotsRead) {
readTrustedBots();
_trustedBotsRead = true;
}
const auto i = _trustedBots.find(botId);
return (i != end(_trustedBots))
&& ((i->second & BotTrustFlag::Payment) != 0);
} }
bool Account::encrypt( bool Account::encrypt(

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "base/timer.h" #include "base/timer.h"
#include "base/flags.h"
#include "storage/cache/storage_cache_database.h" #include "storage/cache/storage_cache_database.h"
#include "data/stickers/data_stickers_set.h" #include "data/stickers/data_stickers_set.h"
#include "data/data_drafts.h" #include "data/data_drafts.h"
@ -135,8 +136,10 @@ public:
const QByteArray& serialized, const QByteArray& serialized,
int32 streamVersion); int32 streamVersion);
void markBotTrusted(not_null<UserData*> bot); void markBotTrustedOpenGame(PeerId botId);
[[nodiscard]] bool isBotTrusted(not_null<UserData*> bot); [[nodiscard]] bool isBotTrustedOpenGame(PeerId botId);
void markBotTrustedPayment(PeerId botId);
[[nodiscard]] bool isBotTrustedPayment(PeerId botId);
[[nodiscard]] bool encrypt( [[nodiscard]] bool encrypt(
const void *src, const void *src,
@ -157,6 +160,11 @@ private:
IncorrectPasscode, IncorrectPasscode,
Failed, Failed,
}; };
enum class BotTrustFlag : uchar {
NoOpenGame = (1 << 0),
Payment = (1 << 1),
};
friend inline constexpr bool is_flag_type(BotTrustFlag) { return true; };
[[nodiscard]] base::flat_set<QString> collectGoodNames() const; [[nodiscard]] base::flat_set<QString> collectGoodNames() const;
[[nodiscard]] auto prepareReadSettingsContext() const [[nodiscard]] auto prepareReadSettingsContext() const
@ -253,7 +261,7 @@ private:
qint32 _cacheTotalTimeLimit = 0; qint32 _cacheTotalTimeLimit = 0;
qint32 _cacheBigFileTotalTimeLimit = 0; qint32 _cacheBigFileTotalTimeLimit = 0;
base::flat_set<uint64> _trustedBots; base::flat_map<PeerId, base::flags<BotTrustFlag>> _trustedBots;
bool _trustedBotsRead = false; bool _trustedBotsRead = false;
bool _readingUserSettings = false; bool _readingUserSettings = false;
bool _recentHashtagsAndBotsWereRead = false; bool _recentHashtagsAndBotsWereRead = false;