-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
VapidKeys.kt
100 lines (91 loc) · 3.93 KB
/
VapidKeys.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package com.interaso.webpush
import java.nio.file.*
import java.security.interfaces.*
import kotlin.io.path.*
/**
* Represents VapidKeys used for web push notifications.
*
* @property publicKey The public key of the VapidKeys.
* @property privateKey The private key of the VapidKeys.
* @property applicationServerKey The uncompressed bytes of the public key.
* @property x509PublicKey The base64 encoded string of the public key.
* @property pkcs8PrivateKey The base64 encoded string of the private key.
*
* @constructor Creates a VapidKeys instance with the specified public and private keys.
*
* @throws IllegalArgumentException If the provided public key does not correspond to the private key.
*/
public class VapidKeys(
public val publicKey: ECPublicKey,
public val privateKey: ECPrivateKey,
) {
public val applicationServerKey: ByteArray = getUncompressedBytes(publicKey)
public val x509PublicKey: String = encodeBase64(publicKey.encoded)
public val pkcs8PrivateKey: String = encodeBase64(privateKey.encoded)
init {
require(areKeysValidPair(privateKey, publicKey)) {
"Public key does not corresponds to private key"
}
}
public companion object Factory {
/**
* Generates VapidKeys using the secp256r1 elliptic curve algorithm.
*
* @return the generated VapidKeys object.
*/
@JvmStatic
public fun generate(): VapidKeys {
return generateSecp256r1KeyPair().run {
VapidKeys(public as ECPublicKey, private as ECPrivateKey)
}
}
/**
* Decodes the specified X509 public key and PKCS8 private key and returns the corresponding VapidKeys object.
*
* @param x509PublicKey The X509 public key encoded as a Base64 string.
* @param pkcs8PrivateKey The PKCS8 private key encoded as a Base64 string.
* @return The VapidKeys object representing the loaded public and private keys.
*/
@JvmStatic
public fun create(x509PublicKey: String, pkcs8PrivateKey: String): VapidKeys {
return VapidKeys(
generatePublicKeyFromX509(decodeBase64(x509PublicKey)),
generatePrivateKeyFromPkcs8(decodeBase64(pkcs8PrivateKey)),
)
}
/**
* Decodes the specified public key and private key from uncompressed bytes format and returns the corresponding VapidKeys object.
*
* @param publicKey The uncompressed public key bytes encoded as a Base64 string.
* @param privateKey The uncompressed private key bytes encoded as a Base64 string.
* @return The VapidKeys object representing the loaded public and private keys.
*/
@JvmStatic
public fun fromUncompressedBytes(publicKey: String, privateKey: String): VapidKeys {
return VapidKeys(
generatePublicKeyFromUncompressedBytes(decodeBase64(publicKey)),
generatePrivateKeyFromUncompressedBytes(decodeBase64(privateKey)),
)
}
/**
* Loads VapidKeys from a given path, expects Base64 encoded keys on separate lines in X509 and PKCS8 formats.
*
* @param path The path to load the VapidKeys from.
* @param generateMissing If set to true and the path does not exist, generate new VapidKeys and save them to the path.
*
* @return The loaded VapidKeys object.
*/
@JvmStatic
public fun load(path: Path, generateMissing: Boolean = true): VapidKeys {
if (!path.exists() && generateMissing) {
return generate().apply {
path.createParentDirectories()
path.writeLines(listOf(x509PublicKey, pkcs8PrivateKey))
}
}
return path.readLines().let { (x509PublicKey, pkcs8PrivateKey) ->
create(x509PublicKey, pkcs8PrivateKey)
}
}
}
}