or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

errors.mdindex.mdinterfaces.mdjwa.mdjwk.mdjws.mdutilities.md

utilities.mddocs/

0

# Base64 and JSON Utilities

1

2

JOSE-compliant base64 encoding/decoding and JSON serialization utilities with support for certificates, CSRs, and typed field handling. Provides the foundation for secure data encoding and structured JSON object management.

3

4

## Capabilities

5

6

### JOSE Base64 Encoding

7

8

URL-safe base64 encoding with padding stripped according to JOSE specifications.

9

10

```python { .api }

11

def b64encode(data: bytes) -> bytes:

12

"""

13

JOSE Base64 encode.

14

15

Parameters:

16

- data: Data to be encoded

17

18

Returns:

19

bytes: JOSE Base64 string (URL-safe, no padding)

20

21

Raises:

22

TypeError: If data is not bytes

23

"""

24

25

def b64decode(data: Union[bytes, str]) -> bytes:

26

"""

27

JOSE Base64 decode.

28

29

Parameters:

30

- data: Base64 string to decode (str or bytes)

31

32

Returns:

33

bytes: Decoded data

34

35

Raises:

36

TypeError: If input is not str or bytes

37

ValueError: If input contains non-ASCII characters (str input)

38

"""

39

```

40

41

#### Usage Examples

42

43

```python

44

from josepy import b64encode, b64decode

45

46

# Encode data to JOSE base64

47

data = b"Hello, JOSE Base64!"

48

encoded = b64encode(data)

49

print(f"Encoded: {encoded}") # URL-safe, no padding

50

51

# Decode back to original

52

decoded = b64decode(encoded)

53

print(f"Decoded: {decoded}")

54

55

# Decode from string

56

encoded_str = encoded.decode('ascii')

57

decoded_from_str = b64decode(encoded_str)

58

assert decoded == decoded_from_str

59

60

# JOSE base64 vs standard base64

61

import base64

62

standard_b64 = base64.b64encode(data)

63

jose_b64 = b64encode(data)

64

print(f"Standard: {standard_b64}") # May have padding and +/

65

print(f"JOSE: {jose_b64}") # URL-safe, no padding

66

```

67

68

### Extended JOSE Base64 Utilities

69

70

Additional encoding/decoding functions for JOSE-specific data handling.

71

72

```python { .api }

73

def encode_b64jose(data: bytes) -> str:

74

"""

75

Encode bytes to JOSE base64 string.

76

77

Parameters:

78

- data: Data to encode

79

80

Returns:

81

str: JOSE base64 encoded string

82

"""

83

84

def decode_b64jose(data: str, size: Optional[int] = None, minimum: bool = False) -> bytes:

85

"""

86

Decode JOSE base64 string to bytes with size validation.

87

88

Parameters:

89

- data: JOSE base64 encoded string

90

- size: Expected output size in bytes (optional)

91

- minimum: If True, size is minimum required (default: exact match)

92

93

Returns:

94

bytes: Decoded data

95

96

Raises:

97

josepy.errors.DeserializationError: If size validation fails

98

"""

99

100

def encode_hex16(value: bytes) -> str:

101

"""

102

Encode bytes to hex string.

103

104

Parameters:

105

- value: Bytes to encode

106

107

Returns:

108

str: Hex encoded string

109

"""

110

111

def decode_hex16(value: str, size: Optional[int] = None, minimum: bool = False) -> bytes:

112

"""

113

Decode hex string to bytes with size validation.

114

115

Parameters:

116

- value: Hex encoded string

117

- size: Expected output size in bytes (optional)

118

- minimum: If True, size is minimum required

119

120

Returns:

121

bytes: Decoded bytes

122

"""

123

```

124

125

### X.509 Certificate Utilities

126

127

Utilities for encoding and decoding X.509 certificates and Certificate Signing Requests (CSRs).

128

129

