diff options
author | FChannel <> | 2022-04-30 22:17:32 -0700 |
---|---|---|
committer | FChannel <> | 2022-06-19 12:53:29 -0700 |
commit | 503a6637b8294aeb8e5e5546f8acbd2b3d6c4744 (patch) | |
tree | 56614d955df0d3e7284baa997bbf1a8dcc2e78f5 /post | |
parent | 1892327cee2c3fa1d3bea729bd08eb63c2189a96 (diff) |
first steps in posting connected. can make reply with no quote or quote OP
do not recommend working on this branch for the time being since
things are being moved around a lot
Diffstat (limited to 'post')
-rw-r--r-- | post/tripcode.go | 116 | ||||
-rw-r--r-- | post/util.go | 285 |
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( + "&", "&", + "\"", """, + "<", "<", + ">", ">", + ) + + 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 } |