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();
} else if (!_bot
|| _bot->isVerified()
|| _bot->session().local().isBotTrusted(_bot)) {
|| _bot->session().local().isBotTrustedOpenGame(_bot->id)) {
open();
} else {
const auto callback = [=, bot = _bot] {
Ui::hideLayer();
bot->session().local().markBotTrusted(bot);
bot->session().local().markBotTrustedOpenGame(bot->id);
open();
};
Ui::show(Box<ConfirmBox>(

View file

@ -166,6 +166,12 @@ void CheckoutProcess::handleFormUpdate(const FormUpdate &update) {
}, [&](const TmpPasswordRequired &) {
_submitState = SubmitState::Validated;
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) {
auto bottomText = tr::lng_payments_processed_by(
lt_provider,
@ -366,6 +372,11 @@ void CheckoutProcess::panelSubmit() {
}
}
void CheckoutProcess::panelTrustAndSubmit() {
_form->trustBot();
panelSubmit();
}
void CheckoutProcess::panelWebviewMessage(
const QJsonDocument &message,
bool saveInformation) {

View file

@ -87,7 +87,6 @@ private:
void editPaymentMethod();
void requestSetPassword();
void requestSetPasswordSure(QPointer<Ui::GenericBox> old);
void requestPassword();
void getPasswordState(
Fn<void(const Core::CloudPasswordState&)> callback);
@ -97,6 +96,7 @@ private:
void panelRequestClose() override;
void panelCloseSure() override;
void panelSubmit() override;
void panelTrustAndSubmit() override;
void panelWebviewMessage(
const QJsonDocument &message,
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_token.h"
#include "stripe/stripe_card_validator.h"
#include "storage/storage_account.h"
#include "ui/image/image.h"
#include "apiwrap.h"
#include "core/core_cloud_password.h"
@ -478,6 +479,12 @@ void Form::submit() {
if (!_paymentMethod.newCredentials && password.isEmpty()) {
_updates.fire(TmpPasswordRequired{});
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;
@ -773,6 +780,10 @@ void Form::setTips(int64 value) {
_invoice.tipsSelected = std::min(value, _invoice.tipsMax);
}
void Form::trustBot() {
_session->local().markBotTrustedPayment(_details.botId);
}
void Form::processShippingOptions(const QVector<MTPShippingOption> &data) {
const auto currency = _invoice.currency;
_shippingOptions = Ui::ShippingOptions{ currency, ranges::views::all(

View file

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

View file

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

View file

@ -289,7 +289,7 @@ struct SimpleFieldState {
};
const auto state = wrap->lifetime().make_state<State>(State{
.rule = LookupCurrencyRule(config.currency),
.st = st::paymentsField,
.st = st::paymentsMoneyField,
});
const auto &rule = state->rule;
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(
const NativeMethodDetails &native,
CardField field) {

View file

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

View file

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

View file

@ -2509,8 +2509,12 @@ void Account::writeTrustedBots() {
quint32 size = sizeof(qint32) + _trustedBots.size() * sizeof(quint64);
EncryptedDescriptor data(size);
data.stream << qint32(_trustedBots.size());
for_const (auto botId, _trustedBots) {
data.stream << quint64(botId);
for (const auto &[peerId, mask] : _trustedBots) {
// 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);
@ -2531,25 +2535,61 @@ void Account::readTrustedBots() {
qint32 size = 0;
trusted.stream >> size;
for (int i = 0; i < size; ++i) {
quint64 botId = 0;
trusted.stream >> botId;
_trustedBots.insert(botId);
auto value = quint64();
trusted.stream >> value;
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) {
if (!isBotTrusted(bot)) {
_trustedBots.insert(bot->id);
writeTrustedBots();
void Account::markBotTrustedOpenGame(PeerId botId) {
if (isBotTrustedOpenGame(botId)) {
return;
}
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) {
readTrustedBots();
_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(

View file

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