```python { .api }

130

def encode_cert(cert: x509.Certificate) -> str:

131

"""

132

Encode X.509 certificate to base64 DER string.

133

134

Parameters:

135

- cert: X.509 certificate object from cryptography

136

137

Returns:

138

str: Base64 DER encoded certificate

139

"""

140

141

def decode_cert(b64der: str) -> x509.Certificate:

142

"""

143

Decode base64 DER string to X.509 certificate.

144

145

Parameters:

146

- b64der: Base64 DER encoded certificate string

147

148

Returns:

149

x509.Certificate: Certificate object

150

151

Raises:

152

josepy.errors.DeserializationError: If decoding fails

153

"""

154

155

def encode_csr(csr: x509.CertificateSigningRequest) -> str:

156

"""

157

Encode X.509 CSR to base64 DER string.

158

159

Parameters:

160

- csr: X.509 CSR object from cryptography

161

162

Returns:

163

str: Base64 DER encoded CSR

164

"""

165

166

def decode_csr(b64der: str) -> x509.CertificateSigningRequest:

167

"""

168

Decode base64 DER string to X.509 CSR.

169

170

Parameters:

171

- b64der: Base64 DER encoded CSR string

172

173

Returns:

174

x509.CertificateSigningRequest: CSR object

175

176

Raises:

177

josepy.errors.DeserializationError: If decoding fails

178

"""

179

```

180

181

#### Usage Examples

182

183

```python

184

from josepy import encode_cert, decode_cert, encode_csr, decode_csr

185

from cryptography import x509

186

from cryptography.x509.oid import NameOID

187

from cryptography.hazmat.primitives import hashes

188

189

# Assuming you have a certificate

190

# cert = x509.load_pem_x509_certificate(cert_pem_data, default_backend())

191

192

# Encode certificate to base64 DER

193

cert_b64 = encode_cert(cert)

194

print(f"Certificate B64: {cert_b64[:60]}...")

195

196

# Decode back to certificate object

197

decoded_cert = decode_cert(cert_b64)

198

assert cert == decoded_cert

199

200

# Same process for CSRs

201

# csr = x509.load_pem_x509_csr(csr_pem_data, default_backend())

202

csr_b64 = encode_csr(csr)

203

decoded_csr = decode_csr(csr_b64)

204

```

205

206

### JSON Object Framework

207

208

Framework for creating JSON-serializable objects with typed fields and validation.

209

210

```python { .api }

211

def field(json_name: str, default: Any = None, omitempty: bool = False, decoder: Optional[Callable] = None, encoder: Optional[Callable] = None) -> Any:

212

"""

213

Declare a JSON field with type annotations and custom encoding/decoding.

214

215

Parameters:

216

- json_name: JSON property name

217

- default: Default value if omitted

218

- omitempty: Skip field if value equals default

219

- decoder: Function to decode from JSON value

220

- encoder: Function to encode to JSON value

221

222

Returns:

223

Field descriptor for use in class definitions

224

"""

225

226

class Field:

227

"""Field descriptor for JSON object properties"""

228

229

def __init__(self, json_name: str, default: Any = None, omitempty: bool = False, decoder: Optional[Callable] = None, encoder: Optional[Callable] = None): ...

230

231

def decode(self, value: Any) -> Any:

232

"""Decode JSON value to Python object"""

233

234

def encode(self, value: Any) -> Any:

235

"""Encode Python object to JSON value"""

236

237

class JSONObjectWithFields:

238

"""Base class for JSON objects with field definitions"""

239

240

@classmethod

241

def from_json(cls, jobj: Any): ...

242

243

def to_partial_json(self) -> Any: ...

244

245

def json_dumps(self, **kwargs) -> str: ...

246

247

@classmethod

248

def json_loads(cls, json_string: str): ...

249

250

class TypedJSONObjectWithFields(JSONObjectWithFields):

251

"""Typed variant supporting automatic type-based deserialization"""

252

253

type_field_name: str = "typ" # JSON field containing type information

254

TYPES: Dict[str, Type] = {} # Registry of types for deserialization

255

```

256

257

#### Usage Examples

258

259

