Skip to content

Commit 018f734

Browse files
committed
review: update & add tests
1 parent dfc519f commit 018f734

2 files changed

Lines changed: 205 additions & 18 deletions

File tree

pkg/extensions/webbotauth_test.go

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import (
55
"net/http"
66
"testing"
77
"time"
8+
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
811
)
912

1013
// TestWebBotAuthDownloadable verifies that the web-bot-auth package can be downloaded from GitHub
@@ -17,19 +20,13 @@ func TestWebBotAuthDownloadable(t *testing.T) {
1720
}
1821

1922
req, err := http.NewRequestWithContext(ctx, http.MethodGet, webBotAuthDownloadURL, nil)
20-
if err != nil {
21-
t.Fatalf("Failed to create request: %v", err)
22-
}
23+
require.NoError(t, err, "Failed to create request")
2324

2425
resp, err := client.Do(req)
25-
if err != nil {
26-
t.Fatalf("Failed to download web-bot-auth: %v", err)
27-
}
26+
require.NoError(t, err, "Failed to download web-bot-auth")
2827
defer resp.Body.Close()
2928

30-
if resp.StatusCode != http.StatusOK {
31-
t.Fatalf("Expected status 200, got %d", resp.StatusCode)
32-
}
29+
require.Equal(t, http.StatusOK, resp.StatusCode, "Expected status 200")
3330

