Skip to content
Open
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
Empty file added nats/contrib/__init__.py
Empty file.
Empty file.
103 changes: 103 additions & 0 deletions nats/contrib/accounts/limits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from dataclasses import dataclass
from typing import Dict, Optional

from nats.contrib.flatten_model import FlatteningModel


@dataclass
class NatsLimits:
data: Optional[int] = None
payload: Optional[int] = None
subs: Optional[int] = None


class AccountLimits(FlatteningModel):
imports: Optional[
int] # `json:"imports,omitempty"` // Max number of imports
exports: Optional[
int] # `json:"exports,omitempty"` // Max number of exports
wildcards: Optional[
bool
] # `json:"wildcards,omitempty"` // Are wildcards allowed in exports
disallow_bearer: Optional[
bool
] # `json:"disallow_bearer,omitempty"` // User JWT can't be bearer token
conn: Optional[
int
] # `json:"conn,omitempty"` // Max number of active connections
leaf: Optional[
int
] # `json:"leaf,omitempty"` // Max number of active leaf node connections

def __init__(
self,
imports: Optional[int] = None,
exports: Optional[int] = None,
wildcards: Optional[bool] = None,
disallow_bearer: Optional[bool] = None,
conn: Optional[int] = None,
leaf: Optional[int] = None,
):
self.imports = imports
self.exports = exports
self.wildcards = wildcards
self.disallow_bearer = disallow_bearer
self.conn = conn
self.leaf = leaf


class JetStreamLimits(FlatteningModel):
mem_storage: Optional[int] = None
disk_storage: Optional[int] = None
streams: Optional[int] = None
consumer: Optional[int] = None
mem_max_stream_bytes: Optional[int] = None
disk_max_stream_bytes: Optional[int] = None
max_bytes_required: Optional[bool] = None
max_ack_pending: Optional[int] = None

def __init__(
self,
mem_storage: Optional[int] = None,
disk_storage: Optional[int] = None,
streams: Optional[int] = None,
consumer: Optional[int] = None,
mem_max_stream_bytes: Optional[int] = None,
disk_max_stream_bytes: Optional[int] = None,
max_bytes_required: Optional[bool] = None,
max_ack_pending: Optional[int] = None,
):
self.mem_storage = mem_storage
self.disk_storage = disk_storage
self.streams = streams
self.consumer = consumer
self.mem_max_stream_bytes = mem_max_stream_bytes
self.disk_max_stream_bytes = disk_max_stream_bytes
self.max_bytes_required = max_bytes_required
self.max_ack_pending = max_ack_pending


JetStreamTieredLimits = Dict[str, JetStreamLimits]


class OperatorLimits(FlatteningModel):
nats_limits: NatsLimits
account_limits: AccountLimits
jetstream_limits: Optional[JetStreamLimits]
tiered_limits: Optional[JetStreamTieredLimits
] # `json:"tiered_limits,omitempty"`

def __init__(
self,
nats_limits: NatsLimits,
account_limits: AccountLimits,
jetstream_limits: Optional[JetStreamLimits] = None,
tiered_limits: Optional[JetStreamTieredLimits] = None,
):
self.nats_limits = nats_limits
self.account_limits = account_limits
self.jetstream_limits = jetstream_limits
self.tiered_limits = tiered_limits

class META:
unflattened_fields = [('tiered_limits', 'tiered_limits')]
104 changes: 104 additions & 0 deletions nats/contrib/accounts/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from dataclasses import dataclass, field, fields
from typing import Dict, List, Optional, Union

from nats.contrib.accounts.limits import OperatorLimits
from nats.contrib.claims.generic import GenericFields
from nats.contrib.exports import Exports
from nats.contrib.flatten_model import FlatteningModel
from nats.contrib.imports import Imports
from nats.contrib.signingkeys import SigningKeys
from nats.contrib.types import Info, Permissions, Types


@dataclass
class WeightedMapping:
subject: str
weight: Optional[
int] = None # uint8 is mapped to int, with Optional for omitempty
cluster: Optional[str] = None


@dataclass
class ExternalAuthorization:
auth_users: Optional[List[str]]
allowed_accounts: Optional[List[str]]
xkey: Optional[str]


@dataclass
class MsgTrace:
# Destination is the subject the server will send message traces to
# if the inbound message contains the "traceparent" header and has
# its sampled field indicating that the trace should be triggered.
dest: Optional[str] # `json:"dest,omitempty"`

# Sampling is used to set the probability sampling, that is, the
# server will get a random number between 1 and 100 and trigger
# the trace if the number is lower than this Sampling value.
# The valid range is [1..100]. If the value is not set Validate()
# will set the value to 100.
sampling: Optional[int] # `json:"sampling,omitempty"`


