diff --git a/.air.toml b/.air.toml index 270f5af..f90403e 100644 --- a/.air.toml +++ b/.air.toml @@ -12,6 +12,7 @@ exclude_dir = [ "views/node_modules", "tmp", "vendor", + "cache", "testdata", "data_git", "cache_gnd", diff --git a/.gitignore b/.gitignore index 8b32700..25d21ba 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ KGPZ/ tmp/ bin/ data_git/ +cache/ cache_geo/ cache_gnd/ data_bilder/ diff --git a/app/kgpz.go b/app/kgpz.go index 1b0e70f..5681160 100644 --- a/app/kgpz.go +++ b/app/kgpz.go @@ -2,6 +2,7 @@ package app import ( "os" + "path/filepath" "sync" "github.com/Theodor-Springmann-Stiftung/kgpz_web/controllers" @@ -83,7 +84,7 @@ func (k *KGPZ) Pre(srv *fiber.App) error { func (k *KGPZ) Init() error { if gp, err := providers.NewGitProvider( k.Config.Config.GitURL, - k.Config.Config.FolderPath, + filepath.Join(k.Config.Config.BaseDIR, k.Config.Config.GITPath), k.Config.Config.GitBranch); err != nil { logging.Error(err, "Error initializing GitProvider. Continuing without Git.") } else { @@ -107,7 +108,7 @@ func (k *KGPZ) Init() error { func (k *KGPZ) initGND() error { k.GND = gnd.NewGNDProvider() - return k.GND.ReadCache(k.Config.GNDPath) + return k.GND.ReadCache(filepath.Join(k.Config.BaseDIR, k.Config.GNDPath)) } func (k *KGPZ) Routes(srv *fiber.App) error { @@ -135,6 +136,18 @@ func (k *KGPZ) Routes(srv *fiber.App) error { srv.Get(CONTACT_URL, controllers.Get(CONTACT_URL)) srv.Get(CITATION_URL, controllers.Get(CITATION_URL)) + if k.Config.WebHookSecret != "" && k.Config.WebHookEndpoint != "" { + handler, rc := controllers.PostWebhook(k.Config.WebHookSecret) + srv.Post(k.Config.WebHookEndpoint, handler) + go func() { + for signal := range rc { + if signal { + k.Pull() + } + } + }() + } + return nil } @@ -189,7 +202,7 @@ func (k *KGPZ) Serialize() error { k.Library = xmlmodels.NewLibrary() } - err := k.Library.Parse(source, k.Config.FolderPath, commit) + err := k.Library.Parse(source, filepath.Join(k.Config.BaseDIR, k.Config.GITPath), commit) return err } diff --git a/controllers/webhooks.go b/controllers/webhooks.go new file mode 100644 index 0000000..46550c4 --- /dev/null +++ b/controllers/webhooks.go @@ -0,0 +1,56 @@ +package controllers + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "strings" + + "github.com/gofiber/fiber/v2" +) + +const SIGNATURE_PREFIX = "sha256=" + +func PostWebhook(secret string) (fiber.Handler, chan bool) { + devchan := make(chan bool) + return func(c *fiber.Ctx) error { + body := c.Body() + if !verifySignature256([]byte(secret), body, c.Get("X-Hub-Signature-256")) { + return c.SendStatus(fiber.StatusUnauthorized) + } + + if c.Get("X-GitHub-Event") == "" { + return c.SendStatus(fiber.StatusBadRequest) + } + + go func() { + devchan <- true + }() + + c.SendStatus(fiber.StatusOK) + return nil + }, devchan +} + +func sign256(secret, body []byte) []byte { + computed := hmac.New(sha256.New, secret) + computed.Write(body) + return []byte(computed.Sum(nil)) +} + +func verifySignature256(secret, payload []byte, header string) bool { + if !strings.HasPrefix(header, SIGNATURE_PREFIX) { + return false + } + + sig, err := hex.DecodeString(header[len(SIGNATURE_PREFIX):]) + if err != nil { + return false + } + + mac := hmac.New(sha256.New, secret) + mac.Write(payload) + expected := mac.Sum(nil) + + return hmac.Equal(expected, sig) +} diff --git a/providers/config.go b/providers/config.go index f7648c7..be8901b 100644 --- a/providers/config.go +++ b/providers/config.go @@ -14,10 +14,12 @@ import ( // WARNING: this is not intended to be used in a multi-threaded environment // Instatiate this once on startup before any goroutines are started const ( - DEFAULT_GIT_DIR = "data_git" - DEFAULT_GND_DIR = "cache_gnd" - DEFAULT_GEO_DIR = "cache_geo" - DEFAULT_IMG_DIR = "data_bilder" + DEFAULT_DIR = "cache" + DEFAULT_GIT_CACHE_DIR = "git" + DEFAULT_GND_CACHE_DIR = "gnd" + DEFAULT_GEO_CACHE_DIR = "geo" + DEFAULT_SEARCH_CACHE_DIR = "search" + DEFAULT_IMG_DIR = "data_bilder" DEFAULT_PORT = "8080" DEFAULT_ADDR = "localhost" @@ -33,9 +35,10 @@ type ConfigProvider struct { type Config struct { // At least one of these should be set + BaseDIR string `json:"base_dir" envconfig:"BASE_DIR"` GitURL string `json:"git_url" envconfig:"GIT_URL"` GitBranch string `json:"git_branch" envconfig:"GIT_BRANCH"` - FolderPath string `json:"folder_path" envconfig:"FOLDER_PATH"` + GITPath string `json:"git_path" envconfig:"GIT_PATH"` GNDPath string `json:"gnd_path" envconfig:"GND_PATH"` GeoPath string `json:"geo_path" envconfig:"GEO_PATH"` ImgPath string `json:"img_path" envconfig:"IMG_PATH"` @@ -65,8 +68,8 @@ func (c *ConfigProvider) Read() error { } func (c *ConfigProvider) Validate() error { - if strings.TrimSpace(c.Config.FolderPath) == "" { - return fmt.Errorf("Folder path not set") + if strings.TrimSpace(c.Config.BaseDIR) == "" { + return fmt.Errorf("Base directory path not set") } return nil } @@ -92,16 +95,20 @@ func readSettingsEnv(cfg *Config) *Config { } func readDefaults(cfg *Config) *Config { - if strings.TrimSpace(cfg.FolderPath) == "" { - cfg.FolderPath = DEFAULT_GIT_DIR + if strings.TrimSpace(cfg.BaseDIR) == "" { + cfg.BaseDIR = DEFAULT_DIR + } + + if strings.TrimSpace(cfg.GITPath) == "" { + cfg.GITPath = DEFAULT_GIT_CACHE_DIR } if strings.TrimSpace(cfg.GNDPath) == "" { - cfg.GNDPath = DEFAULT_GND_DIR + cfg.GNDPath = DEFAULT_GND_CACHE_DIR } if strings.TrimSpace(cfg.GeoPath) == "" { - cfg.GeoPath = DEFAULT_GEO_DIR + cfg.GeoPath = DEFAULT_GEO_CACHE_DIR } if strings.TrimSpace(cfg.Address) == "" { @@ -119,8 +126,10 @@ func readDefaults(cfg *Config) *Config { return cfg } -// Implement stringer func (c *Config) String() string { - return fmt.Sprintf("GitURL: %s\nGitBranch: %s\nFolderPath: %s\nGNDPath: %s\nGeoPath: %s\nWebHookEndpoint: %s\nWebHookSecret: %s\n", - c.GitURL, c.GitBranch, c.FolderPath, c.GNDPath, c.GeoPath, c.WebHookEndpoint, c.WebHookSecret) + json, err := json.Marshal(c) + if err != nil { + return "Config: Error marshalling to JSON" + } + return string(json) } diff --git a/scratchpad.md b/scratchpad.md index 62e2140..ac3d6c3 100644 --- a/scratchpad.md +++ b/scratchpad.md @@ -1,2 +1,56 @@ # Inh. Verz. - 1765/28,113 Klopstock ist doppelt verlinkt, als Anzeige und als Auszug, außerdem ist nochmals die Kategorie Gedichte und litererische Kurztexte vergeben + +Werk: +- Uebersetzung +- Rezension +- Auszug +- Kommentar +- Theaterkritik +- Replik (1x) + +Beitrag: +- Theaterkritik +- Kommentar +- Replik +- Nachtrag + +Mit Titel od. Incipit: +- Auszug +- Rezension +- Aufsatz (mit Autor oft) +- Erzählung +- Brief + +Person: +- Nachruf + +Ohne Bezug: +- Weltnachrichten +- Einkommende Fremde +- Wechselkurse +- Bücher +- Lokalanzeigen +- Lokalnachrichten +- Lotterie +- Wetter +- Panegyrik (Warum nicht Person?) +- Vorladung +- Kriminalanzeige +- Gelehrte Nachrichten +- Proklamation +- Rezepte +- Anzeige +- Korrektur (Warum nicht Beirag?) +- In eigener Sache +- Dersertionsliste +- Notenblatt +- Vorlesungsverzeichnis + + +In Kombination: +- Abbildung +- Kommentar und Auszug + +Anderes: +- Provinienz in Werk diff --git a/build.sh b/scripts/build.sh similarity index 100% rename from build.sh rename to scripts/build.sh diff --git a/reset.sh b/scripts/reset.sh similarity index 68% rename from reset.sh rename to scripts/reset.sh index 04bde5b..451e5f1 100755 --- a/reset.sh +++ b/scripts/reset.sh @@ -2,3 +2,5 @@ rm -rf ./bin rm -rf ./cache_gnd rm -rf ./data_git +rm -rf ./tmp +rm -rf ./cache