Reject NKey files that are readable by group or others (permissions more permissive than 0600). This prevents accidental exposure of private keys through overly permissive file permissions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
151 lines
3.6 KiB
Go
151 lines
3.6 KiB
Go
package nats
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/nats-io/nkeys"
|
|
)
|
|
|
|
func TestConnect_InvalidNKeyFile(t *testing.T) {
|
|
cfg := Config{
|
|
URL: "nats://localhost:4222",
|
|
NKeyFile: "/nonexistent/file",
|
|
Name: "test",
|
|
}
|
|
|
|
_, err := Connect(cfg)
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent nkey file")
|
|
}
|
|
}
|
|
|
|
func TestConnect_InsecureNKeyFilePermissions(t *testing.T) {
|
|
// Create a temp file with insecure permissions
|
|
tmpDir := t.TempDir()
|
|
keyFile := filepath.Join(tmpDir, "insecure.nkey")
|
|
if err := os.WriteFile(keyFile, []byte("test-content"), 0644); err != nil {
|
|
t.Fatalf("failed to write temp file: %v", err)
|
|
}
|
|
|
|
cfg := Config{
|
|
URL: "nats://localhost:4222",
|
|
NKeyFile: keyFile,
|
|
Name: "test",
|
|
}
|
|
|
|
_, err := Connect(cfg)
|
|
if err == nil {
|
|
t.Error("expected error for insecure nkey file permissions")
|
|
}
|
|
if err != nil && !contains(err.Error(), "insecure permissions") {
|
|
t.Errorf("expected insecure permissions error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestConnect_InvalidNKeySeed(t *testing.T) {
|
|
// Create a temp file with invalid content
|
|
tmpDir := t.TempDir()
|
|
keyFile := filepath.Join(tmpDir, "invalid.nkey")
|
|
if err := os.WriteFile(keyFile, []byte("invalid-seed-content"), 0600); err != nil {
|
|
t.Fatalf("failed to write temp file: %v", err)
|
|
}
|
|
|
|
cfg := Config{
|
|
URL: "nats://localhost:4222",
|
|
NKeyFile: keyFile,
|
|
Name: "test",
|
|
}
|
|
|
|
_, err := Connect(cfg)
|
|
if err == nil {
|
|
t.Error("expected error for invalid nkey seed")
|
|
}
|
|
}
|
|
|
|
func TestConnect_ValidSeedParsing(t *testing.T) {
|
|
// Generate a valid NKey seed
|
|
kp, err := nkeys.CreateUser()
|
|
if err != nil {
|
|
t.Fatalf("failed to create nkey: %v", err)
|
|
}
|
|
|
|
seed, err := kp.Seed()
|
|
if err != nil {
|
|
t.Fatalf("failed to get seed: %v", err)
|
|
}
|
|
|
|
// Write seed to temp file
|
|
tmpDir := t.TempDir()
|
|
keyFile := filepath.Join(tmpDir, "test.nkey")
|
|
if err := os.WriteFile(keyFile, seed, 0600); err != nil {
|
|
t.Fatalf("failed to write temp file: %v", err)
|
|
}
|
|
|
|
cfg := Config{
|
|
URL: "nats://localhost:4222", // Connection will fail, but parsing should work
|
|
NKeyFile: keyFile,
|
|
Name: "test",
|
|
}
|
|
|
|
// Connection will fail since no NATS server is running, but we're testing
|
|
// that the seed parsing works correctly
|
|
_, err = Connect(cfg)
|
|
if err == nil {
|
|
// If it somehow connects (unlikely), that's also fine
|
|
return
|
|
}
|
|
|
|
// Error should be about connection, not about nkey parsing
|
|
if err != nil && !contains(err.Error(), "connect") && !contains(err.Error(), "connection") {
|
|
t.Errorf("expected connection error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestConnect_SeedWithWhitespace(t *testing.T) {
|
|
// Generate a valid NKey seed
|
|
kp, err := nkeys.CreateUser()
|
|
if err != nil {
|
|
t.Fatalf("failed to create nkey: %v", err)
|
|
}
|
|
|
|
seed, err := kp.Seed()
|
|
if err != nil {
|
|
t.Fatalf("failed to get seed: %v", err)
|
|
}
|
|
|
|
// Write seed with trailing newline
|
|
tmpDir := t.TempDir()
|
|
keyFile := filepath.Join(tmpDir, "test.nkey")
|
|
seedWithNewline := append(seed, '\n', ' ', '\t', '\n')
|
|
if err := os.WriteFile(keyFile, seedWithNewline, 0600); err != nil {
|
|
t.Fatalf("failed to write temp file: %v", err)
|
|
}
|
|
|
|
cfg := Config{
|
|
URL: "nats://localhost:4222",
|
|
NKeyFile: keyFile,
|
|
Name: "test",
|
|
}
|
|
|
|
// Should parse the seed correctly despite whitespace
|
|
_, err = Connect(cfg)
|
|
if err != nil && contains(err.Error(), "parse") {
|
|
t.Errorf("seed parsing should handle whitespace: %v", err)
|
|
}
|
|
}
|
|
|
|
func contains(s, substr string) bool {
|
|
return len(s) >= len(substr) && (s == substr || len(s) > 0 && containsHelper(s, substr))
|
|
}
|
|
|
|
func containsHelper(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|