summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-10-20 20:38:08 +0300
committerAlexander Neonxp Kiryukhin <i@neonxp.ru>2024-10-20 20:38:08 +0300
commitb26bd10926447ed59cbf263aef087bb7c04f35eb (patch)
treed813a4bcfb6ae04be95966492e9c5d5963f3c90f /pkg
parentd9e19fc53fb386f4160b8c3e9d7c35aa217d9591 (diff)
Добавил /x/file*
Добавил Dockerfile
Diffstat (limited to 'pkg')
-rw-r--r--pkg/api/api.go8
-rw-r--r--pkg/api/file.go51
-rw-r--r--pkg/api/list.go11
-rw-r--r--pkg/api/message.go13
-rw-r--r--pkg/config/config.go13
-rw-r--r--pkg/fetcher/fetcher.go19
-rw-r--r--pkg/idec/blacklist.go65
-rw-r--r--pkg/idec/files.go74
-rw-r--r--pkg/idec/idec.go1
-rw-r--r--pkg/idec/point.go4
-rw-r--r--pkg/model/file.go7
11 files changed, 250 insertions, 16 deletions
diff --git a/pkg/api/api.go b/pkg/api/api.go
index 6bbdd30..fd55f1d 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -30,15 +30,19 @@ func (a *API) Run(ctx context.Context) error {
mux := http.NewServeMux()
mux.HandleFunc(`GET /list.txt`, a.getListHandler)
- mux.HandleFunc(`GET /blacklist.txt`, a.getBlacklistTxtHandler)
+ mux.HandleFunc(`GET /blacklist.txt`, a.getBlacklistHandler)
mux.HandleFunc(`GET /u/e/{ids...}`, a.getEchosHandler)
mux.HandleFunc(`GET /u/m/{ids...}`, a.getBundleHandler)
- mux.HandleFunc(`GET /u/point/{pauth}/{tmsg}`, a.getPointHandler)
+ mux.HandleFunc(`GET /u/point/{pauth}/{tmsg}`, a.postPointHandler)
mux.HandleFunc(`POST /u/point`, a.postPointHandler)
mux.HandleFunc(`GET /m/{msgID}`, a.getMessageHandler)
mux.HandleFunc(`GET /e/{id}`, a.getEchoHandler)
mux.HandleFunc(`GET /x/features`, a.getFeaturesHandler)
mux.HandleFunc(`GET /x/c/{ids...}`, a.getEchosInfo)
+ mux.HandleFunc(`POST /x/filelist`, a.getFilelistHandler)
+ mux.HandleFunc(`GET /x/filelist/{pauth}`, a.getFilelistHandler)
+ mux.HandleFunc(`POST /x/file`, a.getFileHandler)
+ mux.HandleFunc(`GET /x/file/{filename}`, a.getFileHandler)
srv := http.Server{
Addr: a.config.Listen,
diff --git a/pkg/api/file.go b/pkg/api/file.go
new file mode 100644
index 0000000..e2fa8d9
--- /dev/null
+++ b/pkg/api/file.go
@@ -0,0 +1,51 @@
+package api
+
+import (
+ "fmt"
+ "net/http"
+)
+
+func (a *API) getFilelistHandler(w http.ResponseWriter, r *http.Request) {
+ pauth := r.PathValue("pauth")
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+
+ return
+ }
+ form := r.PostForm
+ if form.Has("pauth") {
+ pauth = form.Get("pauth")
+ }
+
+ files, err := a.idec.FilesList(pauth)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+
+ return
+ }
+
+ for _, file := range files {
+ fmt.Fprintf(w, "%s:%d:%s\n", file.FullName, file.Size, file.Name)
+ }
+}
+
+func (a *API) getFileHandler(w http.ResponseWriter, r *http.Request) {
+ filename := r.PathValue("filename")
+ pauth := ""
+ if err := r.ParseForm(); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+
+ return
+ }
+ form := r.PostForm
+ if form.Has("pauth") {
+ pauth = form.Get("pauth")
+ }
+ if form.Has("filename") {
+ filename = form.Get("filename")
+ }
+
+ if err := a.idec.GetFile(pauth, filename, w); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+}
diff --git a/pkg/api/list.go b/pkg/api/list.go
index 812bb0f..80a34ea 100644
--- a/pkg/api/list.go
+++ b/pkg/api/list.go
@@ -3,6 +3,7 @@ package api
import (
"fmt"
"net/http"
+ "strings"
)
func (a *API) getListHandler(w http.ResponseWriter, r *http.Request) {
@@ -17,6 +18,12 @@ func (a *API) getListHandler(w http.ResponseWriter, r *http.Request) {
}
}
-func (a *API) getBlacklistTxtHandler(w http.ResponseWriter, r *http.Request) {
- // TODO
+func (a *API) getBlacklistHandler(w http.ResponseWriter, r *http.Request) {
+ list, err := a.idec.GetBlacklist()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ fmt.Fprint(w, strings.Join(list, "\n"))
}
diff --git a/pkg/api/message.go b/pkg/api/message.go
index 1c28285..81e863f 100644
--- a/pkg/api/message.go
+++ b/pkg/api/message.go
@@ -35,16 +35,21 @@ func (a *API) getMessageHandler(w http.ResponseWriter, r *http.Request) {
}
func (a *API) postPointHandler(w http.ResponseWriter, r *http.Request) {
+ msg, pauth := r.PathValue("tmsg"), r.PathValue("pauth")
if err := r.ParseForm(); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
+
form := r.PostForm
- a.savePointMessage(w, form.Get("tmsg"), form.Get("pauth"))
-}
+ if form.Has("tmsg") {
+ msg = form.Get("tmsg")
+ }
+ if form.Has("pauth") {
+ pauth = form.Get("pauth")
+ }
-func (a *API) getPointHandler(w http.ResponseWriter, r *http.Request) {
- a.savePointMessage(w, r.PathValue("tmsg"), r.PathValue("pauth"))
+ a.savePointMessage(w, msg, pauth)
}
func (a *API) savePointMessage(w http.ResponseWriter, rawMessage, auth string) error {
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 0c967fd..9fd58de 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -7,12 +7,13 @@ import (
)
type Config struct {
- Listen string `yaml:"listen"`
- Node string `yaml:"node"`
- Store string `yaml:"store"`
- LoggerType int `yaml:"logger_type"`
- Echos map[string]Echo `yaml:"echos"`
- Fetch []Node `yaml:"fetch"`
+ Listen string `yaml:"listen"`
+ Node string `yaml:"node"`
+ Store string `yaml:"store"`
+ LoggerType int `yaml:"logger_type"`
+ Echos map[string]Echo `yaml:"echos"`
+ Fetch []Node `yaml:"fetch"`
+ FilesDirectory string `yaml:"files_directory"`
}
type Node struct {
diff --git a/pkg/fetcher/fetcher.go b/pkg/fetcher/fetcher.go
index 0a79a70..5083889 100644
--- a/pkg/fetcher/fetcher.go
+++ b/pkg/fetcher/fetcher.go
@@ -43,6 +43,9 @@ func (f *Fetcher) Run(ctx context.Context) error {
if err := f.downloadMessages(node, messagesToDownloads); err != nil {
return err
}
+ if err := f.downloadBlacklist(node); err != nil {
+ return err
+ }
}
log.Println("finished")
return nil
@@ -133,6 +136,22 @@ func (f *Fetcher) downloadMessagesChunk(node config.Node, messages []string) err
return nil
}
+func (f *Fetcher) downloadBlacklist(node config.Node) error {
+ p := formatCommand(node, "blacklist.txt")
+ resp, err := f.client.Get(p)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ data, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return err
+ }
+ lines := strings.Split(string(data), "\n")
+
+ return f.idec.MergeBlacklist(lines)
+}
+
func formatCommand(node config.Node, method string, args ...string) string {
segments := []string{node.Addr, method}
segments = append(segments, args...)
diff --git a/pkg/idec/blacklist.go b/pkg/idec/blacklist.go
new file mode 100644
index 0000000..a74f541
--- /dev/null
+++ b/pkg/idec/blacklist.go
@@ -0,0 +1,65 @@
+package idec
+
+import (
+ "log"
+
+ "gitrepo.ru/neonxp/idecnode/pkg/model"
+ "go.etcd.io/bbolt"
+)
+
+const blacklistMessage = "<Удалено по черному списку>"
+
+func (i *IDEC) GetBlacklist() ([]string, error) {
+ list := []string{}
+
+ return list, i.db.View(func(tx *bbolt.Tx) error {
+ bucket := tx.Bucket([]byte(blacklist))
+ if bucket == nil {
+ return nil
+ }
+
+ return bucket.ForEach(func(k, _ []byte) error {
+ list = append(list, string(k))
+
+ return nil
+ })
+ })
+}
+
+func (i *IDEC) MergeBlacklist(list []string) error {
+ return i.db.Update(func(tx *bbolt.Tx) error {
+ bucket, err := tx.CreateBucketIfNotExists([]byte(blacklist))
+ if err != nil {
+ return err
+ }
+ messages, err := tx.CreateBucketIfNotExists([]byte(msgBucket))
+ if err != nil {
+ return err
+ }
+
+ for _, k := range list {
+ if k == "" {
+ continue
+ }
+ if err := bucket.Put([]byte(k), []byte{}); err != nil {
+ return err
+ }
+ msgBytes := messages.Get([]byte(k))
+ if msgBytes == nil {
+ continue
+ }
+ msg, err := model.MessageFromBundle(k, string(msgBytes))
+ if err != nil {
+ log.Println(err)
+ continue
+ }
+ msg.Subject = blacklistMessage
+ msg.Message = blacklistMessage
+ if err := messages.Put([]byte(k), []byte(msg.Bundle())); err != nil {
+ log.Println(err)
+ }
+ }
+
+ return nil
+ })
+}
diff --git a/pkg/idec/files.go b/pkg/idec/files.go
new file mode 100644
index 0000000..8fd73b4
--- /dev/null
+++ b/pkg/idec/files.go
@@ -0,0 +1,74 @@
+package idec
+
+import (
+ "errors"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "gitrepo.ru/neonxp/idecnode/pkg/model"
+)
+
+var ErrFileNotAllowed = errors.New("file not allowed")
+
+func (i *IDEC) FilesList(pauth string) ([]model.File, error) {
+ fileDirs := i.allowedDirs(pauth)
+ res := []model.File{}
+ for _, dir := range fileDirs {
+ files, err := filepath.Glob(dir + "/*")
+ if err != nil {
+ return nil, err
+ }
+ for _, f := range files {
+ fi, err := os.Stat(f)
+ if err != nil {
+ return nil, err
+ }
+
+ res = append(res, model.File{
+ Name: fi.Name(),
+ Size: fi.Size(),
+ FullName: strings.TrimPrefix(f, i.config.FilesDirectory),
+ })
+ }
+ }
+
+ return res, nil
+}
+
+func (i *IDEC) GetFile(pauth string, path string, w io.Writer) error {
+ file := filepath.Clean(filepath.Join(i.config.FilesDirectory, path))
+ allowed := false
+ allowedDirs := i.allowedDirs(pauth)
+ for _, dir := range allowedDirs {
+ if filepath.HasPrefix(file, dir) {
+ allowed = true
+ }
+ }
+ if !allowed {
+ return ErrFileNotAllowed
+ }
+
+ fp, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer fp.Close()
+
+ _, err = io.Copy(w, fp)
+
+ return err
+}
+
+func (i *IDEC) allowedDirs(pauth string) []string {
+ fileDirs := []string{
+ filepath.Join(i.config.FilesDirectory, "pub"),
+ }
+ if pauth != "" {
+ if _, err := i.GetPointByAuth(pauth); err == nil {
+ fileDirs = append(fileDirs, filepath.Join(i.config.FilesDirectory, "priv"))
+ }
+ }
+ return fileDirs
+}
diff --git a/pkg/idec/idec.go b/pkg/idec/idec.go
index 0692d65..d50c200 100644
--- a/pkg/idec/idec.go
+++ b/pkg/idec/idec.go
@@ -20,6 +20,7 @@ var (
const (
msgBucket = "_msg"
points = "_points"
+ blacklist = "_blacklist"
)
type IDEC struct {
diff --git a/pkg/idec/point.go b/pkg/idec/point.go
index 897c1bb..74bfc47 100644
--- a/pkg/idec/point.go
+++ b/pkg/idec/point.go
@@ -13,7 +13,7 @@ import (
var errPointFound = errors.New("point found")
-func (i *IDEC) GetPointByAuth(auth string) (*model.Point, error) {
+func (i *IDEC) GetPointByAuth(pauth string) (*model.Point, error) {
point := new(model.Point)
return point, i.db.View(func(tx *bbolt.Tx) error {
@@ -25,7 +25,7 @@ func (i *IDEC) GetPointByAuth(auth string) (*model.Point, error) {
if err := gob.NewDecoder(bytes.NewBuffer(v)).Decode(point); err != nil {
return err
}
- if point.AuthString == auth {
+ if point.AuthString == pauth {
return errPointFound
}
diff --git a/pkg/model/file.go b/pkg/model/file.go
new file mode 100644
index 0000000..d87f581
--- /dev/null
+++ b/pkg/model/file.go
@@ -0,0 +1,7 @@
+package model
+
+type File struct {
+ Name string
+ Size int64
+ FullName string
+}