class Account(FlatteningModel):
imports: Optional[Imports] # `json:"imports,omitempty"`
exports: Optional[Exports] # `json:"exports,omitempty"`
limits: Optional[OperatorLimits] # `json:"limits,omitempty"`
signing_keys: Optional[SigningKeys] # `json:"signing_keys,omitempty"`
revocations: Optional[Dict[str, int]] # `json:"revocations,omitempty"`
default_permissions: Optional[Permissions
] # `json:"default_permissions,omitempty"`
mappings: Optional[Dict[str,
WeightedMapping]] # `json:"mappings,omitempty"`
authorization: Optional[ExternalAuthorization
] # `json:"authorization,omitempty"`
trace: Optional[MsgTrace] # `json:"trace,omitempty"`
cluster_traffic: Optional[str] # `json:"cluster_traffic,omitempty"`

info: Info = field(default_factory=Info)
generic_fields: GenericFields = field(default_factory=GenericFields)

def __init__(
self,
imports: Optional[Imports] = None,
exports: Optional[Exports] = None,
limits: Optional[OperatorLimits] = None,
signing_keys: Optional[SigningKeys] = None,
revocations: Optional[Dict[str, int]] = None,
default_permissions: Optional[Permissions] = None,
mappings: Optional[Dict[str, WeightedMapping]] = None,
authorization: Optional[ExternalAuthorization] = None,
trace: Optional[MsgTrace] = None,
cluster_traffic: Optional[str] = None,
info: Optional[Info] = None,
generic_fields: Optional[GenericFields] = None
):
self.imports = imports
self.exports = exports
self.limits = limits
self.signing_keys = signing_keys
self.revocations = revocations
self.default_permissions = default_permissions
self.mappings = mappings
self.authorization = authorization
self.trace = trace
self.cluster_traffic = cluster_traffic

self.info = info if info else Info()
self.generic_fields = generic_fields if generic_fields else GenericFields(
type=Types.Account, version=2
)

class Meta:
unflatten_fields = [
("imports", "imports"),
("exports", "exports"),
("limits", "limits"),
("signing_keys", "signing_keys"),
("revocations", "revocations"),
("default_permissions", "default_permissions"),
("mappings", "mappings"),
("authorization", "authorization"),
("trace", "trace"),
("cluster_traffic", "cluster_traffic"),
]
Empty file added nats/contrib/claims/__init__.py
Empty file.
20 changes: 20 additions & 0 deletions nats/contrib/claims/generic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import List, Optional

from nats.contrib.flatten_model import FlatteningModel
from nats.contrib.types import Types


class GenericFields(FlatteningModel):
tags: Optional[List[str]]
type: Optional[Types]
version: Optional[int]

def __init__(
self,
tags: Optional[List[str]] = None,
type: Optional[Types] = None,
version: Optional[int] = None,
):
self.tags = tags
self.type = type
self.version = version
60 changes: 60 additions & 0 deletions nats/contrib/claims/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from typing import List, Optional, Union

from nats.contrib.accounts.models import Account
from nats.contrib.flatten_model import FlatteningModel
from nats.contrib.operator.models import Operator
from nats.contrib.types import Types
from nats.contrib.users.models import User


class Claims(FlatteningModel):
# Claims Data
exp: Optional[int] # Expires int64 `json:"exp,omitempty"`
jti: Optional[str] # ID string `json:"jti,omitempty"`
iat: Optional[int] # IssuedAt int64 `json:"iat,omitempty"`
iss: Optional[str] # Issuer string `json:"iss,omitempty"`
name: Optional[str] # Name string `json:"name,omitempty"`
nbf: Optional[int] # NotBefore int64 `json:"nbf,omitempty"`
sub: Optional[str] # Subject string `json:"sub,omitempty"`

# Nats Data
nats: Optional[Union[User, Account, Operator]]
issuer_account: Optional[Union[str, bytes]]

def __init__(
self,
exp: Optional[int] = None,
jti: Optional[str] = None,
iat: Optional[int] = None,
iss: Optional[str] = None,
name: Optional[str] = None,
nbf: Optional[int] = None,
sub: Optional[str] = None,
nats: Optional[Union[User, Account, Operator]] = None,
issuer_account: Optional[Union[str, bytes]] = None,
):
self.exp: Optional[int] = exp
self.jti: Optional[str] = jti
self.iat: Optional[int] = iat
self.iss: Optional[str] = iss
self.name: Optional[str] = name
self.nbf: Optional[int] = nbf
self.sub: Optional[str] = sub

self.nats = nats
self.issuer_account = issuer_account

class Meta:
unflatten_fields = [('nats', 'nats')]


class UserClaims(Claims):
pass


class AccountClaims(Claims):
pass


class OperatorClaims(Claims):
pass
89 changes: 89 additions & 0 deletions nats/contrib/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
from enum import Enum


class Prefix(Enum):
Unknown = -1

# Seed is the version byte used for encoded NATS Seeds
Seed = 18 << 3 # Base32-encodes to 'S...'

