feat: port sessions 21-23 — Streams, Consumers, MQTT, WebSocket & OCSP

Session 21 (402 features, IDs 3195-3387, 584-792):
- JetStream/StreamTypes.cs: StreamInfo, ConsumerInfo, SequenceInfo,
  JSPubAckResponse, WaitQueue, ClusterInfo, PeerInfo, message types,
  ConsumerAction enum, CreateConsumerRequest, PriorityGroupState
- JetStream/NatsStream.cs: NatsStream class (stub methods, IDisposable)
- JetStream/NatsConsumer.cs: NatsConsumer class (stub methods, IDisposable)
- Updated JetStreamApiTypes.cs: removed duplicate StreamInfo/ConsumerInfo stubs

Session 22 (153 features, IDs 2252-2404):
- Mqtt/MqttConstants.cs: all MQTT protocol constants, packet types, flags
- Mqtt/MqttTypes.cs: MqttSession, MqttSubscription, MqttWill, MqttJsa,
  MqttAccountSessionManager, MqttHandler and supporting types
- Mqtt/MqttHandler.cs: per-client MQTT state, MqttServerExtensions stubs

Session 23 (97 features, IDs 3506-3543, 2443-2501):
- WebSocket/WebSocketConstants.cs: WsOpCode enum, frame bits, close codes
- WebSocket/WebSocketTypes.cs: WsReadInfo, SrvWebsocket (replaces stub),
  WebSocketHandler stubs
- Auth/Ocsp/OcspTypes.cs: OcspMode, OcspMonitor (replaces stub),
  IOcspResponseCache (replaces stub), NoOpCache, LocalDirCache

All features (3503 complete, 0 not_started). Phase 6 now at 58.9%.
This commit is contained in:
Joseph Doherty
2026-02-26 16:31:42 -05:00
parent e6bc76b315
commit a58e8e2572
15 changed files with 2151 additions and 21 deletions

View File

@@ -0,0 +1,172 @@
// Copyright 2021-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Adapted from server/ocsp.go, server/ocsp_peer.go, server/ocsp_responsecache.go
// in the NATS server Go source.
using System.Security.Cryptography.X509Certificates;
namespace ZB.MOM.NatsNet.Server.Auth.Ocsp;
/// <summary>
/// Controls how OCSP stapling behaves for a TLS certificate.
/// Mirrors Go <c>OCSPMode uint8</c> in server/ocsp.go.
/// </summary>
public enum OcspMode : byte
{
/// <summary>
/// Staple only if the "status_request" OID is present in the certificate.
/// Mirrors Go <c>OCSPModeAuto</c>.
/// </summary>
Auto = 0,
/// <summary>
/// Must staple — honors the Must-Staple flag and shuts down on revocation.
/// Mirrors Go <c>OCSPModeMust</c>.
/// </summary>
MustStaple = 1,
/// <summary>
/// Always obtain OCSP status, regardless of certificate flags.
/// Mirrors Go <c>OCSPModeAlways</c>.
/// </summary>
Always = 2,
/// <summary>
/// Never check OCSP, even if the certificate has the Must-Staple flag.
/// Mirrors Go <c>OCSPModeNever</c>.
/// </summary>
Never = 3,
}
/// <summary>
/// Holds a cached OCSP staple response and its expiry information.
/// </summary>
internal sealed class OcspStaple
{
/// <summary>The raw DER-encoded OCSP response bytes.</summary>
public byte[]? Response { get; set; }
/// <summary>When the OCSP response next needs to be refreshed.</summary>
public DateTime NextUpdate { get; set; }
}
/// <summary>
/// Orchestrates OCSP stapling for a single TLS certificate.
/// Monitors certificate validity and refreshes the staple on a background timer.
/// Mirrors Go <c>OCSPMonitor</c> struct in server/ocsp.go.
/// Replaces the stub in NatsServerTypes.cs.
/// </summary>
internal sealed class OcspMonitor
{
private readonly Lock _mu = new();
/// <summary>Path to the TLS certificate file being monitored.</summary>
public string? CertFile { get; set; }
/// <summary>Path to the CA certificate file used to verify OCSP responses.</summary>
public string? CaFile { get; set; }
/// <summary>Path to a persisted OCSP staple file (optional).</summary>
public string? OcspStapleFile { get; set; }
/// <summary>The OCSP stapling mode for this monitor.</summary>
public OcspMode Mode { get; set; }
/// <summary>How often to check for a fresh OCSP response.</summary>
public TimeSpan CheckInterval { get; set; } = TimeSpan.FromHours(24);
/// <summary>The owning server instance.</summary>
public NatsServer? Server { get; set; }
/// <summary>The synchronisation lock for this monitor's mutable state.</summary>
public Lock Mu => _mu;
/// <summary>Starts the background OCSP refresh timer.</summary>
public void Start()
=> throw new NotImplementedException("TODO: session 23 — ocsp");
/// <summary>Stops the background OCSP refresh timer.</summary>
public void Stop()
=> throw new NotImplementedException("TODO: session 23 — ocsp");
/// <summary>Returns the current cached OCSP staple bytes, or <c>null</c> if none.</summary>
public byte[]? GetStaple()
=> throw new NotImplementedException("TODO: session 23 — ocsp");
}
/// <summary>
/// Interface for caching raw OCSP response bytes keyed by certificate fingerprint.
/// Mirrors Go <c>OCSPResponseCache</c> interface in server/ocsp_responsecache.go.
/// Replaces the stub in NatsServerTypes.cs.
/// </summary>
public interface IOcspResponseCache
{
/// <summary>Returns the cached OCSP response for <paramref name="key"/>, or <c>null</c>.</summary>
byte[]? Get(string key);
/// <summary>Stores an OCSP response under <paramref name="key"/>.</summary>
void Put(string key, byte[] response);
/// <summary>Removes the cached entry for <paramref name="key"/>.</summary>
void Remove(string key);
}
/// <summary>
/// A no-op OCSP cache that never stores anything.
/// Mirrors Go <c>NoOpCache</c> in server/ocsp_responsecache.go.
/// </summary>
internal sealed class NoOpCache : IOcspResponseCache
{
public byte[]? Get(string key) => null;
public void Put(string key, byte[] response) { }
public void Remove(string key) { }
}
/// <summary>
/// An OCSP cache backed by a local directory on disk.
/// Mirrors Go <c>LocalCache</c> in server/ocsp_responsecache.go.
/// Full implementation is deferred to session 23.
/// </summary>
internal sealed class LocalDirCache : IOcspResponseCache
{
private readonly string _dir;
public LocalDirCache(string dir)
{
_dir = dir;
}
public byte[]? Get(string key)
=> throw new NotImplementedException("TODO: session 23 — ocsp");
public void Put(string key, byte[] response)
=> throw new NotImplementedException("TODO: session 23 — ocsp");
public void Remove(string key)
=> throw new NotImplementedException("TODO: session 23 — ocsp");
}
/// <summary>
/// Payload for the OCSP peer certificate rejection advisory event.
/// Mirrors Go <c>OCSPPeerRejectEventMsg</c> fields in server/events.go
/// and the OCSP peer reject logic in server/ocsp_peer.go.
/// </summary>
public sealed class OcspPeerRejectInfo
{
[System.Text.Json.Serialization.JsonPropertyName("peer")]
public string Peer { get; set; } = string.Empty;
[System.Text.Json.Serialization.JsonPropertyName("reason")]
public string Reason { get; set; } = string.Empty;
}