Skip to content

updated swagger #568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,37 @@ All notable changes to this project will be documented in this file. For commit
- Enhanced user settings page with more toggle options.
- Replaced checkboxes with toggles switches https://github.com/gtsteffaniak/filebrowser/issues/461
- Refreshed Breadcrumbs style.
- main navbar icon is multipurpose menu, close, back and animates
- Main navbar icon is multipurpose menu, close, back and animates
- Enhanced source info on the UI
- User must have permission `realtime: true` property to get realtime events.
- Sources shows status of the directory `ready`, `indexing`, and `unavailable`
- top-right overflow menu for deleting / editing files in peview https://github.com/gtsteffaniak/filebrowser/issues/456
- helpful UI animation for drag and drop files, to get feedback where the drop target is.
- more consistent theme color https://github.com/gtsteffaniak/filebrowser/issues/538
- Top-right overflow menu for deleting / editing files in peview https://github.com/gtsteffaniak/filebrowser/issues/456
- Helpful UI animation for drag and drop files, to get feedback where the drop target is.
- More consistent theme color https://github.com/gtsteffaniak/filebrowser/issues/538
- New file preview types:
- Video thumbnails available via new media integration (see configuration wiki for help) https://github.com/gtsteffaniak/filebrowser/issues/351
- Office file previews if you have office integration enabled. https://github.com/gtsteffaniak/filebrowser/issues/460

**Notes**:
- sesssionId is now unique per window. Previously it was shared accross browser tabs.
- disableUsedPercentage is a backend property now, so users can't "hack" the information to be shown.
- updated documentation for resources api https://github.com/gtsteffaniak/filebrowser/issues/560
- updated placeholder for scopes https://github.com/gtsteffaniak/filebrowser/issues/475
- DisableUsedPercentage is a backend property now, so users can't "hack" the information to be shown.
- Updated documentation for resources api https://github.com/gtsteffaniak/filebrowser/issues/560
- Updated placeholder for scopes https://github.com/gtsteffaniak/filebrowser/issues/475
- When user's API permissions are removed, any api keys the user had will be revoked.
- `server.enableThumbnails` moved to `server.disablePreviews` defaulting to false.

**Bug Fixes**:
- Nil pointer error when source media is disconnected while running.
- source selection buggy https://github.com/gtsteffaniak/filebrowser/issues/537
- upload folder structure https://github.com/gtsteffaniak/filebrowser/issues/539
- Source selection buggy https://github.com/gtsteffaniak/filebrowser/issues/537
- Upload folder structure https://github.com/gtsteffaniak/filebrowser/issues/539
- Editing files on multiple sources https://github.com/gtsteffaniak/filebrowser/issues/535
- Prevent the user from changing the password https://github.com/gtsteffaniak/filebrowser/issues/550
- Links in setting page does not navigate to correct location https://github.com/gtsteffaniak/filebrowser/issues/474
- Url encoding issue https://github.com/gtsteffaniak/filebrowser/issues/530
- certain file types being treated as folders https://github.com/gtsteffaniak/filebrowser/issues/555
- source name with special characters https://github.com/gtsteffaniak/filebrowser/issues/557
- onlyoffice support on proxy auth https://github.com/gtsteffaniak/filebrowser/issues/559
- downloading with user scope https://github.com/gtsteffaniak/filebrowser/issues/564
- Certain file types being treated as folders https://github.com/gtsteffaniak/filebrowser/issues/555
- Source name with special characters https://github.com/gtsteffaniak/filebrowser/issues/557
- Onlyoffice support on proxy auth https://github.com/gtsteffaniak/filebrowser/issues/559
- Downloading with user scope https://github.com/gtsteffaniak/filebrowser/issues/564
- User disableSettings property to be respected.
- Non admin users updating admin settings.
- Right click context issue on safari desktop.
Expand Down
17 changes: 17 additions & 0 deletions backend/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,31 @@ package auth

import (
"net/http"
"sync"

"github.com/gtsteffaniak/filebrowser/backend/database/users"
)

var (
revokedApiKeyList map[string]bool
revokeMu sync.Mutex
)

// Auther is the authentication interface.
type Auther interface {
// Auth is called to authenticate a request.
Auth(r *http.Request, userStore *users.Storage) (*users.User, error)
// LoginPage indicates if this auther needs a login page.
LoginPage() bool
}

func IsRevokedApiKey(key string) bool {
_, exists := revokedApiKeyList[key]
return exists
}

