diff --git a/README.md b/README.md index 02a75ac..1486fbc 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,15 @@ way of handling the configuration and initialization. Download custom-built executables
-Additionally, custom source _(to download binaries)_ can be configured by specifying the environment variables, -`GIT_OWNER` and `GIT_REPO`
+Additionally, custom source _(to download binaries)_ can be configured by specifying the following environment variables + +- **OWNER** - Owner of the GitHub repo. +- **REPO** - Repository name. +- **TOKEN** - GitHub repository token. +- **VERSION** - Version of the release. + +> _also supports the dotenv file `.github.env`, and prefixes like `github`, `git` and `filebrowser`_ + For this custom source feature to work, the executable should be uploaded to releases as assets, and follow the naming convention below. @@ -43,7 +50,7 @@ and follow the naming convention below. python -m pip install pyfilebrowser ``` -**Initiate** +**Initiate [programmatically]** ```python import pyfilebrowser @@ -53,6 +60,11 @@ if __name__ == '__main__': browser.start() ``` +**Initiate [CLI]** +```shell +pyfilebrowser +``` + ## Environment Variables Env vars can either be loaded from `.env` files or directly passed during object init. @@ -68,10 +80,11 @@ Env vars can either be loaded from `.env` files or directly passed during object - **workers** `int` - Number of workers used to run the proxy server. _Defaults to `1`_ - **debug** `bool` - Boolean flag to enable debug level logging. _Defaults to `False`_ - **origins** `List[str]` - Origins to allow connections through proxy server. _Defaults to `host`_ -- **public_ip** `bool` - Boolean flag to allow public IP address of the host. _Defaults to `False`_ -- **private_ip** `bool` - Boolean flag to allow private IP address of the host. _Defaults to `False`_ +- **allow_public_ip** `bool` - Boolean flag to allow public IP address of the host. _Defaults to `False`_ +- **allow_private_ip** `bool` - Boolean flag to allow private IP address of the host. _Defaults to `False`_ - **origin_refresh** `int` - Interval in seconds to refresh all the allowed origins. _Defaults to `None`_ - **error_page** `FilePath` - Error page to serve when filebrowser API is down. _Defaults to_ [error.html] +- **warn_page** `FilePath` - Warning page to serve when accessed from Unsupported browsers. _Defaults to_ [warn.html] - **rate_limit** - `Dict/List[Dict]` with the rate limit for the proxy server. _Defaults to `None`_ > `origin_refresh` allows users to set a custom interval to update the public and private IP address of the host, @@ -216,6 +229,7 @@ Licensed under the [MIT License][license] [pep8]: https://www.python.org/dev/peps/pep-0008/ [isort]: https://pycqa.github.io/isort/ [error.html]: https://github.com/thevickypedia/pyfilebrowser/blob/main/pyfilebrowser/proxy/error.html +[warn.html]: https://github.com/thevickypedia/pyfilebrowser/blob/main/pyfilebrowser/proxy/warn.html [Rate limiting]: https://www.cloudflare.com/learning/bots/what-is-rate-limiting/ [DDoS]: https://www.cloudflare.com/learning/ddos/glossary/denial-of-service/ [Rate Limiter]: https://builtin.com/software-engineering-perspectives/rate-limiter diff --git a/doc_gen/index.rst b/doc_gen/index.rst index 7fb0927..a42ddcd 100644 --- a/doc_gen/index.rst +++ b/doc_gen/index.rst @@ -174,29 +174,13 @@ Download ==== -.. autoclass:: pyfilebrowser.squire.download.ExtendedEnvSettingsSource(pydantic_settings.EnvSettingsSource) - :exclude-members: _abc_impl, model_config, model_fields, model_computed_fields - -==== - -.. autoclass:: pyfilebrowser.squire.download.ExtendedSettingsConfigDict(pydantic_settings.SettingsConfigDict) - :exclude-members: _abc_impl, model_computed_fields, model_config, model_fields, env_prefixes, title, str_to_lower, str_to_upper, str_strip_whitespace, str_min_length, str_max_length, extra, frozen, populate_by_name, use_enum_values, validate_assignment, arbitrary_types_allowed, from_attributes, loc_by_alias, alias_generator, ignored_types, allow_inf_nan, json_schema_extra, json_encoders, strict, revalidate_instances, ser_json_timedelta, ser_json_bytes, ser_json_inf_nan, validate_default, validate_return, protected_namespaces, hide_input_in_errors, defer_build, plugin_settings, schema_generator, json_schema_serialization_defaults_required, json_schema_mode_override, coerce_numbers_to_str, regex_engine, validation_error_cause, case_sensitive, env_prefix, env_file, env_file_encoding, env_ignore_empty, env_nested_delimiter, env_parse_none_str, secrets_dir, json_file, json_file_encoding, yaml_file, yaml_file_encoding, toml_file - -==== - -.. autoclass:: pyfilebrowser.squire.download.ExtendedBaseSettings(pydantic_settings.BaseSettings) - :exclude-members: _abc_impl, model_computed_fields, model_config, model_fields, env_prefixes, title, str_to_lower, str_to_upper, str_strip_whitespace, str_min_length, str_max_length, extra, frozen, populate_by_name, use_enum_values, validate_assignment, arbitrary_types_allowed, from_attributes, loc_by_alias, alias_generator, ignored_types, allow_inf_nan, json_schema_extra, json_encoders, strict, revalidate_instances, ser_json_timedelta, ser_json_bytes, ser_json_inf_nan, validate_default, validate_return, protected_namespaces, hide_input_in_errors, defer_build, plugin_settings, schema_generator, json_schema_serialization_defaults_required, json_schema_mode_override, coerce_numbers_to_str, regex_engine, validation_error_cause, case_sensitive, env_prefix, env_file, env_file_encoding, env_ignore_empty, env_nested_delimiter, env_parse_none_str, secrets_dir, json_file, json_file_encoding, yaml_file, yaml_file_encoding, toml_file - :noindex: - -==== - -.. autoclass:: pyfilebrowser.squire.download.GitHub(ExtendedBaseSettings) +.. autoclass:: pyfilebrowser.squire.download.GitHub(pydantic.BaseSettings) :exclude-members: _abc_impl, model_config, model_fields, model_computed_fields ==== .. automodule:: pyfilebrowser.squire.download - :exclude-members: ExtendedEnvSettingsSource, ExtendedSettingsConfigDict, ExtendedBaseSettings, GitHub, Executable + :exclude-members: GitHub, Executable Steward ======= diff --git a/docs/README.html b/docs/README.html index 8618a1a..d9581d5 100644 --- a/docs/README.html +++ b/docs/README.html @@ -62,9 +62,17 @@

PyFileBrowserpyfilebrowser automatically downloads the system specific executable during startup.

Download custom-built executables -

Additionally, custom source (to download binaries) can be configured by specifying the environment variables, -GIT_OWNER and GIT_REPO
-For this custom source feature to work, the executable should be uploaded to releases as assets, +

Additionally, custom source (to download binaries) can be configured by specifying the following environment variables

+ +
+

also supports the dotenv file .github.env, and prefixes like github, git and filebrowser

+
+

For this custom source feature to work, the executable should be uploaded to releases as assets, and follow the naming convention below.

asset naming convention: ${operating system}-{architecture}-filebrowser-{extension}
@@ -76,7 +84,7 @@

Kick Off
python -m pip install pyfilebrowser
 

-

Initiate

+

Initiate [programmatically]

+

Initiate [CLI]

+
pyfilebrowser
+
+

Environment Variables

@@ -101,10 +113,11 @@

.env

workers int - Number of workers used to run the proxy server. Defaults to 1

  • debug bool - Boolean flag to enable debug level logging. Defaults to False

  • origins List[str] - Origins to allow connections through proxy server. Defaults to host

  • -
  • public_ip bool - Boolean flag to allow public IP address of the host. Defaults to False

  • -
  • private_ip bool - Boolean flag to allow private IP address of the host. Defaults to False

  • +
  • allow_public_ip bool - Boolean flag to allow public IP address of the host. Defaults to False

  • +
  • allow_private_ip bool - Boolean flag to allow private IP address of the host. Defaults to False

  • origin_refresh int - Interval in seconds to refresh all the allowed origins. Defaults to None

  • error_page FilePath - Error page to serve when filebrowser API is down. Defaults to error.html

  • +
  • warn_page FilePath - Warning page to serve when accessed from Unsupported browsers. Defaults to warn.html

  • rate_limit - Dict/List[Dict] with the rate limit for the proxy server. Defaults to None

  • diff --git a/docs/README.md b/docs/README.md index 02a75ac..1486fbc 100644 --- a/docs/README.md +++ b/docs/README.md @@ -27,8 +27,15 @@ way of handling the configuration and initialization. Download custom-built executables
    -Additionally, custom source _(to download binaries)_ can be configured by specifying the environment variables, -`GIT_OWNER` and `GIT_REPO`
    +Additionally, custom source _(to download binaries)_ can be configured by specifying the following environment variables + +- **OWNER** - Owner of the GitHub repo. +- **REPO** - Repository name. +- **TOKEN** - GitHub repository token. +- **VERSION** - Version of the release. + +> _also supports the dotenv file `.github.env`, and prefixes like `github`, `git` and `filebrowser`_ + For this custom source feature to work, the executable should be uploaded to releases as assets, and follow the naming convention below. @@ -43,7 +50,7 @@ and follow the naming convention below. python -m pip install pyfilebrowser ``` -**Initiate** +**Initiate [programmatically]** ```python import pyfilebrowser @@ -53,6 +60,11 @@ if __name__ == '__main__': browser.start() ``` +**Initiate [CLI]** +```shell +pyfilebrowser +``` + ## Environment Variables Env vars can either be loaded from `.env` files or directly passed during object init. @@ -68,10 +80,11 @@ Env vars can either be loaded from `.env` files or directly passed during object - **workers** `int` - Number of workers used to run the proxy server. _Defaults to `1`_ - **debug** `bool` - Boolean flag to enable debug level logging. _Defaults to `False`_ - **origins** `List[str]` - Origins to allow connections through proxy server. _Defaults to `host`_ -- **public_ip** `bool` - Boolean flag to allow public IP address of the host. _Defaults to `False`_ -- **private_ip** `bool` - Boolean flag to allow private IP address of the host. _Defaults to `False`_ +- **allow_public_ip** `bool` - Boolean flag to allow public IP address of the host. _Defaults to `False`_ +- **allow_private_ip** `bool` - Boolean flag to allow private IP address of the host. _Defaults to `False`_ - **origin_refresh** `int` - Interval in seconds to refresh all the allowed origins. _Defaults to `None`_ - **error_page** `FilePath` - Error page to serve when filebrowser API is down. _Defaults to_ [error.html] +- **warn_page** `FilePath` - Warning page to serve when accessed from Unsupported browsers. _Defaults to_ [warn.html] - **rate_limit** - `Dict/List[Dict]` with the rate limit for the proxy server. _Defaults to `None`_ > `origin_refresh` allows users to set a custom interval to update the public and private IP address of the host, @@ -216,6 +229,7 @@ Licensed under the [MIT License][license] [pep8]: https://www.python.org/dev/peps/pep-0008/ [isort]: https://pycqa.github.io/isort/ [error.html]: https://github.com/thevickypedia/pyfilebrowser/blob/main/pyfilebrowser/proxy/error.html +[warn.html]: https://github.com/thevickypedia/pyfilebrowser/blob/main/pyfilebrowser/proxy/warn.html [Rate limiting]: https://www.cloudflare.com/learning/bots/what-is-rate-limiting/ [DDoS]: https://www.cloudflare.com/learning/ddos/glossary/denial-of-service/ [Rate Limiter]: https://builtin.com/software-engineering-perspectives/rate-limiter diff --git a/docs/_sources/README.md.txt b/docs/_sources/README.md.txt index 02a75ac..1486fbc 100644 --- a/docs/_sources/README.md.txt +++ b/docs/_sources/README.md.txt @@ -27,8 +27,15 @@ way of handling the configuration and initialization. Download custom-built executables
    -Additionally, custom source _(to download binaries)_ can be configured by specifying the environment variables, -`GIT_OWNER` and `GIT_REPO`
    +Additionally, custom source _(to download binaries)_ can be configured by specifying the following environment variables + +- **OWNER** - Owner of the GitHub repo. +- **REPO** - Repository name. +- **TOKEN** - GitHub repository token. +- **VERSION** - Version of the release. + +> _also supports the dotenv file `.github.env`, and prefixes like `github`, `git` and `filebrowser`_ + For this custom source feature to work, the executable should be uploaded to releases as assets, and follow the naming convention below. @@ -43,7 +50,7 @@ and follow the naming convention below. python -m pip install pyfilebrowser ``` -**Initiate** +**Initiate [programmatically]** ```python import pyfilebrowser @@ -53,6 +60,11 @@ if __name__ == '__main__': browser.start() ``` +**Initiate [CLI]** +```shell +pyfilebrowser +``` + ## Environment Variables Env vars can either be loaded from `.env` files or directly passed during object init. @@ -68,10 +80,11 @@ Env vars can either be loaded from `.env` files or directly passed during object - **workers** `int` - Number of workers used to run the proxy server. _Defaults to `1`_ - **debug** `bool` - Boolean flag to enable debug level logging. _Defaults to `False`_ - **origins** `List[str]` - Origins to allow connections through proxy server. _Defaults to `host`_ -- **public_ip** `bool` - Boolean flag to allow public IP address of the host. _Defaults to `False`_ -- **private_ip** `bool` - Boolean flag to allow private IP address of the host. _Defaults to `False`_ +- **allow_public_ip** `bool` - Boolean flag to allow public IP address of the host. _Defaults to `False`_ +- **allow_private_ip** `bool` - Boolean flag to allow private IP address of the host. _Defaults to `False`_ - **origin_refresh** `int` - Interval in seconds to refresh all the allowed origins. _Defaults to `None`_ - **error_page** `FilePath` - Error page to serve when filebrowser API is down. _Defaults to_ [error.html] +- **warn_page** `FilePath` - Warning page to serve when accessed from Unsupported browsers. _Defaults to_ [warn.html] - **rate_limit** - `Dict/List[Dict]` with the rate limit for the proxy server. _Defaults to `None`_ > `origin_refresh` allows users to set a custom interval to update the public and private IP address of the host, @@ -216,6 +229,7 @@ Licensed under the [MIT License][license] [pep8]: https://www.python.org/dev/peps/pep-0008/ [isort]: https://pycqa.github.io/isort/ [error.html]: https://github.com/thevickypedia/pyfilebrowser/blob/main/pyfilebrowser/proxy/error.html +[warn.html]: https://github.com/thevickypedia/pyfilebrowser/blob/main/pyfilebrowser/proxy/warn.html [Rate limiting]: https://www.cloudflare.com/learning/bots/what-is-rate-limiting/ [DDoS]: https://www.cloudflare.com/learning/ddos/glossary/denial-of-service/ [Rate Limiter]: https://builtin.com/software-engineering-perspectives/rate-limiter diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt index 7fb0927..a42ddcd 100644 --- a/docs/_sources/index.rst.txt +++ b/docs/_sources/index.rst.txt @@ -174,29 +174,13 @@ Download ==== -.. autoclass:: pyfilebrowser.squire.download.ExtendedEnvSettingsSource(pydantic_settings.EnvSettingsSource) - :exclude-members: _abc_impl, model_config, model_fields, model_computed_fields - -==== - -.. autoclass:: pyfilebrowser.squire.download.ExtendedSettingsConfigDict(pydantic_settings.SettingsConfigDict) - :exclude-members: _abc_impl, model_computed_fields, model_config, model_fields, env_prefixes, title, str_to_lower, str_to_upper, str_strip_whitespace, str_min_length, str_max_length, extra, frozen, populate_by_name, use_enum_values, validate_assignment, arbitrary_types_allowed, from_attributes, loc_by_alias, alias_generator, ignored_types, allow_inf_nan, json_schema_extra, json_encoders, strict, revalidate_instances, ser_json_timedelta, ser_json_bytes, ser_json_inf_nan, validate_default, validate_return, protected_namespaces, hide_input_in_errors, defer_build, plugin_settings, schema_generator, json_schema_serialization_defaults_required, json_schema_mode_override, coerce_numbers_to_str, regex_engine, validation_error_cause, case_sensitive, env_prefix, env_file, env_file_encoding, env_ignore_empty, env_nested_delimiter, env_parse_none_str, secrets_dir, json_file, json_file_encoding, yaml_file, yaml_file_encoding, toml_file - -==== - -.. autoclass:: pyfilebrowser.squire.download.ExtendedBaseSettings(pydantic_settings.BaseSettings) - :exclude-members: _abc_impl, model_computed_fields, model_config, model_fields, env_prefixes, title, str_to_lower, str_to_upper, str_strip_whitespace, str_min_length, str_max_length, extra, frozen, populate_by_name, use_enum_values, validate_assignment, arbitrary_types_allowed, from_attributes, loc_by_alias, alias_generator, ignored_types, allow_inf_nan, json_schema_extra, json_encoders, strict, revalidate_instances, ser_json_timedelta, ser_json_bytes, ser_json_inf_nan, validate_default, validate_return, protected_namespaces, hide_input_in_errors, defer_build, plugin_settings, schema_generator, json_schema_serialization_defaults_required, json_schema_mode_override, coerce_numbers_to_str, regex_engine, validation_error_cause, case_sensitive, env_prefix, env_file, env_file_encoding, env_ignore_empty, env_nested_delimiter, env_parse_none_str, secrets_dir, json_file, json_file_encoding, yaml_file, yaml_file_encoding, toml_file - :noindex: - -==== - -.. autoclass:: pyfilebrowser.squire.download.GitHub(ExtendedBaseSettings) +.. autoclass:: pyfilebrowser.squire.download.GitHub(pydantic.BaseSettings) :exclude-members: _abc_impl, model_config, model_fields, model_computed_fields ==== .. automodule:: pyfilebrowser.squire.download - :exclude-members: ExtendedEnvSettingsSource, ExtendedSettingsConfigDict, ExtendedBaseSettings, GitHub, Executable + :exclude-members: GitHub, Executable Steward ======= diff --git a/docs/genindex.html b/docs/genindex.html index 160ebd5..15df9f9 100644 --- a/docs/genindex.html +++ b/docs/genindex.html @@ -97,10 +97,16 @@

    A

  • after_upload (pyfilebrowser.modals.config.Commands attribute)
  • -
  • allowed_origins (pyfilebrowser.proxy.settings.Session attribute) +
  • alias_choices() (in module pyfilebrowser.squire.download) +
  • +
  • allow_private_ip (pyfilebrowser.proxy.settings.EnvConfig attribute) +
  • +
  • allow_public_ip (pyfilebrowser.proxy.settings.EnvConfig attribute)
  • env_prefix (pyfilebrowser.modals.config.Auther.Config attribute) @@ -294,17 +302,17 @@

    E

  • (pyfilebrowser.modals.users.UserSettings.Config attribute)
  • - -
  • env_prefixes (pyfilebrowser.squire.download.ExtendedSettingsConfigDict attribute) +
  • (pyfilebrowser.squire.download.GitHub.Config attribute)
  • + + + -
  • extract() (pyfilebrowser.squire.struct.LoggerConfig method) @@ -389,9 +395,9 @@

    G

  • @@ -547,8 +553,6 @@

    O

    • origins (pyfilebrowser.proxy.settings.EnvConfig attribute) -
    • -
    • origins_url_checker() (pyfilebrowser.proxy.settings.EnvConfig class method)
    • owner (pyfilebrowser.squire.download.GitHub attribute)
    • @@ -558,6 +562,12 @@

      O

      P

      -
    • private_ip (pyfilebrowser.proxy.settings.EnvConfig attribute) -
    • proxy_auth() (in module pyfilebrowser.proxy.squire)
    • proxy_engine() (in module pyfilebrowser.proxy.main) @@ -583,8 +591,6 @@

      P

    • proxy_server() (in module pyfilebrowser.proxy.server)
    • ProxyServer (class in pyfilebrowser.proxy.server) -
    • -
    • public_ip (pyfilebrowser.proxy.settings.EnvConfig attribute)
    • pyfilebrowser.main @@ -679,8 +685,6 @@

      R

      • rate_limit (pyfilebrowser.proxy.settings.EnvConfig attribute) -
      • -
      • rate_limit_checker() (pyfilebrowser.proxy.settings.EnvConfig class method)
      • RateLimit (class in pyfilebrowser.proxy.settings)
      • @@ -830,16 +834,18 @@

        T

        U

          +
        • userHomeBasePath (pyfilebrowser.modals.config.Config attribute) +
        • username (pyfilebrowser.modals.users.Authentication attribute)
        • users (pyfilebrowser.squire.steward.FileIO attribute) @@ -873,6 +879,10 @@

          V

          W

          +
          • workers (pyfilebrowser.proxy.settings.EnvConfig attribute)
          • diff --git a/docs/index.html b/docs/index.html index 1d015fe..a9168c4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -353,8 +353,8 @@

            ——–Proxy Server——–

            Squire

            -pyfilebrowser.proxy.squire.log_connection(request: Request) None
            -

            Logs the connection information.

            +pyfilebrowser.proxy.squire.log_connection(request: Request) starlette.responses.HTMLResponse | None +

            Logs the connection information and returns an HTML response if the browser is unsupported for video/audio.

            See also

            +
            +
            Returns:
            +

            Returns an HTML response if the browser is unsupported for video/audio rendering.

            +
            +
            Return type:
            +

            HTMLResponse

            +
            +
            @@ -513,13 +521,13 @@

            Settings -
            -public_ip: bool
            +
            +allow_public_ip: bool

            -
            -private_ip: bool
            +
            +allow_private_ip: bool
            @@ -532,21 +540,37 @@

            Settingsrate_limit: Union[RateLimit, List[RateLimit]]

            +
            +
            +unsupported_browsers: Union[str, List[str]]
            +
            + +
            +
            +warn_page: Path
            +
            +
            error_page: Path
            -
            -classmethod origins_url_checker(v: List[Url]) Union[List[str], List]
            +
            +classmethod parse_unsupported_browsers(unsupported_browsers: Union[str, List[str]]) Union[List[str], List]
            +

            Validate unsupported_browsers and convert to list.

            +
            + +
            +
            +classmethod parse_origins(origins: List[Url]) Union[List[str], List]

            Validate origins’ input as a URL, and stores only the host part of the URL.

            -
            -classmethod rate_limit_checker(v: Union[RateLimit, List[RateLimit]], values, **kwargs) Union[List[RateLimit], List]
            -

            Validate origins’ input as a URL, and convert as string when stored.

            +
            +classmethod parse_rate_limit(rate_limit: Union[RateLimit, List[RateLimit]]) Union[List[RateLimit], List]
            +

            Validate rate_limit and convert to list.

            @@ -1730,117 +1754,14 @@

            Download -
            -
            -class pyfilebrowser.squire.download.ExtendedEnvSettingsSource(pydantic_settings.EnvSettingsSource)
            -

            Customized environment settings source that allows specifying multiple prefixes for environmental variables.

            -
            >>> ExtendedEnvSettingsSource
            -
            -
            -
            -
            -get_field_value(field: FieldInfo, field_name: str) Tuple[Any, str, bool]
            -

            Retrieves the field value from the environment with support for multiple prefixes.

            -
            -
            Parameters:
            -
              -
            • field – Information about the field.

            • -
            • field_name – Name of the field.

            • -
            -
            -
            Returns:
            -

            Retrieved value, field key, and a boolean indicating whether the value is complex.

            -
            -
            Return type:
            -

            Tuple[Any, str, bool]

            -
            -
            -
            - -
            - -
            -
            -
            -class pyfilebrowser.squire.download.ExtendedSettingsConfigDict(pydantic_settings.SettingsConfigDict)
            -

            Configuration dictionary extension to support additional settings.

            -
            >>> ExtendedSettingsConfigDict
            -
            -
            -
            -
            -env_prefixes
            -

            List of environment variable prefixes to consider.

            -
            -
            Type:
            -

            List[str] | None

            -
            -
            -
            - -
            - -
            -
            -
            -class pyfilebrowser.squire.download.ExtendedBaseSettings(pydantic_settings.BaseSettings)
            -

            Base settings class extension to customize settings sources.

            -
            >>> ExtendedBaseSettings
            -
            -
            -
            -
            -settings_customise_sources()
            -

            Customizes settings sources for the extended settings class.

            -
            - -

            Create a new model by parsing and validating input data from keyword arguments.

            -

            Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be -validated to form a valid model.

            -

            self is explicitly positional-only to allow self as a field name.

            -
            -
            -classmethod settings_customise_sources(settings_cls: Type[BaseSettings], init_settings: PydanticBaseSettingsSource, env_settings: PydanticBaseSettingsSource, dotenv_settings: PydanticBaseSettingsSource, file_secret_settings: PydanticBaseSettingsSource) Tuple[PydanticBaseSettingsSource, ...]
            -

            Customizes the settings sources for the extended settings class.

            -
            -
            Parameters:
            -
              -
            • settings_cls – The extended settings class.

            • -
            • init_settings – Settings source for initialization.

            • -
            • env_settings – Settings source for environment variables.

            • -
            • dotenv_settings – Settings source for dotenv files.

            • -
            • file_secret_settings – Settings source for secret files.

            • -
            -
            -
            Returns:
            -

            Tuple of customized settings sources.

            -
            -
            Return type:
            -

            Tuple[PydanticBaseSettingsSource, …]

            -
            -
            -
            - -
            -
            -class pyfilebrowser.squire.download.GitHub(ExtendedBaseSettings)
            +class pyfilebrowser.squire.download.GitHub(pydantic.BaseSettings)

            Custom GitHub account information loaded using multiple env prefixes.

            >>> GitHub
             
            -

            References

            -

            https://github.com/pydantic/pydantic/discussions/4319

            -
            -

            See also

            -
              -
            • This model is to load GitHub arguments, which is used to download the appropriate asset from source control.

            • -
            • Dot env (.env) files are not supported. Regular env variables are required.

            • -
            -

            Create a new model by parsing and validating input data from keyword arguments.

            Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

            @@ -1865,10 +1786,48 @@

            Downloadversion: str

            +
            +
            +class Config
            +

            Custom configuration for GitHub settings.

            +
            +
            +env_prefix = ''
            +
            + +
            +
            +env_file = '.github.env'
            +
            + +
            +
            +extra = 'ignore'
            +
            + +
            +


            +
            +pyfilebrowser.squire.download.alias_choices(variable: str) AliasChoices
            +

            Custom alias choices for environment variables for GitHub.

            +
            +
            Parameters:
            +

            variable – Variable name.

            +
            +
            Returns:
            +

            Returns the alias choices for the variable.

            +
            +
            Return type:
            +

            AliasChoices

            +
            +
            +
            + +
            pyfilebrowser.squire.download.binary(logger: Logger, github: GitHub) None

            Downloads the latest released binary asset.

            diff --git a/docs/objects.inv b/docs/objects.inv index eed828a..130c5fd 100644 Binary files a/docs/objects.inv and b/docs/objects.inv differ diff --git a/docs/searchindex.js b/docs/searchindex.js index 6eb2505..5ad9854 100644 --- a/docs/searchindex.js +++ b/docs/searchindex.js @@ -1 +1 @@ -Search.setIndex({"docnames": ["README", "index"], "filenames": ["README.md", "index.rst"], "titles": ["PyFileBrowser", "Welcome to PyFileBrowser\u2019s documentation!"], "terms": {"deploy": 0, "introduc": 0, "python": 0, "librari": 0, "design": 0, "streamlin": 0, "interact": 0, "filebrows": [0, 1], "thi": [0, 1], "wrapper": [0, 1], "simplifi": 0, "integr": 0, "autom": 0, "task": [0, 1], "enabl": [0, 1], "seamless": 0, "your": [0, 1], "local": [0, 1], "system": [0, 1], "via": 0, "": 0, "web": 0, "interfac": 0, "all": [0, 1], "requir": [0, 1], "configur": 0, "set": 0, "user": 0, "profil": [0, 1], "ar": [0, 1], "load": [0, 1], "us": [0, 1], "provid": [0, 1], "more": 0, "central": 0, "wai": 0, "handl": [0, 1], "initi": [0, 1], "automat": 0, "download": 0, "specif": 0, "execut": [0, 1], "dure": [0, 1], "startup": 0, "custom": [0, 1], "built": [0, 1], "addition": 0, "sourc": [0, 1], "binari": [0, 1], "can": [0, 1], "specifi": [0, 1], "git_own": 0, "git_repo": 0, "For": 0, "featur": [0, 1], "work": 0, "should": [0, 1], "upload": [0, 1], "asset": [0, 1], "follow": 0, "name": [0, 1], "convent": 0, "below": 0, "oper": 0, "architectur": 0, "extens": [0, 1], "exampl": 0, "darwin": 0, "amd64": 0, "tar": 0, "gz": 0, "instal": 0, "m": 0, "pip": 0, "import": [0, 1], "__name__": 0, "__main__": 0, "browser": 0, "true": [0, 1], "option": [0, 1], "run": [0, 1], "parallel": [0, 1], "start": [0, 1], "var": [0, 1], "either": 0, "from": [0, 1], "directli": 0, "pass": [0, 1], "object": [0, 1], "init": [0, 1], "host": [0, 1], "str": [0, 1], "hostnam": 0, "ip": 0, "default": [0, 1], "socket": [0, 1], "gethostbynam": 0, "localhost": 0, "port": [0, 1], "int": [0, 1], "number": [0, 1], "8000": 0, "worker": [0, 1], "1": 0, "debug": [0, 1], "bool": [0, 1], "boolean": [0, 1], "flag": [0, 1], "level": [0, 1], "log": [0, 1], "fals": [0, 1], "origin": [0, 1], "list": [0, 1], "allow": [0, 1], "connect": [0, 1], "through": [0, 1], "public": 0, "_": [0, 1], "address": [0, 1], "privat": 0, "refresh": [0, 1], "interv": [0, 1], "second": [0, 1], "none": [0, 1], "error": 0, "page": [0, 1], "filepath": 0, "serv": 0, "when": [0, 1], "api": 0, "i": [0, 1], "down": 0, "html": [0, 1], "dict": [0, 1], "origin_refresh": [0, 1], "updat": [0, 1], "base": [0, 1], "dhcp": 0, "leas": 0, "renew": 0, "case": [0, 1], "long": 0, "session": [0, 1], "config": [0, 1], "refer": [0, 1], "each": [0, 1], "multipl": [0, 1], "user1": 0, "user2": 0, "so": 0, "permiss": [0, 1], "admin": [0, 1], "authent": [0, 1], "sampl": 0, "directori": [0, 1], "nest": [0, 1], "ani": [0, 1], "chang": 0, "made": 0, "ui": 0, "lost": 0, "unless": 0, "back": 0, "up": [0, 1], "manual": 0, "alwai": 0, "go": 0, "instanti": [0, 1], "also": 0, "possibl": 0, "recommend": 0, "file_brows": 0, "user_profil": [0, 1], "usernam": [0, 1], "password": [0, 1], "user123": 0, "pwd456": 0, "might": 0, "complex": [0, 1], "better": 0, "instead": 0, "you": [0, 1], "which": [0, 1], "includ": 0, "collect": 0, "secur": 0, "trace": 0, "inform": [0, 1], "The": [0, 1], "pretti": 0, "restrict": 0, "natur": 0, "while": 0, "cor": [0, 1], "mai": 0, "solv": 0, "purpos": 0, "webpag": 0, "regardless": 0, "tool": 0, "postman": 0, "curl": 0, "wget": 0, "etc": 0, "due": 0, "behavior": 0, "pleas": 0, "make": 0, "sure": 0, "suppos": 0, "revers": 0, "cdn": 0, "redirect": 0, "servic": [0, 1], "fail": [0, 1], "login": 0, "attempt": [0, 1], "three": 0, "than": 0, "3": 0, "result": 0, "being": 0, "temporarili": 0, "block": [0, 1], "everi": 0, "after": [0, 1], "an": [0, 1], "increment": [0, 1], "10": 0, "perman": 0, "month": 0, "forbidden": [0, 1], "implement": [0, 1], "prevent": 0, "ddo": 0, "attack": 0, "maintain": 0, "stabil": 0, "perform": 0, "increas": 0, "inconspicu": 0, "latenc": 0, "asynchron": 0, "function": [0, 1], "render": 0, "payload": [0, 1], "size": [0, 1], "hardli": 0, "notic": 0, "docstr": 0, "format": [0, 1], "googl": 0, "style": 0, "pep": 0, "8": 0, "isort": 0, "gitvers": 0, "usag": 0, "f": 0, "release_not": 0, "rst": 0, "t": [0, 1], "pre": 0, "commit": 0, "ensur": 0, "gener": [0, 1], "sphinx": 0, "5": 0, "recommonmark": 0, "http": [0, 1], "org": 0, "project": 0, "thevickypedia": 0, "github": [0, 1], "io": 0, "vignesh": 0, "rao": 0, "under": 0, "mit": 0, "kick": 1, "off": 1, "environ": 1, "variabl": 1, "code": 1, "standard": 1, "releas": 1, "note": 1, "lint": 1, "pypi": 1, "packag": 1, "runbook": 1, "licens": 1, "copyright": 1, "epoch": 1, "refresh_allowed_origin": 1, "trigger": 1, "onc": 1, "repeatedli": 1, "given": 1, "background": 1, "onli": 1, "env": 1, "private_ip": 1, "public_ip": 1, "thei": 1, "dynam": 1, "valu": 1, "async": 1, "time": 1, "paramet": 1, "return": 1, "appropri": 1, "minut": 1, "type": 1, "handle_auth_error": 1, "request": 1, "incom": 1, "proxy_engin": 1, "proxy_request": 1, "respons": 1, "handler": 1, "forward": 1, "target": 1, "url": 1, "content": 1, "header": 1, "service_unavail": 1, "construct": 1, "jina": 1, "templat": 1, "unavail": 1, "string": 1, "class": 1, "rate_limit": 1, "ratelimit": 1, "rp": 1, "necessari": 1, "arg": 1, "max_request": 1, "maximum": 1, "frame": 1, "cach": 1, "expir": 1, "check": 1, "call": 1, "exce": 1, "identifi": 1, "rais": 1, "429": 1, "too": 1, "mani": 1, "repeated_tim": 1, "repeatedtim": 1, "callabl": 1, "tupl": 1, "kwarg": 1, "thread": 1, "argument": 1, "keyword": 1, "_run": 1, "isn": 1, "alreadi": 1, "stop": 1, "cancel": 1, "futur": 1, "calculate_hash": 1, "hash": 1, "base64_encod": 1, "base64": 1, "encod": 1, "base64_decod": 1, "decod": 1, "hex_decod": 1, "convert": 1, "hex": 1, "hex_encod": 1, "proxyserv": 1, "share": 1, "state": 1, "avail": 1, "between": 1, "protocol": 1, "instanc": 1, "com": 1, "uvicorn": 1, "issu": 1, "742": 1, "issuecom": 1, "674411676": 1, "run_in_parallel": 1, "logger": 1, "dedic": 1, "process": 1, "proxy_serv": 1, "log_config": 1, "auth_map": 1, "ha": 1, "author": 1, "map": 1, "creat": 1, "similar": 1, "add": 1, "depend": 1, "per": 1, "select": 1, "middlewar": 1, "log_connect": 1, "first": 1, "devic": 1, "avoid": 1, "same": 1, "access": 1, "differ": 1, "path": 1, "extract_credenti": 1, "byte": 1, "extract": 1, "credenti": 1, "befor": 1, "javascript": 1, "btoa": 1, "convertstringtohex": 1, "let": 1, "arr": 1, "0": 1, "length": 1, "00": 1, "charcodeat": 1, "tostr": 1, "16": 1, "slice": 1, "4": 1, "u": 1, "join": 1, "expect": 1, "encrypt": 1, "hex_us": 1, "await": 1, "signatur": 1, "calculatehash": 1, "hex_recaptcha": 1, "recaptcha": 1, "authhead": 1, "eslint": 1, "disabl": 1, "line": 1, "yield": 1, "part": 1, "proxy_auth": 1, "cryptograph": 1, "compar": 1, "receiv": 1, "messag": 1, "const": 1, "new": 1, "textencod": 1, "data": 1, "crypto": 1, "subtl": 1, "undefin": 1, "wordarrai": 1, "cryptoj": 1, "lib": 1, "sha512": 1, "enc": 1, "els": 1, "hashbuff": 1, "digest": 1, "sha": 1, "512": 1, "hasharrai": 1, "arrai": 1, "uint8arrai": 1, "padstart": 1, "2": 1, "destin": 1, "pydant": 1, "basemodel": 1, "pars": 1, "valid": 1, "input": 1, "validationerror": 1, "pydantic_cor": 1, "cannot": 1, "form": 1, "self": 1, "explicitli": 1, "posit": 1, "field": 1, "auth_config": 1, "envconfig": 1, "pydantic_set": 1, "baseset": 1, "across": 1, "databas": 1, "union": 1, "error_pag": 1, "classmethod": 1, "origins_url_check": 1, "v": 1, "store": 1, "rate_limit_check": 1, "env_fil": 1, "extra": 1, "ignor": 1, "auth_count": 1, "forbid": 1, "info": 1, "allowed_origin": 1, "stream": 1, "bring": 1, "own": 1, "cleanup": 1, "remov": 1, "exit_process": 1, "delet": 1, "file": 1, "subtitl": 1, "were": 1, "applic": 1, "run_subprocess": 1, "failed_msg": 1, "stdout": 1, "command": 1, "subprocess": 1, "failur": 1, "bad": 1, "show": 1, "hide": 1, "output": 1, "create_us": 1, "json": 1, "create_config": 1, "import_config": 1, "import_us": 1, "background_task": 1, "convers": 1, "abov": 1, "section": 1, "root": 1, "baseurl": 1, "tlskei": 1, "tlscert": 1, "enablethumbnail": 1, "resizepreview": 1, "enableexec": 1, "typedetectionbyhead": 1, "authhook": 1, "tokenexpirationtim": 1, "env_prefix": 1, "brand": 1, "prefix": 1, "branding_": 1, "present": 1, "disableextern": 1, "disableusedpercentag": 1, "theme": 1, "color": 1, "tu": 1, "tus_": 1, "chunksiz": 1, "retrycount": 1, "defaults_": 1, "scope": 1, "viewmod": 1, "singleclick": 1, "sort": 1, "perm": 1, "hidedotfil": 1, "dateformat": 1, "certain": 1, "event": 1, "runner": 1, "shell": 1, "after_copi": 1, "after_delet": 1, "after_renam": 1, "after_sav": 1, "after_upload": 1, "before_copi": 1, "before_delet": 1, "before_renam": 1, "before_sav": 1, "before_upload": 1, "commands_": 1, "signup": 1, "createuserdir": 1, "userhomebasepath": 1, "authmethod": 1, "shell_": 1, "rule": 1, "kei": 1, "secret": 1, "auther": 1, "auth_": 1, "configset": 1, "strenum": 1, "enum": 1, "light": 1, "dark": 1, "blank": 1, "sortbi": 1, "modifi": 1, "asc": 1, "renam": 1, "admin_perm": 1, "administr": 1, "default_perm": 1, "non": 1, "userset": 1, "lockpassword": 1, "from_env_fil": 1, "validate_password_complex": 1, "enter": 1, "dictionari": 1, "machin": 1, "filebrowser_o": 1, "filebrowser_bin": 1, "filebrowser_dl_ext": 1, "filebrowser_arch": 1, "filebrowser_fil": 1, "filebrowser_db": 1, "extendedenvsettingssourc": 1, "envsettingssourc": 1, "environment": 1, "get_field_valu": 1, "fieldinfo": 1, "field_nam": 1, "retriev": 1, "support": 1, "about": 1, "whether": 1, "extendedsettingsconfigdict": 1, "settingsconfigdict": 1, "addit": 1, "consid": 1, "extendedbaseset": 1, "settings_customise_sourc": 1, "extend": 1, "settings_cl": 1, "init_set": 1, "pydanticbasesettingssourc": 1, "env_set": 1, "dotenv_set": 1, "file_secret_set": 1, "dotenv": 1, "account": 1, "discuss": 1, "4319": 1, "control": 1, "dot": 1, "regular": 1, "owner": 1, "repo": 1, "token": 1, "version": 1, "latest": 1, "config_set": 1, "load_user_profil": 1, "current": 1, "fileio": 1, "settings_dir": 1, "ordin": 1, "n": 1, "represent": 1, "determin": 1, "default_logg": 1, "log_to_fil": 1, "consol": 1, "hash_password": 1, "salt": 1, "text": 1, "plain": 1, "validate_password": 1, "hashed_password": 1, "match": 1, "remove_trailing_underscor": 1, "iter": 1, "end": 1, "underscor": 1, "trail": 1, "remove_prefix": 1, "loggerconfig": 1, "formatt": 1, "get": 1, "full": 1, "re": 1, "configr": 1, "update_log_level": 1, "new_valu": 1, "recurs": 1, "where": 1, "equal": 1, "travers": 1, "index": 1, "search": 1}, "objects": {"pyfilebrowser": [[1, 0, 0, "-", "main"]], "pyfilebrowser.main": [[1, 1, 1, "", "FileBrowser"]], "pyfilebrowser.main.FileBrowser": [[1, 2, 1, "", "background_tasks"], [1, 2, 1, "", "cleanup"], [1, 2, 1, "", "create_config"], [1, 2, 1, "", "create_users"], [1, 2, 1, "", "exit_process"], [1, 2, 1, "", "import_config"], [1, 2, 1, "", "import_users"], [1, 2, 1, "", "run_subprocess"], [1, 2, 1, "", "start"]], "pyfilebrowser.modals.config": [[1, 1, 1, "", "Auther"], [1, 1, 1, "", "Branding"], [1, 1, 1, "", "Commands"], [1, 1, 1, "", "Config"], [1, 1, 1, "", "ConfigSettings"], [1, 1, 1, "", "Defaults"], [1, 1, 1, "", "ReCAPTCHA"], [1, 1, 1, "", "Server"], [1, 1, 1, "", "Tus"]], "pyfilebrowser.modals.config.Auther": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "recaptcha"]], "pyfilebrowser.modals.config.Auther.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Branding": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "color"], [1, 3, 1, "", "disableExternal"], [1, 3, 1, "", "disableUsedPercentage"], [1, 3, 1, "", "files"], [1, 3, 1, "", "name"], [1, 3, 1, "", "theme"]], "pyfilebrowser.modals.config.Branding.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Commands": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "after_copy"], [1, 3, 1, "", "after_delete"], [1, 3, 1, "", "after_rename"], [1, 3, 1, "", "after_save"], [1, 3, 1, "", "after_upload"], [1, 3, 1, "", "before_copy"], [1, 3, 1, "", "before_delete"], [1, 3, 1, "", "before_rename"], [1, 3, 1, "", "before_save"], [1, 3, 1, "", "before_upload"]], "pyfilebrowser.modals.config.Commands.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Config": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "authHeader"], [1, 3, 1, "", "authMethod"], [1, 3, 1, "", "branding"], [1, 3, 1, "", "commands"], [1, 3, 1, "", "createUserDir"], [1, 3, 1, "", "defaults"], [1, 3, 1, "", "rules"], [1, 3, 1, "", "shell_"], [1, 3, 1, "", "signup"], [1, 3, 1, "", "tus"], [1, 3, 1, "", "userHomeBasePath"]], "pyfilebrowser.modals.config.Config.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.ConfigSettings": [[1, 3, 1, "", "auther"], [1, 3, 1, "", "server"], [1, 3, 1, "", "settings"]], "pyfilebrowser.modals.config.Defaults": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "commands"], [1, 3, 1, "", "dateFormat"], [1, 3, 1, "", "hideDotfiles"], [1, 3, 1, "", "locale"], [1, 3, 1, "", "perm"], [1, 3, 1, "", "scope"], [1, 3, 1, "", "singleClick"], [1, 3, 1, "", "sorting"], [1, 3, 1, "", "viewMode"]], "pyfilebrowser.modals.config.Defaults.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.ReCAPTCHA": [[1, 3, 1, "", "host"], [1, 3, 1, "", "key"], [1, 3, 1, "", "secret"]], "pyfilebrowser.modals.config.Server": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "address"], [1, 3, 1, "", "authHook"], [1, 3, 1, "", "baseURL"], [1, 3, 1, "", "enableExec"], [1, 3, 1, "", "enableThumbnails"], [1, 3, 1, "", "log"], [1, 3, 1, "", "port"], [1, 3, 1, "", "resizePreview"], [1, 3, 1, "", "root"], [1, 3, 1, "", "socket"], [1, 3, 1, "", "tlsCert"], [1, 3, 1, "", "tlsKey"], [1, 3, 1, "", "tokenExpirationTime"], [1, 3, 1, "", "typeDetectionByHeader"]], "pyfilebrowser.modals.config.Server.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Tus": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "chunkSize"], [1, 3, 1, "", "retryCount"]], "pyfilebrowser.modals.config.Tus.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals": [[1, 0, 0, "-", "models"]], "pyfilebrowser.modals.models": [[1, 1, 1, "", "Log"], [1, 1, 1, "", "Perm"], [1, 1, 1, "", "SortBy"], [1, 1, 1, "", "Sorting"], [1, 1, 1, "", "Theme"], [1, 4, 1, "", "admin_perm"], [1, 4, 1, "", "default_perm"]], "pyfilebrowser.modals.models.Log": [[1, 3, 1, "", "file"], [1, 3, 1, "", "stdout"]], "pyfilebrowser.modals.models.Perm": [[1, 3, 1, "", "admin"], [1, 3, 1, "", "create"], [1, 3, 1, "", "delete"], [1, 3, 1, "", "download"], [1, 3, 1, "", "execute"], [1, 3, 1, "", "modify"], [1, 3, 1, "", "rename"], [1, 3, 1, "", "share"]], "pyfilebrowser.modals.models.SortBy": [[1, 3, 1, "", "modified"], [1, 3, 1, "", "name"], [1, 3, 1, "", "size"]], "pyfilebrowser.modals.models.Sorting": [[1, 3, 1, "", "asc"], [1, 3, 1, "", "by"]], "pyfilebrowser.modals.models.Theme": [[1, 3, 1, "", "blank"], [1, 3, 1, "", "dark"], [1, 3, 1, "", "light"]], "pyfilebrowser.modals.users": [[1, 1, 1, "", "Authentication"], [1, 1, 1, "", "UserSettings"]], "pyfilebrowser.modals.users.Authentication": [[1, 3, 1, "", "admin"], [1, 3, 1, "", "password"], [1, 3, 1, "", "username"]], "pyfilebrowser.modals.users.UserSettings": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "authentication"], [1, 3, 1, "", "commands"], [1, 3, 1, "", "dateFormat"], [1, 2, 1, "", "from_env_file"], [1, 3, 1, "", "hideDotfiles"], [1, 3, 1, "", "locale"], [1, 3, 1, "", "lockPassword"], [1, 3, 1, "", "perm"], [1, 3, 1, "", "rules"], [1, 3, 1, "", "scope"], [1, 3, 1, "", "singleClick"], [1, 3, 1, "", "sorting"], [1, 2, 1, "", "validate_password_complexity"], [1, 3, 1, "", "viewMode"]], "pyfilebrowser.modals.users.UserSettings.Config": [[1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.proxy": [[1, 0, 0, "-", "error"], [1, 0, 0, "-", "main"], [1, 0, 0, "-", "rate_limit"], [1, 0, 0, "-", "repeated_timer"], [1, 0, 0, "-", "secure"], [1, 0, 0, "-", "server"], [1, 0, 0, "-", "squire"]], "pyfilebrowser.proxy.error": [[1, 4, 1, "", "forbidden"], [1, 4, 1, "", "service_unavailable"]], "pyfilebrowser.proxy.main": [[1, 4, 1, "", "epoch"], [1, 4, 1, "", "handle_auth_error"], [1, 4, 1, "", "incrementer"], [1, 4, 1, "", "proxy_engine"], [1, 4, 1, "", "refresh_allowed_origins"]], "pyfilebrowser.proxy.rate_limit": [[1, 1, 1, "", "RateLimiter"]], "pyfilebrowser.proxy.rate_limit.RateLimiter": [[1, 2, 1, "", "init"], [1, 3, 1, "", "max_requests"], [1, 3, 1, "", "seconds"]], "pyfilebrowser.proxy.repeated_timer": [[1, 1, 1, "", "RepeatedTimer"]], "pyfilebrowser.proxy.repeated_timer.RepeatedTimer": [[1, 2, 1, "", "_run"], [1, 2, 1, "", "cancel"], [1, 2, 1, "", "start"], [1, 2, 1, "", "stop"]], "pyfilebrowser.proxy.secure": [[1, 4, 1, "", "base64_decode"], [1, 4, 1, "", "base64_encode"], [1, 4, 1, "", "calculate_hash"], [1, 4, 1, "", "hex_decode"], [1, 4, 1, "", "hex_encode"]], "pyfilebrowser.proxy.server": [[1, 1, 1, "", "ProxyServer"], [1, 4, 1, "", "proxy_server"]], "pyfilebrowser.proxy.server.ProxyServer": [[1, 2, 1, "", "run_in_parallel"]], "pyfilebrowser.proxy.settings": [[1, 1, 1, "", "Destination"], [1, 1, 1, "", "EnvConfig"], [1, 1, 1, "", "RateLimit"], [1, 1, 1, "", "Session"]], "pyfilebrowser.proxy.settings.Destination": [[1, 3, 1, "", "auth_config"], [1, 3, 1, "", "url"]], "pyfilebrowser.proxy.settings.EnvConfig": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "database"], [1, 3, 1, "", "debug"], [1, 3, 1, "", "error_page"], [1, 3, 1, "", "host"], [1, 3, 1, "", "origin_refresh"], [1, 3, 1, "", "origins"], [1, 2, 1, "", "origins_url_checker"], [1, 3, 1, "", "port"], [1, 3, 1, "", "private_ip"], [1, 3, 1, "", "public_ip"], [1, 3, 1, "", "rate_limit"], [1, 2, 1, "", "rate_limit_checker"], [1, 3, 1, "", "workers"]], "pyfilebrowser.proxy.settings.EnvConfig.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "extra"]], "pyfilebrowser.proxy.settings.RateLimit": [[1, 3, 1, "", "max_requests"], [1, 3, 1, "", "seconds"]], "pyfilebrowser.proxy.settings.Session": [[1, 3, 1, "", "allowed_origins"], [1, 3, 1, "", "auth_counter"], [1, 3, 1, "", "forbid"], [1, 3, 1, "", "info"], [1, 3, 1, "", "rps"]], "pyfilebrowser.proxy.squire": [[1, 4, 1, "", "extract_credentials"], [1, 4, 1, "", "log_connection"], [1, 4, 1, "", "proxy_auth"]], "pyfilebrowser.squire": [[1, 0, 0, "-", "download"], [1, 0, 0, "-", "steward"], [1, 0, 0, "-", "struct"]], "pyfilebrowser.squire.download": [[1, 1, 1, "", "Executable"], [1, 1, 1, "", "ExtendedEnvSettingsSource"], [1, 1, 1, "", "ExtendedSettingsConfigDict"], [1, 1, 1, "", "GitHub"], [1, 4, 1, "", "binary"]], "pyfilebrowser.squire.download.Executable": [[1, 3, 1, "", "filebrowser_arch"], [1, 3, 1, "", "filebrowser_bin"], [1, 3, 1, "", "filebrowser_db"], [1, 3, 1, "", "filebrowser_dl_ext"], [1, 3, 1, "", "filebrowser_file"], [1, 3, 1, "", "filebrowser_os"], [1, 3, 1, "", "machine"], [1, 3, 1, "", "system"]], "pyfilebrowser.squire.download.ExtendedEnvSettingsSource": [[1, 2, 1, "", "get_field_value"]], "pyfilebrowser.squire.download.ExtendedSettingsConfigDict": [[1, 3, 1, "", "env_prefixes"]], "pyfilebrowser.squire.download.GitHub": [[1, 3, 1, "", "owner"], [1, 3, 1, "", "repo"], [1, 3, 1, "", "token"], [1, 3, 1, "", "version"]], "pyfilebrowser.squire.steward": [[1, 1, 1, "", "EnvConfig"], [1, 1, 1, "", "FileIO"], [1, 4, 1, "", "default_logger"], [1, 4, 1, "", "hash_password"], [1, 4, 1, "", "ordinal"], [1, 4, 1, "", "remove_prefix"], [1, 4, 1, "", "remove_trailing_underscore"], [1, 4, 1, "", "validate_password"]], "pyfilebrowser.squire.steward.EnvConfig": [[1, 3, 1, "", "config_settings"], [1, 2, 1, "", "load_user_profiles"], [1, 3, 1, "", "user_profiles"]], "pyfilebrowser.squire.steward.FileIO": [[1, 3, 1, "", "config"], [1, 3, 1, "", "settings_dir"], [1, 3, 1, "", "users"]], "pyfilebrowser.squire.struct": [[1, 1, 1, "", "LoggerConfig"], [1, 4, 1, "", "update_log_level"]], "pyfilebrowser.squire.struct.LoggerConfig": [[1, 2, 1, "", "extract"], [1, 2, 1, "", "get"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:attribute", "4": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "function", "Python function"]}, "titleterms": {"pyfilebrows": [0, 1], "kick": 0, "off": 0, "environ": 0, "variabl": 0, "env": 0, "file": 0, "proxi": [0, 1], "server": [0, 1], "firewal": 0, "brute": 0, "forc": 0, "protect": 0, "rate": [0, 1], "limit": [0, 1], "code": 0, "standard": 0, "releas": 0, "note": 0, "lint": 0, "pypi": 0, "packag": 0, "runbook": 0, "licens": 0, "copyright": 0, "welcom": 1, "": 1, "document": 1, "read": 1, "me": 1, "engin": 1, "error": 1, "repeat": 1, "timer": 1, "secur": 1, "squir": 1, "set": 1, "pyfb": 1, "api": 1, "client": 1, "main": 1, "modul": 1, "modal": 1, "configur": 1, "model": 1, "user": 1, "download": 1, "steward": 1, "struct": 1, "indic": 1, "tabl": 1}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file +Search.setIndex({"docnames": ["README", "index"], "filenames": ["README.md", "index.rst"], "titles": ["PyFileBrowser", "Welcome to PyFileBrowser\u2019s documentation!"], "terms": {"deploy": 0, "introduc": 0, "python": 0, "librari": 0, "design": 0, "streamlin": 0, "interact": 0, "filebrows": [0, 1], "thi": [0, 1], "wrapper": [0, 1], "simplifi": 0, "integr": 0, "autom": 0, "task": [0, 1], "enabl": [0, 1], "seamless": 0, "your": [0, 1], "local": [0, 1], "system": [0, 1], "via": 0, "": 0, "web": 0, "interfac": 0, "all": [0, 1], "requir": 0, "configur": 0, "set": 0, "user": 0, "profil": [0, 1], "ar": [0, 1], "load": [0, 1], "us": [0, 1], "provid": [0, 1], "more": 0, "central": 0, "wai": 0, "handl": [0, 1], "initi": [0, 1], "automat": 0, "download": 0, "specif": 0, "execut": [0, 1], "dure": [0, 1], "startup": 0, "custom": [0, 1], "built": [0, 1], "addition": 0, "sourc": [0, 1], "binari": [0, 1], "can": [0, 1], "specifi": 0, "follow": 0, "owner": [0, 1], "github": [0, 1], "repo": [0, 1], "repositori": 0, "name": [0, 1], "token": [0, 1], "version": [0, 1], "also": 0, "support": 0, "dotenv": 0, "prefix": [0, 1], "like": 0, "git": 0, "For": 0, "featur": [0, 1], "work": 0, "should": [0, 1], "upload": [0, 1], "asset": [0, 1], "convent": 0, "below": 0, "oper": 0, "architectur": 0, "extens": 0, "exampl": 0, "darwin": 0, "amd64": 0, "tar": 0, "gz": 0, "instal": 0, "m": 0, "pip": 0, "programmat": 0, "import": [0, 1], "__name__": 0, "__main__": 0, "browser": [0, 1], "true": [0, 1], "option": [0, 1], "run": [0, 1], "parallel": [0, 1], "start": [0, 1], "cli": 0, "var": [0, 1], "either": 0, "from": [0, 1], "directli": 0, "pass": [0, 1], "object": [0, 1], "init": [0, 1], "host": [0, 1], "str": [0, 1], "hostnam": 0, "ip": 0, "default": [0, 1], "socket": [0, 1], "gethostbynam": 0, "localhost": 0, "port": [0, 1], "int": [0, 1], "number": [0, 1], "8000": 0, "worker": [0, 1], "1": 0, "debug": [0, 1], "bool": [0, 1], "boolean": [0, 1], "flag": [0, 1], "level": [0, 1], "log": [0, 1], "fals": [0, 1], "origin": [0, 1], "list": [0, 1], "allow": [0, 1], "connect": [0, 1], "through": [0, 1], "_": [0, 1], "public": 0, "address": [0, 1], "privat": 0, "refresh": [0, 1], "interv": [0, 1], "second": [0, 1], "none": [0, 1], "error": 0, "page": [0, 1], "filepath": 0, "serv": 0, "when": [0, 1], "api": 0, "i": [0, 1], "down": 0, "html": [0, 1], "warn": 0, "access": [0, 1], "unsupport": [0, 1], "dict": [0, 1], "origin_refresh": [0, 1], "updat": [0, 1], "base": [0, 1], "dhcp": 0, "leas": 0, "renew": 0, "case": [0, 1], "long": 0, "session": [0, 1], "config": [0, 1], "refer": [0, 1], "each": [0, 1], "multipl": [0, 1], "user1": 0, "user2": 0, "so": 0, "permiss": [0, 1], "admin": [0, 1], "authent": [0, 1], "sampl": 0, "directori": [0, 1], "nest": [0, 1], "ani": [0, 1], "chang": 0, "made": 0, "ui": 0, "lost": 0, "unless": 0, "back": 0, "up": [0, 1], "manual": 0, "alwai": 0, "go": 0, "instanti": [0, 1], "possibl": 0, "recommend": 0, "file_brows": 0, "user_profil": [0, 1], "usernam": [0, 1], "password": [0, 1], "user123": 0, "pwd456": 0, "might": 0, "complex": 0, "better": 0, "instead": 0, "you": [0, 1], "which": [0, 1], "includ": 0, "collect": 0, "secur": 0, "trace": 0, "inform": [0, 1], "The": [0, 1], "pretti": 0, "restrict": 0, "natur": 0, "while": 0, "cor": [0, 1], "mai": 0, "solv": 0, "purpos": 0, "webpag": 0, "regardless": 0, "tool": 0, "postman": 0, "curl": 0, "wget": 0, "etc": 0, "due": 0, "behavior": 0, "pleas": 0, "make": 0, "sure": 0, "suppos": 0, "revers": 0, "cdn": 0, "redirect": 0, "servic": [0, 1], "fail": [0, 1], "login": 0, "attempt": [0, 1], "three": 0, "than": 0, "3": 0, "result": 0, "being": 0, "temporarili": 0, "block": [0, 1], "everi": 0, "after": [0, 1], "an": [0, 1], "increment": [0, 1], "10": 0, "perman": 0, "month": 0, "forbidden": [0, 1], "implement": [0, 1], "prevent": 0, "ddo": 0, "attack": 0, "maintain": 0, "stabil": 0, "perform": 0, "increas": 0, "inconspicu": 0, "latenc": 0, "asynchron": 0, "function": [0, 1], "render": [0, 1], "payload": [0, 1], "size": [0, 1], "hardli": 0, "notic": 0, "docstr": 0, "format": [0, 1], "googl": 0, "style": 0, "pep": 0, "8": 0, "isort": 0, "gitvers": 0, "usag": 0, "f": 0, "release_not": 0, "rst": 0, "t": [0, 1], "pre": 0, "commit": 0, "ensur": 0, "gener": [0, 1], "sphinx": 0, "5": 0, "recommonmark": 0, "http": [0, 1], "org": 0, "project": 0, "thevickypedia": 0, "io": 0, "vignesh": 0, "rao": 0, "under": 0, "mit": 0, "kick": 1, "off": 1, "environ": 1, "variabl": 1, "code": 1, "standard": 1, "releas": 1, "note": 1, "lint": 1, "pypi": 1, "packag": 1, "runbook": 1, "licens": 1, "copyright": 1, "epoch": 1, "refresh_allowed_origin": 1, "trigger": 1, "onc": 1, "repeatedli": 1, "given": 1, "background": 1, "onli": 1, "env": 1, "private_ip": 1, "public_ip": 1, "thei": 1, "dynam": 1, "valu": 1, "async": 1, "time": 1, "paramet": 1, "return": 1, "appropri": 1, "minut": 1, "type": 1, "handle_auth_error": 1, "request": 1, "incom": 1, "proxy_engin": 1, "proxy_request": 1, "respons": 1, "handler": 1, "forward": 1, "target": 1, "url": 1, "content": 1, "header": 1, "service_unavail": 1, "construct": 1, "jina": 1, "templat": 1, "unavail": 1, "string": 1, "class": 1, "rate_limit": 1, "ratelimit": 1, "rp": 1, "necessari": 1, "arg": 1, "max_request": 1, "maximum": 1, "frame": 1, "cach": 1, "expir": 1, "check": 1, "call": 1, "exce": 1, "identifi": 1, "rais": 1, "429": 1, "too": 1, "mani": 1, "repeated_tim": 1, "repeatedtim": 1, "callabl": 1, "tupl": 1, "kwarg": 1, "thread": 1, "argument": 1, "keyword": 1, "_run": 1, "isn": 1, "alreadi": 1, "stop": 1, "cancel": 1, "futur": 1, "calculate_hash": 1, "hash": 1, "base64_encod": 1, "base64": 1, "encod": 1, "base64_decod": 1, "decod": 1, "hex_decod": 1, "convert": 1, "hex": 1, "hex_encod": 1, "proxyserv": 1, "share": 1, "state": 1, "avail": 1, "between": 1, "protocol": 1, "instanc": 1, "com": 1, "uvicorn": 1, "issu": 1, "742": 1, "issuecom": 1, "674411676": 1, "run_in_parallel": 1, "logger": 1, "dedic": 1, "process": 1, "proxy_serv": 1, "log_config": 1, "auth_map": 1, "ha": 1, "author": 1, "map": 1, "creat": 1, "similar": 1, "add": 1, "depend": 1, "per": 1, "select": 1, "middlewar": 1, "log_connect": 1, "starlett": 1, "htmlrespons": 1, "video": 1, "audio": 1, "first": 1, "devic": 1, "avoid": 1, "same": 1, "differ": 1, "path": 1, "extract_credenti": 1, "byte": 1, "extract": 1, "credenti": 1, "befor": 1, "javascript": 1, "btoa": 1, "convertstringtohex": 1, "let": 1, "arr": 1, "0": 1, "length": 1, "00": 1, "charcodeat": 1, "tostr": 1, "16": 1, "slice": 1, "4": 1, "u": 1, "join": 1, "expect": 1, "encrypt": 1, "hex_us": 1, "await": 1, "signatur": 1, "calculatehash": 1, "hex_recaptcha": 1, "recaptcha": 1, "authhead": 1, "eslint": 1, "disabl": 1, "line": 1, "yield": 1, "part": 1, "proxy_auth": 1, "cryptograph": 1, "compar": 1, "receiv": 1, "messag": 1, "const": 1, "new": 1, "textencod": 1, "data": 1, "crypto": 1, "subtl": 1, "undefin": 1, "wordarrai": 1, "cryptoj": 1, "lib": 1, "sha512": 1, "enc": 1, "els": 1, "hashbuff": 1, "digest": 1, "sha": 1, "512": 1, "hasharrai": 1, "arrai": 1, "uint8arrai": 1, "padstart": 1, "2": 1, "destin": 1, "pydant": 1, "basemodel": 1, "pars": 1, "valid": 1, "input": 1, "validationerror": 1, "pydantic_cor": 1, "cannot": 1, "form": 1, "self": 1, "explicitli": 1, "posit": 1, "field": 1, "auth_config": 1, "envconfig": 1, "pydantic_set": 1, "baseset": 1, "across": 1, "databas": 1, "allow_public_ip": 1, "allow_private_ip": 1, "union": 1, "unsupported_brows": 1, "warn_pag": 1, "error_pag": 1, "classmethod": 1, "parse_unsupported_brows": 1, "parse_origin": 1, "store": 1, "parse_rate_limit": 1, "env_fil": 1, "extra": 1, "ignor": 1, "auth_count": 1, "forbid": 1, "info": 1, "allowed_origin": 1, "stream": 1, "bring": 1, "own": 1, "cleanup": 1, "remov": 1, "exit_process": 1, "delet": 1, "file": 1, "subtitl": 1, "were": 1, "applic": 1, "run_subprocess": 1, "failed_msg": 1, "stdout": 1, "command": 1, "subprocess": 1, "failur": 1, "bad": 1, "show": 1, "hide": 1, "output": 1, "create_us": 1, "json": 1, "create_config": 1, "import_config": 1, "import_us": 1, "background_task": 1, "convers": 1, "abov": 1, "section": 1, "root": 1, "baseurl": 1, "tlskei": 1, "tlscert": 1, "enablethumbnail": 1, "resizepreview": 1, "enableexec": 1, "typedetectionbyhead": 1, "authhook": 1, "tokenexpirationtim": 1, "env_prefix": 1, "brand": 1, "branding_": 1, "present": 1, "disableextern": 1, "disableusedpercentag": 1, "theme": 1, "color": 1, "tu": 1, "tus_": 1, "chunksiz": 1, "retrycount": 1, "defaults_": 1, "scope": 1, "viewmod": 1, "singleclick": 1, "sort": 1, "perm": 1, "hidedotfil": 1, "dateformat": 1, "certain": 1, "event": 1, "runner": 1, "shell": 1, "after_copi": 1, "after_delet": 1, "after_renam": 1, "after_sav": 1, "after_upload": 1, "before_copi": 1, "before_delet": 1, "before_renam": 1, "before_sav": 1, "before_upload": 1, "commands_": 1, "signup": 1, "createuserdir": 1, "userhomebasepath": 1, "authmethod": 1, "shell_": 1, "rule": 1, "kei": 1, "secret": 1, "auther": 1, "auth_": 1, "configset": 1, "strenum": 1, "enum": 1, "light": 1, "dark": 1, "blank": 1, "sortbi": 1, "modifi": 1, "asc": 1, "renam": 1, "admin_perm": 1, "administr": 1, "default_perm": 1, "non": 1, "userset": 1, "lockpassword": 1, "from_env_fil": 1, "validate_password_complex": 1, "enter": 1, "dictionari": 1, "machin": 1, "filebrowser_o": 1, "filebrowser_bin": 1, "filebrowser_dl_ext": 1, "filebrowser_arch": 1, "filebrowser_fil": 1, "filebrowser_db": 1, "account": 1, "alias_choic": 1, "aliaschoic": 1, "alia": 1, "choic": 1, "latest": 1, "config_set": 1, "load_user_profil": 1, "current": 1, "fileio": 1, "settings_dir": 1, "ordin": 1, "n": 1, "represent": 1, "determin": 1, "default_logg": 1, "log_to_fil": 1, "consol": 1, "hash_password": 1, "salt": 1, "text": 1, "plain": 1, "validate_password": 1, "hashed_password": 1, "whether": 1, "match": 1, "remove_trailing_underscor": 1, "iter": 1, "end": 1, "underscor": 1, "trail": 1, "remove_prefix": 1, "loggerconfig": 1, "formatt": 1, "get": 1, "full": 1, "re": 1, "configr": 1, "update_log_level": 1, "new_valu": 1, "recurs": 1, "where": 1, "equal": 1, "travers": 1, "index": 1, "search": 1}, "objects": {"pyfilebrowser": [[1, 0, 0, "-", "main"]], "pyfilebrowser.main": [[1, 1, 1, "", "FileBrowser"]], "pyfilebrowser.main.FileBrowser": [[1, 2, 1, "", "background_tasks"], [1, 2, 1, "", "cleanup"], [1, 2, 1, "", "create_config"], [1, 2, 1, "", "create_users"], [1, 2, 1, "", "exit_process"], [1, 2, 1, "", "import_config"], [1, 2, 1, "", "import_users"], [1, 2, 1, "", "run_subprocess"], [1, 2, 1, "", "start"]], "pyfilebrowser.modals.config": [[1, 1, 1, "", "Auther"], [1, 1, 1, "", "Branding"], [1, 1, 1, "", "Commands"], [1, 1, 1, "", "Config"], [1, 1, 1, "", "ConfigSettings"], [1, 1, 1, "", "Defaults"], [1, 1, 1, "", "ReCAPTCHA"], [1, 1, 1, "", "Server"], [1, 1, 1, "", "Tus"]], "pyfilebrowser.modals.config.Auther": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "recaptcha"]], "pyfilebrowser.modals.config.Auther.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Branding": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "color"], [1, 3, 1, "", "disableExternal"], [1, 3, 1, "", "disableUsedPercentage"], [1, 3, 1, "", "files"], [1, 3, 1, "", "name"], [1, 3, 1, "", "theme"]], "pyfilebrowser.modals.config.Branding.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Commands": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "after_copy"], [1, 3, 1, "", "after_delete"], [1, 3, 1, "", "after_rename"], [1, 3, 1, "", "after_save"], [1, 3, 1, "", "after_upload"], [1, 3, 1, "", "before_copy"], [1, 3, 1, "", "before_delete"], [1, 3, 1, "", "before_rename"], [1, 3, 1, "", "before_save"], [1, 3, 1, "", "before_upload"]], "pyfilebrowser.modals.config.Commands.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Config": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "authHeader"], [1, 3, 1, "", "authMethod"], [1, 3, 1, "", "branding"], [1, 3, 1, "", "commands"], [1, 3, 1, "", "createUserDir"], [1, 3, 1, "", "defaults"], [1, 3, 1, "", "rules"], [1, 3, 1, "", "shell_"], [1, 3, 1, "", "signup"], [1, 3, 1, "", "tus"], [1, 3, 1, "", "userHomeBasePath"]], "pyfilebrowser.modals.config.Config.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.ConfigSettings": [[1, 3, 1, "", "auther"], [1, 3, 1, "", "server"], [1, 3, 1, "", "settings"]], "pyfilebrowser.modals.config.Defaults": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "commands"], [1, 3, 1, "", "dateFormat"], [1, 3, 1, "", "hideDotfiles"], [1, 3, 1, "", "locale"], [1, 3, 1, "", "perm"], [1, 3, 1, "", "scope"], [1, 3, 1, "", "singleClick"], [1, 3, 1, "", "sorting"], [1, 3, 1, "", "viewMode"]], "pyfilebrowser.modals.config.Defaults.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.ReCAPTCHA": [[1, 3, 1, "", "host"], [1, 3, 1, "", "key"], [1, 3, 1, "", "secret"]], "pyfilebrowser.modals.config.Server": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "address"], [1, 3, 1, "", "authHook"], [1, 3, 1, "", "baseURL"], [1, 3, 1, "", "enableExec"], [1, 3, 1, "", "enableThumbnails"], [1, 3, 1, "", "log"], [1, 3, 1, "", "port"], [1, 3, 1, "", "resizePreview"], [1, 3, 1, "", "root"], [1, 3, 1, "", "socket"], [1, 3, 1, "", "tlsCert"], [1, 3, 1, "", "tlsKey"], [1, 3, 1, "", "tokenExpirationTime"], [1, 3, 1, "", "typeDetectionByHeader"]], "pyfilebrowser.modals.config.Server.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals.config.Tus": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "chunkSize"], [1, 3, 1, "", "retryCount"]], "pyfilebrowser.modals.config.Tus.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.modals": [[1, 0, 0, "-", "models"]], "pyfilebrowser.modals.models": [[1, 1, 1, "", "Log"], [1, 1, 1, "", "Perm"], [1, 1, 1, "", "SortBy"], [1, 1, 1, "", "Sorting"], [1, 1, 1, "", "Theme"], [1, 4, 1, "", "admin_perm"], [1, 4, 1, "", "default_perm"]], "pyfilebrowser.modals.models.Log": [[1, 3, 1, "", "file"], [1, 3, 1, "", "stdout"]], "pyfilebrowser.modals.models.Perm": [[1, 3, 1, "", "admin"], [1, 3, 1, "", "create"], [1, 3, 1, "", "delete"], [1, 3, 1, "", "download"], [1, 3, 1, "", "execute"], [1, 3, 1, "", "modify"], [1, 3, 1, "", "rename"], [1, 3, 1, "", "share"]], "pyfilebrowser.modals.models.SortBy": [[1, 3, 1, "", "modified"], [1, 3, 1, "", "name"], [1, 3, 1, "", "size"]], "pyfilebrowser.modals.models.Sorting": [[1, 3, 1, "", "asc"], [1, 3, 1, "", "by"]], "pyfilebrowser.modals.models.Theme": [[1, 3, 1, "", "blank"], [1, 3, 1, "", "dark"], [1, 3, 1, "", "light"]], "pyfilebrowser.modals.users": [[1, 1, 1, "", "Authentication"], [1, 1, 1, "", "UserSettings"]], "pyfilebrowser.modals.users.Authentication": [[1, 3, 1, "", "admin"], [1, 3, 1, "", "password"], [1, 3, 1, "", "username"]], "pyfilebrowser.modals.users.UserSettings": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "authentication"], [1, 3, 1, "", "commands"], [1, 3, 1, "", "dateFormat"], [1, 2, 1, "", "from_env_file"], [1, 3, 1, "", "hideDotfiles"], [1, 3, 1, "", "locale"], [1, 3, 1, "", "lockPassword"], [1, 3, 1, "", "perm"], [1, 3, 1, "", "rules"], [1, 3, 1, "", "scope"], [1, 3, 1, "", "singleClick"], [1, 3, 1, "", "sorting"], [1, 2, 1, "", "validate_password_complexity"], [1, 3, 1, "", "viewMode"]], "pyfilebrowser.modals.users.UserSettings.Config": [[1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.proxy": [[1, 0, 0, "-", "error"], [1, 0, 0, "-", "main"], [1, 0, 0, "-", "rate_limit"], [1, 0, 0, "-", "repeated_timer"], [1, 0, 0, "-", "secure"], [1, 0, 0, "-", "server"], [1, 0, 0, "-", "squire"]], "pyfilebrowser.proxy.error": [[1, 4, 1, "", "forbidden"], [1, 4, 1, "", "service_unavailable"]], "pyfilebrowser.proxy.main": [[1, 4, 1, "", "epoch"], [1, 4, 1, "", "handle_auth_error"], [1, 4, 1, "", "incrementer"], [1, 4, 1, "", "proxy_engine"], [1, 4, 1, "", "refresh_allowed_origins"]], "pyfilebrowser.proxy.rate_limit": [[1, 1, 1, "", "RateLimiter"]], "pyfilebrowser.proxy.rate_limit.RateLimiter": [[1, 2, 1, "", "init"], [1, 3, 1, "", "max_requests"], [1, 3, 1, "", "seconds"]], "pyfilebrowser.proxy.repeated_timer": [[1, 1, 1, "", "RepeatedTimer"]], "pyfilebrowser.proxy.repeated_timer.RepeatedTimer": [[1, 2, 1, "", "_run"], [1, 2, 1, "", "cancel"], [1, 2, 1, "", "start"], [1, 2, 1, "", "stop"]], "pyfilebrowser.proxy.secure": [[1, 4, 1, "", "base64_decode"], [1, 4, 1, "", "base64_encode"], [1, 4, 1, "", "calculate_hash"], [1, 4, 1, "", "hex_decode"], [1, 4, 1, "", "hex_encode"]], "pyfilebrowser.proxy.server": [[1, 1, 1, "", "ProxyServer"], [1, 4, 1, "", "proxy_server"]], "pyfilebrowser.proxy.server.ProxyServer": [[1, 2, 1, "", "run_in_parallel"]], "pyfilebrowser.proxy.settings": [[1, 1, 1, "", "Destination"], [1, 1, 1, "", "EnvConfig"], [1, 1, 1, "", "RateLimit"], [1, 1, 1, "", "Session"]], "pyfilebrowser.proxy.settings.Destination": [[1, 3, 1, "", "auth_config"], [1, 3, 1, "", "url"]], "pyfilebrowser.proxy.settings.EnvConfig": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "allow_private_ip"], [1, 3, 1, "", "allow_public_ip"], [1, 3, 1, "", "database"], [1, 3, 1, "", "debug"], [1, 3, 1, "", "error_page"], [1, 3, 1, "", "host"], [1, 3, 1, "", "origin_refresh"], [1, 3, 1, "", "origins"], [1, 2, 1, "", "parse_origins"], [1, 2, 1, "", "parse_rate_limit"], [1, 2, 1, "", "parse_unsupported_browsers"], [1, 3, 1, "", "port"], [1, 3, 1, "", "rate_limit"], [1, 3, 1, "", "unsupported_browsers"], [1, 3, 1, "", "warn_page"], [1, 3, 1, "", "workers"]], "pyfilebrowser.proxy.settings.EnvConfig.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "extra"]], "pyfilebrowser.proxy.settings.RateLimit": [[1, 3, 1, "", "max_requests"], [1, 3, 1, "", "seconds"]], "pyfilebrowser.proxy.settings.Session": [[1, 3, 1, "", "allowed_origins"], [1, 3, 1, "", "auth_counter"], [1, 3, 1, "", "forbid"], [1, 3, 1, "", "info"], [1, 3, 1, "", "rps"]], "pyfilebrowser.proxy.squire": [[1, 4, 1, "", "extract_credentials"], [1, 4, 1, "", "log_connection"], [1, 4, 1, "", "proxy_auth"]], "pyfilebrowser.squire": [[1, 0, 0, "-", "download"], [1, 0, 0, "-", "steward"], [1, 0, 0, "-", "struct"]], "pyfilebrowser.squire.download": [[1, 1, 1, "", "Executable"], [1, 1, 1, "", "GitHub"], [1, 4, 1, "", "alias_choices"], [1, 4, 1, "", "binary"]], "pyfilebrowser.squire.download.Executable": [[1, 3, 1, "", "filebrowser_arch"], [1, 3, 1, "", "filebrowser_bin"], [1, 3, 1, "", "filebrowser_db"], [1, 3, 1, "", "filebrowser_dl_ext"], [1, 3, 1, "", "filebrowser_file"], [1, 3, 1, "", "filebrowser_os"], [1, 3, 1, "", "machine"], [1, 3, 1, "", "system"]], "pyfilebrowser.squire.download.GitHub": [[1, 1, 1, "", "Config"], [1, 3, 1, "", "owner"], [1, 3, 1, "", "repo"], [1, 3, 1, "", "token"], [1, 3, 1, "", "version"]], "pyfilebrowser.squire.download.GitHub.Config": [[1, 3, 1, "", "env_file"], [1, 3, 1, "", "env_prefix"], [1, 3, 1, "", "extra"]], "pyfilebrowser.squire.steward": [[1, 1, 1, "", "EnvConfig"], [1, 1, 1, "", "FileIO"], [1, 4, 1, "", "default_logger"], [1, 4, 1, "", "hash_password"], [1, 4, 1, "", "ordinal"], [1, 4, 1, "", "remove_prefix"], [1, 4, 1, "", "remove_trailing_underscore"], [1, 4, 1, "", "validate_password"]], "pyfilebrowser.squire.steward.EnvConfig": [[1, 3, 1, "", "config_settings"], [1, 2, 1, "", "load_user_profiles"], [1, 3, 1, "", "user_profiles"]], "pyfilebrowser.squire.steward.FileIO": [[1, 3, 1, "", "config"], [1, 3, 1, "", "settings_dir"], [1, 3, 1, "", "users"]], "pyfilebrowser.squire.struct": [[1, 1, 1, "", "LoggerConfig"], [1, 4, 1, "", "update_log_level"]], "pyfilebrowser.squire.struct.LoggerConfig": [[1, 2, 1, "", "extract"], [1, 2, 1, "", "get"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:attribute", "4": "py:function"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "attribute", "Python attribute"], "4": ["py", "function", "Python function"]}, "titleterms": {"pyfilebrows": [0, 1], "kick": 0, "off": 0, "environ": 0, "variabl": 0, "env": 0, "file": 0, "proxi": [0, 1], "server": [0, 1], "firewal": 0, "brute": 0, "forc": 0, "protect": 0, "rate": [0, 1], "limit": [0, 1], "code": 0, "standard": 0, "releas": 0, "note": 0, "lint": 0, "pypi": 0, "packag": 0, "runbook": 0, "licens": 0, "copyright": 0, "welcom": 1, "": 1, "document": 1, "read": 1, "me": 1, "engin": 1, "error": 1, "repeat": 1, "timer": 1, "secur": 1, "squir": 1, "set": 1, "pyfb": 1, "api": 1, "client": 1, "main": 1, "modul": 1, "modal": 1, "configur": 1, "model": 1, "user": 1, "download": 1, "steward": 1, "struct": 1, "indic": 1, "tabl": 1}, "envversion": {"sphinx.domains.c": 2, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 6, "sphinx.domains.index": 1, "sphinx.domains.javascript": 2, "sphinx.domains.math": 2, "sphinx.domains.python": 3, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx": 56}}) \ No newline at end of file diff --git a/pyfilebrowser/__init__.py b/pyfilebrowser/__init__.py index f2cf45c..e87a53a 100644 --- a/pyfilebrowser/__init__.py +++ b/pyfilebrowser/__init__.py @@ -1,5 +1,54 @@ """Module for packaging.""" +import sys from pyfilebrowser.main import FileBrowser # noqa: F401 version = "0.0.91" + + +def _cli() -> None: + """Starter function to invoke the file browser via CLI commands. + + Keyword Args: + --version | -V: Prints the version. + --proxy | -P: Initiates PyFileBrowser with proxy server enabled. + --help | -H: Prints the help section. + start: Initiates the PyFilebrowser. + """ + assert sys.argv[0].endswith("pyfilebrowser"), "Invalid commandline trigger!!" + options = { + "--proxy | -P": "Initiates PyFileBrowser with proxy server enabled.", + "--version | -V": "Prints the version.", + "--help | -H": "Prints the help section.", + "start": "Initiates the PyFilebrowser.", + } + # weird way to increase spacing to keep all values monotonic + _longest_key = len(max(options.keys())) + _pretext = "\n\t* " + choices = _pretext + _pretext.join( + f"{k} {'·' * (_longest_key - len(k) + 8)}→ {v}".expandtabs() + for k, v in options.items() + ) + args = [arg.lower() for arg in sys.argv[1:]] + try: + assert len(args) in (1, 2) + except (IndexError, AttributeError, AssertionError): + print(f"Cannot proceed without a valid arbitrary command. Please choose from {choices}") + exit(1) + if any(arg in args for arg in ["version", "--version", "-v"]): + print(f"PyFileBrowser: {version}") + exit(0) + elif any(arg in args for arg in ["proxy", "--proxy", "-p"]): + proxy_flag = True + elif any(arg in args for arg in ["help", "--help", "-h"]): + print(f"Usage: pyfilebrowser [arbitrary-command]\nOptions (and corresponding behavior):{choices}") + exit(0) + else: + print(f"Unknown Option: {sys.argv[1]}\nArbitrary commands must be one of {choices}") + exit(1) + if any(arg in args for arg in ["start", "run"]): + FileBrowser(proxy=proxy_flag).start() + else: + raise ValueError( + "\n\tNo 'start' or 'run' command received to initiate the PyFileBrowser" + ) diff --git a/pyfilebrowser/main.py b/pyfilebrowser/main.py index 9972b3b..16c67a3 100644 --- a/pyfilebrowser/main.py +++ b/pyfilebrowser/main.py @@ -176,12 +176,13 @@ def background_tasks(self, auth_map: Dict[str, str]) -> None: if self.proxy: assert proxy_settings.port != int(self.env.config_settings.server.port), \ f"\n\tProxy server can't run on the same port [{proxy_settings.port}] as the server!!" + # This is to check if the port is available, before starting the proxy server in a dedicated process try: with socket.socket() as sock: sock.bind((proxy_settings.host, proxy_settings.port)) except OSError as error: self.logger.error(error) - self.logger.critical("Cannot initiate proxy server") + self.logger.critical("Cannot initiate proxy server, retry after sometime or change the port number.") self.cleanup() raise log_config = struct.LoggerConfig(self.logger).get() diff --git a/pyfilebrowser/proxy/main.py b/pyfilebrowser/proxy/main.py index 599b032..91dbb1d 100644 --- a/pyfilebrowser/proxy/main.py +++ b/pyfilebrowser/proxy/main.py @@ -98,7 +98,8 @@ async def proxy_engine(proxy_request: Request) -> Response: Returns: Response: The response object with the forwarded content and headers. """ - squire.log_connection(proxy_request) + if browser_warning := squire.log_connection(proxy_request): + return browser_warning # Since host header can be overridden, always check with base_url if proxy_request.base_url.hostname not in settings.session.allowed_origins: LOGGER.warning("%s is blocked by firewall, since it is not set in allowed origins %s", @@ -150,14 +151,20 @@ async def proxy_engine(proxy_request: Request) -> Response: LOGGER.debug("Removing %s from auth DB", proxy_request.client.host) database.remove_record(host=proxy_request.client.host) content_type = server_response.headers.get("content-type", "") - if "text" in content_type: + # The "text/javascript" MIME type was used by convention until RFC 4329 -https://www.rfc-editor.org/rfc/rfc4329 + # attempted to replace it with application/javascript, hence this check is necessary. + if "text" in content_type or "javascript" in content_type: + # Having the "Content-Length" header results in: net::ERR_CONTENT_LENGTH_MISMATCH while streaming videos + # There will be a discrepancy between the "Content-Length" header and the actual content being sent. + # Since the content is served via VideoJS plugin, the GO API sends a StreamingResponse with chunked encoding + # which doesn't rely on the "Content-Length" header, so removing it is more suitable + # Reference TransactionID: 06f4d0a3-8a4f-4a3a-bee6-2dd382567532 + LOGGER.debug("Removed 'content-length' header [%s] for the 'content-type' %s", + server_response.headers.pop("content-length", "N/A"), content_type) content = server_response.text else: content = server_response.content server_response.headers.pop("content-encoding", None) - # fixme: there should be a better way to handle this - if "javascript" in content_type: # todo: not sure if this is solely because of VideoJS plugin - server_response.headers.pop("content-length", None) proxy_response = Response( content=content, status_code=server_response.status_code, diff --git a/pyfilebrowser/proxy/server.py b/pyfilebrowser/proxy/server.py index 77a6244..28f2065 100644 --- a/pyfilebrowser/proxy/server.py +++ b/pyfilebrowser/proxy/server.py @@ -38,7 +38,7 @@ def run_in_parallel(self, logger: logging.Logger) -> None: assert logger.name == "proxy" timers = [] if settings.env_config.origin_refresh and \ - (settings.env_config.private_ip or settings.env_config.public_ip): + (settings.env_config.allow_private_ip or settings.env_config.allow_public_ip): timers.append(repeated_timer.RepeatedTimer( function=main.refresh_allowed_origins, interval=settings.env_config.origin_refresh )) diff --git a/pyfilebrowser/proxy/settings.py b/pyfilebrowser/proxy/settings.py index 7fb71e8..c468f84 100644 --- a/pyfilebrowser/proxy/settings.py +++ b/pyfilebrowser/proxy/settings.py @@ -2,6 +2,7 @@ import pathlib import re import socket +import string from typing import Dict, List, Set import requests @@ -76,9 +77,9 @@ def allowance() -> List[HttpUrl]: if env_config.host == socket.gethostbyname('localhost'): base_origins.add("localhost") base_origins.add("0.0.0.0") - if env_config.private_ip and (pri_ip_addr := private_ip_address()): + if env_config.allow_private_ip and (pri_ip_addr := private_ip_address()): base_origins.add(pri_ip_addr) - if env_config.public_ip and (pub_ip_addr := public_ip_address()): + if env_config.allow_public_ip and (pub_ip_addr := public_ip_address()): base_origins.add(pub_ip_addr) return list(base_origins) @@ -133,27 +134,43 @@ class EnvConfig(BaseSettings): debug: bool = False origins: List[HttpUrl] = [] database: str = Field("auth.db", pattern=".*.db$") - public_ip: bool = False - private_ip: bool = False + allow_public_ip: bool = False + allow_private_ip: bool = False origin_refresh: PositiveInt | None = None rate_limit: RateLimit | List[RateLimit] = [] + unsupported_browsers: str | List[str] = ["Chrome"] + warn_page: FilePath = os.path.join(pathlib.PosixPath(__file__).parent, 'warn.html') error_page: FilePath = os.path.join(pathlib.PosixPath(__file__).parent, 'error.html') + # noinspection PyMethodParameters,PyUnusedLocal + @field_validator('unsupported_browsers', mode='after', check_fields=True) + def parse_unsupported_browsers(cls, unsupported_browsers: str | List[str]) -> List[str] | List: + """Validate unsupported_browsers and convert to list.""" + if isinstance(unsupported_browsers, str): + unsupported_browsers = [unsupported_browsers] + if validated := [ + unsupported_browser.lower().strip() for unsupported_browser in unsupported_browsers + if not any(punctuation in unsupported_browser for punctuation in string.punctuation) + and ' ' not in unsupported_browser.strip() + ]: + return validated + raise ValueError("Browser names cannot have punctuations or white spaces") + # noinspection PyMethodParameters,PyUnusedLocal @field_validator('origins', mode='after', check_fields=True) - def origins_url_checker(cls, v: List[HttpUrl]) -> List[str] | List: + def parse_origins(cls, origins: List[HttpUrl]) -> List[str] | List: """Validate origins' input as a URL, and stores only the host part of the URL.""" - if v: - return list(set([i.host for i in v])) + if origins: + return list(set([origin.host for origin in origins])) return [] # noinspection PyMethodParameters,PyUnusedLocal @field_validator('rate_limit', mode='after', check_fields=True) - def rate_limit_checker(cls, v: RateLimit | List[RateLimit], values, **kwargs) -> List[RateLimit] | List: - """Validate origins' input as a URL, and convert as string when stored.""" - if not isinstance(v, list): - v = [v] - return v + def parse_rate_limit(cls, rate_limit: RateLimit | List[RateLimit]) -> List[RateLimit] | List: + """Validate rate_limit and convert to list.""" + if isinstance(rate_limit, list): + return rate_limit + return [rate_limit] class Config: """Environment variables configuration.""" diff --git a/pyfilebrowser/proxy/squire.py b/pyfilebrowser/proxy/squire.py index aef86bf..0bfc5ef 100644 --- a/pyfilebrowser/proxy/squire.py +++ b/pyfilebrowser/proxy/squire.py @@ -1,27 +1,52 @@ import logging import secrets from collections.abc import Generator +from http import HTTPStatus from typing import Dict +import jinja2 +import user_agents from fastapi import Request +from fastapi.responses import HTMLResponse from pyfilebrowser.proxy import secure, settings LOGGER = logging.getLogger('proxy') -def log_connection(request: Request) -> None: - """Logs the connection information. +def log_connection(request: Request) -> HTMLResponse | None: + """Logs the connection information and returns an HTML response if the browser is unsupported for video/audio. See Also: - Only logs the first connection from a device. - This avoids multiple logs when same device is accessing different paths. + + Returns: + HTMLResponse: + Returns an HTML response if the browser is unsupported for video/audio rendering. """ if request.client.host not in settings.session.info: settings.session.info[request.client.host] = None LOGGER.info("Connection received from client-host: %s, host-header: %s, x-fwd-host: %s", request.client.host, request.headers.get('host'), request.headers.get('x-forwarded-host')) - LOGGER.info("User agent: %s", request.headers.get('user-agent')) + if user_agent := request.headers.get('user-agent'): + LOGGER.info("User agent: %s", user_agent) + try: + parsed = user_agents.parse(user_agent) + except Exception as error: + LOGGER.critical("Failed to parse user-agent: %s", error) + return + if parsed.browser.family == "Chrome": + with open(settings.env_config.warn_page) as file: + warn_template = file.read() + return HTMLResponse( + content=jinja2.Template(warn_template).render( + BROWSER_NAME=parsed.browser.family, + BROWSER_VERSION=parsed.browser.version_string, + RECOMMENDATION="Firefox or Safari" + ), + status_code=HTTPStatus.OK.value + ) def extract_credentials(authorization: bytes) -> Generator[str]: diff --git a/pyfilebrowser/proxy/warn.html b/pyfilebrowser/proxy/warn.html new file mode 100644 index 0000000..470503b --- /dev/null +++ b/pyfilebrowser/proxy/warn.html @@ -0,0 +1,86 @@ + + + + + + FastAPI: Reverse Proxy + + + + + + + + + +
            + +
            +

            Browser Warning!!

            +

            You are currently using {{ BROWSER_NAME }} - {{ BROWSER_VERSION }}, which MAY NOT support video/audio rendering

            +

            Please switch to {{ RECOMMENDATION }} if you intend to render video/audio content

            +

            + Image +

            + +
            + +

            Click HERE to reach out.

            + + + diff --git a/pyfilebrowser/requirements.txt b/pyfilebrowser/requirements.txt index dbbba1f..9a22fab 100644 --- a/pyfilebrowser/requirements.txt +++ b/pyfilebrowser/requirements.txt @@ -5,4 +5,5 @@ Jinja2==3.1.* pydantic==2.6.* pydantic-settings==2.2.* requests==2.31.* +user-agents==2.2.* uvicorn==0.29.* diff --git a/pyfilebrowser/squire/download.py b/pyfilebrowser/squire/download.py index 9e0656b..7b4c60e 100644 --- a/pyfilebrowser/squire/download.py +++ b/pyfilebrowser/squire/download.py @@ -6,111 +6,44 @@ import stat import tarfile import zipfile -from typing import Any, List, Tuple, Type import requests from pydantic import BaseModel, FilePath -from pydantic.fields import FieldInfo -from pydantic_settings import (BaseSettings, EnvSettingsSource, - PydanticBaseSettingsSource, SettingsConfigDict) +from pydantic.fields import AliasChoices, Field +from pydantic_settings import BaseSettings -class ExtendedEnvSettingsSource(EnvSettingsSource): - """Customized environment settings source that allows specifying multiple prefixes for environmental variables. +def alias_choices(variable: str) -> AliasChoices: + """Custom alias choices for environment variables for GitHub. - >>> ExtendedEnvSettingsSource - - """ - - def get_field_value(self, field: FieldInfo, field_name: str) -> Tuple[Any, str, bool]: - """Retrieves the field value from the environment with support for multiple prefixes. - - Args: - field: Information about the field. - field_name: Name of the field. - - Returns: - Tuple[Any, str, bool]: - Retrieved value, field key, and a boolean indicating whether the value is complex. - """ - # noinspection PyTypedDict - if prefixes := self.config.get("env_prefixes", []): - for prefix in prefixes: - self.env_prefix = prefix - env_val, field_key, value_is_complex = super().get_field_value(field, field_name) - if env_val is not None: - return env_val, field_key, value_is_complex - - return super().get_field_value(field, field_name) - - -class ExtendedSettingsConfigDict(SettingsConfigDict, total=False): - """Configuration dictionary extension to support additional settings. - - >>> ExtendedSettingsConfigDict + Args: + variable: Variable name. - Attributes: - env_prefixes (List[str] | None): List of environment variable prefixes to consider. + Returns: + AliasChoices: + Returns the alias choices for the variable. """ + return AliasChoices(f"FILEBROWSER_{variable}", f"GIT_{variable}", f"GITHUB_{variable}") - env_prefixes: List[str] | None - - -class ExtendedBaseSettings(BaseSettings): - """Base settings class extension to customize settings sources. - - >>> ExtendedBaseSettings - Methods: - settings_customise_sources: Customizes settings sources for the extended settings class. - """ - - @classmethod - def settings_customise_sources( - cls, - settings_cls: Type[BaseSettings], - init_settings: PydanticBaseSettingsSource, - env_settings: PydanticBaseSettingsSource, - dotenv_settings: PydanticBaseSettingsSource, - file_secret_settings: PydanticBaseSettingsSource - ) -> Tuple[PydanticBaseSettingsSource, ...]: - """Customizes the settings sources for the extended settings class. - - Args: - settings_cls: The extended settings class. - init_settings: Settings source for initialization. - env_settings: Settings source for environment variables. - dotenv_settings: Settings source for dotenv files. - file_secret_settings: Settings source for secret files. - - Returns: - Tuple[PydanticBaseSettingsSource, ...]: - Tuple of customized settings sources. - """ - return (ExtendedEnvSettingsSource(settings_cls),) - - -class GitHub(ExtendedBaseSettings): +class GitHub(BaseSettings): """Custom GitHub account information loaded using multiple env prefixes. >>> GitHub - References: - https://github.com/pydantic/pydantic/discussions/4319 - - See Also: - - This model is to load GitHub arguments, which is used to download the appropriate asset from source control. - - Dot env ``(.env)`` files are not supported. Regular env variables are required. """ - model_config = ExtendedSettingsConfigDict( - env_prefixes=["git_", "github_", "filebrowser_"] - ) + owner: str = Field("filebrowser", validation_alias=alias_choices("OWNER")) + repo: str = Field("filebrowser", validation_alias=alias_choices("REPO")) + token: str | None = Field(None, validation_alias=alias_choices("TOKEN")) + version: str = Field("latest", validation_alias=alias_choices("VERSION")) + + class Config: + """Custom configuration for GitHub settings.""" - owner: str = "filebrowser" - repo: str = "filebrowser" - token: str | None = None - version: str = "latest" + env_prefix = "" + env_file = ".github.env" + extra = "ignore" class Executable(BaseModel): @@ -145,7 +78,7 @@ class Executable(BaseModel): f"Aborted, unsupported or unknown OS: {system}" ) - if "aarch64" in machine: + if "aarch64" in machine or "arm64" in machine: filebrowser_arch: str = "arm64" elif "64" in machine: filebrowser_arch: str = "amd64" diff --git a/pyproject.toml b/pyproject.toml index dc0351f..d24fab6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ requires-python = ">=3.11" [tool.setuptools] packages = ["pyfilebrowser", "pyfilebrowser.modals", "pyfilebrowser.proxy", "pyfilebrowser.squire"] [tool.setuptools.package-data] -"pyfilebrowser.proxy" = ["error.html"] +"pyfilebrowser.proxy" = ["error.html", "warn.html"] [tool.setuptools.dynamic] version = {attr = "pyfilebrowser.version"} @@ -32,6 +32,9 @@ build-backend = "setuptools.build_meta" [project.optional-dependencies] dev = ["sphinx==5.1.1", "pre-commit", "recommonmark"] +[project.scripts] +pyfilebrowser = "pyfilebrowser:_cli" + [project.urls] Homepage = "https://github.com/thevickypedia/pyfilebrowser" Docs = "https://thevickypedia.github.io/pyfilebrowser/"