2023-11-05 04:13:02 +01:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
2023-11-05 04:50:53 +01:00
|
|
|
"fmt"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
2023-11-05 05:09:30 +01:00
|
|
|
"net/http"
|
2023-11-05 04:13:02 +01:00
|
|
|
"io/ioutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/BurntSushi/toml"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
2023-11-05 06:25:21 +01:00
|
|
|
"github.com/dustin/go-humanize"
|
2023-11-05 04:13:02 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type Resource struct {
|
2023-11-05 05:09:30 +01:00
|
|
|
Url string `toml:"url"`
|
|
|
|
Proxied bool `toml:"proxied",default:false`
|
|
|
|
Mime string `toml:"mime"`
|
2023-11-05 04:13:02 +01:00
|
|
|
}
|
2023-11-05 04:36:24 +01:00
|
|
|
func (self Resource) Get() ([]byte, error) {
|
|
|
|
return ioutil.ReadFile(self.Url[7:])
|
|
|
|
}
|
2023-11-05 04:13:02 +01:00
|
|
|
|
|
|
|
type ResourceDConfig struct {
|
2023-11-05 06:25:21 +01:00
|
|
|
Enabled bool `toml:"enabled"`
|
|
|
|
ListenURL string `toml:"listen_url"`
|
|
|
|
ProxyCacheMinSize string `toml:"proxy_cache_min_size",default:5MB`
|
2023-11-05 04:13:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type Config struct {
|
|
|
|
ResourceD ResourceDConfig `toml:"resourceD"`
|
|
|
|
Resource map[string]Resource `toml:"resource"`
|
|
|
|
}
|
|
|
|
|
2023-11-05 04:50:53 +01:00
|
|
|
func (self Config) Validate() int {
|
|
|
|
re, err := regexp.Compile(`^(file|http(s|))://`)
|
|
|
|
if err != nil { panic(err) }
|
|
|
|
|
|
|
|
for key, res := range self.Resource {
|
|
|
|
if ! re.MatchString(res.Url) {
|
|
|
|
panic(fmt.Sprintf("Resource %s has invalid URL: %s\nOnly file://, http:// and https:// URLs are allowed", key, res.Url))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
2023-11-05 06:05:30 +01:00
|
|
|
func (self Resource) GetProxied() ([]byte, error) {
|
|
|
|
|
|
|
|
cached, exists := ProxyResourceCache[self.Url];
|
|
|
|
if exists {
|
|
|
|
return cached, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := http.Get(self.Url)
|
|
|
|
if err != nil { return make([]byte, 0, 0), err }
|
|
|
|
|
|
|
|
buf, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil { return make([]byte, 0, 0), err }
|
|
|
|
|
2023-11-05 06:25:21 +01:00
|
|
|
// cache only those that are less than 5 mb
|
|
|
|
if len(buf) > ProxyCacheMinSize {
|
|
|
|
ProxyResourceCache[self.Url] = buf
|
|
|
|
}
|
2023-11-05 06:05:30 +01:00
|
|
|
|
|
|
|
return buf, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
var ProxyResourceCache map[string][]byte = make(map[string][]byte)
|
2023-11-05 06:25:21 +01:00
|
|
|
var ProxyCacheMinSize int
|
2023-11-05 04:50:53 +01:00
|
|
|
|
2023-11-05 04:13:02 +01:00
|
|
|
func main() {
|
|
|
|
var conf Config
|
|
|
|
|
|
|
|
data, err := ioutil.ReadFile("resourced.toml")
|
|
|
|
if err != nil { panic(err) }
|
|
|
|
|
|
|
|
a, err := toml.Decode(string(data), &conf)
|
|
|
|
if err != nil { panic(err) }
|
|
|
|
_ = a
|
2023-11-05 04:50:53 +01:00
|
|
|
|
2023-11-05 06:25:21 +01:00
|
|
|
cache_min, err := humanize.ParseBytes(conf.ResourceD.ProxyCacheMinSize)
|
|
|
|
if err != nil { panic(err) }
|
|
|
|
ProxyCacheMinSize = int(cache_min)
|
|
|
|
|
2023-11-05 04:50:53 +01:00
|
|
|
conf.Validate()
|
2023-11-05 04:13:02 +01:00
|
|
|
|
2023-11-05 04:36:24 +01:00
|
|
|
app := fiber.New(fiber.Config {
|
|
|
|
Prefork: true,
|
|
|
|
CaseSensitive: false,
|
|
|
|
StrictRouting: true,
|
|
|
|
ServerHeader: "",
|
|
|
|
AppName: "blek! File resourceD",
|
|
|
|
})
|
2023-11-05 04:13:02 +01:00
|
|
|
|
2023-11-05 06:33:30 +01:00
|
|
|
app.Get("/info/is_enabled", func (c *fiber.Ctx) error {
|
|
|
|
return c.JSON(conf.ResourceD.Enabled)
|
|
|
|
})
|
|
|
|
|
2023-11-05 04:36:24 +01:00
|
|
|
app.Use(func (c *fiber.Ctx) error {
|
2023-11-05 04:13:02 +01:00
|
|
|
if ! conf.ResourceD.Enabled {
|
2023-11-05 04:36:24 +01:00
|
|
|
return c.Status(fiber.StatusNotFound).SendString("ResourceD is disabled")
|
2023-11-05 04:13:02 +01:00
|
|
|
}
|
2023-11-05 04:36:24 +01:00
|
|
|
return c.Next()
|
|
|
|
})
|
|
|
|
|
|
|
|
app.Get("/:id", func (c *fiber.Ctx) error {
|
2023-11-05 04:13:02 +01:00
|
|
|
res, exists := conf.Resource[c.Params("id")]
|
|
|
|
if ! exists {
|
|
|
|
return c.Status(fiber.StatusNotFound).SendString("Resource not found")
|
|
|
|
}
|
|
|
|
|
2023-11-05 04:50:53 +01:00
|
|
|
if ! strings.HasPrefix(res.Url, "file://") {
|
2023-11-05 05:09:30 +01:00
|
|
|
|
|
|
|
if res.Proxied {
|
2023-11-05 06:05:30 +01:00
|
|
|
data, err := res.GetProxied()
|
2023-11-05 05:09:30 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Fatalln(err)
|
2023-11-05 06:05:30 +01:00
|
|
|
// we failed, send a redirect instead
|
|
|
|
// (next executed line would be 115)
|
2023-11-05 05:09:30 +01:00
|
|
|
} else {
|
|
|
|
c.Response().Header.SetContentType(res.Mime)
|
2023-11-05 06:05:30 +01:00
|
|
|
c.Response().Header.SetContentLength(len(data))
|
|
|
|
return c.Send(data)
|
2023-11-05 05:09:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 04:50:53 +01:00
|
|
|
c.Location(res.Url)
|
|
|
|
c.Status(302)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-11-05 04:36:24 +01:00
|
|
|
data, err := res.Get()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c.Response().Header.SetContentType(res.Mime)
|
|
|
|
c.Response().Header.SetContentLength(len(data))
|
2023-11-05 04:50:53 +01:00
|
|
|
|
2023-11-05 04:36:24 +01:00
|
|
|
return c.Send(data)
|
2023-11-05 04:13:02 +01:00
|
|
|
})
|
|
|
|
|
|
|
|
log.Fatal(app.Listen(conf.ResourceD.ListenURL))
|
|
|
|
}
|