func RevokeAPIKey(key string) {
revokeMu.Lock()
delete(revokedApiKeyList, key)
revokeMu.Unlock()
}
2 changes: 1 addition & 1 deletion backend/auth/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
if len(a.Fields.Values) > 1 {
u = a.GetUser(u)
// update user with provided fields
err := a.Users.Update(u, true)
err := a.Users.Update(u, u.Permissions.Admin)
if err != nil {
return nil, err
}
Expand Down
5 changes: 3 additions & 2 deletions backend/common/settings/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ func setupAuth() {
if Config.Auth.Methods.ProxyAuth.Enabled {
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "Proxy")
}
if Config.Auth.Methods.OidcAuth.Enabled {
Config.Auth.AuthMethods = append(Config.Auth.AuthMethods, "OIDC")
}
if Config.Auth.Methods.NoAuth {
logger.Warning("Configured with no authentication, this is not recommended.")
Config.Auth.AuthMethods = []string{"Disabled"}
Expand Down Expand Up @@ -232,8 +235,6 @@ func loadEnvConfig() {
func setDefaults() Settings {
return Settings{
Server: Server{
EnableThumbnails: true,
ResizePreview: false,
Port: 80,
NumImageProcessors: 4,
BaseURL: "",
Expand Down
19 changes: 19 additions & 0 deletions backend/common/settings/config_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package settings

import (
"os"
"reflect"
"testing"

Expand Down Expand Up @@ -52,6 +53,24 @@ func TestConfigLoadChanged(t *testing.T) {
}
}

func TestConfigLoadEnvVars(t *testing.T) {
defaultConfig := setDefaults()
expectedKey := "MYKEY"
// mock environment variables
os.Setenv("FILEBROWSER_ONLYOFFICE_SECRET", expectedKey)
err := loadConfigWithDefaults("./validConfig.yaml")
if err != nil {
t.Fatalf("error loading config file: %v", err)
}
if Config.Integrations.OnlyOffice.Secret != expectedKey {
t.Errorf("Expected OnlyOffice.Secret to be '%v', got '%s'", expectedKey, Config.Integrations.OnlyOffice.Secret)
}
// Use go-cmp to compare the two structs
if diff := cmp.Diff(defaultConfig, Config); diff == "" {
t.Errorf("No change when there should have been (-want +got):\n%s", diff)
}
}

func TestConfigLoadSpecificValues(t *testing.T) {
defaultConfig := setDefaults()
err := loadConfigWithDefaults("./validConfig.yaml")
Expand Down
31 changes: 16 additions & 15 deletions backend/common/settings/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,22 @@ type Settings struct {
}

type Server struct {
NumImageProcessors int `json:"numImageProcessors"`
Socket string `json:"socket"`
TLSKey string `json:"tlsKey"`
TLSCert string `json:"tlsCert"`
EnableThumbnails bool `json:"enableThumbnails"`
ResizePreview bool `json:"resizePreview"`
Port int `json:"port"`
BaseURL string `json:"baseURL"`
Logging []LogConfig `json:"logging"`
Database string `json:"database"`
Sources []Source `json:"sources" validate:"required,dive"`
ExternalUrl string `json:"externalUrl"`
InternalUrl string `json:"internalUrl"` // used by integrations
CacheDir string `json:"cacheDir"`
MaxArchiveSizeGB int64 `json:"maxArchiveSize"`
NumImageProcessors int `json:"numImageProcessors"`
Socket string `json:"socket"`
TLSKey string `json:"tlsKey"`
TLSCert string `json:"tlsCert"`
DisablePreviews bool `json:"disablePreview"`
ResizePreviews bool `json:"resizePreview"`
DisableTypeDetectionByHeader bool `json:"disableTypeDetectionByHeader"`
Port int `json:"port"`
BaseURL string `json:"baseURL"`
Logging []LogConfig `json:"logging"`
Database string `json:"database"`
Sources []Source `json:"sources" validate:"required,dive"`
ExternalUrl string `json:"externalUrl"`
InternalUrl string `json:"internalUrl"` // used by integrations
CacheDir string `json:"cacheDir"`
MaxArchiveSizeGB int64 `json:"maxArchiveSize"`
// not exposed to config
SourceMap map[string]Source `json:"-" validate:"omitempty"` // uses realpath as key
NameToSource map[string]Source `json:"-" validate:"omitempty"` // uses name as key
Expand Down
2 changes: 1 addition & 1 deletion backend/common/settings/validConfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ server:
socket: ""
tlsKey: ""
tlsCert: ""
enableThumbnails: false
disablePreview: false
resizePreview: true
port: 80
baseURL: "/"
Expand Down
8 changes: 8 additions & 0 deletions backend/database/storage/bolt/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
storm "github.com/asdine/storm/v3"

"github.com/gtsteffaniak/filebrowser/backend/adapters/fs/files"
"github.com/gtsteffaniak/filebrowser/backend/auth"
"github.com/gtsteffaniak/filebrowser/backend/common/errors"
"github.com/gtsteffaniak/filebrowser/backend/common/logger"
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
Expand Down Expand Up @@ -123,6 +124,13 @@ func (st usersBackend) Update(user *users.User, actorIsAdmin bool, fields ...str
return fmt.Errorf("failed to update user field: %s, error: %v", field, err)
}
}

// last revoke api keys if needed.
if existingUser.Permissions.Api && !user.Permissions.Api && slices.Contains(fields, "Permissions") {
for _, key := range existingUser.ApiKeys {
auth.RevokeAPIKey(key.Key) // add to blacklist
}
}
return nil
}

Expand Down
4 changes: 2 additions & 2 deletions backend/database/users/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (s *Storage) AddApiKey(userID uint, name string, key AuthToken) error {
user.ApiKeys = make(map[string]AuthToken)
}
user.ApiKeys[name] = key
err = s.Update(user, false, "ApiKeys")
err = s.Update(user, true, "ApiKeys")
if err != nil {
return err
}
Expand All @@ -105,7 +105,7 @@ func (s *Storage) DeleteApiKey(userID uint, name string) error {
user.ApiKeys = make(map[string]AuthToken)
}
delete(user.ApiKeys, name)
err = s.Update(user, false, "ApiKeys")
err = s.Update(user, true, "ApiKeys")
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion backend/http/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"time"

"github.com/gtsteffaniak/filebrowser/backend/auth"
"github.com/gtsteffaniak/filebrowser/backend/database/users"
)

Expand Down Expand Up @@ -101,7 +102,7 @@ func deleteApiKeyHandler(w http.ResponseWriter, r *http.Request, d *requestConte
return http.StatusNotFound, err
}

revokeAPIKey(keyInfo.Key) // add to blacklist
auth.RevokeAPIKey(keyInfo.Key) // add to blacklist
response := HttpResponse{
Message: "successfully deleted api key from user",
}
Expand Down
17 changes: 0 additions & 17 deletions backend/http/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"net/http"
"net/url"
"strings"
"sync"
"time"

jwt "github.com/golang-jwt/jwt/v4"
Expand All @@ -24,11 +23,6 @@ import (
"github.com/gtsteffaniak/filebrowser/backend/database/users"
)

var (
revokedApiKeyList map[string]bool
revokeMu sync.Mutex
)

// first checks for cookie
// then checks for header Authorization as Bearer token
// then checks for query parameter
Expand Down Expand Up @@ -250,17 +244,6 @@ func printToken(w http.ResponseWriter, _ *http.Request, user *users.User) (int,
return 0, nil
}

func isRevokedApiKey(key string) bool {
_, exists := revokedApiKeyList[key]
return exists
}

func revokeAPIKey(key string) {
revokeMu.Lock()
delete(revokedApiKeyList, key)
revokeMu.Unlock()
}

func makeSignedTokenAPI(user *users.User, name string, duration time.Duration, perms users.Permissions) (users.AuthToken, error) {
_, ok := user.ApiKeys[name]
if ok {
Expand Down
11 changes: 2 additions & 9 deletions backend/http/httpRouter.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
"github.com/gtsteffaniak/filebrowser/backend/common/version"
"github.com/gtsteffaniak/filebrowser/backend/database/storage"
httpSwagger "github.com/swaggo/http-swagger" // http-swagger middleware
// http-swagger middleware
)

// Embed the files in the frontend/dist directory
Expand Down Expand Up @@ -135,14 +135,7 @@ func StartHttp(ctx context.Context, storage *storage.Storage, shutdownComplete c
router.HandleFunc(fmt.Sprintf("GET %vhealth", config.Server.BaseURL), healthHandler)

// Swagger
router.Handle(fmt.Sprintf("%vswagger/", config.Server.BaseURL),
httpSwagger.Handler(
httpSwagger.URL(config.Server.BaseURL+"swagger/doc.json"), //The url pointing to API definition
httpSwagger.DeepLinking(true),
httpSwagger.DocExpansion("none"),
httpSwagger.DomID("swagger-ui"),
),
)
router.Handle(fmt.Sprintf("%vswagger/", config.Server.BaseURL), withUser(swaggerHandler))

var scheme string
port := ""
Expand Down
16 changes: 9 additions & 7 deletions backend/http/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,21 @@ import (

jwt "github.com/golang-jwt/jwt/v4"
"github.com/gtsteffaniak/filebrowser/backend/adapters/fs/files"
"github.com/gtsteffaniak/filebrowser/backend/auth"
"github.com/gtsteffaniak/filebrowser/backend/common/logger"
"github.com/gtsteffaniak/filebrowser/backend/database/share"
"github.com/gtsteffaniak/filebrowser/backend/database/users"
"github.com/gtsteffaniak/filebrowser/backend/indexing/iteminfo"
)

type requestContext struct {
user *users.User
raw interface{}
path string
token string
share *share.Link
ctx context.Context
user *users.User
raw interface{}
fileInfo iteminfo.ExtendedFileInfo
path string
token string
share *share.Link
ctx context.Context
}

type HttpResponse struct {
Expand Down Expand Up @@ -136,7 +138,7 @@ func withUserHelper(fn handleFunc) handleFunc {
if !token.Valid {
return http.StatusUnauthorized, fmt.Errorf("invalid token")
}
if isRevokedApiKey(tk.Key) || tk.Expires < time.Now().Unix() {
if auth.IsRevokedApiKey(tk.Key) || tk.Expires < time.Now().Unix() {
return http.StatusUnauthorized, fmt.Errorf("token expired or revoked")
}
// Check if the token is about to expire and send a header to renew it
Expand Down
Loading
Loading