mitm.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package clashapi
  2. import (
  3. "context"
  4. "net/http"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing/common"
  7. "github.com/sagernet/sing/service"
  8. "github.com/go-chi/chi/v5"
  9. "github.com/go-chi/render"
  10. "github.com/gofrs/uuid/v5"
  11. "howett.net/plist"
  12. )
  13. func mitmRouter(ctx context.Context) http.Handler {
  14. r := chi.NewRouter()
  15. r.Get("/mobileconfig", getMobileConfig(ctx))
  16. r.Get("/certificate", getCertificate(ctx))
  17. return r
  18. }
  19. func getMobileConfig(ctx context.Context) http.HandlerFunc {
  20. return func(writer http.ResponseWriter, request *http.Request) {
  21. engine := service.FromContext[adapter.MITMEngine](ctx)
  22. if engine == nil {
  23. http.NotFound(writer, request)
  24. render.PlainText(writer, request, "MITM not enabled")
  25. return
  26. }
  27. certificate := engine.ExportCertificate()
  28. if certificate == nil {
  29. http.NotFound(writer, request)
  30. render.PlainText(writer, request, "Certificate not configured")
  31. return
  32. }
  33. writer.Header().Set("Content-Type", "application/x-apple-aspen-config")
  34. uuidGen := common.Must1(uuid.NewV4()).String()
  35. mobileConfig := map[string]interface{}{
  36. "PayloadContent": []interface{}{
  37. map[string]interface{}{
  38. "PayloadCertificateFileName": "Certificates.cer",
  39. "PayloadContent": certificate.Raw,
  40. "PayloadDescription": "Adds a root certificate",
  41. "PayloadDisplayName": certificate.Subject.CommonName,
  42. "PayloadIdentifier": "com.apple.security.root." + uuidGen,
  43. "PayloadType": "com.apple.security.root",
  44. "PayloadUUID": uuidGen,
  45. "PayloadVersion": 1,
  46. },
  47. },
  48. "PayloadDisplayName": certificate.Subject.CommonName,
  49. "PayloadIdentifier": "io.nekohasekai.sfa.ca.profile." + uuidGen,
  50. "PayloadRemovalDisallowed": false,
  51. "PayloadType": "Configuration",
  52. "PayloadUUID": uuidGen,
  53. "PayloadVersion": 1,
  54. }
  55. encoder := plist.NewEncoder(writer)
  56. encoder.Indent("\t")
  57. encoder.Encode(mobileConfig)
  58. }
  59. }
  60. func getCertificate(ctx context.Context) http.HandlerFunc {
  61. return func(writer http.ResponseWriter, request *http.Request) {
  62. engine := service.FromContext[adapter.MITMEngine](ctx)
  63. if engine == nil {
  64. http.NotFound(writer, request)
  65. render.PlainText(writer, request, "MITM not enabled")
  66. return
  67. }
  68. certificate := engine.ExportCertificate()
  69. if certificate == nil {
  70. http.NotFound(writer, request)
  71. render.PlainText(writer, request, "Certificate not configured")
  72. return
  73. }
  74. writer.Header().Set("Content-Type", "application/x-x509-ca-cert")
  75. writer.Header().Set("Content-Disposition", "attachment; filename=Certificate.crt")
  76. writer.Write(certificate.Raw)
  77. }
  78. }