config.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. package server
  2. import (
  3. "crypto/sha256"
  4. "encoding/json"
  5. "fmt"
  6. "io/fs"
  7. "net/netip"
  8. "reflect"
  9. "text/template"
  10. "time"
  11. "heckel.io/ntfy/v2/user"
  12. )
  13. // Defines default config settings (excluding limits, see below)
  14. const (
  15. DefaultListenHTTP = ":80"
  16. DefaultCacheDuration = 12 * time.Hour
  17. DefaultCacheBatchTimeout = time.Duration(0)
  18. DefaultKeepaliveInterval = 45 * time.Second // Not too frequently to save battery (Android read timeout used to be 77s!)
  19. DefaultManagerInterval = time.Minute
  20. DefaultDelayedSenderInterval = 10 * time.Second
  21. DefaultMessageDelayMin = 10 * time.Second
  22. DefaultMessageDelayMax = 3 * 24 * time.Hour
  23. DefaultFirebaseKeepaliveInterval = 3 * time.Hour // ~control topic (Android), not too frequently to save battery
  24. DefaultFirebasePollInterval = 20 * time.Minute // ~poll topic (iOS), max. 2-3 times per hour (see docs)
  25. DefaultFirebaseQuotaExceededPenaltyDuration = 10 * time.Minute // Time that over-users are locked out of Firebase if it returns "quota exceeded"
  26. DefaultStripePriceCacheDuration = 3 * time.Hour // Time to keep Stripe prices cached in memory before a refresh is needed
  27. )
  28. // Platform-specific default paths (set in config_unix.go or config_windows.go)
  29. var (
  30. DefaultConfigFile string
  31. DefaultTemplateDir string
  32. )
  33. // Defines default Web Push settings
  34. const (
  35. DefaultWebPushExpiryWarningDuration = 55 * 24 * time.Hour
  36. DefaultWebPushExpiryDuration = 60 * 24 * time.Hour
  37. )
  38. // Defines all global and per-visitor limits
  39. // - message size limit: the max number of bytes for a message
  40. // - total topic limit: max number of topics overall
  41. // - various attachment limits
  42. const (
  43. DefaultMessageSizeLimit = 4096 // Bytes; note that FCM/APNS have a limit of ~4 KB for the entire message
  44. DefaultTotalTopicLimit = 15000
  45. DefaultAttachmentTotalSizeLimit = int64(5 * 1024 * 1024 * 1024) // 5 GB
  46. DefaultAttachmentFileSizeLimit = int64(15 * 1024 * 1024) // 15 MB
  47. DefaultAttachmentExpiryDuration = 3 * time.Hour
  48. )
  49. // Defines all per-visitor limits
  50. // - per visitor subscription limit: max number of subscriptions (active HTTP connections) per per-visitor/IP
  51. // - per visitor request limit: max number of PUT/GET/.. requests (here: 60 requests bucket, replenished at a rate of one per 5 seconds)
  52. // - per visitor email limit: max number of emails (here: 16 email bucket, replenished at a rate of one per hour)
  53. // - per visitor attachment size limit: total per-visitor attachment size in bytes to be stored on the server
  54. // - per visitor attachment daily bandwidth limit: number of bytes that can be transferred to/from the server
  55. const (
  56. DefaultVisitorSubscriptionLimit = 30
  57. DefaultVisitorRequestLimitBurst = 60
  58. DefaultVisitorRequestLimitReplenish = 5 * time.Second
  59. DefaultVisitorMessageDailyLimit = 0
  60. DefaultVisitorEmailLimitBurst = 16
  61. DefaultVisitorEmailLimitReplenish = time.Hour
  62. DefaultVisitorAccountCreationLimitBurst = 3
  63. DefaultVisitorAccountCreationLimitReplenish = 24 * time.Hour
  64. DefaultVisitorAuthFailureLimitBurst = 30
  65. DefaultVisitorAuthFailureLimitReplenish = time.Minute
  66. DefaultVisitorAttachmentTotalSizeLimit = 100 * 1024 * 1024 // 100 MB
  67. DefaultVisitorAttachmentDailyBandwidthLimit = 500 * 1024 * 1024 // 500 MB
  68. DefaultVisitorPrefixBitsIPv4 = 32 // Use the entire IPv4 address for rate limiting
  69. DefaultVisitorPrefixBitsIPv6 = 64 // Use /64 for IPv6 rate limiting
  70. )
  71. var (
  72. // DefaultVisitorStatsResetTime defines the time at which visitor stats are reset (wall clock only)
  73. DefaultVisitorStatsResetTime = time.Date(0, 0, 0, 0, 0, 0, 0, time.UTC)
  74. // DefaultDisallowedTopics defines the topics that are forbidden, because they are used elsewhere. This array can be
  75. // extended using the server.yml config. If updated, also update in Android and web app.
  76. DefaultDisallowedTopics = []string{"docs", "static", "file", "app", "metrics", "account", "settings", "signup", "login", "v1"}
  77. )
  78. // Config is the main config struct for the application. Use New to instantiate a default config struct.
  79. type Config struct {
  80. File string // Config file, only used for testing
  81. BaseURL string
  82. ListenHTTP string
  83. ListenHTTPS string
  84. ListenUnix string
  85. ListenUnixMode fs.FileMode
  86. KeyFile string
  87. CertFile string
  88. FirebaseKeyFile string
  89. CacheFile string
  90. CacheDuration time.Duration
  91. CacheStartupQueries string
  92. CacheBatchSize int
  93. CacheBatchTimeout time.Duration
  94. AuthFile string
  95. AuthStartupQueries string
  96. AuthDefault user.Permission
  97. AuthUsers []*user.User
  98. AuthAccess map[string][]*user.Grant
  99. AuthTokens map[string][]*user.Token
  100. AuthBcryptCost int
  101. AuthStatsQueueWriterInterval time.Duration
  102. AttachmentCacheDir string
  103. AttachmentTotalSizeLimit int64
  104. AttachmentFileSizeLimit int64
  105. AttachmentExpiryDuration time.Duration
  106. TemplateDir string // Directory to load named templates from
  107. KeepaliveInterval time.Duration
  108. ManagerInterval time.Duration
  109. DisallowedTopics []string
  110. WebRoot string // empty to disable
  111. DelayedSenderInterval time.Duration
  112. FirebaseKeepaliveInterval time.Duration
  113. FirebasePollInterval time.Duration
  114. FirebaseQuotaExceededPenaltyDuration time.Duration
  115. UpstreamBaseURL string
  116. UpstreamAccessToken string
  117. SMTPSenderAddr string
  118. SMTPSenderUser string
  119. SMTPSenderPass string
  120. SMTPSenderFrom string
  121. SMTPServerListen string
  122. SMTPServerDomain string
  123. SMTPServerAddrPrefix string
  124. TwilioAccount string
  125. TwilioAuthToken string
  126. TwilioPhoneNumber string
  127. TwilioCallsBaseURL string
  128. TwilioVerifyBaseURL string
  129. TwilioVerifyService string
  130. TwilioCallFormat *template.Template
  131. MetricsEnable bool
  132. MetricsListenHTTP string
  133. ProfileListenHTTP string
  134. MessageDelayMin time.Duration
  135. MessageDelayMax time.Duration
  136. MessageSizeLimit int
  137. TotalTopicLimit int
  138. TotalAttachmentSizeLimit int64
  139. VisitorSubscriptionLimit int
  140. VisitorAttachmentTotalSizeLimit int64
  141. VisitorAttachmentDailyBandwidthLimit int64
  142. VisitorRequestLimitBurst int
  143. VisitorRequestLimitReplenish time.Duration
  144. VisitorRequestExemptPrefixes []netip.Prefix
  145. VisitorMessageDailyLimit int
  146. VisitorEmailLimitBurst int
  147. VisitorEmailLimitReplenish time.Duration
  148. VisitorAccountCreationLimitBurst int
  149. VisitorAccountCreationLimitReplenish time.Duration
  150. VisitorAuthFailureLimitBurst int
  151. VisitorAuthFailureLimitReplenish time.Duration
  152. VisitorStatsResetTime time.Time // Time of the day at which to reset visitor stats
  153. VisitorSubscriberRateLimiting bool // Enable subscriber-based rate limiting for UnifiedPush topics
  154. VisitorPrefixBitsIPv4 int // Number of bits for IPv4 rate limiting (default: 32)
  155. VisitorPrefixBitsIPv6 int // Number of bits for IPv6 rate limiting (default: 64)
  156. BehindProxy bool // If true, the server will trust the proxy client IP header to determine the client IP address (IPv4 and IPv6 supported)
  157. ProxyForwardedHeader string // The header field to read the real/client IP address from, if BehindProxy is true, defaults to "X-Forwarded-For" (IPv4 and IPv6 supported)
  158. ProxyTrustedPrefixes []netip.Prefix // List of trusted proxy networks (IPv4 or IPv6) that will be stripped from the Forwarded header if BehindProxy is true
  159. StripeSecretKey string
  160. StripeWebhookKey string
  161. StripePriceCacheDuration time.Duration
  162. BillingContact string
  163. EnableSignup bool // Enable creation of accounts via API and UI
  164. EnableLogin bool
  165. RequireLogin bool
  166. EnableReservations bool // Allow users with role "user" to own/reserve topics
  167. EnableMetrics bool
  168. AccessControlAllowOrigin string // CORS header field to restrict access from web clients
  169. WebPushPrivateKey string
  170. WebPushPublicKey string
  171. WebPushFile string
  172. WebPushEmailAddress string
  173. WebPushStartupQueries string
  174. WebPushExpiryDuration time.Duration
  175. WebPushExpiryWarningDuration time.Duration
  176. BuildVersion string // Injected by App
  177. BuildDate string // Injected by App
  178. BuildCommit string // Injected by App
  179. }
  180. // NewConfig instantiates a default new server config
  181. func NewConfig() *Config {
  182. return &Config{
  183. File: DefaultConfigFile, // Only used for testing
  184. BaseURL: "",
  185. ListenHTTP: DefaultListenHTTP,
  186. ListenHTTPS: "",
  187. ListenUnix: "",
  188. ListenUnixMode: 0,
  189. KeyFile: "",
  190. CertFile: "",
  191. FirebaseKeyFile: "",
  192. CacheFile: "",
  193. CacheDuration: DefaultCacheDuration,
  194. CacheStartupQueries: "",
  195. CacheBatchSize: 0,
  196. CacheBatchTimeout: 0,
  197. AuthFile: "",
  198. AuthStartupQueries: "",
  199. AuthDefault: user.PermissionReadWrite,
  200. AuthBcryptCost: user.DefaultUserPasswordBcryptCost,
  201. AuthStatsQueueWriterInterval: user.DefaultUserStatsQueueWriterInterval,
  202. AttachmentCacheDir: "",
  203. AttachmentTotalSizeLimit: DefaultAttachmentTotalSizeLimit,
  204. AttachmentFileSizeLimit: DefaultAttachmentFileSizeLimit,
  205. AttachmentExpiryDuration: DefaultAttachmentExpiryDuration,
  206. TemplateDir: DefaultTemplateDir,
  207. KeepaliveInterval: DefaultKeepaliveInterval,
  208. ManagerInterval: DefaultManagerInterval,
  209. DisallowedTopics: DefaultDisallowedTopics,
  210. WebRoot: "/",
  211. DelayedSenderInterval: DefaultDelayedSenderInterval,
  212. FirebaseKeepaliveInterval: DefaultFirebaseKeepaliveInterval,
  213. FirebasePollInterval: DefaultFirebasePollInterval,
  214. FirebaseQuotaExceededPenaltyDuration: DefaultFirebaseQuotaExceededPenaltyDuration,
  215. UpstreamBaseURL: "",
  216. UpstreamAccessToken: "",
  217. SMTPSenderAddr: "",
  218. SMTPSenderUser: "",
  219. SMTPSenderPass: "",
  220. SMTPSenderFrom: "",
  221. SMTPServerListen: "",
  222. SMTPServerDomain: "",
  223. SMTPServerAddrPrefix: "",
  224. TwilioCallsBaseURL: "https://api.twilio.com", // Override for tests
  225. TwilioAccount: "",
  226. TwilioAuthToken: "",
  227. TwilioPhoneNumber: "",
  228. TwilioVerifyBaseURL: "https://verify.twilio.com", // Override for tests
  229. TwilioVerifyService: "",
  230. TwilioCallFormat: nil,
  231. MessageSizeLimit: DefaultMessageSizeLimit,
  232. MessageDelayMin: DefaultMessageDelayMin,
  233. MessageDelayMax: DefaultMessageDelayMax,
  234. TotalTopicLimit: DefaultTotalTopicLimit,
  235. TotalAttachmentSizeLimit: 0,
  236. VisitorSubscriptionLimit: DefaultVisitorSubscriptionLimit,
  237. VisitorSubscriberRateLimiting: false,
  238. VisitorAttachmentTotalSizeLimit: DefaultVisitorAttachmentTotalSizeLimit,
  239. VisitorAttachmentDailyBandwidthLimit: DefaultVisitorAttachmentDailyBandwidthLimit,
  240. VisitorRequestLimitBurst: DefaultVisitorRequestLimitBurst,
  241. VisitorRequestLimitReplenish: DefaultVisitorRequestLimitReplenish,
  242. VisitorRequestExemptPrefixes: make([]netip.Prefix, 0),
  243. VisitorMessageDailyLimit: DefaultVisitorMessageDailyLimit,
  244. VisitorEmailLimitBurst: DefaultVisitorEmailLimitBurst,
  245. VisitorEmailLimitReplenish: DefaultVisitorEmailLimitReplenish,
  246. VisitorAccountCreationLimitBurst: DefaultVisitorAccountCreationLimitBurst,
  247. VisitorAccountCreationLimitReplenish: DefaultVisitorAccountCreationLimitReplenish,
  248. VisitorAuthFailureLimitBurst: DefaultVisitorAuthFailureLimitBurst,
  249. VisitorAuthFailureLimitReplenish: DefaultVisitorAuthFailureLimitReplenish,
  250. VisitorStatsResetTime: DefaultVisitorStatsResetTime,
  251. VisitorPrefixBitsIPv4: DefaultVisitorPrefixBitsIPv4, // Default: use full IPv4 address
  252. VisitorPrefixBitsIPv6: DefaultVisitorPrefixBitsIPv6, // Default: use /64 for IPv6
  253. BehindProxy: false, // If true, the server will trust the proxy client IP header to determine the client IP address
  254. ProxyForwardedHeader: "X-Forwarded-For", // Default header for reverse proxy client IPs
  255. StripeSecretKey: "",
  256. StripeWebhookKey: "",
  257. StripePriceCacheDuration: DefaultStripePriceCacheDuration,
  258. BillingContact: "",
  259. EnableSignup: false,
  260. EnableLogin: false,
  261. EnableReservations: false,
  262. RequireLogin: false,
  263. AccessControlAllowOrigin: "*",
  264. WebPushPrivateKey: "",
  265. WebPushPublicKey: "",
  266. WebPushFile: "",
  267. WebPushEmailAddress: "",
  268. WebPushExpiryDuration: DefaultWebPushExpiryDuration,
  269. WebPushExpiryWarningDuration: DefaultWebPushExpiryWarningDuration,
  270. BuildVersion: "",
  271. BuildDate: "",
  272. BuildCommit: "",
  273. }
  274. }
  275. // Hash computes an SHA-256 hash of the configuration. This is used to detect
  276. // configuration changes for the web app version check feature. It uses reflection
  277. // to include all JSON-serializable fields automatically.
  278. func (c *Config) Hash() string {
  279. v := reflect.ValueOf(*c)
  280. t := v.Type()
  281. var result string
  282. for i := 0; i < v.NumField(); i++ {
  283. field := v.Field(i)
  284. fieldName := t.Field(i).Name
  285. // Try to marshal the field and skip if it fails (e.g. *template.Template, netip.Prefix)
  286. if b, err := json.Marshal(field.Interface()); err == nil {
  287. result += fmt.Sprintf("%s:%s|", fieldName, string(b))
  288. }
  289. }
  290. return fmt.Sprintf("%x", sha256.Sum256([]byte(result)))
  291. }