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
8 changes: 3 additions & 5 deletions library/src/main/cpp/pro_proof_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ static std::array<unsigned char, N> from_hex(std::span<char> 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;
jmethodID get_signature;

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"))
Expand All @@ -42,7 +40,6 @@ session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) {
jni_utils::JavaLocalRef<jstring> signature(env, (jstring) env->CallObjectMethod(proof, methods.get_signature));

return {
.version = static_cast<std::uint8_t>(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(
Expand All @@ -52,14 +49,15 @@ session::ProProof java_to_cpp_proof(JNIEnv *env, jobject proof) {
}

JavaLocalRef<jobject> 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<jint>(proof.version),
util::bytes_from_span(env, proof.revocation_tag).get(),
util::bytes_from_span(env, proof.rotating_pubkey).get(),
static_cast<jlong>(proof.expiry_at.time_since_epoch().count()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand All @@ -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,
Expand Down Expand Up @@ -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
}
}
2 changes: 1 addition & 1 deletion libsession-util
Loading