nodeinfo.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. package controllers
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/url"
  6. "github.com/owncast/owncast/activitypub/apmodels"
  7. "github.com/owncast/owncast/activitypub/crypto"
  8. "github.com/owncast/owncast/activitypub/persistence"
  9. "github.com/owncast/owncast/activitypub/requests"
  10. "github.com/owncast/owncast/config"
  11. "github.com/owncast/owncast/core/data"
  12. log "github.com/sirupsen/logrus"
  13. )
  14. // NodeInfoController returns the V1 node info response.
  15. func NodeInfoController(w http.ResponseWriter, r *http.Request) {
  16. type links struct {
  17. Rel string `json:"rel"`
  18. Href string `json:"href"`
  19. }
  20. type response struct {
  21. Links []links `json:"links"`
  22. }
  23. if !data.GetFederationEnabled() {
  24. w.WriteHeader(http.StatusMethodNotAllowed)
  25. return
  26. }
  27. serverURL := data.GetServerURL()
  28. if serverURL == "" {
  29. w.WriteHeader(http.StatusNotFound)
  30. return
  31. }
  32. v2, err := url.Parse(serverURL)
  33. if err != nil {
  34. w.WriteHeader(http.StatusInternalServerError)
  35. return
  36. }
  37. v2.Path = "nodeinfo/2.0"
  38. res := response{
  39. Links: []links{
  40. {
  41. Rel: "http://nodeinfo.diaspora.software/ns/schema/2.0",
  42. Href: v2.String(),
  43. },
  44. },
  45. }
  46. if err := writeResponse(res, w); err != nil {
  47. log.Errorln(err)
  48. }
  49. }
  50. // NodeInfoV2Controller returns the V2 node info response.
  51. func NodeInfoV2Controller(w http.ResponseWriter, r *http.Request) {
  52. type software struct {
  53. Name string `json:"name"`
  54. Version string `json:"version"`
  55. }
  56. type users struct {
  57. Total int `json:"total"`
  58. ActiveMonth int `json:"activeMonth"`
  59. ActiveHalfyear int `json:"activeHalfyear"`
  60. }
  61. type usage struct {
  62. Users users `json:"users"`
  63. LocalPosts int `json:"localPosts"`
  64. }
  65. type response struct {
  66. Version string `json:"version"`
  67. Software software `json:"software"`
  68. Protocols []string `json:"protocols"`
  69. Usage usage `json:"usage"`
  70. OpenRegistrations bool `json:"openRegistrations"`
  71. }
  72. if !data.GetFederationEnabled() {
  73. w.WriteHeader(http.StatusMethodNotAllowed)
  74. return
  75. }
  76. localPostCount, _ := persistence.GetLocalPostCount()
  77. res := response{
  78. Version: "2.0",
  79. Software: software{
  80. Name: "Owncast",
  81. Version: config.VersionNumber,
  82. },
  83. Usage: usage{
  84. Users: users{
  85. Total: 1,
  86. ActiveMonth: 1,
  87. ActiveHalfyear: 1,
  88. },
  89. LocalPosts: int(localPostCount),
  90. },
  91. OpenRegistrations: false,
  92. Protocols: []string{"activitypub"},
  93. }
  94. if err := writeResponse(res, w); err != nil {
  95. log.Errorln(err)
  96. }
  97. }
  98. // XNodeInfo2Controller returns the x-nodeinfo2.
  99. func XNodeInfo2Controller(w http.ResponseWriter, r *http.Request) {
  100. type Organization struct {
  101. Name string `json:"name"`
  102. Contact string `json:"contact"`
  103. }
  104. type Server struct {
  105. BaseURL string `json:"baseUrl"`
  106. Version string `json:"version"`
  107. Name string `json:"name"`
  108. Software string `json:"software"`
  109. }
  110. type Services struct {
  111. Outbound []string `json:"outbound"`
  112. Inbound []string `json:"inbound"`
  113. }
  114. type Users struct {
  115. ActiveWeek int `json:"activeWeek"`
  116. Total int `json:"total"`
  117. ActiveMonth int `json:"activeMonth"`
  118. ActiveHalfyear int `json:"activeHalfyear"`
  119. }
  120. type Usage struct {
  121. Users Users `json:"users"`
  122. LocalPosts int `json:"localPosts"`
  123. LocalComments int `json:"localComments"`
  124. }
  125. type response struct {
  126. Organization Organization `json:"organization"`
  127. Server Server `json:"server"`
  128. Services Services `json:"services"`
  129. Protocols []string `json:"protocols"`
  130. Version string `json:"version"`
  131. OpenRegistrations bool `json:"openRegistrations"`
  132. Usage Usage `json:"usage"`
  133. }
  134. if !data.GetFederationEnabled() {
  135. w.WriteHeader(http.StatusMethodNotAllowed)
  136. return
  137. }
  138. serverURL := data.GetServerURL()
  139. if serverURL == "" {
  140. w.WriteHeader(http.StatusNotFound)
  141. return
  142. }
  143. localPostCount, _ := persistence.GetLocalPostCount()
  144. res := &response{
  145. Organization: Organization{
  146. Name: data.GetServerName(),
  147. Contact: serverURL,
  148. },
  149. Server: Server{
  150. BaseURL: serverURL,
  151. Version: config.VersionNumber,
  152. Name: "owncast",
  153. Software: "owncast",
  154. },
  155. Services: Services{
  156. Inbound: []string{"activitypub"},
  157. Outbound: []string{"activitypub"},
  158. },
  159. Protocols: []string{"activitypub"},
  160. Version: config.VersionNumber,
  161. Usage: Usage{
  162. Users: Users{
  163. ActiveWeek: 1,
  164. Total: 1,
  165. ActiveMonth: 1,
  166. ActiveHalfyear: 1,
  167. },
  168. LocalPosts: int(localPostCount),
  169. LocalComments: 0,
  170. },
  171. }
  172. if err := writeResponse(res, w); err != nil {
  173. log.Errorln(err)
  174. }
  175. }
  176. // InstanceV1Controller returns the v1 instance details.
  177. func InstanceV1Controller(w http.ResponseWriter, r *http.Request) {
  178. type Stats struct {
  179. UserCount int `json:"user_count"`
  180. StatusCount int `json:"status_count"`
  181. DomainCount int `json:"domain_count"`
  182. }
  183. type response struct {
  184. URI string `json:"uri"`
  185. Title string `json:"title"`
  186. ShortDescription string `json:"short_description"`
  187. Description string `json:"description"`
  188. Version string `json:"version"`
  189. Stats Stats `json:"stats"`
  190. Thumbnail string `json:"thumbnail"`
  191. Languages []string `json:"languages"`
  192. Registrations bool `json:"registrations"`
  193. ApprovalRequired bool `json:"approval_required"`
  194. InvitesEnabled bool `json:"invites_enabled"`
  195. }
  196. if !data.GetFederationEnabled() {
  197. w.WriteHeader(http.StatusMethodNotAllowed)
  198. return
  199. }
  200. serverURL := data.GetServerURL()
  201. if serverURL == "" {
  202. w.WriteHeader(http.StatusNotFound)
  203. return
  204. }
  205. thumbnail, err := url.Parse(serverURL)
  206. if err != nil {
  207. w.WriteHeader(http.StatusInternalServerError)
  208. return
  209. }
  210. thumbnail.Path = "/logo/external"
  211. localPostCount, _ := persistence.GetLocalPostCount()
  212. res := response{
  213. URI: serverURL,
  214. Title: data.GetServerName(),
  215. ShortDescription: data.GetServerSummary(),
  216. Description: data.GetServerSummary(),
  217. Version: config.GetReleaseString(),
  218. Stats: Stats{
  219. UserCount: 1,
  220. StatusCount: int(localPostCount),
  221. DomainCount: 0,
  222. },
  223. Thumbnail: thumbnail.String(),
  224. Registrations: false,
  225. ApprovalRequired: false,
  226. InvitesEnabled: false,
  227. }
  228. if err := writeResponse(res, w); err != nil {
  229. log.Errorln(err)
  230. }
  231. }
  232. func writeResponse(payload interface{}, w http.ResponseWriter) error {
  233. accountName := data.GetDefaultFederationUsername()
  234. actorIRI := apmodels.MakeLocalIRIForAccount(accountName)
  235. publicKey := crypto.GetPublicKey(actorIRI)
  236. return requests.WritePayloadResponse(payload, w, publicKey)
  237. }
  238. // HostMetaController points to webfinger.
  239. func HostMetaController(w http.ResponseWriter, r *http.Request) {
  240. serverURL := data.GetServerURL()
  241. if serverURL == "" {
  242. w.WriteHeader(http.StatusNotFound)
  243. return
  244. }
  245. res := fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?>
  246. <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
  247. <Link rel="lrdd" type="application/json" template="%s/.well-known/webfinger?resource={uri}"/>
  248. </XRD>`, serverURL)
  249. if _, err := w.Write([]byte(res)); err != nil {
  250. log.Errorln(err)
  251. }
  252. }