aird 0.4.25.dev1__tar.gz → 0.4.25.dev3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aird-0.4.25.dev3/PKG-INFO +315 -0
- aird-0.4.25.dev3/README.md +277 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cli/transfer_http.py +2 -2
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/constants/__init__.py +69 -16
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/compression.py +38 -26
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/events.py +6 -2
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/rate_limit.py +21 -19
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/secret_storage.py +26 -23
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/__init__.py +1 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/config.py +1 -1
- aird-0.4.25.dev3/aird/db/sync.py +102 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/event_loop.py +8 -1
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/admin_handlers.py +29 -1
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/auth_handlers.py +35 -26
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/base_handler.py +11 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/file_op_handlers.py +2 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/health_handler.py +19 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/p2p_handlers.py +68 -42
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/ranged_upload_handlers.py +74 -19
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/share_handlers.py +21 -18
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/transfer_ws_handlers.py +17 -1
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/view_handlers.py +4 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/main.py +57 -15
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/config_service.py +13 -8
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/event_subscribers.py +10 -4
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/css/app.css +1 -1
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/browse/app.js +23 -1
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/file-transfer-http.js +282 -93
- aird-0.4.25.dev3/aird/static/js/file-transfer-ws.js +410 -0
- aird-0.4.25.dev3/aird/static/js/sw-transfer.js +25 -0
- aird-0.4.25.dev3/aird/static/js/transfer-engine/compress-worker.js +61 -0
- aird-0.4.25.dev3/aird/static/js/transfer-engine/engine.js +245 -0
- aird-0.4.25.dev3/aird/static/js/transfer-engine/hasher.js +23 -0
- aird-0.4.25.dev3/aird/static/js/transfer-engine/resume-store.js +79 -0
- aird-0.4.25.dev3/aird/static/js/transfer-engine/worker-lib.js +393 -0
- aird-0.4.25.dev3/aird/static/js/transfer-engine/worker.js +25 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/transfer-tracker.js +158 -39
- aird-0.4.25.dev3/aird/static/js/vendor/fflate.js +1190 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin.html +26 -2
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/browse.html +5 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/super_search.html +1 -4
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/utils/util.py +17 -16
- aird-0.4.25.dev3/aird.egg-info/PKG-INFO +315 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird.egg-info/SOURCES.txt +11 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird.egg-info/requires.txt +0 -1
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/setup.py +2 -2
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_compression.py +2 -4
- aird-0.4.25.dev3/tests/test_free_threading.py +80 -0
- aird-0.4.25.dev3/tests/test_ranged_upload_handlers.py +41 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_security_comprehensive.py +2 -0
- aird-0.4.25.dev1/PKG-INFO +0 -427
- aird-0.4.25.dev1/README.md +0 -388
- aird-0.4.25.dev1/aird/static/js/file-transfer-ws.js +0 -349
- aird-0.4.25.dev1/aird.egg-info/PKG-INFO +0 -427
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/LICENSE +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/MANIFEST.in +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/__main__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/app_context.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cli/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cli/__main__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cli/authelia.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cli/config.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cli/main.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cli/session.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/cloud/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/config.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/constants/admin.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/constants/file_ops.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/constants/input_limits.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/constants/media.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/file_operations.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/file_send.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/filter_expression.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/folder_size.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/http_range.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/input_validation.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/mmap_handler.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/security.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/share_root.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/webauthn_config.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/websocket_manager.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/core/zip_download.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/database/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/database/db.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/database/feature_flags.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/database/ldap.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/audit.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/favorites.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/network_shares.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/policies.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/policy_decisions.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/policy_seeds.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/quota.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/ranged_uploads.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/resource_tags.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/schema.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/shares.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/user_attributes.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/users.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/db/webauthn.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/domain/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/domain/contracts.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/domain/models.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/email/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/email/brevo.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/email/resolve.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/abac_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/api_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/constants.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/handlers/webauthn_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/network_share_manager.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/server_runtime.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/audit_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/email_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/email_subscriber.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/favorites_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/network_share_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/p2p_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/policy_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/quota_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/share_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/tag_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/services/user_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/sql_identifiers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/favicon.png +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/favicon.svg +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/img/logo-icon.png +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/img/logo-mark.svg +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/img/logo-text.png +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/img/logo.png +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/aird-core.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/bg-canvas.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/common/command-palette.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/components/folder-picker.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/download-manager.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/feature-flags-live.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/folder-size-scan.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/login-ui.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/media-view.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/p2p/app.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/p2p/mediator.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/p2p/qr-adapter.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/p2p/signaling-service.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/p2p/state-machine.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/p2p/transfer-service.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/pages/p2p-page.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/pages/super-search.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/app.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/add-files-modal.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/cloud.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/create-share.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/create-users.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/expiry.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/file-icons.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/file-picker.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/init.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/main.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/management-templates.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/management.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/selection.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/share-popup.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/shares-list.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/state.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/share/src/utils.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/theme.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/vendor/pdf.min.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/vendor/pdf.worker.min.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/vendor/qrcode-browser.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/static/js/webauthn.js +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/_admin_tabs.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/_app_nav_header.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/_bg_canvas.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/_theme_early.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/_theme_login_corner.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_audit.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_ldap.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_login.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_network_shares.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_policies.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_tags.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_user_attributes.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/admin_users.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/directory.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/edit.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/error.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/file.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/ldap_config_create.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/ldap_config_edit.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/login.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/media_view.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/p2p_transfer.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/profile.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/share.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/shared_list.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/tagged_files.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/token_verification.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/user_create.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/templates/user_edit.html +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird/utils/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird.egg-info/dependency_links.txt +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird.egg-info/entry_points.txt +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/aird.egg-info/top_level.txt +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/setup.cfg +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/__init__.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/conftest.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/handler_helpers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_admin_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_api_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_architecture_conformance.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_auth_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_auth_handlers_extended.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_base_handler.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_base_handler_pep.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_cli.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_cloud.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_config.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_core_file_operations.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_database_db.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_database_feature_flags.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_database_ldap.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_database_shares.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_database_users.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_database_users_hashing.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_db.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_email_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_file_op_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_filter_expression.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_folder_size.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_http_range.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_main.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_mmap_handler.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_multi_user.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_network_shares.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_p2p_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_password_hashing.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_policy_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_rate_limit.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_secret_storage.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_security.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_server_runtime.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_share_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_share_ownership.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_super_search_handler.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_tag_service.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_transfer_rate_limit.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_transfer_ws_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_util.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_view_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_webauthn_handlers.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_websocket_manager.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_wheel_static_assets.py +0 -0
- {aird-0.4.25.dev1 → aird-0.4.25.dev3}/tests/test_zip_download.py +0 -0
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aird
|
|
3
|
+
Version: 0.4.25.dev3
|
|
4
|
+
Summary: Aird - A lightweight web-based file browser, editor, and streamer with real-time capabilities
|
|
5
|
+
Home-page: https://github.com/blinkerbit/aird
|
|
6
|
+
Author: Viswantha Srinivas P
|
|
7
|
+
Author-email: psviswanatha@gmail.com
|
|
8
|
+
License: Custom
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: Other/Proprietary License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: tornado>=6.5.1
|
|
16
|
+
Requires-Dist: uvloop>=0.19.0; sys_platform == "linux"
|
|
17
|
+
Requires-Dist: ldap3>=2.9.1
|
|
18
|
+
Requires-Dist: aiofiles>=23.0.0
|
|
19
|
+
Requires-Dist: argon2-cffi>=23.1.0
|
|
20
|
+
Requires-Dist: requests>=2.31.0
|
|
21
|
+
Requires-Dist: chardet<6.0.0,>=5.0.0
|
|
22
|
+
Requires-Dist: pyasn1>=0.6.2
|
|
23
|
+
Requires-Dist: webauthn>=2.0.0
|
|
24
|
+
Provides-Extra: compress
|
|
25
|
+
Requires-Dist: zstandard>=0.22.0; extra == "compress"
|
|
26
|
+
Dynamic: author
|
|
27
|
+
Dynamic: author-email
|
|
28
|
+
Dynamic: classifier
|
|
29
|
+
Dynamic: description
|
|
30
|
+
Dynamic: description-content-type
|
|
31
|
+
Dynamic: home-page
|
|
32
|
+
Dynamic: license
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
Dynamic: provides-extra
|
|
35
|
+
Dynamic: requires-dist
|
|
36
|
+
Dynamic: requires-python
|
|
37
|
+
Dynamic: summary
|
|
38
|
+
|
|
39
|
+
# Aird
|
|
40
|
+
|
|
41
|
+
<p align="center">
|
|
42
|
+
<img src="aird/static/img/logo.png" alt="Aird" width="280">
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
**Aird** is a self-hosted file browser, editor, and sharing platform built on **Python** and **Tornado**. It targets fast local and LAN use: parallel HTTP transfers for large files, real-time log streaming, content search, secure shares, optional multi-user isolation, and an admin console that applies settings without restarts.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Highlights
|
|
52
|
+
|
|
53
|
+
| Area | What you get |
|
|
54
|
+
|------|----------------|
|
|
55
|
+
| **File manager** | Browse, upload, download, rename, move, copy, bulk ops, in-browser text edit, ZIP download |
|
|
56
|
+
| **Large transfers** | Parallel **HTTP `Content-Range`** uploads/downloads (primary path for big files) |
|
|
57
|
+
| **Search** | **Super Search** — glob + regex content search with live WebSocket progress |
|
|
58
|
+
| **Streaming** | Tail log files over WebSocket with filters |
|
|
59
|
+
| **Sharing** | Token-based public/private shares, static or live folder views |
|
|
60
|
+
| **Security** | CSRF, CSP, path traversal checks, optional **ABAC** policies, WebAuthn, LDAP |
|
|
61
|
+
| **Integrations** | Google Drive / OneDrive browse, P2P WebRTC rooms, optional embedded SMB & WebDAV |
|
|
62
|
+
| **Ops** | SQLite-backed settings, audit log, feature flags, transfer rate limits, health endpoint |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## File transfers
|
|
67
|
+
|
|
68
|
+
Large uploads are designed for **high-throughput links** (e.g. gigabit LAN or VPN):
|
|
69
|
+
|
|
70
|
+
1. **Small files** — single `POST /upload`.
|
|
71
|
+
2. **Large files** — client opens a range session (`POST /api/upload/range/session`), then sends many parallel **`PUT`** requests with `Content-Range`. Each chunk is written **in place** at the correct byte offset on disk (no separate part files, no concat step at the end).
|
|
72
|
+
3. **Downloads** — `GET /files/...?download=1` with optional `Range` for parallel fetch.
|
|
73
|
+
|
|
74
|
+
Defaults (all adjustable in **Admin → Upload settings**):
|
|
75
|
+
|
|
76
|
+
| Setting | Default | Notes |
|
|
77
|
+
|---------|---------|--------|
|
|
78
|
+
| Max file size | 10 240 MB (10 GiB) | Hard cap per file |
|
|
79
|
+
| Single-request max | 100 MB | Files **≥** this use parallel HTTP ranges |
|
|
80
|
+
| HTTP chunk size | 90 MB | Per range `PUT` body |
|
|
81
|
+
| HTTP parallelism | 16 | Concurrent upload streams |
|
|
82
|
+
|
|
83
|
+
**Behind nginx/Caddy:** set `client_max_body_size` (or equivalent) to at least your HTTP chunk size. If **Single-request max** is `0`, Aird uses a **100 MB** parallel threshold (proxy-safe), not a single POST for the entire max file size.
|
|
84
|
+
|
|
85
|
+
Optional WebSocket upload (`/ws/file-transfer`) remains for specialized paths; the browser UI uses **HTTP parallel** by default.
|
|
86
|
+
|
|
87
|
+
Transfer progress, cancel, and resume metadata are handled in the browser (`transfer-tracker.js`, `transfer-engine/`, service worker `sw-transfer.js`).
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Quick start
|
|
92
|
+
|
|
93
|
+
### Install
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
pip install aird
|
|
97
|
+
|
|
98
|
+
# Optional: HTTP response compression codecs (gzip is always available)
|
|
99
|
+
pip install "aird[compress]"
|
|
100
|
+
|
|
101
|
+
# From source
|
|
102
|
+
git clone https://github.com/blinkerbit/aird.git
|
|
103
|
+
cd aird
|
|
104
|
+
pip install -e .
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Python:** 3.10+ required. On Linux, **free-threaded** builds (`3.13t` / `3.14t`) are supported and recommended for parallel disk I/O; the server detects nogil at startup and sizes the I/O thread pool accordingly.
|
|
108
|
+
|
|
109
|
+
### Run
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Default: port 8000, current directory as root
|
|
113
|
+
python -m aird
|
|
114
|
+
|
|
115
|
+
# Custom root and port
|
|
116
|
+
python -m aird --root /data --port 8080
|
|
117
|
+
|
|
118
|
+
# Multi-user (per-user home directories under root)
|
|
119
|
+
python -m aird --root /data --multi-user
|
|
120
|
+
|
|
121
|
+
# TLS
|
|
122
|
+
python -m aird --ssl-cert /path/cert.pem --ssl-key /path/key.pem --port 443
|
|
123
|
+
|
|
124
|
+
# Worker processes (Linux; default is auto from CPU topology)
|
|
125
|
+
python -m aird --workers 4
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
On first start, random **access** and **admin** tokens are printed unless you set them via `--token`, `--admin-token`, `config.json`, or `AIRD_ACCESS_TOKEN`.
|
|
129
|
+
|
|
130
|
+
Open `http://localhost:8000/` → redirects to `/files/`.
|
|
131
|
+
|
|
132
|
+
### CLI client
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
pip install aird # includes aird-cli
|
|
136
|
+
aird-cli config set server https://your-host
|
|
137
|
+
aird-cli login
|
|
138
|
+
aird-cli ls /
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Configuration
|
|
144
|
+
|
|
145
|
+
### `config.json`
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"port": 8000,
|
|
150
|
+
"root": "/srv/files",
|
|
151
|
+
"hostname": "files.example.com",
|
|
152
|
+
"token": "your-access-token",
|
|
153
|
+
"admin_token": "your-admin-token",
|
|
154
|
+
"multi_user": false,
|
|
155
|
+
"workers": 2,
|
|
156
|
+
"ldap": {
|
|
157
|
+
"enabled": false,
|
|
158
|
+
"server": "ldap://ldap.example.com",
|
|
159
|
+
"base_dn": "dc=example,dc=com"
|
|
160
|
+
},
|
|
161
|
+
"feature_flags": {
|
|
162
|
+
"file_upload": true,
|
|
163
|
+
"super_search": true,
|
|
164
|
+
"abac_engine": false
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
python -m aird --config /etc/aird/config.json
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Environment variables (common)
|
|
174
|
+
|
|
175
|
+
| Variable | Purpose |
|
|
176
|
+
|----------|---------|
|
|
177
|
+
| `AIRD_ACCESS_TOKEN` | Login token |
|
|
178
|
+
| `AIRD_COOKIE_SECRET` | Persistent session signing (set in production) |
|
|
179
|
+
| `AIRD_CORPORATE_IP_CIDRS` | Comma-separated CIDRs for ABAC / WAN compression rules |
|
|
180
|
+
| `AIRD_GDRIVE_ACCESS_TOKEN` / `AIRD_ONEDRIVE_ACCESS_TOKEN` | Cloud providers |
|
|
181
|
+
|
|
182
|
+
### Admin console
|
|
183
|
+
|
|
184
|
+
`GET /admin` — feature flags, upload limits, extension allow-list, WebSocket pool limits, LDAP, network shares, ABAC policies/tags, users, audit. Changes persist to SQLite and apply without restart (feature-flag subscribers refresh over `/features` WebSocket).
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Production deployment
|
|
189
|
+
|
|
190
|
+
### Reverse proxy
|
|
191
|
+
|
|
192
|
+
Aird listens on one port (default **8000**). Terminate TLS at **Caddy**, **nginx**, or similar.
|
|
193
|
+
|
|
194
|
+
**nginx example** (adjust chunk size to match Admin → HTTP chunk):
|
|
195
|
+
|
|
196
|
+
```nginx
|
|
197
|
+
client_max_body_size 128m;
|
|
198
|
+
|
|
199
|
+
location / {
|
|
200
|
+
proxy_pass http://127.0.0.1:8000;
|
|
201
|
+
proxy_http_version 1.1;
|
|
202
|
+
proxy_set_header Host $host;
|
|
203
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
204
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
205
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
WebSocket routes (`/stream/`, `/search/ws`, `/features`, `/ws/…`) need `Upgrade` and `Connection` headers if you proxy them.
|
|
210
|
+
|
|
211
|
+
### Ubuntu deploy script
|
|
212
|
+
|
|
213
|
+
`deploy_local.ps1` (run from Windows) syncs source or a wheel to a remote host, creates a **uv** venv with **Python 3.14t**, and installs the package. See `docs/wireguard-deploy.md` for VPN-only TLS layouts.
|
|
214
|
+
|
|
215
|
+
### Systemd
|
|
216
|
+
|
|
217
|
+
Run `python -m aird` (or the venv equivalent) as a service user with `--config` pointing at your JSON file. Logs go to the data directory (`aird.log` under the platform app data path).
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## API overview
|
|
222
|
+
|
|
223
|
+
Authentication: session cookie after `/login`, bearer token, or `Authorization` header where supported. Mutating requests require the `_xsrf` cookie + `X-XSRFToken` header.
|
|
224
|
+
|
|
225
|
+
| Operation | Method / path |
|
|
226
|
+
|-----------|----------------|
|
|
227
|
+
| List directory | `GET /api/files/{path}` |
|
|
228
|
+
| Upload (small) | `POST /upload` |
|
|
229
|
+
| Upload (large) | `POST /api/upload/range/session` then `PUT /api/upload/range/{id}` |
|
|
230
|
+
| Upload status | `GET /api/upload/range/{id}/status` |
|
|
231
|
+
| Download | `GET /files/{path}?download=1` |
|
|
232
|
+
| Edit | `GET /edit/{path}`, `POST /edit` |
|
|
233
|
+
| Delete / rename / mkdir | `POST /delete`, `POST /rename`, `POST /mkdir` |
|
|
234
|
+
| Search UI | `GET /search` |
|
|
235
|
+
| Search (live) | WebSocket `/search/ws` |
|
|
236
|
+
| Log stream | WebSocket `/stream/{path}` |
|
|
237
|
+
| Shares | `POST /share/create`, `GET /share/list`, … |
|
|
238
|
+
| Health | `GET /health` |
|
|
239
|
+
|
|
240
|
+
Page-level UI contracts and routes are documented under [`docs/`](docs/README.md).
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Architecture notes
|
|
245
|
+
|
|
246
|
+
- **Async I/O:** Tornado event loop; on Linux optionally **uvloop**.
|
|
247
|
+
- **Free-threaded Python:** SQLite access is wrapped (`aird/db/sync.py`); upload chunk writes use `asyncio.to_thread` / `os.pwrite` so parallel range PUTs do not block the loop.
|
|
248
|
+
- **HTTP compression:** `gzip` by default; optional `zstandard` via `pip install aird[compress]` (loaded only on builds where the extension is nogil-safe).
|
|
249
|
+
- **Security headers:** COOP/COEP/CORP for transfer workers; strict CSP on HTML pages.
|
|
250
|
+
- **ABAC:** Optional policy engine (`abac_engine` flag) with admin-defined policies, tags, and user attributes.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Development
|
|
255
|
+
|
|
256
|
+
### Frontend assets
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
npm install
|
|
260
|
+
npm run css:build # Tailwind → aird/static/css/app.css
|
|
261
|
+
npm run js:share # Bundle share UI
|
|
262
|
+
npm run vendor:fflate # Compression worker dependency
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Tests
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
python -m pytest tests/
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Project layout
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
aird/
|
|
275
|
+
handlers/ # HTTP & WebSocket handlers
|
|
276
|
+
services/ # Config, quota, share, audit, …
|
|
277
|
+
static/js/ # Browser UI & transfer engine
|
|
278
|
+
templates/ # Jinja2 pages
|
|
279
|
+
core/ # Compression, mmap, rate limits, …
|
|
280
|
+
docs/ # Per-page UI & admin documentation
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Security
|
|
286
|
+
|
|
287
|
+
- Path traversal and symlink checks on file access
|
|
288
|
+
- Argon2 password hashing for local users
|
|
289
|
+
- CSRF on state-changing requests
|
|
290
|
+
- Upload extension allow-list (or allow-all) with max size enforced server-side
|
|
291
|
+
- Optional storage quotas (multi-user)
|
|
292
|
+
- Audit trail and live policy-decision stream for ABAC
|
|
293
|
+
|
|
294
|
+
Report issues via GitHub. For production, set `AIRD_COOKIE_SECRET`, use TLS, and restrict admin routes.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## License
|
|
299
|
+
|
|
300
|
+
**Business Source License 1.1 (BSL)** — see [LICENSE](LICENSE). Converts to **Apache 2.0** after the change date in the license file.
|
|
301
|
+
|
|
302
|
+
Commercial **File-Management-as-a-Service** use requires a separate license. Contact **Viswanatha Srinivas P**.
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Links
|
|
307
|
+
|
|
308
|
+
- **Repository:** https://github.com/blinkerbit/aird
|
|
309
|
+
- **PyPI:** https://pypi.org/project/aird/
|
|
310
|
+
- **UI / admin docs:** [docs/README.md](docs/README.md) · [docs/transfers.md](docs/transfers.md)
|
|
311
|
+
- **Issues:** https://github.com/blinkerbit/aird/issues
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
Made by **Viswanatha Srinivas P**
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Aird
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="aird/static/img/logo.png" alt="Aird" width="280">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
**Aird** is a self-hosted file browser, editor, and sharing platform built on **Python** and **Tornado**. It targets fast local and LAN use: parallel HTTP transfers for large files, real-time log streaming, content search, secure shares, optional multi-user isolation, and an admin console that applies settings without restarts.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Highlights
|
|
14
|
+
|
|
15
|
+
| Area | What you get |
|
|
16
|
+
|------|----------------|
|
|
17
|
+
| **File manager** | Browse, upload, download, rename, move, copy, bulk ops, in-browser text edit, ZIP download |
|
|
18
|
+
| **Large transfers** | Parallel **HTTP `Content-Range`** uploads/downloads (primary path for big files) |
|
|
19
|
+
| **Search** | **Super Search** — glob + regex content search with live WebSocket progress |
|
|
20
|
+
| **Streaming** | Tail log files over WebSocket with filters |
|
|
21
|
+
| **Sharing** | Token-based public/private shares, static or live folder views |
|
|
22
|
+
| **Security** | CSRF, CSP, path traversal checks, optional **ABAC** policies, WebAuthn, LDAP |
|
|
23
|
+
| **Integrations** | Google Drive / OneDrive browse, P2P WebRTC rooms, optional embedded SMB & WebDAV |
|
|
24
|
+
| **Ops** | SQLite-backed settings, audit log, feature flags, transfer rate limits, health endpoint |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## File transfers
|
|
29
|
+
|
|
30
|
+
Large uploads are designed for **high-throughput links** (e.g. gigabit LAN or VPN):
|
|
31
|
+
|
|
32
|
+
1. **Small files** — single `POST /upload`.
|
|
33
|
+
2. **Large files** — client opens a range session (`POST /api/upload/range/session`), then sends many parallel **`PUT`** requests with `Content-Range`. Each chunk is written **in place** at the correct byte offset on disk (no separate part files, no concat step at the end).
|
|
34
|
+
3. **Downloads** — `GET /files/...?download=1` with optional `Range` for parallel fetch.
|
|
35
|
+
|
|
36
|
+
Defaults (all adjustable in **Admin → Upload settings**):
|
|
37
|
+
|
|
38
|
+
| Setting | Default | Notes |
|
|
39
|
+
|---------|---------|--------|
|
|
40
|
+
| Max file size | 10 240 MB (10 GiB) | Hard cap per file |
|
|
41
|
+
| Single-request max | 100 MB | Files **≥** this use parallel HTTP ranges |
|
|
42
|
+
| HTTP chunk size | 90 MB | Per range `PUT` body |
|
|
43
|
+
| HTTP parallelism | 16 | Concurrent upload streams |
|
|
44
|
+
|
|
45
|
+
**Behind nginx/Caddy:** set `client_max_body_size` (or equivalent) to at least your HTTP chunk size. If **Single-request max** is `0`, Aird uses a **100 MB** parallel threshold (proxy-safe), not a single POST for the entire max file size.
|
|
46
|
+
|
|
47
|
+
Optional WebSocket upload (`/ws/file-transfer`) remains for specialized paths; the browser UI uses **HTTP parallel** by default.
|
|
48
|
+
|
|
49
|
+
Transfer progress, cancel, and resume metadata are handled in the browser (`transfer-tracker.js`, `transfer-engine/`, service worker `sw-transfer.js`).
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Quick start
|
|
54
|
+
|
|
55
|
+
### Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install aird
|
|
59
|
+
|
|
60
|
+
# Optional: HTTP response compression codecs (gzip is always available)
|
|
61
|
+
pip install "aird[compress]"
|
|
62
|
+
|
|
63
|
+
# From source
|
|
64
|
+
git clone https://github.com/blinkerbit/aird.git
|
|
65
|
+
cd aird
|
|
66
|
+
pip install -e .
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Python:** 3.10+ required. On Linux, **free-threaded** builds (`3.13t` / `3.14t`) are supported and recommended for parallel disk I/O; the server detects nogil at startup and sizes the I/O thread pool accordingly.
|
|
70
|
+
|
|
71
|
+
### Run
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Default: port 8000, current directory as root
|
|
75
|
+
python -m aird
|
|
76
|
+
|
|
77
|
+
# Custom root and port
|
|
78
|
+
python -m aird --root /data --port 8080
|
|
79
|
+
|
|
80
|
+
# Multi-user (per-user home directories under root)
|
|
81
|
+
python -m aird --root /data --multi-user
|
|
82
|
+
|
|
83
|
+
# TLS
|
|
84
|
+
python -m aird --ssl-cert /path/cert.pem --ssl-key /path/key.pem --port 443
|
|
85
|
+
|
|
86
|
+
# Worker processes (Linux; default is auto from CPU topology)
|
|
87
|
+
python -m aird --workers 4
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
On first start, random **access** and **admin** tokens are printed unless you set them via `--token`, `--admin-token`, `config.json`, or `AIRD_ACCESS_TOKEN`.
|
|
91
|
+
|
|
92
|
+
Open `http://localhost:8000/` → redirects to `/files/`.
|
|
93
|
+
|
|
94
|
+
### CLI client
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install aird # includes aird-cli
|
|
98
|
+
aird-cli config set server https://your-host
|
|
99
|
+
aird-cli login
|
|
100
|
+
aird-cli ls /
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Configuration
|
|
106
|
+
|
|
107
|
+
### `config.json`
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"port": 8000,
|
|
112
|
+
"root": "/srv/files",
|
|
113
|
+
"hostname": "files.example.com",
|
|
114
|
+
"token": "your-access-token",
|
|
115
|
+
"admin_token": "your-admin-token",
|
|
116
|
+
"multi_user": false,
|
|
117
|
+
"workers": 2,
|
|
118
|
+
"ldap": {
|
|
119
|
+
"enabled": false,
|
|
120
|
+
"server": "ldap://ldap.example.com",
|
|
121
|
+
"base_dn": "dc=example,dc=com"
|
|
122
|
+
},
|
|
123
|
+
"feature_flags": {
|
|
124
|
+
"file_upload": true,
|
|
125
|
+
"super_search": true,
|
|
126
|
+
"abac_engine": false
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
python -m aird --config /etc/aird/config.json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Environment variables (common)
|
|
136
|
+
|
|
137
|
+
| Variable | Purpose |
|
|
138
|
+
|----------|---------|
|
|
139
|
+
| `AIRD_ACCESS_TOKEN` | Login token |
|
|
140
|
+
| `AIRD_COOKIE_SECRET` | Persistent session signing (set in production) |
|
|
141
|
+
| `AIRD_CORPORATE_IP_CIDRS` | Comma-separated CIDRs for ABAC / WAN compression rules |
|
|
142
|
+
| `AIRD_GDRIVE_ACCESS_TOKEN` / `AIRD_ONEDRIVE_ACCESS_TOKEN` | Cloud providers |
|
|
143
|
+
|
|
144
|
+
### Admin console
|
|
145
|
+
|
|
146
|
+
`GET /admin` — feature flags, upload limits, extension allow-list, WebSocket pool limits, LDAP, network shares, ABAC policies/tags, users, audit. Changes persist to SQLite and apply without restart (feature-flag subscribers refresh over `/features` WebSocket).
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Production deployment
|
|
151
|
+
|
|
152
|
+
### Reverse proxy
|
|
153
|
+
|
|
154
|
+
Aird listens on one port (default **8000**). Terminate TLS at **Caddy**, **nginx**, or similar.
|
|
155
|
+
|
|
156
|
+
**nginx example** (adjust chunk size to match Admin → HTTP chunk):
|
|
157
|
+
|
|
158
|
+
```nginx
|
|
159
|
+
client_max_body_size 128m;
|
|
160
|
+
|
|
161
|
+
location / {
|
|
162
|
+
proxy_pass http://127.0.0.1:8000;
|
|
163
|
+
proxy_http_version 1.1;
|
|
164
|
+
proxy_set_header Host $host;
|
|
165
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
166
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
167
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
WebSocket routes (`/stream/`, `/search/ws`, `/features`, `/ws/…`) need `Upgrade` and `Connection` headers if you proxy them.
|
|
172
|
+
|
|
173
|
+
### Ubuntu deploy script
|
|
174
|
+
|
|
175
|
+
`deploy_local.ps1` (run from Windows) syncs source or a wheel to a remote host, creates a **uv** venv with **Python 3.14t**, and installs the package. See `docs/wireguard-deploy.md` for VPN-only TLS layouts.
|
|
176
|
+
|
|
177
|
+
### Systemd
|
|
178
|
+
|
|
179
|
+
Run `python -m aird` (or the venv equivalent) as a service user with `--config` pointing at your JSON file. Logs go to the data directory (`aird.log` under the platform app data path).
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## API overview
|
|
184
|
+
|
|
185
|
+
Authentication: session cookie after `/login`, bearer token, or `Authorization` header where supported. Mutating requests require the `_xsrf` cookie + `X-XSRFToken` header.
|
|
186
|
+
|
|
187
|
+
| Operation | Method / path |
|
|
188
|
+
|-----------|----------------|
|
|
189
|
+
| List directory | `GET /api/files/{path}` |
|
|
190
|
+
| Upload (small) | `POST /upload` |
|
|
191
|
+
| Upload (large) | `POST /api/upload/range/session` then `PUT /api/upload/range/{id}` |
|
|
192
|
+
| Upload status | `GET /api/upload/range/{id}/status` |
|
|
193
|
+
| Download | `GET /files/{path}?download=1` |
|
|
194
|
+
| Edit | `GET /edit/{path}`, `POST /edit` |
|
|
195
|
+
| Delete / rename / mkdir | `POST /delete`, `POST /rename`, `POST /mkdir` |
|
|
196
|
+
| Search UI | `GET /search` |
|
|
197
|
+
| Search (live) | WebSocket `/search/ws` |
|
|
198
|
+
| Log stream | WebSocket `/stream/{path}` |
|
|
199
|
+
| Shares | `POST /share/create`, `GET /share/list`, … |
|
|
200
|
+
| Health | `GET /health` |
|
|
201
|
+
|
|
202
|
+
Page-level UI contracts and routes are documented under [`docs/`](docs/README.md).
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Architecture notes
|
|
207
|
+
|
|
208
|
+
- **Async I/O:** Tornado event loop; on Linux optionally **uvloop**.
|
|
209
|
+
- **Free-threaded Python:** SQLite access is wrapped (`aird/db/sync.py`); upload chunk writes use `asyncio.to_thread` / `os.pwrite` so parallel range PUTs do not block the loop.
|
|
210
|
+
- **HTTP compression:** `gzip` by default; optional `zstandard` via `pip install aird[compress]` (loaded only on builds where the extension is nogil-safe).
|
|
211
|
+
- **Security headers:** COOP/COEP/CORP for transfer workers; strict CSP on HTML pages.
|
|
212
|
+
- **ABAC:** Optional policy engine (`abac_engine` flag) with admin-defined policies, tags, and user attributes.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Development
|
|
217
|
+
|
|
218
|
+
### Frontend assets
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
npm install
|
|
222
|
+
npm run css:build # Tailwind → aird/static/css/app.css
|
|
223
|
+
npm run js:share # Bundle share UI
|
|
224
|
+
npm run vendor:fflate # Compression worker dependency
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Tests
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
python -m pytest tests/
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Project layout
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
aird/
|
|
237
|
+
handlers/ # HTTP & WebSocket handlers
|
|
238
|
+
services/ # Config, quota, share, audit, …
|
|
239
|
+
static/js/ # Browser UI & transfer engine
|
|
240
|
+
templates/ # Jinja2 pages
|
|
241
|
+
core/ # Compression, mmap, rate limits, …
|
|
242
|
+
docs/ # Per-page UI & admin documentation
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Security
|
|
248
|
+
|
|
249
|
+
- Path traversal and symlink checks on file access
|
|
250
|
+
- Argon2 password hashing for local users
|
|
251
|
+
- CSRF on state-changing requests
|
|
252
|
+
- Upload extension allow-list (or allow-all) with max size enforced server-side
|
|
253
|
+
- Optional storage quotas (multi-user)
|
|
254
|
+
- Audit trail and live policy-decision stream for ABAC
|
|
255
|
+
|
|
256
|
+
Report issues via GitHub. For production, set `AIRD_COOKIE_SECRET`, use TLS, and restrict admin routes.
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## License
|
|
261
|
+
|
|
262
|
+
**Business Source License 1.1 (BSL)** — see [LICENSE](LICENSE). Converts to **Apache 2.0** after the change date in the license file.
|
|
263
|
+
|
|
264
|
+
Commercial **File-Management-as-a-Service** use requires a separate license. Contact **Viswanatha Srinivas P**.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Links
|
|
269
|
+
|
|
270
|
+
- **Repository:** https://github.com/blinkerbit/aird
|
|
271
|
+
- **PyPI:** https://pypi.org/project/aird/
|
|
272
|
+
- **UI / admin docs:** [docs/README.md](docs/README.md) · [docs/transfers.md](docs/transfers.md)
|
|
273
|
+
- **Issues:** https://github.com/blinkerbit/aird/issues
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
Made by **Viswanatha Srinivas P**
|
|
@@ -10,8 +10,8 @@ from typing import Any, Callable
|
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
DEFAULT_CHUNK =
|
|
14
|
-
DEFAULT_CONCURRENCY =
|
|
13
|
+
DEFAULT_CHUNK = 16 * 1024 * 1024
|
|
14
|
+
DEFAULT_CONCURRENCY = 12
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def _clone_session(http: requests.Session) -> requests.Session:
|