All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.signal.libsignal.zkgroup.groupsend.GroupSendEndorsement Maven / Gradle / Ivy

There is a newer version: 0.62.0
Show newest version
//
// Copyright 2024 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//

package org.signal.libsignal.zkgroup.groupsend;

import static org.signal.libsignal.internal.FilterExceptions.filterExceptions;

import java.nio.ByteBuffer;
import java.time.Instant;
import java.util.Collection;
import org.signal.libsignal.internal.Native;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.groups.GroupSecretParams;
import org.signal.libsignal.zkgroup.internal.ByteArray;

/**
 * An endorsement for a user or set of users in a group.
 *
 * 

GroupSendEndorsements provide a form of authorization by demonstrating that the holder of the * endorsement is in a group with a particular user or set of users. They can be {@link #combine * combined} and {@link #byRemoving removed} in a set-like fashion. * *

The endorsement "flow" starts with receiving a {@link GroupSendEndorsementsResponse} from the * group server, which contains endorsements for all members in a group (including the local user). * The response object provides the single expiration for all the endorsements. From there, the * {@code receive} method produces a {@link GroupSendEndorsementsResponse.ReceivedEndorsements}, * which exposes the individual endorsements as well as a combined endorsement for everyone but the * local user. Clients should save these endorsements and the expiration with the group state. * *

When it comes time to send a message to an individual user, clients should check to see if * they have a {@link GroupSendEndorsement.Token} for that user, and generate and cache one using * {@link #toToken} if not. The token should then be converted to a full token using {@link * GroupSendEndorsement.Token#toFullToken}, providing the expiration saved previously. Finally, the * serialized full token can be used as authorization in a request to the chat server. * *

Similarly, when it comes time to send a message to the group, clients should start by {@link * #byRemoving removing} the endorsements of any users they are excluding (say, because they need a * Sender Key Distribution Message first), and then converting the resulting endorsement to a token. * From there, the token can be converted to a full token and serialized as for an individual send. * (Saving the repeated work of converting to a token is left to the clients here; worst case, it's * still cheaper than a usual zkgroup presentation.) */ public final class GroupSendEndorsement extends ByteArray { public GroupSendEndorsement(byte[] contents) throws InvalidInputException { super(contents); filterExceptions( InvalidInputException.class, () -> Native.GroupSendEndorsement_CheckValidContents(contents)); } GroupSendEndorsement(byte[] contents, UncheckedAndUncloned marker) { super(contents, marker); } /** * Combines several endorsements into one. * *

For example, if you have endorsements to send to Meredith and Aruna individually, then you * can combine them to produce an endorsement to send a multi-recipient message to the two of * them. */ public static GroupSendEndorsement combine(Collection endorsements) { ByteBuffer[] buffers = new ByteBuffer[endorsements.size()]; int nextOffset = 0; for (GroupSendEndorsement next : endorsements) { byte[] nextEndorsementRaw = next.getInternalContentsForJNI(); buffers[nextOffset] = ByteBuffer.allocateDirect(nextEndorsementRaw.length); buffers[nextOffset].put(nextEndorsementRaw); ++nextOffset; } byte[] rawCombinedEndorsement = Native.GroupSendEndorsement_Combine(buffers); return filterExceptions(() -> new GroupSendEndorsement(rawCombinedEndorsement)); } /** * Removes an endorsement (individual or combined) from this combined endorsement. * *

If {@code this} is not a combined endorsement, or {@code toRemove} includes * endorsements that were not combined into {@code this}, the result will not generate valid * tokens. */ public GroupSendEndorsement byRemoving(GroupSendEndorsement toRemove) { byte[] rawResult = Native.GroupSendEndorsement_Remove( getInternalContentsForJNI(), toRemove.getInternalContentsForJNI()); return filterExceptions(() -> new GroupSendEndorsement(rawResult)); } /** * A minimal cacheable representation of an endorsement. * *

This contains the minimal information needed to represent this specific endorsement; it must * be converted to a {@link GroupSendFullToken} before sending to the chat server. (It is valid to * do this immediately; it just uses up extra space.) * *

Generated by {@link GroupSendEndorsement#toToken}. */ public static class Token extends ByteArray { public Token(byte[] contents) throws InvalidInputException { super(contents); filterExceptions( InvalidInputException.class, () -> Native.GroupSendToken_CheckValidContents(contents)); } /** * Converts this token to a "full token", which can be sent to the chat server as * authentication. * *

{@code expiration} must be the same expiration that was in the original {@link * GroupSendEndorsementsResponse}, or the resulting token will fail to verify. */ public GroupSendFullToken toFullToken(Instant expiration) { byte[] rawResult = Native.GroupSendToken_ToFullToken( getInternalContentsForJNI(), expiration.getEpochSecond()); return filterExceptions(() -> new GroupSendFullToken(rawResult)); } } /** * Generates a cacheable token used to authenticate sends. * *

The token is no longer associated with the group; it merely identifies the user or set of * users referenced by this endorsement. (Of course, a set of users is a pretty good stand-in for * a group.) * * @see Token */ public Token toToken(GroupSecretParams groupParams) { byte[] rawResult = Native.GroupSendEndorsement_ToToken( getInternalContentsForJNI(), groupParams.getInternalContentsForJNI()); return filterExceptions(() -> new Token(rawResult)); } /** * Generates a token used to authenticate sends, ready to put in an auth header. * *

{@code expiration} must be the same expiration that was in the original {@link * GroupSendEndorsementsResponse}, or the resulting token will fail to verify. * *

Equivalent to {@link #toToken} followed by {@link Token#toFullToken}. */ public GroupSendFullToken toFullToken(GroupSecretParams groupParams, Instant expiration) { return toToken(groupParams).toFullToken(expiration); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy