001/* 002 * Copyright 2022-2026 Revetware LLC. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.soklet; 018 019import org.jspecify.annotations.NonNull; 020 021import javax.annotation.concurrent.ThreadSafe; 022 023/** 024 * Thread-safe application-supplied alternative to Soklet's built-in 025 * request-state protection. 026 * <p> 027 * The protector owns its algorithm, envelope format, keys, rotation, fleet 028 * compatibility, randomness, and per-key invocation limits. Soklet continues 029 * to own canonical state serialization, size, round, and lifetime checks, plus 030 * context binding. Implementations must authenticate the exact associated data 031 * supplied in the context and may be invoked concurrently. 032 * 033 * @author <a href="https://www.revetkn.com">Mark Allen</a> 034 */ 035@ThreadSafe 036public interface McpRequestStateProtector { 037 /** 038 * Protects canonical framework request-state bytes. 039 * 040 * @param requestStateProtectionContext immutable binding context 041 * @param plaintext call-confined canonical framework bytes; implementations 042 * must not retain or mutate this array 043 * @return opaque string suitable for the MCP wire value 044 * @throws McpRequestStateProtectionException on a sanitized protection 045 * failure 046 */ 047 @NonNull 048 String seal(@NonNull McpRequestStateProtectionContext requestStateProtectionContext, 049 byte @NonNull [] plaintext) 050 throws McpRequestStateProtectionException; 051 052 /** 053 * Opens a framework request-state wire value previously produced by this 054 * protector. 055 * 056 * @param requestStateProtectionContext immutable expected binding context 057 * @param protectedState opaque value received from the client 058 * @return newly allocated canonical framework bytes whose ownership transfers 059 * to Soklet 060 * @throws McpRequestStateProtectionException with 061 * {@link McpRequestStateProtectionException.Reason#INVALID_STATE} for every 062 * malformation, authentication failure, expiry-equivalent failure, or 063 * context mismatch detected by the protector 064 */ 065 byte @NonNull [] open(@NonNull McpRequestStateProtectionContext requestStateProtectionContext, 066 @NonNull String protectedState) 067 throws McpRequestStateProtectionException; 068}