Compare commits
9
Commits
main
...
v0.7.9-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5b4c0c43b | ||
|
|
d4556968bf | ||
|
|
aa3167803d | ||
|
|
dae64f67f5 | ||
|
|
7c4c61ef28 | ||
|
|
7e4e966983 | ||
|
|
f8677169d5 | ||
|
|
455ef2e347 | ||
|
|
629dcbcc68 |
No files matched your search
@@ -15,18 +15,18 @@ jobs:
|
||||
go-version: 'stable'
|
||||
- working-directory: backend
|
||||
run: go test -race -v ./...
|
||||
# golanci-lint is currently disabled due to slowness
|
||||
# lint-backend:
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: actions/setup-go@v5
|
||||
# with:
|
||||
# go-version: 'stable'
|
||||
# - uses: golangci/golangci-lint-action@v5
|
||||
# with:
|
||||
# version: 'v1.64'
|
||||
# working-directory: backend
|
||||
lint-backend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 'stable'
|
||||
- uses: golangci/golangci-lint-action@v7
|
||||
with:
|
||||
version: 'v2.1.6'
|
||||
working-directory: backend
|
||||
install-mode: goinstall
|
||||
format-backend:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -2,6 +2,32 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version).
|
||||
|
||||
## v0.7.9-beta
|
||||
|
||||
**New Features**:
|
||||
- Admin users will get a small notification banner for available update in sidebar with link to new release.
|
||||
|
||||
**Notes**:
|
||||
- docker now defaults to ./data/databse.db as the database path allowing a simplified initial docker-compose.yaml. Existing configurations do not need updating.
|
||||
- oidc groups header updates admin permission of existing user (either add/remove if role exists)'
|
||||
- builds amd64 binary with musl for compatibility (glic error) https://github.com/gtsteffaniak/filebrowser/issues/755
|
||||
- renamed `server.sources.config.disabled` to `server.sources.config.disableIndexing`
|
||||
- better support for running with disabled index.
|
||||
- small indexing behavior tweaks.
|
||||
- markdown viewer hides sidebar https://github.com/gtsteffaniak/filebrowser/issues/744
|
||||
- quick download only applies to files
|
||||
|
||||
**BugFixes**:
|
||||
- subtitles filename issue https://github.com/gtsteffaniak/filebrowser/issues/678
|
||||
- search result links not working with custom baseUrl https://github.com/gtsteffaniak/filebrowser/issues/746
|
||||
- preview error for office native preview https://github.com/gtsteffaniak/filebrowser/issues/744
|
||||
- more source name safety for special characters.
|
||||
- shares with special character errors https://github.com/gtsteffaniak/filebrowser/issues/753
|
||||
- backspace navigates back a page when typing https://github.com/gtsteffaniak/filebrowser/issues/663
|
||||
- markdown viewer scrolling https://github.com/gtsteffaniak/filebrowser/issues/767
|
||||
- fix user permissions updated when modifying api key permissions
|
||||
- fix language change issue https://github.com/gtsteffaniak/filebrowser/issues/768 https://github.com/gtsteffaniak/filebrowser/issues/487
|
||||
|
||||
## v0.7.8-beta
|
||||
|
||||
Note: if using oidc, please update from 0.7.7 to resolve invalid_grant issue. Also - oidc no longer creates users automatically by default -- must be enabled.
|
||||
|
||||
@@ -18,6 +18,18 @@
|
||||
> [!WARNING]
|
||||
> There is no stable version -- planned for 2025. ([Read more](https://github.com/gtsteffaniak/filebrowser/discussions/628))
|
||||
|
||||
## About
|
||||
|
||||
FileBrowser Quantum provides an easy way to access and manage your files from the web. It has has a web page interface that allows you to create secure shared links, users with their own specific permissions and settings, and offers a great viewing experience for many file types.
|
||||
|
||||
This version is called "Quantum" because it packs tons of advanced features into a tiny easy to run file. Unlike the majority of alternative options, FileBrowser Quantum is simple to install and easy to configure.
|
||||
|
||||
The goal for this repo is to become the best open-source self-hosted file browsing application that exists -- **all for free**. This repo will always be free and open-source.
|
||||
|
||||
Ready to try it out? See [Getting Started Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Getting-Started).
|
||||
|
||||
## How its different
|
||||
|
||||
FileBrowser Quantum is a massive fork of the file browser open-source project with the following changes:
|
||||
|
||||
1. ✅ Multiple sources support
|
||||
@@ -43,18 +55,11 @@ Notable features that this fork *does not* have (removed):
|
||||
- ❌ rules are not supported yet (planned).
|
||||
- ❌ shell commands are completely removed and will not be returned.
|
||||
|
||||
## About
|
||||
> [!WARNING]
|
||||
> Every file and directory in the source gets indexed (by default). This enables powerful features such as instant search, but large source filesystems can increase your system requirements. [See indexing wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Indexing) for more info.
|
||||
|
||||
FileBrowser Quantum differs significantly from the original version. Many of these changes required a significant overhaul. Creating a fork was a necessary process to make the program better. There have been many growing pains, but a stable release is planned and coming soon.
|
||||
|
||||
This version is called "Quantum" because it packs tons of advanced features in a tiny executable file. Unlike the majority of alternative options, FileBrowser Quantum is simple to install and easy to configure.
|
||||
|
||||
The goal for this repo is to become the best open-source self-hosted file browsing application that exists -- **all for free**.
|
||||
|
||||
This repo will always be free and open-source.
|
||||
|
||||
For more, see the [Q&A Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Q&A)
|
||||
|
||||
## The UI
|
||||
|
||||
The UI has a simple three-component navigation system:
|
||||
@@ -94,6 +99,10 @@ See [Office Support Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Offic
|
||||
|
||||
See the [Migration Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Migration)
|
||||
|
||||
## Other Questions
|
||||
|
||||
For more, see the [Q&A Wiki](https://github.com/gtsteffaniak/filebrowser/wiki/Q&A)
|
||||
|
||||
## Comparison Chart
|
||||
|
||||
Application Name | <img width="48" src="https://github.com/user-attachments/assets/59986a2a-f960-4536-aa35-4a9a7c98ad48" > Quantum | <img width="48" src="https://github.com/filebrowser/filebrowser/blob/master/frontend/public/img/logo.svg" > Filebrowser | <img width="48" src="https://github.com/mickael-kerjean/filestash/blob/master/public/assets/logo/app_icon.png?raw=true" > Filestash | <img width="48" src="https://avatars.githubusercontent.com/u/19211038?s=200&v=4" > Nextcloud | <img width="48" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/da/Google_Drive_logo.png/480px-Google_Drive_logo.png" > Google_Drive | <img width="48" src="https://avatars.githubusercontent.com/u/6422152?v=4" > FileRun
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ RUN npm run build-docker
|
||||
|
||||
FROM alpine:latest
|
||||
COPY --from=ffmpeg [ "/ffmpeg", "/ffprobe", "/usr/local/bin/" ]
|
||||
|
||||
ENV FILEBROWSER_FFMPEG_PATH="/usr/local/bin/"
|
||||
ENV FILEBROWSER_DATABASE="/home/filebrowser/data/database.db"
|
||||
ENV FILEBROWSER_NO_EMBEDED="true"
|
||||
ENV PATH="$PATH:/home/filebrowser"
|
||||
RUN apk --no-cache add ca-certificates mailcap tzdata
|
||||
@@ -30,7 +30,7 @@ RUN adduser -D -s /bin/true -u 1000 filebrowser
|
||||
USER filebrowser
|
||||
WORKDIR /home/filebrowser
|
||||
COPY --from=base --chown=filebrowser:1000 /app/filebrowser ./
|
||||
COPY --from=base --chown=filebrowser:1000 /app/config.media.yaml ./config.yaml
|
||||
COPY --from=base --chown=filebrowser:1000 /app/config.yaml ./data/config.yaml
|
||||
COPY --from=nbuild --chown=filebrowser:1000 /app/dist/ ./http/dist/
|
||||
## sanity checks
|
||||
RUN [ "filebrowser", "version" ]
|
||||
|
||||
@@ -19,13 +19,14 @@ RUN npm run build-docker
|
||||
|
||||
FROM alpine:latest
|
||||
ENV FILEBROWSER_NO_EMBEDED="true"
|
||||
ENV FILEBROWSER_DATABASE="/home/filebrowser/data/database.db"
|
||||
ENV PATH="$PATH:/home/filebrowser"
|
||||
RUN apk --no-cache add ca-certificates mailcap tzdata
|
||||
RUN adduser -D -s /bin/true -u 1000 filebrowser
|
||||
USER filebrowser
|
||||
WORKDIR /home/filebrowser
|
||||
COPY --from=base --chown=filebrowser:1000 /app/filebrowser ./
|
||||
COPY --from=base --chown=filebrowser:1000 /app/config.yaml ./config.yaml
|
||||
COPY --from=base --chown=filebrowser:1000 /app/config.yaml ./data/config.yaml
|
||||
COPY --from=nbuild --chown=filebrowser:1000 /app/dist/ ./http/dist/
|
||||
## sanity checks
|
||||
RUN [ "filebrowser", "version" ]
|
||||
|
||||
+145
-231
@@ -1,232 +1,146 @@
|
||||
# This code is licensed under the terms of the MIT license https://opensource.org/license/mit
|
||||
# Copyright (c) 2021 Marat Reymers
|
||||
|
||||
## Golden config for golangci-lint v1.59.1
|
||||
#
|
||||
# This is the best config for golangci-lint based on my experience and opinion.
|
||||
# It is very strict, but not extremely strict.
|
||||
# Feel free to adapt and change it for your needs.
|
||||
|
||||
run:
|
||||
# Timeout for analysis, e.g. 30s, 5m.
|
||||
# Default: 1m
|
||||
timeout: 3m
|
||||
|
||||
|
||||
# This file contains only configs which differ from defaults.
|
||||
# All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml
|
||||
linters-settings:
|
||||
cyclop:
|
||||
# The maximal code complexity to report.
|
||||
# Default: 10
|
||||
max-complexity: 30
|
||||
# The maximal average package complexity.
|
||||
# If it's higher than 0.0 (float) the check is enabled
|
||||
# Default: 0.0
|
||||
package-average: 10.0
|
||||
|
||||
errcheck:
|
||||
# Report about not checking of errors in type assertions: `a := b.(MyStruct)`.
|
||||
# Such cases aren't reported by default.
|
||||
# Default: false
|
||||
check-type-assertions: true
|
||||
|
||||
exhaustive:
|
||||
# Program elements to check for exhaustiveness.
|
||||
# Default: [ switch ]
|
||||
check:
|
||||
- switch
|
||||
- map
|
||||
|
||||
exhaustruct:
|
||||
# List of regular expressions to exclude struct packages and their names from checks.
|
||||
# Regular expressions must match complete canonical struct package/name/structname.
|
||||
# Default: []
|
||||
exclude:
|
||||
# std libs
|
||||
- "^net/http.Client$"
|
||||
- "^net/http.Cookie$"
|
||||
- "^net/http.Request$"
|
||||
- "^net/http.Response$"
|
||||
- "^net/http.Server$"
|
||||
- "^net/http.Transport$"
|
||||
- "^net/url.URL$"
|
||||
- "^os/exec.Cmd$"
|
||||
- "^reflect.StructField$"
|
||||
# public libs
|
||||
- "^github.com/Shopify/sarama.Config$"
|
||||
- "^github.com/Shopify/sarama.ProducerMessage$"
|
||||
- "^github.com/mitchellh/mapstructure.DecoderConfig$"
|
||||
- "^github.com/prometheus/client_golang/.+Opts$"
|
||||
- "^github.com/spf13/cobra.Command$"
|
||||
- "^github.com/spf13/cobra.CompletionOptions$"
|
||||
- "^github.com/stretchr/testify/mock.Mock$"
|
||||
- "^github.com/testcontainers/testcontainers-go.+Request$"
|
||||
- "^github.com/testcontainers/testcontainers-go.FromDockerfile$"
|
||||
- "^golang.org/x/tools/go/analysis.Analyzer$"
|
||||
- "^google.golang.org/protobuf/.+Options$"
|
||||
- "^gopkg.in/yaml.v3.Node$"
|
||||
|
||||
funlen:
|
||||
# Checks the number of lines in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 60
|
||||
lines: 100
|
||||
# Checks the number of statements in a function.
|
||||
# If lower than 0, disable the check.
|
||||
# Default: 40
|
||||
statements: 50
|
||||
# Ignore comments when counting lines.
|
||||
# Default false
|
||||
ignore-comments: true
|
||||
|
||||
gocognit:
|
||||
# Minimal code complexity to report.
|
||||
# Default: 30 (but we recommend 10-20)
|
||||
min-complexity: 20
|
||||
|
||||
gocritic:
|
||||
# Settings passed to gocritic.
|
||||
# The settings key is the name of a supported gocritic checker.
|
||||
# The list of supported checkers can be find in https://go-critic.github.io/overview.
|
||||
settings:
|
||||
captLocal:
|
||||
# Whether to restrict checker to params only.
|
||||
# Default: true
|
||||
paramsOnly: false
|
||||
underef:
|
||||
# Whether to skip (*x).method() calls where x is a pointer receiver.
|
||||
# Default: true
|
||||
skipRecvDeref: false
|
||||
|
||||
gomodguard:
|
||||
blocked:
|
||||
# List of blocked modules.
|
||||
# Default: []
|
||||
modules:
|
||||
- github.com/golang/protobuf:
|
||||
recommendations:
|
||||
- google.golang.org/protobuf
|
||||
reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules"
|
||||
- github.com/satori/go.uuid:
|
||||
recommendations:
|
||||
- github.com/google/uuid
|
||||
reason: "satori's package is not maintained"
|
||||
- github.com/gofrs/uuid:
|
||||
recommendations:
|
||||
- github.com/gofrs/uuid/v5
|
||||
reason: "gofrs' package was not go module before v5"
|
||||
|
||||
govet:
|
||||
# Enable all analyzers.
|
||||
# Default: false
|
||||
enable-all: true
|
||||
# Disable analyzers by name.
|
||||
# Run `go tool vet help` to see all analyzers.
|
||||
# Default: []
|
||||
disable:
|
||||
- fieldalignment # too strict
|
||||
# Settings per analyzer.
|
||||
settings:
|
||||
shadow:
|
||||
# Whether to be strict about shadowing; can be noisy.
|
||||
# Default: false
|
||||
strict: false
|
||||
|
||||
inamedparam:
|
||||
# Skips check for interface methods with only a single parameter.
|
||||
# Default: false
|
||||
skip-single-param: true
|
||||
|
||||
mnd:
|
||||
# List of function patterns to exclude from analysis.
|
||||
# Values always ignored: `time.Date`,
|
||||
# `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`,
|
||||
# `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`.
|
||||
# Default: []
|
||||
ignored-functions:
|
||||
- args.Error
|
||||
- flag.Arg
|
||||
- flag.Duration.*
|
||||
- flag.Float.*
|
||||
- flag.Int.*
|
||||
- flag.Uint.*
|
||||
- os.Chmod
|
||||
- os.Mkdir.*
|
||||
- os.OpenFile
|
||||
- os.WriteFile
|
||||
- prometheus.ExponentialBuckets.*
|
||||
- prometheus.LinearBuckets
|
||||
|
||||
nakedret:
|
||||
# Make an issue if func has more lines of code than this setting, and it has naked returns.
|
||||
# Default: 30
|
||||
max-func-lines: 0
|
||||
|
||||
nolintlint:
|
||||
# Exclude following linters from requiring an explanation.
|
||||
# Default: []
|
||||
allow-no-explanation: [ funlen, gocognit, lll ]
|
||||
# Enable to require an explanation of nonzero length after each nolint directive.
|
||||
# Default: false
|
||||
require-explanation: true
|
||||
# Enable to require nolint directives to mention the specific linter being suppressed.
|
||||
# Default: false
|
||||
require-specific: true
|
||||
|
||||
perfsprint:
|
||||
# Optimizes into strings concatenation.
|
||||
# Default: true
|
||||
strconcat: false
|
||||
|
||||
rowserrcheck:
|
||||
# database/sql is always checked
|
||||
# Default: []
|
||||
packages:
|
||||
- github.com/jmoiron/sqlx
|
||||
|
||||
sloglint:
|
||||
# Enforce not using global loggers.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all global loggers
|
||||
# - "default": report only the default slog logger
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#no-global
|
||||
# Default: ""
|
||||
no-global: "all"
|
||||
# Enforce using methods that accept a context.
|
||||
# Values:
|
||||
# - "": disabled
|
||||
# - "all": report all contextless calls
|
||||
# - "scope": report only if a context exists in the scope of the outermost function
|
||||
# https://github.com/go-simpler/sloglint?tab=readme-ov-file#context-only
|
||||
# Default: ""
|
||||
context: "scope"
|
||||
|
||||
tenv:
|
||||
# The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures.
|
||||
# Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked.
|
||||
# Default: false
|
||||
all: true
|
||||
|
||||
|
||||
issues:
|
||||
# Maximum count of issues with the same text.
|
||||
# Set to 0 to disable.
|
||||
# Default: 3
|
||||
max-same-issues: 50
|
||||
|
||||
exclude-rules:
|
||||
- source: "(noinspection|TODO)"
|
||||
linters: [ godot ]
|
||||
- source: "//noinspection"
|
||||
linters: [ gocritic ]
|
||||
- path: "_test\\.go"
|
||||
linters:
|
||||
- bodyclose
|
||||
- dupl
|
||||
version: "2"
|
||||
linters:
|
||||
settings:
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
- '-QF1001'
|
||||
- '-ST1003'
|
||||
- '-ST1016'
|
||||
- '-QF1004'
|
||||
- '-QF1003'
|
||||
cyclop:
|
||||
max-complexity: 30
|
||||
package-average: 10
|
||||
errcheck:
|
||||
check-type-assertions: true
|
||||
exhaustive:
|
||||
check:
|
||||
- switch
|
||||
- map
|
||||
exhaustruct:
|
||||
exclude:
|
||||
- ^net/http.Client$
|
||||
- ^net/http.Cookie$
|
||||
- ^net/http.Request$
|
||||
- ^net/http.Response$
|
||||
- ^net/http.Server$
|
||||
- ^net/http.Transport$
|
||||
- ^net/url.URL$
|
||||
- ^os/exec.Cmd$
|
||||
- ^reflect.StructField$
|
||||
- ^github.com/Shopify/sarama.Config$
|
||||
- ^github.com/Shopify/sarama.ProducerMessage$
|
||||
- ^github.com/mitchellh/mapstructure.DecoderConfig$
|
||||
- ^github.com/prometheus/client_golang/.+Opts$
|
||||
- ^github.com/spf13/cobra.Command$
|
||||
- ^github.com/spf13/cobra.CompletionOptions$
|
||||
- ^github.com/stretchr/testify/mock.Mock$
|
||||
- ^github.com/testcontainers/testcontainers-go.+Request$
|
||||
- ^github.com/testcontainers/testcontainers-go.FromDockerfile$
|
||||
- ^golang.org/x/tools/go/analysis.Analyzer$
|
||||
- ^google.golang.org/protobuf/.+Options$
|
||||
- ^gopkg.in/yaml.v3.Node$
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
ignore-comments: true
|
||||
gocognit:
|
||||
min-complexity: 20
|
||||
gocritic:
|
||||
settings:
|
||||
captLocal:
|
||||
paramsOnly: false
|
||||
underef:
|
||||
skipRecvDeref: false
|
||||
gomodguard:
|
||||
blocked:
|
||||
modules:
|
||||
- github.com/golang/protobuf:
|
||||
recommendations:
|
||||
- google.golang.org/protobuf
|
||||
reason: see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules
|
||||
- github.com/satori/go.uuid:
|
||||
recommendations:
|
||||
- github.com/google/uuid
|
||||
reason: satori's package is not maintained
|
||||
- github.com/gofrs/uuid:
|
||||
recommendations:
|
||||
- github.com/gofrs/uuid/v5
|
||||
reason: gofrs' package was not go module before v5
|
||||
govet:
|
||||
disable:
|
||||
- fieldalignment
|
||||
enable-all: true
|
||||
settings:
|
||||
shadow:
|
||||
strict: false
|
||||
inamedparam:
|
||||
skip-single-param: true
|
||||
mnd:
|
||||
ignored-functions:
|
||||
- args.Error
|
||||
- flag.Arg
|
||||
- flag.Duration.*
|
||||
- flag.Float.*
|
||||
- flag.Int.*
|
||||
- flag.Uint.*
|
||||
- os.Chmod
|
||||
- os.Mkdir.*
|
||||
- os.OpenFile
|
||||
- os.WriteFile
|
||||
- prometheus.ExponentialBuckets.*
|
||||
- prometheus.LinearBuckets
|
||||
nakedret:
|
||||
max-func-lines: 0
|
||||
nolintlint:
|
||||
require-explanation: true
|
||||
require-specific: true
|
||||
allow-no-explanation:
|
||||
- funlen
|
||||
- goconst
|
||||
- gosec
|
||||
- noctx
|
||||
- wrapcheck
|
||||
- gocognit
|
||||
- lll
|
||||
perfsprint:
|
||||
strconcat: false
|
||||
rowserrcheck:
|
||||
packages:
|
||||
- github.com/jmoiron/sqlx
|
||||
sloglint:
|
||||
no-global: all
|
||||
context: scope
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
rules:
|
||||
- linters:
|
||||
- godot
|
||||
source: (noinspection|TODO)
|
||||
- linters:
|
||||
- gocritic
|
||||
source: //noinspection
|
||||
- linters:
|
||||
- bodyclose
|
||||
- dupl
|
||||
- funlen
|
||||
- goconst
|
||||
- gosec
|
||||
- noctx
|
||||
- wrapcheck
|
||||
path: _test\.go
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
issues:
|
||||
max-same-issues: 50
|
||||
formatters:
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
@@ -7,8 +7,10 @@ builds:
|
||||
- id: linux-amd64
|
||||
env:
|
||||
- CGO_ENABLED=1
|
||||
- CC=zig cc -target x86_64-linux-musl
|
||||
tags:
|
||||
- mupdf
|
||||
- musl
|
||||
ldflags: &ldflags
|
||||
- -s -w -X github.com/gtsteffaniak/filebrowser/backend/common/version.Version={{ .Version }} -X github.com/gtsteffaniak/filebrowser/backend/common/version.CommitSHA={{ .ShortCommit }}
|
||||
main: main.go
|
||||
|
||||
@@ -41,32 +41,23 @@ func FileInfoFaster(opts iteminfo.FileOptions) (iteminfo.ExtendedFileInfo, error
|
||||
return response, err
|
||||
}
|
||||
opts.IsDir = isDir
|
||||
// TODO: whats the best way to save trips to disk here?
|
||||
// disabled using cache because its not clear if this is helping or hurting
|
||||
// check if the file exists in the index
|
||||
//info, exists := index.GetReducedMetadata(opts.Path, opts.IsDir)
|
||||
//if exists {
|
||||
// err := RefreshFileInfo(opts)
|
||||
// if err != nil {
|
||||
// return info, err
|
||||
// }
|
||||
// if opts.Content {
|
||||
// content := ""
|
||||
// content, err = getContent(opts.Path)
|
||||
// if err != nil {
|
||||
// return info, err
|
||||
// }
|
||||
// info.Content = content
|
||||
// }
|
||||
// return info, nil
|
||||
//}
|
||||
var info *iteminfo.FileInfo
|
||||
var exists bool
|
||||
err = index.RefreshFileInfo(opts)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
info, exists := index.GetReducedMetadata(opts.Path, opts.IsDir)
|
||||
if !exists {
|
||||
return response, fmt.Errorf("could not get metadata for path: %v", opts.Path)
|
||||
if err == errors.ErrNotIndexed && index.Config.DisableIndexing {
|
||||
info, err = index.GetFsDirInfo(opts.Path)
|
||||
if err != nil {
|
||||
return response, err
|
||||
}
|
||||
} else {
|
||||
return response, fmt.Errorf("could not refresh file info: %v", err)
|
||||
}
|
||||
} else {
|
||||
info, exists = index.GetReducedMetadata(opts.Path, opts.IsDir)
|
||||
if !exists {
|
||||
return response, fmt.Errorf("could not get metadata for path: %v", opts.Path)
|
||||
}
|
||||
}
|
||||
if opts.Content {
|
||||
if info.Size < 20*1024*1024 { // 20 megabytes in bytes
|
||||
|
||||
+9
-4
@@ -36,10 +36,15 @@ func runCLI() bool {
|
||||
|
||||
if configPath == "" {
|
||||
configPath = os.Getenv("FILEBROWSER_CONFIG")
|
||||
}
|
||||
|
||||
if configPath == "" {
|
||||
configPath = "config.yaml"
|
||||
// backwards compatibility in docker, prefer config.yaml if it exists
|
||||
if configPath != "" {
|
||||
_, err := os.Stat(configPath)
|
||||
if err != nil {
|
||||
logger.Fatalf("config file %v does not exist, please create it or set the FILEBROWSER_CONFIG environment variable to a valid config file path", configPath)
|
||||
}
|
||||
} else {
|
||||
configPath = "config.yaml"
|
||||
}
|
||||
}
|
||||
|
||||
// Parse global flags (before subcommands)
|
||||
|
||||
+11
-2
@@ -7,8 +7,12 @@ import (
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
_ "net/http/pprof"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/adapters/fs/fileutils"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/utils"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/version"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/database/storage"
|
||||
fbhttp "github.com/gtsteffaniak/filebrowser/backend/http"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/indexing"
|
||||
@@ -16,8 +20,6 @@ import (
|
||||
"github.com/gtsteffaniak/filebrowser/backend/swagger/docs"
|
||||
"github.com/gtsteffaniak/go-logger/logger"
|
||||
"github.com/swaggo/swag"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/version"
|
||||
)
|
||||
|
||||
var store *storage.Storage
|
||||
@@ -51,6 +53,13 @@ func StartFilebrowser() {
|
||||
if !keepGoing {
|
||||
return
|
||||
}
|
||||
info, _ := utils.CheckForUpdates()
|
||||
if info.LatestVersion != "" {
|
||||
logger.Infof("A new version is available: %s (current: %s)", info.LatestVersion, info.CurrentVersion)
|
||||
logger.Infof("Release notes: %s", info.ReleaseNotes)
|
||||
}
|
||||
go utils.StartCheckForUpdates()
|
||||
|
||||
// Create context and channels for graceful shutdown
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
@@ -21,4 +21,5 @@ var (
|
||||
ErrNoTotpProvided = errors.New("OTP code is required for user")
|
||||
ErrNoTotpConfigured = errors.New("OTP is enforced, but user is not yet configured")
|
||||
ErrUnauthorized = errors.New("user unauthorized")
|
||||
ErrNotIndexed = errors.New("directory or item excluded from indexing")
|
||||
)
|
||||
@@ -226,7 +226,7 @@ func loadConfigWithDefaults(configFile string) error {
|
||||
// Open and read the YAML file
|
||||
yamlFile, err := os.Open(configFile)
|
||||
if err != nil {
|
||||
logger.Warningf("could not open config file '%v', using default settings", configFile)
|
||||
logger.Errorf("could not open config file '%v', using default settings.", configFile)
|
||||
Config.Server.Sources = []Source{
|
||||
{
|
||||
Path: ".",
|
||||
@@ -292,12 +292,16 @@ func setDefaults() Settings {
|
||||
if cpus := runtime.NumCPU(); cpus > 0 {
|
||||
numCpus = cpus
|
||||
}
|
||||
database := os.Getenv("FILEBROWSER_DATABASE")
|
||||
if database == "" {
|
||||
database = "database.db"
|
||||
}
|
||||
return Settings{
|
||||
Server: Server{
|
||||
Port: 80,
|
||||
NumImageProcessors: numCpus,
|
||||
BaseURL: "",
|
||||
Database: "database.db",
|
||||
Database: database,
|
||||
SourceMap: map[string]Source{},
|
||||
NameToSource: map[string]Source{},
|
||||
MaxArchiveSizeGB: 50,
|
||||
|
||||
@@ -78,17 +78,17 @@ type Source struct {
|
||||
}
|
||||
|
||||
type SourceConfig struct {
|
||||
IndexingInterval uint32 `json:"indexingInterval"` // optional manual overide interval in seconds to re-index the source
|
||||
Disabled bool `json:"disabled"` // disable the indexing of this source
|
||||
MaxWatchers int `json:"maxWatchers"` // number of concurrent watchers to use for this source, currently not supported
|
||||
NeverWatch []string `json:"neverWatchPaths"` // paths to never watch, relative to the source path (eg. "/folder/file.txt")
|
||||
IgnoreHidden bool `json:"ignoreHidden"` // ignore hidden files and folders.
|
||||
IgnoreZeroSizeFolders bool `json:"ignoreZeroSizeFolders"` // ignore folders with 0 size
|
||||
Exclude IndexFilter `json:"exclude"` // exclude files and folders from indexing, if include is not set
|
||||
Include IndexFilter `json:"include"` // include files and folders from indexing, if exclude is not set
|
||||
DefaultUserScope string `json:"defaultUserScope"` // default "/" should match folders under path
|
||||
DefaultEnabled bool `json:"defaultEnabled"` // should be added as a default source for new users?
|
||||
CreateUserDir bool `json:"createUserDir"` // create a user directory for each user
|
||||
IndexingInterval uint32 `json:"indexingIntervalMinutes"` // optional manual overide interval in seconds to re-index the source
|
||||
DisableIndexing bool `json:"disableIndexing"` // disable the indexing of this source
|
||||
MaxWatchers int `json:"maxWatchers"` // number of concurrent watchers to use for this source, currently not supported
|
||||
NeverWatch []string `json:"neverWatchPaths"` // paths to never watch, relative to the source path (eg. "/folder/file.txt")
|
||||
IgnoreHidden bool `json:"ignoreHidden"` // ignore hidden files and folders.
|
||||
IgnoreZeroSizeFolders bool `json:"ignoreZeroSizeFolders"` // ignore folders with 0 size
|
||||
Exclude IndexFilter `json:"exclude"` // exclude files and folders from indexing, if include is not set
|
||||
Include IndexFilter `json:"include"` // include files and folders from indexing, if exclude is not set
|
||||
DefaultUserScope string `json:"defaultUserScope"` // default "/" should match folders under path
|
||||
DefaultEnabled bool `json:"defaultEnabled"` // should be added as a default source for new users?
|
||||
CreateUserDir bool `json:"createUserDir"` // create a user directory for each user
|
||||
}
|
||||
|
||||
type IndexFilter struct {
|
||||
@@ -113,22 +113,23 @@ type ExternalLink struct {
|
||||
// UserDefaults is a type that holds the default values
|
||||
// for some fields on User.
|
||||
type UserDefaults struct {
|
||||
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
|
||||
DarkMode bool `json:"darkMode"` // should dark mode be enabled
|
||||
Locale string `json:"locale"` // language to use: eg. de, en, or fr
|
||||
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
|
||||
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
|
||||
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
|
||||
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
|
||||
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
|
||||
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
|
||||
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
|
||||
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
|
||||
LockPassword bool `json:"lockPassword"` // disable the user from changing their password
|
||||
DisableSettings bool `json:"disableSettings,omitempty"` // disable the user from viewing the settings page
|
||||
Preview users.Preview `json:"preview"`
|
||||
DefaultScopes []users.SourceScope `json:"-"`
|
||||
Permissions users.Permissions `json:"permissions"`
|
||||
LoginMethod string `json:"loginMethod,omitempty"` // login method to use: eg. password, proxy, oidc
|
||||
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
|
||||
DarkMode bool `json:"darkMode"` // should dark mode be enabled
|
||||
Locale string `json:"locale"` // language to use: eg. de, en, or fr
|
||||
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
|
||||
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
|
||||
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
|
||||
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
|
||||
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
|
||||
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
|
||||
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
|
||||
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
|
||||
LockPassword bool `json:"lockPassword"` // disable the user from changing their password
|
||||
DisableSettings bool `json:"disableSettings,omitempty"` // disable the user from viewing the settings page
|
||||
Preview users.Preview `json:"preview"`
|
||||
DefaultScopes []users.SourceScope `json:"-"`
|
||||
Permissions users.Permissions `json:"permissions"`
|
||||
LoginMethod string `json:"loginMethod,omitempty"` // login method to use: eg. password, proxy, oidc
|
||||
DisableUpdateNotifications bool `json:"disableUpdateNotifications"` // disable update notifications banner for admin users
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/version"
|
||||
"github.com/gtsteffaniak/go-logger/logger"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
var updateAvailableUrl = ""
|
||||
|
||||
type Tag struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type updateInfo struct {
|
||||
LatestVersion string
|
||||
CurrentVersion string
|
||||
ReleaseNotes string
|
||||
ReleaseUrl string
|
||||
}
|
||||
|
||||
func CheckForUpdates() (updateInfo, error) {
|
||||
// --- Configuration ---
|
||||
repoOwner := "gtsteffaniak"
|
||||
repoName := "filebrowser"
|
||||
currentVersion := version.Version
|
||||
splitVersion := strings.Split(currentVersion, "-")
|
||||
versionCategory := "stable"
|
||||
if len(splitVersion) > 1 {
|
||||
versionCategory = splitVersion[1]
|
||||
}
|
||||
githubApiUrl := fmt.Sprintf("https://api.github.com/repos/%s/%s/tags", repoOwner, repoName)
|
||||
// Make the GET request
|
||||
resp, err := http.Get(githubApiUrl)
|
||||
if err != nil {
|
||||
return updateInfo{}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return updateInfo{}, fmt.Errorf("failed to fetch tags from GitHub API")
|
||||
}
|
||||
// Decode the JSON response
|
||||
var tags []Tag
|
||||
if err := json.NewDecoder(resp.Body).Decode(&tags); err != nil {
|
||||
return updateInfo{}, err
|
||||
}
|
||||
// Find the latest beta version greater than the current one
|
||||
var NewVersion string
|
||||
for _, tag := range tags {
|
||||
// Check if the version is valid, is a pre-release, and contains "beta"
|
||||
if semver.IsValid(tag.Name) && strings.Contains(semver.Prerelease(tag.Name), versionCategory) {
|
||||
// Check if this tag is greater than the current version
|
||||
// and also greater than any other beta version we've found so far
|
||||
if semver.Compare(tag.Name, currentVersion) > 0 {
|
||||
if NewVersion == "" || semver.Compare(tag.Name, NewVersion) > 0 {
|
||||
NewVersion = tag.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if NewVersion == "" {
|
||||
// No newer version found, return empty updateInfo
|
||||
return updateInfo{}, fmt.Errorf("no newer version found for %s", currentVersion)
|
||||
}
|
||||
|
||||
updateAvailableUrl = fmt.Sprintf("https://github.com/%s/%s/releases/tag/%s", repoOwner, repoName, NewVersion)
|
||||
return updateInfo{
|
||||
LatestVersion: NewVersion,
|
||||
CurrentVersion: currentVersion,
|
||||
ReleaseNotes: updateAvailableUrl,
|
||||
ReleaseUrl: updateAvailableUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func GetUpdateAvailableUrl() string {
|
||||
return updateAvailableUrl
|
||||
}
|
||||
|
||||
// starts a background process to check for updates periodically.
|
||||
func StartCheckForUpdates() {
|
||||
// Create a ticker that fires every 24 hours.
|
||||
ticker := time.NewTicker(24 * time.Hour)
|
||||
defer ticker.Stop()
|
||||
// Start a loop that waits for the ticker to fire.
|
||||
for range ticker.C {
|
||||
_, err := CheckForUpdates()
|
||||
if err != nil {
|
||||
// In a real application, you might want more sophisticated logging.
|
||||
logger.Debug("update check failed:", err)
|
||||
continue // Don't stop the loop, just wait for the next tick.
|
||||
}
|
||||
// Update the global variable with the result of the check.
|
||||
// This will be an empty string if no newer version was found.
|
||||
}
|
||||
}
|
||||
@@ -75,21 +75,22 @@ type SourceScope struct {
|
||||
|
||||
// json tags must match variable name with smaller case first letter
|
||||
type NonAdminEditable struct {
|
||||
Preview Preview `json:"preview"`
|
||||
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
|
||||
DarkMode bool `json:"darkMode"` // should dark mode be enabled
|
||||
Password string `json:"password,omitempty"`
|
||||
Locale string `json:"locale"` // language to use: eg. de, en, or fr
|
||||
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
|
||||
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
|
||||
Sorting Sorting `json:"sorting"`
|
||||
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
|
||||
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
|
||||
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
|
||||
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
|
||||
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
|
||||
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
|
||||
Preview Preview `json:"preview"`
|
||||
StickySidebar bool `json:"stickySidebar"` // keep sidebar open when navigating
|
||||
DarkMode bool `json:"darkMode"` // should dark mode be enabled
|
||||
Password string `json:"password,omitempty"`
|
||||
Locale string `json:"locale"` // language to use: eg. de, en, or fr
|
||||
ViewMode string `json:"viewMode"` // view mode to use: eg. normal, list, grid, or compact
|
||||
SingleClick bool `json:"singleClick"` // open directory on single click, also enables middle click to open in new tab
|
||||
Sorting Sorting `json:"sorting"`
|
||||
ShowHidden bool `json:"showHidden"` // show hidden files in the UI. On windows this includes files starting with a dot and windows hidden files
|
||||
DateFormat bool `json:"dateFormat"` // when false, the date is relative, when true, the date is an exact timestamp
|
||||
GallerySize int `json:"gallerySize"` // 0-9 - the size of the gallery thumbnails
|
||||
ThemeColor string `json:"themeColor"` // theme color to use: eg. #ff0000, or var(--red), var(--purple), etc
|
||||
QuickDownload bool `json:"quickDownload"` // show icon to download in one click
|
||||
DisableOnlyOfficeExt string `json:"disableOnlyOfficeExt"` // comma separated list of file extensions to disable onlyoffice preview for
|
||||
DisableOfficePreviewExt string `json:"disableOfficePreviewExt"` // comma separated list of file extensions to disable office preview for
|
||||
DisableUpdateNotifications bool `json:"disableUpdateNotifications"` // disable update notifications
|
||||
}
|
||||
|
||||
var PublicUser = User{
|
||||
|
||||
+66
-53
@@ -20,8 +20,8 @@ require (
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/swaggo/http-swagger v1.3.4
|
||||
github.com/swaggo/swag v1.16.4
|
||||
golang.org/x/crypto v0.38.0
|
||||
golang.org/x/image v0.27.0
|
||||
golang.org/x/crypto v0.39.0
|
||||
golang.org/x/image v0.28.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sys v0.33.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -32,55 +32,63 @@ require (
|
||||
4d63.com/gochecknoglobals v0.2.2 // indirect
|
||||
github.com/4meepo/tagalign v1.4.2 // indirect
|
||||
github.com/Abirdcfly/dupword v0.1.3 // indirect
|
||||
github.com/Antonboom/errname v1.0.0 // indirect
|
||||
github.com/Antonboom/nilnil v1.0.1 // indirect
|
||||
github.com/Antonboom/testifylint v1.5.2 // indirect
|
||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
|
||||
github.com/Crocmagnon/fatcontext v0.7.1 // indirect
|
||||
github.com/Antonboom/errname v1.1.0 // indirect
|
||||
github.com/Antonboom/nilnil v1.1.0 // indirect
|
||||
github.com/Antonboom/testifylint v1.6.1 // indirect
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
|
||||
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.3.1 // indirect
|
||||
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect
|
||||
github.com/alecthomas/chroma/v2 v2.17.2 // indirect
|
||||
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
|
||||
github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
|
||||
github.com/alexkohler/nakedret/v2 v2.0.6 // indirect
|
||||
github.com/alexkohler/prealloc v1.0.0 // indirect
|
||||
github.com/alingse/asasalint v0.0.11 // indirect
|
||||
github.com/alingse/nilnesserr v0.1.2 // indirect
|
||||
github.com/alingse/nilnesserr v0.2.0 // indirect
|
||||
github.com/ashanbrown/forbidigo v1.6.0 // indirect
|
||||
github.com/ashanbrown/makezero v1.2.0 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bkielbasa/cyclop v1.2.3 // indirect
|
||||
github.com/blizzy78/varnamelen v0.8.0 // indirect
|
||||
github.com/bombsimon/wsl/v4 v4.5.0 // indirect
|
||||
github.com/bombsimon/wsl/v4 v4.7.0 // indirect
|
||||
github.com/boombuler/barcode v1.0.2 // indirect
|
||||
github.com/breml/bidichk v0.3.2 // indirect
|
||||
github.com/breml/errchkjson v0.4.0 // indirect
|
||||
github.com/butuzov/ireturn v0.3.1 // indirect
|
||||
github.com/breml/bidichk v0.3.3 // indirect
|
||||
github.com/breml/errchkjson v0.4.1 // indirect
|
||||
github.com/butuzov/ireturn v0.4.0 // indirect
|
||||
github.com/butuzov/mirror v1.3.0 // indirect
|
||||
github.com/catenacyber/perfsprint v0.8.2 // indirect
|
||||
github.com/catenacyber/perfsprint v0.9.1 // indirect
|
||||
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charithe/durationcheck v0.0.10 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/ckaznocha/intrange v0.3.0 // indirect
|
||||
github.com/ckaznocha/intrange v0.3.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/curioswitch/go-reassign v0.3.0 // indirect
|
||||
github.com/daixiang0/gci v0.13.5 // indirect
|
||||
github.com/daixiang0/gci v0.13.6 // indirect
|
||||
github.com/dave/dst v0.27.3 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/denis-tingaikin/go-header v0.5.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.11.5 // 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/ebitengine/purego v0.8.4 // indirect
|
||||
github.com/ettle/strcase v0.2.0 // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/firefart/nonamedreturns v1.0.5 // indirect
|
||||
github.com/firefart/nonamedreturns v1.0.6 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.4 // indirect
|
||||
github.com/fzipp/gocyclo v0.6.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/ghostiam/protogetter v0.3.9 // indirect
|
||||
github.com/go-critic/go-critic v0.12.0 // indirect
|
||||
github.com/ghostiam/protogetter v0.3.15 // indirect
|
||||
github.com/go-critic/go-critic v0.13.0 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
|
||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
||||
@@ -101,16 +109,17 @@ require (
|
||||
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gofrs/flock v0.12.1 // indirect
|
||||
github.com/golang/geo v0.0.0-20250602202553-92e1c6cfbc31 // indirect
|
||||
github.com/golang/geo v0.0.0-20250613135800-9e8e59d779cc // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
|
||||
github.com/golangci/go-printf-func-name v0.1.0 // indirect
|
||||
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
|
||||
github.com/golangci/golangci-lint v1.64.8 // indirect
|
||||
github.com/golangci/golangci-lint/v2 v2.1.6 // indirect
|
||||
github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 // indirect
|
||||
github.com/golangci/misspell v0.6.0 // indirect
|
||||
github.com/golangci/plugin-module-register v0.1.1 // indirect
|
||||
github.com/golangci/revgrep v0.8.0 // indirect
|
||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
|
||||
github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect
|
||||
github.com/gordonklaus/ineffassign v0.1.0 // indirect
|
||||
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
|
||||
github.com/gostaticanalysis/comment v1.5.0 // indirect
|
||||
@@ -122,28 +131,30 @@ require (
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jgautheron/goconst v1.7.1 // indirect
|
||||
github.com/jgautheron/goconst v1.8.1 // indirect
|
||||
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
|
||||
github.com/jjti/go-spancheck v0.6.4 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/julz/importas v0.2.0 // indirect
|
||||
github.com/jupiterrider/ffi v0.4.1 // indirect
|
||||
github.com/jupiterrider/ffi v0.5.0 // indirect
|
||||
github.com/karamaru-alpha/copyloopvar v1.2.1 // indirect
|
||||
github.com/kisielk/errcheck v1.9.0 // indirect
|
||||
github.com/kkHAIKE/contextcheck v1.1.6 // indirect
|
||||
github.com/kulti/thelper v0.6.3 // indirect
|
||||
github.com/kunwardeep/paralleltest v1.0.10 // indirect
|
||||
github.com/kunwardeep/paralleltest v1.0.14 // indirect
|
||||
github.com/lasiar/canonicalheader v1.1.2 // indirect
|
||||
github.com/ldez/exptostd v0.4.2 // indirect
|
||||
github.com/ldez/exptostd v0.4.3 // indirect
|
||||
github.com/ldez/gomoddirectives v0.6.1 // indirect
|
||||
github.com/ldez/grignotin v0.9.0 // indirect
|
||||
github.com/ldez/tagliatelle v0.7.1 // indirect
|
||||
github.com/ldez/usetesting v0.4.2 // indirect
|
||||
github.com/ldez/usetesting v0.4.3 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/leonklingele/grouper v1.1.2 // indirect
|
||||
github.com/macabu/inamedparam v0.1.3 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/macabu/inamedparam v0.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/manuelarte/funcorder v0.2.1 // indirect
|
||||
github.com/maratori/testableexamples v1.0.0 // indirect
|
||||
github.com/maratori/testpackage v1.1.1 // indirect
|
||||
github.com/matoous/godox v1.1.0 // indirect
|
||||
@@ -151,25 +162,26 @@ require (
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mgechev/revive v1.7.0 // indirect
|
||||
github.com/mgechev/revive v1.9.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moricho/tparallel v0.3.2 // indirect
|
||||
github.com/muesli/termenv v0.16.0 // indirect
|
||||
github.com/nakabonne/nestif v0.3.1 // indirect
|
||||
github.com/nishanths/exhaustive v0.12.0 // indirect
|
||||
github.com/nishanths/predeclared v0.2.2 // indirect
|
||||
github.com/nunnatsa/ginkgolinter v0.19.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.2.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polyfloyd/go-errorlint v1.7.1 // indirect
|
||||
github.com/polyfloyd/go-errorlint v1.8.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // 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.4.3-0.20240823090925-0fe6f58b47b1 // indirect
|
||||
github.com/quasilyte/go-ruleguard v0.4.4 // indirect
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect
|
||||
github.com/quasilyte/gogrep v0.5.0 // indirect
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
|
||||
@@ -178,16 +190,15 @@ require (
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/ryancurrah/gomodguard v1.3.5 // indirect
|
||||
github.com/ryancurrah/gomodguard v1.4.1 // indirect
|
||||
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
|
||||
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
|
||||
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
|
||||
github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect
|
||||
github.com/securego/gosec/v2 v2.22.2 // indirect
|
||||
github.com/securego/gosec/v2 v2.22.3 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sivchari/containedctx v1.0.3 // indirect
|
||||
github.com/sivchari/tenv v1.12.1 // indirect
|
||||
github.com/sonatard/noctx v0.1.0 // indirect
|
||||
github.com/sourcegraph/go-diff v0.7.0 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
@@ -201,45 +212,47 @@ require (
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
github.com/swaggo/files v1.0.1 // indirect
|
||||
github.com/tdakkota/asciicheck v0.4.1 // indirect
|
||||
github.com/tetafro/godot v1.5.0 // indirect
|
||||
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect
|
||||
github.com/timonwong/loggercheck v0.10.1 // indirect
|
||||
github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect
|
||||
github.com/tetafro/godot v1.5.1 // indirect
|
||||
github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect
|
||||
github.com/timonwong/loggercheck v0.11.0 // indirect
|
||||
github.com/tomarrell/wrapcheck/v2 v2.11.0 // indirect
|
||||
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
|
||||
github.com/ultraware/funlen v0.2.0 // indirect
|
||||
github.com/ultraware/whitespace v0.2.0 // indirect
|
||||
github.com/urfave/cli/v2 v2.3.0 // indirect
|
||||
github.com/uudashr/gocognit v1.2.0 // indirect
|
||||
github.com/uudashr/iface v1.3.1 // indirect
|
||||
github.com/xen0n/gosmopolitan v1.2.2 // indirect
|
||||
github.com/xen0n/gosmopolitan v1.3.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/yagipy/maintidx v1.0.0 // indirect
|
||||
github.com/yeya24/promlinter v0.3.0 // indirect
|
||||
github.com/ykadowak/zerologlint v0.1.5 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
gitlab.com/bosi/decorder v0.4.2 // indirect
|
||||
go-simpler.org/musttag v0.13.0 // indirect
|
||||
go-simpler.org/sloglint v0.9.0 // indirect
|
||||
go.etcd.io/bbolt v1.4.0 // indirect
|
||||
go-simpler.org/musttag v0.13.1 // indirect
|
||||
go-simpler.org/sloglint v0.11.0 // indirect
|
||||
go.augendre.info/fatcontext v0.8.0 // indirect
|
||||
go.etcd.io/bbolt v1.4.1 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
golang.org/x/text v0.25.0 // indirect
|
||||
golang.org/x/tools v0.33.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
golang.org/x/mod v0.25.0 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sync v0.15.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/tools v0.34.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
honnef.co/go/tools v0.6.1 // indirect
|
||||
mvdan.cc/gofumpt v0.7.0 // indirect
|
||||
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
|
||||
mvdan.cc/gofumpt v0.8.0 // indirect
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
tool (
|
||||
github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
github.com/golangci/golangci-lint/v2/cmd/golangci-lint
|
||||
github.com/swaggo/swag/cmd/swag
|
||||
)
|
||||
+138
-112
@@ -39,18 +39,16 @@ github.com/4meepo/tagalign v1.4.2 h1:0hcLHPGMjDyM1gHG58cS73aQF8J4TdVR96TZViorO9E
|
||||
github.com/4meepo/tagalign v1.4.2/go.mod h1:+p4aMyFM+ra7nb41CnFG6aSDXqRxU/w1VQqScKqDARI=
|
||||
github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE=
|
||||
github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw=
|
||||
github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA=
|
||||
github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI=
|
||||
github.com/Antonboom/nilnil v1.0.1 h1:C3Tkm0KUxgfO4Duk3PM+ztPncTFlOf0b2qadmS0s4xs=
|
||||
github.com/Antonboom/nilnil v1.0.1/go.mod h1:CH7pW2JsRNFgEh8B2UaPZTEPhCMuFowP/e8Udp9Nnb0=
|
||||
github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk=
|
||||
github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8=
|
||||
github.com/Antonboom/errname v1.1.0 h1:A+ucvdpMwlo/myWrkHEUEBWc/xuXdud23S8tmTb/oAE=
|
||||
github.com/Antonboom/errname v1.1.0/go.mod h1:O1NMrzgUcVBGIfi3xlVuvX8Q/VP/73sseCaAppfjqZw=
|
||||
github.com/Antonboom/nilnil v1.1.0 h1:jGxJxjgYS3VUUtOTNk8Z1icwT5ESpLH/426fjmQG+ng=
|
||||
github.com/Antonboom/nilnil v1.1.0/go.mod h1:b7sAlogQjFa1wV8jUW3o4PMzDVFLbTux+xnQdvzdcIE=
|
||||
github.com/Antonboom/testifylint v1.6.1 h1:6ZSytkFWatT8mwZlmRCHkWz1gPi+q6UBSbieji2Gj/o=
|
||||
github.com/Antonboom/testifylint v1.6.1/go.mod h1:k+nEkathI2NFjKO6HvwmSrbzUcQ6FAnbZV+ZRrnXPLI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
|
||||
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Crocmagnon/fatcontext v0.7.1 h1:SC/VIbRRZQeQWj/TcQBS6JmrXcfA+BU4OGSVUt54PjM=
|
||||
github.com/Crocmagnon/fatcontext v0.7.1/go.mod h1:1wMvv3NXEBJucFGfwOJBxSVWcoIO6emV215SMkW9MFU=
|
||||
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
|
||||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM=
|
||||
@@ -59,14 +57,16 @@ github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1 h1:Sz1JIXEcSfhz7fUi7xHnh
|
||||
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.1/go.mod h1:n/LSCXNuIYqVfBlVXyHfMQkZDdp1/mmxfSjADd3z1Zg=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
|
||||
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
|
||||
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
|
||||
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4=
|
||||
github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo=
|
||||
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwvZMJY1tzqBvQgpaZiQRuIDD40jM=
|
||||
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.17.2 h1:Rm81SCZ2mPoH+Q8ZCc/9YvzPUN/E7HgPiPJD8SLV6GI=
|
||||
github.com/alecthomas/chroma/v2 v2.17.2/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk=
|
||||
github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU=
|
||||
github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E=
|
||||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
|
||||
@@ -76,20 +76,22 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
||||
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/nakedret/v2 v2.0.5 h1:fP5qLgtwbx9EJE8dGEERT02YwS8En4r9nnZ71RK+EVU=
|
||||
github.com/alexkohler/nakedret/v2 v2.0.5/go.mod h1:bF5i0zF2Wo2o4X4USt9ntUWve6JbFv02Ff4vlkmS/VU=
|
||||
github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ=
|
||||
github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q=
|
||||
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/alingse/nilnesserr v0.1.2 h1:Yf8Iwm3z2hUUrP4muWfW83DF4nE3r1xZ26fGWUKCZlo=
|
||||
github.com/alingse/nilnesserr v0.1.2/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg=
|
||||
github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w=
|
||||
github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg=
|
||||
github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac=
|
||||
github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0=
|
||||
github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY=
|
||||
github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
|
||||
github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU=
|
||||
github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
@@ -100,21 +102,21 @@ github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5
|
||||
github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo=
|
||||
github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
|
||||
github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
|
||||
github.com/bombsimon/wsl/v4 v4.5.0 h1:iZRsEvDdyhd2La0FVi5k6tYehpOR/R7qIUjmKk7N74A=
|
||||
github.com/bombsimon/wsl/v4 v4.5.0/go.mod h1:NOQ3aLF4nD7N5YPXMruR6ZXDOAqLoM0GEpLwTdvmOSc=
|
||||
github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ=
|
||||
github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
|
||||
github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs=
|
||||
github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos=
|
||||
github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk=
|
||||
github.com/breml/errchkjson v0.4.0/go.mod h1:AuBOSTHyLSaaAFlWsRSuRBIroCh3eh7ZHh5YeelDIk8=
|
||||
github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY=
|
||||
github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M=
|
||||
github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE=
|
||||
github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE=
|
||||
github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg=
|
||||
github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s=
|
||||
github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E=
|
||||
github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70=
|
||||
github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc=
|
||||
github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI=
|
||||
github.com/catenacyber/perfsprint v0.8.2 h1:+o9zVmCSVa7M4MvabsWvESEhpsMkhfE7k0sHNGL95yw=
|
||||
github.com/catenacyber/perfsprint v0.8.2/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM=
|
||||
github.com/catenacyber/perfsprint v0.9.1 h1:5LlTp4RwTooQjJCvGEFV6XksZvWE7wCOUvjD2z0vls0=
|
||||
github.com/catenacyber/perfsprint v0.9.1/go.mod h1:q//VWC2fWbcdSLEY1R3l8n0zQCDPdE4IjZwyY1HMunM=
|
||||
github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
|
||||
github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
@@ -124,13 +126,23 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charithe/durationcheck v0.0.10 h1:wgw73BiocdBDQPik+zcEoBG/ob8uyBHf2iyoHGPf5w4=
|
||||
github.com/charithe/durationcheck v0.0.10/go.mod h1:bCWXb7gYRysD1CU3C+u4ceO49LoGOY1C1L6uouGNreQ=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
||||
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
|
||||
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||
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/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY=
|
||||
github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo=
|
||||
github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs=
|
||||
github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk=
|
||||
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/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk=
|
||||
@@ -140,15 +152,19 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs=
|
||||
github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88=
|
||||
github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
|
||||
github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
|
||||
github.com/daixiang0/gci v0.13.6 h1:RKuEOSkGpSadkGbvZ6hJ4ddItT3cVZ9Vn9Rybk6xjl8=
|
||||
github.com/daixiang0/gci v0.13.6/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
|
||||
github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY=
|
||||
github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc=
|
||||
github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo=
|
||||
github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
|
||||
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.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
|
||||
github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY=
|
||||
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dsoprea/go-exif/v2 v2.0.0-20200321225314-640175a69fe4/go.mod h1:Lm2lMM2zx8p4a34ZemkaUV95AnMl4ZvLbCUbwOvLC2E=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20200717053412-08f1b6708903/go.mod h1:0nsO1ce0mh5czxGeLo4+OCZ/C6Eo6ZlMWsz7rH/Gxv8=
|
||||
github.com/dsoprea/go-exif/v3 v3.0.0-20210625224831-a6301f85c82b/go.mod h1:cg5SNYKHMmzxsr9X6ZeLh/nfBRHHp5PngtEPcujONtk=
|
||||
@@ -178,8 +194,8 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
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.5 h1:tM+Me2ZaXs8tfdDw3X6DOX++wMCOqzYUho6tUTYIdRA=
|
||||
github.com/firefart/nonamedreturns v1.0.5/go.mod h1:gHJjDqhGM4WyPt639SOZs+G89Ko7QKH5R5BhnO6xJhw=
|
||||
github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E=
|
||||
github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
|
||||
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
|
||||
@@ -190,10 +206,10 @@ github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBv
|
||||
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
|
||||
github.com/gen2brain/go-fitz v1.24.14 h1:09weRkjVtLYNGo7l0J7DyOwBExbwi8SJ9h8YPhw9WEo=
|
||||
github.com/gen2brain/go-fitz v1.24.14/go.mod h1:0KaZeQgASc20Yp5R/pFzyy7SmP01XcoHKNF842U2/S4=
|
||||
github.com/ghostiam/protogetter v0.3.9 h1:j+zlLLWzqLay22Cz/aYwTHKQ88GE2DQ6GkWSYFOI4lQ=
|
||||
github.com/ghostiam/protogetter v0.3.9/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
|
||||
github.com/go-critic/go-critic v0.12.0 h1:iLosHZuye812wnkEz1Xu3aBwn5ocCPfc9yqmFG9pa6w=
|
||||
github.com/go-critic/go-critic v0.12.0/go.mod h1:DpE0P6OVc6JzVYzmM5gq5jMU31zLr4am5mB/VfFK64w=
|
||||
github.com/ghostiam/protogetter v0.3.15 h1:1KF5sXel0HE48zh1/vn0Loiw25A9ApyseLzQuif1mLY=
|
||||
github.com/ghostiam/protogetter v0.3.15/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
|
||||
github.com/go-critic/go-critic v0.13.0 h1:kJzM7wzltQasSUXtYyTl6UaPVySO6GkaR1thFnJ6afY=
|
||||
github.com/go-critic/go-critic v0.13.0/go.mod h1:M/YeuJ3vOCQDnP2SU+ZhjgRzwzcBW87JqLpMJLrZDLI=
|
||||
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=
|
||||
@@ -272,10 +288,8 @@ github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w
|
||||
github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20200319012246-673a6f80352d/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20210211234256-740aa86cb551/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI=
|
||||
github.com/golang/geo v0.0.0-20250516193853-92f93c4cb289 h1:HeOFbnyPys/vx/t+d4fwZM782mnjRVtbjxVkDittTUs=
|
||||
github.com/golang/geo v0.0.0-20250516193853-92f93c4cb289/go.mod h1:Vaw7L5b+xa3Rj4/pRtrQkymn3lSBRB/NAEdbF9YEVLA=
|
||||
github.com/golang/geo v0.0.0-20250602202553-92e1c6cfbc31 h1:E1wdqK72/SVuxkxQ2DSE7YZEmcUZvExysw58zmkLKik=
|
||||
github.com/golang/geo v0.0.0-20250602202553-92e1c6cfbc31/go.mod h1:Vaw7L5b+xa3Rj4/pRtrQkymn3lSBRB/NAEdbF9YEVLA=
|
||||
github.com/golang/geo v0.0.0-20250613135800-9e8e59d779cc h1:HeTandKJybEWXv6wW9o3ybXTNqGGV4Q6kW3S+8RsXbk=
|
||||
github.com/golang/geo v0.0.0-20250613135800-9e8e59d779cc/go.mod h1:Vaw7L5b+xa3Rj4/pRtrQkymn3lSBRB/NAEdbF9YEVLA=
|
||||
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=
|
||||
@@ -314,15 +328,18 @@ github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywn
|
||||
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE=
|
||||
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY=
|
||||
github.com/golangci/golangci-lint v1.64.8 h1:y5TdeVidMtBGG32zgSC7ZXTFNHrsJkDnpO4ItB3Am+I=
|
||||
github.com/golangci/golangci-lint v1.64.8/go.mod h1:5cEsUQBSr6zi8XI8OjmcY2Xmliqc4iYL7YoPrL+zLJ4=
|
||||
github.com/golangci/golangci-lint/v2 v2.1.6 h1:LXqShFfAGM5BDzEOWD2SL1IzJAgUOqES/HRBsfKjI+w=
|
||||
github.com/golangci/golangci-lint/v2 v2.1.6/go.mod h1:EPj+fgv4TeeBq3TcqaKZb3vkiV5dP4hHHKhXhEhzci8=
|
||||
github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 h1:AkK+w9FZBXlU/xUmBtSJN1+tAI4FIvy5WtnUnY8e4p8=
|
||||
github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95/go.mod h1:k9mmcyWKSTMcPPvQUCfRWWQ9VHJ1U9Dc0R7kaXAgtnQ=
|
||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
||||
github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c=
|
||||
github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc=
|
||||
github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s=
|
||||
github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k=
|
||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNFP0hTEi1YKjB/ub8zkpaOqFFMApi2EAs=
|
||||
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ=
|
||||
github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM=
|
||||
github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc=
|
||||
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=
|
||||
@@ -393,8 +410,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk=
|
||||
github.com/jgautheron/goconst v1.7.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
|
||||
github.com/jgautheron/goconst v1.8.1 h1:PPqCYp3K/xlOj5JmIe6O1Mj6r1DbkdbLtR3AJuZo414=
|
||||
github.com/jgautheron/goconst v1.8.1/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako=
|
||||
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/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc=
|
||||
@@ -412,8 +429,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=
|
||||
github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY=
|
||||
github.com/jupiterrider/ffi v0.4.1 h1:Obg+xpuA+rRkRTEN7xu3IagjNDMO8fRUhOPpLEztPYI=
|
||||
github.com/jupiterrider/ffi v0.4.1/go.mod h1:Ba3hjU7Sz2+TO8HupjZwGssVnzo7RG3xF77byUBueB4=
|
||||
github.com/jupiterrider/ffi v0.5.0 h1:j2nSgpabbV1JOwgP4Kn449sJUHq3cVLAZVBoOYn44V8=
|
||||
github.com/jupiterrider/ffi v0.5.0/go.mod h1:x7xdNKo8h0AmLuXfswDUBxUsd2OqUP4ekC8sCnsmbvo=
|
||||
github.com/karamaru-alpha/copyloopvar v1.2.1 h1:wmZaZYIjnJ0b5UoKDjUHrikcV0zuPyyxI4SVplLd2CI=
|
||||
github.com/karamaru-alpha/copyloopvar v1.2.1/go.mod h1:nFmMlFNlClC2BPvNaHMdkirmTJxVCY0lhxBtlfOypMM=
|
||||
github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M=
|
||||
@@ -435,30 +452,34 @@ 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.10 h1:wrodoaKYzS2mdNVnc4/w31YaXFtsc21PCTdvWJ/lDDs=
|
||||
github.com/kunwardeep/paralleltest v1.0.10/go.mod h1:2C7s65hONVqY7Q5Efj5aLzRCNLjw2h4eMc9EcypGjcY=
|
||||
github.com/kunwardeep/paralleltest v1.0.14 h1:wAkMoMeGX/kGfhQBPODT/BL8XhK23ol/nuQ3SwFaUw8=
|
||||
github.com/kunwardeep/paralleltest v1.0.14/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk=
|
||||
github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4=
|
||||
github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI=
|
||||
github.com/ldez/exptostd v0.4.2 h1:l5pOzHBz8mFOlbcifTxzfyYbgEmoUqjxLFHZkjlbHXs=
|
||||
github.com/ldez/exptostd v0.4.2/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ=
|
||||
github.com/ldez/exptostd v0.4.3 h1:Ag1aGiq2epGePuRJhez2mzOpZ8sI9Gimcb4Sb3+pk9Y=
|
||||
github.com/ldez/exptostd v0.4.3/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ=
|
||||
github.com/ldez/gomoddirectives v0.6.1 h1:Z+PxGAY+217f/bSGjNZr/b2KTXcyYLgiWI6geMBN2Qc=
|
||||
github.com/ldez/gomoddirectives v0.6.1/go.mod h1:cVBiu3AHR9V31em9u2kwfMKD43ayN5/XDgr+cdaFaKs=
|
||||
github.com/ldez/grignotin v0.9.0 h1:MgOEmjZIVNn6p5wPaGp/0OKWyvq42KnzAt/DAb8O4Ow=
|
||||
github.com/ldez/grignotin v0.9.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk=
|
||||
github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk=
|
||||
github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I=
|
||||
github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA=
|
||||
github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ=
|
||||
github.com/ldez/usetesting v0.4.3 h1:pJpN0x3fMupdTf/IapYjnkhiY1nSTN+pox1/GyBRw3k=
|
||||
github.com/ldez/usetesting v0.4.3/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
|
||||
github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
|
||||
github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk=
|
||||
github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE=
|
||||
github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U=
|
||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
|
||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/manuelarte/funcorder v0.2.1 h1:7QJsw3qhljoZ5rH0xapIvjw31EcQeFbF31/7kQ/xS34=
|
||||
github.com/manuelarte/funcorder v0.2.1/go.mod h1:BQQ0yW57+PF9ZpjpeJDKOffEsQbxDFKW8F8zSMe/Zd0=
|
||||
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.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
|
||||
@@ -476,8 +497,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
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/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY=
|
||||
github.com/mgechev/revive v1.7.0/go.mod h1:qZnwcNhoguE58dfi96IJeSTPeZQejNeoMQLUZGi4SW4=
|
||||
github.com/mgechev/revive v1.9.0 h1:8LaA62XIKrb8lM6VsBSQ92slt/o92z5+hTw3CmrvSrM=
|
||||
github.com/mgechev/revive v1.9.0/go.mod h1:LAPq3+MgOf7GcL5PlWIkHb0PT7XH4NuC2LdWymhb9Mo=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
@@ -489,6 +510,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI=
|
||||
github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U=
|
||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
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=
|
||||
@@ -501,10 +524,10 @@ github.com/nunnatsa/ginkgolinter v0.19.1 h1:mjwbOlDQxZi9Cal+KfbEJTCz327OLNfwNvoZ
|
||||
github.com/nunnatsa/ginkgolinter v0.19.1/go.mod h1:jkQ3naZDmxaZMXPWaS9rblH+i+GWXQCaS/JFIWcOH2s=
|
||||
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.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
|
||||
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
|
||||
github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
|
||||
github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
|
||||
github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
|
||||
github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
|
||||
github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w=
|
||||
@@ -514,16 +537,16 @@ github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT9
|
||||
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.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
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/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.7.1 h1:RyLVXIbosq1gBdk/pChWA8zWYLsq9UEw7a1L5TVMCnA=
|
||||
github.com/polyfloyd/go-errorlint v1.7.1/go.mod h1:aXjNb1x2TNhoLsk26iv1yl7a+zTnXPhwEMtEXukiLR8=
|
||||
github.com/polyfloyd/go-errorlint v1.8.0 h1:DL4RestQqRLr8U4LygLw8g2DX6RN1eBJOpa2mzsrl1Q=
|
||||
github.com/polyfloyd/go-errorlint v1.8.0/go.mod h1:G2W0Q5roxbLCt0ZQbdoxQxXktTjwNyDbEaj3n7jvl4s=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
|
||||
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
||||
@@ -552,8 +575,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
||||
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.4.3-0.20240823090925-0fe6f58b47b1 h1:+Wl/0aFp0hpuHM3H//KMft64WQ1yX9LdJY64Qm/gFCo=
|
||||
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1/go.mod h1:GJLgqsLeo4qgavUoL8JeGFNS7qcisx3awV/w9eWTmNI=
|
||||
github.com/quasilyte/go-ruleguard v0.4.4 h1:53DncefIeLX3qEpjzlS1lyUmQoUEeOWPFWqaTJq9eAQ=
|
||||
github.com/quasilyte/go-ruleguard v0.4.4/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE=
|
||||
github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
|
||||
github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo=
|
||||
@@ -573,8 +596,8 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryancurrah/gomodguard v1.3.5 h1:cShyguSwUEeC0jS7ylOiG/idnd1TpJ1LfHGpV3oJmPU=
|
||||
github.com/ryancurrah/gomodguard v1.3.5/go.mod h1:MXlEPQRxgfPQa62O8wzK3Ozbkv9Rkqr+wKjSxTdsNJE=
|
||||
github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g=
|
||||
github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I=
|
||||
github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU=
|
||||
github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ=
|
||||
github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0=
|
||||
@@ -585,8 +608,10 @@ github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tM
|
||||
github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
|
||||
github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ=
|
||||
github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
|
||||
github.com/securego/gosec/v2 v2.22.2 h1:IXbuI7cJninj0nRpZSLCUlotsj8jGusohfONMrHoF6g=
|
||||
github.com/securego/gosec/v2 v2.22.2/go.mod h1:UEBGA+dSKb+VqM6TdehR7lnQtIIMorYJ4/9CW1KVQBE=
|
||||
github.com/securego/gosec/v2 v2.22.3 h1:mRrCNmRF2NgZp4RJ8oJ6yPJ7G4x6OCiAXHd8x4trLRc=
|
||||
github.com/securego/gosec/v2 v2.22.3/go.mod h1:42M9Xs0v1WseinaB/BmNGO8AVqG8vRfhC2686ACY48k=
|
||||
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
|
||||
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
@@ -599,8 +624,6 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE=
|
||||
github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4=
|
||||
github.com/sivchari/tenv v1.12.1 h1:+E0QzjktdnExv/wwsnnyk4oqZBUfuh89YMQT1cyuvSY=
|
||||
github.com/sivchari/tenv v1.12.1/go.mod h1:1LjSOUCc25snIr5n3DtGGrENhX3LuWefcplwVGC24mw=
|
||||
github.com/sonatard/noctx v0.1.0 h1:JjqOc2WN16ISWAjAk8M5ej0RfExEXtkEyExl2hLW+OM=
|
||||
github.com/sonatard/noctx v0.1.0/go.mod h1:0RvBxqY8D4j9cTTTWE8ylt2vqj2EPI8fHmrxHdsaZ2c=
|
||||
github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
|
||||
@@ -652,14 +675,14 @@ 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.5.0 h1:aNwfVI4I3+gdxjMgYPus9eHmoBeJIbnajOyqZYStzuw=
|
||||
github.com/tetafro/godot v1.5.0/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
|
||||
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 h1:y4mJRFlM6fUyPhoXuFg/Yu02fg/nIPFMOY8tOqppoFg=
|
||||
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460=
|
||||
github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg=
|
||||
github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=
|
||||
github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg=
|
||||
github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
|
||||
github.com/tetafro/godot v1.5.1 h1:PZnjCol4+FqaEzvZg5+O8IY2P3hfY9JzRBNPv1pEDS4=
|
||||
github.com/tetafro/godot v1.5.1/go.mod h1:cCdPtEndkmqqrhiCfkmxDodMQJ/f3L1BCNskCUZdTwk=
|
||||
github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk=
|
||||
github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460=
|
||||
github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M=
|
||||
github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=
|
||||
github.com/tomarrell/wrapcheck/v2 v2.11.0 h1:BJSt36snX9+4WTIXeJ7nvHBQBcm1h2SjQMSlmQ6aFSU=
|
||||
github.com/tomarrell/wrapcheck/v2 v2.11.0/go.mod h1:wFL9pDWDAbXhhPZZt+nG8Fu+h29TtnZ2MW6Lx4BRXIU=
|
||||
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.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI=
|
||||
@@ -674,8 +697,10 @@ github.com/uudashr/iface v1.3.1 h1:bA51vmVx1UIhiIsQFSNq6GZ6VPTk3WNMZgRiCe9R29U=
|
||||
github.com/uudashr/iface v1.3.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||
github.com/xen0n/gosmopolitan v1.2.2 h1:/p2KTnMzwRexIW8GlKawsTWOxn7UHA+jCMF/V8HHtvU=
|
||||
github.com/xen0n/gosmopolitan v1.2.2/go.mod h1:7XX7Mj61uLYrj0qmeN0zi7XDon9JRAEhYQqAPLVNTeg=
|
||||
github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM=
|
||||
github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
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.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs=
|
||||
@@ -695,13 +720,15 @@ gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo=
|
||||
gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8=
|
||||
go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ=
|
||||
go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28=
|
||||
go-simpler.org/musttag v0.13.0 h1:Q/YAW0AHvaoaIbsPj3bvEI5/QFP7w696IMUpnKXQfCE=
|
||||
go-simpler.org/musttag v0.13.0/go.mod h1:FTzIGeK6OkKlUDVpj0iQUXZLUO1Js9+mvykDQy9C5yM=
|
||||
go-simpler.org/sloglint v0.9.0 h1:/40NQtjRx9txvsB/RN022KsUJU+zaaSb/9q9BSefSrE=
|
||||
go-simpler.org/sloglint v0.9.0/go.mod h1:G/OrAF6uxj48sHahCzrbarVMptL2kjWTaUeC8+fOGww=
|
||||
go-simpler.org/musttag v0.13.1 h1:lw2sJyu7S1X8lc8zWUAdH42y+afdcCnHhWpnkWvd6vU=
|
||||
go-simpler.org/musttag v0.13.1/go.mod h1:8r450ehpMLQgvpb6sg+hV5Ur47eH6olp/3yEanfG97k=
|
||||
go-simpler.org/sloglint v0.11.0 h1:JlR1X4jkbeaffiyjLtymeqmGDKBDO1ikC6rjiuFAOco=
|
||||
go-simpler.org/sloglint v0.11.0/go.mod h1:CFDO8R1i77dlciGfPEPvYke2ZMx4eyGiEIWkyeW2Pvw=
|
||||
go.augendre.info/fatcontext v0.8.0 h1:2dfk6CQbDGeu1YocF59Za5Pia7ULeAM6friJ3LP7lmk=
|
||||
go.augendre.info/fatcontext v0.8.0/go.mod h1:oVJfMgwngMsHO+KB2MdgzcO+RvtNdiCEOlWvSFtax/s=
|
||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
|
||||
go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
|
||||
go.etcd.io/bbolt v1.4.1 h1:5mOV+HWjIPLEAlUGMsveaUvK2+byZMFOzojoi7bh7uI=
|
||||
go.etcd.io/bbolt v1.4.1/go.mod h1:c8zu2BnXWTu2XM4XcICtbGSl9cFwsXtcf9zLt2OncM8=
|
||||
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=
|
||||
@@ -726,8 +753,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
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=
|
||||
@@ -746,9 +773,8 @@ golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac h1:TSSpLIG4v+p0rP
|
||||
golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac/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/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.27.0 h1:C8gA4oWU/tKkdCfYT6T2u4faJu3MeNS5O8UPWlPF61w=
|
||||
golang.org/x/image v0.27.0/go.mod h1:xbdrClrAUway1MUTEZDq9mz/UpRwYAkFFNUslZtcB+g=
|
||||
golang.org/x/image v0.28.0 h1:gdem5JW1OLS4FbkWgLO+7ZeFzYtL3xClb97GaUzYMFE=
|
||||
golang.org/x/image v0.28.0/go.mod h1:GUJYXtnGKEUgggyzh+Vxt+AviiCcyiwpsl8iQ8MvwGY=
|
||||
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=
|
||||
@@ -776,8 +802,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
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=
|
||||
@@ -822,8 +848,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
|
||||
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
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=
|
||||
@@ -847,8 +873,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
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=
|
||||
@@ -929,8 +955,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
|
||||
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
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=
|
||||
@@ -990,8 +1016,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
|
||||
golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc=
|
||||
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
|
||||
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
|
||||
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
|
||||
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=
|
||||
@@ -1073,8 +1099,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
||||
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.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
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=
|
||||
@@ -1105,10 +1131,10 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI=
|
||||
honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4=
|
||||
mvdan.cc/gofumpt v0.7.0 h1:bg91ttqXmi9y2xawvkuMXyvAA/1ZGJqYAEGjXuP0JXU=
|
||||
mvdan.cc/gofumpt v0.7.0/go.mod h1:txVFJy/Sc/mvaycET54pV8SW8gWxTlUuGHVEcncmNUo=
|
||||
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f h1:lMpcwN6GxNbWtbpI1+xzFLSW8XzX0u72NttUGVFjO3U=
|
||||
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f/go.mod h1:RSLa7mKKCNeTTMHBw5Hsy2rfJmd6O2ivt9Dw9ZqCQpQ=
|
||||
mvdan.cc/gofumpt v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
|
||||
mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg=
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8=
|
||||
mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4/go.mod h1:rthT7OuvRbaGcd5ginj6dA2oLE7YNlta9qhBNNdCaLE=
|
||||
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=
|
||||
|
||||
+11
-19
@@ -125,32 +125,15 @@ func oidcCallbackHandler(w http.ResponseWriter, r *http.Request, d *requestConte
|
||||
logger.Debugf("failed to verify ID token: %v. This might be expected, falling back to UserInfo endpoint.", err)
|
||||
// Verification failed, claimsFromIDToken remains false
|
||||
} else {
|
||||
var claims map[string]interface{}
|
||||
// Decode the ID token claims into a map to handle arbitrary structure
|
||||
// This is where the JWE unmarshalling error occurs if the token is encrypted
|
||||
if err := idToken.Claims(&claims); err != nil {
|
||||
if err := idToken.Claims(&userdata); err != nil {
|
||||
logger.Warningf("failed to decode ID token claims: %v. Falling back to UserInfo endpoint.", err)
|
||||
// Claims decoding failed, claimsFromIDToken remains false
|
||||
} else {
|
||||
// Successfully verified and decoded ID token claims
|
||||
logger.Debugf("ID Token verified and claims decoded: %+v", claims)
|
||||
logger.Debugf("ID Token verified and claims decoded: %+v", userdata)
|
||||
|
||||
// Populate userdata from ID token claims
|
||||
if name, ok := claims["name"].(string); ok {
|
||||
userdata.Name = name
|
||||
}
|
||||
if preferredUsername, ok := claims["preferred_username"].(string); ok {
|
||||
userdata.PreferredUsername = preferredUsername
|
||||
}
|
||||
if email, ok := claims["email"].(string); ok {
|
||||
userdata.Email = email
|
||||
}
|
||||
if sub, ok := claims["sub"].(string); ok {
|
||||
userdata.Sub = sub
|
||||
}
|
||||
if phone, ok := claims["phone_number"].(string); ok {
|
||||
userdata.Phone = phone
|
||||
}
|
||||
// Decide if we rely on ID token claims or still need UserInfo
|
||||
// Even if parsing succeeded, if essential claims are missing, use UserInfo
|
||||
switch oidcCfg.UserIdentifier {
|
||||
@@ -245,6 +228,15 @@ func loginWithOidcUser(w http.ResponseWriter, r *http.Request, username string,
|
||||
} else {
|
||||
return http.StatusForbidden, fmt.Errorf("user %s does not exist and createUser is disabled. Your admin needs to create your user before you can access this application", username)
|
||||
}
|
||||
} else {
|
||||
// update user admin perms
|
||||
if isAdmin != user.Permissions.Admin {
|
||||
user.Permissions.Admin = isAdmin
|
||||
err = store.Users.Update(user, true, "Permissions")
|
||||
if err != nil {
|
||||
logger.Warningf("failed to update oidc user %s admin permissions: %v", username, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if user.LoginMethod != users.LoginMethodOidc {
|
||||
logger.Warningf("user %s is not allowed to login with oidc authentication, bypassing and updating login method", user.Username)
|
||||
|
||||
+8
-9
@@ -44,12 +44,7 @@ func setContentDisposition(w http.ResponseWriter, r *http.Request, fileName stri
|
||||
// @Failure 500 {object} map[string]string "Internal server error"
|
||||
// @Router /api/raw [get]
|
||||
func rawHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (int, error) {
|
||||
encodedFiles := r.URL.Query().Get("files")
|
||||
// Decode the URL-encoded path
|
||||
files, err := url.QueryUnescape(encodedFiles)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, fmt.Errorf("invalid path encoding: %v", err)
|
||||
}
|
||||
files := r.URL.Query().Get("files")
|
||||
fileList := strings.Split(files, "||")
|
||||
return rawFilesHandler(w, r, d, fileList)
|
||||
}
|
||||
@@ -188,8 +183,9 @@ func rawFilesHandler(w http.ResponseWriter, r *http.Request, d *requestContext,
|
||||
|
||||
firstFileSource := splitFile[0]
|
||||
firstFilePath := splitFile[1]
|
||||
fileName := filepath.Base(firstFilePath)
|
||||
// decode url encoded source name
|
||||
var err error
|
||||
fileName := filepath.Base(firstFilePath)
|
||||
userscope := "/"
|
||||
if d.user.Username != "publicUser" {
|
||||
userscope, err = settings.GetScopeFromSourceName(d.user.Scopes, firstFileSource)
|
||||
@@ -323,11 +319,11 @@ func computeArchiveSize(fileList []string, d *requestContext) (int64, error) {
|
||||
}
|
||||
source := splitFile[0]
|
||||
path := splitFile[1]
|
||||
var err error
|
||||
idx := indexing.GetIndex(source)
|
||||
if idx == nil {
|
||||
return 0, fmt.Errorf("source %s is not available", source)
|
||||
}
|
||||
var err error
|
||||
userScope := "/"
|
||||
if d.user.Username != "publicUser" {
|
||||
userScope, err = settings.GetScopeFromSourceName(d.user.Scopes, source)
|
||||
@@ -342,7 +338,10 @@ func computeArchiveSize(fileList []string, d *requestContext) (int64, error) {
|
||||
indexPath := idx.MakeIndexPath(realPath)
|
||||
info, ok := idx.GetReducedMetadata(indexPath, isDir)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("failed to get metadata info for %s", path)
|
||||
info, err = idx.GetFsDirInfo(indexPath)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to get file info for %s : %v", path, err)
|
||||
}
|
||||
}
|
||||
estimatedSize += info.Size
|
||||
}
|
||||
|
||||
@@ -41,13 +41,6 @@ func resourceGetHandler(w http.ResponseWriter, r *http.Request, d *requestContex
|
||||
source := r.URL.Query().Get("source")
|
||||
if source == "" {
|
||||
source = config.Server.DefaultSource.Name
|
||||
} else {
|
||||
var err error
|
||||
// decode url encoded source name
|
||||
source, err = url.QueryUnescape(source)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, fmt.Errorf("invalid source encoding: %v", err)
|
||||
}
|
||||
}
|
||||
// Decode the URL-encoded path
|
||||
path, err := url.QueryUnescape(encodedPath)
|
||||
|
||||
@@ -60,13 +60,6 @@ func searchHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (i
|
||||
source := r.URL.Query().Get("source")
|
||||
if source == "" {
|
||||
source = config.Server.DefaultSource.Name
|
||||
} else {
|
||||
var err error
|
||||
// decode url encoded source name
|
||||
source, err = url.QueryUnescape(source)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, fmt.Errorf("invalid source encoding: %v", err)
|
||||
}
|
||||
}
|
||||
scope := r.URL.Query().Get("scope")
|
||||
unencodedScope, err := url.QueryUnescape(scope)
|
||||
@@ -85,11 +78,12 @@ func searchHandler(w http.ResponseWriter, r *http.Request, d *requestContext) (i
|
||||
return http.StatusForbidden, err
|
||||
}
|
||||
combinedPath := index.MakeIndexPath(filepath.Join(userscope, searchScope))
|
||||
combinedPath = strings.TrimSuffix(combinedPath, "/") + "/" // Ensure trailing slash
|
||||
// Perform the search using the provided query and user scope
|
||||
response := index.Search(query, combinedPath, sessionId)
|
||||
for i := range response {
|
||||
// Remove the user scope from the path
|
||||
response[i].Path = strings.TrimPrefix(response[i].Path, userscope)
|
||||
response[i].Path = strings.TrimPrefix(response[i].Path, combinedPath)
|
||||
if response[i].Path == "" {
|
||||
response[i].Path = "/"
|
||||
}
|
||||
|
||||
@@ -69,13 +69,6 @@ func shareGetHandler(w http.ResponseWriter, r *http.Request, d *requestContext)
|
||||
source := r.URL.Query().Get("source")
|
||||
if source == "" {
|
||||
source = settings.Config.Server.DefaultSource.Name
|
||||
} else {
|
||||
var err error
|
||||
// decode url encoded source name
|
||||
source, err = url.QueryUnescape(source)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, fmt.Errorf("invalid source encoding: %v", err)
|
||||
}
|
||||
}
|
||||
// Decode the URL-encoded path
|
||||
path, err := url.QueryUnescape(encodedPath)
|
||||
@@ -199,13 +192,6 @@ func sharePostHandler(w http.ResponseWriter, r *http.Request, d *requestContext)
|
||||
sourceName := r.URL.Query().Get("source")
|
||||
if sourceName == "" {
|
||||
sourceName = config.Server.DefaultSource.Name
|
||||
} else {
|
||||
var err error
|
||||
// decode url encoded source name
|
||||
sourceName, err = url.QueryUnescape(sourceName)
|
||||
if err != nil {
|
||||
return http.StatusBadRequest, fmt.Errorf("invalid source encoding: %v", err)
|
||||
}
|
||||
}
|
||||
source := config.Server.NameToSource[sourceName]
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"text/template"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/utils"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/version"
|
||||
)
|
||||
|
||||
@@ -59,6 +60,7 @@ func handleWithStaticData(w http.ResponseWriter, r *http.Request, file, contentT
|
||||
"PasswordAvailable": config.Auth.Methods.PasswordAuth.Enabled,
|
||||
"MediaAvailable": config.Integrations.Media.FfmpegPath != "",
|
||||
"MuPdfAvailable": config.Server.MuPdfAvailable,
|
||||
"UpdateAvailable": utils.GetUpdateAvailableUrl(),
|
||||
}
|
||||
|
||||
b, err := json.Marshal(data)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/utils"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/indexing/iteminfo"
|
||||
@@ -39,6 +40,7 @@ type Index struct {
|
||||
CurrentSchedule int `json:"-"`
|
||||
settings.Source `json:"-"`
|
||||
Directories map[string]*iteminfo.FileInfo `json:"-"`
|
||||
DirectoriesLedger map[string]bool `json:"-"`
|
||||
runningScannerCount int `json:"-"`
|
||||
SmartModifier time.Duration `json:"-"`
|
||||
FilesChangedDuringIndexing bool `json:"-"`
|
||||
@@ -66,34 +68,36 @@ func init() {
|
||||
func Initialize(source settings.Source, mock bool) {
|
||||
indexesMutex.Lock()
|
||||
newIndex := Index{
|
||||
mock: mock,
|
||||
Source: source,
|
||||
Directories: make(map[string]*iteminfo.FileInfo),
|
||||
mock: mock,
|
||||
Source: source,
|
||||
Directories: make(map[string]*iteminfo.FileInfo),
|
||||
DirectoriesLedger: make(map[string]bool),
|
||||
}
|
||||
newIndex.ReducedIndex = ReducedIndex{
|
||||
Status: "indexing",
|
||||
IdxName: source.Name,
|
||||
Assessment: "unknown",
|
||||
}
|
||||
indexes[newIndex.Source.Name] = &newIndex
|
||||
indexes[newIndex.Name] = &newIndex
|
||||
indexesMutex.Unlock()
|
||||
if !newIndex.Source.Config.Disabled {
|
||||
if !newIndex.Config.DisableIndexing {
|
||||
time.Sleep(time.Second)
|
||||
logger.Infof("initializing index: [%v]", newIndex.Source.Name)
|
||||
logger.Infof("initializing index: [%v]", newIndex.Name)
|
||||
newIndex.RunIndexing("/", false)
|
||||
go newIndex.setupIndexingScanners()
|
||||
} else {
|
||||
logger.Debug("indexing disabled for source: " + newIndex.Source.Name)
|
||||
newIndex.Status = "ready"
|
||||
logger.Debug("indexing disabled for source: " + newIndex.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Define a function to recursively index files and directories
|
||||
func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) error {
|
||||
realPath := strings.TrimRight(idx.Source.Path, "/") + adjustedPath
|
||||
realPath := strings.TrimRight(idx.Path, "/") + adjustedPath
|
||||
// Open the directory
|
||||
dir, err := os.Open(realPath)
|
||||
if err != nil {
|
||||
idx.RemoveDirectory(adjustedPath) // Remove, must have been deleted
|
||||
// must have been deleted
|
||||
return err
|
||||
}
|
||||
defer dir.Close()
|
||||
@@ -102,6 +106,21 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if excluded from indexing
|
||||
hidden := isHidden(dirInfo, idx.Path+adjustedPath)
|
||||
if idx.shouldSkip(dirInfo.IsDir(), hidden, adjustedPath) {
|
||||
logger.Debugf("skipping directory %s due to exclusion rules", adjustedPath)
|
||||
return errors.ErrNotIndexed
|
||||
}
|
||||
|
||||
// if indexing, mark the directory as valid and indexed.
|
||||
if recursive {
|
||||
// Prevent race conditions if scanning becomes concurrent in the future.
|
||||
idx.mu.Lock()
|
||||
idx.DirectoriesLedger[adjustedPath] = true
|
||||
idx.mu.Unlock()
|
||||
}
|
||||
combinedPath := adjustedPath + "/"
|
||||
if adjustedPath == "/" {
|
||||
combinedPath = "/"
|
||||
@@ -109,9 +128,9 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err
|
||||
// get whats currently in cache
|
||||
idx.mu.RLock()
|
||||
cacheDirItems := []iteminfo.ItemInfo{}
|
||||
modChange := true // default to true
|
||||
modChange := false
|
||||
cachedDir, exists := idx.Directories[adjustedPath]
|
||||
if exists && quick {
|
||||
if exists {
|
||||
modChange = dirInfo.ModTime() != cachedDir.ModTime
|
||||
cacheDirItems = cachedDir.Folders
|
||||
}
|
||||
@@ -119,48 +138,107 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err
|
||||
|
||||
// If the directory has not been modified since the last index, skip expensive readdir
|
||||
// recursively check cached dirs for mod time changes as well
|
||||
if !modChange && recursive {
|
||||
for _, item := range cacheDirItems {
|
||||
err = idx.indexDirectory(combinedPath+item.Name, quick, true)
|
||||
if err != nil {
|
||||
logger.Errorf("error indexing directory %v : %v", combinedPath+item.Name, err)
|
||||
if recursive {
|
||||
if modChange {
|
||||
idx.mu.Lock()
|
||||
idx.FilesChangedDuringIndexing = true
|
||||
idx.mu.Unlock()
|
||||
} else if quick {
|
||||
for _, item := range cacheDirItems {
|
||||
err = idx.indexDirectory(combinedPath+item.Name, quick, true)
|
||||
if err != nil && err != errors.ErrNotIndexed {
|
||||
logger.Errorf("error indexing directory %v : %v", combinedPath+item.Name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
dirFileInfo, err2 := idx.GetDirInfo(dir, dirInfo, realPath, adjustedPath, combinedPath, quick, recursive)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
// Update the current directory metadata in the index
|
||||
idx.UpdateMetadata(dirFileInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (idx *Index) GetFsDirInfo(adjustedPath string) (*iteminfo.FileInfo, error) {
|
||||
realPath, isDir, err := idx.GetRealPath(adjustedPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
originalPath := realPath
|
||||
if !isDir {
|
||||
// get parent directory info
|
||||
realPath = filepath.Dir(realPath)
|
||||
}
|
||||
dir, err := os.Open(realPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dir.Close()
|
||||
|
||||
dirInfo, err := dir.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
combinedPath := adjustedPath + "/"
|
||||
if adjustedPath == "/" {
|
||||
combinedPath = "/"
|
||||
}
|
||||
var response *iteminfo.FileInfo
|
||||
response, err = idx.GetDirInfo(dir, dirInfo, realPath, adjustedPath, combinedPath, false, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isDir {
|
||||
baseName := filepath.Base(originalPath)
|
||||
idx.MakeIndexPath(realPath)
|
||||
found := false
|
||||
for _, item := range response.Files {
|
||||
if item.Name == baseName {
|
||||
response = &iteminfo.FileInfo{
|
||||
Path: adjustedPath + "/" + item.Name,
|
||||
ItemInfo: item,
|
||||
}
|
||||
found = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !found {
|
||||
return nil, fmt.Errorf("file not found in directory: %s", adjustedPath)
|
||||
}
|
||||
|
||||
if quick {
|
||||
idx.mu.Lock()
|
||||
idx.FilesChangedDuringIndexing = true
|
||||
idx.mu.Unlock()
|
||||
}
|
||||
return response, nil
|
||||
|
||||
}
|
||||
|
||||
func (idx *Index) GetDirInfo(dirInfo *os.File, stat os.FileInfo, realPath, adjustedPath, combinedPath string, quick, recursive bool) (*iteminfo.FileInfo, error) {
|
||||
// Read directory contents
|
||||
files, err := dir.Readdir(-1)
|
||||
files, err := dirInfo.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var totalSize int64
|
||||
fileInfos := []iteminfo.ItemInfo{}
|
||||
dirInfos := []iteminfo.ItemInfo{}
|
||||
|
||||
// Process each file and directory in the current directory
|
||||
for _, file := range files {
|
||||
isHidden := isHidden(file, idx.Source.Path+combinedPath)
|
||||
hidden := isHidden(file, idx.Path+combinedPath)
|
||||
isDir := iteminfo.IsDirectory(file)
|
||||
fullCombined := combinedPath + file.Name()
|
||||
if idx.shouldSkip(isDir, isHidden, fullCombined) {
|
||||
if idx.shouldSkip(isDir, hidden, fullCombined) && recursive {
|
||||
continue
|
||||
}
|
||||
itemInfo := &iteminfo.ItemInfo{
|
||||
Name: file.Name(),
|
||||
ModTime: file.ModTime(),
|
||||
Hidden: isHidden,
|
||||
Hidden: hidden,
|
||||
}
|
||||
|
||||
if isDir {
|
||||
|
||||
// skip non-indexable dirs.
|
||||
if file.Name() == "$RECYCLE.BIN" || file.Name() == "System Volume Information" {
|
||||
continue
|
||||
@@ -168,6 +246,8 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err
|
||||
|
||||
dirPath := combinedPath + file.Name()
|
||||
if recursive {
|
||||
// clear for garbage collection
|
||||
file = nil
|
||||
// Recursively index the subdirectory
|
||||
err = idx.indexDirectory(dirPath, quick, recursive)
|
||||
if err != nil {
|
||||
@@ -191,9 +271,11 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err
|
||||
idx.NumFiles++
|
||||
}
|
||||
}
|
||||
if totalSize == 0 && idx.Source.Config.IgnoreZeroSizeFolders {
|
||||
return nil
|
||||
|
||||
if totalSize == 0 && idx.Config.IgnoreZeroSizeFolders {
|
||||
return nil, errors.ErrNotIndexed
|
||||
}
|
||||
|
||||
// Create FileInfo for the current directory
|
||||
dirFileInfo := &iteminfo.FileInfo{
|
||||
Path: adjustedPath,
|
||||
@@ -201,16 +283,13 @@ func (idx *Index) indexDirectory(adjustedPath string, quick, recursive bool) err
|
||||
Folders: dirInfos,
|
||||
}
|
||||
dirFileInfo.ItemInfo = iteminfo.ItemInfo{
|
||||
Name: dirInfo.Name(),
|
||||
Name: filepath.Base(dirInfo.Name()),
|
||||
Type: "directory",
|
||||
Size: totalSize,
|
||||
ModTime: dirInfo.ModTime(),
|
||||
ModTime: stat.ModTime(),
|
||||
}
|
||||
|
||||
dirFileInfo.SortItems()
|
||||
// Update the current directory metadata in the index
|
||||
idx.UpdateMetadata(dirFileInfo)
|
||||
return nil
|
||||
return dirFileInfo, nil
|
||||
}
|
||||
|
||||
// input should be non-index path.
|
||||
@@ -218,12 +297,12 @@ func (idx *Index) MakeIndexPath(subPath string) string {
|
||||
if strings.HasPrefix(subPath, "./") {
|
||||
subPath = strings.TrimPrefix(subPath, ".")
|
||||
}
|
||||
if idx.Source.Path == subPath || subPath == "." {
|
||||
if idx.Path == subPath || subPath == "." {
|
||||
return "/"
|
||||
}
|
||||
// clean path
|
||||
subPath = strings.TrimSuffix(subPath, "/")
|
||||
adjustedPath := strings.TrimPrefix(subPath, idx.Source.Path)
|
||||
adjustedPath := strings.TrimPrefix(subPath, idx.Path)
|
||||
// remove index prefix
|
||||
adjustedPath = strings.ReplaceAll(adjustedPath, "\\", "/")
|
||||
// remove trailing slash
|
||||
@@ -247,7 +326,7 @@ func (idx *Index) recursiveUpdateDirSizes(childInfo *iteminfo.FileInfo, previous
|
||||
}
|
||||
|
||||
func (idx *Index) GetRealPath(relativePath ...string) (string, bool, error) {
|
||||
combined := append([]string{idx.Source.Path}, relativePath...)
|
||||
combined := append([]string{idx.Path}, relativePath...)
|
||||
joinedPath := filepath.Join(combined...)
|
||||
isDir, _ := RealPathCache.Get(joinedPath + ":isdir").(bool)
|
||||
cached, ok := RealPathCache.Get(joinedPath).(string)
|
||||
@@ -279,7 +358,7 @@ func (idx *Index) RefreshFileInfo(opts iteminfo.FileOptions) error {
|
||||
}
|
||||
err := idx.indexDirectory(refreshOptions.Path, false, false)
|
||||
if err != nil {
|
||||
return fmt.Errorf("file/folder does not exist to refresh data: %s", refreshOptions.Path)
|
||||
return err
|
||||
}
|
||||
file, exists := idx.GetMetadataInfo(refreshOptions.Path, true)
|
||||
if !exists {
|
||||
@@ -317,21 +396,24 @@ func isHidden(file os.FileInfo, srcPath string) bool {
|
||||
}
|
||||
|
||||
func (idx *Index) shouldSkip(isDir bool, isHidden bool, fullCombined string) bool {
|
||||
if idx.Config.DisableIndexing {
|
||||
return true
|
||||
}
|
||||
// check inclusions first
|
||||
if isDir && len(idx.Source.Config.Include.Folders) > 0 {
|
||||
if !slices.Contains(idx.Source.Config.Include.Folders, fullCombined) {
|
||||
if isDir && len(idx.Config.Include.Folders) > 0 {
|
||||
if !slices.Contains(idx.Config.Include.Folders, fullCombined) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if !isDir && len(idx.Source.Config.Include.Files) > 0 {
|
||||
if !slices.Contains(idx.Source.Config.Include.Files, fullCombined) {
|
||||
if !isDir && len(idx.Config.Include.Files) > 0 {
|
||||
if !slices.Contains(idx.Config.Include.Files, fullCombined) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if !isDir && len(idx.Source.Config.Include.FileEndsWith) > 0 {
|
||||
if !isDir && len(idx.Config.Include.FileEndsWith) > 0 {
|
||||
shouldSkip := true
|
||||
for _, end := range idx.Source.Config.Include.FileEndsWith {
|
||||
for _, end := range idx.Config.Include.FileEndsWith {
|
||||
if strings.HasSuffix(fullCombined, end) {
|
||||
shouldSkip = false
|
||||
break
|
||||
@@ -343,19 +425,19 @@ func (idx *Index) shouldSkip(isDir bool, isHidden bool, fullCombined string) boo
|
||||
}
|
||||
|
||||
// check exclusions
|
||||
if isDir && slices.Contains(idx.Source.Config.Exclude.Folders, fullCombined) {
|
||||
if isDir && slices.Contains(idx.Config.Exclude.Folders, fullCombined) {
|
||||
return true
|
||||
}
|
||||
if !isDir && slices.Contains(idx.Source.Config.Exclude.Files, fullCombined) {
|
||||
if !isDir && slices.Contains(idx.Config.Exclude.Files, fullCombined) {
|
||||
return true
|
||||
}
|
||||
if idx.Source.Config.IgnoreHidden && isHidden {
|
||||
if idx.Config.IgnoreHidden && isHidden {
|
||||
return true
|
||||
}
|
||||
|
||||
if !isDir && len(idx.Source.Config.Exclude.FileEndsWith) > 0 {
|
||||
if !isDir && len(idx.Config.Exclude.FileEndsWith) > 0 {
|
||||
shouldSkip := false
|
||||
for _, end := range idx.Source.Config.Exclude.FileEndsWith {
|
||||
for _, end := range idx.Config.Exclude.FileEndsWith {
|
||||
if strings.HasSuffix(fullCombined, end) {
|
||||
shouldSkip = true
|
||||
break
|
||||
@@ -378,13 +460,13 @@ func (idx *Index) SetUsage(usage DiskUsage) {
|
||||
}
|
||||
idx.mu.Lock()
|
||||
defer idx.mu.Unlock()
|
||||
idx.ReducedIndex.DiskUsed = int64(usage.Used)
|
||||
idx.ReducedIndex.DiskTotal = int64(usage.Total)
|
||||
idx.DiskUsed = int64(usage.Used)
|
||||
idx.DiskTotal = int64(usage.Total)
|
||||
}
|
||||
|
||||
func (idx *Index) SetStatus(status IndexStatus) {
|
||||
idx.mu.Lock()
|
||||
idx.ReducedIndex.Status = status
|
||||
idx.Status = status
|
||||
switch status {
|
||||
case INDEXING:
|
||||
idx.runningScannerCount++
|
||||
|
||||
@@ -9,15 +9,17 @@ import (
|
||||
)
|
||||
|
||||
// schedule in minutes
|
||||
var scanSchedule = []time.Duration{
|
||||
5 * time.Minute, // 5 minute quick scan & 25 minutes for a full scan
|
||||
10 * time.Minute,
|
||||
20 * time.Minute,
|
||||
40 * time.Minute, // [3] element is 40 minutes, reset anchor for full scan
|
||||
1 * time.Hour,
|
||||
2 * time.Hour,
|
||||
3 * time.Hour,
|
||||
4 * time.Hour, // 4 hours for quick scan & 20 hours for a full scan
|
||||
var scanSchedule = map[int]time.Duration{
|
||||
0: 5 * time.Minute, // 5 minute quick scan & 25 minutes for a full scan
|
||||
1: 10 * time.Minute,
|
||||
2: 20 * time.Minute,
|
||||
3: 40 * time.Minute, // reset anchor for full scan
|
||||
4: 1 * time.Hour,
|
||||
5: 2 * time.Hour,
|
||||
6: 3 * time.Hour, // [6]
|
||||
7: 4 * time.Hour, // [7] 4 hours for quick scan & 20 hours for a full scan
|
||||
8: 8 * time.Hour,
|
||||
9: 12 * time.Hour,
|
||||
}
|
||||
|
||||
var fullScanAnchor = 3 // index of the schedule for a full scan
|
||||
@@ -31,8 +33,8 @@ func (idx *Index) newScanner(origin string) {
|
||||
if idx.Assessment == "simple" {
|
||||
sleepTime = scanSchedule[idx.CurrentSchedule] - idx.SmartModifier
|
||||
}
|
||||
if idx.Source.Config.IndexingInterval > 0 {
|
||||
sleepTime = time.Duration(idx.Source.Config.IndexingInterval) * time.Minute
|
||||
if idx.Config.IndexingInterval > 0 {
|
||||
sleepTime = time.Duration(idx.Config.IndexingInterval) * time.Minute
|
||||
}
|
||||
// Log and sleep before indexing
|
||||
logger.Debugf("Next scan in %v", sleepTime)
|
||||
@@ -53,6 +55,7 @@ func (idx *Index) PreScan() {
|
||||
|
||||
func (idx *Index) PostScan() {
|
||||
idx.mu.Lock()
|
||||
idx.garbageCollection()
|
||||
idx.runningScannerCount--
|
||||
idx.mu.Unlock()
|
||||
if idx.runningScannerCount == 0 {
|
||||
@@ -60,6 +63,19 @@ func (idx *Index) PostScan() {
|
||||
}
|
||||
}
|
||||
|
||||
func (idx *Index) garbageCollection() {
|
||||
for path := range idx.Directories {
|
||||
_, ok := idx.DirectoriesLedger[path]
|
||||
if !ok {
|
||||
idx.Directories[path] = nil
|
||||
delete(idx.Directories, path)
|
||||
idx.NumDeleted++
|
||||
}
|
||||
}
|
||||
// Reset the ledger for the next scan.
|
||||
idx.DirectoriesLedger = make(map[string]bool)
|
||||
}
|
||||
|
||||
func (idx *Index) UpdateSchedule() {
|
||||
// Adjust schedule based on file changes
|
||||
if idx.FilesChangedDuringIndexing {
|
||||
@@ -109,13 +125,17 @@ func (idx *Index) SendSourceUpdateEvent() {
|
||||
}
|
||||
|
||||
func (idx *Index) RunIndexing(origin string, quick bool) {
|
||||
if idx.runningScannerCount > 0 {
|
||||
logger.Debugf("Indexing already in progress for [%v]", idx.Name)
|
||||
return
|
||||
}
|
||||
idx.PreScan()
|
||||
prevNumDirs := idx.NumDirs
|
||||
prevNumFiles := idx.NumFiles
|
||||
if quick {
|
||||
logger.Debugf("Starting quick scan for [%v]", idx.Source.Name)
|
||||
logger.Debugf("Starting quick scan for [%v]", idx.Name)
|
||||
} else {
|
||||
logger.Debugf("Starting full scan for [%v]", idx.Source.Name)
|
||||
logger.Debugf("Starting full scan for [%v]", idx.Name)
|
||||
idx.NumDirs = 0
|
||||
idx.NumFiles = 0
|
||||
}
|
||||
@@ -126,13 +146,13 @@ func (idx *Index) RunIndexing(origin string, quick bool) {
|
||||
if err != nil {
|
||||
logger.Errorf("Error during indexing: %v", err)
|
||||
}
|
||||
firstRun := idx.LastIndexed == time.Time{}
|
||||
firstRun := time.Time.Equal(idx.LastIndexed, time.Time{})
|
||||
// Update the LastIndexed time
|
||||
idx.LastIndexed = time.Now()
|
||||
idx.LastIndexedUnix = idx.LastIndexed.Unix()
|
||||
if quick {
|
||||
idx.QuickScanTime = int(time.Since(startTime).Seconds())
|
||||
logger.Debugf("Time spent indexing [%v]: %v seconds", idx.Source.Name, idx.QuickScanTime)
|
||||
logger.Debugf("Time spent indexing [%v]: %v seconds", idx.Name, idx.QuickScanTime)
|
||||
} else {
|
||||
idx.FullScanTime = int(time.Since(startTime).Seconds())
|
||||
// update smart indexing
|
||||
@@ -147,14 +167,14 @@ func (idx *Index) RunIndexing(origin string, quick bool) {
|
||||
idx.Assessment = "normal"
|
||||
}
|
||||
if firstRun {
|
||||
logger.Infof("Index assessment : [%v] complexity=%v directories=%v files=%v", idx.Source.Name, idx.Assessment, idx.NumDirs, idx.NumFiles)
|
||||
logger.Infof("Index assessment : [%v] complexity=%v directories=%v files=%v", idx.Name, idx.Assessment, idx.NumDirs, idx.NumFiles)
|
||||
} else {
|
||||
logger.Debugf("Index assessment : [%v] complexity=%v directories=%v files=%v", idx.Source.Name, idx.Assessment, idx.NumDirs, idx.NumFiles)
|
||||
logger.Debugf("Index assessment : [%v] complexity=%v directories=%v files=%v", idx.Name, idx.Assessment, idx.NumDirs, idx.NumFiles)
|
||||
}
|
||||
if idx.NumDirs != prevNumDirs || idx.NumFiles != prevNumFiles {
|
||||
idx.FilesChangedDuringIndexing = true
|
||||
}
|
||||
logger.Debugf("Time spent indexing [%v]: %v seconds", idx.Source.Name, idx.FullScanTime)
|
||||
logger.Debugf("Time spent indexing [%v]: %v seconds", idx.Name, idx.FullScanTime)
|
||||
}
|
||||
|
||||
idx.PostScan()
|
||||
|
||||
@@ -20,6 +20,17 @@ var AllFiletypeOptions = []string{
|
||||
"text",
|
||||
}
|
||||
|
||||
var SubtitleExts = []string{
|
||||
".vtt",
|
||||
".srt",
|
||||
".lrc",
|
||||
".sbv",
|
||||
".ass",
|
||||
".ssa",
|
||||
".sub",
|
||||
".smi",
|
||||
}
|
||||
|
||||
var MuPdfConvertable = []string{
|
||||
".pdf", // PDF
|
||||
".xps", // XPS
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package iteminfo
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -14,18 +15,17 @@ func (i *ExtendedFileInfo) DetectSubtitles(parentInfo *FileInfo) {
|
||||
logger.Debug("subtitles are not supported for this file : " + i.Name)
|
||||
return
|
||||
}
|
||||
|
||||
base := strings.Split(i.Name, ".")[0]
|
||||
ext := filepath.Ext(i.Name)
|
||||
baseWithoutExt := strings.TrimSuffix(i.Name, ext)
|
||||
for _, f := range parentInfo.Files {
|
||||
baseName := strings.Split(f.Name, ".")[0]
|
||||
if baseName != base {
|
||||
baseName := strings.TrimSuffix(i.Name, ext)
|
||||
if baseName != baseWithoutExt {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, subtitleExt := range []string{".vtt", ".srt", ".lrc", ".sbv", ".ass", ".ssa", ".sub", ".smi"} {
|
||||
for _, subtitleExt := range SubtitleExts {
|
||||
if strings.HasSuffix(f.Name, subtitleExt) {
|
||||
fullPathBase := strings.Split(i.Path, ".")[0]
|
||||
i.Subtitles = append(i.Subtitles, fullPathBase+subtitleExt)
|
||||
i.Subtitles = append(i.Subtitles, parentInfo.Path+f.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ func (idx *Index) UpdateMetadata(info *iteminfo.FileInfo) bool {
|
||||
|
||||
// GetMetadataInfo retrieves the FileInfo from the specified file or directory in the index.
|
||||
func (idx *Index) GetReducedMetadata(target string, isDir bool) (*iteminfo.FileInfo, bool) {
|
||||
idx.mu.Lock()
|
||||
defer idx.mu.Unlock()
|
||||
idx.mu.RLock()
|
||||
defer idx.mu.RUnlock()
|
||||
checkDir := idx.MakeIndexPath(target)
|
||||
if !isDir {
|
||||
checkDir = idx.MakeIndexPath(filepath.Dir(target))
|
||||
@@ -71,13 +71,6 @@ func (idx *Index) GetMetadataInfo(target string, isDir bool) (*iteminfo.FileInfo
|
||||
return dir, exists
|
||||
}
|
||||
|
||||
func (idx *Index) RemoveDirectory(path string) {
|
||||
idx.mu.Lock()
|
||||
defer idx.mu.Unlock()
|
||||
idx.NumDeleted++
|
||||
delete(idx.Directories, path)
|
||||
}
|
||||
|
||||
func GetIndex(name string) *Index {
|
||||
indexesMutex.Lock()
|
||||
defer indexesMutex.Unlock()
|
||||
|
||||
@@ -193,20 +193,6 @@ func TestSetDirectoryInfo(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Test for RemoveDirectory
|
||||
func TestRemoveDirectory(t *testing.T) {
|
||||
index := &Index{
|
||||
Directories: map[string]*iteminfo.FileInfo{
|
||||
"/testpath": {},
|
||||
},
|
||||
}
|
||||
index.RemoveDirectory("/testpath")
|
||||
_, exists := index.Directories["/testpath"]
|
||||
if exists {
|
||||
t.Fatalf("expected directory to be removed")
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
testIndex = Index{
|
||||
ReducedIndex: ReducedIndex{
|
||||
|
||||
@@ -37,12 +37,12 @@ func (idx *Index) Search(search string, scope string, sourceSession string) []Se
|
||||
results := make(map[string]SearchResult, 0)
|
||||
count := 0
|
||||
var directories []string
|
||||
cachedDirs, ok := SearchResultsCache.Get(idx.Source.Path + scope).([]string)
|
||||
cachedDirs, ok := SearchResultsCache.Get(idx.Path + scope).([]string)
|
||||
if ok {
|
||||
directories = cachedDirs
|
||||
} else {
|
||||
directories = idx.getDirsInScope(scope)
|
||||
SearchResultsCache.Set(idx.Source.Path+scope, directories)
|
||||
SearchResultsCache.Set(idx.Path+scope, directories)
|
||||
}
|
||||
for _, searchTerm := range searchOptions.Terms {
|
||||
if searchTerm == "" {
|
||||
|
||||
@@ -92,7 +92,7 @@ func GetPreviewForFile(file iteminfo.ExtendedFileInfo, previewSize, url string,
|
||||
if !AvailablePreview(file) {
|
||||
return nil, ErrUnsupportedMedia
|
||||
}
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime, seekPercentage)
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ModTime, seekPercentage)
|
||||
if data, found, err := service.fileCache.Load(context.Background(), cacheKey); err != nil {
|
||||
return nil, fmt.Errorf("failed to load from cache: %w", err)
|
||||
} else if found {
|
||||
@@ -110,7 +110,7 @@ func GeneratePreview(file iteminfo.ExtendedFileInfo, previewSize, officeUrl stri
|
||||
)
|
||||
// Generate thumbnail image from video
|
||||
hasher := md5.New() //nolint:gosec
|
||||
_, _ = hasher.Write([]byte(CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime, seekPercentage)))
|
||||
_, _ = hasher.Write([]byte(CacheKey(file.RealPath, previewSize, file.ModTime, seekPercentage)))
|
||||
hash := hex.EncodeToString(hasher.Sum(nil))
|
||||
// Generate an image from office document
|
||||
if iteminfo.HasDocConvertableExtension(file.Name, file.Type) {
|
||||
@@ -154,13 +154,13 @@ func GeneratePreview(file iteminfo.ExtendedFileInfo, previewSize, officeUrl stri
|
||||
return nil, fmt.Errorf("failed to resize preview image: %w", err)
|
||||
}
|
||||
// Cache and return
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime, seekPercentage)
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ModTime, seekPercentage)
|
||||
if err := service.fileCache.Store(context.Background(), cacheKey, resizedBytes); err != nil {
|
||||
logger.Errorf("failed to cache resized image: %v", err)
|
||||
}
|
||||
return resizedBytes, nil
|
||||
} else {
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ItemInfo.ModTime, seekPercentage)
|
||||
cacheKey := CacheKey(file.RealPath, previewSize, file.ModTime, seekPercentage)
|
||||
if err := service.fileCache.Store(context.Background(), cacheKey, imageBytes); err != nil {
|
||||
logger.Errorf("failed to cache resized image: %v", err)
|
||||
}
|
||||
@@ -202,9 +202,9 @@ func CacheKey(realPath, previewSize string, modTime time.Time, percentage int) s
|
||||
}
|
||||
|
||||
func DelThumbs(ctx context.Context, file iteminfo.ExtendedFileInfo) {
|
||||
errSmall := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "small", file.ItemInfo.ModTime, 0))
|
||||
errSmall := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "small", file.ModTime, 0))
|
||||
if errSmall != nil {
|
||||
errLarge := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "large", file.ItemInfo.ModTime, 0))
|
||||
errLarge := service.fileCache.Delete(ctx, CacheKey(file.RealPath, "large", file.ModTime, 0))
|
||||
if errLarge != nil {
|
||||
logger.Debugf("Could not delete thumbnail: %v", file.Name)
|
||||
}
|
||||
|
||||
@@ -2174,7 +2174,7 @@ const docTemplate = `{
|
||||
"description": "default \"/\" should match folders under path",
|
||||
"type": "string"
|
||||
},
|
||||
"disabled": {
|
||||
"disableIndexing": {
|
||||
"description": "disable the indexing of this source",
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -2202,7 +2202,7 @@ const docTemplate = `{
|
||||
}
|
||||
]
|
||||
},
|
||||
"indexingInterval": {
|
||||
"indexingIntervalMinutes": {
|
||||
"description": "optional manual overide interval in seconds to re-index the source",
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -2242,6 +2242,10 @@ const docTemplate = `{
|
||||
"description": "disable the user from viewing the settings page",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableUpdateNotifications": {
|
||||
"description": "disable update notifications banner for admin users",
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
@@ -2466,6 +2470,10 @@ const docTemplate = `{
|
||||
"disableSettings": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableUpdateNotifications": {
|
||||
"description": "disable update notifications",
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
|
||||
@@ -2163,7 +2163,7 @@
|
||||
"description": "default \"/\" should match folders under path",
|
||||
"type": "string"
|
||||
},
|
||||
"disabled": {
|
||||
"disableIndexing": {
|
||||
"description": "disable the indexing of this source",
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -2191,7 +2191,7 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"indexingInterval": {
|
||||
"indexingIntervalMinutes": {
|
||||
"description": "optional manual overide interval in seconds to re-index the source",
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -2231,6 +2231,10 @@
|
||||
"description": "disable the user from viewing the settings page",
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableUpdateNotifications": {
|
||||
"description": "disable update notifications banner for admin users",
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
@@ -2455,6 +2459,10 @@
|
||||
"disableSettings": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"disableUpdateNotifications": {
|
||||
"description": "disable update notifications",
|
||||
"type": "boolean"
|
||||
},
|
||||
"gallerySize": {
|
||||
"description": "0-9 - the size of the gallery thumbnails",
|
||||
"type": "integer"
|
||||
|
||||
@@ -410,7 +410,7 @@ definitions:
|
||||
defaultUserScope:
|
||||
description: default "/" should match folders under path
|
||||
type: string
|
||||
disabled:
|
||||
disableIndexing:
|
||||
description: disable the indexing of this source
|
||||
type: boolean
|
||||
exclude:
|
||||
@@ -427,7 +427,7 @@ definitions:
|
||||
allOf:
|
||||
- $ref: '#/definitions/settings.IndexFilter'
|
||||
description: include files and folders from indexing, if exclude is not set
|
||||
indexingInterval:
|
||||
indexingIntervalMinutes:
|
||||
description: optional manual overide interval in seconds to re-index the source
|
||||
type: integer
|
||||
maxWatchers:
|
||||
@@ -460,6 +460,9 @@ definitions:
|
||||
disableSettings:
|
||||
description: disable the user from viewing the settings page
|
||||
type: boolean
|
||||
disableUpdateNotifications:
|
||||
description: disable update notifications banner for admin users
|
||||
type: boolean
|
||||
gallerySize:
|
||||
description: 0-9 - the size of the gallery thumbnails
|
||||
type: integer
|
||||
@@ -624,6 +627,9 @@ definitions:
|
||||
type: string
|
||||
disableSettings:
|
||||
type: boolean
|
||||
disableUpdateNotifications:
|
||||
description: disable update notifications
|
||||
type: boolean
|
||||
gallerySize:
|
||||
description: 0-9 - the size of the gallery thumbnails
|
||||
type: integer
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
server:
|
||||
numImageProcessors: 14 # number of concurrent image processing jobs used to create previews, default is number of cpu cores available.
|
||||
numImageProcessors: 8 # number of concurrent image processing jobs used to create previews, default is number of cpu cores available.
|
||||
socket: "" # socket to listen on
|
||||
tlsKey: "" # path to TLS key
|
||||
tlsCert: "" # path to TLS cert
|
||||
@@ -21,8 +21,8 @@ server:
|
||||
- path: /relative/or/absolute/path # file system path. (Can be relative) validate:required
|
||||
name: backend # display name
|
||||
config:
|
||||
indexingInterval: 0 # optional manual overide interval in seconds to re-index the source
|
||||
disabled: false # disable the indexing of this source
|
||||
indexingIntervalMinutes: 0 # optional manual overide interval in seconds to re-index the source
|
||||
disableIndexing: false # disable the indexing of this source
|
||||
maxWatchers: 0 # number of concurrent watchers to use for this source, currently not supported
|
||||
neverWatchPaths: []
|
||||
ignoreHidden: false # ignore hidden files and folders.
|
||||
@@ -116,6 +116,7 @@ userDefaults:
|
||||
share: false
|
||||
realtime: false
|
||||
loginMethod: password # login method to use: eg. password, proxy, oidc
|
||||
disableUpdateNotifications: false # disable update notifications banner for admin users
|
||||
integrations:
|
||||
office: # validate:omitempty
|
||||
url: "" # The URL to the OnlyOffice Document Server, needs to be accessible to the user. validate:required
|
||||
|
||||
+10
-12
@@ -26,7 +26,7 @@ export async function fetchFiles(url, content = false) {
|
||||
async function resourceAction(url, method, content) {
|
||||
try {
|
||||
const result = extractSourceFromPath(url)
|
||||
let source = result.source
|
||||
let source = encodeURIComponent(result.source)
|
||||
let path = result.path
|
||||
let opts = { method }
|
||||
if (content) {
|
||||
@@ -69,14 +69,13 @@ export function download(format, files) {
|
||||
if (format !== 'zip') {
|
||||
format = 'tar.gz'
|
||||
}
|
||||
|
||||
let fileargs = ''
|
||||
if (files.length === 1) {
|
||||
const result = extractSourceFromPath(decodeURI(files[0]))
|
||||
const result = extractSourceFromPath(decodeURIComponent(files[0]))
|
||||
fileargs = result.source + '::' + result.path + '||'
|
||||
} else {
|
||||
for (let file of files) {
|
||||
const result = extractSourceFromPath(decodeURI(file))
|
||||
const result = extractSourceFromPath(decodeURIComponent(file))
|
||||
fileargs += result.source + '::' + result.path + '||'
|
||||
}
|
||||
}
|
||||
@@ -110,7 +109,7 @@ export async function post(url, content = '', overwrite = false, onupload) {
|
||||
|
||||
const apiPath = getApiPath('api/resources', {
|
||||
path: result.path,
|
||||
source: result.source,
|
||||
source: encodeURIComponent(result.source),
|
||||
override: overwrite
|
||||
})
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -164,7 +163,7 @@ export async function moveCopy(
|
||||
const toResult = extractSourceFromPath(item.to)
|
||||
let localParams = {
|
||||
...params,
|
||||
destination: toResult.source + '::' + toResult.path,
|
||||
destination: encodeURIComponent(toResult.source) + '::' + toResult.path,
|
||||
from: fromResult.source + '::' + fromResult.path
|
||||
}
|
||||
const apiPath = getApiPath('api/resources', localParams)
|
||||
@@ -189,12 +188,11 @@ export async function moveCopy(
|
||||
}
|
||||
}
|
||||
|
||||
export async function checksum(url, algo) {
|
||||
export async function checksum(source, path, algo) {
|
||||
try {
|
||||
const result = extractSourceFromPath(url)
|
||||
const params = {
|
||||
path: encodeURIComponent(result.path),
|
||||
source: result.source,
|
||||
path: encodeURIComponent(path),
|
||||
source: encodeURIComponent(source),
|
||||
checksum: algo
|
||||
}
|
||||
const apiPath = getApiPath('api/resources', params)
|
||||
@@ -210,7 +208,7 @@ export async function checksum(url, algo) {
|
||||
export function getDownloadURL(source, path, inline, useExternal) {
|
||||
try {
|
||||
const params = {
|
||||
files: source + '::' + encodeURIComponent(path),
|
||||
files: encodeURIComponent(source) + '::' + encodeURIComponent(path),
|
||||
...(inline && { inline: 'true' })
|
||||
}
|
||||
const apiPath = getApiPath('api/raw', params)
|
||||
@@ -230,7 +228,7 @@ export function getPreviewURL(source, path, modified) {
|
||||
const params = {
|
||||
path: encodeURIComponent(path),
|
||||
key: Date.parse(modified), // Use modified date as cache key
|
||||
source: source,
|
||||
source: encodeURIComponent(source),
|
||||
inline: 'true'
|
||||
}
|
||||
const apiPath = getApiPath('api/preview', params)
|
||||
|
||||
@@ -8,7 +8,7 @@ export default async function search(base, source, query) {
|
||||
if (!base.endsWith("/")) {
|
||||
base += "/";
|
||||
}
|
||||
const apiPath = getApiPath("api/search", { scope: encodeURIComponent(base), query: query, source: source });
|
||||
const apiPath = getApiPath("api/search", { scope: encodeURIComponent(base), query: query, source: encodeURIComponent(source) });
|
||||
const res = await fetchURL(apiPath);
|
||||
let data = await res.json();
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function list() {
|
||||
|
||||
export async function get(path, source) {
|
||||
try {
|
||||
const params = { path, source };
|
||||
const params = { path: encodeURIComponent(path), source: encodeURIComponent(source) };
|
||||
const apiPath = getApiPath("api/share",params);
|
||||
let data = fetchJSON(apiPath);
|
||||
return adjustedData(data, path);
|
||||
@@ -29,7 +29,7 @@ export async function remove(hash) {
|
||||
}
|
||||
|
||||
export async function create(path, source, password = "", expires = "", unit = "hours") {
|
||||
const params = { path: encodeURIComponent(path), source: source };
|
||||
const params = { path: encodeURIComponent(path), source: encodeURIComponent(source) };
|
||||
const apiPath = getApiPath("api/share",params);
|
||||
let body = "{}";
|
||||
if (password != "" || expires !== "" || unit !== "hours") {
|
||||
|
||||
@@ -148,7 +148,7 @@ import { getHumanReadableFilesize } from "@/utils/filesizes";
|
||||
import { url } from "@/utils/";
|
||||
|
||||
import Icon from "@/components/files/Icon.vue";
|
||||
import { serverHasMultipleSources } from "@/utils/constants";
|
||||
import { serverHasMultipleSources, baseURL } from "@/utils/constants";
|
||||
|
||||
var boxes = {
|
||||
folder: { label: "folders", icon: "folder" },
|
||||
@@ -395,9 +395,9 @@ export default {
|
||||
const encodedPath = encodeURIComponent(path).replace("/%20/g", "/");
|
||||
let fullpath = path;
|
||||
if (serverHasMultipleSources) {
|
||||
fullpath = "/files/" + this.selectedSource + "/" + encodedPath;
|
||||
fullpath = baseURL+"files/" + this.selectedSource + "/" + encodedPath;
|
||||
} else {
|
||||
fullpath = "/files/" + encodedPath;
|
||||
fullpath = baseURL+"files/" + encodedPath;
|
||||
}
|
||||
return fullpath;
|
||||
},
|
||||
@@ -498,9 +498,9 @@ export default {
|
||||
this.ongoing = true;
|
||||
let source = this.selectedSource;
|
||||
if (source == "") {
|
||||
source = state.sources.current;
|
||||
this.selectedSource = state.sources.current;
|
||||
}
|
||||
this.results = await search(this.getContext, source, searchTypesFull + this.value);
|
||||
this.results = await search(this.getContext, this.selectedSource, searchTypesFull + this.value);
|
||||
|
||||
this.ongoing = false;
|
||||
if (this.results.length == 0) {
|
||||
@@ -519,13 +519,17 @@ export default {
|
||||
if (this.getContext === "/") {
|
||||
path = s.path;
|
||||
}
|
||||
let urlPath = "/files/" + state.sources.current + path;
|
||||
if (!state.serverHasMultipleSources) {
|
||||
urlPath = "/files" + path;
|
||||
}
|
||||
const modifiedItem = {
|
||||
name: pathParts.pop(),
|
||||
path: path,
|
||||
size: s.size,
|
||||
type: s.type,
|
||||
source: "",
|
||||
url: path,
|
||||
source: this.selectedSource,
|
||||
url: urlPath,
|
||||
fullPath: path,
|
||||
};
|
||||
mutations.resetSelected();
|
||||
|
||||
@@ -101,7 +101,7 @@ export default {
|
||||
return state.user.viewMode === "gallery";
|
||||
},
|
||||
quickDownloadEnabled() {
|
||||
return state.user?.quickDownload;
|
||||
return state.user?.quickDownload && !this.galleryView && !this.isDir;
|
||||
},
|
||||
isHiddenNotSelected() {
|
||||
return !this.isSelected && this.reducedOpacity;
|
||||
|
||||
@@ -165,7 +165,7 @@ export default {
|
||||
event.preventDefault();
|
||||
let link;
|
||||
if (state.isSearchActive) {
|
||||
const hash = await filesApi.checksum(state.selected[0].path, algo);
|
||||
const hash = await filesApi.checksum(state.selected[0].source, state.selected[0].path, algo);
|
||||
event.target.innerHTML = hash;
|
||||
return;
|
||||
}
|
||||
@@ -175,7 +175,7 @@ export default {
|
||||
link = state.route.path;
|
||||
}
|
||||
|
||||
const hash = await filesApi.checksum(link, algo);
|
||||
const hash = await filesApi.checksum(state.sources.current, link, algo);
|
||||
event.target.innerHTML = hash;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<select @change="change" :value="locale">
|
||||
<option v-for="(value, label) in locales" :key="label" :value="label">
|
||||
{{ $t("languages." + value) }}
|
||||
{{ $t("languages." + label) }}
|
||||
</option>
|
||||
</select>
|
||||
</template>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
'active-settings': active(setting.id + '-main'),
|
||||
}"
|
||||
>
|
||||
<div v-if="shouldShow(setting)" class="settings-card">{{ setting.label }}</div>
|
||||
<div v-if="shouldShow(setting)" class="settings-card">{{ $t(setting.label) }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
id="sidebar"
|
||||
:class="{ active: active, 'dark-mode': isDarkMode, 'behind-overlay': behindOverlay }"
|
||||
>
|
||||
<div v-if="shouldShow" class="button release-banner">
|
||||
<a :href="releaseUrl">{{ $t("sidebar.updateIsAvailable") }}</a>
|
||||
<i @click="setSeenUpdate" aria-label="close-banner" class="material-icons">close</i>
|
||||
</div>
|
||||
<SidebarSettings v-if="isSettings"></SidebarSettings>
|
||||
<SidebarGeneral v-else-if="isLoggedIn"></SidebarGeneral>
|
||||
|
||||
@@ -19,7 +23,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { externalLinks, name } from "@/utils/constants";
|
||||
import { externalLinks, name, updateAvailable } from "@/utils/constants";
|
||||
import { getters, mutations, state } from "@/store"; // Import your custom store
|
||||
import SidebarGeneral from "./General.vue";
|
||||
import SidebarSettings from "./Settings.vue";
|
||||
@@ -36,18 +40,34 @@ export default {
|
||||
name,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
// Ensure the sidebar is initialized correctly
|
||||
mutations.setSeenUpdate(localStorage.getItem("seenUpdate"));
|
||||
},
|
||||
computed: {
|
||||
releaseUrl: () => updateAvailable,
|
||||
isDarkMode: () => getters.isDarkMode(),
|
||||
isLoggedIn: () => getters.isLoggedIn(),
|
||||
isSettings: () => getters.isSettings(),
|
||||
active: () => getters.isSidebarVisible(),
|
||||
behindOverlay: () => state.isSearchActive,
|
||||
shouldShow() {
|
||||
return (
|
||||
updateAvailable != "" &&
|
||||
state.user.permissions.admin &&
|
||||
state.seenUpdate != updateAvailable &&
|
||||
!state.user.disableUpdateNotifications
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// Show the help overlay
|
||||
help() {
|
||||
mutations.showHover("help");
|
||||
},
|
||||
setSeenUpdate() {
|
||||
mutations.setSeenUpdate(updateAvailable);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -155,4 +175,12 @@ body.rtl .action {
|
||||
.clickable:hover {
|
||||
box-shadow: 0 2px 2px #00000024, 0 1px 5px #0000001f, 0 3px 1px -2px #0003;
|
||||
}
|
||||
|
||||
.release-banner {
|
||||
background-color: var(--primarColor);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
||||
@@ -197,7 +197,8 @@
|
||||
"highQualityPreview": "High quality preview for gallery images",
|
||||
"editOffice": "Edit/view office files",
|
||||
"popupPreview": "Enable pop-up preview",
|
||||
"filePreviewOptions": "File preview options"
|
||||
"filePreviewOptions": "File preview options",
|
||||
"disableUpdateNotifications": "Disable showing notification update banner in sidebar."
|
||||
},
|
||||
"settings": {
|
||||
"enterPassword": "Enter password",
|
||||
@@ -311,7 +312,8 @@
|
||||
"settings": "Settings",
|
||||
"sources": "Sources",
|
||||
"signup": "Signup",
|
||||
"siteSettings": "Site Settings"
|
||||
"siteSettings": "Site Settings",
|
||||
"updateIsAvailable": "An update is available!"
|
||||
},
|
||||
"success": {
|
||||
"linkCopied": "Link copied!"
|
||||
|
||||
@@ -24,7 +24,6 @@ export const getters = {
|
||||
if (
|
||||
cv == 'preview' ||
|
||||
cv == 'onlyOfficeEditor' ||
|
||||
cv == 'markdownViewer' ||
|
||||
cv == 'epubViewer' ||
|
||||
cv == 'docViewer' ||
|
||||
cv == 'editor'
|
||||
@@ -153,16 +152,8 @@ export const getters = {
|
||||
) {
|
||||
visible = false
|
||||
}
|
||||
if (currentView == 'preview') {
|
||||
const contentType = getters.previewType()
|
||||
if (
|
||||
contentType == 'audio' ||
|
||||
contentType == 'video' ||
|
||||
contentType == 'image' ||
|
||||
contentType == 'pdf'
|
||||
) {
|
||||
visible = false
|
||||
}
|
||||
if (currentView == 'preview' || currentView == 'markdownViewer') {
|
||||
visible = false
|
||||
}
|
||||
if (currentView == 'editor' || currentView == 'onlyOfficeEditor') {
|
||||
visible = false
|
||||
|
||||
@@ -8,6 +8,11 @@ import { sortedItems } from "@/utils/sort.js";
|
||||
import { serverHasMultipleSources } from "@/utils/constants.js";
|
||||
|
||||
export const mutations = {
|
||||
setSeenUpdate: (value) => {
|
||||
state.seenUpdate = value
|
||||
localStorage.setItem("seenUpdate", value);
|
||||
emitStateChanged();
|
||||
},
|
||||
setMultiButtonState: (value) => {
|
||||
if (state.multiButtonLastState != value) {
|
||||
state.multiButtonLastState = state.multiButtonState;
|
||||
@@ -88,7 +93,7 @@ export const mutations = {
|
||||
let sources = {info: {}, current: currentSource, count: user.scopes.length};
|
||||
for (const source of user.scopes) {
|
||||
sources.info[source.name] = {
|
||||
pathPrefix: sources.count == 1 ? "" : source.name,
|
||||
pathPrefix: sources.count == 1 ? "" : encodeURIComponent(source.name),
|
||||
used: 0,
|
||||
total: 0,
|
||||
usedPercentage: 0,
|
||||
@@ -212,9 +217,12 @@ export const mutations = {
|
||||
if (value.username != "publicUser") {
|
||||
mutations.setSources(value);
|
||||
}
|
||||
console.log("Setting current user:", value);
|
||||
// Ensure locale exists and is valid
|
||||
if (!value.locale) {
|
||||
value.locale = i18n.detectLocale(); // Default to detected locale if missing
|
||||
} else {
|
||||
i18n.setLocale(value.locale);
|
||||
}
|
||||
state.user = value;
|
||||
} catch (error) {
|
||||
@@ -270,7 +278,6 @@ export const mutations = {
|
||||
|
||||
// Merge the new values into the current user state
|
||||
state.user = { ...state.user, ...value };
|
||||
|
||||
// Handle locale change
|
||||
if (state.user.locale !== previousUser.locale) {
|
||||
//state.user.locale = i18n.detectLocale();
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import i18n from '@/i18n'; // Import the default export (your i18n instance)
|
||||
|
||||
const name = window.FileBrowser.Name;
|
||||
const disableExternal = window.FileBrowser.DisableExternal;
|
||||
const externalLinks = window.FileBrowser.ExternalLinks;
|
||||
@@ -22,17 +20,19 @@ const oidcAvailable = window.FileBrowser.OidcAvailable;
|
||||
const passwordAvailable = window.FileBrowser.PasswordAvailable;
|
||||
const mediaAvailable = window.FileBrowser.MediaAvailable;
|
||||
const muPdfAvailable = window.FileBrowser.MuPdfAvailable;
|
||||
const updateAvailable = window.FileBrowser.UpdateAvailable;
|
||||
const origin = window.location.origin;
|
||||
|
||||
const settings = [
|
||||
{ id: 'profile', label: i18n.global.t('settings.profileSettings'), component: 'ProfileSettings' },
|
||||
{ id: 'shares', label: i18n.global.t('settings.shareSettings'), component: 'SharesSettings', permissions: { share: true } },
|
||||
{ id: 'api', label: i18n.global.t('api.title'), component: 'ApiKeys', permissions: { api: true } },
|
||||
{ id: 'profile', label: 'settings.profileSettings', component: 'ProfileSettings' },
|
||||
{ id: 'shares', label: 'settings.shareSettings', component: 'SharesSettings', permissions: { share: true } },
|
||||
{ id: 'api', label: 'api.title', component: 'ApiKeys', permissions: { api: true } },
|
||||
//{ id: 'global', label: 'Global', component: 'GlobalSettings', permissions: { admin: true } },
|
||||
{ id: 'users', label: i18n.global.t('settings.userManagement'), component: 'UserManagement' },
|
||||
{ id: 'users', label: 'settings.userManagement', component: 'UserManagement' },
|
||||
];
|
||||
|
||||
export {
|
||||
updateAvailable,
|
||||
muPdfAvailable,
|
||||
mediaAvailable,
|
||||
oidcAvailable,
|
||||
|
||||
@@ -121,9 +121,8 @@ export function extractSourceFromPath(url) {
|
||||
if (state.serverHasMultipleSources) {
|
||||
source = path.split('/')[2];
|
||||
path = removePrefix(path, `/files/${source}`);
|
||||
source = encodeURIComponent(source)
|
||||
} else {
|
||||
source = encodeURIComponent(state.sources.current);
|
||||
source = state.sources.current;
|
||||
path = removePrefix(path, '/files');
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ export default {
|
||||
routePath == "/";
|
||||
// lets redirect if multiple sources and user went to /files/
|
||||
if (state.serverHasMultipleSources && rootRoute) {
|
||||
router.push(`${routePath}/${state.sources.current}`);
|
||||
const urlEncodedSource = encodeURIComponent(state.sources.current)
|
||||
router.push(`${routePath}/${urlEncodedSource}`);
|
||||
return;
|
||||
}
|
||||
this.lastHash = "";
|
||||
|
||||
@@ -608,6 +608,9 @@ export default {
|
||||
break;
|
||||
|
||||
case "Backspace":
|
||||
if (getters.CurrentPromptName !== null) {
|
||||
return;
|
||||
}
|
||||
// go back
|
||||
router.push({ path: newPath });
|
||||
break;
|
||||
|
||||
@@ -127,7 +127,10 @@ export default {
|
||||
".hwp": true,
|
||||
".hwpx": true,
|
||||
};
|
||||
return !!pdfConvertCompatibleFileExtensions[ext];
|
||||
if (state.user.disableOfficePreviewExt.includes(ext)) {
|
||||
return false;
|
||||
}
|
||||
return !!pdfConvertCompatibleFileExtensions[ext] ;
|
||||
},
|
||||
sidebarShowing() {
|
||||
return getters.isSidebarVisible();
|
||||
|
||||
@@ -86,6 +86,9 @@ export default {
|
||||
error: null,
|
||||
links: {},
|
||||
clip: null,
|
||||
user: {
|
||||
permissions: { ...state.user.permissions}
|
||||
},
|
||||
};
|
||||
},
|
||||
async created() {
|
||||
@@ -115,9 +118,6 @@ export default {
|
||||
active() {
|
||||
return state.activeSettingsView === "shares-main";
|
||||
},
|
||||
user() {
|
||||
return state.user;
|
||||
},
|
||||
loading() {
|
||||
return getters.isLoading();
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="card-content">
|
||||
<form>
|
||||
<div class="card-content">
|
||||
<h3>{{ $t('settings.listingOptions') }}</h3>
|
||||
<h3>{{ $t("settings.listingOptions") }}</h3>
|
||||
<div class="settings-items">
|
||||
<ToggleSwitch
|
||||
class="item"
|
||||
@@ -24,7 +24,7 @@
|
||||
:name="$t('profileSettings.showQuickDownload')"
|
||||
/>
|
||||
</div>
|
||||
<h3> {{ $t('profileSettings.filePreviewOptions') }}</h3>
|
||||
<h3>{{ $t("profileSettings.filePreviewOptions") }}</h3>
|
||||
<div class="settings-items">
|
||||
<ToggleSwitch
|
||||
class="item"
|
||||
@@ -61,9 +61,9 @@
|
||||
/>
|
||||
</div>
|
||||
<div v-if="hasOnlyOfficeEnabled">
|
||||
<h3> {{ $t('settings.disableOfficePreview')}} </h3>
|
||||
<h3>{{ $t("settings.disableOfficePreview") }}</h3>
|
||||
<p>
|
||||
{{ $t('settings.disableOfficePreviewDescription') }}
|
||||
{{ $t("settings.disableOfficePreviewDescription") }}
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<input
|
||||
@@ -74,14 +74,20 @@
|
||||
id="onlyofficeExt"
|
||||
v-model="formOnlyOfficeExt"
|
||||
/>
|
||||
<button type="button" class="button form-button" @click="submitOnlyOfficeChange"> {{ $t('buttons.save') }} </button>
|
||||
<button
|
||||
type="button"
|
||||
class="button form-button"
|
||||
@click="submitOnlyOfficeChange"
|
||||
>
|
||||
{{ $t("buttons.save") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="muPdfAvailable">
|
||||
<h3> {{ $t('settings.disableOfficePreviews')}} </h3>
|
||||
<h3>{{ $t("settings.disableOfficePreviews") }}</h3>
|
||||
<p>
|
||||
{{ $t('settings.disableOfficePreviewsDescription') }}
|
||||
{{ $t("settings.disableOfficePreviewsDescription") }}
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<input
|
||||
@@ -92,11 +98,22 @@
|
||||
id="officePreviewExt"
|
||||
v-model="formOfficePreviewExt"
|
||||
/>
|
||||
<button type="button" class="button form-button" @click="submitOfficePreviewsChange"> {{ $t('buttons.save') }} </button>
|
||||
<button
|
||||
type="button"
|
||||
class="button form-button"
|
||||
@click="submitOfficePreviewsChange"
|
||||
>
|
||||
{{ $t("buttons.save") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3> {{ $t('settings.themeColor') }} </h3>
|
||||
<ToggleSwitch
|
||||
v-if="localuser.permissions?.admin"
|
||||
class="item"
|
||||
v-model="localuser.disableUpdateNotifications"
|
||||
:name="$t('profileSettings.disableUpdateNotifications')"
|
||||
/>
|
||||
<h3>{{ $t("settings.themeColor") }}</h3>
|
||||
<ButtonGroup
|
||||
:buttons="colorChoices"
|
||||
@button-clicked="setColor"
|
||||
@@ -132,7 +149,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
localuser: { preview: {} },
|
||||
localuser: { preview: {}, permissions: {} }, // Initialize localuser with empty objects to avoid undefined errors
|
||||
initialized: false,
|
||||
formOnlyOfficeExt: "", // holds temporary input before saving
|
||||
formOfficePreviewExt: "", // holds temporary input before saving
|
||||
@@ -250,6 +267,4 @@ export default {
|
||||
.card-content h3 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
Reference in new issue
Block a user