aboutsummaryrefslogtreecommitdiff
path: root/post
diff options
context:
space:
mode:
Diffstat (limited to 'post')
-rw-r--r--post/tripcode.go116
-rw-r--r--post/util.go285
2 files changed, 355 insertions, 46 deletions
diff --git a/post/tripcode.go b/post/tripcode.go
new file mode 100644
index 0000000..3b7e48b
--- /dev/null
+++ b/post/tripcode.go
@@ -0,0 +1,116 @@
+package post
+
+import (
+ "bytes"
+ "regexp"
+ "strings"
+
+ "github.com/FChannel0/FChannel-Server/config"
+ "github.com/gofiber/fiber/v2"
+ _ "github.com/lib/pq"
+ "github.com/simia-tech/crypt"
+ "golang.org/x/text/encoding/japanese"
+ "golang.org/x/text/transform"
+)
+
+const SaltTable = "" +
+ "................................" +
+ ".............../0123456789ABCDEF" +
+ "GABCDEFGHIJKLMNOPQRSTUVWXYZabcde" +
+ "fabcdefghijklmnopqrstuvwxyz....." +
+ "................................" +
+ "................................" +
+ "................................" +
+ "................................"
+
+func TripCode(pass string) (string, error) {
+ pass = TripCodeConvert(pass)
+
+ var salt [2]rune
+
+ s := []rune(pass + "H..")[1:3]
+
+ for i, r := range s {
+ salt[i] = rune(SaltTable[r%256])
+ }
+
+ enc, err := crypt.Crypt(pass, "$1$"+string(salt[:]))
+ if err != nil {
+ return "", err
+ }
+
+ // normally i would just return error here but if the encrypt fails, this operation may fail and as a result cause a panic
+ return enc[len(enc)-10 : len(enc)], nil
+}
+
+func TripCodeSecure(pass string) (string, error) {
+ pass = TripCodeConvert(pass)
+
+ enc, err := crypt.Crypt(pass, "$1$"+config.Salt)
+ if err != nil {
+ return "", err
+ }
+
+ return enc[len(enc)-10 : len(enc)], nil
+}
+
+func TripCodeConvert(str string) string {
+ var s bytes.Buffer
+
+ transform.NewWriter(&s, japanese.ShiftJIS.NewEncoder()).Write([]byte(str))
+
+ re := strings.NewReplacer(
+ "&", "&",
+ "\"", """,
+ "<", "&lt;",
+ ">", "&gt;",
+ )
+
+ return re.Replace(s.String())
+}
+
+func CreateNameTripCode(ctx *fiber.Ctx) (string, string, error) {
+ // TODO: to allow this to compile, this will fail for the case of the admin
+ // this can be easily fixed when the rest of the code gets converted to fiber
+
+ input := ctx.FormValue("name")
+
+ tripSecure := regexp.MustCompile("##(.+)?")
+
+ if tripSecure.MatchString(input) {
+ chunck := tripSecure.FindString(input)
+ chunck = strings.Replace(chunck, "##", "", 1)
+
+ //ce := regexp.MustCompile(`(?i)Admin`)
+ //admin := ce.MatchString(chunck)
+
+ //board, modcred := GetPasswordFromSession(r)
+
+ //if admin && HasAuth(modcred, board) {
+ // return tripSecure.ReplaceAllString(input, ""), "#Admin"
+ //}
+
+ hash, err := TripCodeSecure(chunck)
+ return tripSecure.ReplaceAllString(input, ""), "!!" + hash, err
+ }
+
+ trip := regexp.MustCompile("#(.+)?")
+
+ if trip.MatchString(input) {
+ chunck := trip.FindString(input)
+ chunck = strings.Replace(chunck, "#", "", 1)
+
+ //ce := regexp.MustCompile(`(?i)Admin`)
+ //admin := ce.MatchString(chunck)
+ //board, modcred := GetPasswordFromSession(r)
+
+ //if admin && HasAuth(db, modcred, board) {
+ // return trip.ReplaceAllString(input, ""), "#Admin"
+ //}
+
+ hash, err := TripCode(chunck)
+ return trip.ReplaceAllString(input, ""), "!" + hash, err
+ }
+
+ return input, "", nil
+}
diff --git a/post/util.go b/post/util.go
index c4920f7..cead842 100644
--- a/post/util.go
+++ b/post/util.go
@@ -1,93 +1,286 @@
package post
import (
+ "io/ioutil"
"mime/multipart"
- "net/http"
+ "os"
+ "os/exec"
"regexp"
+ "strings"
+ "time"
+ "github.com/FChannel0/FChannel-Server/activitypub"
"github.com/FChannel0/FChannel-Server/config"
+ "github.com/FChannel0/FChannel-Server/db"
+ "github.com/FChannel0/FChannel-Server/util"
+ "github.com/FChannel0/FChannel-Server/webfinger"
+ "github.com/gofiber/fiber/v2"
)
-type PostBlacklist struct {
- Id int
- Regex string
-}
+func ParseCommentForReplies(comment string, op string) ([]activitypub.ObjectBase, error) {
+ re := regexp.MustCompile(`(>>(https?://[A-Za-z0-9_.:\-~]+\/[A-Za-z0-9_.\-~]+\/)(f[A-Za-z0-9_.\-~]+-)?([A-Za-z0-9_.\-~]+)?#?([A-Za-z0-9_.\-~]+)?)`)
+ match := re.FindAllStringSubmatch(comment, -1)
+
+ var links []string
-func DeleteRegexBlacklistDB(id int) error {
- query := `delete from postblacklist where id=$1`
+ for i := 0; i < len(match); i++ {
+ str := strings.Replace(match[i][0], ">>", "", 1)
+ str = strings.Replace(str, "www.", "", 1)
+ str = strings.Replace(str, "http://", "", 1)
+ str = strings.Replace(str, "https://", "", 1)
+ str = config.TP + "" + str
+ _, isReply, err := db.IsReplyToOP(op, str)
+ if err != nil {
+ return nil, err
+ }
- _, err := config.DB.Exec(query, id)
- return err
+ if !util.IsInStringArray(links, str) && isReply {
+ links = append(links, str)
+ }
+ }
+
+ var validLinks []activitypub.ObjectBase
+ for i := 0; i < len(links); i++ {
+ _, isValid, err := webfinger.CheckValidActivity(links[i])
+ if err != nil {
+ return nil, err
+ }
+
+ if isValid {
+ var reply activitypub.ObjectBase
+ reply.Id = links[i]
+ reply.Published = time.Now().UTC()
+ validLinks = append(validLinks, reply)
+ }
+ }
+
+ return validLinks, nil
}
-func GetFileContentType(out multipart.File) (string, error) {
- buffer := make([]byte, 512)
+func ParseCommentForReply(comment string) (string, error) {
+ re := regexp.MustCompile(`(>>(https?://[A-Za-z0-9_.:\-~]+\/[A-Za-z0-9_.\-~]+\/)(f[A-Za-z0-9_.\-~]+-)?([A-Za-z0-9_.\-~]+)?#?([A-Za-z0-9_.\-~]+)?)`)
+ match := re.FindAllStringSubmatch(comment, -1)
- _, err := out.Read(buffer)
- if err != nil {
- return "", err
+ var links []string
+
+ for i := 0; i < len(match); i++ {
+ str := strings.Replace(match[i][0], ">>", "", 1)
+ links = append(links, str)
+ }
+
+ if len(links) > 0 {
+ _, isValid, err := webfinger.CheckValidActivity(strings.ReplaceAll(links[0], ">", ""))
+ if err != nil {
+ return "", err
+ }
+
+ if isValid {
+ return links[0], nil
+ }
}
- out.Seek(0, 0)
+ return "", nil
+}
- contentType := http.DetectContentType(buffer)
+func ParseOptions(ctx *fiber.Ctx, obj activitypub.ObjectBase) activitypub.ObjectBase {
+ options := util.EscapeString(ctx.FormValue("options"))
+ if options != "" {
+ option := strings.Split(options, ";")
+ email := regexp.MustCompile(".+@.+\\..+")
+ wallet := regexp.MustCompile("wallet:.+")
+ delete := regexp.MustCompile("delete:.+")
+ for _, e := range option {
+ if e == "noko" {
+ obj.Option = append(obj.Option, "noko")
+ } else if e == "sage" {
+ obj.Option = append(obj.Option, "sage")
+ } else if e == "nokosage" {
+ obj.Option = append(obj.Option, "nokosage")
+ } else if email.MatchString(e) {
+ obj.Option = append(obj.Option, "email:"+e)
+ } else if wallet.MatchString(e) {
+ obj.Option = append(obj.Option, "wallet")
+ var wallet activitypub.CryptoCur
+ value := strings.Split(e, ":")
+ wallet.Type = value[0]
+ wallet.Address = value[1]
+ obj.Wallet = append(obj.Wallet, wallet)
+ } else if delete.MatchString(e) {
+ obj.Option = append(obj.Option, e)
+ }
+ }
+ }
- return contentType, nil
+ return obj
}
-func GetRegexBlacklistDB() ([]PostBlacklist, error) {
- var list []PostBlacklist
+func CheckCaptcha(captcha string) (bool, error) {
+ parts := strings.Split(captcha, ":")
- query := `select id, regex from postblacklist`
+ if strings.Trim(parts[0], " ") == "" || strings.Trim(parts[1], " ") == "" {
+ return false, nil
+ }
- rows, err := config.DB.Query(query)
+ path := "public/" + parts[0] + ".png"
+ code, err := db.GetCaptchaCodeDB(path)
if err != nil {
- return list, err
+ return false, err
}
- defer rows.Close()
- for rows.Next() {
- var temp PostBlacklist
- rows.Scan(&temp.Id, &temp.Regex)
+ if code != "" {
+ err = db.DeleteCaptchaCodeDB(path)
+ if err != nil {
+ return false, err
+ }
+
+ err = db.CreateNewCaptcha()
+ if err != nil {
+ return false, err
+ }
- list = append(list, temp)
}
- return list, nil
+ return code == strings.ToUpper(parts[1]), nil
}
-func IsPostBlacklist(comment string) (bool, error) {
- postblacklist, err := GetRegexBlacklistDB()
+func IsMediaBanned(f multipart.File) (bool, error) {
+ f.Seek(0, 0)
+ fileBytes := make([]byte, 2048)
+
+ _, err := f.Read(fileBytes)
if err != nil {
- return false, err
+ return true, err
}
- for _, e := range postblacklist {
- re := regexp.MustCompile(e.Regex)
+ hash := util.HashBytes(fileBytes)
+
+ // f.Seek(0, 0)
+ return db.IsHashBanned(hash)
+}
- if re.MatchString(comment) {
- return true, nil
+func SupportedMIMEType(mime string) bool {
+ for _, e := range config.SupportedFiles {
+ if e == mime {
+ return true
}
}
- return false, nil
+ return false
}
-func WriteRegexBlacklistDB(regex string) error {
- var re string
+func ObjectFromForm(ctx *fiber.Ctx, obj activitypub.ObjectBase) (activitypub.ObjectBase, error) {
- query := `select from postblacklist where regex=$1`
- if err := config.DB.QueryRow(query, regex).Scan(&re); err != nil {
- return err
+ header, _ := ctx.FormFile("file")
+
+ var file multipart.File
+
+ if header != nil {
+ file, _ = header.Open()
}
- if re != "" {
- return nil
+ var err error
+
+ if file != nil {
+ defer file.Close()
+
+ var tempFile = new(os.File)
+ obj.Attachment, tempFile, err = activitypub.CreateAttachmentObject(file, header)
+ if err != nil {
+ return obj, err
+ }
+
+ defer tempFile.Close()
+
+ fileBytes, _ := ioutil.ReadAll(file)
+
+ tempFile.Write(fileBytes)
+
+ re := regexp.MustCompile(`image/(jpe?g|png|webp)`)
+ if re.MatchString(obj.Attachment[0].MediaType) {
+ fileLoc := strings.ReplaceAll(obj.Attachment[0].Href, config.Domain, "")
+
+ cmd := exec.Command("exiv2", "rm", "."+fileLoc)
+
+ if err := cmd.Run(); err != nil {
+ return obj, err
+ }
+ }
+
+ obj.Preview = activitypub.CreatePreviewObject(obj.Attachment[0])
}
- query = `insert into postblacklist (regex) values ($1)`
+ obj.AttributedTo = util.EscapeString(ctx.FormValue("name"))
+ obj.TripCode = util.EscapeString(ctx.FormValue("tripcode"))
+ obj.Name = util.EscapeString(ctx.FormValue("subject"))
+ obj.Content = util.EscapeString(ctx.FormValue("comment"))
+ obj.Sensitive = (ctx.FormValue("sensitive") != "")
+
+ obj = ParseOptions(ctx, obj)
+
+ var originalPost activitypub.ObjectBase
+ originalPost.Id = util.EscapeString(ctx.FormValue("inReplyTo"))
+
+ obj.InReplyTo = append(obj.InReplyTo, originalPost)
+
+ var activity activitypub.Activity
+
+ if !util.IsInStringArray(activity.To, originalPost.Id) {
+ activity.To = append(activity.To, originalPost.Id)
+ }
+
+ if originalPost.Id != "" {
+ if local, _ := activitypub.IsActivityLocal(activity); !local {
+ actor, err := webfinger.FingerActor(originalPost.Id)
+ if err != nil {
+ return obj, err
+ }
+
+ if !util.IsInStringArray(obj.To, actor.Id) {
+ obj.To = append(obj.To, actor.Id)
+ }
+ } else if err != nil {
+ return obj, err
+ }
+ }
+
+ replyingTo, err := ParseCommentForReplies(ctx.FormValue("comment"), originalPost.Id)
+
+ if err != nil {
+ return obj, err
+ }
+
+ for _, e := range replyingTo {
+ has := false
+
+ for _, f := range obj.InReplyTo {
+ if e.Id == f.Id {
+ has = true
+ break
+ }
+ }
+
+ if !has {
+ obj.InReplyTo = append(obj.InReplyTo, e)
+
+ var activity activitypub.Activity
+
+ activity.To = append(activity.To, e.Id)
+
+ if local, err := activitypub.IsActivityLocal(activity); err == nil && !local {
+ actor, err := webfinger.FingerActor(e.Id)
+ if err != nil {
+ return obj, err
+ }
+
+ if !util.IsInStringArray(obj.To, actor.Id) {
+ obj.To = append(obj.To, actor.Id)
+ }
+ } else if err != nil {
+ return obj, err
+ }
+ }
+ }
- _, err := config.DB.Exec(query, regex)
- return err
+ return obj, nil
}