diff --git a/library/src/main/cpp/pro_backend.cpp b/library/src/main/cpp/pro_backend.cpp index 38775ab..020197a 100644 --- a/library/src/main/cpp/pro_backend.cpp +++ b/library/src/main/cpp/pro_backend.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "jni_utils.h" #include "util.h" @@ -60,6 +61,28 @@ JavaLocalRef serialize_provider_urls(JNIEnv* env, const pb::ProviderURL jstring_from_optional(env, u.cancel_subscription_url).get())}; } +/// The Pro URL registry as one Kotlin object. Reads `SESSION_PROTOCOL_STRINGS` directly - it is +/// declared `extern const` in the public C header, so no C++ surface had to be added for this. +/// +/// Field order MUST match `ProUrls`'s constructor. The two document urls are the `url_pro_*` ones: +/// the registry also carries generic `url_privacy_policy` / `url_terms_of_service`, which are +/// different pages and do not belong on a Pro object. +JavaLocalRef serialize_pro_urls(JNIEnv* env) { + static BasicJavaClassInfo cls(env, "network/loki/messenger/libsession_util/pro/ProUrls", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + const auto& s = SESSION_PROTOCOL_STRINGS; + return {env, env->NewObject(cls.java_class, cls.constructor, + jstring_from_optional(env, std::string_view(s.url_pro_access_not_found)).get(), + jstring_from_optional(env, std::string_view(s.url_pro_faq)).get(), + jstring_from_optional(env, std::string_view(s.url_pro_page)).get(), + jstring_from_optional(env, std::string_view(s.url_pro_privacy_policy)).get(), + jstring_from_optional(env, std::string_view(s.url_pro_roadmap)).get(), + jstring_from_optional(env, std::string_view(s.url_pro_support)).get(), + jstring_from_optional(env, std::string_view(s.url_pro_terms_of_service)).get(), + jstring_from_optional(env, std::string_view(s.url_pro_upgrade)).get())}; +} + // §1: `plan` is a parsed ProPlanPeriod (count + unit). We hand the app the structured pair — // count as an int, unit as a lowercase name — so nothing downstream has to re-parse a slug (matching // the nodejs glue's {planCount, planUnit}). The unit is preserved exactly, never canonicalized. @@ -249,6 +272,14 @@ Java_network_loki_messenger_libsession_1util_pro_BackendRequests_providerUrls( }); } +extern "C" +JNIEXPORT jobject JNICALL +Java_network_loki_messenger_libsession_1util_pro_BackendRequests_proUrls(JNIEnv* env, jobject) { + return run_catching_cxx_exception_or_throws(env, [=]() -> jobject { + return serialize_pro_urls(env).release(); + }); +} + // --- Backend identity constants (single source of truth in libsession) --- extern "C" diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt index 2d029b1..c856082 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/BackendRequests.kt @@ -40,6 +40,13 @@ object BackendRequests : LibSessionUtilCApi() { external fun providerUrls(providerCode: String): ProviderUrls? + /** + * The Pro URL registry. Identical for every user and owned by libsession, so read this rather than + * copying the values — a client-side copy of a libsession constant is a value that can silently + * drift from the one the other clients use. + */ + external fun proUrls(): ProUrls + /** * The purchasable payment-provider slugs to surface to users (single source of truth in libsession; * excludes non-purchasable providers like `stf`). Order is not significant — the client diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProBackendResponses.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProBackendResponses.kt index 78429d8..7ae3c50 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProBackendResponses.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProBackendResponses.kt @@ -53,6 +53,27 @@ data class ProRequest( val body: String, ) +/** + * The Pro URL registry — the `url_pro_*` fields of libsession's `SESSION_PROTOCOL_STRINGS`. + * + * Not per-provider and not translation data: these are identical for every user, which is why + * libsession owns them. Exposed as one object rather than eight calls, matching [ProviderUrls]. + * + * Note [privacyPolicy] and [termsOfService] are the **Pro** documents (`url_pro_*`), not Session's + * general ones — the registry carries both pairs and they are different pages. + */ +@Keep +data class ProUrls( + val accessNotFound: String, + val faq: String, + val page: String, + val privacyPolicy: String, + val roadmap: String, + val support: String, + val termsOfService: String, + val upgrade: String, +) + /** Per-provider support/management URLs — libsession is the source of truth for these. */ @Keep data class ProviderUrls(