diff --git a/library/src/main/cpp/pro_proof_util.cpp b/library/src/main/cpp/pro_proof_util.cpp index 3102ff4..2338eee 100644 --- a/library/src/main/cpp/pro_proof_util.cpp +++ b/library/src/main/cpp/pro_proof_util.cpp @@ -19,7 +19,6 @@ static std::array from_hex(std::span input) { session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { struct ProProofMethods : public JavaClassInfo { - jmethodID get_version; jmethodID get_revocation_tag; jmethodID get_rotating_pub_key; jmethodID get_expiry_seconds; @@ -27,7 +26,6 @@ session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { ProProofMethods(JNIEnv *env, jobject obj) : JavaClassInfo(env, obj) - , get_version(env->GetMethodID(java_class, "getVersion", "()I")) , get_revocation_tag(env->GetMethodID(java_class, "getRevocationTagHex", "()Ljava/lang/String;")) , get_rotating_pub_key(env->GetMethodID(java_class, "getRotatingPubKeyHex", "()Ljava/lang/String;")) , get_expiry_seconds(env->GetMethodID(java_class, "getExpirySeconds", "()J")) @@ -42,7 +40,6 @@ session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { jni_utils::JavaLocalRef signature(env, (jstring) env->CallObjectMethod(proof, methods.get_signature)); return { - .version = static_cast(env->CallIntMethod(proof, methods.get_version)), .revocation_tag = from_hex<32>(jni_utils::JavaStringRef(env, revocation_tag.get()).get()), .rotating_pubkey = from_hex<32>(jni_utils::JavaStringRef(env, rotating_pub_key.get()).get()), .expiry_at = std::chrono::sys_seconds( @@ -52,14 +49,15 @@ session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) { } JavaLocalRef cpp_to_java_proof(JNIEnv *env, const session::ProProof &proof) { + // No leading `I`: ProProof carries no version. The proof's format is fixed by the signing + // domain prefix baked into its signature, not by a field, so there is nothing to marshal. static BasicJavaClassInfo class_info(env, "network/loki/messenger/libsession_util/pro/ProProof", - "(I[B[BJ[B)V"); + "([B[BJ[B)V"); return {env, env->NewObject( class_info.java_class, class_info.constructor, - static_cast(proof.version), util::bytes_from_span(env, proof.revocation_tag).get(), util::bytes_from_span(env, proof.rotating_pubkey).get(), static_cast(proof.expiry_at.time_since_epoch().count()), diff --git a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt index eeba248..88c8c58 100644 --- a/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt +++ b/library/src/main/java/network/loki/messenger/libsession_util/pro/ProProof.kt @@ -10,11 +10,15 @@ typealias ProProofStatus = Int /** * Represents a proof of Pro. This class is marked as @Serializable to represent the JSON structure * received from the Pro Backend. + * + * There is deliberately no `version` field. A proof's format is bound into its signature by the + * 16-byte domain prefix that format selects (`ProProof_v0_____`), so the version was never part of + * the signed bytes and carrying it proved nothing. A future format arrives as its own field rather + * than a version bump, so to a client that does not know it the proof simply does not appear — + * reported as [STATUS_INVALID]. Protobuf tag 1 held the old field and must never be reused. */ @Serializable data class ProProof( - val version: Int, - @SerialName("revocation_tag") val revocationTagHex: String, @@ -29,13 +33,11 @@ data class ProProof( ) { @Keep constructor( - version: Int, revocationTag: ByteArray, rotatingPubKey: ByteArray, expirySeconds: Long, signature: ByteArray ): this( - version = version, revocationTagHex = revocationTag.toHexString(), rotatingPubKeyHex = rotatingPubKey.toHexString(), expirySeconds = expirySeconds, @@ -92,5 +94,12 @@ data class ProProof( const val STATUS_INVALID_USER_SIGNATURE: ProProofStatus = 2 const val STATUS_VALID: ProProofStatus = 3 const val STATUS_EXPIRED: ProProofStatus = 4 + + /** + * Nothing could be evaluated, so the decoded proof is not to be trusted: the message + * carried no proof this client can read — either none was attached, or it is in a format + * this client does not know. Such a message is delivered as non-Pro rather than dropped. + */ + const val STATUS_INVALID: ProProofStatus = 5 } } \ No newline at end of file diff --git a/libsession-util b/libsession-util index 194752f..ce82717 160000 --- a/libsession-util +++ b/libsession-util @@ -1 +1 @@ -Subproject commit 194752f094818f092d9262bf3986f7d68c3d4ced +Subproject commit ce827173f295019021197ce54d5d051323490ecc