A clean, Markdown-based publishing platform made for writers. Write together, and build a community. https://writefreely.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

161 lines
3.8 KiB

  1. /*
  2. * Copyright © 2020-2021 Musing Studio LLC.
  3. *
  4. * This file is part of WriteFreely.
  5. *
  6. * WriteFreely is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License, included
  8. * in the LICENSE file in this source code package.
  9. */
  10. package writefreely
  11. import (
  12. "bytes"
  13. "fmt"
  14. "github.com/gorilla/mux"
  15. "github.com/writeas/impart"
  16. "github.com/writeas/web-core/log"
  17. "io"
  18. "net/http"
  19. "net/url"
  20. "os"
  21. "strings"
  22. )
  23. func displayMonetization(monetization, alias string) string {
  24. if monetization == "" {
  25. return ""
  26. }
  27. ptrURL, err := url.Parse(strings.Replace(monetization, "$", "https://", 1))
  28. if err == nil {
  29. if strings.HasSuffix(ptrURL.Host, ".xrptipbot.com") {
  30. // xrp tip bot doesn't support stream receipts, so return plain pointer
  31. return monetization
  32. }
  33. }
  34. u := os.Getenv("PAYMENT_HOST")
  35. if u == "" {
  36. return "$webmonetization.org/api/receipts/" + url.PathEscape(monetization)
  37. }
  38. u += "/" + alias
  39. return u
  40. }
  41. func handleSPSPEndpoint(app *App, w http.ResponseWriter, r *http.Request) error {
  42. idStr := r.FormValue("id")
  43. id, err := url.QueryUnescape(idStr)
  44. if err != nil {
  45. log.Error("Unable to unescape: %s", err)
  46. return err
  47. }
  48. var c *Collection
  49. if strings.IndexRune(id, '.') > 0 && app.cfg.App.SingleUser {
  50. c, err = app.db.GetCollectionByID(1)
  51. } else {
  52. c, err = app.db.GetCollection(id)
  53. }
  54. if err != nil {
  55. return err
  56. }
  57. pointer := c.Monetization
  58. if pointer == "" {
  59. err := impart.HTTPError{http.StatusNotFound, "No monetization pointer."}
  60. return err
  61. }
  62. fmt.Fprintf(w, pointer)
  63. return nil
  64. }
  65. func handleGetSplitContent(app *App, w http.ResponseWriter, r *http.Request) error {
  66. var collID int64
  67. var collLookupID string
  68. var coll *Collection
  69. var err error
  70. vars := mux.Vars(r)
  71. if collAlias := vars["alias"]; collAlias != "" {
  72. // Fetch collection information, since an alias is provided
  73. coll, err = app.db.GetCollection(collAlias)
  74. if err != nil {
  75. return err
  76. }
  77. collID = coll.ID
  78. collLookupID = coll.Alias
  79. }
  80. p, err := app.db.GetPost(vars["post"], collID)
  81. if err != nil {
  82. return err
  83. }
  84. receipt := r.FormValue("receipt")
  85. if receipt == "" {
  86. return impart.HTTPError{http.StatusBadRequest, "No `receipt` given."}
  87. }
  88. err = verifyReceipt(receipt, collLookupID)
  89. if err != nil {
  90. return err
  91. }
  92. d := struct {
  93. Content string `json:"body"`
  94. HTMLContent string `json:"html_body"`
  95. }{}
  96. if exc := strings.Index(p.Content, shortCodePaid); exc > -1 {
  97. baseURL := ""
  98. if coll != nil {
  99. baseURL = coll.CanonicalURL()
  100. }
  101. d.Content = p.Content[exc+len(shortCodePaid):]
  102. d.HTMLContent = applyMarkdown([]byte(d.Content), baseURL, app.cfg)
  103. }
  104. return impart.WriteSuccess(w, d, http.StatusOK)
  105. }
  106. func verifyReceipt(receipt, id string) error {
  107. receiptsHost := os.Getenv("RECEIPTS_HOST")
  108. if receiptsHost == "" {
  109. receiptsHost = "https://webmonetization.org/api/receipts/verify?id=" + id
  110. } else {
  111. receiptsHost = fmt.Sprintf("%s/receipts?id=%s", receiptsHost, id)
  112. }
  113. log.Info("Verifying receipt %s at %s", receipt, receiptsHost)
  114. r, err := http.NewRequest("POST", receiptsHost, bytes.NewBufferString(receipt))
  115. if err != nil {
  116. log.Error("Unable to create new request to %s: %s", receiptsHost, err)
  117. return err
  118. }
  119. resp, err := http.DefaultClient.Do(r)
  120. if err != nil {
  121. log.Error("Unable to Do() request to %s: %s", receiptsHost, err)
  122. return err
  123. }
  124. if resp != nil && resp.Body != nil {
  125. defer resp.Body.Close()
  126. }
  127. body, err := io.ReadAll(resp.Body)
  128. if err != nil {
  129. log.Error("Unable to read %s response body: %s", receiptsHost, err)
  130. return err
  131. }
  132. log.Info("Status : %s", resp.Status)
  133. log.Info("Response: %s", body)
  134. if resp.StatusCode != http.StatusOK {
  135. log.Error("Bad response from %s:\nStatus: %d\n%s", receiptsHost, resp.StatusCode, string(body))
  136. return impart.HTTPError{resp.StatusCode, string(body)}
  137. }
  138. return nil
  139. }