Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 0 additions & 7 deletions include/session/pro_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,6 @@ typedef struct session_pro_backend_request {
LIBSESSION_EXPORT
void session_pro_backend_request_free(session_pro_backend_request* request);

typedef enum SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT {
SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT_SUCCESS,
SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT_GENERIC_ERROR,
SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT_COUNT,
} SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT;

/// Response outcome (wire `status`, spec §5). CLOSED/exhaustive: the backend will never add a
/// value, so an unrecognized wire status is reported as a protocol error (RESPONSE_STATUS_ERROR +
/// error_code "invalid_response"). Mirrors C++ session::pro_backend::ResponseStatus.
Expand Down Expand Up @@ -223,7 +217,6 @@ typedef struct session_pro_backend_get_pro_status_response {
/// Opaque account Pro status code ("never"/"active"/"expired"); unknown values pass through.
/// NUL-terminated; points into the response's `internal_`.
const char* status;
SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT error_report;
bool auto_renewing;
int64_t expiry_ts;
int64_t grace_period_duration;
Expand Down
5 changes: 0 additions & 5 deletions include/session/pro_backend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,6 @@ struct ProStatusResponse : ResponseBase {
/// has no payments. (The full payment history is a separate query -- parse_payment_details.)
std::optional<ProPaymentItem> latest_payment;

/// Error code that indicates that the Session Pro Backend encountered an error book-keeping
/// Session Pro entitlement for the user. If this value is not `SUCCESS` implementing clients
/// can optionally prompt the user that they should contact support for investigation.
SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT error_report;

/// Flag to indicate if the user will automatically renew their subscription.
bool auto_renewing;

Expand Down
10 changes: 0 additions & 10 deletions src/pro_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,15 +564,6 @@ ProStatusResponse parse_pro_status(std::string_view json) {
// parse.
result.user_status = json_require<std::string>(result_obj, "user_status", errs);

uint32_t error_report = json_require<uint32_t>(result_obj, "error_report", errs);
if (error_report >= SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT_COUNT) {
errs.push_back(fmt::format("Error report value was out-of-bounds: {}", error_report));
set_protocol_error(result, errs.front());
return result;
}
result.error_report =
static_cast<SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT>(error_report);

result.auto_renewing = json_require<bool>(result_obj, "auto_renewing", errs);

int64_t expiry_ts = json_require<int64_t>(result_obj, "expiry_ts", errs);
Expand Down Expand Up @@ -926,7 +917,6 @@ session_pro_backend_get_pro_status_response_parse(const char* json, size_t json_
fill_c_header(result.header, *owned);

result.status = owned->user_status.c_str();
result.error_report = owned->error_report;
result.auto_renewing = owned->auto_renewing;
result.expiry_ts = epoch_seconds(owned->expiry_at);
result.grace_period_duration = owned->grace_period_duration.count();
Expand Down
56 changes: 21 additions & 35 deletions src/session_encrypt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -925,59 +925,45 @@ DecryptGroupMessage decrypt_group_message(

oxenc::bt_dict_consumer dict{to_string_view(plain)};

if (!dict.skip_until(""))
throw std::runtime_error{"group message version tag (\"\") is missing"};
if (auto v = dict.consume_integer<int>(); v != 1)
if (auto v = dict.require<int>(""); v != 1)
throw std::runtime_error{
fmt::format("group message version tag ({}) is not compatible (we support v1)", v)};

if (!dict.skip_until("a"))
throw std::runtime_error{"missing message author pubkey"};
auto ed_pk = to_span(dict.consume_string_view());
if (ed_pk.size() != 32)
throw std::runtime_error{
fmt::format("message author pubkey size ({}) is invalid", ed_pk.size())};

auto x_pk = ed25519::pk_to_x25519(ed_pk.first<32>());
auto ed_pk = dict.require_span<std::byte, 32>("a");
auto x_pk = ed25519::pk_to_x25519(ed_pk);

session_id = "05{:x}"_format(x_pk);

std::span<const std::byte> raw_data;
if (dict.skip_until("d")) {
raw_data = to_span(dict.consume_string_view());
if (raw_data.empty())
throw std::runtime_error{"uncompressed message data (\"d\") cannot be empty"};
}
auto plain_data = dict.maybe<std::span<const std::byte>>("d");
if (plain_data && plain_data->empty())
throw std::runtime_error{"uncompressed message data (d) cannot be empty"};

if (!dict.skip_until("s"))
throw std::runtime_error{"message signature is missing"};
auto ed_sig = to_span(dict.consume_string_view());
if (ed_sig.size() != 64)
throw std::runtime_error{
fmt::format("message signature size ({}) is invalid", ed_sig.size())};
auto ed_sig = dict.require_span<std::byte, 64>("s");

bool compressed = false;
if (dict.skip_until("z")) {
if (!raw_data.empty())
auto comp_data = dict.maybe<std::span<const std::byte>>("z");
if (comp_data) {
if (comp_data->empty())
throw std::runtime_error{"compressed message data (z) cannot be empty"};
if (plain_data)
throw std::runtime_error{
"message signature cannot contain both compressed (z) and uncompressed (d) "
"data"};
raw_data = to_span(dict.consume_string_view());
if (raw_data.empty())
throw std::runtime_error{"compressed message data (\"z\") cannot be empty"};

compressed = true;
} else if (raw_data.empty())
} else if (!plain_data)
throw std::runtime_error{"message must contain compressed (z) or uncompressed (d) data"};

auto raw_data = comp_data ? *comp_data : *plain_data;

// The value we verify is the raw data *followed by* the group Ed25519 pubkey. (See the comment
// in encrypt_message).
std::vector<std::byte> to_verify(raw_data.size() + group_ed25519_pubkey.size());
std::memcpy(to_verify.data(), raw_data.data(), raw_data.size());
std::memcpy(
to_verify.data() + raw_data.size(),
group_ed25519_pubkey.data(),
group_ed25519_pubkey.size());
std::vector<std::byte> to_verify;
to_verify.reserve(raw_data.size() + group_ed25519_pubkey.size());

to_verify.insert(to_verify.end(), raw_data.begin(), raw_data.end());
to_verify.insert(to_verify.end(), group_ed25519_pubkey.begin(), group_ed25519_pubkey.end());

if (!ed25519::verify(ed_sig.first<64>(), ed_pk.first<32>(), to_verify))
throw std::runtime_error{"message signature failed validation"};

Expand Down
4 changes: 2 additions & 2 deletions tests/pro_backend/seed_payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ def cmd_payment(args):
payment_tx=_payment_tx(args.provider, args.payment_id),
plan=plan,
purchased_at=now,
expires_at=base.round_datetime_to_next_day(now)
expiry_at=base.round_datetime_to_next_day(now)
+ datetime.timedelta(days=args.expiry_days),
platform_refund_expires_at=base.EPOCH,
platform_refund_expiry_at=base.EPOCH,
platform_obfuscated_account_id=_obfuscated_id(args.provider, vk),
err=err,
)
Expand Down
3 changes: 0 additions & 3 deletions tests/test_pro_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,6 @@ TEST_CASE("Pro Backend C API", "[pro_backend]") {
j["status"] = "ok";
j["result"] = {
{"user_status", "expired"},
{"error_report", SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT_GENERIC_ERROR},
{"auto_renewing", true},
{"expiry_ts", unix_ts + 2},
{"grace_period_duration", 1000},
Expand All @@ -388,8 +387,6 @@ TEST_CASE("Pro Backend C API", "[pro_backend]") {
REQUIRE(result.header.status == SESSION_PRO_BACKEND_RESPONSE_STATUS_OK);
REQUIRE(result.header.error == nullptr);
REQUIRE(std::string_view(result.status) == "expired");
REQUIRE(result.error_report ==
SESSION_PRO_BACKEND_GET_PRO_STATUS_ERROR_REPORT_GENERIC_ERROR);
REQUIRE(result.auto_renewing == true);
REQUIRE(result.grace_period_duration == 1000);
REQUIRE(result.expiry_ts == unix_ts + 2);
Expand Down