Compare commits
No files matched your search
@@ -1,4 +1,4 @@
|
||||
backend/database.db
|
||||
backend/**.db
|
||||
backend/vendor/**
|
||||
frontend/dist/**
|
||||
frontend/node_modules/**
|
||||
@@ -1,24 +0,0 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v5
|
||||
with:
|
||||
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
|
||||
close-pr-message: 'This PR was closed because it has been stalled for 5 days with no activity.'
|
||||
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
|
||||
days-before-stale: 30
|
||||
days-before-close: 5
|
||||
exempt-issue-labels: 'feature ☘,enhancement ⚙,bug 🐞'
|
||||
exempt-pr-labels: 'need-help,wip'
|
||||
operations-per-run: 100
|
||||
@@ -2,6 +2,30 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
# v0.2.1
|
||||
- issue #29 - Rules can now be configured and read from configuration yaml
|
||||
- issue #28 - Allow disable settings per user.
|
||||
- issue #27 - shorten download link for password protected files
|
||||
- issue #26 - enable dark mode per user and improve switching performance.
|
||||
- More rounded corners and improved listing styling
|
||||
- improve search performance
|
||||
- fixes authentication issues
|
||||
- adds compact view mode
|
||||
- improves view mode configuration and behavior
|
||||
- updates configuration file to accept new settings
|
||||
|
||||
# v0.2.0
|
||||
- improved UI
|
||||
- more unified coehisive look
|
||||
- Adjusted header bar look and icon behavior
|
||||
- The shell is dead.
|
||||
- If you need to use custom commands, exec into the docker container.
|
||||
- The json config file is dead.
|
||||
- All configuration is done via advanced `filebrowser.yaml`
|
||||
- The only flag that is allowed is flag to specify config file.
|
||||
- Removed old code to migrate database versions
|
||||
- Removed all unused cmd code
|
||||
|
||||
# v0.1.4
|
||||
- various UI fixes
|
||||
- Added download button back to toolbar
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
## Filebrowser
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/license/apache-2-0/"><img src="https://img.shields.io/badge/License-Apache_2.0-blue.svg" alt="License: Apache-2.0"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="frontend/public/img/icons/favicon-256x256.png" width="100" title="Login With Custom URL">
|
||||
</p>
|
||||
<h3 align="center">Filebrowser - A modern file manager for the web</h3>
|
||||
<p align="center">
|
||||
<img width="500" src="https://github.com/gtsteffaniak/filebrowser/assets/42989099/b45683b0-bd55-4430-9831-650fe0d21eb8" title="Main Screenshot">
|
||||
</p>
|
||||
|
||||
**Note: Intended to be used in docker only.**
|
||||
> **NOTE**
|
||||
Intended for docker use only
|
||||
|
||||
> **Warning**
|
||||
Starting with v0.2.0, *ALL* configuration is done via `filebrowser.yaml` configuration file. `.filebrowser.json` and any flags other than `-c` and `-config` during execution WILL NO LONGER WORK. This is by design, in order to use the v0.2.0 You can mount your directory and initialize a new DB with a new default `filebrowser.yaml` which you can tweak and use in the future. Or you can copy and paste the default startup `filebrowser.yaml` below.
|
||||
|
||||
This fork makes the following significant changes to filebrowser for origin:
|
||||
|
||||
1. [x] Improves search to use index instead of filesystem.
|
||||
- [x] Lightning fast
|
||||
- [x] Realtime results as you type
|
||||
- [x] Works with file type filter
|
||||
- [x] better desktop search view
|
||||
1. [ ] Preview enhancements
|
||||
- Preview default view is constrained to files subwindow,
|
||||
which can be toggled to fullscreen.
|
||||
1. [x] Improved and simplified GUI
|
||||
- Moved all action buttons to file action bar except for switch-view
|
||||
- Simplified navbar to 3 main actions: settings,search, and switch-view
|
||||
- New search view on desktop
|
||||
1. [x] Updated version and dependencies
|
||||
- [x] Uses latest npm and node version
|
||||
- [x] Removes deprecated npm packages
|
||||
- [x] Updates golang dependencies
|
||||
- [ ] Remove all unnecessary packages, replaces with generic functions.
|
||||
1. [ ] Moved all configurations to filebrowser.json.
|
||||
no more flags or binary operations to db
|
||||
1. [ ] File browsing uses index first for better performance
|
||||
- file details shown only when toggled or needed
|
||||
- Lightning fast, realtime results as you type
|
||||
- Works with more type filters
|
||||
1. [x] Improved and simplified GUI navbar and sidebar menu.
|
||||
1. [x] Updated version and dependencies.
|
||||
1. [x] **IMPORTANT** Moved all configurations to `filebrowser.yaml`.
|
||||
|
||||
## About
|
||||
|
||||
@@ -38,50 +36,46 @@ work better in terms of asthetics and performance. Improved search,
|
||||
simplified ui (without removing features) and more secure and up-to-date
|
||||
build are just a few examples.
|
||||
|
||||
There are a few more changes needed to get it to a stable status where it
|
||||
will only recieve security updates. These changes are mentioned above.
|
||||
Once this is fully complete, the only updates to th
|
||||
|
||||
## Look
|
||||
<p align="center">
|
||||
<img width="500" src="https://github.com/gtsteffaniak/filebrowser/assets/42989099/35cdeb3b-ab79-4b04-8001-8f51f6ea06bb" title="Dark mode">
|
||||
<img width="500" alt="image" src="https://github.com/gtsteffaniak/filebrowser/assets/42989099/55fa4f5c-440e-4a97-b711-96139208a163">
|
||||
<img width="500" alt="image" src="https://github.com/gtsteffaniak/filebrowser/assets/42989099/c76f4100-949b-4e17-a3e6-e410fb8ec08f">
|
||||
<img width="500" alt="image" src="https://github.com/gtsteffaniak/filebrowser/assets/42989099/0bde26f3-fa90-411e-bd0b-abaa47506d62">
|
||||
<img width="560" alt="image" src="https://github.com/gtsteffaniak/filebrowser/assets/42989099/71d8f2b8-6fe6-4fdc-8aac-503d08c28d86">
|
||||
|
||||
General UI desktop (dark mode):
|
||||

|
||||
|
||||
[General UI mobile (dark mode)](https://github.com/gtsteffaniak/filebrowser/assets/42989099/634d3ba6-7ac0-425b-8a83-419743e92fec)
|
||||
</p>
|
||||
|
||||

|
||||
## Search Performance
|
||||
|
||||
[However, mobile search still appears very similar to filebrowser/filebrowsers original implementation](https://github.com/gtsteffaniak/filebrowser/assets/42989099/e179b821-f4e2-4568-b895-4e00de371637)
|
||||
|
||||
## Performance
|
||||
|
||||
Search Performance - 100x faster search. However, this will be at expense of RAM. if you have < 1 million
|
||||
100x faster search. However, this will be at expense of RAM. if you have < 1 million
|
||||
files and folders in the given scope, the RAM usage should be less than 200MB total. RAM requirements
|
||||
should scale based on the number of directories.
|
||||
|
||||
Also , the approx. time to fully index will vary widely based on performance. A sufficiently performant
|
||||
system should fully index within the first 5 minutes, potentially within the first few seconds.
|
||||
|
||||
For example, a low end 11th gen i5 with SSD indexes 86K files within 1 second:
|
||||
For example, a low end 11th gen i5 with SSD indexes 128K files within 1 second:
|
||||
|
||||
```
|
||||
2023/08/01 00:08:29 Using config file: /.filebrowser.json
|
||||
2023/08/01 00:08:29 Indexing files...
|
||||
2023/08/01 00:08:29 Listening on [::]:8080
|
||||
2023/08/01 00:08:30 Successfully indexed files.
|
||||
2023/08/01 00:08:30 Files found : 85310
|
||||
2023/08/01 00:08:30 Directories found : 1711
|
||||
2023/08/01 00:08:30 Indexing scheduler will run every 5 minutes
|
||||
2023/09/09 21:38:50 Initializing with config file: filebrowser.yaml
|
||||
2023/09/09 21:38:50 Indexing files...
|
||||
2023/09/09 21:38:50 Listening on [::]:8080
|
||||
2023/09/09 21:38:51 Successfully indexed files.
|
||||
2023/09/09 21:38:51 Files found : 123452
|
||||
2023/09/09 21:38:51 Directories found : 1768
|
||||
2023/09/09 21:38:51 Indexing scheduler will run every 5 minutes
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
Using docker:
|
||||
|
||||
1. docker run:
|
||||
1. docker run (no persistent db):
|
||||
|
||||
```
|
||||
docker run -it -v /path/to/folder:/srv -p 8080:8080 gtstef/filebrowser
|
||||
docker run -it -v /path/to/folder:/srv -p 80:8080 gtstef/filebrowser
|
||||
```
|
||||
|
||||
1. docker-compose:
|
||||
@@ -93,12 +87,13 @@ version: '3.7'
|
||||
services:
|
||||
filebrowser:
|
||||
volumes:
|
||||
- '/path/to/folder:/srv'
|
||||
#- './database/:/database/'
|
||||
- './config.json:/.filebrowser.json'
|
||||
- '/path/to/folder:/srv' # required (for now not configurable)
|
||||
- './database:/database' # optional if you want db to persist - configure a path under "database" dir in config file.
|
||||
- './filebrowser.yaml:/filebrowser.yaml' # required
|
||||
ports:
|
||||
- '8080:8080'
|
||||
- '80:8080'
|
||||
image: gtstef/filebrowser
|
||||
restart: always
|
||||
```
|
||||
|
||||
- with network share
|
||||
@@ -108,30 +103,39 @@ version: '3.7'
|
||||
services:
|
||||
filebrowser:
|
||||
volumes:
|
||||
- 'nas:/srv'
|
||||
#- './database/:/database/'
|
||||
#- './config.json:/.filebrowser.json'
|
||||
- 'storage:/srv' # required (for now not configurable)
|
||||
- './database:/database' # optional if you want db to persist - configure a path under "database" dir in config file.
|
||||
- './filebrowser.yaml:/filebrowser.yaml' # required
|
||||
ports:
|
||||
- '8080:80'
|
||||
- '80:8080'
|
||||
image: gtstef/filebrowser
|
||||
restart: always
|
||||
volumes:
|
||||
nas:
|
||||
storage:
|
||||
driver_opts:
|
||||
type: cifs
|
||||
o: "username=myusername,password=mypassword,rw"
|
||||
device: "//fileshare/"
|
||||
o: "username=admin,password=password,rw" # enter valid info here
|
||||
device: "//192.168.1.100/share/" # enter valid hinfo here
|
||||
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Note: still a WIP migrating configuration to json.
|
||||
All configuration is now done via a single configuration file: `filebrowser.yaml`, here is an example minimal [configuration file](./backend/filebrowser.yaml).
|
||||
|
||||
All configuration is now done via the filebrowser.json config file.
|
||||
This was chosen because it works best with a docker first use case.
|
||||
View the [Configuration Help Page](./configuration.md) for available configuration options and other help.
|
||||
|
||||
Previously the primary way to configure filebrowser was via flags.
|
||||
But this quickly became cumbersome if you had many configurations to make
|
||||
### background & help
|
||||
|
||||
The original project filebrowser/filebrowser used multiple different ways to configure the server.
|
||||
This was confusing and difficult to work with from a user and from a developer's perspective.
|
||||
So I completely redesigned the program to use one single human-readable config file.
|
||||
|
||||
I understand many coming from the original fork may notice differences which make using this improved version more difficult. If you notice issues that you believe should be fixed, please open an issue here and it will very likely be addressed with a PR within a few weeks.
|
||||
|
||||
This version of filebrowser is going through a configuration overhaul as mentioned above. Certain features related to rules and commands may not work as they do on the original filebrowser. The purpose of this is to create a more consistent experience where configuration is done via files rather than running commands, so that it's very clear what the current state of the configuration is. When running commands its not clear what the configuration is.
|
||||
|
||||
## Roadmap
|
||||
|
||||
see [Roadmap Page](./roadmap.md)
|
||||
|
||||
The other method to configure was via `filebrowser config` commands which
|
||||
would write configurations to a db if it existed already.
|
||||
When considering
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
|
||||
"port": 8080,
|
||||
"baseURL": "",
|
||||
"address": "",
|
||||
"log": "stdout",
|
||||
"database": "./database.db",
|
||||
"root": "/srv"
|
||||
|
||||
}
|
||||
@@ -3,14 +3,13 @@ package auth
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
// Auther is the authentication interface.
|
||||
type Auther interface {
|
||||
// Auth is called to authenticate a request.
|
||||
Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error)
|
||||
Auth(r *http.Request, usr users.Store) (*users.User, error)
|
||||
// LoginPage indicates if this auther needs a login page.
|
||||
LoginPage() bool
|
||||
}
|
||||
@@ -15,9 +15,6 @@ import (
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
// MethodHookAuth is used to identify hook auth.
|
||||
const MethodHookAuth = "hook"
|
||||
|
||||
type hookCred struct {
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
@@ -34,7 +31,7 @@ type HookAuth struct {
|
||||
}
|
||||
|
||||
// Auth authenticates the user via a json in content body.
|
||||
func (a *HookAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
|
||||
func (a *HookAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
|
||||
var cred hookCred
|
||||
|
||||
if r.Body == nil {
|
||||
@@ -47,8 +44,8 @@ func (a *HookAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings
|
||||
}
|
||||
|
||||
a.Users = usr
|
||||
a.Settings = stg
|
||||
a.Server = srv
|
||||
a.Settings = &settings.GlobalConfiguration
|
||||
a.Server = &settings.GlobalConfiguration.Server
|
||||
a.Cred = cred
|
||||
|
||||
action, err := a.RunCommand()
|
||||
@@ -149,23 +146,19 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
}
|
||||
|
||||
if u == nil {
|
||||
pass, err := users.HashPwd(a.Cred.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println("creds", a.Cred.Password)
|
||||
// create user with the provided credentials
|
||||
d := &users.User{
|
||||
Username: a.Cred.Username,
|
||||
Password: pass,
|
||||
Scope: a.Settings.Defaults.Scope,
|
||||
Locale: a.Settings.Defaults.Locale,
|
||||
ViewMode: a.Settings.Defaults.ViewMode,
|
||||
SingleClick: a.Settings.Defaults.SingleClick,
|
||||
Sorting: a.Settings.Defaults.Sorting,
|
||||
Perm: a.Settings.Defaults.Perm,
|
||||
Commands: a.Settings.Defaults.Commands,
|
||||
HideDotfiles: a.Settings.Defaults.HideDotfiles,
|
||||
Password: a.Cred.Password,
|
||||
Scope: a.Settings.UserDefaults.Scope,
|
||||
Locale: a.Settings.UserDefaults.Locale,
|
||||
ViewMode: a.Settings.UserDefaults.ViewMode,
|
||||
SingleClick: a.Settings.UserDefaults.SingleClick,
|
||||
Sorting: a.Settings.UserDefaults.Sorting,
|
||||
Perm: a.Settings.UserDefaults.Perm,
|
||||
Commands: a.Settings.UserDefaults.Commands,
|
||||
HideDotfiles: a.Settings.UserDefaults.HideDotfiles,
|
||||
}
|
||||
u = a.GetUser(d)
|
||||
|
||||
@@ -182,16 +175,6 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
}
|
||||
} else if p := !users.CheckPwd(a.Cred.Password, u.Password); len(a.Fields.Values) > 1 || p {
|
||||
u = a.GetUser(u)
|
||||
|
||||
// update the password when it doesn't match the current
|
||||
if p {
|
||||
pass, err := users.HashPwd(a.Cred.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.Password = pass
|
||||
}
|
||||
|
||||
// update user with provided fields
|
||||
err := a.Users.Update(u)
|
||||
if err != nil {
|
||||
@@ -205,31 +188,31 @@ func (a *HookAuth) SaveUser() (*users.User, error) {
|
||||
// GetUser returns a User filled with hook values or provided defaults
|
||||
func (a *HookAuth) GetUser(d *users.User) *users.User {
|
||||
// adds all permissions when user is admin
|
||||
isAdmin := a.Fields.GetBoolean("user.perm.admin", d.Perm.Admin)
|
||||
isAdmin := d.Perm.Admin
|
||||
perms := users.Permissions{
|
||||
Admin: isAdmin,
|
||||
Execute: isAdmin || a.Fields.GetBoolean("user.perm.execute", d.Perm.Execute),
|
||||
Create: isAdmin || a.Fields.GetBoolean("user.perm.create", d.Perm.Create),
|
||||
Rename: isAdmin || a.Fields.GetBoolean("user.perm.rename", d.Perm.Rename),
|
||||
Modify: isAdmin || a.Fields.GetBoolean("user.perm.modify", d.Perm.Modify),
|
||||
Delete: isAdmin || a.Fields.GetBoolean("user.perm.delete", d.Perm.Delete),
|
||||
Share: isAdmin || a.Fields.GetBoolean("user.perm.share", d.Perm.Share),
|
||||
Download: isAdmin || a.Fields.GetBoolean("user.perm.download", d.Perm.Download),
|
||||
Execute: isAdmin || d.Perm.Execute,
|
||||
Create: isAdmin || d.Perm.Create,
|
||||
Rename: isAdmin || d.Perm.Rename,
|
||||
Modify: isAdmin || d.Perm.Modify,
|
||||
Delete: isAdmin || d.Perm.Delete,
|
||||
Share: isAdmin || d.Perm.Share,
|
||||
Download: isAdmin || d.Perm.Download,
|
||||
}
|
||||
user := users.User{
|
||||
ID: d.ID,
|
||||
Username: d.Username,
|
||||
Password: d.Password,
|
||||
Scope: a.Fields.GetString("user.scope", d.Scope),
|
||||
Locale: a.Fields.GetString("user.locale", d.Locale),
|
||||
ViewMode: users.ViewMode(a.Fields.GetString("user.viewMode", string(d.ViewMode))),
|
||||
SingleClick: a.Fields.GetBoolean("user.singleClick", d.SingleClick),
|
||||
Scope: d.Scope,
|
||||
Locale: d.Locale,
|
||||
ViewMode: d.ViewMode,
|
||||
SingleClick: d.SingleClick,
|
||||
Sorting: files.Sorting{
|
||||
Asc: a.Fields.GetBoolean("user.sorting.asc", d.Sorting.Asc),
|
||||
By: a.Fields.GetString("user.sorting.by", d.Sorting.By),
|
||||
Asc: d.Sorting.Asc,
|
||||
By: d.Sorting.By,
|
||||
},
|
||||
Commands: a.Fields.GetArray("user.commands", d.Commands),
|
||||
HideDotfiles: a.Fields.GetBoolean("user.hideDotfiles", d.HideDotfiles),
|
||||
Commands: d.Commands,
|
||||
HideDotfiles: d.HideDotfiles,
|
||||
Perm: perms,
|
||||
LockPassword: true,
|
||||
}
|
||||
|
||||
@@ -11,9 +11,6 @@ import (
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
// MethodJSONAuth is used to identify json auth.
|
||||
const MethodJSONAuth = "json"
|
||||
|
||||
type jsonCred struct {
|
||||
Password string `json:"password"`
|
||||
Username string `json:"username"`
|
||||
@@ -26,13 +23,13 @@ type JSONAuth struct {
|
||||
}
|
||||
|
||||
// Auth authenticates the user via a json in content body.
|
||||
func (a JSONAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
|
||||
func (a JSONAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
|
||||
config := &settings.GlobalConfiguration
|
||||
var cred jsonCred
|
||||
|
||||
if r.Body == nil {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&cred)
|
||||
if err != nil {
|
||||
return nil, os.ErrPermission
|
||||
@@ -51,7 +48,7 @@ func (a JSONAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings,
|
||||
}
|
||||
}
|
||||
|
||||
u, err := usr.Get(srv.Root, cred.Username)
|
||||
u, err := usr.Get(config.Server.Root, cred.Username)
|
||||
if err != nil || !users.CheckPwd(cred.Password, u.Password) {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ const MethodNoAuth = "noauth"
|
||||
type NoAuth struct{}
|
||||
|
||||
// Auth uses authenticates user 1.
|
||||
func (a NoAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
|
||||
return usr.Get(srv.Root, uint(1))
|
||||
func (a NoAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
|
||||
return usr.Get(settings.GlobalConfiguration.Server.Root, uint(1))
|
||||
}
|
||||
|
||||
// LoginPage tells that no auth doesn't require a login page.
|
||||
|
||||
@@ -4,8 +4,9 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
@@ -18,9 +19,9 @@ type ProxyAuth struct {
|
||||
}
|
||||
|
||||
// Auth authenticates the user via an HTTP header.
|
||||
func (a ProxyAuth) Auth(r *http.Request, usr users.Store, stg *settings.Settings, srv *settings.Server) (*users.User, error) {
|
||||
func (a ProxyAuth) Auth(r *http.Request, usr users.Store) (*users.User, error) {
|
||||
username := r.Header.Get(a.Header)
|
||||
user, err := usr.Get(srv.Root, username)
|
||||
user, err := usr.Get(settings.GlobalConfiguration.Server.Root, username)
|
||||
if err == errors.ErrNotExist {
|
||||
return nil, os.ErrPermission
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
|
||||
== Running benchmark ==
|
||||
/usr/local/go/bin/go
|
||||
? github.com/gtsteffaniak/filebrowser [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/auth [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/cmd [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/diskcache 0.004s
|
||||
? github.com/gtsteffaniak/filebrowser/errors [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/files [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/fileutils 0.003s
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 h: 401 <nil>
|
||||
2023/10/18 10:19:52 h: 401 <nil>
|
||||
2023/10/18 10:19:52 h: 401 <nil>
|
||||
2023/10/18 10:19:52 h: 401 <nil>
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:52 Saving new user: username
|
||||
2023/10/18 10:19:53 h: 401 <nil>
|
||||
2023/10/18 10:19:53 h: 401 <nil>
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/http 0.208s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/img 0.124s
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
pkg: github.com/gtsteffaniak/filebrowser/index
|
||||
cpu: 11th Gen Intel(R) Core(TM) i5-11320H @ 3.20GHz
|
||||
BenchmarkFillIndex-8 10 3239196 ns/op 11289 B/op 448 allocs/op
|
||||
BenchmarkSearchAllIndexes-8 10 6645964 ns/op 3176834 B/op 59104 allocs/op
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/index 0.126s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/rules 0.002s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/runner 0.003s
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/settings 0.005s
|
||||
? github.com/gtsteffaniak/filebrowser/share [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/storage [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/storage/bolt [no test files]
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/users 0.003s
|
||||
? github.com/gtsteffaniak/filebrowser/version [no test files]
|
||||
@@ -1,12 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// Execute executes the commands.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(cmdsCmd)
|
||||
}
|
||||
|
||||
var cmdsCmd = &cobra.Command{
|
||||
Use: "cmds",
|
||||
Short: "Command runner management utility",
|
||||
Long: `Command runner management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
|
||||
func printEvents(m map[string][]string) {
|
||||
for evt, cmds := range m {
|
||||
for i, cmd := range cmds {
|
||||
fmt.Printf("%s(%d): %s\n", evt, i, cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmdsCmd.AddCommand(cmdsAddCmd)
|
||||
}
|
||||
|
||||
var cmdsAddCmd = &cobra.Command{
|
||||
Use: "add <event> <command>",
|
||||
Short: "Add a command to run on a specific event",
|
||||
Long: `Add a command to run on a specific event.`,
|
||||
Args: cobra.MinimumNArgs(2), //nolint:gomnd
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
s, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
command := strings.Join(args[1:], " ")
|
||||
s.Commands[args[0]] = append(s.Commands[args[0]], command)
|
||||
err = d.store.Settings.Save(s)
|
||||
checkErr(err)
|
||||
printEvents(s.Commands)
|
||||
}, pythonConfig{}),
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmdsCmd.AddCommand(cmdsLsCmd)
|
||||
cmdsLsCmd.Flags().StringP("event", "e", "", "event name, without 'before' or 'after'")
|
||||
}
|
||||
|
||||
var cmdsLsCmd = &cobra.Command{
|
||||
Use: "ls",
|
||||
Short: "List all commands for each event",
|
||||
Long: `List all commands for each event.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
s, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
evt := mustGetString(cmd.Flags(), "event")
|
||||
|
||||
if evt == "" {
|
||||
printEvents(s.Commands)
|
||||
} else {
|
||||
show := map[string][]string{}
|
||||
show["before_"+evt] = s.Commands["before_"+evt]
|
||||
show["after_"+evt] = s.Commands["after_"+evt]
|
||||
printEvents(show)
|
||||
}
|
||||
}, pythonConfig{}),
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmdsCmd.AddCommand(cmdsRmCmd)
|
||||
}
|
||||
|
||||
var cmdsRmCmd = &cobra.Command{
|
||||
Use: "rm <event> <index> [index_end]",
|
||||
Short: "Removes a command from an event hooker",
|
||||
Long: `Removes a command from an event hooker. The provided index
|
||||
is the same that's printed when you run 'cmds ls'. Note
|
||||
that after each removal/addition, the index of the
|
||||
commands change. So be careful when removing them after each
|
||||
other.
|
||||
|
||||
You can also specify an optional parameter (index_end) so
|
||||
you can remove all commands from 'index' to 'index_end',
|
||||
including 'index_end'.`,
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
if err := cobra.RangeArgs(2, 3)(cmd, args); err != nil { //nolint:gomnd
|
||||
return err
|
||||
}
|
||||
|
||||
for _, arg := range args[1:] {
|
||||
if _, err := strconv.Atoi(arg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
s, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
evt := args[0]
|
||||
|
||||
i, err := strconv.Atoi(args[1])
|
||||
checkErr(err)
|
||||
f := i
|
||||
if len(args) == 3 { //nolint:gomnd
|
||||
f, err = strconv.Atoi(args[2])
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
s.Commands[evt] = append(s.Commands[evt][:i], s.Commands[evt][f+1:]...)
|
||||
err = d.store.Settings.Save(s)
|
||||
checkErr(err)
|
||||
printEvents(s.Commands)
|
||||
}, pythonConfig{}),
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
nerrors "errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/auth"
|
||||
"github.com/gtsteffaniak/filebrowser/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(configCmd)
|
||||
}
|
||||
|
||||
var configCmd = &cobra.Command{
|
||||
Use: "config",
|
||||
Short: "Configuration management utility",
|
||||
Long: `Configuration management utility.`,
|
||||
Args: cobra.NoArgs,
|
||||
}
|
||||
|
||||
func addConfigFlags(flags *pflag.FlagSet) {
|
||||
addServerFlags(flags)
|
||||
addUserFlags(flags)
|
||||
flags.BoolP("signup", "s", false, "allow users to signup")
|
||||
flags.String("shell", "", "shell command to which other commands should be appended")
|
||||
|
||||
flags.String("auth.method", string(auth.MethodJSONAuth), "authentication type")
|
||||
flags.String("auth.header", "", "HTTP header for auth.method=proxy")
|
||||
flags.String("auth.command", "", "command for auth.method=hook")
|
||||
|
||||
flags.String("recaptcha.host", "https://www.google.com", "use another host for ReCAPTCHA. recaptcha.net might be useful in China")
|
||||
flags.String("recaptcha.key", "", "ReCaptcha site key")
|
||||
flags.String("recaptcha.secret", "", "ReCaptcha secret")
|
||||
|
||||
flags.String("branding.name", "", "replace 'File Browser' by this name")
|
||||
flags.String("branding.color", "", "set the theme color")
|
||||
flags.String("branding.files", "", "path to directory with images and custom styles")
|
||||
flags.Bool("branding.disableExternal", false, "disable external links such as GitHub links")
|
||||
flags.Bool("branding.disableUsedPercentage", false, "disable used disk percentage graph")
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func getAuthentication(flags *pflag.FlagSet, defaults ...interface{}) (string, auth.Auther) {
|
||||
method := mustGetString(flags, "auth.method")
|
||||
|
||||
var defaultAuther map[string]interface{}
|
||||
if len(defaults) > 0 {
|
||||
if hasAuth := defaults[0]; hasAuth != true {
|
||||
for _, arg := range defaults {
|
||||
switch def := arg.(type) {
|
||||
case *settings.Settings:
|
||||
method = def.AuthMethod
|
||||
case auth.Auther:
|
||||
ms, err := json.Marshal(def)
|
||||
checkErr(err)
|
||||
err = json.Unmarshal(ms, &defaultAuther)
|
||||
checkErr(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var auther auth.Auther
|
||||
if method == auth.MethodProxyAuth {
|
||||
header := mustGetString(flags, "auth.header")
|
||||
|
||||
if header == "" {
|
||||
header = defaultAuther["header"].(string)
|
||||
}
|
||||
|
||||
if header == "" {
|
||||
checkErr(nerrors.New("you must set the flag 'auth.header' for method 'proxy'"))
|
||||
}
|
||||
|
||||
auther = &auth.ProxyAuth{Header: header}
|
||||
}
|
||||
|
||||
if method == auth.MethodNoAuth {
|
||||
auther = &auth.NoAuth{}
|
||||
}
|
||||
|
||||
if method == auth.MethodJSONAuth {
|
||||
jsonAuth := &auth.JSONAuth{}
|
||||
host := mustGetString(flags, "recaptcha.host")
|
||||
key := mustGetString(flags, "recaptcha.key")
|
||||
secret := mustGetString(flags, "recaptcha.secret")
|
||||
|
||||
if key == "" {
|
||||
if kmap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
|
||||
key = kmap["key"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
if secret == "" {
|
||||
if smap, ok := defaultAuther["recaptcha"].(map[string]interface{}); ok {
|
||||
secret = smap["secret"].(string)
|
||||
}
|
||||
}
|
||||
|
||||
if key != "" && secret != "" {
|
||||
jsonAuth.ReCaptcha = &auth.ReCaptcha{
|
||||
Host: host,
|
||||
Key: key,
|
||||
Secret: secret,
|
||||
}
|
||||
}
|
||||
auther = jsonAuth
|
||||
}
|
||||
|
||||
if method == auth.MethodHookAuth {
|
||||
command := mustGetString(flags, "auth.command")
|
||||
|
||||
if command == "" {
|
||||
command = defaultAuther["command"].(string)
|
||||
}
|
||||
|
||||
if command == "" {
|
||||
checkErr(nerrors.New("you must set the flag 'auth.command' for method 'hook'"))
|
||||
}
|
||||
|
||||
auther = &auth.HookAuth{Command: command}
|
||||
}
|
||||
|
||||
if auther == nil {
|
||||
panic(errors.ErrInvalidAuthMethod)
|
||||
}
|
||||
|
||||
return method, auther
|
||||
}
|
||||
|
||||
func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Auther) {
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) //nolint:gomnd
|
||||
|
||||
fmt.Fprintf(w, "Sign up:\t%t\n", set.Signup)
|
||||
fmt.Fprintf(w, "Create User Dir:\t%t\n", set.CreateUserDir)
|
||||
fmt.Fprintf(w, "Auth method:\t%s\n", set.AuthMethod)
|
||||
fmt.Fprintf(w, "Shell:\t%s\t\n", strings.Join(set.Shell, " "))
|
||||
fmt.Fprintln(w, "\nBranding:")
|
||||
fmt.Fprintf(w, "\tName:\t%s\n", set.Branding.Name)
|
||||
fmt.Fprintf(w, "\tFiles override:\t%s\n", set.Branding.Files)
|
||||
fmt.Fprintf(w, "\tDisable external links:\t%t\n", set.Branding.DisableExternal)
|
||||
fmt.Fprintf(w, "\tDisable used disk percentage graph:\t%t\n", set.Branding.DisableUsedPercentage)
|
||||
fmt.Fprintf(w, "\tColor:\t%s\n", set.Branding.Color)
|
||||
fmt.Fprintln(w, "\nServer:")
|
||||
fmt.Fprintf(w, "\tLog:\t%s\n", ser.Log)
|
||||
fmt.Fprintf(w, "\tPort:\t%s\n", ser.Port)
|
||||
fmt.Fprintf(w, "\tBase URL:\t%s\n", ser.BaseURL)
|
||||
fmt.Fprintf(w, "\tRoot:\t%s\n", ser.Root)
|
||||
fmt.Fprintf(w, "\tSocket:\t%s\n", ser.Socket)
|
||||
fmt.Fprintf(w, "\tAddress:\t%s\n", ser.Address)
|
||||
fmt.Fprintf(w, "\tTLS Cert:\t%s\n", ser.TLSCert)
|
||||
fmt.Fprintf(w, "\tTLS Key:\t%s\n", ser.TLSKey)
|
||||
fmt.Fprintf(w, "\tExec Enabled:\t%t\n", ser.EnableExec)
|
||||
fmt.Fprintln(w, "\nDefaults:")
|
||||
fmt.Fprintf(w, "\tScope:\t%s\n", set.Defaults.Scope)
|
||||
fmt.Fprintf(w, "\tLocale:\t%s\n", set.Defaults.Locale)
|
||||
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
|
||||
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
|
||||
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
|
||||
fmt.Fprintf(w, "\tSorting:\n")
|
||||
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
|
||||
fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)
|
||||
fmt.Fprintf(w, "\tPermissions:\n")
|
||||
fmt.Fprintf(w, "\t\tAdmin:\t%t\n", set.Defaults.Perm.Admin)
|
||||
fmt.Fprintf(w, "\t\tExecute:\t%t\n", set.Defaults.Perm.Execute)
|
||||
fmt.Fprintf(w, "\t\tCreate:\t%t\n", set.Defaults.Perm.Create)
|
||||
fmt.Fprintf(w, "\t\tRename:\t%t\n", set.Defaults.Perm.Rename)
|
||||
fmt.Fprintf(w, "\t\tModify:\t%t\n", set.Defaults.Perm.Modify)
|
||||
fmt.Fprintf(w, "\t\tDelete:\t%t\n", set.Defaults.Perm.Delete)
|
||||
fmt.Fprintf(w, "\t\tShare:\t%t\n", set.Defaults.Perm.Share)
|
||||
fmt.Fprintf(w, "\t\tDownload:\t%t\n", set.Defaults.Perm.Download)
|
||||
w.Flush()
|
||||
|
||||
b, err := json.MarshalIndent(auther, "", " ")
|
||||
checkErr(err)
|
||||
fmt.Printf("\nAuther configuration (raw):\n\n%s\n\n", string(b))
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configCatCmd)
|
||||
}
|
||||
|
||||
var configCatCmd = &cobra.Command{
|
||||
Use: "cat",
|
||||
Short: "Prints the configuration",
|
||||
Long: `Prints the configuration.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
set, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
ser, err := d.store.Settings.GetServer()
|
||||
checkErr(err)
|
||||
auther, err := d.store.Auth.Get(set.AuthMethod)
|
||||
checkErr(err)
|
||||
printSettings(ser, set, auther)
|
||||
}, pythonConfig{}),
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configExportCmd)
|
||||
}
|
||||
|
||||
var configExportCmd = &cobra.Command{
|
||||
Use: "export <path>",
|
||||
Short: "Export the configuration to a file",
|
||||
Long: `Export the configuration to a file. The path must be for a
|
||||
json or yaml file. This exported configuration can be changed,
|
||||
and imported again with 'config import' command.`,
|
||||
Args: jsonYamlArg,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
settings, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
server, err := d.store.Settings.GetServer()
|
||||
checkErr(err)
|
||||
|
||||
auther, err := d.store.Auth.Get(settings.AuthMethod)
|
||||
checkErr(err)
|
||||
|
||||
data := &settingsFile{
|
||||
Settings: settings,
|
||||
Auther: auther,
|
||||
Server: server,
|
||||
}
|
||||
|
||||
err = marshal(args[0], data)
|
||||
checkErr(err)
|
||||
}, pythonConfig{}),
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/auth"
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configImportCmd)
|
||||
}
|
||||
|
||||
type settingsFile struct {
|
||||
Settings *settings.Settings `json:"settings"`
|
||||
Server *settings.Server `json:"server"`
|
||||
Auther interface{} `json:"auther"`
|
||||
}
|
||||
|
||||
var configImportCmd = &cobra.Command{
|
||||
Use: "import <path>",
|
||||
Short: "Import a configuration file",
|
||||
Long: `Import a configuration file. This will replace all the existing
|
||||
configuration. Can be used with or without unexisting databases.
|
||||
|
||||
If used with a nonexisting database, a key will be generated
|
||||
automatically. Otherwise the key will be kept the same as in the
|
||||
database.
|
||||
|
||||
The path must be for a json or yaml file.`,
|
||||
Args: jsonYamlArg,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
var key []byte
|
||||
if d.hadDB {
|
||||
settings, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
key = settings.Key
|
||||
} else {
|
||||
key = generateKey()
|
||||
}
|
||||
|
||||
file := settingsFile{}
|
||||
err := unmarshal(args[0], &file)
|
||||
checkErr(err)
|
||||
|
||||
file.Settings.Key = key
|
||||
err = d.store.Settings.Save(file.Settings)
|
||||
checkErr(err)
|
||||
|
||||
err = d.store.Settings.SaveServer(file.Server)
|
||||
checkErr(err)
|
||||
|
||||
var rawAuther interface{}
|
||||
if filepath.Ext(args[0]) != ".json" { //nolint:goconst
|
||||
rawAuther = cleanUpInterfaceMap(file.Auther.(map[interface{}]interface{}))
|
||||
} else {
|
||||
rawAuther = file.Auther
|
||||
}
|
||||
|
||||
var auther auth.Auther
|
||||
switch file.Settings.AuthMethod {
|
||||
case auth.MethodJSONAuth:
|
||||
auther = getAuther(auth.JSONAuth{}, rawAuther).(*auth.JSONAuth)
|
||||
case auth.MethodNoAuth:
|
||||
auther = getAuther(auth.NoAuth{}, rawAuther).(*auth.NoAuth)
|
||||
case auth.MethodProxyAuth:
|
||||
auther = getAuther(auth.ProxyAuth{}, rawAuther).(*auth.ProxyAuth)
|
||||
case auth.MethodHookAuth:
|
||||
auther = getAuther(&auth.HookAuth{}, rawAuther).(*auth.HookAuth)
|
||||
default:
|
||||
checkErr(errors.New("invalid auth method"))
|
||||
}
|
||||
|
||||
err = d.store.Auth.Save(auther)
|
||||
checkErr(err)
|
||||
|
||||
printSettings(file.Server, file.Settings, auther)
|
||||
}, pythonConfig{allowNoDB: true}),
|
||||
}
|
||||
|
||||
func getAuther(sample auth.Auther, data interface{}) interface{} {
|
||||
authType := reflect.TypeOf(sample)
|
||||
auther := reflect.New(authType).Interface()
|
||||
bytes, err := json.Marshal(data)
|
||||
checkErr(err)
|
||||
err = json.Unmarshal(bytes, &auther)
|
||||
checkErr(err)
|
||||
return auther
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configInitCmd)
|
||||
addConfigFlags(configInitCmd.Flags())
|
||||
}
|
||||
|
||||
var configInitCmd = &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize a new database",
|
||||
Long: `Initialize a new database to use with File Browser. All of
|
||||
this options can be changed in the future with the command
|
||||
'filebrowser config set'. The user related flags apply
|
||||
to the defaults when creating new users and you don't
|
||||
override the options.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
defaults := settings.UserDefaults{}
|
||||
flags := cmd.Flags()
|
||||
getUserDefaults(flags, &defaults, true)
|
||||
authMethod, auther := getAuthentication(flags)
|
||||
|
||||
s := &settings.Settings{
|
||||
Key: generateKey(),
|
||||
Signup: mustGetBool(flags, "signup"),
|
||||
Shell: convertCmdStrToCmdArray(mustGetString(flags, "shell")),
|
||||
AuthMethod: authMethod,
|
||||
Defaults: defaults,
|
||||
Branding: settings.Branding{
|
||||
Name: mustGetString(flags, "branding.name"),
|
||||
DisableExternal: mustGetBool(flags, "branding.disableExternal"),
|
||||
DisableUsedPercentage: mustGetBool(flags, "branding.DisableUsedPercentage"),
|
||||
Files: mustGetString(flags, "branding.files"),
|
||||
},
|
||||
}
|
||||
|
||||
ser := &settings.Server{
|
||||
Address: mustGetString(flags, "address"),
|
||||
Socket: mustGetString(flags, "socket"),
|
||||
Root: mustGetString(flags, "root"),
|
||||
BaseURL: mustGetString(flags, "baseurl"),
|
||||
TLSKey: mustGetString(flags, "key"),
|
||||
TLSCert: mustGetString(flags, "cert"),
|
||||
Port: mustGetString(flags, "port"),
|
||||
Log: mustGetString(flags, "log"),
|
||||
}
|
||||
err := d.store.Settings.Save(s)
|
||||
checkErr(err)
|
||||
err = d.store.Settings.SaveServer(ser)
|
||||
checkErr(err)
|
||||
err = d.store.Auth.Save(auther)
|
||||
checkErr(err)
|
||||
|
||||
fmt.Printf(`
|
||||
Congratulations! You've set up your database to use with File Browser.
|
||||
Now add your first user via 'filebrowser users add' and then you just
|
||||
need to call the main command to boot up the server.
|
||||
`)
|
||||
printSettings(ser, s, auther)
|
||||
}, pythonConfig{noDB: true}),
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configSetCmd)
|
||||
addConfigFlags(configSetCmd.Flags())
|
||||
}
|
||||
|
||||
var configSetCmd = &cobra.Command{
|
||||
Use: "set",
|
||||
Short: "Updates the configuration",
|
||||
Long: `Updates the configuration. Set the flags for the options
|
||||
you want to change. Other options will remain unchanged.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
flags := cmd.Flags()
|
||||
set, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
|
||||
ser, err := d.store.Settings.GetServer()
|
||||
checkErr(err)
|
||||
|
||||
hasAuth := false
|
||||
flags.Visit(func(flag *pflag.Flag) {
|
||||
switch flag.Name {
|
||||
case "baseurl":
|
||||
ser.BaseURL = mustGetString(flags, flag.Name)
|
||||
case "root":
|
||||
ser.Root = mustGetString(flags, flag.Name)
|
||||
case "socket":
|
||||
ser.Socket = mustGetString(flags, flag.Name)
|
||||
case "cert":
|
||||
ser.TLSCert = mustGetString(flags, flag.Name)
|
||||
case "key":
|
||||
ser.TLSKey = mustGetString(flags, flag.Name)
|
||||
case "address":
|
||||
ser.Address = mustGetString(flags, flag.Name)
|
||||
case "port":
|
||||
ser.Port = mustGetString(flags, flag.Name)
|
||||
case "log":
|
||||
ser.Log = mustGetString(flags, flag.Name)
|
||||
case "signup":
|
||||
set.Signup = mustGetBool(flags, flag.Name)
|
||||
case "auth.method":
|
||||
hasAuth = true
|
||||
case "shell":
|
||||
set.Shell = convertCmdStrToCmdArray(mustGetString(flags, flag.Name))
|
||||
case "branding.name":
|
||||
set.Branding.Name = mustGetString(flags, flag.Name)
|
||||
case "branding.color":
|
||||
set.Branding.Color = mustGetString(flags, flag.Name)
|
||||
case "branding.disableExternal":
|
||||
set.Branding.DisableExternal = mustGetBool(flags, flag.Name)
|
||||
case "branding.disableUsedPercentage":
|
||||
set.Branding.DisableUsedPercentage = mustGetBool(flags, flag.Name)
|
||||
case "branding.files":
|
||||
set.Branding.Files = mustGetString(flags, flag.Name)
|
||||
}
|
||||
})
|
||||
|
||||
getUserDefaults(flags, &set.Defaults, false)
|
||||
|
||||
// read the defaults
|
||||
auther, err := d.store.Auth.Get(set.AuthMethod)
|
||||
checkErr(err)
|
||||
|
||||
// check if there are new flags for existing auth method
|
||||
set.AuthMethod, auther = getAuthentication(flags, hasAuth, set, auther)
|
||||
|
||||
err = d.store.Auth.Save(auther)
|
||||
checkErr(err)
|
||||
err = d.store.Settings.Save(set)
|
||||
checkErr(err)
|
||||
err = d.store.Settings.SaveServer(ser)
|
||||
checkErr(err)
|
||||
printSettings(ser, set, auther)
|
||||
}, pythonConfig{}),
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(docsCmd)
|
||||
docsCmd.Flags().StringP("path", "p", "./docs", "path to save the docs")
|
||||
}
|
||||
|
||||
func printToc(names []string) {
|
||||
for i, name := range names {
|
||||
name = strings.TrimSuffix(name, filepath.Ext(name))
|
||||
name = strings.Replace(name, "-", " ", -1)
|
||||
names[i] = name
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
|
||||
toc := ""
|
||||
for _, name := range names {
|
||||
toc += "* [" + name + "](cli/" + strings.Replace(name, " ", "-", -1) + ".md)\n"
|
||||
}
|
||||
|
||||
fmt.Println(toc)
|
||||
}
|
||||
|
||||
var docsCmd = &cobra.Command{
|
||||
Use: "docs",
|
||||
Hidden: true,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
dir := mustGetString(cmd.Flags(), "path")
|
||||
generateDocs(rootCmd, dir)
|
||||
names := []string{}
|
||||
|
||||
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil || info.IsDir() {
|
||||
return err
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(info.Name(), "filebrowser") {
|
||||
return nil
|
||||
}
|
||||
|
||||
names = append(names, info.Name())
|
||||
return nil
|
||||
})
|
||||
|
||||
checkErr(err)
|
||||
printToc(names)
|
||||
},
|
||||
}
|
||||
|
||||
func generateDocs(cmd *cobra.Command, dir string) {
|
||||
for _, c := range cmd.Commands() {
|
||||
if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() {
|
||||
continue
|
||||
}
|
||||
|
||||
generateDocs(c, dir)
|
||||
}
|
||||
|
||||
basename := strings.Replace(cmd.CommandPath(), " ", "-", -1) + ".md"
|
||||
filename := filepath.Join(dir, basename)
|
||||
f, err := os.Create(filename)
|
||||
checkErr(err)
|
||||
defer f.Close()
|
||||
generateMarkdown(cmd, f)
|
||||
}
|
||||
|
||||
func generateMarkdown(cmd *cobra.Command, w io.Writer) {
|
||||
cmd.InitDefaultHelpCmd()
|
||||
cmd.InitDefaultHelpFlag()
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
name := cmd.CommandPath()
|
||||
|
||||
short := cmd.Short
|
||||
long := cmd.Long
|
||||
if long == "" {
|
||||
long = short
|
||||
}
|
||||
|
||||
buf.WriteString("---\ndescription: " + short + "\n---\n\n")
|
||||
buf.WriteString("# " + name + "\n\n")
|
||||
buf.WriteString("## Synopsis\n\n")
|
||||
buf.WriteString(long + "\n\n")
|
||||
|
||||
if cmd.Runnable() {
|
||||
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.UseLine()))
|
||||
}
|
||||
|
||||
if len(cmd.Example) > 0 {
|
||||
buf.WriteString("## Examples\n\n")
|
||||
buf.WriteString(fmt.Sprintf("```\n%s\n```\n\n", cmd.Example))
|
||||
}
|
||||
|
||||
printOptions(buf, cmd)
|
||||
_, err := buf.WriteTo(w)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
func generateFlagsTable(fs *pflag.FlagSet, buf io.StringWriter) {
|
||||
_, _ = buf.WriteString("| Name | Shorthand | Usage |\n")
|
||||
_, _ = buf.WriteString("|------|-----------|-------|\n")
|
||||
|
||||
fs.VisitAll(func(f *pflag.Flag) {
|
||||
_, _ = buf.WriteString("|" + f.Name + "|" + f.Shorthand + "|" + f.Usage + "|\n")
|
||||
})
|
||||
}
|
||||
|
||||
func printOptions(buf *bytes.Buffer, cmd *cobra.Command) {
|
||||
flags := cmd.NonInheritedFlags()
|
||||
flags.SetOutput(buf)
|
||||
if flags.HasAvailableFlags() {
|
||||
buf.WriteString("## Options\n\n")
|
||||
generateFlagsTable(flags, buf)
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
|
||||
parentFlags := cmd.InheritedFlags()
|
||||
parentFlags.SetOutput(buf)
|
||||
if parentFlags.HasAvailableFlags() {
|
||||
buf.WriteString("### Inherited\n\n")
|
||||
generateFlagsTable(parentFlags, buf)
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(hashCmd)
|
||||
}
|
||||
|
||||
var hashCmd = &cobra.Command{
|
||||
Use: "hash <password>",
|
||||
Short: "Hashes a password",
|
||||
Long: `Hashes a password using bcrypt algorithm.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
pwd, err := users.HashPwd(args[0])
|
||||
checkErr(err)
|
||||
fmt.Println(pwd)
|
||||
},
|
||||
}
|
||||
@@ -2,39 +2,30 @@ package cmd
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"io"
|
||||
"flag"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/spf13/afero"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
v "github.com/spf13/viper"
|
||||
lumberjack "gopkg.in/natefinch/lumberjack.v2"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/auth"
|
||||
"github.com/gtsteffaniak/filebrowser/diskcache"
|
||||
fbhttp "github.com/gtsteffaniak/filebrowser/http"
|
||||
"github.com/gtsteffaniak/filebrowser/img"
|
||||
"github.com/gtsteffaniak/filebrowser/search"
|
||||
"github.com/gtsteffaniak/filebrowser/index"
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/storage"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
var (
|
||||
cfgFile string
|
||||
)
|
||||
|
||||
type dirFS struct {
|
||||
http.Dir
|
||||
}
|
||||
@@ -44,106 +35,28 @@ func (d dirFS) Open(name string) (fs.File, error) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
cobra.MousetrapHelpText = ""
|
||||
rootCmd.SetVersionTemplate("File Browser version {{printf \"%s\" .Version}}\n")
|
||||
|
||||
flags := rootCmd.Flags()
|
||||
|
||||
persistent := rootCmd.PersistentFlags()
|
||||
|
||||
persistent.StringVarP(&cfgFile, "config", "c", "", "config file path")
|
||||
persistent.StringP("database", "d", "./filebrowser.db", "database path")
|
||||
flags.Bool("noauth", false, "use the noauth auther when using quick setup")
|
||||
flags.String("username", "admin", "username for the first user when using quick config")
|
||||
flags.String("password", "", "hashed password for the first user when using quick config (default \"admin\")")
|
||||
|
||||
addServerFlags(flags)
|
||||
}
|
||||
|
||||
func getEnvVariableAsUint32(key string) uint32 {
|
||||
valueStr := os.Getenv(key)
|
||||
value, err := strconv.ParseUint(valueStr, 10, 32)
|
||||
if err != nil {
|
||||
return 5 // default value every 5 minutes
|
||||
}
|
||||
return uint32(value)
|
||||
}
|
||||
|
||||
func addServerFlags(flags *pflag.FlagSet) {
|
||||
flags.StringP("address", "a", "127.0.0.1", "address to listen on")
|
||||
flags.StringP("log", "l", "stdout", "log output")
|
||||
flags.StringP("port", "p", "8080", "port to listen on")
|
||||
flags.StringP("cert", "t", "", "tls certificate")
|
||||
flags.StringP("key", "k", "", "tls key")
|
||||
flags.StringP("root", "r", ".", "root to prepend to relative paths")
|
||||
flags.String("socket", "", "socket to listen to (cannot be used with address, port, cert nor key flags)")
|
||||
flags.Uint32("socket-perm", 0666, "unix socket file permissions") //nolint:gomnd
|
||||
flags.StringP("baseurl", "b", "", "base url")
|
||||
flags.String("cache-dir", "", "file cache directory (disabled if empty)")
|
||||
flags.Int("img-processors", 4, "image processors count") //nolint:gomnd
|
||||
flags.Bool("disable-thumbnails", false, "disable image thumbnails")
|
||||
flags.Bool("disable-preview-resize", true, "disable resize of image previews")
|
||||
flags.Bool("disable-exec", false, "disables Command Runner feature")
|
||||
flags.Bool("disable-type-detection-by-header", false, "disables type detection by reading file headers")
|
||||
// Define a flag for the config option (-c or --config)
|
||||
configFlag := pflag.StringP("config", "c", "filebrowser.yaml", "Path to the config file")
|
||||
// Bind the flags to the pflag command line parser
|
||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||
pflag.Parse()
|
||||
log.Println("Initializing with config file:", *configFlag)
|
||||
settings.Initialize(*configFlag)
|
||||
}
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "filebrowser",
|
||||
Short: "A stylish web-based file browser",
|
||||
Long: `File Browser CLI lets you create the database to use with File Browser,
|
||||
manage your users and all the configurations without acessing the
|
||||
web interface.
|
||||
|
||||
If you've never run File Browser, you'll need to have a database for
|
||||
it. Don't worry: you don't need to setup a separate database server.
|
||||
We're using Bolt DB which is a single file database and all managed
|
||||
by ourselves.
|
||||
|
||||
For this specific command, all the flags you have available (except
|
||||
"config" for the configuration file), can be given either through
|
||||
environment variables or configuration files.
|
||||
|
||||
If you don't set "config", it will look for a configuration file called
|
||||
.filebrowser.{json, toml, yaml, yml} in the following directories:
|
||||
|
||||
- ./
|
||||
- $HOME/
|
||||
- /etc/filebrowser/
|
||||
|
||||
The precedence of the configuration values are as follows:
|
||||
|
||||
- flags
|
||||
- environment variables
|
||||
- configuration file
|
||||
- database values
|
||||
- defaults
|
||||
|
||||
The environment variables are prefixed by "FB_" followed by the option
|
||||
name in caps. So to set "database" via an env variable, you should
|
||||
set FB_DATABASE.
|
||||
|
||||
Also, if the database path doesn't exist, File Browser will enter into
|
||||
the quick setup mode and a new database will be bootstraped and a new
|
||||
user created with the credentials from options "username" and "password".`,
|
||||
Use: "filebrowser",
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
log.Println(cfgFile)
|
||||
|
||||
serverConfig := settings.GlobalConfiguration.Server
|
||||
if !d.hadDB {
|
||||
quickSetup(cmd.Flags(), d)
|
||||
quickSetup(d)
|
||||
}
|
||||
|
||||
// build img service
|
||||
workersCount, err := cmd.Flags().GetInt("img-processors")
|
||||
checkErr(err)
|
||||
if workersCount < 1 {
|
||||
if serverConfig.NumImageProcessors < 1 {
|
||||
log.Fatal("Image resize workers count could not be < 1")
|
||||
}
|
||||
imgSvc := img.New(workersCount)
|
||||
|
||||
imgSvc := img.New(serverConfig.NumImageProcessors)
|
||||
var fileCache diskcache.Interface = diskcache.NewNoOp()
|
||||
cacheDir, err := cmd.Flags().GetString("cache-dir")
|
||||
checkErr(err)
|
||||
cacheDir := "/tmp"
|
||||
if cacheDir != "" {
|
||||
if err := os.MkdirAll(cacheDir, 0700); err != nil { //nolint:govet,gomnd
|
||||
log.Fatalf("can't make directory %s: %s", cacheDir, err)
|
||||
@@ -151,51 +64,38 @@ user created with the credentials from options "username" and "password".`,
|
||||
fileCache = diskcache.New(afero.NewOsFs(), cacheDir)
|
||||
}
|
||||
// initialize indexing and schedule indexing ever n minutes (default 5)
|
||||
indexingInterval := getEnvVariableAsUint32("INDEXING_INTERVAL")
|
||||
go search.InitializeIndex(indexingInterval)
|
||||
|
||||
server := getRunParams(cmd.Flags(), d.store)
|
||||
setupLog(server.Log)
|
||||
|
||||
root, err := filepath.Abs(server.Root)
|
||||
go index.Initialize(serverConfig.IndexingInterval)
|
||||
_, err := os.Stat(serverConfig.Root)
|
||||
checkErr(err)
|
||||
server.Root = root
|
||||
|
||||
adr := server.Address + ":" + server.Port
|
||||
|
||||
var listener net.Listener
|
||||
|
||||
address := serverConfig.Address + ":" + strconv.Itoa(serverConfig.Port)
|
||||
switch {
|
||||
case server.Socket != "":
|
||||
listener, err = net.Listen("unix", server.Socket)
|
||||
case serverConfig.Socket != "":
|
||||
listener, err = net.Listen("unix", serverConfig.Socket)
|
||||
checkErr(err)
|
||||
socketPerm, err := cmd.Flags().GetUint32("socket-perm") //nolint:govet
|
||||
checkErr(err)
|
||||
err = os.Chmod(server.Socket, os.FileMode(socketPerm))
|
||||
err = os.Chmod(serverConfig.Socket, os.FileMode(socketPerm))
|
||||
checkErr(err)
|
||||
case server.TLSKey != "" && server.TLSCert != "":
|
||||
cer, err := tls.LoadX509KeyPair(server.TLSCert, server.TLSKey) //nolint:govet
|
||||
case serverConfig.TLSKey != "" && serverConfig.TLSCert != "":
|
||||
cer, err := tls.LoadX509KeyPair(serverConfig.TLSCert, serverConfig.TLSKey) //nolint:govet
|
||||
checkErr(err)
|
||||
listener, err = tls.Listen("tcp", adr, &tls.Config{
|
||||
listener, err = tls.Listen("tcp", address, &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
Certificates: []tls.Certificate{cer}},
|
||||
)
|
||||
checkErr(err)
|
||||
default:
|
||||
listener, err = net.Listen("tcp", adr)
|
||||
listener, err = net.Listen("tcp", address)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
sigc := make(chan os.Signal, 1)
|
||||
signal.Notify(sigc, os.Interrupt, syscall.SIGTERM)
|
||||
go cleanupHandler(listener, sigc)
|
||||
|
||||
assetsFs := dirFS{Dir: http.Dir("frontend/dist")}
|
||||
handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, server, assetsFs)
|
||||
handler, err := fbhttp.NewHandler(imgSvc, fileCache, d.store, &serverConfig, assetsFs)
|
||||
checkErr(err)
|
||||
|
||||
defer listener.Close()
|
||||
|
||||
log.Println("Listening on", listener.Addr().String())
|
||||
//nolint: gosec
|
||||
if err := http.Serve(listener, handler); err != nil {
|
||||
@@ -204,6 +104,12 @@ user created with the credentials from options "username" and "password".`,
|
||||
}, pythonConfig{allowNoDB: true}),
|
||||
}
|
||||
|
||||
func StartFilebrowser() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfacer
|
||||
sig := <-c
|
||||
log.Printf("Caught signal %s: shutting down.", sig)
|
||||
@@ -211,217 +117,38 @@ func cleanupHandler(listener net.Listener, c chan os.Signal) { //nolint:interfac
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
||||
server, err := st.Settings.GetServer()
|
||||
checkErr(err)
|
||||
|
||||
if val, set := getParamB(flags, "root"); set {
|
||||
server.Root = val
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "baseurl"); set {
|
||||
server.BaseURL = val
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "log"); set {
|
||||
server.Log = val
|
||||
}
|
||||
|
||||
isSocketSet := false
|
||||
isAddrSet := false
|
||||
|
||||
if val, set := getParamB(flags, "address"); set {
|
||||
server.Address = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "port"); set {
|
||||
server.Port = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "key"); set {
|
||||
server.TLSKey = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "cert"); set {
|
||||
server.TLSCert = val
|
||||
isAddrSet = isAddrSet || set
|
||||
}
|
||||
|
||||
if val, set := getParamB(flags, "socket"); set {
|
||||
server.Socket = val
|
||||
isSocketSet = isSocketSet || set
|
||||
}
|
||||
|
||||
if isAddrSet && isSocketSet {
|
||||
checkErr(errors.New("--socket flag cannot be used with --address, --port, --key nor --cert"))
|
||||
}
|
||||
|
||||
// Do not use saved Socket if address was manually set.
|
||||
if isAddrSet && server.Socket != "" {
|
||||
server.Socket = ""
|
||||
}
|
||||
|
||||
_, disableThumbnails := getParamB(flags, "disable-thumbnails")
|
||||
server.EnableThumbnails = !disableThumbnails
|
||||
|
||||
_, disablePreviewResize := getParamB(flags, "disable-preview-resize")
|
||||
server.ResizePreview = !disablePreviewResize
|
||||
|
||||
_, disableTypeDetectionByHeader := getParamB(flags, "disable-type-detection-by-header")
|
||||
server.TypeDetectionByHeader = !disableTypeDetectionByHeader
|
||||
|
||||
_, disableExec := getParamB(flags, "disable-exec")
|
||||
server.EnableExec = !disableExec
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
// getParamB returns a parameter as a string and a boolean to tell if it is different from the default
|
||||
//
|
||||
// NOTE: we could simply bind the flags to viper and use IsSet.
|
||||
// Although there is a bug on Viper that always returns true on IsSet
|
||||
// if a flag is binded. Our alternative way is to manually check
|
||||
// the flag and then the value from env/config/gotten by viper.
|
||||
// https://github.com/spf13/viper/pull/331
|
||||
func getParamB(flags *pflag.FlagSet, key string) (string, bool) {
|
||||
value, _ := flags.GetString(key)
|
||||
|
||||
// If set on Flags, use it.
|
||||
if flags.Changed(key) {
|
||||
return value, true
|
||||
}
|
||||
|
||||
// If set through viper (env, config), return it.
|
||||
if v.IsSet(key) {
|
||||
return v.GetString(key), true
|
||||
}
|
||||
|
||||
// Otherwise use default value on flags.
|
||||
return value, false
|
||||
}
|
||||
|
||||
func getParam(flags *pflag.FlagSet, key string) string {
|
||||
val, _ := getParamB(flags, key)
|
||||
return val
|
||||
}
|
||||
|
||||
func setupLog(logMethod string) {
|
||||
switch logMethod {
|
||||
case "stdout":
|
||||
log.SetOutput(os.Stdout)
|
||||
case "stderr":
|
||||
log.SetOutput(os.Stderr)
|
||||
case "":
|
||||
log.SetOutput(io.Discard)
|
||||
default:
|
||||
log.SetOutput(&lumberjack.Logger{
|
||||
Filename: logMethod,
|
||||
MaxSize: 100,
|
||||
MaxAge: 14,
|
||||
MaxBackups: 10,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func quickSetup(flags *pflag.FlagSet, d pythonData) {
|
||||
set := &settings.Settings{
|
||||
Key: generateKey(),
|
||||
Signup: false,
|
||||
CreateUserDir: false,
|
||||
UserHomeBasePath: settings.DefaultUsersHomeBasePath,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: ".",
|
||||
Locale: "en",
|
||||
SingleClick: false,
|
||||
Perm: users.Permissions{
|
||||
Admin: false,
|
||||
Execute: true,
|
||||
Create: true,
|
||||
Rename: true,
|
||||
Modify: true,
|
||||
Delete: true,
|
||||
Share: true,
|
||||
Download: true,
|
||||
},
|
||||
},
|
||||
AuthMethod: "",
|
||||
Branding: settings.Branding{},
|
||||
Commands: nil,
|
||||
Shell: nil,
|
||||
Rules: nil,
|
||||
}
|
||||
|
||||
var err error
|
||||
if _, noauth := getParamB(flags, "noauth"); noauth {
|
||||
set.AuthMethod = auth.MethodNoAuth
|
||||
err = d.store.Auth.Save(&auth.NoAuth{})
|
||||
func quickSetup(d pythonData) {
|
||||
settings.GlobalConfiguration.Auth.Key = generateKey()
|
||||
if settings.GlobalConfiguration.Auth.Method == "noauth" {
|
||||
err := d.store.Auth.Save(&auth.NoAuth{})
|
||||
checkErr(err)
|
||||
} else {
|
||||
set.AuthMethod = auth.MethodJSONAuth
|
||||
err = d.store.Auth.Save(&auth.JSONAuth{})
|
||||
}
|
||||
|
||||
err = d.store.Settings.Save(set)
|
||||
checkErr(err)
|
||||
|
||||
ser := &settings.Server{
|
||||
BaseURL: getParam(flags, "baseurl"),
|
||||
Port: getParam(flags, "port"),
|
||||
Log: getParam(flags, "log"),
|
||||
TLSKey: getParam(flags, "key"),
|
||||
TLSCert: getParam(flags, "cert"),
|
||||
Address: getParam(flags, "address"),
|
||||
Root: getParam(flags, "root"),
|
||||
}
|
||||
err = d.store.Settings.SaveServer(ser)
|
||||
checkErr(err)
|
||||
|
||||
username := getParam(flags, "username")
|
||||
password := getParam(flags, "password")
|
||||
|
||||
if password == "" {
|
||||
password, err = users.HashPwd("admin")
|
||||
settings.GlobalConfiguration.Auth.Method = "password"
|
||||
err := d.store.Auth.Save(&auth.JSONAuth{})
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
if username == "" || password == "" {
|
||||
log.Fatal("username and password cannot be empty during quick setup")
|
||||
}
|
||||
|
||||
user := &users.User{
|
||||
Username: username,
|
||||
Password: password,
|
||||
LockPassword: false,
|
||||
}
|
||||
|
||||
set.Defaults.Apply(user)
|
||||
err := d.store.Settings.Save(&settings.GlobalConfiguration)
|
||||
checkErr(err)
|
||||
err = d.store.Settings.SaveServer(&settings.GlobalConfiguration.Server)
|
||||
checkErr(err)
|
||||
user := &users.User{}
|
||||
settings.GlobalConfiguration.UserDefaults.Apply(user)
|
||||
user.Username = settings.GlobalConfiguration.Auth.AdminUsername
|
||||
user.Password = settings.GlobalConfiguration.Auth.AdminPassword
|
||||
user.Perm.Admin = true
|
||||
|
||||
user.Scope = "./"
|
||||
user.DarkMode = true
|
||||
user.ViewMode = "normal"
|
||||
user.LockPassword = false
|
||||
user.Perm = users.Permissions{
|
||||
Create: true,
|
||||
Rename: true,
|
||||
Modify: true,
|
||||
Delete: true,
|
||||
Share: true,
|
||||
Download: true,
|
||||
Admin: true,
|
||||
}
|
||||
err = d.store.Users.Save(user)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
if cfgFile == "" {
|
||||
v.AddConfigPath(".")
|
||||
v.AddConfigPath("/etc/filebrowser/")
|
||||
v.SetConfigName(".filebrowser")
|
||||
} else {
|
||||
v.SetConfigFile(cfgFile)
|
||||
}
|
||||
|
||||
v.SetEnvPrefix("FB")
|
||||
v.AutomaticEnv()
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(v.ConfigParseError); ok {
|
||||
panic(err)
|
||||
}
|
||||
cfgFile = "No config file used"
|
||||
} else {
|
||||
cfgFile = "Using config file: " + v.ConfigFileUsed()
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/storage/bolt/importer"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(upgradeCmd)
|
||||
|
||||
upgradeCmd.Flags().String("old.database", "", "")
|
||||
upgradeCmd.Flags().String("old.config", "", "")
|
||||
_ = upgradeCmd.MarkFlagRequired("old.database")
|
||||
}
|
||||
|
||||
var upgradeCmd = &cobra.Command{
|
||||
Use: "upgrade",
|
||||
Short: "Upgrades an old configuration",
|
||||
Long: `Upgrades an old configuration. This command DOES NOT
|
||||
import share links because they are incompatible with
|
||||
this version.`,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
flags := cmd.Flags()
|
||||
oldDB := mustGetString(flags, "old.database")
|
||||
oldConf := mustGetString(flags, "old.config")
|
||||
err := importer.Import(oldDB, oldConf, getParam(flags, "database"))
|
||||
checkErr(err)
|
||||
},
|
||||
}
|
||||
@@ -1,16 +1,13 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
@@ -59,76 +56,3 @@ func parseUsernameOrID(arg string) (username string, id uint) {
|
||||
}
|
||||
return "", uint(id64)
|
||||
}
|
||||
|
||||
func addUserFlags(flags *pflag.FlagSet) {
|
||||
flags.Bool("perm.admin", false, "admin perm for users")
|
||||
flags.Bool("perm.execute", true, "execute perm for users")
|
||||
flags.Bool("perm.create", true, "create perm for users")
|
||||
flags.Bool("perm.rename", true, "rename perm for users")
|
||||
flags.Bool("perm.modify", true, "modify perm for users")
|
||||
flags.Bool("perm.delete", true, "delete perm for users")
|
||||
flags.Bool("perm.share", true, "share perm for users")
|
||||
flags.Bool("perm.download", true, "download perm for users")
|
||||
flags.String("sorting.by", "name", "sorting mode (name, size or modified)")
|
||||
flags.Bool("sorting.asc", false, "sorting by ascending order")
|
||||
flags.Bool("lockPassword", false, "lock password")
|
||||
flags.StringSlice("commands", nil, "a list of the commands a user can execute")
|
||||
flags.String("scope", ".", "scope for users")
|
||||
flags.String("locale", "en", "locale for users")
|
||||
flags.String("viewMode", string(users.ListViewMode), "view mode for users")
|
||||
flags.Bool("singleClick", false, "use single clicks only")
|
||||
}
|
||||
|
||||
func getViewMode(flags *pflag.FlagSet) users.ViewMode {
|
||||
viewMode := users.ViewMode(mustGetString(flags, "viewMode"))
|
||||
if viewMode != users.ListViewMode && viewMode != users.MosaicViewMode {
|
||||
checkErr(errors.New("view mode must be \"" + string(users.ListViewMode) + "\" or \"" + string(users.MosaicViewMode) + "\""))
|
||||
}
|
||||
return viewMode
|
||||
}
|
||||
|
||||
//nolint:gocyclo
|
||||
func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all bool) {
|
||||
visit := func(flag *pflag.Flag) {
|
||||
switch flag.Name {
|
||||
case "scope":
|
||||
defaults.Scope = mustGetString(flags, flag.Name)
|
||||
case "locale":
|
||||
defaults.Locale = mustGetString(flags, flag.Name)
|
||||
case "viewMode":
|
||||
defaults.ViewMode = getViewMode(flags)
|
||||
case "singleClick":
|
||||
defaults.SingleClick = mustGetBool(flags, flag.Name)
|
||||
case "perm.admin":
|
||||
defaults.Perm.Admin = mustGetBool(flags, flag.Name)
|
||||
case "perm.execute":
|
||||
defaults.Perm.Execute = mustGetBool(flags, flag.Name)
|
||||
case "perm.create":
|
||||
defaults.Perm.Create = mustGetBool(flags, flag.Name)
|
||||
case "perm.rename":
|
||||
defaults.Perm.Rename = mustGetBool(flags, flag.Name)
|
||||
case "perm.modify":
|
||||
defaults.Perm.Modify = mustGetBool(flags, flag.Name)
|
||||
case "perm.delete":
|
||||
defaults.Perm.Delete = mustGetBool(flags, flag.Name)
|
||||
case "perm.share":
|
||||
defaults.Perm.Share = mustGetBool(flags, flag.Name)
|
||||
case "perm.download":
|
||||
defaults.Perm.Download = mustGetBool(flags, flag.Name)
|
||||
case "commands":
|
||||
commands, err := flags.GetStringSlice(flag.Name)
|
||||
checkErr(err)
|
||||
defaults.Commands = commands
|
||||
case "sorting.by":
|
||||
defaults.Sorting.By = mustGetString(flags, flag.Name)
|
||||
case "sorting.asc":
|
||||
defaults.Sorting.Asc = mustGetBool(flags, flag.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if all {
|
||||
flags.VisitAll(visit)
|
||||
} else {
|
||||
flags.Visit(visit)
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
func init() {
|
||||
usersCmd.AddCommand(usersAddCmd)
|
||||
addUserFlags(usersAddCmd.Flags())
|
||||
}
|
||||
|
||||
var usersAddCmd = &cobra.Command{
|
||||
@@ -17,21 +16,11 @@ var usersAddCmd = &cobra.Command{
|
||||
Long: `Create a new user and add it to the database.`,
|
||||
Args: cobra.ExactArgs(2), //nolint:gomnd
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
s, err := d.store.Settings.Get()
|
||||
checkErr(err)
|
||||
getUserDefaults(cmd.Flags(), &s.Defaults, false)
|
||||
|
||||
password, err := users.HashPwd(args[1])
|
||||
checkErr(err)
|
||||
|
||||
user := &users.User{
|
||||
Username: args[0],
|
||||
Password: password,
|
||||
Password: args[1],
|
||||
LockPassword: mustGetBool(cmd.Flags(), "lockPassword"),
|
||||
}
|
||||
|
||||
s.Defaults.Apply(user)
|
||||
|
||||
servSettings, err := d.store.Settings.GetServer()
|
||||
checkErr(err)
|
||||
// since getUserDefaults() polluted s.Defaults.Scope
|
||||
|
||||
@@ -3,16 +3,11 @@ package cmd
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
func init() {
|
||||
usersCmd.AddCommand(usersUpdateCmd)
|
||||
|
||||
usersUpdateCmd.Flags().StringP("password", "p", "", "new password")
|
||||
usersUpdateCmd.Flags().StringP("username", "u", "", "new username")
|
||||
addUserFlags(usersUpdateCmd.Flags())
|
||||
}
|
||||
|
||||
var usersUpdateCmd = &cobra.Command{
|
||||
@@ -23,9 +18,6 @@ options you want to change.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: python(func(cmd *cobra.Command, args []string, d pythonData) {
|
||||
username, id := parseUsernameOrID(args[0])
|
||||
flags := cmd.Flags()
|
||||
password := mustGetString(flags, "password")
|
||||
newUsername := mustGetString(flags, "username")
|
||||
|
||||
var (
|
||||
err error
|
||||
@@ -37,37 +29,8 @@ options you want to change.`,
|
||||
} else {
|
||||
user, err = d.store.Users.Get("", username)
|
||||
}
|
||||
|
||||
checkErr(err)
|
||||
|
||||
defaults := settings.UserDefaults{
|
||||
Scope: user.Scope,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
Perm: user.Perm,
|
||||
Sorting: user.Sorting,
|
||||
Commands: user.Commands,
|
||||
}
|
||||
getUserDefaults(flags, &defaults, false)
|
||||
user.Scope = defaults.Scope
|
||||
user.Locale = defaults.Locale
|
||||
user.ViewMode = defaults.ViewMode
|
||||
user.SingleClick = defaults.SingleClick
|
||||
user.Perm = defaults.Perm
|
||||
user.Commands = defaults.Commands
|
||||
user.Sorting = defaults.Sorting
|
||||
user.LockPassword = mustGetBool(flags, "lockPassword")
|
||||
|
||||
if newUsername != "" {
|
||||
user.Username = newUsername
|
||||
}
|
||||
|
||||
if password != "" {
|
||||
user.Password, err = users.HashPwd(password)
|
||||
checkErr(err)
|
||||
}
|
||||
|
||||
err = d.store.Users.Update(user)
|
||||
checkErr(err)
|
||||
printUsers([]*users.User{user})
|
||||
|
||||
@@ -3,16 +3,14 @@ package cmd
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/storage"
|
||||
@@ -85,8 +83,7 @@ func dbExists(path string) (bool, error) {
|
||||
func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
||||
return func(cmd *cobra.Command, args []string) {
|
||||
data := pythonData{hadDB: true}
|
||||
|
||||
path := getParam(cmd.Flags(), "database")
|
||||
path := settings.GlobalConfiguration.Server.Database
|
||||
exists, err := dbExists(path)
|
||||
|
||||
if err != nil {
|
||||
@@ -100,6 +97,7 @@ func python(fn pythonFunc, cfg pythonConfig) cobraFunc {
|
||||
data.hadDB = exists
|
||||
db, err := storm.Open(path)
|
||||
checkErr(err)
|
||||
|
||||
defer db.Close()
|
||||
data.store, err = bolt.NewStorage(db)
|
||||
checkErr(err)
|
||||
@@ -118,8 +116,8 @@ func marshal(filename string, data interface{}) error {
|
||||
encoder.SetIndent("", " ")
|
||||
return encoder.Encode(data)
|
||||
case ".yml", ".yaml": //nolint:goconst
|
||||
encoder := yaml.NewEncoder(fd)
|
||||
return encoder.Encode(data)
|
||||
_, err := yaml.Marshal(fd)
|
||||
return err
|
||||
default:
|
||||
return errors.New("invalid format: " + ext)
|
||||
}
|
||||
@@ -152,42 +150,3 @@ func jsonYamlArg(cmd *cobra.Command, args []string) error {
|
||||
return errors.New("invalid format: " + ext)
|
||||
}
|
||||
}
|
||||
|
||||
func cleanUpInterfaceMap(in map[interface{}]interface{}) map[string]interface{} {
|
||||
result := make(map[string]interface{})
|
||||
for k, v := range in {
|
||||
result[fmt.Sprintf("%v", k)] = cleanUpMapValue(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func cleanUpInterfaceArray(in []interface{}) []interface{} {
|
||||
result := make([]interface{}, len(in))
|
||||
for i, v := range in {
|
||||
result[i] = cleanUpMapValue(v)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func cleanUpMapValue(v interface{}) interface{} {
|
||||
switch v := v.(type) {
|
||||
case []interface{}:
|
||||
return cleanUpInterfaceArray(v)
|
||||
case map[interface{}]interface{}:
|
||||
return cleanUpInterfaceMap(v)
|
||||
default:
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// convertCmdStrToCmdArray checks if cmd string is blank (whitespace included)
|
||||
// then returns empty string array, else returns the splitted word array of cmd.
|
||||
// This is to ensure the result will never be []string{""}
|
||||
func convertCmdStrToCmdArray(cmd string) []string {
|
||||
var cmdArray []string
|
||||
trimmedCmdStr := strings.TrimSpace(cmd)
|
||||
if trimmedCmdStr != "" {
|
||||
cmdArray = strings.Split(trimmedCmdStr, " ")
|
||||
}
|
||||
return cmdArray
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
server:
|
||||
port: 8080
|
||||
baseURL: "/"
|
||||
auth:
|
||||
method: password
|
||||
signup: true
|
||||
userDefaults:
|
||||
darkMode: true
|
||||
disableSettings: false
|
||||
scope: "."
|
||||
hideDotfiles: true
|
||||
singleClick: false
|
||||
permissions:
|
||||
admin: false
|
||||
create: false
|
||||
rename: false
|
||||
modify: false
|
||||
delete: false
|
||||
share: false
|
||||
download: false
|
||||
@@ -1,68 +1,58 @@
|
||||
module github.com/gtsteffaniak/filebrowser
|
||||
|
||||
go 1.21.1
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/asdine/storm/v3 v3.2.1
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/dsoprea/go-exif/v3 v3.0.1
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
|
||||
github.com/goccy/go-yaml v1.11.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||
github.com/google/go-cmp v0.5.9
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/maruel/natural v1.1.0
|
||||
github.com/marusama/semaphore/v2 v2.5.0
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/pelletier/go-toml/v2 v2.1.0
|
||||
github.com/shirou/gopsutil/v3 v3.23.9
|
||||
github.com/spf13/afero v1.10.0
|
||||
github.com/shirou/gopsutil/v3 v3.23.8
|
||||
github.com/spf13/afero v1.9.5
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.17.0
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
golang.org/x/crypto v0.14.0
|
||||
golang.org/x/image v0.13.0
|
||||
golang.org/x/crypto v0.12.0
|
||||
golang.org/x/image v0.12.0
|
||||
golang.org/x/text v0.13.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect
|
||||
github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/fatih/color v1.10.0 // indirect
|
||||
github.com/go-errors/errors v1.4.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551 // indirect
|
||||
github.com/golang/snappy v0.0.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/klauspost/compress v1.11.4 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.9 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/net v0.15.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
go.etcd.io/bbolt v1.3.4 // indirect
|
||||
golang.org/x/net v0.10.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -56,9 +56,8 @@ github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnht
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
|
||||
@@ -87,12 +86,10 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
github.com/go-errors/errors v1.1.1/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
|
||||
@@ -103,6 +100,14 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/goccy/go-yaml v1.11.0 h1:n7Z+zx8S9f9KgzG6KtQKf+kwqXZlLNR2F6018Dgau54=
|
||||
github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
@@ -133,9 +138,8 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
|
||||
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
@@ -174,12 +178,8 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
@@ -190,74 +190,57 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.11.4 h1:kz40R/YWls3iqT9zX9AHN3WoVsrAWVyui5sxuLqiXqU=
|
||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/maruel/natural v1.1.0 h1:2z1NgP/Vae+gYrtC0VuvrTJ6U35OuyUqDdfluLqMWuQ=
|
||||
github.com/maruel/natural v1.1.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ=
|
||||
github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM=
|
||||
github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
|
||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
|
||||
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E=
|
||||
github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA=
|
||||
github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE=
|
||||
github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
|
||||
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
|
||||
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
|
||||
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
|
||||
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
|
||||
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
@@ -265,8 +248,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
|
||||
@@ -282,30 +263,27 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -316,13 +294,11 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg=
|
||||
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
|
||||
golang.org/x/image v0.12.0 h1:w13vZbU4o5rKOFFR8y7M+c4A5jXDC0uXTdHYRP8X2DQ=
|
||||
golang.org/x/image v0.12.0/go.mod h1:Lu90jvHG7GfemOIcldsh9A2hS01ocl6oNO7ype5mEnk=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -344,6 +320,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -378,9 +356,11 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -400,6 +380,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -414,6 +396,7 @@ golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -438,16 +421,17 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -456,6 +440,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -508,9 +493,12 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
@@ -600,16 +588,13 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/golang-jwt/jwt/v4/request"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
@@ -19,20 +20,8 @@ const (
|
||||
TokenExpirationTime = time.Hour * 2
|
||||
)
|
||||
|
||||
type userInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
}
|
||||
|
||||
type authToken struct {
|
||||
User userInfo `json:"user"`
|
||||
User users.User `json:"user"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
@@ -66,7 +55,7 @@ func (e extractor) ExtractToken(r *http.Request) (string, error) {
|
||||
func withUser(fn handleFunc) handleFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
keyFunc := func(token *jwt.Token) (interface{}, error) {
|
||||
return d.settings.Key, nil
|
||||
return d.settings.Auth.Key, nil
|
||||
}
|
||||
|
||||
var tk authToken
|
||||
@@ -102,12 +91,12 @@ func withAdmin(fn handleFunc) handleFunc {
|
||||
}
|
||||
|
||||
var loginHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
auther, err := d.store.Auth.Get(d.settings.AuthMethod)
|
||||
auther, err := d.store.Auth.Get(d.settings.Auth.Method)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
user, err := auther.Auth(r, d.store.Users, d.settings, d.server)
|
||||
user, err := auther.Auth(r, d.store.Users)
|
||||
if err == os.ErrPermission {
|
||||
return http.StatusForbidden, nil
|
||||
} else if err != nil {
|
||||
@@ -123,7 +112,7 @@ type signupBody struct {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -143,17 +132,9 @@ var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int,
|
||||
|
||||
user := &users.User{
|
||||
Username: info.Username,
|
||||
Password: info.Password,
|
||||
}
|
||||
|
||||
d.settings.Defaults.Apply(user)
|
||||
|
||||
pwd, err := users.HashPwd(info.Password)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
user.Password = pwd
|
||||
|
||||
settings.GlobalConfiguration.UserDefaults.Apply(user)
|
||||
userHome, err := d.settings.MakeUserDir(user.Username, user.Scope, d.server.Root)
|
||||
if err != nil {
|
||||
log.Printf("create user: failed to mkdir user home dir: [%s]", userHome)
|
||||
@@ -161,7 +142,7 @@ var signupHandler = func(w http.ResponseWriter, r *http.Request, d *data) (int,
|
||||
}
|
||||
user.Scope = userHome
|
||||
log.Printf("new user: %s, home dir: [%s].", user.Username, userHome)
|
||||
|
||||
settings.GlobalConfiguration.UserDefaults.Apply(user)
|
||||
err = d.store.Users.Save(user)
|
||||
if err == errors.ErrExist {
|
||||
return http.StatusConflict, err
|
||||
@@ -178,17 +159,7 @@ var renewHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data
|
||||
|
||||
func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.User) (int, error) {
|
||||
claims := &authToken{
|
||||
User: userInfo{
|
||||
ID: user.ID,
|
||||
Locale: user.Locale,
|
||||
ViewMode: user.ViewMode,
|
||||
SingleClick: user.SingleClick,
|
||||
Perm: user.Perm,
|
||||
LockPassword: user.LockPassword,
|
||||
Commands: user.Commands,
|
||||
HideDotfiles: user.HideDotfiles,
|
||||
DateFormat: user.DateFormat,
|
||||
},
|
||||
User: *user,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(TokenExpirationTime)),
|
||||
@@ -197,7 +168,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use
|
||||
}
|
||||
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
signed, err := token.SignedString(d.settings.Key)
|
||||
signed, err := token.SignedString(d.settings.Auth.Key)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/runner"
|
||||
)
|
||||
|
||||
const (
|
||||
WSWriteDeadline = 10 * time.Second
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
}
|
||||
|
||||
var (
|
||||
cmdNotAllowed = []byte("Command not allowed.")
|
||||
)
|
||||
|
||||
//nolint:unparam
|
||||
func wsErr(ws *websocket.Conn, r *http.Request, status int, err error) {
|
||||
txt := http.StatusText(status)
|
||||
if err != nil || status >= 400 {
|
||||
log.Printf("%s: %v %s %v", r.URL.Path, status, r.RemoteAddr, err)
|
||||
}
|
||||
if err := ws.WriteControl(websocket.CloseInternalServerErr, []byte(txt), time.Now().Add(WSWriteDeadline)); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
var commandsHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
var raw string
|
||||
|
||||
for {
|
||||
_, msg, err := conn.ReadMessage() //nolint:govet
|
||||
if err != nil {
|
||||
wsErr(conn, r, http.StatusInternalServerError, err)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
raw = strings.TrimSpace(string(msg))
|
||||
if raw != "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
command, err := runner.ParseCommand(d.settings, raw)
|
||||
if err != nil {
|
||||
if err := conn.WriteMessage(websocket.TextMessage, []byte(err.Error())); err != nil { //nolint:govet
|
||||
wsErr(conn, r, http.StatusInternalServerError, err)
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if !d.server.EnableExec || !d.user.CanExecute(command[0]) {
|
||||
if err := conn.WriteMessage(websocket.TextMessage, cmdNotAllowed); err != nil { //nolint:govet
|
||||
wsErr(conn, r, http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
cmd := exec.Command(command[0], command[1:]...) //nolint:gosec
|
||||
cmd.Dir = d.user.FullPath(r.URL.Path)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
wsErr(conn, r, http.StatusInternalServerError, err)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
stderr, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
wsErr(conn, r, http.StatusInternalServerError, err)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
wsErr(conn, r, http.StatusInternalServerError, err)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
s := bufio.NewScanner(io.MultiReader(stdout, stderr))
|
||||
for s.Scan() {
|
||||
if err := conn.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
wsErr(conn, r, http.StatusInternalServerError, err)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
})
|
||||
@@ -32,58 +32,44 @@ func NewHandler(
|
||||
})
|
||||
})
|
||||
index, static := getStaticHandlers(store, server, assetsFs)
|
||||
|
||||
// NOTE: This fixes the issue where it would redirect if people did not put a
|
||||
// trailing slash in the end. I hate this decision since this allows some awful
|
||||
// URLs https://www.gorillatoolkit.org/pkg/mux#Router.SkipClean
|
||||
r = r.SkipClean(true)
|
||||
|
||||
monkey := func(fn handleFunc, prefix string) http.Handler {
|
||||
return handle(fn, prefix, store, server)
|
||||
}
|
||||
|
||||
r.HandleFunc("/health", healthHandler)
|
||||
r.PathPrefix("/static").Handler(static)
|
||||
r.NotFoundHandler = index
|
||||
|
||||
api := r.PathPrefix("/api").Subrouter()
|
||||
|
||||
api.Handle("/login", monkey(loginHandler, ""))
|
||||
api.Handle("/signup", monkey(signupHandler, ""))
|
||||
api.Handle("/renew", monkey(renewHandler, ""))
|
||||
|
||||
users := api.PathPrefix("/users").Subrouter()
|
||||
users.Handle("", monkey(usersGetHandler, "")).Methods("GET")
|
||||
users.Handle("", monkey(userPostHandler, "")).Methods("POST")
|
||||
users.Handle("/{id:[0-9]+}", monkey(userPutHandler, "")).Methods("PUT")
|
||||
users.Handle("/{id:[0-9]+}", monkey(userGetHandler, "")).Methods("GET")
|
||||
users.Handle("/{id:[0-9]+}", monkey(userDeleteHandler, "")).Methods("DELETE")
|
||||
|
||||
api.PathPrefix("/resources").Handler(monkey(resourceGetHandler, "/api/resources")).Methods("GET")
|
||||
api.PathPrefix("/resources").Handler(monkey(resourceDeleteHandler(fileCache), "/api/resources")).Methods("DELETE")
|
||||
api.PathPrefix("/resources").Handler(monkey(resourcePostHandler(fileCache), "/api/resources")).Methods("POST")
|
||||
api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT")
|
||||
api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH")
|
||||
|
||||
api.PathPrefix("/usage").Handler(monkey(diskUsage, "/api/usage")).Methods("GET")
|
||||
|
||||
api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET")
|
||||
api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET")
|
||||
api.PathPrefix("/share").Handler(monkey(sharePostHandler, "/api/share")).Methods("POST")
|
||||
api.PathPrefix("/share").Handler(monkey(shareDeleteHandler, "/api/share")).Methods("DELETE")
|
||||
|
||||
api.Handle("/settings", monkey(settingsGetHandler, "")).Methods("GET")
|
||||
api.Handle("/settings", monkey(settingsPutHandler, "")).Methods("PUT")
|
||||
|
||||
api.PathPrefix("/raw").Handler(monkey(rawHandler, "/api/raw")).Methods("GET")
|
||||
api.PathPrefix("/preview/{size}/{path:.*}").
|
||||
Handler(monkey(previewHandler(imgSvc, fileCache, server.EnableThumbnails, server.ResizePreview), "/api/preview")).Methods("GET")
|
||||
api.PathPrefix("/command").Handler(monkey(commandsHandler, "/api/command")).Methods("GET")
|
||||
api.PathPrefix("/search").Handler(monkey(searchHandler, "/api/search")).Methods("GET")
|
||||
|
||||
public := api.PathPrefix("/public").Subrouter()
|
||||
public.PathPrefix("/dl").Handler(monkey(publicDlHandler, "/api/public/dl/")).Methods("GET")
|
||||
public.PathPrefix("/share").Handler(monkey(publicShareHandler, "/api/public/share/")).Methods("GET")
|
||||
|
||||
return stripPrefix(server.BaseURL, r), nil
|
||||
}
|
||||
@@ -85,7 +85,11 @@ func TestPublicShareHandlerAuthentication(t *testing.T) {
|
||||
if err := storage.Users.Save(&users.User{Username: "username", Password: "pw"}); err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,22 @@ package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/search"
|
||||
"github.com/gtsteffaniak/filebrowser/index"
|
||||
)
|
||||
|
||||
var searchHandler = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
response := []map[string]interface{}{}
|
||||
query := r.URL.Query().Get("query")
|
||||
|
||||
// Retrieve the User-Agent and X-Auth headers from the request
|
||||
sessionId := r.Header.Get("SessionId")
|
||||
indexInfo, fileTypes := search.SearchAllIndexes(query, r.URL.Path, sessionId)
|
||||
for _, path := range indexInfo {
|
||||
userScope := r.Header.Get("UserScope")
|
||||
index := *index.GetIndex()
|
||||
combinedScope := strings.TrimPrefix(userScope+r.URL.Path, ".")
|
||||
combinedScope = strings.TrimPrefix(combinedScope, "/")
|
||||
results, fileTypes := index.Search(query, combinedScope, sessionId)
|
||||
for _, path := range results {
|
||||
responseObj := map[string]interface{}{
|
||||
"path": path,
|
||||
"dir": true,
|
||||
|
||||
@@ -14,19 +14,19 @@ type settingsData struct {
|
||||
UserHomeBasePath string `json:"userHomeBasePath"`
|
||||
Defaults settings.UserDefaults `json:"defaults"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
Branding settings.Branding `json:"branding"`
|
||||
Frontend settings.Frontend `json:"frontend"`
|
||||
Shell []string `json:"shell"`
|
||||
Commands map[string][]string `json:"commands"`
|
||||
}
|
||||
|
||||
var settingsGetHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) {
|
||||
data := &settingsData{
|
||||
Signup: d.settings.Signup,
|
||||
CreateUserDir: d.settings.CreateUserDir,
|
||||
UserHomeBasePath: d.settings.UserHomeBasePath,
|
||||
Defaults: d.settings.Defaults,
|
||||
Signup: settings.GlobalConfiguration.Auth.Signup,
|
||||
CreateUserDir: settings.GlobalConfiguration.Server.CreateUserDir,
|
||||
UserHomeBasePath: settings.GlobalConfiguration.Server.UserHomeBasePath,
|
||||
Defaults: d.settings.UserDefaults,
|
||||
Rules: d.settings.Rules,
|
||||
Branding: d.settings.Branding,
|
||||
Frontend: d.settings.Frontend,
|
||||
Shell: d.settings.Shell,
|
||||
Commands: d.settings.Commands,
|
||||
}
|
||||
@@ -41,15 +41,13 @@ var settingsPutHandler = withAdmin(func(w http.ResponseWriter, r *http.Request,
|
||||
return http.StatusBadRequest, err
|
||||
}
|
||||
|
||||
d.settings.Signup = req.Signup
|
||||
d.settings.CreateUserDir = req.CreateUserDir
|
||||
d.settings.UserHomeBasePath = req.UserHomeBasePath
|
||||
d.settings.Defaults = req.Defaults
|
||||
d.settings.Server.CreateUserDir = req.CreateUserDir
|
||||
d.settings.Server.UserHomeBasePath = req.UserHomeBasePath
|
||||
d.settings.UserDefaults = req.Defaults
|
||||
d.settings.Rules = req.Rules
|
||||
d.settings.Branding = req.Branding
|
||||
d.settings.Frontend = req.Frontend
|
||||
d.settings.Shell = req.Shell
|
||||
d.settings.Commands = req.Commands
|
||||
|
||||
err = d.store.Settings.Save(d.settings)
|
||||
return errToStatus(err), err
|
||||
})
|
||||
@@ -129,7 +129,7 @@ var sharePostHandler = withPermShare(func(w http.ResponseWriter, r *http.Request
|
||||
|
||||
var token string
|
||||
if len(hash) > 0 {
|
||||
tokenBuffer := make([]byte, 96) //nolint:gomnd
|
||||
tokenBuffer := make([]byte, 24) //nolint:gomnd
|
||||
if _, err := rand.Read(tokenBuffer); err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
@@ -21,33 +21,33 @@ import (
|
||||
func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys fs.FS, file, contentType string) (int, error) {
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
|
||||
auther, err := d.store.Auth.Get(d.settings.AuthMethod)
|
||||
auther, err := d.store.Auth.Get(d.settings.Auth.Method)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"Name": d.settings.Branding.Name,
|
||||
"DisableExternal": d.settings.Branding.DisableExternal,
|
||||
"DisableUsedPercentage": d.settings.Branding.DisableUsedPercentage,
|
||||
"Color": d.settings.Branding.Color,
|
||||
"Name": d.settings.Frontend.Name,
|
||||
"DisableExternal": d.settings.Frontend.DisableExternal,
|
||||
"DisableUsedPercentage": d.settings.Frontend.DisableUsedPercentage,
|
||||
"darkMode": settings.GlobalConfiguration.UserDefaults.DarkMode,
|
||||
"Color": d.settings.Frontend.Color,
|
||||
"BaseURL": d.server.BaseURL,
|
||||
"Version": version.Version,
|
||||
"StaticURL": path.Join(d.server.BaseURL, "/static"),
|
||||
"Signup": d.settings.Signup,
|
||||
"NoAuth": d.settings.AuthMethod == auth.MethodNoAuth,
|
||||
"AuthMethod": d.settings.AuthMethod,
|
||||
"Signup": settings.GlobalConfiguration.Auth.Signup,
|
||||
"NoAuth": d.settings.Auth.Method == "noauth",
|
||||
"AuthMethod": d.settings.Auth.Method,
|
||||
"LoginPage": auther.LoginPage(),
|
||||
"CSS": false,
|
||||
"ReCaptcha": false,
|
||||
"Theme": d.settings.Branding.Theme,
|
||||
"EnableThumbs": d.server.EnableThumbnails,
|
||||
"ResizePreview": d.server.ResizePreview,
|
||||
"EnableExec": d.server.EnableExec,
|
||||
}
|
||||
|
||||
if d.settings.Branding.Files != "" {
|
||||
fPath := filepath.Join(d.settings.Branding.Files, "custom.css")
|
||||
if d.settings.Frontend.Files != "" {
|
||||
fPath := filepath.Join(d.settings.Frontend.Files, "custom.css")
|
||||
_, err := os.Stat(fPath) //nolint:govet
|
||||
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
@@ -59,8 +59,8 @@ func handleWithStaticData(w http.ResponseWriter, _ *http.Request, d *data, fSys
|
||||
}
|
||||
}
|
||||
|
||||
if d.settings.AuthMethod == auth.MethodJSONAuth {
|
||||
raw, err := d.store.Auth.Get(d.settings.AuthMethod) //nolint:govet
|
||||
if d.settings.Auth.Method == "password" {
|
||||
raw, err := d.store.Auth.Get(d.settings.Auth.Method) //nolint:govet
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
@@ -115,15 +115,15 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
|
||||
const maxAge = 86400 // 1 day
|
||||
w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%v", maxAge))
|
||||
|
||||
if d.settings.Branding.Files != "" {
|
||||
if d.settings.Frontend.Files != "" {
|
||||
if strings.HasPrefix(r.URL.Path, "img/") {
|
||||
fPath := filepath.Join(d.settings.Branding.Files, r.URL.Path)
|
||||
fPath := filepath.Join(d.settings.Frontend.Files, r.URL.Path)
|
||||
if _, err := os.Stat(fPath); err == nil {
|
||||
http.ServeFile(w, r, fPath)
|
||||
return 0, nil
|
||||
}
|
||||
} else if r.URL.Path == "custom.css" && d.settings.Branding.Files != "" {
|
||||
http.ServeFile(w, r, filepath.Join(d.settings.Branding.Files, "custom.css"))
|
||||
} else if r.URL.Path == "custom.css" && d.settings.Frontend.Files != "" {
|
||||
http.ServeFile(w, r, filepath.Join(d.settings.Frontend.Files, "custom.css"))
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
@@ -139,7 +139,7 @@ func getStaticHandlers(store *storage.Storage, server *settings.Server, assetsFs
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Encoding", "gzip")
|
||||
w.Header().Set("Content-Type", "application/javascript; charset=utf-8")
|
||||
w.Header().Set("Content-Type", "application/javascript; charset=utf-8") // Set the correct MIME type for JavaScript files
|
||||
|
||||
if _, err := w.Write(fileContents); err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
|
||||
@@ -124,11 +124,6 @@ var userPostHandler = withAdmin(func(w http.ResponseWriter, r *http.Request, d *
|
||||
return http.StatusBadRequest, errors.ErrEmptyPassword
|
||||
}
|
||||
|
||||
req.Data.Password, err = users.HashPwd(req.Data.Password)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
userHome, err := d.settings.MakeUserDir(req.Data.Username, req.Data.Scope, d.server.Root)
|
||||
if err != nil {
|
||||
log.Printf("create user: failed to mkdir user home dir: [%s]", userHome)
|
||||
@@ -184,7 +179,6 @@ var userPutHandler = withSelfOrAdmin(func(w http.ResponseWriter, r *http.Request
|
||||
if !d.user.Perm.Admin && d.user.LockPassword {
|
||||
return http.StatusForbidden, nil
|
||||
}
|
||||
|
||||
req.Data.Password, err = users.HashPwd(req.Data.Password)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
package search
|
||||
package index
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var typeRegexp = regexp.MustCompile(`type:(\S+)`)
|
||||
|
||||
var AllFiletypeOptions = []string{
|
||||
"image",
|
||||
"audio",
|
||||
"archive",
|
||||
"video",
|
||||
"doc",
|
||||
"dir",
|
||||
}
|
||||
var documentTypes = []string{
|
||||
".word",
|
||||
".pdf",
|
||||
@@ -120,3 +128,35 @@ func updateSize(given string) int {
|
||||
return size
|
||||
}
|
||||
}
|
||||
|
||||
func IsMatchingType(extension string, matchType string) bool {
|
||||
mimetype := mime.TypeByExtension(extension)
|
||||
if strings.HasPrefix(mimetype, matchType) {
|
||||
return true
|
||||
}
|
||||
switch matchType {
|
||||
case "doc":
|
||||
return isDoc(extension)
|
||||
case "archive":
|
||||
return isArchive(extension)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isDoc(extension string) bool {
|
||||
for _, typefile := range documentTypes {
|
||||
if extension == typefile {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isArchive(extension string) bool {
|
||||
for _, typefile := range compressedFile {
|
||||
if extension == typefile {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
)
|
||||
|
||||
type Index struct {
|
||||
Dirs []string
|
||||
Files []string
|
||||
}
|
||||
|
||||
var (
|
||||
rootPath string = "/srv"
|
||||
indexes Index
|
||||
indexMutex sync.RWMutex
|
||||
lastIndexed time.Time
|
||||
)
|
||||
|
||||
func GetIndex() *Index {
|
||||
return &indexes
|
||||
}
|
||||
|
||||
func Initialize(intervalMinutes uint32) {
|
||||
// Initialize the index
|
||||
indexes = Index{
|
||||
Dirs: []string{},
|
||||
Files: []string{},
|
||||
}
|
||||
rootPath = settings.GlobalConfiguration.Server.Root
|
||||
var numFiles, numDirs int
|
||||
log.Println("Indexing files...")
|
||||
lastIndexedStart := time.Now()
|
||||
// Call the function to index files and directories
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
go indexingScheduler(intervalMinutes)
|
||||
log.Println("Successfully indexed files.")
|
||||
log.Println("Files found :", totalNumFiles)
|
||||
log.Println("Directories found :", totalNumDirs)
|
||||
}
|
||||
|
||||
func indexingScheduler(intervalMinutes uint32) {
|
||||
log.Printf("Indexing scheduler will run every %v minutes", intervalMinutes)
|
||||
for {
|
||||
indexes.Dirs = slices.Compact(indexes.Dirs)
|
||||
indexes.Files = slices.Compact(indexes.Files)
|
||||
time.Sleep(time.Duration(intervalMinutes) * time.Minute)
|
||||
var numFiles, numDirs int
|
||||
lastIndexedStart := time.Now()
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
if totalNumFiles+totalNumDirs > 0 {
|
||||
log.Println("re-indexing found changes and updated the index.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removeFromSlice(slice []string, target string) []string {
|
||||
for i, s := range slice {
|
||||
if s == target {
|
||||
// Swap the target element with the last element
|
||||
slice[i], slice[len(slice)-1] = slice[len(slice)-1], slice[i]
|
||||
// Resize the slice to exclude the last element
|
||||
slice = slice[:len(slice)-1]
|
||||
break // Exit the loop, assuming there's only one target element
|
||||
}
|
||||
}
|
||||
return slice
|
||||
}
|
||||
|
||||
// Define a function to recursively index files and directories
|
||||
func indexFiles(path string, numFiles *int, numDirs *int) (int, int, error) {
|
||||
// Check if the current directory has been modified since last indexing
|
||||
dir, err := os.Open(path)
|
||||
if err != nil {
|
||||
// directory must have been deleted, remove from index
|
||||
indexes.Dirs = removeFromSlice(indexes.Dirs, path)
|
||||
indexes.Files = removeFromSlice(indexes.Files, path)
|
||||
}
|
||||
defer dir.Close()
|
||||
dirInfo, err := dir.Stat()
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Compare the last modified time of the directory with the last indexed time
|
||||
if dirInfo.ModTime().Before(lastIndexed) {
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
// Read the directory contents
|
||||
files, err := dir.Readdir(-1)
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Iterate over the files and directories
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
*numDirs++
|
||||
addToIndex(path, file.Name(), true)
|
||||
_, _, err := indexFiles(path+"/"+file.Name(), numFiles, numDirs) // recursive
|
||||
if err != nil {
|
||||
log.Println("Could not index :", err)
|
||||
}
|
||||
} else {
|
||||
*numFiles++
|
||||
addToIndex(path, file.Name(), false)
|
||||
}
|
||||
}
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
|
||||
func addToIndex(path string, fileName string, isDir bool) {
|
||||
indexMutex.Lock()
|
||||
defer indexMutex.Unlock()
|
||||
path = strings.TrimPrefix(path, rootPath+"/")
|
||||
path = strings.TrimSuffix(path, "/")
|
||||
adjustedPath := path + "/" + fileName
|
||||
if path == rootPath {
|
||||
adjustedPath = fileName
|
||||
}
|
||||
if isDir {
|
||||
indexes.Dirs = append(indexes.Dirs, adjustedPath)
|
||||
} else {
|
||||
indexes.Files = append(indexes.Files, adjustedPath)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func BenchmarkFillIndex(b *testing.B) {
|
||||
indexes = Index{
|
||||
Dirs: []string{},
|
||||
Files: []string{},
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
createMockData(50, 3) // 1000 dirs, 3 files per dir
|
||||
}
|
||||
}
|
||||
|
||||
func createMockData(numDirs, numFilesPerDir int) {
|
||||
for i := 0; i < numDirs; i++ {
|
||||
dirName := generateRandomPath(rand.Intn(3) + 1)
|
||||
addToIndex("/", dirName, true)
|
||||
for j := 0; j < numFilesPerDir; j++ {
|
||||
fileName := "file-" + getRandomTerm() + getRandomExtension()
|
||||
addToIndex("/"+dirName, fileName, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateRandomPath(levels int) string {
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
dirName := "srv"
|
||||
for i := 0; i < levels; i++ {
|
||||
dirName += "/" + getRandomTerm()
|
||||
}
|
||||
return dirName
|
||||
}
|
||||
|
||||
func getRandomTerm() string {
|
||||
wordbank := []string{
|
||||
"hi", "test", "other", "name",
|
||||
"cool", "things", "more", "items",
|
||||
}
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func getRandomExtension() string {
|
||||
wordbank := []string{
|
||||
".txt", ".mp3", ".mov", ".doc",
|
||||
".mp4", ".bak", ".zip", ".jpg",
|
||||
}
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func generateRandomSearchTerms(numTerms int) []string {
|
||||
// Generate random search terms
|
||||
searchTerms := make([]string, numTerms)
|
||||
for i := 0; i < numTerms; i++ {
|
||||
searchTerms[i] = getRandomTerm()
|
||||
}
|
||||
return searchTerms
|
||||
}
|
||||
|
||||
// JSONBytesEqual compares the JSON in two byte slices.
|
||||
func JSONBytesEqual(a, b []byte) (bool, error) {
|
||||
var j, j2 interface{}
|
||||
if err := json.Unmarshal(a, &j); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &j2); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return reflect.DeepEqual(j2, j), nil
|
||||
}
|
||||
|
||||
func TestGetIndex(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want *map[string][]string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := GetIndex(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetIndex() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitializeIndex(t *testing.T) {
|
||||
type args struct {
|
||||
intervalMinutes uint32
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
Initialize(tt.args.intervalMinutes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_indexingScheduler(t *testing.T) {
|
||||
type args struct {
|
||||
intervalMinutes uint32
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
indexingScheduler(tt.args.intervalMinutes)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_indexFiles(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
numFiles *int
|
||||
numDirs *int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int
|
||||
want1 int
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, got1, err := indexFiles(tt.args.path, tt.args.numFiles, tt.args.numDirs)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("indexFiles() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("indexFiles() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
if got1 != tt.want1 {
|
||||
t.Errorf("indexFiles() got1 = %v, want %v", got1, tt.want1)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_addToIndex(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
fileName string
|
||||
isDir bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
addToIndex(tt.args.path, tt.args.fileName, tt.args.isDir)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
sessionInProgress sync.Map
|
||||
mutex sync.RWMutex
|
||||
maxSearchResults = 100
|
||||
bytesInMegabyte int64 = 1000000
|
||||
)
|
||||
|
||||
func (si *Index) Search(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
|
||||
if scope == "" {
|
||||
scope = "/"
|
||||
}
|
||||
runningHash := generateRandomHash(4)
|
||||
sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
|
||||
searchOptions := ParseSearch(search)
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
fileListTypes := make(map[string]map[string]bool)
|
||||
matching := []string{}
|
||||
for _, searchTerm := range searchOptions.Terms {
|
||||
if searchTerm == "" {
|
||||
continue
|
||||
}
|
||||
// Iterate over the embedded index.Index fields Dirs and Files
|
||||
for _, i := range []string{"Dirs", "Files"} {
|
||||
isDir := false
|
||||
count := 0
|
||||
var paths []string
|
||||
|
||||
switch i {
|
||||
case "Dirs":
|
||||
isDir = true
|
||||
paths = si.Dirs
|
||||
case "Files":
|
||||
paths = si.Files
|
||||
}
|
||||
for _, path := range paths {
|
||||
value, found := sessionInProgress.Load(sourceSession)
|
||||
if !found || value != runningHash {
|
||||
return []string{}, map[string]map[string]bool{}
|
||||
}
|
||||
if count > maxSearchResults {
|
||||
break
|
||||
}
|
||||
pathName := scopedPathNameFilter(path, scope, isDir)
|
||||
if pathName == "" {
|
||||
continue
|
||||
}
|
||||
fileTypes := map[string]bool{}
|
||||
matches, fileType := containsSearchTerm(path, searchTerm, *searchOptions, isDir, fileTypes)
|
||||
if !matches {
|
||||
continue
|
||||
}
|
||||
fileListTypes[pathName] = fileType
|
||||
matching = append(matching, pathName)
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort the strings based on the number of elements after splitting by "/"
|
||||
sort.Slice(matching, func(i, j int) bool {
|
||||
parts1 := strings.Split(matching[i], "/")
|
||||
parts2 := strings.Split(matching[j], "/")
|
||||
return len(parts1) < len(parts2)
|
||||
})
|
||||
return matching, fileListTypes
|
||||
}
|
||||
|
||||
func scopedPathNameFilter(pathName string, scope string, isDir bool) string {
|
||||
scope = strings.TrimPrefix(scope, "/")
|
||||
pathName = strings.TrimPrefix(pathName, "/")
|
||||
pathName = strings.TrimSuffix(pathName, "/")
|
||||
if strings.HasPrefix(pathName, scope) {
|
||||
pathName = strings.TrimPrefix(pathName, scope)
|
||||
if isDir {
|
||||
pathName = pathName + "/"
|
||||
}
|
||||
} else {
|
||||
pathName = "" // return not matched
|
||||
}
|
||||
return pathName
|
||||
}
|
||||
|
||||
func containsSearchTerm(pathName string, searchTerm string, options SearchOptions, isDir bool, fileTypes map[string]bool) (bool, map[string]bool) {
|
||||
conditions := options.Conditions
|
||||
path := getLastPathComponent(pathName)
|
||||
// Convert to lowercase once
|
||||
if !conditions["exact"] {
|
||||
path = strings.ToLower(path)
|
||||
searchTerm = strings.ToLower(searchTerm)
|
||||
}
|
||||
if strings.Contains(path, searchTerm) {
|
||||
// Calculate fileSize only if needed
|
||||
var fileSize int64
|
||||
matchesAllConditions := true
|
||||
extension := filepath.Ext(path)
|
||||
for _, k := range AllFiletypeOptions {
|
||||
if IsMatchingType(extension, k) {
|
||||
fileTypes[k] = true
|
||||
}
|
||||
}
|
||||
fileTypes["dir"] = isDir
|
||||
for t, v := range conditions {
|
||||
if t == "exact" {
|
||||
continue
|
||||
}
|
||||
var matchesCondition bool
|
||||
switch t {
|
||||
case "larger":
|
||||
if fileSize == 0 {
|
||||
fileSize = getFileSize(pathName)
|
||||
}
|
||||
matchesCondition = fileSize > int64(options.LargerThan)*bytesInMegabyte
|
||||
case "smaller":
|
||||
if fileSize == 0 {
|
||||
fileSize = getFileSize(pathName)
|
||||
}
|
||||
matchesCondition = fileSize < int64(options.SmallerThan)*bytesInMegabyte
|
||||
default:
|
||||
matchesCondition = v == fileTypes[t]
|
||||
}
|
||||
if !matchesCondition {
|
||||
matchesAllConditions = false
|
||||
}
|
||||
}
|
||||
return matchesAllConditions, fileTypes
|
||||
}
|
||||
// Clear variables and return
|
||||
return false, map[string]bool{}
|
||||
}
|
||||
|
||||
func getFileSize(filepath string) int64 {
|
||||
fileInfo, err := os.Stat(rootPath + "/" + filepath)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return fileInfo.Size()
|
||||
}
|
||||
|
||||
func getLastPathComponent(path string) string {
|
||||
// Use filepath.Base to extract the last component of the path
|
||||
return filepath.Base(path)
|
||||
}
|
||||
|
||||
func generateRandomHash(length int) string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
result := make([]byte, length)
|
||||
for i := range result {
|
||||
result[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
package index
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func BenchmarkSearchAllIndexes(b *testing.B) {
|
||||
indexes = Index{
|
||||
Dirs: []string{},
|
||||
Files: []string{},
|
||||
}
|
||||
// Create mock data
|
||||
createMockData(50, 3) // 1000 dirs, 3 files per dir
|
||||
|
||||
// Generate 100 random search terms
|
||||
searchTerms := generateRandomSearchTerms(100)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Execute the SearchAllIndexes function
|
||||
for _, term := range searchTerms {
|
||||
indexes.Search(term, "/", "test")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over test files and compare output
|
||||
func TestParseSearch(t *testing.T) {
|
||||
value := ParseSearch("my test search")
|
||||
want := &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
},
|
||||
Terms: []string{"my test search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("case:exact my|test|search")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": true,
|
||||
},
|
||||
Terms: []string{"my", "test", "search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:largerThan=100 type:smallerThan=1000 test")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"larger": true,
|
||||
},
|
||||
Terms: []string{"test"},
|
||||
LargerThan: 100,
|
||||
SmallerThan: 1000,
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:audio thisfile")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"audio": true,
|
||||
},
|
||||
Terms: []string{"thisfile"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchIndexes(t *testing.T) {
|
||||
indexes = Index{
|
||||
Dirs: []string{
|
||||
"/test",
|
||||
"/test/path",
|
||||
"/new/test/path",
|
||||
},
|
||||
Files: []string{
|
||||
"/test/path/file.txt",
|
||||
"/test/audio1.wav",
|
||||
"/new/test/audio.wav",
|
||||
"/new/test/video.mp4",
|
||||
"/new/test/video.MP4",
|
||||
"/new/test/path/archive.zip",
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
search string
|
||||
scope string
|
||||
expectedResult []string
|
||||
expectedTypes map[string]map[string]bool
|
||||
}{
|
||||
{
|
||||
search: "audio",
|
||||
scope: "/new/",
|
||||
expectedResult: []string{"test/audio.wav"},
|
||||
expectedTypes: map[string]map[string]bool{
|
||||
"test/audio.wav": map[string]bool{"audio": true, "dir": false},
|
||||
},
|
||||
},
|
||||
{
|
||||
search: "test",
|
||||
scope: "/",
|
||||
expectedResult: []string{"test/"},
|
||||
expectedTypes: map[string]map[string]bool{
|
||||
"test/": map[string]bool{"dir": true},
|
||||
},
|
||||
},
|
||||
{
|
||||
search: "archive",
|
||||
scope: "/",
|
||||
expectedResult: []string{"new/test/path/archive.zip"},
|
||||
expectedTypes: map[string]map[string]bool{
|
||||
"new/test/path/archive.zip": map[string]bool{"archive": true, "dir": false},
|
||||
},
|
||||
},
|
||||
{
|
||||
search: "video",
|
||||
scope: "/",
|
||||
expectedResult: []string{
|
||||
"new/test/video.mp4",
|
||||
"new/test/video.MP4",
|
||||
},
|
||||
expectedTypes: map[string]map[string]bool{
|
||||
"new/test/video.MP4": map[string]bool{"video": true, "dir": false},
|
||||
"new/test/video.mp4": map[string]bool{"video": true, "dir": false},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.search, func(t *testing.T) {
|
||||
actualResult, actualTypes := indexes.Search(tt.search, tt.scope, "")
|
||||
assert.Equal(t, tt.expectedResult, actualResult)
|
||||
if len(tt.expectedTypes) > 0 {
|
||||
for key, value := range tt.expectedTypes {
|
||||
actualValue, exists := actualTypes[key]
|
||||
assert.True(t, exists, "Expected type key '%s' not found in actual types", key)
|
||||
assert.Equal(t, value, actualValue, "Type value mismatch for key '%s'", key)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_isDoc(t *testing.T) {
|
||||
type args struct {
|
||||
extension string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := isDoc(tt.args.extension); got != tt.want {
|
||||
t.Errorf("isDoc() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getFileSize(t *testing.T) {
|
||||
type args struct {
|
||||
filepath string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int64
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getFileSize(tt.args.filepath); got != tt.want {
|
||||
t.Errorf("getFileSize() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_isArchive(t *testing.T) {
|
||||
type args struct {
|
||||
extension string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := isArchive(tt.args.extension); got != tt.want {
|
||||
t.Errorf("isArchive() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_getLastPathComponent(t *testing.T) {
|
||||
type args struct {
|
||||
path string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := getLastPathComponent(tt.args.path); got != tt.want {
|
||||
t.Errorf("getLastPathComponent() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_generateRandomHash(t *testing.T) {
|
||||
type args struct {
|
||||
length int
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := generateRandomHash(tt.args.length); got != tt.want {
|
||||
t.Errorf("generateRandomHash() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,5 +5,5 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
cmd.StartFilebrowser()
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/bin/sh
|
||||
## TEST file used by docker testing containers
|
||||
touch render.yml
|
||||
checkExit() {
|
||||
if [ "$?" -ne 0 ];then
|
||||
exit 1
|
||||
@@ -10,7 +9,7 @@ checkExit() {
|
||||
if command -v go &> /dev/null
|
||||
then
|
||||
printf "\n == Running benchmark == \n"
|
||||
go test -bench=. -benchmem ./...
|
||||
go test -bench=. -benchtime=10x -benchmem ./...
|
||||
checkExit
|
||||
else
|
||||
echo "ERROR: unable to perform tests"
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/bin/sh
|
||||
## TEST file used by docker testing containers
|
||||
touch render.yml
|
||||
checkExit() {
|
||||
if [ "$?" -ne 0 ];then
|
||||
exit 1
|
||||
|
||||
@@ -1,279 +0,0 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math/rand"
|
||||
"mime"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
sessionInProgress sync.Map // Track session with requests in progress
|
||||
rootPath string = "/srv"
|
||||
indexes map[string][]string
|
||||
mutex sync.RWMutex
|
||||
lastIndexed time.Time
|
||||
)
|
||||
|
||||
func InitializeIndex(intervalMinutes uint32) {
|
||||
// Initialize the indexes map
|
||||
indexes = make(map[string][]string)
|
||||
indexes["dirs"] = []string{}
|
||||
indexes["files"] = []string{}
|
||||
var numFiles, numDirs int
|
||||
log.Println("Indexing files...")
|
||||
lastIndexedStart := time.Now()
|
||||
// Call the function to index files and directories
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
go indexingScheduler(intervalMinutes)
|
||||
log.Println("Successfully indexed files.")
|
||||
log.Println("Files found :", totalNumFiles)
|
||||
log.Println("Directories found :", totalNumDirs)
|
||||
}
|
||||
|
||||
func indexingScheduler(intervalMinutes uint32) {
|
||||
log.Printf("Indexing scheduler will run every %v minutes", intervalMinutes)
|
||||
for {
|
||||
time.Sleep(time.Duration(intervalMinutes) * time.Minute)
|
||||
var numFiles, numDirs int
|
||||
lastIndexedStart := time.Now()
|
||||
totalNumFiles, totalNumDirs, err := indexFiles(rootPath, &numFiles, &numDirs)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
lastIndexed = lastIndexedStart
|
||||
if totalNumFiles+totalNumDirs > 0 {
|
||||
log.Println("re-indexing found changes and updated the index.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Define a function to recursively index files and directories
|
||||
func indexFiles(path string, numFiles *int, numDirs *int) (int, int, error) {
|
||||
// Check if the current directory has been modified since last indexing
|
||||
dir, err := os.Open(path)
|
||||
if err != nil {
|
||||
// directory must have been deleted, remove from index
|
||||
delete(indexes, path)
|
||||
}
|
||||
defer dir.Close()
|
||||
dirInfo, err := dir.Stat()
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Compare the last modified time of the directory with the last indexed time
|
||||
if dirInfo.ModTime().Before(lastIndexed) {
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
// Read the directory contents
|
||||
files, err := dir.Readdir(-1)
|
||||
if err != nil {
|
||||
return *numFiles, *numDirs, err
|
||||
}
|
||||
// Iterate over the files and directories
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
*numDirs++
|
||||
addToIndex(path, file.Name(), true)
|
||||
indexFiles(path+"/"+file.Name(), numFiles, numDirs) // recursive
|
||||
} else {
|
||||
*numFiles++
|
||||
addToIndex(path, file.Name(), false)
|
||||
}
|
||||
}
|
||||
return *numFiles, *numDirs, nil
|
||||
}
|
||||
|
||||
func addToIndex(path string, fileName string, isDir bool) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
path = strings.TrimPrefix(path, rootPath+"/")
|
||||
path = strings.TrimSuffix(path, "/")
|
||||
adjustedPath := path + "/" + fileName
|
||||
if path == rootPath {
|
||||
adjustedPath = fileName
|
||||
}
|
||||
if isDir {
|
||||
indexes["dirs"] = append(indexes["dirs"], adjustedPath)
|
||||
} else {
|
||||
indexes["files"] = append(indexes["files"], adjustedPath)
|
||||
}
|
||||
}
|
||||
|
||||
func SearchAllIndexes(search string, scope string, sourceSession string) ([]string, map[string]map[string]bool) {
|
||||
runningHash := generateRandomHash(4)
|
||||
sessionInProgress.Store(sourceSession, runningHash) // Store the value in the sync.Map
|
||||
|
||||
searchOptions := ParseSearch(search)
|
||||
mutex.RLock()
|
||||
defer mutex.RUnlock()
|
||||
fileListTypes := make(map[string]map[string]bool)
|
||||
var matching []string
|
||||
maximum := 100
|
||||
|
||||
for _, searchTerm := range searchOptions.Terms {
|
||||
if searchTerm == "" {
|
||||
continue
|
||||
}
|
||||
// Iterate over the indexes
|
||||
for _, i := range []string{"dirs", "files"} {
|
||||
isdir := i == "dirs"
|
||||
count := 0
|
||||
for _, path := range indexes[i] {
|
||||
value, found := sessionInProgress.Load(sourceSession)
|
||||
if !found || value != runningHash {
|
||||
return []string{}, map[string]map[string]bool{}
|
||||
}
|
||||
if count > maximum {
|
||||
break
|
||||
}
|
||||
pathName := scopedPathNameFilter(path, scope)
|
||||
if pathName == "" {
|
||||
continue
|
||||
}
|
||||
matches, fileType := containsSearchTerm(path, searchTerm, *searchOptions, isdir)
|
||||
if !matches {
|
||||
continue
|
||||
}
|
||||
if isdir {
|
||||
pathName = pathName + "/"
|
||||
}
|
||||
matching = append(matching, pathName)
|
||||
fileListTypes[pathName] = fileType
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort the strings based on the number of elements after splitting by "/"
|
||||
sort.Slice(matching, func(i, j int) bool {
|
||||
parts1 := strings.Split(matching[i], "/")
|
||||
parts2 := strings.Split(matching[j], "/")
|
||||
return len(parts1) < len(parts2)
|
||||
})
|
||||
return matching, fileListTypes
|
||||
}
|
||||
|
||||
func scopedPathNameFilter(pathName string, scope string) string {
|
||||
scope = strings.TrimPrefix(scope, "/")
|
||||
if strings.HasPrefix(pathName, scope) {
|
||||
pathName = strings.TrimPrefix(pathName, scope)
|
||||
} else {
|
||||
pathName = ""
|
||||
}
|
||||
return pathName
|
||||
}
|
||||
|
||||
func containsSearchTerm(pathName string, searchTerm string, options SearchOptions, isDir bool) (bool, map[string]bool) {
|
||||
conditions := options.Conditions
|
||||
path := getLastPathComponent(pathName)
|
||||
// Convert to lowercase once
|
||||
lowerSearchTerm := searchTerm
|
||||
if !conditions["exact"] {
|
||||
path = strings.ToLower(path)
|
||||
lowerSearchTerm = strings.ToLower(searchTerm)
|
||||
}
|
||||
if strings.Contains(path, lowerSearchTerm) {
|
||||
// Reuse the fileTypes map and clear its values
|
||||
fileTypes := map[string]bool{
|
||||
"audio": false,
|
||||
"image": false,
|
||||
"video": false,
|
||||
"doc": false,
|
||||
"archive": false,
|
||||
"dir": false,
|
||||
}
|
||||
// Calculate fileSize only if needed
|
||||
var fileSize int64
|
||||
if conditions["larger"] || conditions["smaller"] {
|
||||
fileSize = getFileSize(pathName)
|
||||
}
|
||||
matchesAllConditions := true
|
||||
extension := filepath.Ext(path)
|
||||
mimetype := mime.TypeByExtension(extension)
|
||||
fileTypes["audio"] = strings.HasPrefix(mimetype, "audio")
|
||||
fileTypes["image"] = strings.HasPrefix(mimetype, "image")
|
||||
fileTypes["video"] = strings.HasPrefix(mimetype, "video")
|
||||
fileTypes["doc"] = isDoc(extension)
|
||||
fileTypes["archive"] = isArchive(extension)
|
||||
fileTypes["dir"] = isDir
|
||||
for t, v := range conditions {
|
||||
if t == "exact" {
|
||||
continue
|
||||
}
|
||||
var matchesCondition bool
|
||||
switch t {
|
||||
case "larger":
|
||||
matchesCondition = fileSize > int64(options.LargerThan)*1000000
|
||||
case "smaller":
|
||||
matchesCondition = fileSize < int64(options.SmallerThan)*1000000
|
||||
default:
|
||||
matchesCondition = v == fileTypes[t]
|
||||
}
|
||||
if !matchesCondition {
|
||||
matchesAllConditions = false
|
||||
}
|
||||
}
|
||||
return matchesAllConditions, fileTypes
|
||||
}
|
||||
// Clear variables and return
|
||||
return false, map[string]bool{}
|
||||
}
|
||||
|
||||
func isDoc(extension string) bool {
|
||||
for _, typefile := range documentTypes {
|
||||
if extension == typefile {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getFileSize(filepath string) int64 {
|
||||
fileInfo, err := os.Stat(rootPath + "/" + filepath)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return fileInfo.Size()
|
||||
}
|
||||
|
||||
func isArchive(extension string) bool {
|
||||
for _, typefile := range compressedFile {
|
||||
if extension == typefile {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func getLastPathComponent(path string) string {
|
||||
// Use filepath.Base to extract the last component of the path
|
||||
return filepath.Base(path)
|
||||
}
|
||||
|
||||
func generateRandomHash(length int) string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||
rand.Seed(rand.Int63()) // Automatically seeded based on current time
|
||||
result := make([]byte, length)
|
||||
for i := range result {
|
||||
result[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func stringExistsInArray(target string, strings []string) bool {
|
||||
for _, s := range strings {
|
||||
if s == target {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// loop over test files and compare output
|
||||
func TestParseSearch(t *testing.T) {
|
||||
value := ParseSearch("my test search")
|
||||
want := &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
},
|
||||
Terms: []string{"my test search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("case:exact my|test|search")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": true,
|
||||
},
|
||||
Terms: []string{"my", "test", "search"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:largerThan=100 type:smallerThan=1000 test")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"larger": true,
|
||||
},
|
||||
Terms: []string{"test"},
|
||||
LargerThan: 100,
|
||||
SmallerThan: 1000,
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
value = ParseSearch("type:audio thisfile")
|
||||
want = &SearchOptions{
|
||||
Conditions: map[string]bool{
|
||||
"exact": false,
|
||||
"audio": true,
|
||||
},
|
||||
Terms: []string{"thisfile"},
|
||||
}
|
||||
if !reflect.DeepEqual(value, want) {
|
||||
t.Fatalf("\n got: %+v\n want: %+v", value, want)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSearchAllIndexes(b *testing.B) {
|
||||
indexes = make(map[string][]string)
|
||||
|
||||
// Create mock data
|
||||
createMockData(500, 3) // 1000 dirs, 3 files per dir
|
||||
|
||||
// Generate 100 random search terms
|
||||
searchTerms := generateRandomSearchTerms(100)
|
||||
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Execute the SearchAllIndexes function
|
||||
for _, term := range searchTerms {
|
||||
SearchAllIndexes(term, "/")
|
||||
}
|
||||
}
|
||||
printBenchmarkResults(b)
|
||||
}
|
||||
|
||||
func BenchmarkFillIndex(b *testing.B) {
|
||||
indexes = make(map[string][]string)
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
createMockData(10000, 10) // 1000 dirs, 3 files per dir
|
||||
}
|
||||
printBenchmarkResults(b)
|
||||
}
|
||||
|
||||
func createMockData(numDirs, numFilesPerDir int) {
|
||||
for i := 0; i < numDirs; i++ {
|
||||
dirName := "srv/" + getRandomTerm()
|
||||
addToIndex("/", dirName, true)
|
||||
for j := 0; j < numFilesPerDir; j++ {
|
||||
fileName := "file-" + getRandomTerm() + getRandomExtension()
|
||||
addToIndex("/"+dirName, fileName, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getRandomTerm() string {
|
||||
wordbank := []string{
|
||||
"hi", "test", "other", "name",
|
||||
"cool", "things", "more", "items",
|
||||
}
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func getRandomExtension() string {
|
||||
wordbank := []string{
|
||||
".txt", ".mp3", ".mov", ".doc",
|
||||
".mp4", ".bak", ".zip", ".jpg",
|
||||
}
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
index := rand.Intn(len(wordbank))
|
||||
return wordbank[index]
|
||||
}
|
||||
|
||||
func generateRandomSearchTerms(numTerms int) []string {
|
||||
// Generate random search terms
|
||||
searchTerms := make([]string, numTerms)
|
||||
for i := 0; i < numTerms; i++ {
|
||||
searchTerms[i] = getRandomTerm()
|
||||
}
|
||||
return searchTerms
|
||||
}
|
||||
|
||||
// JSONBytesEqual compares the JSON in two byte slices.
|
||||
func JSONBytesEqual(a, b []byte) (bool, error) {
|
||||
var j, j2 interface{}
|
||||
if err := json.Unmarshal(a, &j); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := json.Unmarshal(b, &j2); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return reflect.DeepEqual(j2, j), nil
|
||||
}
|
||||
|
||||
func passedFunc(t *testing.T) {
|
||||
t.Logf("%s passed!", t.Name())
|
||||
}
|
||||
|
||||
func formatDuration(duration time.Duration) string {
|
||||
if duration >= time.Second {
|
||||
return fmt.Sprintf("%.2f seconds", duration.Seconds())
|
||||
} else if duration >= time.Millisecond {
|
||||
return fmt.Sprintf("%.2f ms", float64(duration.Milliseconds()))
|
||||
}
|
||||
return fmt.Sprintf("%.2f ns", float64(duration.Nanoseconds()))
|
||||
}
|
||||
|
||||
func formatMemory(bytes int64) string {
|
||||
sizes := []string{"B", "KB", "MB", "GB", "TB"}
|
||||
i := 0
|
||||
for bytes >= 1024 && i < len(sizes)-1 {
|
||||
bytes /= 1024
|
||||
i++
|
||||
}
|
||||
return fmt.Sprintf("%d %s", bytes, sizes[i])
|
||||
}
|
||||
|
||||
// Output the benchmark results with human-readable units
|
||||
func printBenchmarkResults(b *testing.B) {
|
||||
averageTimePerIteration := b.Elapsed() / time.Duration(b.N)
|
||||
fmt.Printf("\nIterations : %d\n", b.N)
|
||||
fmt.Printf("Total time : %s\n", formatDuration(b.Elapsed()))
|
||||
fmt.Printf("Avg time per op : %s\n", formatDuration(averageTimePerIteration))
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
var GlobalConfiguration Settings
|
||||
|
||||
func Initialize(configFile string) {
|
||||
yamlData := loadConfigFile(configFile)
|
||||
GlobalConfiguration = setDefaults()
|
||||
err := yaml.Unmarshal(yamlData, &GlobalConfiguration)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshaling YAML data: %v", err)
|
||||
}
|
||||
GlobalConfiguration.UserDefaults.Perm = GlobalConfiguration.UserDefaults.Permissions
|
||||
}
|
||||
|
||||
func loadConfigFile(configFile string) []byte {
|
||||
// Open and read the YAML file
|
||||
yamlFile, err := os.Open(configFile)
|
||||
if err != nil {
|
||||
log.Printf("ERROR: opening config file\n %v\n WARNING: Using default config only\n If this was a mistake, please make sure the file exists and is accessible by the filebrowser binary.\n\n", err)
|
||||
GlobalConfiguration = setDefaults()
|
||||
return []byte{}
|
||||
}
|
||||
defer yamlFile.Close()
|
||||
|
||||
stat, err := yamlFile.Stat()
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting file information: %s", err.Error())
|
||||
}
|
||||
|
||||
yamlData := make([]byte, stat.Size())
|
||||
_, err = yamlFile.Read(yamlData)
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading YAML data: %v", err)
|
||||
}
|
||||
return yamlData
|
||||
}
|
||||
|
||||
func setDefaults() Settings {
|
||||
return Settings{
|
||||
Server: Server{
|
||||
EnableThumbnails: true,
|
||||
ResizePreview: false,
|
||||
EnableExec: false,
|
||||
IndexingInterval: 5,
|
||||
Port: 8080,
|
||||
NumImageProcessors: 4,
|
||||
BaseURL: "",
|
||||
Database: "database.db",
|
||||
Log: "stdout",
|
||||
Root: "/srv",
|
||||
},
|
||||
Auth: Auth{
|
||||
AdminUsername: "admin",
|
||||
AdminPassword: "admin",
|
||||
Method: "password",
|
||||
Signup: false,
|
||||
Recaptcha: Recaptcha{
|
||||
Host: "",
|
||||
},
|
||||
},
|
||||
UserDefaults: UserDefaults{
|
||||
Scope: ".",
|
||||
LockPassword: false,
|
||||
HideDotfiles: true,
|
||||
DarkMode: false,
|
||||
DisableSettings: false,
|
||||
Locale: "en",
|
||||
Permissions: users.Permissions{
|
||||
Create: false,
|
||||
Rename: false,
|
||||
Modify: false,
|
||||
Delete: false,
|
||||
Share: false,
|
||||
Download: false,
|
||||
Admin: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Apply applies the default options to a user.
|
||||
func (d *UserDefaults) Apply(u *users.User) {
|
||||
u.DisableSettings = d.DisableSettings
|
||||
u.DarkMode = d.DarkMode
|
||||
u.Scope = d.Scope
|
||||
u.Locale = d.Locale
|
||||
u.ViewMode = d.ViewMode
|
||||
u.SingleClick = d.SingleClick
|
||||
u.Perm = d.Perm
|
||||
u.Sorting = d.Sorting
|
||||
u.Commands = d.Commands
|
||||
u.HideDotfiles = d.HideDotfiles
|
||||
u.DateFormat = d.DateFormat
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
type args struct {
|
||||
configFile string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
Initialize(tt.args.configFile)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_loadConfigFile(t *testing.T) {
|
||||
type args struct {
|
||||
configFile string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []byte
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := loadConfigFile(tt.args.configFile); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("loadConfigFile() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_setDefaults(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
want Settings
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := setDefaults(); !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("setDefaults() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,13 @@ var (
|
||||
// MakeUserDir makes the user directory according to settings.
|
||||
func (s *Settings) MakeUserDir(username, userScope, serverRoot string) (string, error) {
|
||||
userScope = strings.TrimSpace(userScope)
|
||||
if userScope == "" && s.CreateUserDir {
|
||||
if userScope == "" && s.Server.CreateUserDir {
|
||||
username = cleanUsername(username)
|
||||
if username == "" || username == "-" || username == "." {
|
||||
log.Printf("create user: invalid user for home dir creation: [%s]", username)
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/rules"
|
||||
)
|
||||
|
||||
func TestSettings_MakeUserDir(t *testing.T) {
|
||||
type fields struct {
|
||||
Signup bool
|
||||
CreateUserDir bool
|
||||
UserHomeBasePath string
|
||||
Commands map[string][]string
|
||||
Shell []string
|
||||
AdminUsername string
|
||||
AdminPassword string
|
||||
Rules []rules.Rule
|
||||
Server Server
|
||||
Auth Auth
|
||||
Frontend Frontend
|
||||
Users []UserDefaults
|
||||
UserDefaults UserDefaults
|
||||
}
|
||||
type args struct {
|
||||
username string
|
||||
userScope string
|
||||
serverRoot string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
args args
|
||||
want string
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
s := &Settings{
|
||||
Commands: tt.fields.Commands,
|
||||
Shell: tt.fields.Shell,
|
||||
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)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("Settings.MakeUserDir() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if got != tt.want {
|
||||
t.Errorf("Settings.MakeUserDir() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_cleanUsername(t *testing.T) {
|
||||
type args struct {
|
||||
s string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := cleanUsername(tt.args.s); got != tt.want {
|
||||
t.Errorf("cleanUsername() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -35,3 +35,7 @@ func GenerateKey() ([]byte, error) {
|
||||
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func GetSettingsConfig(nameType string, Value string) string {
|
||||
return nameType + Value
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/goccy/go-yaml"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestConfigLoadChanged(t *testing.T) {
|
||||
yamlData := loadConfigFile("./testingConfig.yaml")
|
||||
// Marshal the YAML data to a more human-readable format
|
||||
newConfig := setDefaults()
|
||||
GlobalConfiguration := setDefaults()
|
||||
|
||||
err := yaml.Unmarshal(yamlData, &newConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshaling YAML data: %v", err)
|
||||
}
|
||||
// Use go-cmp to compare the two structs
|
||||
if diff := cmp.Diff(newConfig, GlobalConfiguration); diff == "" {
|
||||
t.Errorf("No change when there should have been (-want +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigLoadSpecificValues(t *testing.T) {
|
||||
yamlData := loadConfigFile("./testingConfig.yaml")
|
||||
// Marshal the YAML data to a more human-readable format
|
||||
newConfig := setDefaults()
|
||||
GlobalConfiguration := setDefaults()
|
||||
|
||||
err := yaml.Unmarshal(yamlData, &newConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("Error unmarshaling YAML data: %v", err)
|
||||
}
|
||||
testCases := []struct {
|
||||
fieldName string
|
||||
globalVal interface{}
|
||||
newVal interface{}
|
||||
}{
|
||||
{"Auth.Method", GlobalConfiguration.Auth.Method, newConfig.Auth.Method},
|
||||
{"Auth.Method", GlobalConfiguration.Auth.Method, newConfig.Auth.Method},
|
||||
{"Frontend.disableExternal", GlobalConfiguration.Frontend.DisableExternal, newConfig.Frontend.DisableExternal},
|
||||
{"UserDefaults.HideDotfiles", GlobalConfiguration.UserDefaults.HideDotfiles, newConfig.UserDefaults.HideDotfiles},
|
||||
{"Server.Database", GlobalConfiguration.Server.Database, newConfig.Server.Database},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
if tc.globalVal == tc.newVal {
|
||||
t.Errorf("Differences should have been found:\n\tGlobalConfig.%s: %v \n\tSetConfig: %v \n", tc.fieldName, tc.globalVal, tc.newVal)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package settings
|
||||
import (
|
||||
"github.com/gtsteffaniak/filebrowser/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/rules"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
// StorageBackend is a settings storage backend.
|
||||
@@ -30,8 +29,8 @@ func (s *Storage) Get() (*Settings, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if set.UserHomeBasePath == "" {
|
||||
set.UserHomeBasePath = DefaultUsersHomeBasePath
|
||||
if set.Server.UserHomeBasePath == "" {
|
||||
set.Server.UserHomeBasePath = DefaultUsersHomeBasePath
|
||||
}
|
||||
return set, nil
|
||||
}
|
||||
@@ -46,20 +45,20 @@ var defaultEvents = []string{
|
||||
|
||||
// Save saves the settings for the current instance.
|
||||
func (s *Storage) Save(set *Settings) error {
|
||||
if len(set.Key) == 0 {
|
||||
if len(set.Auth.Key) == 0 {
|
||||
return errors.ErrEmptyKey
|
||||
}
|
||||
|
||||
if set.Defaults.Locale == "" {
|
||||
set.Defaults.Locale = "en"
|
||||
if set.UserDefaults.Locale == "" {
|
||||
set.UserDefaults.Locale = "en"
|
||||
}
|
||||
|
||||
if set.Defaults.Commands == nil {
|
||||
set.Defaults.Commands = []string{}
|
||||
if set.UserDefaults.Commands == nil {
|
||||
set.UserDefaults.Commands = []string{}
|
||||
}
|
||||
|
||||
if set.Defaults.ViewMode == "" {
|
||||
set.Defaults.ViewMode = users.MosaicViewMode
|
||||
if set.UserDefaults.ViewMode == "" {
|
||||
set.UserDefaults.ViewMode = "normal"
|
||||
}
|
||||
|
||||
if set.Rules == nil {
|
||||
|
||||
@@ -1,49 +1,42 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"github.com/gtsteffaniak/filebrowser/files"
|
||||
"github.com/gtsteffaniak/filebrowser/rules"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
// Apply applies the default options to a user.
|
||||
func (d *UserDefaults) Apply(u *users.User) {
|
||||
u.Scope = d.Scope
|
||||
u.Locale = d.Locale
|
||||
u.ViewMode = d.ViewMode
|
||||
u.SingleClick = d.SingleClick
|
||||
u.Perm = d.Perm
|
||||
u.Sorting = d.Sorting
|
||||
u.Commands = d.Commands
|
||||
u.HideDotfiles = d.HideDotfiles
|
||||
u.DateFormat = d.DateFormat
|
||||
type Settings struct {
|
||||
Commands map[string][]string `json:"commands"`
|
||||
Shell []string `json:"shell"`
|
||||
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 Settings struct {
|
||||
Key []byte `json:"key"`
|
||||
Signup bool `json:"signup"`
|
||||
CreateUserDir bool `json:"createUserDir"`
|
||||
UserHomeBasePath string `json:"userHomeBasePath"`
|
||||
Defaults UserDefaults `json:"defaults"`
|
||||
Commands map[string][]string `json:"commands"`
|
||||
Shell []string `json:"shell"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
Server Server `json:"server"`
|
||||
AuthMethod string `json:"authMethod"`
|
||||
Auth struct {
|
||||
Header string `json:"header"`
|
||||
Method string `json:"method"`
|
||||
Command string `json:"command"`
|
||||
Signup bool `json:"signup"`
|
||||
Shell string `json:"shell"`
|
||||
} `json:"auth"`
|
||||
type Auth struct {
|
||||
Recaptcha Recaptcha `json:"recaptcha"`
|
||||
Header string `json:"header"`
|
||||
Method string `json:"method"`
|
||||
Command string `json:"command"`
|
||||
Signup bool `json:"signup"`
|
||||
Shell string `json:"shell"`
|
||||
AdminUsername string `json:"adminUsername"`
|
||||
AdminPassword string `json:"adminPassword"`
|
||||
Key []byte `json:"key"`
|
||||
}
|
||||
|
||||
Branding Branding `json:"branding"`
|
||||
|
||||
UserDefaults UserDefaults `json:"userDefaults"`
|
||||
type Recaptcha struct {
|
||||
Host string `json:"host"`
|
||||
Key string `json:"key"`
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
IndexingInterval uint32 `json:"indexingInterval"`
|
||||
NumImageProcessors int `json:"numImageProcessors"`
|
||||
Socket string `json:"socket"`
|
||||
TLSKey string `json:"tlsKey"`
|
||||
TLSCert string `json:"tlsCert"`
|
||||
@@ -52,76 +45,42 @@ type Server struct {
|
||||
EnableExec bool `json:"enableExec"`
|
||||
TypeDetectionByHeader bool `json:"typeDetectionByHeader"`
|
||||
AuthHook string `json:"authHook"`
|
||||
Port string `json:"port"`
|
||||
Port int `json:"port"`
|
||||
BaseURL string `json:"baseURL"`
|
||||
Address string `json:"address"`
|
||||
Log string `json:"log"`
|
||||
Database string `json:"database"`
|
||||
Root string `json:"root"`
|
||||
EnablePreviewResize bool `json:"disable-preview-resize"`
|
||||
UserHomeBasePath string `json:"userHomeBasePath"`
|
||||
CreateUserDir bool `json:"createUserDir"`
|
||||
}
|
||||
|
||||
type Branding struct {
|
||||
type Frontend struct {
|
||||
Name string `json:"name"`
|
||||
DisableExternal bool `json:"disableExternal"`
|
||||
DisableUsedPercentage bool `json:"disableUsedPercentage"`
|
||||
Files string `json:"files"`
|
||||
Theme string `json:"theme"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
// UserDefaults is a type that holds the default values
|
||||
// for some fields on User.
|
||||
type UserDefaults struct {
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode users.ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
DarkMode bool `json:"darkMode"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
DisableSettings bool `json:"disableSettings,omitempty"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
ViewMode string `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
Sorting struct {
|
||||
By string `json:"by"`
|
||||
Asc bool `json:"asc"`
|
||||
} `json:"sorting"`
|
||||
Perm users.Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
Permissions users.Permissions `json:"permissions"`
|
||||
Commands []string `json:"commands,omitempty"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
}
|
||||
|
||||
//{
|
||||
// "server":{
|
||||
// "port":8080,
|
||||
// "baseURL":"",
|
||||
// "address":"",
|
||||
// "log":"stdout",
|
||||
// "database":"./database.db",
|
||||
// "root":"/srv",
|
||||
// "disable-thumbnails":false,
|
||||
// "disable-preview-resize":false,
|
||||
// "disable-exec":false,
|
||||
// "disable-type-detection-by-header":false
|
||||
// },
|
||||
// "auth":{
|
||||
// "header":"",
|
||||
// "method":"",
|
||||
// "command":"",
|
||||
// "signup":false,
|
||||
// "shell":""
|
||||
// },
|
||||
// "branding":{
|
||||
// "name":"",
|
||||
// "color":"",
|
||||
// "files":"",
|
||||
// "disableExternal":"",
|
||||
// "disableUsedPercentage":""
|
||||
// },
|
||||
// "permissions":{
|
||||
// "Admin":false,
|
||||
// "Execute":true,
|
||||
// "Create":true,
|
||||
// "Rename":true,
|
||||
// "Modify":true,
|
||||
// "Delete":true,
|
||||
// "Share":true,
|
||||
// "Download":true
|
||||
// },
|
||||
// "commands":{},
|
||||
// "shell":{},
|
||||
// "rules":{}
|
||||
// }
|
||||
@@ -0,0 +1,52 @@
|
||||
server:
|
||||
indexingInterval: 5
|
||||
numImageProcessors: 4
|
||||
socket: ""
|
||||
tlsKey: ""
|
||||
tlsCert: ""
|
||||
enableThumbnails: false
|
||||
resizePreview: true
|
||||
typeDetectionByHeader: true
|
||||
port: 8080
|
||||
baseURL: "/"
|
||||
address: ""
|
||||
log: "stdout"
|
||||
database: "mydb.db"
|
||||
root: "/srv"
|
||||
auth:
|
||||
recaptcha:
|
||||
host: ""
|
||||
key: ""
|
||||
secret: ""
|
||||
header: ""
|
||||
method: json
|
||||
command: ""
|
||||
signup: false
|
||||
shell: ""
|
||||
frontend:
|
||||
name: ""
|
||||
disableExternal: true
|
||||
disableUsedPercentage: true
|
||||
files: ""
|
||||
color: ""
|
||||
userDefaults:
|
||||
scope: ""
|
||||
locale: ""
|
||||
viewMode: ""
|
||||
darkMode: true
|
||||
disableSettings: false
|
||||
singleClick: true
|
||||
sorting:
|
||||
by: ""
|
||||
asc: true
|
||||
permissions:
|
||||
admin: true
|
||||
execute: true
|
||||
create: true
|
||||
rename: true
|
||||
modify: true
|
||||
delete: true
|
||||
share: true
|
||||
download: true
|
||||
hideDotfiles: false
|
||||
dateFormat: false
|
||||
@@ -2,7 +2,6 @@ package bolt
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/auth"
|
||||
"github.com/gtsteffaniak/filebrowser/errors"
|
||||
)
|
||||
@@ -13,20 +12,18 @@ type authBackend struct {
|
||||
|
||||
func (s authBackend) Get(t string) (auth.Auther, error) {
|
||||
var auther auth.Auther
|
||||
|
||||
switch t {
|
||||
case auth.MethodJSONAuth:
|
||||
case "password":
|
||||
auther = &auth.JSONAuth{}
|
||||
case auth.MethodProxyAuth:
|
||||
case "proxy":
|
||||
auther = &auth.ProxyAuth{}
|
||||
case auth.MethodHookAuth:
|
||||
case "hook":
|
||||
auther = &auth.HookAuth{}
|
||||
case auth.MethodNoAuth:
|
||||
case "noauth":
|
||||
auther = &auth.NoAuth{}
|
||||
default:
|
||||
return nil, errors.ErrInvalidAuthMethod
|
||||
}
|
||||
|
||||
return auther, get(s.db, "auther", auther)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package bolt
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
)
|
||||
|
||||
@@ -20,7 +19,10 @@ func (s settingsBackend) Save(set *settings.Settings) error {
|
||||
}
|
||||
|
||||
func (s settingsBackend) GetServer() (*settings.Server, error) {
|
||||
server := &settings.Server{}
|
||||
server := &settings.Server{
|
||||
Port: 8080,
|
||||
NumImageProcessors: 1,
|
||||
}
|
||||
return server, get(s.db, "server", server)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
"github.com/pelletier/go-toml/v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/auth"
|
||||
"github.com/gtsteffaniak/filebrowser/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/storage"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
type oldDefs struct {
|
||||
Commands []string `json:"commands" yaml:"commands" toml:"commands"`
|
||||
Scope string `json:"scope" yaml:"scope" toml:"scope"`
|
||||
ViewMode string `json:"viewMode" yaml:"viewMode" toml:"viewMode"`
|
||||
Locale string `json:"locale" yaml:"locale" toml:"locale"`
|
||||
AllowCommands bool `json:"allowCommands" yaml:"allowCommands" toml:"allowCommands"`
|
||||
AllowEdit bool `json:"allowEdit" yaml:"allowEdit" toml:"allowEdit"`
|
||||
AllowNew bool `json:"allowNew" yaml:"allowNew" toml:"allowNew"`
|
||||
}
|
||||
|
||||
type oldAuth struct {
|
||||
Method string `json:"method" yaml:"method" toml:"method"` // default none proxy
|
||||
Header string `json:"header" yaml:"header" toml:"header"`
|
||||
Command string `json:"command" yaml:"command" toml:"command"`
|
||||
}
|
||||
|
||||
type oldConf struct {
|
||||
Port string `json:"port" yaml:"port" toml:"port"`
|
||||
BaseURL string `json:"baseURL" yaml:"baseURL" toml:"baseURL"`
|
||||
Log string `json:"log" yaml:"log" toml:"log"`
|
||||
Address string `json:"address" yaml:"address" toml:"address"`
|
||||
Defaults oldDefs `json:"defaults" yaml:"defaults" toml:"defaults"`
|
||||
ReCaptcha struct {
|
||||
Key string `json:"key" yaml:"key" toml:"key"`
|
||||
Secret string `json:"secret" yaml:"secret" toml:"secret"`
|
||||
Host string `json:"host" yaml:"host" toml:"host"`
|
||||
} `json:"recaptcha" yaml:"recaptcha" toml:"recaptcha"`
|
||||
Auth oldAuth `json:"auth" yaml:"auth" toml:"auth"`
|
||||
}
|
||||
|
||||
var defaults = &oldConf{
|
||||
Port: "0",
|
||||
Log: "stdout",
|
||||
Defaults: oldDefs{
|
||||
Commands: []string{"git", "svn", "hg"},
|
||||
ViewMode: string(users.MosaicViewMode),
|
||||
AllowCommands: true,
|
||||
AllowEdit: true,
|
||||
AllowNew: true,
|
||||
Locale: "en",
|
||||
},
|
||||
Auth: oldAuth{
|
||||
Method: "default",
|
||||
},
|
||||
}
|
||||
|
||||
func readConf(path string) (*oldConf, error) {
|
||||
cfg := &oldConf{}
|
||||
if path != "" {
|
||||
ext := filepath.Ext(path)
|
||||
|
||||
fd, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
switch ext {
|
||||
case ".json":
|
||||
err = json.NewDecoder(fd).Decode(cfg)
|
||||
case ".toml":
|
||||
err = toml.NewDecoder(fd).Decode(cfg)
|
||||
case ".yaml", ".yml":
|
||||
err = yaml.NewDecoder(fd).Decode(cfg)
|
||||
default:
|
||||
return nil, errors.New("unsupported config extension " + ext)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
cfg = defaults
|
||||
path, err := filepath.Abs(".")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.Defaults.Scope = path
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func importConf(db *storm.DB, path string, sto *storage.Storage) error {
|
||||
cfg, err := readConf(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
commands := map[string][]string{}
|
||||
err = db.Get("config", "commands", &commands)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := []byte{}
|
||||
err = db.Get("config", "key", &key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s := &settings.Settings{
|
||||
Key: key,
|
||||
Signup: false,
|
||||
Defaults: settings.UserDefaults{
|
||||
Scope: cfg.Defaults.Scope,
|
||||
Commands: cfg.Defaults.Commands,
|
||||
ViewMode: users.ViewMode(cfg.Defaults.ViewMode),
|
||||
Locale: cfg.Defaults.Locale,
|
||||
Perm: users.Permissions{
|
||||
Admin: false,
|
||||
Execute: cfg.Defaults.AllowCommands,
|
||||
Create: cfg.Defaults.AllowNew,
|
||||
Rename: cfg.Defaults.AllowEdit,
|
||||
Modify: cfg.Defaults.AllowEdit,
|
||||
Delete: cfg.Defaults.AllowEdit,
|
||||
Share: true,
|
||||
Download: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
server := &settings.Server{
|
||||
BaseURL: cfg.BaseURL,
|
||||
Port: cfg.Port,
|
||||
Address: cfg.Address,
|
||||
Log: cfg.Log,
|
||||
}
|
||||
|
||||
var auther auth.Auther
|
||||
switch cfg.Auth.Method {
|
||||
case "proxy":
|
||||
auther = &auth.ProxyAuth{Header: cfg.Auth.Header}
|
||||
s.AuthMethod = string(auth.MethodProxyAuth)
|
||||
case "hook":
|
||||
auther = &auth.HookAuth{Command: cfg.Auth.Command}
|
||||
s.AuthMethod = string(auth.MethodHookAuth)
|
||||
case "none":
|
||||
auther = &auth.NoAuth{}
|
||||
s.AuthMethod = string(auth.MethodNoAuth)
|
||||
default:
|
||||
auther = &auth.JSONAuth{
|
||||
ReCaptcha: &auth.ReCaptcha{
|
||||
Host: cfg.ReCaptcha.Host,
|
||||
Key: cfg.ReCaptcha.Key,
|
||||
Secret: cfg.ReCaptcha.Secret,
|
||||
},
|
||||
}
|
||||
s.AuthMethod = string(auth.MethodJSONAuth)
|
||||
}
|
||||
|
||||
err = sto.Auth.Save(auther)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sto.Settings.Save(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sto.Settings.SaveServer(server)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Configuration successfully imported.")
|
||||
return nil
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"github.com/asdine/storm/v3"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/storage/bolt"
|
||||
)
|
||||
|
||||
// Import imports an old configuration to a newer database.
|
||||
func Import(oldDBPath, oldConf, newDBPath string) error {
|
||||
oldDB, err := storm.Open(oldDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer oldDB.Close()
|
||||
|
||||
newDB, err := storm.Open(newDBPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer newDB.Close()
|
||||
|
||||
sto, err := bolt.NewStorage(newDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = importUsers(oldDB, sto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = importConf(oldDB, oldConf, sto)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package importer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/asdine/storm/v3"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/rules"
|
||||
"github.com/gtsteffaniak/filebrowser/storage"
|
||||
"github.com/gtsteffaniak/filebrowser/users"
|
||||
)
|
||||
|
||||
type oldUser struct {
|
||||
ID int `storm:"id,increment"`
|
||||
Admin bool `json:"admin"`
|
||||
AllowCommands bool `json:"allowCommands"` // Execute commands
|
||||
AllowEdit bool `json:"allowEdit"` // Edit/rename files
|
||||
AllowNew bool `json:"allowNew"` // Create files and folders
|
||||
AllowPublish bool `json:"allowPublish"` // Publish content (to use with static gen)
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
Commands []string `json:"commands"`
|
||||
Locale string `json:"locale"`
|
||||
Password string `json:"password"`
|
||||
Rules []*rules.Rule `json:"rules"`
|
||||
Scope string `json:"filesystem"`
|
||||
Username string `json:"username" storm:"index,unique"`
|
||||
ViewMode string `json:"viewMode"`
|
||||
}
|
||||
|
||||
func readOldUsers(db *storm.DB) ([]*oldUser, error) {
|
||||
var oldUsers []*oldUser
|
||||
err := db.Bolt.View(func(tx *bolt.Tx) error {
|
||||
return tx.Bucket([]byte("User")).ForEach(func(k []byte, v []byte) error {
|
||||
if len(v) > 0 && string(v)[0] == '{' {
|
||||
user := &oldUser{}
|
||||
err := json.Unmarshal(v, user)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldUsers = append(oldUsers, user)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
return oldUsers, err
|
||||
}
|
||||
|
||||
func convertUsersToNew(old []*oldUser) ([]*users.User, error) {
|
||||
list := []*users.User{}
|
||||
|
||||
for _, oldUser := range old {
|
||||
user := &users.User{
|
||||
Username: oldUser.Username,
|
||||
Password: oldUser.Password,
|
||||
Scope: oldUser.Scope,
|
||||
Locale: oldUser.Locale,
|
||||
LockPassword: oldUser.LockPassword,
|
||||
ViewMode: users.ViewMode(oldUser.ViewMode),
|
||||
Commands: oldUser.Commands,
|
||||
Rules: []rules.Rule{},
|
||||
Perm: users.Permissions{
|
||||
Admin: oldUser.Admin,
|
||||
Execute: oldUser.AllowCommands,
|
||||
Create: oldUser.AllowNew,
|
||||
Rename: oldUser.AllowEdit,
|
||||
Modify: oldUser.AllowEdit,
|
||||
Delete: oldUser.AllowEdit,
|
||||
Share: true,
|
||||
Download: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, rule := range oldUser.Rules {
|
||||
user.Rules = append(user.Rules, *rule)
|
||||
}
|
||||
|
||||
err := user.Clean("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
list = append(list, user)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func importUsers(old *storm.DB, sto *storage.Storage) error {
|
||||
oldUsers, err := readOldUsers(old)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newUsers, err := convertUsersToNew(oldUsers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, user := range newUsers {
|
||||
err = sto.Users.Save(user)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("%d users successfully imported into the new DB.\n", len(newUsers))
|
||||
return nil
|
||||
}
|
||||
@@ -73,7 +73,12 @@ func (st usersBackend) Update(user *users.User, fields ...string) error {
|
||||
}
|
||||
|
||||
func (st usersBackend) Save(user *users.User) error {
|
||||
err := st.db.Save(user)
|
||||
pass, err := users.HashPwd(user.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user.Password = pass
|
||||
err = st.db.Save(user)
|
||||
if err == storm.ErrAlreadyExists {
|
||||
return errors.ErrExist
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
== Running tests ==
|
||||
/usr/local/go/bin/go
|
||||
? github.com/gtsteffaniak/filebrowser [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/auth [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/cmd [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/errors [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/files [no test files]
|
||||
=== RUN TestFileCache
|
||||
--- PASS: TestFileCache (0.00s)
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/diskcache (cached)
|
||||
=== RUN TestCommonPrefix
|
||||
=== RUN TestCommonPrefix/sub_folder
|
||||
=== RUN TestCommonPrefix/relative_path
|
||||
=== RUN TestCommonPrefix/no_common_path
|
||||
=== RUN TestCommonPrefix/same_lvl
|
||||
--- PASS: TestCommonPrefix (0.00s)
|
||||
--- PASS: TestCommonPrefix/sub_folder (0.00s)
|
||||
--- PASS: TestCommonPrefix/relative_path (0.00s)
|
||||
--- PASS: TestCommonPrefix/no_common_path (0.00s)
|
||||
--- PASS: TestCommonPrefix/same_lvl (0.00s)
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/fileutils (cached)
|
||||
? github.com/gtsteffaniak/filebrowser/settings [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/share [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/storage [no test files]
|
||||
? github.com/gtsteffaniak/filebrowser/storage/bolt [no test files]
|
||||
2023/09/02 13:07:17 Error opening YAML file: open filebrowser.yaml: no such file or directory
|
||||
FAIL github.com/gtsteffaniak/filebrowser/http 0.008s
|
||||
=== RUN TestService_Resize
|
||||
=== RUN TestService_Resize/convert_to_png
|
||||
=== RUN TestService_Resize/convert_to_tiff
|
||||
=== RUN TestService_Resize/resize_bmp
|
||||
=== RUN TestService_Resize/resize_with_medium_quality
|
||||
=== RUN TestService_Resize/resize_with_low_quality
|
||||
=== RUN TestService_Resize/get_thumbnail_from_file_with_APP0_JFIF
|
||||
=== RUN TestService_Resize/fill_upscale
|
||||
=== RUN TestService_Resize/fit_upscale
|
||||
=== RUN TestService_Resize/convert_to_gif
|
||||
=== RUN TestService_Resize/convert_to_bmp
|
||||
=== RUN TestService_Resize/resize_tiff
|
||||
=== RUN TestService_Resize/resize_with_high_quality
|
||||
=== RUN TestService_Resize/fill_downscale
|
||||
=== RUN TestService_Resize/keep_original_format
|
||||
=== RUN TestService_Resize/convert_to_unknown
|
||||
=== RUN TestService_Resize/get_thumbnail_from_file_without_APP0_JFIF
|
||||
=== RUN TestService_Resize/resize_for_higher_quality_levels
|
||||
=== RUN TestService_Resize/broken_file
|
||||
=== RUN TestService_Resize/fit_downscale
|
||||
=== RUN TestService_Resize/convert_to_jpeg
|
||||
=== RUN TestService_Resize/resize_png
|
||||
=== RUN TestService_Resize/resize_gif
|
||||
=== RUN TestService_Resize/resize_with_unknown_quality
|
||||
=== RUN TestService_Resize/resize_from_file_without_IFD1_thumbnail
|
||||
--- PASS: TestService_Resize (1.36s)
|
||||
--- PASS: TestService_Resize/convert_to_png (0.01s)
|
||||
--- PASS: TestService_Resize/convert_to_tiff (0.01s)
|
||||
--- PASS: TestService_Resize/resize_bmp (0.01s)
|
||||
--- PASS: TestService_Resize/resize_with_medium_quality (0.01s)
|
||||
--- PASS: TestService_Resize/resize_with_low_quality (0.01s)
|
||||
--- PASS: TestService_Resize/get_thumbnail_from_file_with_APP0_JFIF (0.02s)
|
||||
--- PASS: TestService_Resize/fill_upscale (0.01s)
|
||||
--- PASS: TestService_Resize/fit_upscale (0.00s)
|
||||
--- PASS: TestService_Resize/convert_to_gif (0.01s)
|
||||
--- PASS: TestService_Resize/convert_to_bmp (0.01s)
|
||||
--- PASS: TestService_Resize/resize_tiff (0.01s)
|
||||
--- PASS: TestService_Resize/resize_with_high_quality (0.01s)
|
||||
--- PASS: TestService_Resize/fill_downscale (0.01s)
|
||||
--- PASS: TestService_Resize/keep_original_format (0.01s)
|
||||
--- PASS: TestService_Resize/convert_to_unknown (0.01s)
|
||||
--- PASS: TestService_Resize/get_thumbnail_from_file_without_APP0_JFIF (0.03s)
|
||||
--- PASS: TestService_Resize/resize_for_higher_quality_levels (0.03s)
|
||||
--- PASS: TestService_Resize/broken_file (0.00s)
|
||||
--- PASS: TestService_Resize/fit_downscale (0.01s)
|
||||
--- PASS: TestService_Resize/convert_to_jpeg (0.01s)
|
||||
--- PASS: TestService_Resize/resize_png (0.02s)
|
||||
--- PASS: TestService_Resize/resize_gif (0.02s)
|
||||
--- PASS: TestService_Resize/resize_with_unknown_quality (0.01s)
|
||||
--- PASS: TestService_Resize/resize_from_file_without_IFD1_thumbnail (1.09s)
|
||||
=== RUN TestService_FormatFromExtension
|
||||
=== RUN TestService_FormatFromExtension/gif
|
||||
=== RUN TestService_FormatFromExtension/tiff
|
||||
=== RUN TestService_FormatFromExtension/bmp
|
||||
=== RUN TestService_FormatFromExtension/unknown
|
||||
=== RUN TestService_FormatFromExtension/jpg
|
||||
=== RUN TestService_FormatFromExtension/jpeg
|
||||
=== RUN TestService_FormatFromExtension/png
|
||||
--- PASS: TestService_FormatFromExtension (0.00s)
|
||||
--- PASS: TestService_FormatFromExtension/gif (0.00s)
|
||||
--- PASS: TestService_FormatFromExtension/tiff (0.00s)
|
||||
--- PASS: TestService_FormatFromExtension/bmp (0.00s)
|
||||
--- PASS: TestService_FormatFromExtension/unknown (0.00s)
|
||||
--- PASS: TestService_FormatFromExtension/jpg (0.00s)
|
||||
--- PASS: TestService_FormatFromExtension/jpeg (0.00s)
|
||||
--- PASS: TestService_FormatFromExtension/png (0.00s)
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/img (cached)
|
||||
=== RUN TestMatchHidden
|
||||
--- PASS: TestMatchHidden (0.00s)
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/rules (cached)
|
||||
2023/09/02 13:07:17 Error opening YAML file: open filebrowser.yaml: no such file or directory
|
||||
FAIL github.com/gtsteffaniak/filebrowser/runner 0.007s
|
||||
=== RUN TestParseSearch
|
||||
--- PASS: TestParseSearch (0.00s)
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/search (cached)
|
||||
? github.com/gtsteffaniak/filebrowser/version [no test files]
|
||||
testing: warning: no tests to run
|
||||
PASS
|
||||
ok github.com/gtsteffaniak/filebrowser/users (cached) [no tests to run]
|
||||
FAIL
|
||||
@@ -1,180 +0,0 @@
|
||||
module github.com/gtsteffaniak/filebrowser/tools
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/golangci/golangci-lint v1.51.1
|
||||
golang.org/x/tools v0.6.0
|
||||
)
|
||||
|
||||
require (
|
||||
4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
|
||||
4d63.com/gochecknoglobals v0.2.1 // indirect
|
||||
github.com/Abirdcfly/dupword v0.0.9 // indirect
|
||||
github.com/Antonboom/errname v0.1.7 // indirect
|
||||
github.com/Antonboom/nilnil v0.1.1 // indirect
|
||||
github.com/BurntSushi/toml v1.2.1 // indirect
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
||||
github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/OpenPeeDeeP/depguard v1.1.1 // indirect
|
||||
github.com/alexkohler/prealloc v1.0.0 // indirect
|
||||
github.com/alingse/asasalint v0.0.11 // indirect
|
||||
github.com/ashanbrown/forbidigo v1.3.0 // indirect
|
||||
github.com/ashanbrown/makezero v1.1.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bkielbasa/cyclop v1.2.0 // indirect
|
||||
github.com/blizzy78/varnamelen v0.8.0 // indirect
|
||||
github.com/bombsimon/wsl/v3 v3.3.0 // indirect
|
||||
github.com/breml/bidichk v0.2.3 // indirect
|
||||
github.com/breml/errchkjson v0.3.0 // indirect
|
||||
github.com/butuzov/ireturn v0.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/charithe/durationcheck v0.0.9 // indirect
|
||||
github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348 // indirect
|
||||
github.com/curioswitch/go-reassign v0.2.0 // indirect
|
||||
github.com/daixiang0/gci v0.9.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/denis-tingaikin/go-header v0.4.3 // indirect
|
||||
github.com/esimonov/ifshort v1.0.4 // indirect
|
||||
github.com/ettle/strcase v0.1.1 // indirect
|
||||
github.com/fatih/color v1.14.1 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/firefart/nonamedreturns v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fzipp/gocyclo v0.6.0 // indirect
|
||||
github.com/go-critic/go-critic v0.6.5 // indirect
|
||||
github.com/go-toolsmith/astcast v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astcopy v1.0.3 // indirect
|
||||
github.com/go-toolsmith/astequal v1.0.3 // indirect
|
||||
github.com/go-toolsmith/astfmt v1.0.0 // indirect
|
||||
github.com/go-toolsmith/astp v1.0.0 // indirect
|
||||
github.com/go-toolsmith/strparse v1.0.0 // indirect
|
||||
github.com/go-toolsmith/typep v1.0.2 // indirect
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
|
||||
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe // indirect
|
||||
github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // indirect
|
||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect
|
||||
github.com/golangci/misspell v0.4.0 // indirect
|
||||
github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 // indirect
|
||||
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
|
||||
github.com/gostaticanalysis/comment v1.4.2 // indirect
|
||||
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
|
||||
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-version v1.6.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/jgautheron/goconst v1.5.1 // indirect
|
||||
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
||||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
|
||||
github.com/julz/importas v0.1.0 // indirect
|
||||
github.com/junk1tm/musttag v0.4.4 // indirect
|
||||
github.com/kisielk/errcheck v1.6.3 // indirect
|
||||
github.com/kisielk/gotool v1.0.0 // indirect
|
||||
github.com/kkHAIKE/contextcheck v1.1.3 // indirect
|
||||
github.com/kulti/thelper v0.6.3 // indirect
|
||||
github.com/kunwardeep/paralleltest v1.0.6 // indirect
|
||||
github.com/kyoh86/exportloopref v0.1.11 // indirect
|
||||
github.com/ldez/gomoddirectives v0.2.3 // indirect
|
||||
github.com/ldez/tagliatelle v0.4.0 // indirect
|
||||
github.com/leonklingele/grouper v1.1.1 // indirect
|
||||
github.com/lufeee/execinquery v1.2.1 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/maratori/testableexamples v1.0.0 // indirect
|
||||
github.com/maratori/testpackage v1.1.0 // indirect
|
||||
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mbilski/exhaustivestruct v1.2.0 // indirect
|
||||
github.com/mgechev/revive v1.2.5 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moricho/tparallel v0.2.1 // indirect
|
||||
github.com/nakabonne/nestif v0.3.1 // indirect
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
|
||||
github.com/nishanths/exhaustive v0.9.5 // indirect
|
||||
github.com/nishanths/predeclared v0.2.2 // indirect
|
||||
github.com/nunnatsa/ginkgolinter v0.8.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polyfloyd/go-errorlint v1.0.6 // indirect
|
||||
github.com/prometheus/client_golang v1.12.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/quasilyte/go-ruleguard v0.3.18 // indirect
|
||||
github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f // indirect
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
|
||||
github.com/ryancurrah/gomodguard v1.3.0 // indirect
|
||||
github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect
|
||||
github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect
|
||||
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
|
||||
github.com/sashamelentyev/usestdlibvars v1.21.1 // indirect
|
||||
github.com/securego/gosec/v2 v2.14.0 // indirect
|
||||
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/sivchari/containedctx v1.0.2 // indirect
|
||||
github.com/sivchari/nosnakecase v1.7.0 // indirect
|
||||
github.com/sivchari/tenv v1.7.1 // indirect
|
||||
github.com/sonatard/noctx v0.0.1 // indirect
|
||||
github.com/sourcegraph/go-diff v0.7.0 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/cobra v1.6.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.12.0 // indirect
|
||||
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
|
||||
github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
|
||||
github.com/stretchr/objx v0.5.0 // indirect
|
||||
github.com/stretchr/testify v1.8.1 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect
|
||||
github.com/tdakkota/asciicheck v0.1.1 // indirect
|
||||
github.com/tetafro/godot v1.4.11 // indirect
|
||||
github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e // indirect
|
||||
github.com/timonwong/loggercheck v0.9.3 // indirect
|
||||
github.com/tomarrell/wrapcheck/v2 v2.8.0 // indirect
|
||||
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
|
||||
github.com/ultraware/funlen v0.0.3 // indirect
|
||||
github.com/ultraware/whitespace v0.0.5 // indirect
|
||||
github.com/uudashr/gocognit v1.0.6 // indirect
|
||||
github.com/yagipy/maintidx v1.0.0 // indirect
|
||||
github.com/yeya24/promlinter v0.2.0 // indirect
|
||||
gitlab.com/bosi/decorder v0.2.3 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.6.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
honnef.co/go/tools v0.4.0 // indirect
|
||||
mvdan.cc/gofumpt v0.4.0 // indirect
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect
|
||||
mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect
|
||||
)
|
||||
@@ -1,981 +0,0 @@
|
||||
4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA=
|
||||
4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs=
|
||||
4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc=
|
||||
4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Abirdcfly/dupword v0.0.9 h1:MxprGjKq3yDBICXDgEEsyGirIXfMYXkLNT/agPsE1tk=
|
||||
github.com/Abirdcfly/dupword v0.0.9/go.mod h1:PzmHVLLZ27MvHSzV7eFmMXSFArWXZPZmfuuziuUrf2g=
|
||||
github.com/Antonboom/errname v0.1.7 h1:mBBDKvEYwPl4WFFNwec1CZO096G6vzK9vvDQzAwkako=
|
||||
github.com/Antonboom/errname v0.1.7/go.mod h1:g0ONh16msHIPgJSGsecu1G/dcF2hlYR/0SddnIAGavU=
|
||||
github.com/Antonboom/nilnil v0.1.1 h1:PHhrh5ANKFWRBh7TdYmyyq2gyT2lotnvFvvFbylF81Q=
|
||||
github.com/Antonboom/nilnil v0.1.1/go.mod h1:L1jBqoWM7AOeTD+tSquifKSesRHs4ZdaxvZR+xdJEaI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
|
||||
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
|
||||
github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0 h1:+r1rSv4gvYn0wmRjC8X7IAzX8QezqtFV9m0MUHFJgts=
|
||||
github.com/GaijinEntertainment/go-exhaustruct/v2 v2.3.0/go.mod h1:b3g59n2Y+T5xmcxJL+UEG2f8cQploZm1mR/v6BW0mU0=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/OpenPeeDeeP/depguard v1.1.1 h1:TSUznLjvp/4IUP+OQ0t/4jF4QUyxIcVX8YnghZdunyA=
|
||||
github.com/OpenPeeDeeP/depguard v1.1.1/go.mod h1:JtAMzWkmFEzDPyAd+W0NHl1lvpQKTvT9jnRVsohBKpc=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw=
|
||||
github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
|
||||
github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
|
||||
github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
|
||||
github.com/ashanbrown/forbidigo v1.3.0 h1:VkYIwb/xxdireGAdJNZoo24O4lmnEWkactplBlWTShc=
|
||||
github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI=
|
||||
github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
|
||||
github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7A=
|
||||
github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI=
|
||||
github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
|
||||
github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
|
||||
github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM=
|
||||
github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
|
||||
github.com/breml/bidichk v0.2.3 h1:qe6ggxpTfA8E75hdjWPZ581sY3a2lnl0IRxLQFelECI=
|
||||
github.com/breml/bidichk v0.2.3/go.mod h1:8u2C6DnAy0g2cEq+k/A2+tr9O1s+vHGxWn0LTc70T2A=
|
||||
github.com/breml/errchkjson v0.3.0 h1:YdDqhfqMT+I1vIxPSas44P+9Z9HzJwCeAzjB8PxP1xw=
|
||||
github.com/breml/errchkjson v0.3.0/go.mod h1:9Cogkyv9gcT8HREpzi3TiqBxCqDzo8awa92zSDFcofU=
|
||||
github.com/butuzov/ireturn v0.1.1 h1:QvrO2QF2+/Cx1WA/vETCIYBKtRjc30vesdoPUNo1EbY=
|
||||
github.com/butuzov/ireturn v0.1.1/go.mod h1:Wh6Zl3IMtTpaIKbmwzqi6olnM9ptYQxxVacMsOEFPoc=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charithe/durationcheck v0.0.9 h1:mPP4ucLrf/rKZiIG/a9IPXHGlh8p4CzgpyTy6EEutYk=
|
||||
github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
|
||||
github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348 h1:cy5GCEZLUCshCGCRRUjxHrDUqkB4l5cuUt3ShEckQEo=
|
||||
github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348/go.mod h1:f/miWtG3SSuTxKsNK3o58H1xl+XV6ZIfbC6p7lPPB8U=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cristalhq/acmd v0.8.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ=
|
||||
github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo=
|
||||
github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
|
||||
github.com/daixiang0/gci v0.9.0 h1:t8XZ0vK6l0pwPoOmoGyqW2NwQlvbpAQNVvu/GRBgykM=
|
||||
github.com/daixiang0/gci v0.9.0/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denis-tingaikin/go-header v0.4.3 h1:tEaZKAlqql6SKCY++utLmkPLd6K8IBM20Ha7UVm+mtU=
|
||||
github.com/denis-tingaikin/go-header v0.4.3/go.mod h1:0wOCWuN71D5qIgE2nz9KrKmuYBAC2Mra5RassOIQ2/c=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStBA=
|
||||
github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0=
|
||||
github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw=
|
||||
github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY=
|
||||
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
|
||||
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y=
|
||||
github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
|
||||
github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
|
||||
github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
|
||||
github.com/go-critic/go-critic v0.6.5 h1:fDaR/5GWURljXwF8Eh31T2GZNz9X4jeboS912mWF8Uo=
|
||||
github.com/go-critic/go-critic v0.6.5/go.mod h1:ezfP/Lh7MA6dBNn4c6ab5ALv3sKnZVLx37tr00uuaOY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
|
||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
||||
github.com/go-toolsmith/astcopy v1.0.2/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y=
|
||||
github.com/go-toolsmith/astcopy v1.0.3 h1:r0bgSRlMOAgO+BdQnVAcpMSMkrQCnV6ZJmIkrJgcJj0=
|
||||
github.com/go-toolsmith/astcopy v1.0.3/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y=
|
||||
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astequal v1.0.2/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
|
||||
github.com/go-toolsmith/astequal v1.0.3 h1:+LVdyRatFS+XO78SGV4I3TCEA0AC7fKEGma+fH+674o=
|
||||
github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
|
||||
github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
|
||||
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
|
||||
github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
|
||||
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
|
||||
github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o=
|
||||
github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM=
|
||||
github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
|
||||
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
|
||||
github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk=
|
||||
github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
|
||||
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6J5HIP8ZtyMdiDscjMLfRBSPuzVVeo=
|
||||
github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ=
|
||||
github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzrdA+Nx5WA3tV1N0goTspwmKCQvBY=
|
||||
github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs=
|
||||
github.com/golangci/golangci-lint v1.51.1 h1:N5HD/x0ZrhJYsgKWyz7yJxxQ8JKR0Acc+FOP7QtGSAA=
|
||||
github.com/golangci/golangci-lint v1.51.1/go.mod h1:hnyNNO3fJ2Rjwo6HM+VXvcmLkKDOuBAnR9gVlS1mW1E=
|
||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA=
|
||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
||||
github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0=
|
||||
github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc=
|
||||
github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ=
|
||||
github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs=
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 h1:9alfqbrhuD+9fLZ4iaAVwhlp5PEhmnBt7yvK2Oy5C1U=
|
||||
github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
||||
github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw=
|
||||
github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
|
||||
github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc=
|
||||
github.com/gostaticanalysis/comment v1.3.0/go.mod h1:xMicKDx7XRXYdVwY9f9wQpDJVnqWxw9wCauCMKp+IBI=
|
||||
github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado=
|
||||
github.com/gostaticanalysis/comment v1.4.2 h1:hlnx5+S2fY9Zo9ePo4AhgYsYHbM2+eAv8m/s1JiCd6Q=
|
||||
github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM=
|
||||
github.com/gostaticanalysis/forcetypeassert v0.1.0 h1:6eUflI3DiGusXGK6X7cCcIgVCpZ2CiZ1Q7jl6ZxNV70=
|
||||
github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3VhWZ2mqag3IkWsDHVbplHXak=
|
||||
github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk=
|
||||
github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A=
|
||||
github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
|
||||
github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
|
||||
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM=
|
||||
github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
|
||||
github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs=
|
||||
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
|
||||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48=
|
||||
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY=
|
||||
github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0=
|
||||
github.com/junk1tm/musttag v0.4.4 h1:VK4L7v7lvWAhKDDx0cUJgbb0UBNipYinv8pPeHJzH9Q=
|
||||
github.com/junk1tm/musttag v0.4.4/go.mod h1:XkcL/9O6RmD88JBXb+I15nYRl9W4ExhgQeCBEhfMC8U=
|
||||
github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8=
|
||||
github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/kkHAIKE/contextcheck v1.1.3 h1:l4pNvrb8JSwRd51ojtcOxOeHJzHek+MtOyXbaR0uvmw=
|
||||
github.com/kkHAIKE/contextcheck v1.1.3/go.mod h1:PG/cwd6c0705/LM0KTr1acO2gORUxkSVWyLJOFW5qoo=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs=
|
||||
github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I=
|
||||
github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoaGS+Ugg8g=
|
||||
github.com/kunwardeep/paralleltest v1.0.6/go.mod h1:Y0Y0XISdZM5IKm3TREQMZ6iteqn1YuwCsJO/0kL9Zes=
|
||||
github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ=
|
||||
github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA=
|
||||
github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA=
|
||||
github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0=
|
||||
github.com/ldez/tagliatelle v0.4.0 h1:sylp7d9kh6AdXN2DpVGHBRb5guTVAgOxqNGhbqc4b1c=
|
||||
github.com/ldez/tagliatelle v0.4.0/go.mod h1:mNtTfrHy2haaBAw+VT7IBV6VXBThS7TCreYWbBcJ87I=
|
||||
github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU=
|
||||
github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY=
|
||||
github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM=
|
||||
github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI=
|
||||
github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
|
||||
github.com/maratori/testpackage v1.1.0 h1:GJY4wlzQhuBusMF1oahQCBtUV/AQ/k69IZ68vxaac2Q=
|
||||
github.com/maratori/testpackage v1.1.0/go.mod h1:PeAhzU8qkCwdGEMTEupsHJNlQu2gZopMC6RjbhmHeDc=
|
||||
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7RXkts09K+dEBJWakUWwICVqYbA=
|
||||
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo=
|
||||
github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc=
|
||||
github.com/mgechev/revive v1.2.5 h1:UF9AR8pOAuwNmhXj2odp4mxv9Nx2qUIwVz8ZsU+Mbec=
|
||||
github.com/mgechev/revive v1.2.5/go.mod h1:nFOXent79jMTISAfOAasKfy0Z2Ejq0WX7Qn/KAdYopI=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/moricho/tparallel v0.2.1 h1:95FytivzT6rYzdJLdtfn6m1bfFJylOJK41+lgv/EHf4=
|
||||
github.com/moricho/tparallel v0.2.1/go.mod h1:fXEIZxG2vdfl0ZF8b42f5a78EhjjD5mX8qUplsoSU4k=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U=
|
||||
github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nishanths/exhaustive v0.9.5 h1:TzssWan6orBiLYVqewCG8faud9qlFntJE30ACpzmGME=
|
||||
github.com/nishanths/exhaustive v0.9.5/go.mod h1:IbwrGdVMizvDcIxPYGVdQn5BqWJaOwpCvg4RGb8r/TA=
|
||||
github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
|
||||
github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
|
||||
github.com/nunnatsa/ginkgolinter v0.8.1 h1:/y4o/0hV+ruUHj4xXh89xlFjoaitnI4LnkpuYs02q1c=
|
||||
github.com/nunnatsa/ginkgolinter v0.8.1/go.mod h1:FYYLtszIdmzCH8XMaMPyxPVXZ7VCaIm55bA+gugx+14=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo/v2 v2.3.1 h1:8SbseP7qM32WcvE6VaN6vfXxv698izmsJ1UQX9ve7T8=
|
||||
github.com/onsi/gomega v1.22.1 h1:pY8O4lBfsHKZHM/6nrxkhVPUznOlIu3quZcKP/M20KI=
|
||||
github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=
|
||||
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/polyfloyd/go-errorlint v1.0.6 h1:ZevdyEGxDoHAMQUVvdTT06hnYuKULe8TQkOmIYx6s1c=
|
||||
github.com/polyfloyd/go-errorlint v1.0.6/go.mod h1:NcnNncnm8fVV7vfQWiI4HZrzWFzGp24C262IQutNcMs=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30=
|
||||
github.com/quasilyte/go-ruleguard v0.3.18 h1:sd+abO1PEI9fkYennwzHn9kl3nqP6M5vE7FiOzZ+5CE=
|
||||
github.com/quasilyte/go-ruleguard v0.3.18/go.mod h1:lOIzcYlgxrQ2sGJ735EHXmf/e9MJ516j16K/Ifcttvs=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.21/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
|
||||
github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
|
||||
github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f h1:6Gtn2i04RD0gVyYf2/IUMTIs+qYleBt4zxDqkLTcu4U=
|
||||
github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng=
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY=
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
|
||||
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw=
|
||||
github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50=
|
||||
github.com/ryanrolds/sqlclosecheck v0.4.0 h1:i8SX60Rppc1wRuyQjMciLqIzV3xnoHB7/tXbr6RGYNI=
|
||||
github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ=
|
||||
github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
|
||||
github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
|
||||
github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
|
||||
github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
|
||||
github.com/sashamelentyev/usestdlibvars v1.21.1 h1:GQGlReyL9Ek8DdJmwtwhHbhwHnuPfsKaprpjnrPcjxc=
|
||||
github.com/sashamelentyev/usestdlibvars v1.21.1/go.mod h1:MPI52Qq99iO9sFZZcKJ2y/bx6BNjs+/2bw3PCggIbew=
|
||||
github.com/securego/gosec/v2 v2.14.0 h1:U1hfs0oBackChXA72plCYVA4cOlQ4gO+209dHiSNZbI=
|
||||
github.com/securego/gosec/v2 v2.14.0/go.mod h1:Ff03zEi5NwSOfXj9nFpBfhbWTtROCkg9N+9goggrYn4=
|
||||
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
|
||||
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sivchari/containedctx v1.0.2 h1:0hLQKpgC53OVF1VT7CeoFHk9YKstur1XOgfYIc1yrHI=
|
||||
github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw=
|
||||
github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8=
|
||||
github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY=
|
||||
github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak=
|
||||
github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg=
|
||||
github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY=
|
||||
github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI=
|
||||
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
|
||||
github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
|
||||
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
|
||||
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
|
||||
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
|
||||
github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
|
||||
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
|
||||
github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc=
|
||||
github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
|
||||
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8=
|
||||
github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk=
|
||||
github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A=
|
||||
github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
|
||||
github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
|
||||
github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
|
||||
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
|
||||
github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
|
||||
github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw=
|
||||
github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8=
|
||||
github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e h1:MV6KaVu/hzByHP0UvJ4HcMGE/8a6A4Rggc/0wx2AvJo=
|
||||
github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ=
|
||||
github.com/timonwong/loggercheck v0.9.3 h1:ecACo9fNiHxX4/Bc02rW2+kaJIAMAes7qJ7JKxt0EZI=
|
||||
github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw=
|
||||
github.com/tomarrell/wrapcheck/v2 v2.8.0 h1:qDzbir0xmoE+aNxGCPrn+rUSxAX+nG6vREgbbXAR81I=
|
||||
github.com/tomarrell/wrapcheck/v2 v2.8.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg=
|
||||
github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
|
||||
github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
|
||||
github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA=
|
||||
github.com/ultraware/funlen v0.0.3/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/whitespace v0.0.5 h1:hh+/cpIcopyMYbZNVov9iSxvJU3OYQg78Sfaqzi/CzI=
|
||||
github.com/ultraware/whitespace v0.0.5/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
||||
github.com/uudashr/gocognit v1.0.6 h1:2Cgi6MweCsdB6kpcVQp7EW4U23iBFQWfTXiWlyp842Y=
|
||||
github.com/uudashr/gocognit v1.0.6/go.mod h1:nAIUuVBnYU7pcninia3BHOvQkpQCeO76Uscky5BOwcY=
|
||||
github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM=
|
||||
github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk=
|
||||
github.com/yeya24/promlinter v0.2.0 h1:xFKDQ82orCU5jQujdaD8stOHiv8UN68BSdn2a8u8Y3o=
|
||||
github.com/yeya24/promlinter v0.2.0/go.mod h1:u54lkmBOZrpEbQQ6gox2zWKKLKu2SGe+2KOiextY+IA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
gitlab.com/bosi/decorder v0.2.3 h1:gX4/RgK16ijY8V+BRQHAySfQAb354T7/xQpDB2n10P0=
|
||||
gitlab.com/bosi/decorder v0.2.3/go.mod h1:9K1RB5+VPNQYtXtTDAzd2OEftsZb1oV0IrJrzChSdGE=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
|
||||
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
|
||||
golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a h1:Jw5wfR+h9mnIYH+OtGT2im5wV1YGGDora5vTv/aa5bE=
|
||||
golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190307163923-6a08e3108db3/go.mod h1:25r3+/G6/xytQM8iWZKq3Hn0kr0rgFKPUNVEL/dr3z4=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||
golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
|
||||
golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.4.0 h1:lyXVV1c8wUBJRKqI8JgIpT8TW1VDagfYYaxbKa/HoL8=
|
||||
honnef.co/go/tools v0.4.0/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA=
|
||||
mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
|
||||
mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||
mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w=
|
||||
mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@commitlint/cli": "^15.0.0",
|
||||
"@commitlint/config-conventional": "^15.0.0",
|
||||
"standard-version": "^9.3.2"
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
//go:build tools
|
||||
// +build tools
|
||||
|
||||
package tools
|
||||
|
||||
// Manage tool dependencies via go.mod.
|
||||
//
|
||||
// https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module
|
||||
// https://github.com/golang/go/issues/25922
|
||||
//
|
||||
// nolint
|
||||
import (
|
||||
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
|
||||
_ "golang.org/x/tools/cmd/goimports"
|
||||
)
|
||||
@@ -1,13 +0,0 @@
|
||||
package users
|
||||
|
||||
// Permissions describe a user's permissions.
|
||||
type Permissions struct {
|
||||
Admin bool `json:"admin"`
|
||||
Execute bool `json:"execute"`
|
||||
Create bool `json:"create"`
|
||||
Rename bool `json:"rename"`
|
||||
Modify bool `json:"modify"`
|
||||
Delete bool `json:"delete"`
|
||||
Share bool `json:"share"`
|
||||
Download bool `json:"download"`
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package users
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -73,7 +74,7 @@ func (s *Storage) Gets(baseScope string) ([]*User, error) {
|
||||
|
||||
// Update updates a user in the database.
|
||||
func (s *Storage) Update(user *User, fields ...string) error {
|
||||
err := user.Clean("", fields...)
|
||||
err := user.Clean("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -91,6 +92,7 @@ func (s *Storage) Update(user *User, fields ...string) error {
|
||||
|
||||
// Save saves the user in a storage.
|
||||
func (s *Storage) Save(user *User) error {
|
||||
log.Println("Saving new user:", user.Username)
|
||||
if err := user.Clean(""); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -6,36 +6,40 @@ import (
|
||||
|
||||
"github.com/spf13/afero"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/files"
|
||||
"github.com/gtsteffaniak/filebrowser/rules"
|
||||
)
|
||||
|
||||
// ViewMode describes a view mode.
|
||||
type ViewMode string
|
||||
|
||||
const (
|
||||
ListViewMode ViewMode = "list"
|
||||
MosaicViewMode ViewMode = "mosaic"
|
||||
)
|
||||
type Permissions struct {
|
||||
Admin bool `json:"admin"`
|
||||
Execute bool `json:"execute"`
|
||||
Create bool `json:"create"`
|
||||
Rename bool `json:"rename"`
|
||||
Modify bool `json:"modify"`
|
||||
Delete bool `json:"delete"`
|
||||
Share bool `json:"share"`
|
||||
Download bool `json:"download"`
|
||||
}
|
||||
|
||||
// User describes a user.
|
||||
type User struct {
|
||||
ID uint `storm:"id,increment" json:"id"`
|
||||
Username string `storm:"unique" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
ViewMode ViewMode `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Perm Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Fs afero.Fs `json:"-" yaml:"-"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
DarkMode bool `json:"darkMode"`
|
||||
DisableSettings bool `json:"disableSettings"`
|
||||
ID uint `storm:"id,increment" json:"id"`
|
||||
Username string `storm:"unique" json:"username"`
|
||||
Password string `json:"password"`
|
||||
Scope string `json:"scope"`
|
||||
Locale string `json:"locale"`
|
||||
LockPassword bool `json:"lockPassword"`
|
||||
ViewMode string `json:"viewMode"`
|
||||
SingleClick bool `json:"singleClick"`
|
||||
Perm Permissions `json:"perm"`
|
||||
Commands []string `json:"commands"`
|
||||
Sorting files.Sorting `json:"sorting"`
|
||||
Fs afero.Fs `json:"-" yaml:"-"`
|
||||
Rules []rules.Rule `json:"rules"`
|
||||
HideDotfiles bool `json:"hideDotfiles"`
|
||||
DateFormat bool `json:"dateFormat"`
|
||||
}
|
||||
|
||||
// GetRules implements rules.Provider.
|
||||
@@ -43,53 +47,11 @@ func (u *User) GetRules() []rules.Rule {
|
||||
return u.Rules
|
||||
}
|
||||
|
||||
var checkableFields = []string{
|
||||
"Username",
|
||||
"Password",
|
||||
"Scope",
|
||||
"ViewMode",
|
||||
"Commands",
|
||||
"Sorting",
|
||||
"Rules",
|
||||
}
|
||||
|
||||
// Clean cleans up a user and verifies if all its fields
|
||||
// are alright to be saved.
|
||||
//
|
||||
//nolint:gocyclo
|
||||
func (u *User) Clean(baseScope string, fields ...string) error {
|
||||
if len(fields) == 0 {
|
||||
fields = checkableFields
|
||||
}
|
||||
|
||||
for _, field := range fields {
|
||||
switch field {
|
||||
case "Username":
|
||||
if u.Username == "" {
|
||||
return errors.ErrEmptyUsername
|
||||
}
|
||||
case "Password":
|
||||
if u.Password == "" {
|
||||
return errors.ErrEmptyPassword
|
||||
}
|
||||
case "ViewMode":
|
||||
if u.ViewMode == "" {
|
||||
u.ViewMode = ListViewMode
|
||||
}
|
||||
case "Commands":
|
||||
if u.Commands == nil {
|
||||
u.Commands = []string{}
|
||||
}
|
||||
case "Sorting":
|
||||
if u.Sorting.By == "" {
|
||||
u.Sorting.By = "name"
|
||||
}
|
||||
case "Rules":
|
||||
if u.Rules == nil {
|
||||
u.Rules = []rules.Rule{}
|
||||
}
|
||||
}
|
||||
}
|
||||
func (u *User) Clean(baseScope string) error {
|
||||
|
||||
if u.Fs == nil {
|
||||
scope := u.Scope
|
||||
|
||||
@@ -2,7 +2,7 @@ package version
|
||||
|
||||
var (
|
||||
// Version is the current File Browser version.
|
||||
Version = "(0.1.4)"
|
||||
Version = "(0.2.1)"
|
||||
// CommitSHA is the commmit sha.
|
||||
CommitSHA = "(unknown)"
|
||||
)
|
||||
@@ -0,0 +1,230 @@
|
||||
# Configuration Help
|
||||
|
||||
This document covers the available configuration options, their defaults, and how they affect the functionality of filebrowser.
|
||||
|
||||
## All possible configurations
|
||||
|
||||
Here is an expanded config file which includes all possible configurations:
|
||||
|
||||
```
|
||||
adminUsername: admin
|
||||
adminPassword: admin
|
||||
server:
|
||||
CreateUserDir: false
|
||||
UserHomeBasePath: ""
|
||||
indexingInterval: 5
|
||||
numImageProcessors: 4
|
||||
socket: ""
|
||||
tlsKey: ""
|
||||
tlsCert: ""
|
||||
enableThumbnails: false
|
||||
resizePreview: true
|
||||
typeDetectionByHeader: true
|
||||
port: 8080
|
||||
baseURL: "/"
|
||||
address: ""
|
||||
log: "stdout"
|
||||
database: "/database/database.db"
|
||||
root: "/srv"
|
||||
auth:
|
||||
recaptcha:
|
||||
host: ""
|
||||
key: ""
|
||||
secret: ""
|
||||
header: ""
|
||||
method: json
|
||||
command: ""
|
||||
signup: false
|
||||
shell: ""
|
||||
frontend:
|
||||
name: ""
|
||||
disableExternal: false
|
||||
disableUsedPercentage: true
|
||||
files: ""
|
||||
color: ""
|
||||
userDefaults:
|
||||
settingsAllowed: true
|
||||
darkMode: false
|
||||
scope: ""
|
||||
locale: "en"
|
||||
viewMode: ""
|
||||
singleClick: true
|
||||
sorting:
|
||||
by: ""
|
||||
asc: true
|
||||
permissions:
|
||||
admin: true
|
||||
execute: true
|
||||
create: true
|
||||
rename: true
|
||||
modify: true
|
||||
delete: true
|
||||
share: true
|
||||
download: true
|
||||
commands: []
|
||||
hideDotfiles: false
|
||||
dateFormat: false
|
||||
```
|
||||
|
||||
Here are the defaults if nothing is set:
|
||||
|
||||
```
|
||||
adminUsername: admin
|
||||
adminPassword: admin
|
||||
server:
|
||||
enableThumbnails: true
|
||||
enableExec: false
|
||||
indexingInterval: 5
|
||||
port: 8080
|
||||
numImageProcessors: 4
|
||||
baseURL: ""
|
||||
database: database.db
|
||||
log: stdout
|
||||
root: /srv
|
||||
auth:
|
||||
method: password
|
||||
recaptcha:
|
||||
host: ""
|
||||
userDefaults:
|
||||
settingsAllowed: true
|
||||
darkMode: false
|
||||
scope: ""
|
||||
locale: "en"
|
||||
scope: "."
|
||||
lockPassword: false
|
||||
hideDotfiles: true
|
||||
permissions:
|
||||
create: true
|
||||
rename: true
|
||||
modify: true
|
||||
delete: true
|
||||
share: true
|
||||
download: true
|
||||
```
|
||||
|
||||
## About each configuration
|
||||
|
||||
# Configuration Settings Documentation
|
||||
|
||||
## About each configuration
|
||||
|
||||
### Server configuration settings
|
||||
|
||||
- `indexingInterval`: This is the time in minutes the system waits before checking for filesystem changes. Default: `5`
|
||||
|
||||
- `numImageProcessors`: This is the number of image processors available. Default: `4`
|
||||
|
||||
- `socket`: This is the socket configuration.
|
||||
|
||||
- `tlsKey`: This is the TLS key configuration.
|
||||
|
||||
- `tlsCert`: This is the TLS certificate configuration.
|
||||
|
||||
- `enableThumbnails`: This boolean value determines whether thumbnails are enabled on ui. Default: `true`
|
||||
|
||||
- `resizePreview`: This boolean value determines whether preview resizing is enabled. Default: `false`
|
||||
|
||||
- `typeDetectionByHeader`: This boolean value determines whether type detection is based on headers.
|
||||
|
||||
- `port`: This is the port number on which the server is running. Default: `8080`
|
||||
|
||||
- `baseURL`: This is the base URL for the server. Default: `""`
|
||||
|
||||
- `address`: This is the server address configuration. Default: `0.0.0.0`
|
||||
|
||||
- `log`: This specifies the log destination. Default: `stdout`
|
||||
|
||||
- `database`: This is the database file path + filename that will be created if it does not already exist. If it exists, it will use the existing file. Default `database.db`
|
||||
|
||||
- `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
|
||||
|
||||
- `recaptcha`:
|
||||
|
||||
- `host`: This is the host for reCAPTCHA.
|
||||
|
||||
- `key`: This is the reCAPTCHA key.
|
||||
|
||||
- `secret`: This is the reCAPTCHA secret.
|
||||
|
||||
- `header`: This is the authentication header.
|
||||
|
||||
- `method`: This is the authentication method used (e.g., "json"). Possible values:
|
||||
- `password` - username and password
|
||||
- `hook` - hook authentication
|
||||
- `proxy` - proxy authentication
|
||||
- `oath` - oath authentication
|
||||
- `noauth` - no authentication/login required.
|
||||
|
||||
- `command`: Deprecated: This is the authentication command.
|
||||
|
||||
- `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
|
||||
|
||||
- `name`: This is the name of the frontend.
|
||||
|
||||
- `disableExternal`: This boolean value determines whether external access is disabled.
|
||||
|
||||
- `disableUsedPercentage`: This boolean value determines whether used percentage is disabled.
|
||||
|
||||
- `files`: This is the files configuration.
|
||||
|
||||
- `theme`: This is the theme configuration.
|
||||
|
||||
- `color`: This is the color configuration.
|
||||
|
||||
### UserDefaults configuration settings
|
||||
|
||||
- `darkMode`: Determines whether dark mode is enabled for the user (`true` or `false`)
|
||||
|
||||
- `settingsAllowed`: Determines whether settings page is enabled for the user (`true` or `false`)
|
||||
|
||||
- `scope`: This is a scope of the permissions, "." or "./" means all directories, "./downloads" would mean only the downloads folder.
|
||||
|
||||
- `locale`: String locale configuration. Default: `en`
|
||||
|
||||
- `viewMode`: This is the view mode configuration. Possible values: `normal`, `compact`, `list`, and `gallery`. default: `normal`
|
||||
|
||||
- `singleClick`: This boolean value determines whether single-click is enabled. (`true` or `false`)
|
||||
|
||||
- `sorting`:
|
||||
|
||||
- `by`: This is the sorting method used (e.g., "asc").
|
||||
|
||||
- `asc`: This boolean value determines the sorting order is ascending or descending. (`true` or `false`)
|
||||
|
||||
- `permissions`:
|
||||
|
||||
- `admin`: This boolean value determines whether admin permissions are granted.
|
||||
|
||||
- `execute`: This boolean value determines whether execute permissions are granted.
|
||||
|
||||
- `create`: This boolean value determines whether create permissions are granted.
|
||||
|
||||
- `rename`: This boolean value determines whether rename permissions are granted.
|
||||
|
||||
- `modify`: This boolean value determines whether modify permissions are granted.
|
||||
|
||||
- `delete`: This boolean value determines whether delete permissions are granted.
|
||||
|
||||
- `share`: This boolean value determines whether share permissions are granted.
|
||||
|
||||
- `download`: This boolean value determines whether download permissions are granted.
|
||||
|
||||
- `commands`: Deprecated: This is a list of commands.
|
||||
|
||||
- `hideDotfiles`: This boolean value determines whether dotfiles are hidden. (`true` or `false`)
|
||||
|
||||
- `dateFormat`: This boolean value determines whether date formatting is enabled. (`true` or `false`)
|
||||
@@ -0,0 +1,16 @@
|
||||
env:
|
||||
browser: true
|
||||
es2021: true
|
||||
extends:
|
||||
- eslint:recommended
|
||||
- plugin:vue/vue3-essential
|
||||
parserOptions:
|
||||
ecmaVersion: latest
|
||||
sourceType: module
|
||||
plugins:
|
||||
- vue
|
||||
rules:
|
||||
vue/multi-word-component-names: off
|
||||
vue/no-reserved-component-names: warn
|
||||
vue/no-mutating-props: off
|
||||
vue/no-deprecated-v-bind-sync: warn
|
||||
@@ -6,19 +6,22 @@
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"fix": "npx vue-cli-service lint",
|
||||
"watch": "vue-cli-service build --watch"
|
||||
"watch": "vue-cli-service build --watch",
|
||||
"lint": "eslint --ext .vue,.js src/",
|
||||
"lint:fix": "eslint --ext .vue,.js --fix src/",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "^1.4.7",
|
||||
"ace-builds": "^1.24.2",
|
||||
"clipboard": "^2.0.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"css-vars-ponyfill": "^2.4.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"js-base64": "^2.5.1",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"material-icons": "^1.10.5",
|
||||
"moment": "^2.29.4",
|
||||
"normalize.css": "^8.0.1",
|
||||
"noty": "^3.2.0-beta",
|
||||
"pretty-bytes": "^6.0.0",
|
||||
"qrcode.vue": "^1.7.0",
|
||||
@@ -36,6 +39,8 @@
|
||||
"devDependencies": {
|
||||
"@vue/cli-service": "^5.0.8",
|
||||
"compression-webpack-plugin": "^10.0.0",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-plugin-vue": "^9.17.0",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"postcss": {
|
||||
|
||||
|
Before Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1 @@
|
||||
favicon-256x256.png
|
||||
@@ -0,0 +1 @@
|
||||
favicon-256x256.png
|
||||
|
Before Width: | Height: | Size: 23 KiB |
|
Before Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 843 B |
@@ -0,0 +1 @@
|
||||
favicon-256x256.png
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
@@ -0,0 +1 @@
|
||||
favicon-256x256.png
|
||||
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
@@ -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 |
|
After Width: | Height: | Size: 15 KiB |
@@ -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 |