V0.2.1 - update signup (#47)

Co-authored-by: Graham Steffaniak <graham.steffaniak@autodesk.com>
This commit is contained in:
Graham Steffaniak 2023-10-10 20:03:33 -05:00 committed by GitHub
parent 1429963e76
commit d53426b580
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 102 additions and 276 deletions

View File

@ -118,7 +118,7 @@ func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfac
} }
func quickSetup(d pythonData) { func quickSetup(d pythonData) {
settings.GlobalConfiguration.Key = generateKey() settings.GlobalConfiguration.Auth.Key = generateKey()
if settings.GlobalConfiguration.Auth.Method == "noauth" { if settings.GlobalConfiguration.Auth.Method == "noauth" {
err := d.store.Auth.Save(&auth.NoAuth{}) err := d.store.Auth.Save(&auth.NoAuth{})
checkErr(err) checkErr(err)
@ -131,8 +131,8 @@ func quickSetup(d pythonData) {
checkErr(err) checkErr(err)
err = d.store.Settings.SaveServer(&settings.GlobalConfiguration.Server) err = d.store.Settings.SaveServer(&settings.GlobalConfiguration.Server)
checkErr(err) checkErr(err)
username := settings.GlobalConfiguration.AdminUsername username := settings.GlobalConfiguration.Auth.AdminUsername
password := settings.GlobalConfiguration.AdminPassword password := settings.GlobalConfiguration.Auth.AdminPassword
if username == "" || password == "" { if username == "" || password == "" {
log.Fatal("username and password cannot be empty during quick setup") log.Fatal("username and password cannot be empty during quick setup")
} }

View File

@ -1,9 +1,10 @@
server: server:
port: 8080 port: 8080
baseURL: "/" baseURL: "/"
root: "/Users/steffag/git/go"
auth: auth:
method: password method: password
signup: true signup: false
userDefaults: userDefaults:
darkMode: true darkMode: true
disableSettings: false disableSettings: false

View File

@ -55,7 +55,7 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
func withUser(fn handleFunc) handleFunc { func withUser(fn handleFunc) handleFunc {
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
keyFunc := func(token *jwt.Token) (interface{}, error) { keyFunc := func(token *jwt.Token) (interface{}, error) {
return d.settings.Key, nil return d.settings.Auth.Key, nil
} }
var tk authToken var tk authToken
@ -112,7 +112,7 @@ type signupBody struct {
} }
var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
if !d.settings.Signup { if !settings.GlobalConfiguration.Auth.Signup {
return http.StatusMethodNotAllowed, nil return http.StatusMethodNotAllowed, nil
} }
@ -142,7 +142,7 @@ var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int,
} }
user.Scope = userHome user.Scope = userHome
log.Printf("new user: %s, home dir: [%s].", user.Username, userHome) log.Printf("new user: %s, home dir: [%s].", user.Username, userHome)
settings.GlobalConfiguration.UserDefaults.Apply(user)
err = d.store.Users.Save(user) err = d.store.Users.Save(user)
if err == errors.ErrExist { if err == errors.ErrExist {
return http.StatusConflict, err return http.StatusConflict, err
@ -168,7 +168,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use
} }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signed, err := token.SignedString(d.settings.Key) signed, err := token.SignedString(d.settings.Auth.Key)
if err != nil { if err != nil {
return http.StatusInternalServerError, err return http.StatusInternalServerError, err
} }

View File

@ -85,7 +85,11 @@ func TestPublicShareHandlerAuthentication(t *testing.T) {
if err := storage.Users.Save(&users.User{Username: "username", Password: "pw"}); err != nil { if err := storage.Users.Save(&users.User{Username: "username", Password: "pw"}); err != nil {
t.Fatalf("failed to save user: %v", err) t.Fatalf("failed to save user: %v", err)
} }
if err := storage.Settings.Save(&settings.Settings{Key: []byte("key")}); err != nil { if err := storage.Settings.Save(&settings.Settings{
Auth: settings.Auth{
Key: []byte("key"),
},
}); err != nil {
t.Fatalf("failed to save settings: %v", err) t.Fatalf("failed to save settings: %v", err)
} }

View File

@ -21,9 +21,9 @@ type settingsData struct {
var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
data := &settingsData{ data := &settingsData{
Signup: d.settings.Signup, Signup: settings.GlobalConfiguration.Auth.Signup,
CreateUserDir: d.settings.CreateUserDir, CreateUserDir: settings.GlobalConfiguration.Server.CreateUserDir,
UserHomeBasePath: d.settings.UserHomeBasePath, UserHomeBasePath: settings.GlobalConfiguration.Server.UserHomeBasePath,
Defaults: d.settings.UserDefaults, Defaults: d.settings.UserDefaults,
Rules: d.settings.Rules, Rules: d.settings.Rules,
Frontend: d.settings.Frontend, Frontend: d.settings.Frontend,
@ -41,9 +41,8 @@ var settingsPutHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
return http.StatusBadRequest, err return http.StatusBadRequest, err
} }
d.settings.Signup = req.Signup d.settings.Server.CreateUserDir = req.CreateUserDir
d.settings.CreateUserDir = req.CreateUserDir d.settings.Server.UserHomeBasePath = req.UserHomeBasePath
d.settings.UserHomeBasePath = req.UserHomeBasePath
d.settings.UserDefaults = req.Defaults d.settings.UserDefaults = req.Defaults
d.settings.Rules = req.Rules d.settings.Rules = req.Rules
d.settings.Frontend = req.Frontend d.settings.Frontend = req.Frontend

View File

@ -30,11 +30,12 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
"Name": d.settings.Frontend.Name, "Name": d.settings.Frontend.Name,
"DisableExternal": d.settings.Frontend.DisableExternal, "DisableExternal": d.settings.Frontend.DisableExternal,
"DisableUsedPercentage": d.settings.Frontend.DisableUsedPercentage, "DisableUsedPercentage": d.settings.Frontend.DisableUsedPercentage,
"darkMode": settings.GlobalConfiguration.UserDefaults.DarkMode,
"Color": d.settings.Frontend.Color, "Color": d.settings.Frontend.Color,
"BaseURL": d.server.BaseURL, "BaseURL": d.server.BaseURL,
"Version": version.Version, "Version": version.Version,
"StaticURL": path.Join(d.server.BaseURL, "/static"), "StaticURL": path.Join(d.server.BaseURL, "/static"),
"Signup": d.settings.Signup, "Signup": settings.GlobalConfiguration.Auth.Signup,
"NoAuth": d.settings.Auth.Method == "noauth", "NoAuth": d.settings.Auth.Method == "noauth",
"AuthMethod": d.settings.Auth.Method, "AuthMethod": d.settings.Auth.Method,
"LoginPage": auther.LoginPage(), "LoginPage": auther.LoginPage(),

View File

@ -45,9 +45,6 @@ func loadConfigFile(configFile string) []byte {
func setDefaults() Settings { func setDefaults() Settings {
return Settings{ return Settings{
Signup: true,
AdminUsername: "admin",
AdminPassword: "admin",
Server: Server{ Server: Server{
EnableThumbnails: true, EnableThumbnails: true,
EnableExec: false, EnableExec: false,
@ -60,8 +57,10 @@ func setDefaults() Settings {
Root: "/srv", Root: "/srv",
}, },
Auth: Auth{ Auth: Auth{
Method: "password", AdminUsername: "admin",
Signup: true, AdminPassword: "admin",
Method: "password",
Signup: true,
Recaptcha: Recaptcha{ Recaptcha: Recaptcha{
Host: "", Host: "",
}, },

View File

@ -21,13 +21,13 @@ var (
// MakeUserDir makes the user directory according to settings. // MakeUserDir makes the user directory according to settings.
func (s *Settings) MakeUserDir(username, userScope, serverRoot string) (string, error) { func (s *Settings) MakeUserDir(username, userScope, serverRoot string) (string, error) {
userScope = strings.TrimSpace(userScope) userScope = strings.TrimSpace(userScope)
if userScope == "" && s.CreateUserDir { if userScope == "" && s.Server.CreateUserDir {
username = cleanUsername(username) username = cleanUsername(username)
if username == "" || username == "-" || username == "." { if username == "" || username == "-" || username == "." {
log.Printf("create user: invalid user for home dir creation: [%s]", username) log.Printf("create user: invalid user for home dir creation: [%s]", username)
return "", errors.New("invalid user for home dir creation") return "", errors.New("invalid user for home dir creation")
} }
userScope = path.Join(s.UserHomeBasePath, username) userScope = path.Join(s.Server.UserHomeBasePath, username)
} }
userScope = path.Join("/", userScope) userScope = path.Join("/", userScope)

View File

@ -8,7 +8,6 @@ import (
func TestSettings_MakeUserDir(t *testing.T) { func TestSettings_MakeUserDir(t *testing.T) {
type fields struct { type fields struct {
Key []byte
Signup bool Signup bool
CreateUserDir bool CreateUserDir bool
UserHomeBasePath string UserHomeBasePath string
@ -40,20 +39,14 @@ func TestSettings_MakeUserDir(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
s := &Settings{ s := &Settings{
Key: tt.fields.Key, Commands: tt.fields.Commands,
Signup: tt.fields.Signup, Shell: tt.fields.Shell,
CreateUserDir: tt.fields.CreateUserDir, Rules: tt.fields.Rules,
UserHomeBasePath: tt.fields.UserHomeBasePath, Server: tt.fields.Server,
Commands: tt.fields.Commands, Auth: tt.fields.Auth,
Shell: tt.fields.Shell, Frontend: tt.fields.Frontend,
AdminUsername: tt.fields.AdminUsername, Users: tt.fields.Users,
AdminPassword: tt.fields.AdminPassword, UserDefaults: tt.fields.UserDefaults,
Rules: tt.fields.Rules,
Server: tt.fields.Server,
Auth: tt.fields.Auth,
Frontend: tt.fields.Frontend,
Users: tt.fields.Users,
UserDefaults: tt.fields.UserDefaults,
} }
got, err := s.MakeUserDir(tt.args.username, tt.args.userScope, tt.args.serverRoot) got, err := s.MakeUserDir(tt.args.username, tt.args.userScope, tt.args.serverRoot)
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {

View File

@ -29,8 +29,8 @@ func (s *Storage) Get() (*Settings, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
if set.UserHomeBasePath == "" { if set.Server.UserHomeBasePath == "" {
set.UserHomeBasePath = DefaultUsersHomeBasePath set.Server.UserHomeBasePath = DefaultUsersHomeBasePath
} }
return set, nil return set, nil
} }
@ -45,7 +45,7 @@ var defaultEvents = []string{
// Save saves the settings for the current instance. // Save saves the settings for the current instance.
func (s *Storage) Save(set *Settings) error { func (s *Storage) Save(set *Settings) error {
if len(set.Key) == 0 { if len(set.Auth.Key) == 0 {
return errors.ErrEmptyKey return errors.ErrEmptyKey
} }

View File

@ -6,29 +6,26 @@ import (
) )
type Settings struct { type Settings struct {
Key []byte `json:"key"` Commands map[string][]string `json:"commands"`
Signup bool `json:"signup"` Shell []string `json:"shell"`
CreateUserDir bool `json:"createUserDir"` Rules []rules.Rule `json:"rules"`
UserHomeBasePath string `json:"userHomeBasePath"` Server Server `json:"server"`
Commands map[string][]string `json:"commands"` Auth Auth `json:"auth"`
Shell []string `json:"shell"` Frontend Frontend `json:"frontend"`
AdminUsername string `json:"adminUsername"` Users []UserDefaults `json:"users,omitempty"`
AdminPassword string `json:"adminPassword"` UserDefaults UserDefaults `json:"userDefaults"`
Rules []rules.Rule `json:"rules"`
Server Server `json:"server"`
Auth Auth `json:"auth"`
Frontend Frontend `json:"frontend"`
Users []UserDefaults `json:"users,omitempty"`
UserDefaults UserDefaults `json:"userDefaults"`
} }
type Auth struct { type Auth struct {
Recaptcha Recaptcha `json:"recaptcha"` Recaptcha Recaptcha `json:"recaptcha"`
Header string `json:"header"` Header string `json:"header"`
Method string `json:"method"` Method string `json:"method"`
Command string `json:"command"` Command string `json:"command"`
Signup bool `json:"signup"` Signup bool `json:"signup"`
Shell string `json:"shell"` Shell string `json:"shell"`
AdminUsername string `json:"adminUsername"`
AdminPassword string `json:"adminPassword"`
Key []byte `json:"key"`
} }
type Recaptcha struct { type Recaptcha struct {
@ -54,6 +51,8 @@ type Server struct {
Log string `json:"log"` Log string `json:"log"`
Database string `json:"database"` Database string `json:"database"`
Root string `json:"root"` Root string `json:"root"`
UserHomeBasePath string `json:"userHomeBasePath"`
CreateUserDir bool `json:"createUserDir"`
} }
type Frontend struct { type Frontend struct {

View File

@ -2,7 +2,6 @@ package bolt
import ( import (
"fmt" "fmt"
"log"
"reflect" "reflect"
"github.com/asdine/storm/v3" "github.com/asdine/storm/v3"
@ -74,7 +73,6 @@ func (st usersBackend) Update(user *users.User, fields ...string) error {
} }
func (st usersBackend) Save(user *users.User) error { func (st usersBackend) Save(user *users.User) error {
log.Println("userinfo", user.Password)
pass, err := users.HashPwd(user.Password) pass, err := users.HashPwd(user.Password)
if err != nil { if err != nil {
return err return err

View File

@ -1,14 +1,11 @@
package users package users
import ( import (
"log"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
) )
// HashPwd hashes a password. // HashPwd hashes a password.
func HashPwd(password string) (string, error) { func HashPwd(password string) (string, error) {
log.Println("hashing password", password)
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err return string(bytes), err
} }

View File

@ -7,10 +7,11 @@ This document covers the available configuration options, their defaults, and ho
Here is an expanded config file which includes all possible configurations: Here is an expanded config file which includes all possible configurations:
``` ```
signup: false
adminUsername: admin adminUsername: admin
adminPassword: admin adminPassword: admin
server: server:
CreateUserDir: false
UserHomeBasePath: ""
indexingInterval: 5 indexingInterval: 5
numImageProcessors: 4 numImageProcessors: 4
socket: "" socket: ""
@ -33,6 +34,7 @@ auth:
header: "" header: ""
method: json method: json
command: "" command: ""
signup: false
shell: "" shell: ""
frontend: frontend:
name: "" name: ""
@ -67,7 +69,6 @@ userDefaults:
Here are the defaults if nothing is set: Here are the defaults if nothing is set:
``` ```
signup: true
adminUsername: admin adminUsername: admin
adminPassword: admin adminPassword: admin
server: server:
@ -107,12 +108,6 @@ userDefaults:
## About each configuration ## About each configuration
- `Signup`: This boolean value indicates whether user signup is enabled on the login page. NOTE: Be mindful of `userDefaults` settings if enabled. Default: `false`
- `AdminUsername`: This is the username of the admin user. Default: `admin`
- `AdminPassword`: This is the password of the admin user. Default: `admin`
### Server configuration settings ### Server configuration settings
- `indexingInterval`: This is the time in minutes the system waits before checking for filesystem changes. Default: `5` - `indexingInterval`: This is the time in minutes the system waits before checking for filesystem changes. Default: `5`
@ -143,6 +138,10 @@ userDefaults:
- `root`: This is the root directory path. Default: `/srv` - `root`: This is the root directory path. Default: `/srv`
- `CreateUserDir`: Boolean to create user directory on user creation. Default: `false`
- `UserHomeBasePath`: String to define user home directory base path. Default: `""`
### Auth configuration settings ### Auth configuration settings
- `recaptcha`: - `recaptcha`:
@ -166,6 +165,12 @@ userDefaults:
- `shell`: This is the shell configuration. - `shell`: This is the shell configuration.
- `Signup`: This boolean value indicates whether user signup is enabled on the login page. NOTE: Be mindful of `userDefaults` settings if enabled. Default: `false`
- `AdminUsername`: This is the username of the admin user. Default: `admin`
- `AdminPassword`: This is the password of the admin user. Default: `admin`
### Frontend configuration settings ### Frontend configuration settings
- `name`: This is the name of the frontend. - `name`: This is the name of the frontend.

View File

@ -1,42 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="700.000000pt" height="700.000000pt" viewBox="0 0 700.000000 700.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,700.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M3245 6989 c-522 -39 -1042 -197 -1480 -449 -849 -488 -1459 -1308
-1673 -2250 -177 -776 -89 -1582 250 -2301 368 -778 1052 -1418 1857 -1739
903 -359 1927 -325 2812 92 778 368 1418 1052 1739 1857 359 903 325 1927 -92
2812 -296 627 -806 1175 -1423 1529 -587 338 -1308 500 -1990 449z m555 -580
c519 -51 1018 -245 1446 -565 788 -588 1229 -1526 1174 -2496 -16 -277 -58
-500 -145 -763 -144 -440 -378 -819 -710 -1150 -452 -452 -1005 -730 -1655
-832 -91 -14 -175 -18 -405 -18 -304 0 -369 6 -595 51 -1105 223 -1999 1092
-2259 2197 -52 221 -73 412 -73 667 0 397 64 732 204 1080 304 752 886 1334
1638 1638 431 174 895 238 1380 191z"/>
<path d="M2670 5215 c0 -13 -44 -15 -335 -15 -352 0 -383 -3 -399 -45 -3 -9
-6 -758 -6 -1663 0 -1168 -3 -1643 -11 -1632 -8 11 -9 8 -4 -15 3 -16 17 -41
31 -55 l24 -25 1530 0 1530 0 24 25 c14 14 26 36 27 50 1 14 1 711 1 1550 l-2
1526 -228 142 -229 142 -136 0 -137 0 0 -600 0 -600 -705 0 -705 0 0 615 0
615 -135 0 c-113 0 -135 -2 -135 -15z m-264 -190 c57 -29 89 -71 103 -137 35
-154 -98 -282 -258 -247 -55 12 -122 62 -148 113 -36 69 -12 186 49 243 62 58
170 70 254 28z m2316 -1702 c17 -15 18 -49 18 -670 l0 -653 -1245 0 -1245 0 0
654 c0 582 2 656 16 670 14 14 139 16 1226 16 1113 0 1213 -1 1230 -17z
m-2602 -1363 c40 -40 13 -100 -43 -100 -60 0 -88 59 -47 100 11 11 31 20 45
20 14 0 34 -9 45 -20z m2840 0 c41 -41 11 -100 -52 -100 -35 0 -58 24 -58 60
0 54 71 79 110 40z"/>
<path d="M2431 3091 c-7 -13 -7 -23 2 -35 11 -15 97 -16 1067 -14 l1055 3 0
30 0 30 -1057 3 c-1023 2 -1058 1 -1067 -17z"/>
<path d="M2436 2675 c-19 -19 -11 -41 17 -49 41 -11 2067 -7 2088 4 23 13 25
46 3 54 -9 3 -483 6 -1054 6 -919 0 -1040 -2 -1054 -15z"/>
<path d="M2447 2273 c-14 -4 -17 -13 -15 -36 l3 -32 1049 -3 c767 -1 1052 1
1062 9 20 16 17 47 -5 59 -20 10 -2055 13 -2094 3z"/>
<path d="M3822 5027 c-21 -23 -22 -30 -22 -293 0 -258 1 -271 20 -292 27 -29
56 -35 140 -30 56 3 75 8 93 26 22 22 22 26 22 298 l0 276 -24 19 c-19 16 -40
19 -115 19 -84 0 -95 -2 -114 -23z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,147 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xml:space="preserve"
width="560"
height="560"
version="1.1"
style="clip-rule:evenodd;fill-rule:evenodd;image-rendering:optimizeQuality;shape-rendering:geometricPrecision;text-rendering:geometricPrecision"
viewBox="0 0 560 560"
id="svg44"
sodipodi:docname="icon_raw.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
inkscape:export-filename="/home/umarcor/filebrowser/logo/icon_raw.svg.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"><metadata
id="metadata48"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="711"
id="namedview46"
showgrid="false"
inkscape:zoom="0.33714286"
inkscape:cx="-172.33051"
inkscape:cy="280"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="svg44" />
<defs
id="defs4">
<style
type="text/css"
id="style2">
<![CDATA[
.fil1 {fill:#FEFEFE}
.fil6 {fill:#006498}
.fil7 {fill:#0EA5EB}
.fil8 {fill:#2979FF}
.fil3 {fill:#2BBCFF}
.fil0 {fill:#455A64}
.fil4 {fill:#53C6FC}
.fil5 {fill:#BDEAFF}
.fil2 {fill:#332C2B;fill-opacity:0.149020}
]]>
</style>
</defs>
<g
id="g85"
transform="translate(-70,-70)"><path
class="fil1"
d="M 350,71 C 504,71 629,196 629,350 629,504 504,629 350,629 196,629 71,504 71,350 71,196 196,71 350,71 Z"
id="path9"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil2"
d="M 475,236 593,387 C 596,503 444,639 301,585 L 225,486 339,330 c 0,0 138,-95 136,-94 z"
id="path11"
inkscape:connector-curvature="0"
style="fill:#332c2b;fill-opacity:0.14902003" /><path
class="fil3"
d="m 231,211 h 208 l 38,24 v 246 c 0,5 -3,8 -8,8 H 231 c -5,0 -8,-3 -8,-8 V 219 c 0,-5 3,-8 8,-8 z"
id="path13"
inkscape:connector-curvature="0"
style="fill:#2bbcff" /><path
class="fil4"
d="m 231,211 h 208 l 38,24 v 2 L 440,214 H 231 c -4,0 -7,3 -7,7 v 263 c -1,-1 -1,-2 -1,-3 V 219 c 0,-5 3,-8 8,-8 z"
id="path15"
inkscape:connector-curvature="0"
style="fill:#53c6fc" /><polygon
class="fil5"
points="305,212 418,212 418,310 305,310 "
id="polygon17"
style="fill:#bdeaff" /><path
class="fil5"
d="m 255,363 h 189 c 3,0 5,2 5,4 V 483 H 250 V 367 c 0,-2 2,-4 5,-4 z"
id="path19"
inkscape:connector-curvature="0"
style="fill:#bdeaff" /><polygon
class="fil6"
points="250,470 449,470 449,483 250,483 "
id="polygon21"
style="fill:#006498" /><path
class="fil6"
d="m 380,226 h 10 c 3,0 6,2 6,5 v 40 c 0,3 -3,6 -6,6 h -10 c -3,0 -6,-3 -6,-6 v -40 c 0,-3 3,-5 6,-5 z"
id="path23"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil1"
d="m 254,226 c 10,0 17,7 17,17 0,9 -7,16 -17,16 -9,0 -17,-7 -17,-16 0,-10 8,-17 17,-17 z"
id="path25"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil6"
d="m 267,448 h 165 c 2,0 3,1 3,3 v 0 c 0,1 -1,3 -3,3 H 267 c -2,0 -3,-2 -3,-3 v 0 c 0,-2 1,-3 3,-3 z"
id="path27"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil6"
d="m 267,415 h 165 c 2,0 3,1 3,3 v 0 c 0,1 -1,2 -3,2 H 267 c -2,0 -3,-1 -3,-2 v 0 c 0,-2 1,-3 3,-3 z"
id="path29"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil6"
d="m 267,381 h 165 c 2,0 3,2 3,3 v 0 c 0,2 -1,3 -3,3 H 267 c -2,0 -3,-1 -3,-3 v 0 c 0,-1 1,-3 3,-3 z"
id="path31"
inkscape:connector-curvature="0"
style="fill:#006498" /><path
class="fil1"
d="m 236,472 c 3,0 5,2 5,5 0,2 -2,4 -5,4 -3,0 -5,-2 -5,-4 0,-3 2,-5 5,-5 z"
id="path33"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><path
class="fil1"
d="m 463,472 c 3,0 5,2 5,5 0,2 -2,4 -5,4 -3,0 -5,-2 -5,-4 0,-3 2,-5 5,-5 z"
id="path35"
inkscape:connector-curvature="0"
style="fill:#fefefe" /><polygon
class="fil6"
points="305,212 284,212 284,310 305,310 "
id="polygon37"
style="fill:#006498" /><path
class="fil7"
d="m 477,479 v 2 c 0,5 -3,8 -8,8 H 231 c -5,0 -8,-3 -8,-8 v -2 c 0,4 3,8 8,8 h 238 c 5,0 8,-4 8,-8 z"
id="path39"
inkscape:connector-curvature="0"
style="fill:#0ea5eb" /><path
class="fil8"
d="M 350,70 C 505,70 630,195 630,350 630,505 505,630 350,630 195,630 70,505 70,350 70,195 195,70 350,70 Z m 0,46 C 479,116 584,221 584,350 584,479 479,584 350,584 221,584 116,479 116,350 116,221 221,116 350,116 Z"
id="path41"
inkscape:connector-curvature="0"
style="fill:#2979ff" /></g>
</svg>

Before

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -120,17 +120,22 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<div id="loading"> [{[ if .darkMode -]}]
<div id="loading dark-mode">
<div class="spinner"> <div class="spinner">
<div class="bounce1"></div> <div class="bounce1"></div>
<div class="bounce2"></div> <div class="bounce2"></div>
<div class="bounce3"></div> <div class="bounce3"></div>
</div> </div>
</div> </div>
[{[ else ]}]
[{[ if .darkMode -]}] <div id="loading">
<link rel="stylesheet" href="[{[ .StaticURL ]}]/themes/dark.css" /> <div class="spinner">
[{[ end ]}] <div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div> [{[ end ]}]
[{[ if .CSS -]}] [{[ if .CSS -]}]
<link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" /> <link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" />
[{[ end ]}] [{[ end ]}]

View File

@ -1,5 +1,5 @@
#login { #login {
background: #fff; background: var(--background);
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;

View File

@ -3,11 +3,12 @@ const disableExternal = window.FileBrowser.DisableExternal;
const disableUsedPercentage = window.FileBrowser.DisableUsedPercentage; const disableUsedPercentage = window.FileBrowser.DisableUsedPercentage;
const baseURL = window.FileBrowser.BaseURL; const baseURL = window.FileBrowser.BaseURL;
const staticURL = window.FileBrowser.StaticURL; const staticURL = window.FileBrowser.StaticURL;
const darkMode = window.FileBrowser.darkMode;
const recaptcha = window.FileBrowser.ReCaptcha; const recaptcha = window.FileBrowser.ReCaptcha;
const recaptchaKey = window.FileBrowser.ReCaptchaKey; const recaptchaKey = window.FileBrowser.ReCaptchaKey;
const signup = window.FileBrowser.Signup; const signup = window.FileBrowser.Signup;
const version = window.FileBrowser.Version; const version = window.FileBrowser.Version;
const logoURL = `${staticURL}/img/logo.svg`; const logoURL = `${staticURL}/img/logo.png`;
const noAuth = window.FileBrowser.NoAuth; const noAuth = window.FileBrowser.NoAuth;
const authMethod = window.FileBrowser.AuthMethod; const authMethod = window.FileBrowser.AuthMethod;
const loginPage = window.FileBrowser.LoginPage; const loginPage = window.FileBrowser.LoginPage;
@ -16,6 +17,7 @@ const resizePreview = window.FileBrowser.ResizePreview;
const enableExec = window.FileBrowser.EnableExec; const enableExec = window.FileBrowser.EnableExec;
const origin = window.location.origin; const origin = window.location.origin;
console.log(window.FileBrowser)
export { export {
name, name,
disableExternal, disableExternal,
@ -33,4 +35,5 @@ export {
resizePreview, resizePreview,
enableExec, enableExec,
origin, origin,
darkMode
}; };

View File

@ -1,5 +1,5 @@
<template> <template>
<div id="login" :class="{ recaptcha: recaptcha }"> <div id="login" :class="{ recaptcha: recaptcha, 'dark-mode': isDarkMode }">
<form @submit="submit"> <form @submit="submit">
<img :src="logoURL" alt="File Browser" /> <img :src="logoURL" alt="File Browser" />
<h1>{{ name }}</h1> <h1>{{ name }}</h1>
@ -51,6 +51,7 @@ import {
recaptcha, recaptcha,
recaptchaKey, recaptchaKey,
signup, signup,
darkMode,
} from "@/utils/constants"; } from "@/utils/constants";
export default { export default {
@ -59,6 +60,9 @@ export default {
signup: () => signup, signup: () => signup,
name: () => name, name: () => name,
logoURL: () => logoURL, logoURL: () => logoURL,
isDarkMode() {
return darkMode === true
},
}, },
data: function () { data: function () {
return { return {

View File

@ -57,7 +57,7 @@ export default {
this.$store.commit("updateRequest", { name: "Settings" }); this.$store.commit("updateRequest", { name: "Settings" });
}, },
computed: { computed: {
...mapState(["user"]), ...mapState(["user", "loading"]),
settingsEnabled() { settingsEnabled() {
return this.user.disableSettings == false; return this.user.disableSettings == false;
}, },

View File

@ -4,7 +4,7 @@
@mousemove="toggleNavigation" @mousemove="toggleNavigation"
@touchstart="toggleNavigation" @touchstart="toggleNavigation"
> >
<div class="loading delayed" v-if="loading"> <div class="loading delayed" :class="{ 'dark-mode': isDarkMode }" v-if="loading">
<div class="spinner"> <div class="spinner">
<div class="bounce1"></div> <div class="bounce1"></div>
<div class="bounce2"></div> <div class="bounce2"></div>
@ -103,7 +103,7 @@
<script> <script>
import { mapState } from "vuex"; import { mapState } from "vuex";
import { files as api } from "@/api"; import { files as api } from "@/api";
import { resizePreview } from "@/utils/constants"; import { resizePreview, darkMode } from "@/utils/constants";
import url from "@/utils/url"; import url from "@/utils/url";
import throttle from "lodash.throttle"; import throttle from "lodash.throttle";
import ExtendedImage from "@/components/files/ExtendedImage"; import ExtendedImage from "@/components/files/ExtendedImage";
@ -132,6 +132,9 @@ export default {
}, },
computed: { computed: {
...mapState(["req", "user", "oldReq", "jwt", "loading", "show"]), ...mapState(["req", "user", "oldReq", "jwt", "loading", "show"]),
isDarkMode() {
return this.user && this.user.darkMode ? this.user.darkMode : darkMode;
},
hasPrevious() { hasPrevious() {
return this.previousLink !== ""; return this.previousLink !== "";
}, },

View File

@ -37,7 +37,7 @@
</form> </form>
</div> </div>
<div v-if="$store.state.show === 'deleteUser'" class="card floating"> <div v-if="showDeletePrompt" class="card floating">
<div class="card-content"> <div class="card-content">
<p>Are you sure you want to delete this user?</p> <p>Are you sure you want to delete this user?</p>
</div> </div>
@ -78,6 +78,7 @@ export default {
error: null, error: null,
originalUser: null, originalUser: null,
user: {}, user: {},
showDelete: false,
createUserDir: false, createUserDir: false,
}; };
}, },
@ -89,6 +90,9 @@ export default {
return this.$route.path === "/settings/users/new"; return this.$route.path === "/settings/users/new";
}, },
...mapState(["loading"]), ...mapState(["loading"]),
showDeletePrompt() {
return this.showDelete
},
}, },
watch: { watch: {
$route: "fetchData", $route: "fetchData",
@ -125,7 +129,7 @@ export default {
} }
}, },
deletePrompt() { deletePrompt() {
this.showHover("deleteUser"); this.showDelete = true
}, },
async deleteUser(event) { async deleteUser(event) {
event.preventDefault(); event.preventDefault();