"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateStreamMessage = void 0;
const oldStreamMessageBinaryUtils_1 = require("../protocol/oldStreamMessageBinaryUtils");
const StreamMessage_1 = require("../protocol/StreamMessage");
const StreamMetadata_1 = require("../StreamMetadata");
const StreamrClientError_1 = require("../StreamrClientError");
const validateStreamMessage = async (msg, streamRegistry, signatureValidator) => {
    await doValidate(msg, streamRegistry, signatureValidator).catch((err) => {
        // all StreamMessageError already have this streamMessage, maybe this is
        // here if e.g. contract call fails? TODO is this really needed as
        // the onError callback in messagePipeline knows which message
        // it is handling?
        if (!err.streamMessage) {
            err.streamMessage = msg;
        }
        throw err;
    });
};
exports.validateStreamMessage = validateStreamMessage;
/**
 * Checks that the given StreamMessage satisfies the requirements of the protocol.
 * This includes checking permissions as well as signature. The method supports all
 * message types defined by the protocol.
 *
 * Resolves the promise if the message is valid, rejects otherwise.
 *
 * @param streamMessage the StreamMessage to validate.
 */
const doValidate = async (streamMessage, streamRegistry, signatureValidator) => {
    await signatureValidator.assertSignatureIsValid(streamMessage);
    switch (streamMessage.messageType) {
        case StreamMessage_1.StreamMessageType.MESSAGE:
            return validateMessage(streamMessage, streamRegistry);
        case StreamMessage_1.StreamMessageType.GROUP_KEY_REQUEST:
            return validateGroupKeyMessage(streamMessage, (0, oldStreamMessageBinaryUtils_1.convertBytesToGroupKeyRequest)(streamMessage.content).recipient, streamMessage.getPublisherId(), streamRegistry);
        case StreamMessage_1.StreamMessageType.GROUP_KEY_RESPONSE:
            return validateGroupKeyMessage(streamMessage, streamMessage.getPublisherId(), (0, oldStreamMessageBinaryUtils_1.convertBytesToGroupKeyResponse)(streamMessage.content).recipient, streamRegistry);
        default:
            throw new StreamrClientError_1.StreamrClientError(`Unknown message type: ${streamMessage.messageType}!`, 'ASSERTION_FAILED', streamMessage);
    }
};
const validateMessage = async (streamMessage, streamRegistry) => {
    const streamId = streamMessage.getStreamId();
    const streamMetadata = await streamRegistry.getStreamMetadata(streamId);
    const partitionCount = (0, StreamMetadata_1.getPartitionCount)(streamMetadata);
    if (streamMessage.getStreamPartition() < 0 || streamMessage.getStreamPartition() >= partitionCount) {
        throw new StreamrClientError_1.StreamrClientError(`Partition ${streamMessage.getStreamPartition()} is out of range (0..${partitionCount - 1})`, 'INVALID_PARTITION', streamMessage);
    }
    const sender = streamMessage.getPublisherId();
    const isPublisher = await streamRegistry.isStreamPublisher(streamId, sender);
    if (!isPublisher) {
        throw new StreamrClientError_1.StreamrClientError(`${sender} is not a publisher on stream ${streamId}`, 'MISSING_PERMISSION', streamMessage);
    }
};
const validateGroupKeyMessage = async (streamMessage, expectedPublisherId, expectedSubscriberId, streamRegistry) => {
    const streamId = streamMessage.getStreamId();
    const isPublisher = await streamRegistry.isStreamPublisher(streamId, expectedPublisherId);
    if (!isPublisher) {
        throw new StreamrClientError_1.StreamrClientError(`${expectedPublisherId} is not a publisher on stream ${streamId}`, 'MISSING_PERMISSION', streamMessage);
    }
    const isSubscriber = await streamRegistry.isStreamSubscriber(streamId, expectedSubscriberId);
    if (!isSubscriber) {
        throw new StreamrClientError_1.StreamrClientError(`${expectedSubscriberId} is not a subscriber on stream ${streamId}`, 'MISSING_PERMISSION', streamMessage);
    }
};
//# sourceMappingURL=validateStreamMessage.js.map