mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-28 12:16:48 +08:00
290 lines
7.4 KiB
Go
290 lines
7.4 KiB
Go
package common
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"io/fs"
|
|
"net/http"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
type Plugin struct {
|
|
Type string
|
|
Enable bool
|
|
}
|
|
|
|
type Register struct{}
|
|
type Get struct{}
|
|
type All struct{}
|
|
|
|
var Hooks = struct {
|
|
Get Get
|
|
Register Register
|
|
}{
|
|
Get: Get{},
|
|
Register: Register{},
|
|
}
|
|
|
|
/*
|
|
* ProcessFileContentBeforeSend is a processing hooks used in plugins like:
|
|
* 1. pluggable image transcoding service: plg_image_light, plg_image_bimg, plg_image_golang
|
|
* 2. video transcoding service: plg_video_transcode
|
|
* 3. disallow certain type of file: plg_security_svg
|
|
*/
|
|
var process_file_content_before_send []func(io.ReadCloser, *App, *http.ResponseWriter, *http.Request) (io.ReadCloser, error)
|
|
|
|
func (this Register) ProcessFileContentBeforeSend(fn func(io.ReadCloser, *App, *http.ResponseWriter, *http.Request) (io.ReadCloser, error)) {
|
|
process_file_content_before_send = append(process_file_content_before_send, fn)
|
|
}
|
|
func (this Get) ProcessFileContentBeforeSend() []func(io.ReadCloser, *App, *http.ResponseWriter, *http.Request) (io.ReadCloser, error) {
|
|
return process_file_content_before_send
|
|
}
|
|
|
|
/*
|
|
* HttpEndpoint is a hook that makes it possible to register new endpoint in the application.
|
|
* It is used in plugin like:
|
|
* 1. plg_video_transcoder to server the transcoded video segment via hls
|
|
* 2. plg_editor_onlyoffice to server the content for a custom type in an iframe
|
|
* 3. plg_handler_syncthing to create better integration with syncthing
|
|
* 4. plg_handler_console to server a full blown console for debugging the application
|
|
*/
|
|
var http_endpoint []func(*mux.Router, *App) error
|
|
|
|
func (this Register) HttpEndpoint(fn func(*mux.Router, *App) error) {
|
|
http_endpoint = append(http_endpoint, fn)
|
|
}
|
|
func (this Get) HttpEndpoint() []func(*mux.Router, *App) error {
|
|
return http_endpoint
|
|
}
|
|
|
|
/*
|
|
* Override some urls with static content. The main use case for this is to enable
|
|
* plugins to change the frontend code and overwrite some core components
|
|
*/
|
|
func (this Register) Static(www fs.FS, chroot string) {
|
|
fs.WalkDir(www, ".", func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
return err
|
|
} else if d.IsDir() {
|
|
return nil
|
|
}
|
|
this.HttpEndpoint(func(r *mux.Router, app *App) error {
|
|
r.PathPrefix("/" + strings.TrimPrefix(path, chroot)).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
f, err := www.Open(path)
|
|
if err != nil {
|
|
w.Header().Set("Content-Type", "text/plain")
|
|
w.Write([]byte("plugin.go::static::err " + err.Error()))
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", GetMimeType(filepath.Ext(path)))
|
|
io.Copy(w, f)
|
|
f.Close()
|
|
})
|
|
return nil
|
|
})
|
|
return nil
|
|
})
|
|
}
|
|
|
|
/*
|
|
* Starter is the meat that let us connect to a wide variety of server like:
|
|
* - plg_starter_http which is the default that server the application under 8334
|
|
* - plg_starter_tor to serve the application via tor
|
|
* - plg_starter_web that create ssl certificate via letsencrypt
|
|
* - plg_started_http2 to create an HTTP2 server
|
|
* - ...
|
|
*/
|
|
var starter_process []func(*mux.Router)
|
|
|
|
func (this Register) Starter(fn func(*mux.Router)) {
|
|
starter_process = append(starter_process, fn)
|
|
}
|
|
func (this Get) Starter() []func(*mux.Router) {
|
|
return starter_process
|
|
}
|
|
|
|
/*
|
|
* AuthenticationMiddleware is what enabled us to authenticate user via different means:
|
|
* - plg_authentication_admin to enable connection to an admin
|
|
* - plg_authentication_saml
|
|
* - plg_authentication_openid
|
|
* - plg_authentication_ldap
|
|
* - ...
|
|
*/
|
|
var authentication_middleware map[string]IAuthentication = make(map[string]IAuthentication, 0)
|
|
|
|
func (this Register) AuthenticationMiddleware(id string, am IAuthentication) {
|
|
authentication_middleware[id] = am
|
|
}
|
|
|
|
func (this Get) AuthenticationMiddleware() map[string]IAuthentication {
|
|
return authentication_middleware
|
|
}
|
|
|
|
/*
|
|
* AuthorisationMiddleware is to enable custom rule for authorisation. eg: anonymous can see, registered
|
|
* user can see/edit some files but not some others, admin can do everything
|
|
*/
|
|
var authorisation_middleware []IAuthorisation
|
|
|
|
func (this Register) AuthorisationMiddleware(a IAuthorisation) {
|
|
authorisation_middleware = append(authorisation_middleware, a)
|
|
}
|
|
|
|
func (this Get) AuthorisationMiddleware() []IAuthorisation {
|
|
return authorisation_middleware
|
|
}
|
|
|
|
/*
|
|
* Search is the pluggable search mechanism. By default, there's 2 options:
|
|
* - plg_search_stateless which does stateless search based on filename only
|
|
* - plg_search_statefull which does full text search with a sqlite data store
|
|
* The idea here is to enable different type of usage like leveraging elastic search or solr
|
|
* with custom stuff around it
|
|
*/
|
|
var search ISearch
|
|
|
|
func (this Register) SearchEngine(s ISearch) {
|
|
search = s
|
|
}
|
|
|
|
func (this Get) SearchEngine() ISearch {
|
|
return search
|
|
}
|
|
|
|
/*
|
|
* The idea here is to enable plugin to register their own thumbnailing process, typically
|
|
* images but could also be videos, pdf, excel documents, ...
|
|
*/
|
|
var thumbnailer map[string]IThumbnailer = make(map[string]IThumbnailer)
|
|
|
|
func (this Register) Thumbnailer(mimeType string, fn IThumbnailer) {
|
|
thumbnailer[mimeType] = fn
|
|
}
|
|
|
|
func (this Get) Thumbnailer() map[string]IThumbnailer {
|
|
return thumbnailer
|
|
}
|
|
|
|
/*
|
|
* Pluggable Audit interface
|
|
*/
|
|
var audit IAuditPlugin
|
|
|
|
func (this Register) AuditEngine(a IAuditPlugin) {
|
|
audit = a
|
|
}
|
|
|
|
func (this Get) AuditEngine() IAuditPlugin {
|
|
return audit
|
|
}
|
|
|
|
/*
|
|
* UI Overrides
|
|
* They are the means by which server plugin change the frontend behaviors.
|
|
*/
|
|
var overrides []string
|
|
|
|
func (this Register) FrontendOverrides(url string) {
|
|
overrides = append(overrides, url)
|
|
}
|
|
func (this Get) FrontendOverrides() []string {
|
|
return overrides
|
|
}
|
|
|
|
var xdg_open []string
|
|
|
|
func (this Register) XDGOpen(jsString string) {
|
|
xdg_open = append(xdg_open, jsString)
|
|
}
|
|
func (this Get) XDGOpen() []string {
|
|
return xdg_open
|
|
}
|
|
|
|
var cssOverride []func() string
|
|
|
|
func (this Register) CSS(stylesheet string) {
|
|
cssOverride = append(cssOverride, func() string {
|
|
return stylesheet
|
|
})
|
|
}
|
|
|
|
func (this Register) CSSFunc(stylesheet func() string) {
|
|
cssOverride = append(cssOverride, stylesheet)
|
|
}
|
|
|
|
func (this Get) CSS() string {
|
|
s := ""
|
|
for i := 0; i < len(cssOverride); i++ {
|
|
s += cssOverride[i]() + "\n"
|
|
}
|
|
return s
|
|
}
|
|
|
|
var favicon struct {
|
|
binary []byte
|
|
mime string
|
|
}
|
|
|
|
func (this Register) Favicon(binary []byte) {
|
|
favicon.binary = binary
|
|
favicon.mime = "image/svg+xml"
|
|
if bytes.HasPrefix(binary, []byte{0x00, 0x00, 0x01, 0x00}) {
|
|
favicon.mime = "image/x-icon"
|
|
} else if bytes.HasPrefix(binary, []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}) {
|
|
favicon.mime = "image/png"
|
|
}
|
|
}
|
|
|
|
func (this Get) Favicon() ([]byte, string) {
|
|
return favicon.binary, favicon.mime
|
|
}
|
|
|
|
const OverrideVideoSourceMapper = "/overrides/video-transcoder.js"
|
|
|
|
var afterload []func()
|
|
|
|
func (this Register) Onload(fn func()) {
|
|
afterload = append(afterload, fn)
|
|
}
|
|
func (this Get) Onload() []func() {
|
|
return afterload
|
|
}
|
|
|
|
var middlewares []func(HandlerFunc) HandlerFunc
|
|
|
|
func (this Register) Middleware(m func(HandlerFunc) HandlerFunc) {
|
|
middlewares = append(middlewares, m)
|
|
}
|
|
|
|
func (this Get) Middleware() []func(HandlerFunc) HandlerFunc {
|
|
return middlewares
|
|
}
|
|
|
|
var staticOverrides [][]byte
|
|
|
|
func (this Register) StaticPatch(pathFile []byte) {
|
|
staticOverrides = append(staticOverrides, pathFile)
|
|
}
|
|
|
|
func (this Get) StaticPatch() [][]byte {
|
|
return staticOverrides
|
|
}
|
|
|
|
var meta IMetadata
|
|
|
|
func (this Register) Metadata(m IMetadata) {
|
|
meta = m
|
|
}
|
|
|
|
func (this Get) Metadata() IMetadata {
|
|
return meta
|
|
}
|
|
|
|
func init() {
|
|
Hooks.Register.FrontendOverrides(OverrideVideoSourceMapper)
|
|
}
|