ssl-error-detection.test.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /**
  2. * SSL Certificate Error Detection Tests
  3. *
  4. * TDD: Tests written first, implementation follows
  5. */
  6. import { describe, expect, it } from "vitest";
  7. import { isSSLCertificateError } from "@/app/v1/_lib/proxy/errors";
  8. describe("isSSLCertificateError", () => {
  9. describe("should detect SSL certificate errors", () => {
  10. it("should detect certificate hostname mismatch", () => {
  11. const error = new Error("Hostname/IP does not match certificate's altnames");
  12. expect(isSSLCertificateError(error)).toBe(true);
  13. });
  14. it("should detect ERR_TLS_CERT_ALTNAME_INVALID", () => {
  15. const error = new Error("ERR_TLS_CERT_ALTNAME_INVALID");
  16. expect(isSSLCertificateError(error)).toBe(true);
  17. });
  18. it("should detect self-signed certificate error", () => {
  19. const error = new Error("self signed certificate");
  20. expect(isSSLCertificateError(error)).toBe(true);
  21. });
  22. it("should detect depth_zero_self_signed_cert", () => {
  23. const error = new Error("depth_zero_self_signed_cert");
  24. expect(isSSLCertificateError(error)).toBe(true);
  25. });
  26. it("should detect expired certificate error", () => {
  27. const error = new Error("certificate has expired");
  28. expect(isSSLCertificateError(error)).toBe(true);
  29. });
  30. it("should detect cert_has_expired", () => {
  31. const error = new Error("cert_has_expired");
  32. expect(isSSLCertificateError(error)).toBe(true);
  33. });
  34. it("should detect unable to verify certificate", () => {
  35. const error = new Error("unable to verify the first certificate");
  36. expect(isSSLCertificateError(error)).toBe(true);
  37. });
  38. it("should detect unable_to_verify_leaf_signature", () => {
  39. const error = new Error("unable_to_verify_leaf_signature");
  40. expect(isSSLCertificateError(error)).toBe(true);
  41. });
  42. it("should detect unable_to_get_issuer_cert", () => {
  43. const error = new Error("unable_to_get_issuer_cert");
  44. expect(isSSLCertificateError(error)).toBe(true);
  45. });
  46. it("should detect SSL handshake error", () => {
  47. const error = new Error("SSL handshake failed");
  48. expect(isSSLCertificateError(error)).toBe(true);
  49. });
  50. it("should detect TLS error", () => {
  51. const error = new Error("TLS connection failed");
  52. expect(isSSLCertificateError(error)).toBe(true);
  53. });
  54. it("should detect certificate chain error", () => {
  55. const error = new Error("certificate chain is invalid");
  56. expect(isSSLCertificateError(error)).toBe(true);
  57. });
  58. it("should detect CERT_UNTRUSTED", () => {
  59. const error = new Error("CERT_UNTRUSTED");
  60. expect(isSSLCertificateError(error)).toBe(true);
  61. });
  62. it("should detect error with code property", () => {
  63. const error = new Error("Connection failed") as NodeJS.ErrnoException;
  64. error.code = "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
  65. expect(isSSLCertificateError(error)).toBe(true);
  66. });
  67. it("should detect error with name containing SSL", () => {
  68. const error = new Error("Connection failed");
  69. error.name = "SSLError";
  70. expect(isSSLCertificateError(error)).toBe(true);
  71. });
  72. });
  73. describe("should not match non-SSL errors", () => {
  74. it("should not match connection refused error", () => {
  75. const error = new Error("Connection refused");
  76. expect(isSSLCertificateError(error)).toBe(false);
  77. });
  78. it("should not match timeout error", () => {
  79. const error = new Error("Request timeout");
  80. expect(isSSLCertificateError(error)).toBe(false);
  81. });
  82. it("should not match DNS error", () => {
  83. const error = new Error("getaddrinfo ENOTFOUND api.example.com");
  84. expect(isSSLCertificateError(error)).toBe(false);
  85. });
  86. it("should not match network unreachable error", () => {
  87. const error = new Error("Network is unreachable");
  88. expect(isSSLCertificateError(error)).toBe(false);
  89. });
  90. it("should not match HTTP error", () => {
  91. const error = new Error("HTTP 500 Internal Server Error");
  92. expect(isSSLCertificateError(error)).toBe(false);
  93. });
  94. it("should not match abort error", () => {
  95. const error = new Error("The operation was aborted");
  96. error.name = "AbortError";
  97. expect(isSSLCertificateError(error)).toBe(false);
  98. });
  99. it("should not match ECONNRESET", () => {
  100. const error = new Error("Connection reset by peer") as NodeJS.ErrnoException;
  101. error.code = "ECONNRESET";
  102. expect(isSSLCertificateError(error)).toBe(false);
  103. });
  104. it("should not match ETIMEDOUT", () => {
  105. const error = new Error("Connection timed out") as NodeJS.ErrnoException;
  106. error.code = "ETIMEDOUT";
  107. expect(isSSLCertificateError(error)).toBe(false);
  108. });
  109. it("should not match generic error", () => {
  110. const error = new Error("Something went wrong");
  111. expect(isSSLCertificateError(error)).toBe(false);
  112. });
  113. it("should not match empty error message", () => {
  114. const error = new Error("");
  115. expect(isSSLCertificateError(error)).toBe(false);
  116. });
  117. });
  118. describe("edge cases", () => {
  119. it("should handle non-Error objects", () => {
  120. expect(isSSLCertificateError("certificate error")).toBe(false);
  121. expect(isSSLCertificateError(null)).toBe(false);
  122. expect(isSSLCertificateError(undefined)).toBe(false);
  123. expect(isSSLCertificateError(123)).toBe(false);
  124. expect(isSSLCertificateError({})).toBe(false);
  125. });
  126. it("should handle Error with undefined message", () => {
  127. const error = new Error();
  128. expect(isSSLCertificateError(error)).toBe(false);
  129. });
  130. it("should be case insensitive", () => {
  131. expect(isSSLCertificateError(new Error("CERTIFICATE ERROR"))).toBe(true);
  132. expect(isSSLCertificateError(new Error("Certificate Error"))).toBe(true);
  133. expect(isSSLCertificateError(new Error("SSL_ERROR"))).toBe(true);
  134. expect(isSSLCertificateError(new Error("Ssl_Error"))).toBe(true);
  135. });
  136. it("should detect SSL error in nested cause", () => {
  137. const cause = new Error("self signed certificate");
  138. const error = new Error("Request failed", { cause });
  139. // Note: This test documents expected behavior - implementation may need to check cause
  140. expect(isSSLCertificateError(error)).toBe(true);
  141. });
  142. });
  143. });