3431
// Verify Content-Type indicates a zip file
3532
contentType := resp.Header.Get("Content-Type")
@@ -39,8 +36,8 @@ func TestWebBotAuthDownloadable(t *testing.T) {
3936

4037
// Verify Content-Length is reasonable (should be at least 1KB)
4138
contentLength := resp.ContentLength
42-
if contentLength > 0 && contentLength < 1024 {
43-
t.Fatalf("Content-Length too small: %d bytes (expected at least 1KB)", contentLength)
39+
if contentLength > 0 {
40+
assert.GreaterOrEqual(t, contentLength, int64(1024), "Content-Length should be at least 1KB")
4441
}
4542

4643
t.Logf("Successfully verified web-bot-auth is downloadable")
@@ -60,13 +57,8 @@ func TestDownloadAndExtractWebBotAuth(t *testing.T) {
6057
browserExtDir, cleanup, err := downloadAndExtractWebBotAuth(ctx)
6158
defer cleanup()
6259

63-
if err != nil {
64-
t.Fatalf("Failed to download and extract web-bot-auth: %v", err)
65-
}
66-
67-
if browserExtDir == "" {
68-
t.Fatal("Expected non-empty browser extension directory path")
69-
}
60+
require.NoError(t, err, "Failed to download and extract web-bot-auth")
61+
require.NotEmpty(t, browserExtDir, "Expected non-empty browser extension directory path")
7062

7163
t.Logf("Successfully downloaded and extracted to: %s", browserExtDir)
7264
}

pkg/util/crypto_test.go

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
package util
2+
3+
import (
4+
"crypto/ed25519"
5+
"crypto/x509"
6+
"encoding/base64"
7+
"encoding/pem"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestValidatePEMKey(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
pemData string
18+
wantErr bool
19+
errMsg string
20+
}{
21+
{
22+
name: "valid Ed25519 PEM key",
23+
pemData: `-----BEGIN PRIVATE KEY-----
24+
MC4CAQAwBQYDK2VwBCIEIJ+DYvh6SEqVTm50DFtMDoQikTmiCqirVv9mWG9qfSnF
25+
-----END PRIVATE KEY-----`,
26+
wantErr: false,
27+
},
28+
{
29+
name: "invalid PEM format",
30+
pemData: "not a pem key",
31+
wantErr: true,
32+
errMsg: "failed to decode PEM block",
33+
},
34+
{
35+
name: "wrong PEM type",
36+
pemData: `-----BEGIN PUBLIC KEY-----
37+
MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=
38+
-----END PUBLIC KEY-----`,
39+
wantErr: true,
40+
errMsg: "invalid PEM type",
41+
},
42+
{
43+
name: "invalid PKCS8 data",
44+
pemData: `-----BEGIN PRIVATE KEY-----
45+
aW52YWxpZCBkYXRh
46+
-----END PRIVATE KEY-----`,
47+
wantErr: true,
48+
errMsg: "failed to parse PKCS#8 private key",
49+
},
50+
}
51+
52+
for _, tt := range tests {
53+
t.Run(tt.name, func(t *testing.T) {
54+
err := ValidatePEMKey(tt.pemData)
55+
if tt.wantErr {
56+
require.Error(t, err)
57+
if tt.errMsg != "" {
58+
assert.Contains(t, err.Error(), tt.errMsg)
59+
}
60+
} else {
61+
require.NoError(t, err)
62+
}
63+
})
64+
}
65+
}
66+
67+
func TestConvertJWKToPEM(t *testing.T) {
68+
tests := []struct {
69+
name string
70+
jwkJSON string
71+
wantErr bool
72+
errMsg string
73+
wantPubKey string // Expected base64url-encoded public key for validation
74+
}{
75+
{
76+
name: "valid JWK",
77+
jwkJSON: `{
78+
"kty": "OKP",
79+
"crv": "Ed25519",
80+
"d": "n4Ni-HpISpVObnQMW0wOhCKROaIKqKtW_2ZYb2p9KcU",
81+
"x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"
82+
}`,
83+
wantErr: false,
84+
wantPubKey: "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs",
85+
},
86+
{
87+
name: "invalid JSON",
88+
jwkJSON: `{invalid json}`,
89+
wantErr: true,
90+
errMsg: "failed to parse JWK",
91+
},
92+
{
93+
name: "wrong key type",
94+
jwkJSON: `{
95+
"kty": "RSA",
96+
"crv": "Ed25519",
97+
"d": "test"
98+
}`,
99+
wantErr: true,
100+
errMsg: "invalid key type",
101+
},
102+
{
103+
name: "wrong curve",
104+
jwkJSON: `{
105+
"kty": "OKP",
106+
"crv": "Ed448",
107+
"d": "test"
108+
}`,
109+
wantErr: true,
110+
errMsg: "invalid key type",
111+
},
112+
{
113+
name: "invalid base64url encoding",
114+
jwkJSON: `{
115+
"kty": "OKP",
116+
"crv": "Ed25519",
117+
"d": "not valid base64url!!!"
118+
}`,
119+
wantErr: true,
120+
errMsg: "failed to decode private key",
121+
},
122+
{
123+
name: "invalid key size",
124+
jwkJSON: `{
125+
"kty": "OKP",
126+
"crv": "Ed25519",
127+
"d": "dGVzdA"
128+
}`,
129+
wantErr: true,
130+
errMsg: "invalid private key size",
131+
},
132+
{
133+
name: "missing private key component",
134+
jwkJSON: `{
135+
"kty": "OKP",
136+
"crv": "Ed25519",
137+
"x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"
138+
}`,
139+
wantErr: true,
140+
errMsg: "invalid private key size",
141+
},
142+
{
143+
name: "missing key type",
144+
jwkJSON: `{
145+
"crv": "Ed25519",
146+
"d": "n4Ni-HpISpVObnQMW0wOhCKROaIKqKtW_2ZYb2p9KcU"
147+
}`,
148+
wantErr: true,
149+
errMsg: "invalid key type",
150+
},
151+
}
152+
153+
for _, tt := range tests {
154+
t.Run(tt.name, func(t *testing.T) {
155+
t.Parallel()
156+
157+
pemData, err := ConvertJWKToPEM(tt.jwkJSON)
158+
if tt.wantErr {
159+
require.ErrorContains(t, err, tt.errMsg)
160+
return
161+
}
162+
163+
require.NoError(t, err)
164+
require.NotEmpty(t, pemData)
165+
166+
// Decode and validate the PEM structure
167+
block, rest := pem.Decode(pemData)
168+
require.NotNil(t, block, "Failed to decode PEM block")
169+
assert.Empty(t, rest, "Expected single PEM block, found extra data")
170+
assert.Equal(t, "PRIVATE KEY", block.Type)
171+
172+
// Parse as PKCS#8 and verify it's Ed25519
173+
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
174+
require.NoError(t, err, "Failed to parse PKCS#8")
175+
176+
ed25519Key, ok := privateKey.(ed25519.PrivateKey)
177+
require.True(t, ok, "Expected Ed25519 private key, got %T", privateKey)
178+
assert.Len(t, ed25519Key, ed25519.PrivateKeySize, "Invalid private key size")
179+
180+
// Verify the public key matches expected value (if provided)
181+
if tt.wantPubKey != "" {
182+
pubKey := ed25519Key.Public().(ed25519.PublicKey)
183+
// Encode to base64url for comparison
184+
actualPubKey := base64.RawURLEncoding.EncodeToString(pubKey)
185+
assert.Equal(t, tt.wantPubKey, actualPubKey, "Public key mismatch")
186+
}
187+
188+
// Roundtrip test: verify the key can sign and verify
189+
message := []byte("test message")
190+
signature := ed25519.Sign(ed25519Key, message)
191+
pubKey := ed25519Key.Public().(ed25519.PublicKey)
192+
assert.True(t, ed25519.Verify(pubKey, message, signature), "Signature verification failed")
193+
})
194+
}
195+
}

0 commit comments

Comments
 (0)