```python

260

from josepy import field, JSONObjectWithFields

261

from josepy.json_util import TypedJSONObjectWithFields

262

263

# Define a custom JSON object with fields

264

class Person(JSONObjectWithFields):

265

name: str = field('name')

266

age: int = field('age', default=0)

267

email: str = field('email', omitempty=True)

268

269

# Create and serialize

270

person = Person(name="Alice", age=30, email="alice@example.com")

271

person_json = person.json_dumps()

272

print(f"Person JSON: {person_json}")

273

274

# Deserialize

275

loaded_person = Person.json_loads(person_json)

276

print(f"Loaded: {loaded_person.name}, age {loaded_person.age}")

277

278

# Typed objects with automatic type detection

279

class Message(TypedJSONObjectWithFields):

280

type_field_name = "type"

281

282

content: str = field('content')

283

284

class ErrorMessage(Message):

285

error_code: int = field('error_code')

286

287

class InfoMessage(Message):

288

info_level: str = field('info_level')

289

290

# Register types

291

Message.TYPES['error'] = ErrorMessage

292

Message.TYPES['info'] = InfoMessage

293

294

# Automatic deserialization based on type field

295

error_json = '{"type": "error", "content": "Failed", "error_code": 500}'

296

msg = Message.from_json(json.loads(error_json))

297

print(f"Message type: {type(msg).__name__}") # ErrorMessage

298

```

299

300

### Utility Classes

301

302

Additional utility classes for key handling and immutable data structures.

303

304

```python { .api }

305

class ComparableKey:

306

"""Comparable wrapper for cryptography keys"""

307

308

def __init__(self, wrapped): ...

309

def public_key(self) -> 'ComparableKey': ...

310

def __eq__(self, other) -> bool: ...

311

def __hash__(self) -> int: ...

312

313

class ComparableRSAKey(ComparableKey):

314

"""Comparable wrapper for RSA keys"""

315

316

class ComparableECKey(ComparableKey):

317

"""Comparable wrapper for EC keys"""

318

319

class ImmutableMap:

320

"""Immutable key-to-value mapping with attribute access"""

321

322

def __init__(self, **kwargs): ...

323

def update(self, **kwargs) -> 'ImmutableMap': ...

324

def __getitem__(self, key: str) -> Any: ...

325

def __iter__(self): ...

326

def __len__(self) -> int: ...

327

def __hash__(self) -> int: ...

328

```

329

330

#### Usage Examples

331

332

```python

333

from josepy import ComparableRSAKey, ImmutableMap

334

from cryptography.hazmat.primitives.asymmetric import rsa

335

from cryptography.hazmat.backends import default_backend

336

337

# Comparable keys enable equality comparison

338

key1 = rsa.generate_private_key(65537, 2048, default_backend())

339

key2 = rsa.generate_private_key(65537, 2048, default_backend())

340

341

comp_key1 = ComparableRSAKey(key1)

342

comp_key2 = ComparableRSAKey(key2)

343

comp_key1_copy = ComparableRSAKey(key1)

344

345

print(f"Keys equal: {comp_key1 == comp_key1_copy}") # True

346

print(f"Different keys: {comp_key1 == comp_key2}") # False

347

348

# Keys can be used in sets and dictionaries

349

key_set = {comp_key1, comp_key2, comp_key1_copy}

350

print(f"Unique keys: {len(key_set)}") # 2

351

352

# Immutable maps

353

config = ImmutableMap(host="localhost", port=8080, ssl=True)

354

print(f"Host: {config.host}, Port: {config.port}")

355

356

# Update creates new instance

357

new_config = config.update(port=9090, debug=True)

358

print(f"New port: {new_config.port}, Debug: {new_config.debug}")

359

print(f"Original port: {config.port}") # Unchanged

360

361

# Can be used as dict keys (hashable)

362

configs = {config: "production", new_config: "development"}

363

```

364

365

## Error Handling

366

367

All utilities may raise specific exceptions for validation and encoding failures:

368

369

```python

370

from josepy.errors import DeserializationError

371

372

try:

373

# Invalid base64

374

decoded = b64decode("invalid base64!")

375

except ValueError as e:

376

print(f"Base64 decode error: {e}")

377

378

try:

379

# Size validation failure

380

data = decode_b64jose("dGVzdA", size=10) # "test" is only 4 bytes

381

except DeserializationError as e:

382

print(f"Size validation error: {e}")

383

384

try:

385

# Invalid certificate data

386

cert = decode_cert("not a certificate")

387

except DeserializationError as e:

388

print(f"Certificate decode error: {e}")

389

```