mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-10-27 19:53:41 +08:00
feature (dynamic): make configuration dynamic
This commit is contained in:
11
cmd/main.go
11
cmd/main.go
@ -27,6 +27,11 @@ func start(routes *mux.Router) {
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
InitConfig()
|
||||
InitPluginList(embed.EmbedPluginList)
|
||||
for _, fn := range Hooks.Get.Onload() {
|
||||
fn()
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
for _, obj := range Hooks.Get.Starter() {
|
||||
wg.Add(1)
|
||||
@ -35,11 +40,5 @@ func start(routes *mux.Router) {
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
go func() {
|
||||
InitPluginList(embed.EmbedPluginList)
|
||||
for _, fn := range Hooks.Get.Onload() {
|
||||
go fn()
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ type FormElement struct {
|
||||
Required bool `json:"required"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
func InitConfig() {
|
||||
Config = NewConfiguration()
|
||||
Config.Load()
|
||||
Config.Initialise()
|
||||
|
||||
@ -21,16 +21,17 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
configPath string = GetAbsolutePath(CONFIG_PATH, "config.json")
|
||||
configKeysToEncrypt []string = []string{
|
||||
"middleware.identity_provider.params",
|
||||
"middleware.attribute_mapping.params",
|
||||
}
|
||||
)
|
||||
var configKeysToEncrypt []string = []string{
|
||||
"middleware.identity_provider.params",
|
||||
"middleware.attribute_mapping.params",
|
||||
}
|
||||
|
||||
func configPath() string {
|
||||
return GetAbsolutePath(CONFIG_PATH, "config.json")
|
||||
}
|
||||
|
||||
func LoadConfig() ([]byte, error) {
|
||||
file, err := os.OpenFile(configPath, os.O_RDONLY, os.ModePerm)
|
||||
file, err := os.OpenFile(configPath(), os.O_RDONLY, os.ModePerm)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
os.MkdirAll(GetAbsolutePath(CONFIG_PATH), os.ModePerm)
|
||||
@ -70,12 +71,12 @@ func LoadConfig() ([]byte, error) {
|
||||
}
|
||||
|
||||
func SaveConfig(v []byte) error {
|
||||
file, err := os.Create(configPath)
|
||||
file, err := os.Create(configPath())
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Filestash needs to be able to create/edit its own configuration which it can't at the moment. "+
|
||||
"Change the permission for filestash to create and edit `%s`",
|
||||
configPath,
|
||||
configPath(),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -17,17 +17,32 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
LOG_PATH = "data/state/log/"
|
||||
CONFIG_PATH = "data/state/config/"
|
||||
DB_PATH = "data/state/db/"
|
||||
FTS_PATH = "data/state/search/"
|
||||
CERT_PATH = "data/state/certs/"
|
||||
TMP_PATH = "data/cache/tmp/"
|
||||
CONFIG_PATH = "state/config/"
|
||||
CERT_PATH = "state/certs/"
|
||||
DB_PATH = "state/db/"
|
||||
FTS_PATH = "state/search/"
|
||||
LOG_PATH = "state/log/"
|
||||
TMP_PATH = "cache/tmp/"
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.MkdirAll(filepath.Join(GetCurrentDir(), LOG_PATH), os.ModePerm)
|
||||
// STEP1: setup app path
|
||||
rootPath := "data/"
|
||||
if p := os.Getenv("FILESTASH_PATH"); p != "" {
|
||||
rootPath = p
|
||||
}
|
||||
LOG_PATH = filepath.Join(rootPath, LOG_PATH)
|
||||
CONFIG_PATH = filepath.Join(rootPath, CONFIG_PATH)
|
||||
DB_PATH = filepath.Join(rootPath, DB_PATH)
|
||||
FTS_PATH = filepath.Join(rootPath, FTS_PATH)
|
||||
CERT_PATH = filepath.Join(rootPath, CERT_PATH)
|
||||
TMP_PATH = filepath.Join(rootPath, TMP_PATH)
|
||||
|
||||
// STEP2: initialise the config
|
||||
os.MkdirAll(filepath.Join(GetCurrentDir(), CERT_PATH), os.ModePerm)
|
||||
os.MkdirAll(filepath.Join(GetCurrentDir(), DB_PATH), os.ModePerm)
|
||||
os.MkdirAll(filepath.Join(GetCurrentDir(), FTS_PATH), os.ModePerm)
|
||||
os.MkdirAll(filepath.Join(GetCurrentDir(), LOG_PATH), os.ModePerm)
|
||||
os.RemoveAll(filepath.Join(GetCurrentDir(), TMP_PATH))
|
||||
os.MkdirAll(filepath.Join(GetCurrentDir(), TMP_PATH), os.ModePerm)
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type Plugin struct {
|
||||
|
||||
@ -40,7 +40,7 @@ func generateNewCertificate(root *x509.Certificate, key *rsa.PrivateKey) (*x509.
|
||||
}
|
||||
|
||||
func pullCertificateFromFS() (*x509.Certificate, []byte, error) {
|
||||
file, err := os.OpenFile(certPEMPath, os.O_RDONLY, os.ModePerm)
|
||||
file, err := os.OpenFile(certPEMPath(), os.O_RDONLY, os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -58,7 +58,7 @@ func pullCertificateFromFS() (*x509.Certificate, []byte, error) {
|
||||
}
|
||||
|
||||
func saveCertificateToFS(certPEM []byte) error {
|
||||
file, err := os.OpenFile(certPEMPath, os.O_WRONLY|os.O_CREATE, 0600)
|
||||
file, err := os.OpenFile(certPEMPath(), os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -69,5 +69,5 @@ func saveCertificateToFS(certPEM []byte) error {
|
||||
}
|
||||
|
||||
func clearCert() {
|
||||
os.Remove(certPEMPath)
|
||||
os.Remove(certPEMPath())
|
||||
}
|
||||
|
||||
@ -2,14 +2,20 @@ package ssl
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"os"
|
||||
)
|
||||
|
||||
var keyPEMPath string = GetAbsolutePath(CERT_PATH, "key.pem")
|
||||
var certPEMPath string = GetAbsolutePath(CERT_PATH, "cert.pem")
|
||||
var (
|
||||
keyPEMPath func() string
|
||||
certPEMPath func() string
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.MkdirAll(GetAbsolutePath(CERT_PATH), os.ModePerm)
|
||||
keyPEMPath = func() string {
|
||||
return GetAbsolutePath(CERT_PATH, "key.pem")
|
||||
}
|
||||
certPEMPath = func() string {
|
||||
return GetAbsolutePath(CERT_PATH, "cert.pem")
|
||||
}
|
||||
}
|
||||
|
||||
func Clear() {
|
||||
|
||||
@ -37,7 +37,7 @@ func generateNewPrivateKey() (*rsa.PrivateKey, []byte, error) {
|
||||
}
|
||||
|
||||
func pullPrivateKeyFromFS() (*rsa.PrivateKey, []byte, error) {
|
||||
file, err := os.OpenFile(keyPEMPath, os.O_RDONLY, os.ModePerm)
|
||||
file, err := os.OpenFile(keyPEMPath(), os.O_RDONLY, os.ModePerm)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@ -56,7 +56,7 @@ func pullPrivateKeyFromFS() (*rsa.PrivateKey, []byte, error) {
|
||||
}
|
||||
|
||||
func savePrivateKeyToFS(privatePEM []byte) error {
|
||||
file, err := os.OpenFile(keyPEMPath, os.O_WRONLY|os.O_CREATE, 0600)
|
||||
file, err := os.OpenFile(keyPEMPath(), os.O_WRONLY|os.O_CREATE, 0600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -69,5 +69,5 @@ func savePrivateKeyToFS(privatePEM []byte) error {
|
||||
}
|
||||
|
||||
func clearPrivateKey() {
|
||||
os.Remove(keyPEMPath)
|
||||
os.Remove(keyPEMPath())
|
||||
}
|
||||
|
||||
@ -32,11 +32,6 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
FileCache = NewAppCache()
|
||||
cachePath := GetAbsolutePath(TMP_PATH)
|
||||
FileCache.OnEvict(func(key string, value interface{}) {
|
||||
os.RemoveAll(filepath.Join(cachePath, key))
|
||||
})
|
||||
ZipTimeout = func() int {
|
||||
return Config.Get("features.protection.zip_timeout").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -50,7 +45,13 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
ZipTimeout()
|
||||
FileCache = NewAppCache()
|
||||
FileCache.OnEvict(func(key string, value interface{}) {
|
||||
os.RemoveAll(filepath.Join(GetAbsolutePath(TMP_PATH), key))
|
||||
})
|
||||
Hooks.Register.Onload(func() {
|
||||
ZipTimeout()
|
||||
})
|
||||
}
|
||||
|
||||
func FileLs(ctx *App, res http.ResponseWriter, req *http.Request) {
|
||||
|
||||
@ -9,6 +9,19 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var telemetry = Telemetry{Data: make([]LogEntry, 0)}
|
||||
|
||||
func init() {
|
||||
Hooks.Register.Onload(func() {
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(10 * time.Second)
|
||||
telemetry.Flush()
|
||||
}
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
type Middleware func(func(*App, http.ResponseWriter, *http.Request)) func(*App, http.ResponseWriter, *http.Request)
|
||||
|
||||
func NewMiddlewareChain(fn func(*App, http.ResponseWriter, *http.Request), m []Middleware, app App) http.HandlerFunc {
|
||||
@ -108,7 +121,7 @@ func Logger(ctx App, res http.ResponseWriter, req *http.Request) {
|
||||
RequestID: func() string {
|
||||
defer func() string {
|
||||
if r := recover(); r != nil {
|
||||
Log.Debug("middleware::index get header '%s'", r)
|
||||
return "oops"
|
||||
}
|
||||
return "null"
|
||||
}()
|
||||
@ -161,14 +174,3 @@ func (this *Telemetry) Flush() {
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
var telemetry Telemetry = Telemetry{Data: make([]LogEntry, 0)}
|
||||
|
||||
func init() {
|
||||
go func() {
|
||||
for {
|
||||
time.Sleep(10 * time.Second)
|
||||
telemetry.Flush()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@ -4,39 +4,38 @@ import (
|
||||
"database/sql"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
_ "modernc.org/sqlite"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
var DB *sql.DB
|
||||
|
||||
func init() {
|
||||
cachePath := GetAbsolutePath(DB_PATH)
|
||||
os.MkdirAll(cachePath, os.ModePerm)
|
||||
var err error
|
||||
if DB, err = sql.Open("sqlite", cachePath+"/share.sql?_fk=true"); err != nil {
|
||||
Log.Error("model::index sqlite open error '%s'", err.Error())
|
||||
return
|
||||
}
|
||||
Hooks.Register.Onload(func() {
|
||||
var err error
|
||||
if DB, err = sql.Open("sqlite", GetAbsolutePath(DB_PATH)+"/share.sql?_fk=true"); err != nil {
|
||||
Log.Error("model::index sqlite open error '%s'", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if stmt, err := DB.Prepare("CREATE TABLE IF NOT EXISTS Location(backend VARCHAR(16), path VARCHAR(512), CONSTRAINT pk_location PRIMARY KEY(backend, path))"); err == nil {
|
||||
stmt.Exec()
|
||||
}
|
||||
|
||||
if stmt, err := DB.Prepare("CREATE TABLE IF NOT EXISTS Share(id VARCHAR(64) PRIMARY KEY, related_backend VARCHAR(16), related_path VARCHAR(512), params JSON, auth VARCHAR(4093) NOT NULL, FOREIGN KEY (related_backend, related_path) REFERENCES Location(backend, path) ON UPDATE CASCADE ON DELETE CASCADE)"); err == nil {
|
||||
stmt.Exec()
|
||||
}
|
||||
|
||||
if stmt, err := DB.Prepare("CREATE TABLE IF NOT EXISTS Verification(key VARCHAR(512), code VARCHAR(4), expire DATETIME DEFAULT (datetime('now', '+10 minutes')))"); err == nil {
|
||||
stmt.Exec()
|
||||
if stmt, err = DB.Prepare("CREATE INDEX idx_verification ON Verification(code, expire)"); err == nil {
|
||||
if stmt, err := DB.Prepare("CREATE TABLE IF NOT EXISTS Location(backend VARCHAR(16), path VARCHAR(512), CONSTRAINT pk_location PRIMARY KEY(backend, path))"); err == nil {
|
||||
stmt.Exec()
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
autovacuum()
|
||||
}()
|
||||
if stmt, err := DB.Prepare("CREATE TABLE IF NOT EXISTS Share(id VARCHAR(64) PRIMARY KEY, related_backend VARCHAR(16), related_path VARCHAR(512), params JSON, auth VARCHAR(4093) NOT NULL, FOREIGN KEY (related_backend, related_path) REFERENCES Location(backend, path) ON UPDATE CASCADE ON DELETE CASCADE)"); err == nil {
|
||||
stmt.Exec()
|
||||
}
|
||||
|
||||
if stmt, err := DB.Prepare("CREATE TABLE IF NOT EXISTS Verification(key VARCHAR(512), code VARCHAR(4), expire DATETIME DEFAULT (datetime('now', '+10 minutes')))"); err == nil {
|
||||
stmt.Exec()
|
||||
if stmt, err = DB.Prepare("CREATE INDEX idx_verification ON Verification(code, expire)"); err == nil {
|
||||
stmt.Exec()
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
autovacuum()
|
||||
}()
|
||||
})
|
||||
}
|
||||
|
||||
func autovacuum() {
|
||||
|
||||
@ -10,28 +10,20 @@ package model
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/mickael-kerjean/net/webdav"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/mickael-kerjean/net/webdav"
|
||||
)
|
||||
|
||||
const DAVCachePath = "data/cache/webdav/"
|
||||
|
||||
var (
|
||||
cachePath string
|
||||
webdavCache AppCache
|
||||
)
|
||||
var webdavCache AppCache
|
||||
|
||||
func init() {
|
||||
cachePath = GetAbsolutePath(DAVCachePath) + "/"
|
||||
os.RemoveAll(cachePath)
|
||||
os.MkdirAll(cachePath, os.ModePerm)
|
||||
|
||||
webdavCache = NewQuickCache(20, 10)
|
||||
webdavCache.OnEvict(func(filename string, _ interface{}) {
|
||||
os.Remove(filename)
|
||||
@ -64,7 +56,7 @@ func (this WebdavFs) Mkdir(ctx context.Context, name string, perm os.FileMode) e
|
||||
}
|
||||
|
||||
func (this *WebdavFs) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
|
||||
cachePath := fmt.Sprintf("%stmp_%s", cachePath, Hash(this.id+name, 20))
|
||||
cachePath := filepath.Join(GetAbsolutePath(TMP_PATH), "webdav_"+Hash(this.id+name, 20))
|
||||
fwriteFile := func() *os.File {
|
||||
if this.req.Method == "PUT" {
|
||||
f, err := os.OpenFile(cachePath+"_writer", os.O_WRONLY|os.O_CREATE|os.O_EXCL, os.ModePerm)
|
||||
@ -119,7 +111,7 @@ func (this *WebdavFs) Stat(ctx context.Context, name string) (os.FileInfo, error
|
||||
this.webdavFile = &WebdavFile{
|
||||
path: fullname,
|
||||
backend: this.backend,
|
||||
cache: fmt.Sprintf("%stmp_%s", cachePath, Hash(this.id+name, 20)),
|
||||
cache: filepath.Join(GetAbsolutePath(TMP_PATH), "webdav_"+Hash(this.id+name, 20)),
|
||||
}
|
||||
return this.webdavFile.Stat()
|
||||
}
|
||||
|
||||
@ -19,6 +19,7 @@ import (
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_local"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_mysql"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_nfs"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_nfs4"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_nop"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_s3"
|
||||
_ "github.com/mickael-kerjean/filestash/server/plugin/plg_backend_samba"
|
||||
@ -39,5 +40,5 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
Log.Debug("Plugin loader")
|
||||
Hooks.Register.Onload(func() { Log.Debug("plugins loaded") })
|
||||
}
|
||||
|
||||
@ -6,21 +6,20 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
)
|
||||
|
||||
var (
|
||||
BackblazeCachePath string = "data/cache/tmp/"
|
||||
BackblazeCache AppCache
|
||||
)
|
||||
var BackblazeCache AppCache
|
||||
|
||||
type Backblaze struct {
|
||||
params map[string]string
|
||||
@ -41,9 +40,6 @@ type BackblazeError struct {
|
||||
func init() {
|
||||
Backend.Register("backblaze", Backblaze{})
|
||||
BackblazeCache = NewAppCache()
|
||||
cachePath := GetAbsolutePath(BackblazeCachePath)
|
||||
os.RemoveAll(cachePath)
|
||||
os.MkdirAll(cachePath, os.ModePerm)
|
||||
}
|
||||
|
||||
func (this Backblaze) Init(params map[string]string, app *App) (IBackend, error) {
|
||||
@ -429,7 +425,10 @@ func (this Backblaze) Save(path string, file io.Reader) error {
|
||||
ContentLength int64
|
||||
Sha1 []byte
|
||||
}{}
|
||||
backblazeFileDetail.path = GetAbsolutePath(BackblazeCachePath + "data_" + QuickString(20) + ".dat")
|
||||
backblazeFileDetail.path = filepath.Join(
|
||||
GetAbsolutePath(TMP_PATH),
|
||||
"data_"+QuickString(20)+".dat",
|
||||
)
|
||||
f, err := os.OpenFile(backblazeFileDetail.path, os.O_CREATE|os.O_RDWR, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
package plg_backend_ftp_only
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
//"github.com/secsy/goftp" <- FTP issue with microsoft FTP
|
||||
"github.com/prasad83/goftp"
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
|
||||
//"github.com/secsy/goftp" <- FTP issue with microsoft FTP
|
||||
"github.com/prasad83/goftp"
|
||||
)
|
||||
|
||||
var FtpCache AppCache
|
||||
|
||||
@ -17,8 +17,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const GitCachePath = "data/cache/git/"
|
||||
|
||||
var GitCache AppCache
|
||||
|
||||
type Git struct {
|
||||
@ -29,9 +27,6 @@ func init() {
|
||||
Backend.Register("git", Git{})
|
||||
|
||||
GitCache = NewAppCache()
|
||||
cachePath := GetAbsolutePath(GitCachePath)
|
||||
os.RemoveAll(cachePath)
|
||||
os.MkdirAll(cachePath, os.ModePerm)
|
||||
GitCache.OnEvict(func(key string, value interface{}) {
|
||||
g := value.(*Git)
|
||||
g.Close()
|
||||
@ -94,7 +89,10 @@ func (git Git) Init(params map[string]string, app *App) (IBackend, error) {
|
||||
}
|
||||
|
||||
hash := GenerateID(app)
|
||||
p.basePath = GetAbsolutePath(GitCachePath + "repo_" + hash + "/")
|
||||
p.basePath = filepath.Join(
|
||||
GetAbsolutePath(TMP_PATH),
|
||||
"git_"+hash,
|
||||
) + "/"
|
||||
|
||||
repo, err := g.git.open(p, p.basePath)
|
||||
g.git.repo = repo
|
||||
|
||||
@ -195,7 +195,7 @@ func (this Mysql) Ls(path string) ([]os.FileInfo, error) {
|
||||
}
|
||||
|
||||
rows, err := this.db.Query(fmt.Sprintf(
|
||||
"SELECT CONCAT(%s) as filename %sFROM %s.%s %s LIMIT 15000",
|
||||
"SELECT CONCAT(%s) as filename %sFROM %s.%s %s LIMIT 500000",
|
||||
func() string {
|
||||
q := strings.Join(extractNamePlus(sqlFields.Select), ", ' - ', ")
|
||||
if len(sqlFields.Esthetics) != 0 {
|
||||
|
||||
@ -154,7 +154,7 @@ func (this Nfs4Share) Rm(path string) error {
|
||||
}
|
||||
|
||||
func (this Nfs4Share) Mv(from string, to string) error {
|
||||
return ErrNotImplemented
|
||||
return this.client.Rename(from, to)
|
||||
}
|
||||
|
||||
func (this Nfs4Share) Touch(path string) error {
|
||||
|
||||
@ -23,6 +23,10 @@ import (
|
||||
var (
|
||||
SECRET_KEY_DERIVATE_FOR_ONLYOFFICE string
|
||||
OnlyOfficeCache *cache.Cache
|
||||
|
||||
plugin_enable func() bool
|
||||
server_url func() string
|
||||
can_download func() bool
|
||||
)
|
||||
|
||||
type OnlyOfficeCacheData struct {
|
||||
@ -32,7 +36,9 @@ type OnlyOfficeCacheData struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
plugin_enable := func() bool {
|
||||
SECRET_KEY_DERIVATE_FOR_ONLYOFFICE = Hash("ONLYOFFICE_"+SECRET_KEY, len(SECRET_KEY))
|
||||
OnlyOfficeCache = cache.New(720*time.Minute, 720*time.Minute)
|
||||
plugin_enable = func() bool {
|
||||
return Config.Get("features.office.enable").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
@ -47,71 +53,73 @@ func init() {
|
||||
}
|
||||
return f
|
||||
}).Bool()
|
||||
}()
|
||||
Config.Get("features.office.onlyoffice_server").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "onlyoffice_server"
|
||||
f.Name = "onlyoffice_server"
|
||||
f.Type = "text"
|
||||
f.Description = "Location of your OnlyOffice server"
|
||||
f.Default = "http://127.0.0.1:8080"
|
||||
f.Placeholder = "Eg: http://127.0.0.1:8080"
|
||||
if u := os.Getenv("ONLYOFFICE_URL"); u != "" {
|
||||
f.Default = u
|
||||
f.Placeholder = fmt.Sprintf("Default: '%s'", u)
|
||||
}
|
||||
return f
|
||||
})
|
||||
Config.Get("features.office.can_download").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "onlyoffice_can_download"
|
||||
f.Name = "can_download"
|
||||
f.Type = "boolean"
|
||||
f.Description = "Display Download button in onlyoffice"
|
||||
f.Default = true
|
||||
return f
|
||||
})
|
||||
|
||||
if plugin_enable == false {
|
||||
return
|
||||
}
|
||||
server_url = func() string {
|
||||
return Config.Get("features.office.onlyoffice_server").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "onlyoffice_server"
|
||||
f.Name = "onlyoffice_server"
|
||||
f.Type = "text"
|
||||
f.Description = "Location of your OnlyOffice server"
|
||||
f.Default = "http://127.0.0.1:8080"
|
||||
f.Placeholder = "Eg: http://127.0.0.1:8080"
|
||||
if u := os.Getenv("ONLYOFFICE_URL"); u != "" {
|
||||
f.Default = u
|
||||
f.Placeholder = fmt.Sprintf("Default: '%s'", u)
|
||||
}
|
||||
return f
|
||||
}).String()
|
||||
}
|
||||
can_download = func() bool {
|
||||
return Config.Get("features.office.can_download").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "onlyoffice_can_download"
|
||||
f.Name = "can_download"
|
||||
f.Type = "boolean"
|
||||
f.Description = "Display Download button in onlyoffice"
|
||||
f.Default = true
|
||||
return f
|
||||
}).Bool()
|
||||
}
|
||||
|
||||
SECRET_KEY_DERIVATE_FOR_ONLYOFFICE = Hash("ONLYOFFICE_"+SECRET_KEY, len(SECRET_KEY))
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
||||
oods := r.PathPrefix("/onlyoffice").Subrouter()
|
||||
oods.PathPrefix("/static/").HandlerFunc(StaticHandler).Methods("GET", "POST")
|
||||
oods.HandleFunc("/event", OnlyOfficeEventHandler).Methods("POST")
|
||||
oods.HandleFunc("/content", FetchContentHandler).Methods("GET")
|
||||
Hooks.Register.Onload(func() {
|
||||
if plugin_enable() == false {
|
||||
return
|
||||
}
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
||||
oods := r.PathPrefix("/onlyoffice").Subrouter()
|
||||
oods.PathPrefix("/static/").HandlerFunc(StaticHandler).Methods("GET", "POST")
|
||||
oods.HandleFunc("/event", OnlyOfficeEventHandler).Methods("POST")
|
||||
oods.HandleFunc("/content", FetchContentHandler).Methods("GET")
|
||||
|
||||
r.HandleFunc(
|
||||
COOKIE_PATH+"onlyoffice/iframe",
|
||||
NewMiddlewareChain(
|
||||
IframeContentHandler,
|
||||
[]Middleware{SessionStart, LoggedInOnly},
|
||||
*app,
|
||||
),
|
||||
).Methods("GET")
|
||||
return nil
|
||||
})
|
||||
Hooks.Register.XDGOpen(`
|
||||
if(mime === "application/word" || mime === "application/msword" ||
|
||||
mime === "application/vnd.oasis.opendocument.text" || mime === "application/vnd.oasis.opendocument.spreadsheet" ||
|
||||
mime === "application/excel" || mime === "application/vnd.ms-excel" || mime === "application/powerpoint" ||
|
||||
mime === "application/vnd.ms-powerpoint" || mime === "application/vnd.oasis.opendocument.presentation" ) {
|
||||
r.HandleFunc(
|
||||
COOKIE_PATH+"onlyoffice/iframe",
|
||||
NewMiddlewareChain(
|
||||
IframeContentHandler,
|
||||
[]Middleware{SessionStart, LoggedInOnly},
|
||||
*app,
|
||||
),
|
||||
).Methods("GET")
|
||||
return nil
|
||||
})
|
||||
Hooks.Register.XDGOpen(`
|
||||
if(mime === "application/word" || mime === "application/msword" ||
|
||||
mime === "application/vnd.oasis.opendocument.text" || mime === "application/vnd.oasis.opendocument.spreadsheet" ||
|
||||
mime === "application/excel" || mime === "application/vnd.ms-excel" || mime === "application/powerpoint" ||
|
||||
mime === "application/vnd.ms-powerpoint" || mime === "application/vnd.oasis.opendocument.presentation" ) {
|
||||
return ["appframe", {"endpoint": "/api/onlyoffice/iframe"}];
|
||||
}
|
||||
`)
|
||||
OnlyOfficeCache = cache.New(720*time.Minute, 720*time.Minute)
|
||||
}
|
||||
`)
|
||||
})
|
||||
}
|
||||
|
||||
func StaticHandler(res http.ResponseWriter, req *http.Request) {
|
||||
req.URL.Path = strings.TrimPrefix(req.URL.Path, "/onlyoffice/static")
|
||||
oodsLocation := Config.Get("features.office.onlyoffice_server").String()
|
||||
u, err := url.Parse(oodsLocation)
|
||||
u, err := url.Parse(server_url())
|
||||
if err != nil {
|
||||
SendErrorResult(res, err)
|
||||
return
|
||||
@ -161,7 +169,7 @@ func IframeContentHandler(ctx *App, res http.ResponseWriter, req *http.Request)
|
||||
if model.CanRead(ctx) == false {
|
||||
SendErrorResult(res, ErrPermissionDenied)
|
||||
return
|
||||
} else if oodsLocation := Config.Get("features.office.onlyoffice_server").String(); oodsLocation == "" {
|
||||
} else if server_url() == "" {
|
||||
res.WriteHeader(http.StatusServiceUnavailable)
|
||||
res.Write([]byte("<p>The Onlyoffice server hasn't been configured</p>"))
|
||||
res.Write([]byte("<style>p {color: white; text-align: center; margin-top: 50px; font-size: 20px; opacity: 0.6; font-family: monospace; } </style>"))
|
||||
@ -365,7 +373,7 @@ func IframeContentHandler(ctx *App, res http.ResponseWriter, req *http.Request)
|
||||
filetype,
|
||||
key,
|
||||
func() string {
|
||||
if Config.Get("features.office.can_download").Bool() {
|
||||
if can_download() {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
|
||||
@ -8,11 +8,6 @@ import (
|
||||
_ "embed"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"github.com/creack/pty"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -21,6 +16,13 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
|
||||
"github.com/creack/pty"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/websocket"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
//go:embed src/app.css
|
||||
@ -47,18 +49,19 @@ var console_enable = func() bool {
|
||||
}
|
||||
|
||||
func init() {
|
||||
console_enable()
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, _ *App) error {
|
||||
Hooks.Register.Onload(func() {
|
||||
if console_enable() == false {
|
||||
return nil
|
||||
return
|
||||
}
|
||||
r.PathPrefix("/admin/tty/").Handler(
|
||||
AuthBasic(
|
||||
func() (string, string) { return "admin", Config.Get("auth.admin").String() },
|
||||
TTYHandler("/admin/tty/"),
|
||||
),
|
||||
)
|
||||
return nil
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, _ *App) error {
|
||||
r.PathPrefix("/admin/tty/").Handler(
|
||||
AuthBasic(
|
||||
func() (string, string) { return "admin", Config.Get("auth.admin").String() },
|
||||
TTYHandler("/admin/tty/"),
|
||||
),
|
||||
)
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -19,40 +19,53 @@ import (
|
||||
|
||||
const SYNCTHING_URI = "/admin/syncthing"
|
||||
|
||||
var (
|
||||
plugin_enable func() bool
|
||||
server_url func() string
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin_enable := Config.Get("features.syncthing.enable").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Name = "enable"
|
||||
f.Type = "enable"
|
||||
f.Target = []string{"syncthing_server_url"}
|
||||
f.Description = "Enable/Disable integration with the syncthing server. This will make your syncthing server available at `/admin/syncthing`"
|
||||
f.Default = false
|
||||
if u := os.Getenv("SYNCTHING_URL"); u != "" {
|
||||
f.Default = true
|
||||
}
|
||||
return f
|
||||
}).Bool()
|
||||
Config.Get("features.syncthing.server_url").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "syncthing_server_url"
|
||||
f.Name = "server_url"
|
||||
f.Type = "text"
|
||||
f.Description = "Location of your Syncthing server"
|
||||
f.Default = ""
|
||||
f.Placeholder = "Eg: http://127.0.0.1:8080"
|
||||
if u := os.Getenv("SYNCTHING_URL"); u != "" {
|
||||
f.Default = u
|
||||
f.Placeholder = fmt.Sprintf("Default: '%s'", u)
|
||||
}
|
||||
return f
|
||||
plugin_enable = func() bool {
|
||||
return Config.Get("features.syncthing.enable").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Name = "enable"
|
||||
f.Type = "enable"
|
||||
f.Target = []string{"syncthing_server_url"}
|
||||
f.Description = "Enable/Disable integration with the syncthing server. This will make your syncthing server available at `/admin/syncthing`"
|
||||
f.Default = false
|
||||
if u := os.Getenv("SYNCTHING_URL"); u != "" {
|
||||
f.Default = true
|
||||
}
|
||||
return f
|
||||
}).Bool()
|
||||
}
|
||||
server_url = func() string {
|
||||
return Config.Get("features.syncthing.server_url").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "syncthing_server_url"
|
||||
f.Name = "server_url"
|
||||
f.Type = "text"
|
||||
f.Description = "Location of your Syncthing server"
|
||||
f.Default = ""
|
||||
f.Placeholder = "Eg: http://127.0.0.1:8080"
|
||||
if u := os.Getenv("SYNCTHING_URL"); u != "" {
|
||||
f.Default = u
|
||||
f.Placeholder = fmt.Sprintf("Default: '%s'", u)
|
||||
}
|
||||
return f
|
||||
}).String()
|
||||
}
|
||||
Hooks.Register.Onload(func() {
|
||||
plugin_enable()
|
||||
server_url()
|
||||
})
|
||||
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, _ *App) error {
|
||||
if plugin_enable == false {
|
||||
if plugin_enable() == false {
|
||||
return nil
|
||||
}
|
||||
r.HandleFunc(SYNCTHING_URI, func(res http.ResponseWriter, req *http.Request) {
|
||||
@ -121,7 +134,7 @@ func SyncthingProxyHandler(res http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
return "http"
|
||||
}())
|
||||
u, err := url.Parse(Config.Get("features.syncthing.server_url").String())
|
||||
u, err := url.Parse(server_url())
|
||||
if err != nil {
|
||||
SendErrorResult(res, err)
|
||||
return
|
||||
|
||||
@ -2,15 +2,15 @@ package plg_image_light
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const ImageCachePath = "data/cache/image/"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
)
|
||||
|
||||
func init() {
|
||||
plugin_enable := func() bool {
|
||||
@ -25,8 +25,6 @@ func init() {
|
||||
return f
|
||||
}).Bool()
|
||||
}
|
||||
plugin_enable()
|
||||
|
||||
thumb_size := func() int {
|
||||
return Config.Get("features.image.thumbnail_size").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -41,8 +39,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
thumb_size()
|
||||
|
||||
thumb_quality := func() int {
|
||||
return Config.Get("features.image.thumbnail_quality").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -57,8 +53,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
thumb_quality()
|
||||
|
||||
thumb_caching := func() int {
|
||||
return Config.Get("features.image.thumbnail_caching").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -73,8 +67,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
thumb_caching()
|
||||
|
||||
image_quality := func() int {
|
||||
return Config.Get("features.image.image_quality").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -89,8 +81,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
image_quality()
|
||||
|
||||
image_caching := func() int {
|
||||
return Config.Get("features.image.image_caching").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -105,11 +95,14 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
image_caching()
|
||||
|
||||
cachePath := GetAbsolutePath(ImageCachePath)
|
||||
os.RemoveAll(cachePath)
|
||||
os.MkdirAll(cachePath, os.ModePerm)
|
||||
Hooks.Register.Onload(func() {
|
||||
plugin_enable()
|
||||
thumb_size()
|
||||
thumb_quality()
|
||||
thumb_caching()
|
||||
image_quality()
|
||||
image_caching()
|
||||
})
|
||||
|
||||
Hooks.Register.ProcessFileContentBeforeSend(func(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
|
||||
if plugin_enable() == false {
|
||||
@ -134,7 +127,7 @@ func init() {
|
||||
/////////////////////////
|
||||
// Specify transformation
|
||||
transform := &Transform{
|
||||
Input: GetAbsolutePath(ImageCachePath + "imagein_" + QuickString(10)),
|
||||
Input: filepath.Join(GetAbsolutePath(TMP_PATH), "imagein_"+QuickString(10)),
|
||||
Size: thumb_size(),
|
||||
Crop: true,
|
||||
Quality: thumb_quality(),
|
||||
|
||||
@ -37,7 +37,6 @@ func init() {
|
||||
return f
|
||||
}).Bool()
|
||||
}
|
||||
SEARCH_ENABLE()
|
||||
SEARCH_PROCESS_MAX = func() int {
|
||||
return Config.Get("features.search.process_max").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -52,7 +51,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
SEARCH_PROCESS_MAX()
|
||||
SEARCH_PROCESS_PAR = func() int {
|
||||
return Config.Get("features.search.process_par").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -67,7 +65,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
SEARCH_PROCESS_PAR()
|
||||
SEARCH_REINDEX = func() int {
|
||||
return Config.Get("features.search.reindex_time").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -82,7 +79,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
SEARCH_REINDEX()
|
||||
CYCLE_TIME = func() int {
|
||||
return Config.Get("features.search.cycle_time").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -97,7 +93,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
CYCLE_TIME()
|
||||
MAX_INDEXING_FSIZE = func() int {
|
||||
return Config.Get("features.search.max_size").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -112,7 +107,6 @@ func init() {
|
||||
return f
|
||||
}).Int()
|
||||
}
|
||||
MAX_INDEXING_FSIZE()
|
||||
INDEXING_EXT = func() string {
|
||||
return Config.Get("features.search.indexer_ext").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
@ -127,32 +121,41 @@ func init() {
|
||||
return f
|
||||
}).String()
|
||||
}
|
||||
INDEXING_EXT()
|
||||
|
||||
onChange := Config.ListenForChange()
|
||||
runner := func() {
|
||||
startSearch := false
|
||||
for {
|
||||
if SEARCH_ENABLE() == false {
|
||||
select {
|
||||
case <-onChange.Listener:
|
||||
startSearch = SEARCH_ENABLE()
|
||||
Hooks.Register.Onload(func() {
|
||||
SEARCH_ENABLE()
|
||||
SEARCH_PROCESS_MAX()
|
||||
SEARCH_PROCESS_PAR()
|
||||
SEARCH_REINDEX()
|
||||
CYCLE_TIME()
|
||||
MAX_INDEXING_FSIZE()
|
||||
INDEXING_EXT()
|
||||
|
||||
onChange := Config.ListenForChange()
|
||||
runner := func() {
|
||||
startSearch := false
|
||||
for {
|
||||
if SEARCH_ENABLE() == false {
|
||||
select {
|
||||
case <-onChange.Listener:
|
||||
startSearch = SEARCH_ENABLE()
|
||||
}
|
||||
if startSearch == false {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if startSearch == false {
|
||||
sidx := SProc.Peek()
|
||||
if sidx == nil {
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
sidx.mu.Lock()
|
||||
sidx.Execute()
|
||||
sidx.mu.Unlock()
|
||||
}
|
||||
sidx := SProc.Peek()
|
||||
if sidx == nil {
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
sidx.mu.Lock()
|
||||
sidx.Execute()
|
||||
sidx.mu.Unlock()
|
||||
}
|
||||
}
|
||||
for i := 0; i < SEARCH_PROCESS_PAR(); i++ {
|
||||
go runner()
|
||||
}
|
||||
for i := 0; i < SEARCH_PROCESS_PAR(); i++ {
|
||||
go runner()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ func init() {
|
||||
return f
|
||||
}).Int()) * time.Millisecond
|
||||
}
|
||||
SEARCH_TIMEOUT()
|
||||
|
||||
Hooks.Register.Onload(func() {
|
||||
SEARCH_TIMEOUT()
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -8,8 +8,12 @@ import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
disable_svg func() bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
disable_svg := func() bool {
|
||||
disable_svg = func() bool {
|
||||
return Config.Get("features.protection.disable_svg").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
@ -23,22 +27,25 @@ func init() {
|
||||
return f
|
||||
}).Bool()
|
||||
}
|
||||
disable_svg()
|
||||
|
||||
Hooks.Register.ProcessFileContentBeforeSend(func(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
|
||||
if GetMimeType(req.URL.Query().Get("path")) != "image/svg+xml" {
|
||||
return reader, nil
|
||||
} else if disable_svg() == true {
|
||||
return reader, ErrNotAllowed
|
||||
Hooks.Register.Onload(func() {
|
||||
if disable_svg() == false {
|
||||
return
|
||||
}
|
||||
Hooks.Register.ProcessFileContentBeforeSend(func(reader io.ReadCloser, ctx *App, res *http.ResponseWriter, req *http.Request) (io.ReadCloser, error) {
|
||||
if GetMimeType(req.URL.Query().Get("path")) != "image/svg+xml" {
|
||||
return reader, nil
|
||||
} else if disable_svg() == true {
|
||||
return reader, ErrNotAllowed
|
||||
}
|
||||
|
||||
// XSS
|
||||
(*res).Header().Set("Content-Security-Policy", "script-src 'none'; default-src 'none'; img-src 'self'")
|
||||
// XML bomb
|
||||
txt, _ := ioutil.ReadAll(reader)
|
||||
if regexp.MustCompile("(?is)entity").Match(txt) {
|
||||
txt = []byte("")
|
||||
}
|
||||
return NewReadCloserFromBytes(txt), nil
|
||||
// XSS
|
||||
(*res).Header().Set("Content-Security-Policy", "script-src 'none'; default-src 'none'; img-src 'self'")
|
||||
// XML bomb
|
||||
txt, _ := ioutil.ReadAll(reader)
|
||||
if regexp.MustCompile("(?is)entity").Match(txt) {
|
||||
txt = []byte("")
|
||||
}
|
||||
return NewReadCloserFromBytes(txt), nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -2,22 +2,26 @@ package plg_starter_http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func init() {
|
||||
port := Config.Get("general.port").Int()
|
||||
|
||||
Hooks.Register.Starter(func(r *mux.Router) {
|
||||
Log.Info("[http] starting ...")
|
||||
port := Config.Get("general.port").Int()
|
||||
srv := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", port),
|
||||
Handler: r,
|
||||
}
|
||||
go ensureAppHasBooted(fmt.Sprintf("http://127.0.0.1:%d/about", port), fmt.Sprintf("[http] listening on :%d", port))
|
||||
go ensureAppHasBooted(
|
||||
fmt.Sprintf("http://127.0.0.1:%d/about", port),
|
||||
fmt.Sprintf("[http] listening on :%d", port),
|
||||
)
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
Log.Error("error: %v", err)
|
||||
return
|
||||
|
||||
@ -9,26 +9,37 @@ package plg_starter_http2
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/mickael-kerjean/filestash/server/common/ssl"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"github.com/mickael-kerjean/filestash/server/common/ssl"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
var SSL_PATH string = GetAbsolutePath(CERT_PATH, "ssl")
|
||||
var (
|
||||
SSL_PATH string
|
||||
config_port func() int
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.MkdirAll(SSL_PATH, os.ModePerm)
|
||||
domain := Config.Get("general.host").String()
|
||||
config_port = func() int {
|
||||
return Config.Get("general.port").Int()
|
||||
}
|
||||
Hooks.Register.Onload(func() {
|
||||
SSL_PATH = filepath.Join(GetAbsolutePath(CERT_PATH), "ssl")
|
||||
os.MkdirAll(SSL_PATH, os.ModePerm)
|
||||
})
|
||||
|
||||
Hooks.Register.Starter(func(r *mux.Router) {
|
||||
domain := Config.Get("general.host").String()
|
||||
Log.Info("[https] starting ...%s", domain)
|
||||
srv := &http.Server{
|
||||
Addr: fmt.Sprintf(":https"),
|
||||
Addr: fmt.Sprintf(":%d", config_port()),
|
||||
Handler: r,
|
||||
TLSConfig: &DefaultTLSConfig,
|
||||
ErrorLog: NewNilLogger(),
|
||||
@ -56,29 +67,32 @@ func init() {
|
||||
srv.TLSConfig.GetCertificate = mngr.GetCertificate
|
||||
}
|
||||
|
||||
go ensureAppHasBooted("https://127.0.0.1/about", fmt.Sprintf("[https] started"))
|
||||
go func() {
|
||||
if err := srv.ListenAndServeTLS("", ""); err != nil {
|
||||
Log.Error("[https]: listen_serve %v", err)
|
||||
srv = &http.Server{
|
||||
Addr: fmt.Sprintf(":http"),
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Connection", "close")
|
||||
http.Redirect(
|
||||
w,
|
||||
req,
|
||||
"https://"+req.Host+req.URL.String(),
|
||||
http.StatusMovedPermanently,
|
||||
)
|
||||
}),
|
||||
}
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
srv := http.Server{
|
||||
Addr: fmt.Sprintf(":http"),
|
||||
ReadTimeout: 5 * time.Second,
|
||||
WriteTimeout: 5 * time.Second,
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Connection", "close")
|
||||
http.Redirect(
|
||||
w,
|
||||
req,
|
||||
"https://"+req.Host+req.URL.String(),
|
||||
http.StatusMovedPermanently,
|
||||
)
|
||||
}),
|
||||
}
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
Log.Error("[https]: http_redirect %v", err)
|
||||
|
||||
go ensureAppHasBooted(
|
||||
fmt.Sprintf("https://127.0.0.1:%d/about", config_port()),
|
||||
fmt.Sprintf("[https] started"),
|
||||
)
|
||||
if err := srv.ListenAndServeTLS("", ""); err != nil {
|
||||
Log.Error("[https]: listen_serve %v", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
@ -11,10 +11,9 @@ import (
|
||||
)
|
||||
|
||||
func init() {
|
||||
domain := Config.Get("general.host").String()
|
||||
port := Config.Get("general.port").Int()
|
||||
|
||||
Hooks.Register.Starter(func(r *mux.Router) {
|
||||
domain := Config.Get("general.host").String()
|
||||
port := Config.Get("general.port").Int()
|
||||
Log.Info("[https] starting ...%s", domain)
|
||||
srv := &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", port),
|
||||
|
||||
@ -7,15 +7,16 @@ import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
var TOR_PATH string = GetAbsolutePath(CERT_PATH, "tor")
|
||||
var (
|
||||
enable_plugin func() bool
|
||||
tor_url func() string
|
||||
)
|
||||
|
||||
func init() {
|
||||
os.MkdirAll(TOR_PATH, os.ModePerm)
|
||||
enable_tor := func() bool {
|
||||
enable_plugin = func() bool {
|
||||
return Config.Get("features.server.tor_enable").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
@ -29,29 +30,37 @@ func init() {
|
||||
return f
|
||||
}).Bool()
|
||||
}
|
||||
enable_tor()
|
||||
Config.Get("features.server.tor_url").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "tor_url"
|
||||
f.Name = "tor_url"
|
||||
f.Type = "text"
|
||||
f.Target = []string{}
|
||||
f.Description = "Your onion site"
|
||||
f.ReadOnly = true
|
||||
f.Placeholder = "LOADING... Refresh the page in a few seconds"
|
||||
return f
|
||||
})
|
||||
tor_url = func() string {
|
||||
return Config.Get("features.server.tor_url").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
}
|
||||
f.Id = "tor_url"
|
||||
f.Name = "tor_url"
|
||||
f.Type = "text"
|
||||
f.Target = []string{}
|
||||
f.Description = "Your onion site"
|
||||
f.ReadOnly = true
|
||||
f.Placeholder = "LOADING... Refresh the page in a few seconds"
|
||||
return f
|
||||
}).String()
|
||||
}
|
||||
|
||||
Hooks.Register.Onload(func() {
|
||||
tor_url()
|
||||
enable_plugin()
|
||||
})
|
||||
Hooks.Register.Starter(func(r *mux.Router) {
|
||||
if enable_tor() == false {
|
||||
torPath := GetAbsolutePath(CERT_PATH, "tor")
|
||||
os.MkdirAll(torPath, os.ModePerm)
|
||||
|
||||
if enable_plugin() == false {
|
||||
startTor := false
|
||||
onChange := Config.ListenForChange()
|
||||
for {
|
||||
select {
|
||||
case <-onChange.Listener:
|
||||
startTor = enable_tor()
|
||||
startTor = enable_plugin()
|
||||
}
|
||||
if startTor == true {
|
||||
break
|
||||
@ -62,7 +71,7 @@ func init() {
|
||||
|
||||
Log.Info("[tor] starting ...")
|
||||
t, err := tor.Start(nil, &tor.StartConf{
|
||||
DataDir: TOR_PATH,
|
||||
DataDir: torPath,
|
||||
})
|
||||
if err != nil {
|
||||
Log.Error("[tor] Unable to start Tor: %v", err)
|
||||
|
||||
@ -2,8 +2,10 @@ package plg_video_transcoder
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
@ -20,11 +22,17 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
HLS_SEGMENT_LENGTH = 30
|
||||
HLS_SEGMENT_LENGTH = 5
|
||||
FPS = 30
|
||||
CLEAR_CACHE_AFTER = 12
|
||||
VideoCachePath = "data/cache/video/"
|
||||
)
|
||||
|
||||
var (
|
||||
plugin_enable func() bool
|
||||
blacklist_format func() string
|
||||
)
|
||||
|
||||
func init() {
|
||||
ffmpegIsInstalled := false
|
||||
ffprobeIsInstalled := false
|
||||
@ -34,7 +42,7 @@ func init() {
|
||||
if _, err := exec.LookPath("ffprobe"); err == nil {
|
||||
ffprobeIsInstalled = true
|
||||
}
|
||||
plugin_enable := func() bool {
|
||||
plugin_enable = func() bool {
|
||||
return Config.Get("features.video.enable_transcoder").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
@ -50,8 +58,7 @@ func init() {
|
||||
return f
|
||||
}).Bool()
|
||||
}
|
||||
|
||||
blacklist_format := func() string {
|
||||
blacklist_format = func() string {
|
||||
return Config.Get("features.video.blacklist_format").Schema(func(f *FormElement) *FormElement {
|
||||
if f == nil {
|
||||
f = &FormElement{}
|
||||
@ -67,50 +74,52 @@ func init() {
|
||||
return f
|
||||
}).String()
|
||||
}
|
||||
blacklist_format()
|
||||
|
||||
if plugin_enable() == false {
|
||||
return
|
||||
} else if ffmpegIsInstalled == false {
|
||||
Log.Warning("[plugin video transcoder] ffmpeg needs to be installed")
|
||||
return
|
||||
} else if ffprobeIsInstalled == false {
|
||||
Log.Warning("[plugin video transcoder] ffprobe needs to be installed")
|
||||
return
|
||||
}
|
||||
Hooks.Register.Onload(func() {
|
||||
blacklist_format()
|
||||
if plugin_enable() == false {
|
||||
return
|
||||
} else if ffmpegIsInstalled == false {
|
||||
Log.Warning("[plugin video transcoder] ffmpeg needs to be installed")
|
||||
return
|
||||
} else if ffprobeIsInstalled == false {
|
||||
Log.Warning("[plugin video transcoder] ffprobe needs to be installed")
|
||||
return
|
||||
}
|
||||
|
||||
cachePath := GetAbsolutePath(VideoCachePath)
|
||||
os.RemoveAll(cachePath)
|
||||
os.MkdirAll(cachePath, os.ModePerm)
|
||||
cachePath := GetAbsolutePath(VideoCachePath)
|
||||
os.RemoveAll(cachePath)
|
||||
os.MkdirAll(cachePath, os.ModePerm)
|
||||
|
||||
Hooks.Register.ProcessFileContentBeforeSend(hls_playlist)
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
||||
r.PathPrefix("/hls/hls_{segment}.ts").Handler(NewMiddlewareChain(
|
||||
hls_transcode,
|
||||
[]Middleware{SecureHeaders},
|
||||
*app,
|
||||
)).Methods("GET")
|
||||
return nil
|
||||
})
|
||||
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
||||
r.HandleFunc(OverrideVideoSourceMapper, func(res http.ResponseWriter, req *http.Request) {
|
||||
res.Header().Set("Content-Type", GetMimeType(req.URL.String()))
|
||||
res.Write([]byte(`window.overrides["video-map-sources"] = function(sources){`))
|
||||
res.Write([]byte(` return sources.map(function(source){`))
|
||||
|
||||
blacklists := strings.Split(blacklist_format(), ",")
|
||||
for i := 0; i < len(blacklists); i++ {
|
||||
blacklists[i] = strings.TrimSpace(blacklists[i])
|
||||
res.Write([]byte(fmt.Sprintf(`if(source.type == "%s"){ return source; } `, GetMimeType("."+blacklists[i]))))
|
||||
}
|
||||
res.Write([]byte(` source.src = source.src + "&transcode=hls";`))
|
||||
res.Write([]byte(` source.type = "application/x-mpegURL";`))
|
||||
res.Write([]byte(` return source;`))
|
||||
res.Write([]byte(` })`))
|
||||
res.Write([]byte(`}`))
|
||||
Hooks.Register.ProcessFileContentBeforeSend(hls_playlist)
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
||||
r.PathPrefix("/hls/hls_{segment}.ts").Handler(NewMiddlewareChain(
|
||||
hls_transcode,
|
||||
[]Middleware{SecureHeaders},
|
||||
*app,
|
||||
)).Methods("GET")
|
||||
return nil
|
||||
})
|
||||
|
||||
Hooks.Register.HttpEndpoint(func(r *mux.Router, app *App) error {
|
||||
r.HandleFunc(OverrideVideoSourceMapper, func(res http.ResponseWriter, req *http.Request) {
|
||||
res.Header().Set("Content-Type", GetMimeType(req.URL.String()))
|
||||
res.Write([]byte(`window.overrides["video-map-sources"] = function(sources){`))
|
||||
res.Write([]byte(` return sources.map(function(source){`))
|
||||
|
||||
blacklists := strings.Split(blacklist_format(), ",")
|
||||
for i := 0; i < len(blacklists); i++ {
|
||||
blacklists[i] = strings.TrimSpace(blacklists[i])
|
||||
res.Write([]byte(fmt.Sprintf(`if(source.type == "%s"){ return source; } `, GetMimeType("."+blacklists[i]))))
|
||||
}
|
||||
res.Write([]byte(` source.src = source.src + "&transcode=hls";`))
|
||||
res.Write([]byte(` source.type = "application/x-mpegURL";`))
|
||||
res.Write([]byte(` return source;`))
|
||||
res.Write([]byte(` })`))
|
||||
res.Write([]byte(`}`))
|
||||
})
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user