# PrefixBytePrivate is the version byte used for encoded NATS Private keys
Private = 15 << 3 # Base32-encodes to 'P...'

# PrefixByteOperator is the version byte used for encoded NATS Operators
Operator = 14 << 3 # Base32-encodes to 'O...'

# PrefixByteServer is the version byte used for encoded NATS Servers
Server = 13 << 3 # Base32-encodes to 'N...'

# PrefixByteCluster is the version byte used for encoded NATS Clusters
Cluster = 2 << 3 # Base32-encodes to 'C...'

# PrefixByteAccount is the version byte used for encoded NATS Accounts
Account = 0 # Base32-encodes to 'A...'

# PrefixByteUser is the version byte used for encoded NATS Users
User = 20 << 3 # Base32-encodes to 'U...'

Curve = 23 << 3 # Base32-encodes to 'X...'


accLookupReqTokens = 6
accLookupReqSubj = "$SYS.REQ.ACCOUNT.{subject}.CLAIMS.LOOKUP"
accPackReqSubj = "$SYS.REQ.CLAIMS.PACK"
accListReqSubj = "$SYS.REQ.CLAIMS.LIST"
accClaimsReqSubj = "$SYS.REQ.CLAIMS.UPDATE"
accDeleteReqSubj = "$SYS.REQ.CLAIMS.DELETE"

connectEventSubj = "$SYS.ACCOUNT.{subject}.CONNECT"
disconnectEventSubj = "$SYS.ACCOUNT.{subject}.DISCONNECT"
accDirectReqSubj = "$SYS.REQ.ACCOUNT.{account_name}.{subject}"
accPingReqSubj = "$SYS.REQ.ACCOUNT.PING.{subject}" # atm. only used for STATZ and CONNZ import from system account
# kept for backward compatibility when using http resolver
# this overlaps with the names for events but you'd have to have the operator private key in order to succeed.
accUpdateEventSubjOld = "$SYS.ACCOUNT.{subject}.CLAIMS.UPDATE"
accUpdateEventSubjNew = "$SYS.REQ.ACCOUNT.{subject}.CLAIMS.UPDATE"
connsRespSubj = "$SYS._INBOX_.{subject}"
accConnsEventSubjNew = "$SYS.ACCOUNT.{subject}.SERVER.CONNS"
accConnsEventSubjOld = "$SYS.SERVER.ACCOUNT.{subject}.CONNS" # kept for backward compatibility
lameDuckEventSubj = "$SYS.SERVER.{subject}.LAMEDUCK"
shutdownEventSubj = "$SYS.SERVER.{subject}.SHUTDOWN"
clientKickReqSubj = "$SYS.REQ.SERVER.{subject}.KICK"
clientLDMReqSubj = "$SYS.REQ.SERVER.{subject}.LDM"
authErrorEventSubj = "$SYS.SERVER.{subject}.CLIENT.AUTH.ERR"
authErrorAccountEventSubj = "$SYS.ACCOUNT.CLIENT.AUTH.ERR"
serverStatsSubj = "$SYS.SERVER.{subject}.STATSZ"
serverDirectReqSubj = "$SYS.REQ.SERVER.{server_id}.{subject}"
serverPingReqSubj = "$SYS.REQ.SERVER.PING.{subject}"
serverStatsPingReqSubj = "$SYS.REQ.SERVER.PING" # use $SYS.REQ.SERVER.PING.STATSZ instead
serverReloadReqSubj = "$SYS.REQ.SERVER.{subject}.RELOAD" # with server ID
leafNodeConnectEventSubj = "$SYS.ACCOUNT.{subject}.LEAFNODE.CONNECT" # for internal use only
remoteLatencyEventSubj = "$SYS.LATENCY.M2.{subject}"
inboxRespSubj = "$SYS._INBOX.{subject}.{subject}"

# Used to return information to a user on bound account and user permissions.
userDirectInfoSubj = "$SYS.REQ.USER.INFO"
userDirectReqSubj = "$SYS.REQ.USER.{subject}.INFO"

# FIXME(dlc) - Should account scope, even with wc for now, but later on
# we can then shard as needed.
accNumSubsReqSubj = "$SYS.REQ.ACCOUNT.NSUBS"

# These are for exported debug services. These are local to this server only.
accSubsSubj = "$SYS.DEBUG.SUBSCRIBERS"

shutdownEventTokens = 4
serverSubjectIndex = 2
accUpdateTokensNew = 6
accUpdateTokensOld = 5
accUpdateAccIdxOld = 2

accReqTokens = 5
accReqAccIndex = 3

ocspPeerRejectEventSubj = "$SYS.SERVER.%s.OCSP.PEER.CONN.REJECT"
ocspPeerChainlinkInvalidEventSubj = "$SYS.SERVER.%s.OCSP.PEER.LINK.INVALID"

CurveKeyLen = 32
CurveDecodeLen = 35
CurveNonceLen = 24
Loading