Skip to content

Commit af89120

Browse files
committed
Add kdocs.
1 parent 8413eea commit af89120

15 files changed

Lines changed: 883 additions & 13 deletions

paseto/src/main/kotlin/net/aholbrook/paseto/Claims.kt

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,20 @@ import kotlin.contracts.ExperimentalContracts
1414
import kotlin.contracts.InvocationKind
1515
import kotlin.contracts.contract
1616

17+
/**
18+
* Marker type for custom claim values.
19+
*
20+
* Claims can be represented as objects, arrays, primitives, or null.
21+
*
22+
* @property objectOrNull Value as [ClaimObject] when object-typed.
23+
* @property arrayOrNull Value as [ClaimArray] when array-typed.
24+
* @property primitiveOrNull Value as [ClaimPrimitive] when primitive-typed.
25+
* @property stringOrNull Primitive string value if present.
26+
* @property booleanOrNull Primitive boolean value if present.
27+
* @property intOrNull Primitive int value if present.
28+
* @property longOrNull Primitive long value if present.
29+
* @property doubleOrNull Primitive double value if present.
30+
*/
1731
sealed interface ClaimElement {
1832
val objectOrNull: ClaimObject? get() = this as? ClaimObject
1933
val arrayOrNull: ClaimArray? get() = this as? ClaimArray
@@ -26,6 +40,15 @@ sealed interface ClaimElement {
2640
val doubleOrNull: Double? get() = null
2741
}
2842

43+
/**
44+
* Attempt to read this claim as a supported Kotlin type.
45+
*
46+
* Supported types are: [String], [Boolean], [Int], [Long], [Double], [ClaimObject],
47+
* and [ClaimArray]. Calling with an unsupported type will return `null`.
48+
*
49+
* @receiver Claim element to cast.
50+
* @return Cast value or `null` if unsupported/unmatched.
51+
*/
2952
inline fun <reified T> ClaimElement.asType(): T? = when (T::class) {
3053
String::class -> primitiveOrNull?.stringOrNull as? T
3154
Boolean::class -> primitiveOrNull?.booleanOrNull as? T
@@ -37,10 +60,12 @@ inline fun <reified T> ClaimElement.asType(): T? = when (T::class) {
3760
else -> null
3861
}
3962

63+
/** Null claim value. */
4064
object ClaimNull : ClaimElement
4165

4266
@JvmInline
4367
@Suppress("JavaDefaultMethodsNotOverriddenByDelegation")
68+
/** Array claim value. */
4469
value class ClaimArray internal constructor(private val content: List<ClaimElement>) :
4570
ClaimElement,
4671
List<ClaimElement> by content {
@@ -49,6 +74,7 @@ value class ClaimArray internal constructor(private val content: List<ClaimEleme
4974
}
5075

5176
@JvmInline
77+
/** Object claim value. */
5278
value class ClaimObject internal constructor(private val content: Map<String, ClaimElement>) :
5379
ClaimElement,
5480
Map<String, ClaimElement> by content {
@@ -60,6 +86,7 @@ value class ClaimObject internal constructor(private val content: Map<String, Cl
6086
}
6187

6288
@JvmInline
89+
/** Primitive claim value. */
6390
value class ClaimPrimitive internal constructor(internal val primitive: JsonPrimitive) : ClaimElement {
6491
override val stringOrNull: String? get() = primitive.contentOrNull?.takeIf { primitive.isString }
6592
override val booleanOrNull: Boolean? get() = primitive.booleanOrNull
@@ -70,19 +97,61 @@ value class ClaimPrimitive internal constructor(internal val primitive: JsonPrim
7097
}
7198

7299
@PasetoDslMarker
100+
/** DSL Builder for [ClaimObject]. */
73101
class ClaimObjectBuilder @PublishedApi internal constructor() {
74102
private val content: MutableMap<String, ClaimElement> = linkedMapOf()
75103

104+
/**
105+
* Put a nested claim value.
106+
*
107+
* @param key Claim key.
108+
* @param value Claim value.
109+
* @return Previous value for [key], if present.
110+
*/
76111
fun put(key: String, value: ClaimElement): ClaimElement? = content.put(key, value)
112+
/**
113+
* Put a boolean claim value.
114+
*
115+
* @param key Claim key.
116+
* @param value Claim value.
117+
* @return Previous value for [key], if present.
118+
*/
77119
fun put(key: String, value: Boolean): ClaimElement? = content.put(key, primitiveValue(value))
120+
/**
121+
* Put a numeric claim value.
122+
*
123+
* @param key Claim key.
124+
* @param value Claim value.
125+
* @return Previous value for [key], if present.
126+
*/
78127
fun put(key: String, value: Number): ClaimElement? = content.put(key, primitiveValue(value))
128+
/**
129+
* Put a string claim value.
130+
*
131+
* @param key Claim key.
132+
* @param value Claim value.
133+
* @return Previous value for [key], if present.
134+
*/
79135
fun put(key: String, value: String): ClaimElement? = content.put(key, primitiveValue(value))
136+
/**
137+
* Put a `null` claim value.
138+
*
139+
* @param key Claim key.
140+
* @param value Claim value.
141+
* @return Previous value for [key], if present.
142+
*/
80143
fun put(key: String, value: Nothing?): ClaimElement? = content.put(key, primitiveValue(value))
81144

82145
@PublishedApi
83146
internal fun build(): ClaimObject = ClaimObject(content)
84147
}
85148

149+
/**
150+
* Build a [ClaimObject] using the claim DSL.
151+
*
152+
* @param init Claim-object builder block.
153+
* @return Built [ClaimObject].
154+
*/
86155
@OptIn(ExperimentalContracts::class)
87156
inline fun claimObject(init: ClaimObjectBuilder.() -> Unit): ClaimObject {
88157
contract { callsInPlace(init, InvocationKind.EXACTLY_ONCE) }
@@ -93,19 +162,56 @@ inline fun claimObject(init: ClaimObjectBuilder.() -> Unit): ClaimObject {
93162
}
94163

95164
@PasetoDslMarker
165+
/** DSL builder for [ClaimArray]. */
96166
class ClaimArrayBuilder @PublishedApi internal constructor() {
97167
private val content: MutableList<ClaimElement> = mutableListOf()
98168

169+
/**
170+
* Add a nested claim value.
171+
*
172+
* @param value Claim value to append.
173+
* @return `true` when appended.
174+
*/
99175
fun add(value: ClaimElement): Boolean = content.add(value)
176+
/**
177+
* Add a boolean value.
178+
*
179+
* @param value Claim value to append.
180+
* @return `true` when appended.
181+
*/
100182
fun add(value: Boolean): Boolean = content.add(primitiveValue(value))
183+
/**
184+
* Add a numeric value.
185+
*
186+
* @param value Claim value to append.
187+
* @return `true` when appended.
188+
*/
101189
fun add(value: Number): Boolean = content.add(primitiveValue(value))
190+
/**
191+
* Add a string value.
192+
*
193+
* @param value Claim value to append.
194+
* @return `true` when appended.
195+
*/
102196
fun add(value: String): Boolean = content.add(primitiveValue(value))
197+
/**
198+
* Add a `null` value.
199+
*
200+
* @param value Claim value to append.
201+
* @return `true` when appended.
202+
*/
103203
fun add(value: Nothing?): Boolean = content.add(primitiveValue(value))
104204

105205
@PublishedApi
106206
internal fun build(): ClaimArray = ClaimArray(content)
107207
}
108208

209+
/**
210+
* Build a [ClaimArray] using the claim DSL.
211+
*
212+
* @param init Array builder block.
213+
* @return Built [ClaimArray].
214+
*/
109215
@OptIn(ExperimentalContracts::class)
110216
inline fun claimArray(init: ClaimArrayBuilder.() -> Unit): ClaimArray {
111217
contract { callsInPlace(init, InvocationKind.EXACTLY_ONCE) }
@@ -129,7 +235,31 @@ internal fun ClaimElement.toJson(): JsonElement = when (this) {
129235
is ClaimObject -> JsonObject(this.mapValues { it.value.toJson() })
130236
}
131237

238+
/**
239+
* Convert a nullable boolean into a [ClaimPrimitive].
240+
*
241+
* @param value Boolean value.
242+
* @return Primitive claim.
243+
*/
132244
fun primitiveValue(value: Boolean?): ClaimPrimitive = ClaimPrimitive(JsonPrimitive(value))
245+
/**
246+
* Convert a nullable number into a [ClaimPrimitive].
247+
*
248+
* @param value Number value.
249+
* @return Primitive claim.
250+
*/
133251
fun primitiveValue(value: Number?): ClaimPrimitive = ClaimPrimitive(JsonPrimitive(value))
252+
/**
253+
* Convert a nullable string into a [ClaimPrimitive].
254+
*
255+
* @param value String value.
256+
* @return Primitive claim.
257+
*/
134258
fun primitiveValue(value: String?): ClaimPrimitive = ClaimPrimitive(JsonPrimitive(value))
259+
/**
260+
* Convert nullable `Nothing` into a JSON null [ClaimPrimitive].
261+
*
262+
* @param value Null literal.
263+
* @return Primitive claim.
264+
*/
135265
fun primitiveValue(value: Nothing?): ClaimPrimitive = ClaimPrimitive(JsonPrimitive(value))

paseto/src/main/kotlin/net/aholbrook/paseto/Footer.kt

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,50 @@ import kotlin.contracts.ExperimentalContracts
55
import kotlin.contracts.InvocationKind
66
import kotlin.contracts.contract
77

8+
/**
9+
* Marker interface for supported token footer types.
10+
*/
811
sealed interface Footer
912

13+
/**
14+
* String footer value.
15+
*
16+
* @property value Footer text.
17+
*/
1018
@JvmInline
1119
value class StringFooter internal constructor(val value: String) : Footer
1220

1321
@ConsistentCopyVisibility
22+
/**
23+
* Structured footer with reserved `kid`/`wpk` fields plus arbitrary custom claims.
24+
*
25+
* @property keyId Optional key identifier (`kid`).
26+
* @property wrappedKey Optional wrapped key value (`wpk`).
27+
* @property claims Custom footer claims.
28+
*/
1429
data class ClaimFooter internal constructor(
1530
val keyId: String?, // kid
1631
val wrappedKey: String?, // wpk
1732
val claims: ClaimObject,
1833
) : Footer
1934

2035
@PasetoDslMarker
36+
/**
37+
* DSL builder for [ClaimFooter].
38+
*
39+
* @property keyId Optional key identifier (`kid`).
40+
* @property wrappedKey Optional wrapped key value (`wpk`).
41+
*/
2142
class ClaimFooterBuilder @PublishedApi internal constructor() {
2243
var keyId: String? = null // kid
2344
var wrappedKey: String? = null // wpk
2445
private var claims: ClaimObject = ClaimObject()
2546

47+
/**
48+
* Replace footer custom claims using the claim-object DSL.
49+
*
50+
* @param init Claim-object builder block.
51+
*/
2652
@OptIn(ExperimentalContracts::class)
2753
fun claims(init: ClaimObjectBuilder.() -> Unit) {
2854
contract { callsInPlace(init, InvocationKind.EXACTLY_ONCE) }
@@ -32,6 +58,11 @@ class ClaimFooterBuilder @PublishedApi internal constructor() {
3258
claims = builder.build()
3359
}
3460

61+
/**
62+
* Replace footer custom claims with an existing [ClaimObject].
63+
*
64+
* @param claims Claim object to store on the footer.
65+
*/
3566
fun claims(claims: ClaimObject) {
3667
this.claims = claims
3768
}
@@ -44,8 +75,20 @@ class ClaimFooterBuilder @PublishedApi internal constructor() {
4475
)
4576
}
4677

78+
/**
79+
* Create a plain [StringFooter].
80+
*
81+
* @param footer Footer text.
82+
* @return A [StringFooter] value.
83+
*/
4784
fun footer(footer: String) = StringFooter(footer)
4885

86+
/**
87+
* Build a structured [ClaimFooter] using the footer DSL.
88+
*
89+
* @param init Footer builder block.
90+
* @return A [ClaimFooter] value.
91+
*/
4992
@OptIn(ExperimentalContracts::class)
5093
inline fun footer(init: ClaimFooterBuilder.() -> Unit): ClaimFooter {
5194
contract { callsInPlace(init, InvocationKind.EXACTLY_ONCE) }
@@ -60,18 +103,30 @@ inline fun footer(init: ClaimFooterBuilder.() -> Unit): ClaimFooter {
60103
*/
61104
sealed interface TaintedFooter
62105

106+
/**
107+
* Tainted string footer extracted without token verification.
108+
*
109+
* @property value Unverified footer text.
110+
*/
63111
@JvmInline
64112
value class TaintedStringFooter(val value: String) : TaintedFooter
65113

66114
@ConsistentCopyVisibility
115+
/**
116+
* Tainted claim footer extracted without token verification.
117+
*
118+
* @property keyId Optional unverified key identifier (`kid`).
119+
* @property wrappedKey Optional unverified wrapped key value (`wpk`).
120+
* @property claims Unverified footer claims.
121+
*/
67122
data class TaintedClaimFooter internal constructor(
68123
val keyId: String?, // kid
69124
val wrappedKey: String?, // wpk
70125
val claims: ClaimObject,
71126
) : TaintedFooter
72127

73128
/**
74-
* Converts a [Footer] to it's [TaintedFooter] variant.
129+
* Converts a [Footer] to its [TaintedFooter] variant.
75130
*
76131
* This can be used to compare an [TaintedClaimFooter] against a [ClaimFooter] built using the [footer] builder.
77132
* @receiver A [Footer] instance to turn taint.
@@ -83,19 +138,23 @@ fun Footer.taint(): TaintedFooter = when (this) {
83138
}
84139

85140
/**
86-
* Escape hatch for direct access to the footer's claims as a [JsonObject].
141+
* Escape hatch for direct access to footer claims as a [JsonObject].
87142
*
88143
* This is an internal API because it couples the caller to the `kotlinx.serialization` JSON implementation.
89144
* It may change or be removed without notice if the underlying serialization strategy changes.
145+
* @receiver Verified [ClaimFooter].
146+
* @return Footer claims as a [JsonObject].
90147
*/
91148
@InternalApi
92149
fun ClaimFooter.claimsJson(): JsonObject = claims.toJson() as JsonObject
93150

94151
/**
95-
* Escape hatch for direct access to the footer's claims as a [JsonObject].
152+
* Escape hatch for direct access to footer claims as a [JsonObject].
96153
*
97154
* This is an internal API because it couples the caller to the `kotlinx.serialization` JSON implementation.
98155
* It may change or be removed without notice if the underlying serialization strategy changes.
156+
* @receiver Unverified [TaintedClaimFooter].
157+
* @return Footer claims as a [JsonObject].
99158
*/
100159
@InternalApi
101160
fun TaintedClaimFooter.claimsJson(): JsonObject = claims.toJson() as JsonObject

paseto/src/main/kotlin/net/aholbrook/paseto/FooterSerde.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,23 @@ internal data class FooterOptions(
5454
val maxKeys: Int = 512,
5555
)
5656

57+
/**
58+
* Builder for footer parsing and validation settings used by [TokenServiceBuilder.footerOptions].
59+
*
60+
* @property parseMode Footer decode strategy, see [FooterParseMode].
61+
* @property maxLength Maximum footer length in characters.
62+
* @property maxDepth Maximum JSON nesting depth for object-like footers.
63+
* @property maxKeys Maximum JSON key count for object-like footers.
64+
*/
5765
@PasetoDslMarker
5866
class FooterOptionsBuilder @PublishedApi internal constructor() {
67+
/** Strategy used to decode footer text (`AUTO`, `CLAIMS`, or `STRING`). */
5968
var parseMode: FooterParseMode = FooterParseMode.AUTO
69+
/** Maximum allowed footer string length in characters. */
6070
var maxLength: Int = 8192
71+
/** Maximum allowed JSON object/array nesting depth for object-like footers. */
6172
var maxDepth: Int = 2
73+
/** Maximum allowed JSON key count for object-like footers. */
6274
var maxKeys: Int = 512
6375

6476
internal fun build(): FooterOptions = FooterOptions(

0 commit comments

Comments
 (0)