mmisp-lib 0.8.0__tar.gz → 0.8.2__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.
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/PKG-INFO +1 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/pyproject.toml +1 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/organisations.py +5 -5
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/sharing_groups.py +51 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/commandline_tool/main.py +2 -2
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/commandline_tool/organisation.py +3 -3
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/config.py +19 -14
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/database.py +3 -1
- mmisp_lib-0.8.2/src/mmisp/db/list_json_type.py +31 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/galaxy_cluster.py +2 -19
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/organisation.py +2 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/server.py +2 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/sharing_group.py +44 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/compatibility_helpers.py +13 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/organisation_generator.py +1 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp_lib.egg-info/PKG-INFO +1 -1
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp_lib.egg-info/SOURCES.txt +1 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/tests/test_commandline_tool.py +3 -3
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/LICENSE +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/README.md +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/setup.cfg +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/attributes.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/auth_keys.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/authentication.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/common.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/events.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/feeds.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/galaxies.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/galaxy_clusters.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/galaxy_common.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/jobs.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/logs.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/noticelists.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/objects.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/py.typed +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/responses/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/responses/check_graph_response.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/responses/standard_status_response.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/roles.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/server.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/servers.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/shadow_attribute.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/sightings.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/statistics.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/tags.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/taxonomies.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/user_settings.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/users.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/warninglists.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/workflows.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/commandline_tool/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/commandline_tool/py.typed +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/commandline_tool/setup.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/commandline_tool/user.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/additional_properties.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/all_models.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/lib.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/mixins.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/admin_setting.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/attribute.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/auth_key.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/blocklist.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/correlation.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/event.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/feed.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/galaxy.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/identity_provider.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/log.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/noticelist.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/object.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/post.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/role.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/shadow_attribute.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/sighting.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/tag.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/taxonomy.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/threat_level.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/user.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/user_setting.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/warninglist.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/workflow.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/models/workflow_blueprint.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/mypy.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/print_changes.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/py.typed +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/db/uuid_type.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/actions.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/attribute_search_filter.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/attributes.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/distribution.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/fallbacks.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/galaxies.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/galaxy_clusters.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/logger.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/permissions.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/py.typed +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/serialisation_helper.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/lib/uuid.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/enrichment/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/enrichment/data.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/enrichment/enrichment_plugin.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/exceptions.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/models/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/models/attribute.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/plugin_info.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/plugin_type.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/plugins/py.typed +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/fixtures.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/attribute_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/feed_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/attribute_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/auth_key_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/correlation_exclusions_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/correlation_value_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/default_correlation_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/event_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/galaxy_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/identity_provider_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/noticelist_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/object_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/over_correlating_value_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/post_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/role_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/server_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/shadow_attribute_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/sharing_group_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/sighting_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/tag_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/taxonomy_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/user_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/user_setting_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/warninglist_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/workflow_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/object_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/sighting_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/tag_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/taxonomies_generator.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/util/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/util/crypto.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/util/models.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/util/partial.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/util/py.typed +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/util/uuid.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/__init__.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/execution.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/fastapi.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/graph.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/input.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/legacy.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/misp_core_format.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/modules.py +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/workflows/py.typed +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp_lib.egg-info/dependency_links.txt +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp_lib.egg-info/entry_points.txt +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp_lib.egg-info/requires.txt +0 -0
- {mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp_lib.egg-info/top_level.txt +0 -0
@@ -23,7 +23,7 @@ class Organisation(BaseOrganisation):
|
|
23
23
|
contacts: str | None = None
|
24
24
|
local: bool
|
25
25
|
"""organisation gains access to the local instance, otherwise treated as external"""
|
26
|
-
restricted_to_domain:
|
26
|
+
restricted_to_domain: list | str | None = None
|
27
27
|
landingpage: str | None = None
|
28
28
|
|
29
29
|
class Config:
|
@@ -45,7 +45,7 @@ class GetOrganisationResponse(BaseModel):
|
|
45
45
|
created_by: str
|
46
46
|
contacts: str | None = None
|
47
47
|
local: bool
|
48
|
-
restricted_to_domain:
|
48
|
+
restricted_to_domain: list | str | None = None
|
49
49
|
landingpage: str | None = None
|
50
50
|
|
51
51
|
def dict(self: Self, *args, **kwargs) -> dict:
|
@@ -90,7 +90,7 @@ class OrganisationUsersResponse(BaseModel):
|
|
90
90
|
uuid: str | None = None
|
91
91
|
contacts: str | None = None
|
92
92
|
local: bool | None = None
|
93
|
-
restricted_to_domain:
|
93
|
+
restricted_to_domain: list | str | None = None
|
94
94
|
landingpage: str | None = None
|
95
95
|
|
96
96
|
|
@@ -105,7 +105,7 @@ class AddOrganisation(BaseModel):
|
|
105
105
|
contacts: str | None = None
|
106
106
|
local: bool
|
107
107
|
"""organisation gains access to the local instance, otherwise treated as external"""
|
108
|
-
restricted_to_domain: str | None = None
|
108
|
+
restricted_to_domain: list[str] | None = None
|
109
109
|
landingpage: str | None = None
|
110
110
|
|
111
111
|
class Config:
|
@@ -121,7 +121,7 @@ class EditOrganisation(BaseModel):
|
|
121
121
|
contacts: str | None = None
|
122
122
|
local: bool
|
123
123
|
"""organisation gains access to the local instance, otherwise treated as external"""
|
124
|
-
restricted_to_domain: str | None = None
|
124
|
+
restricted_to_domain: list[str] | None = None
|
125
125
|
landingpage: str | None = None
|
126
126
|
|
127
127
|
class Config:
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import uuid
|
1
2
|
from datetime import datetime
|
2
3
|
|
3
4
|
from pydantic import BaseModel, Field
|
@@ -22,6 +23,28 @@ class SharingGroup(BaseModel):
|
|
22
23
|
roaming: bool
|
23
24
|
|
24
25
|
|
26
|
+
# org_count: int = 0
|
27
|
+
|
28
|
+
|
29
|
+
class ShortSharingGroup(BaseModel):
|
30
|
+
id: int
|
31
|
+
name: str
|
32
|
+
releasability: str
|
33
|
+
description: str
|
34
|
+
uuid: str
|
35
|
+
active: bool
|
36
|
+
local: bool
|
37
|
+
roaming: bool
|
38
|
+
|
39
|
+
org_count: int = 0
|
40
|
+
|
41
|
+
|
42
|
+
class ShortOrganisation(BaseModel):
|
43
|
+
id: int
|
44
|
+
name: str
|
45
|
+
uuid: uuid.UUID
|
46
|
+
|
47
|
+
|
25
48
|
class SharingGroupServer(BaseModel):
|
26
49
|
id: int
|
27
50
|
sharing_group_id: int
|
@@ -81,12 +104,39 @@ class ViewUpdateSharingGroupLegacyResponseSharingGroupOrgItem(BaseModel):
|
|
81
104
|
Organisation: ViewUpdateSharingGroupLegacyResponseOrganisationInfo
|
82
105
|
|
83
106
|
|
84
|
-
class
|
107
|
+
class SharingGroupResponse(BaseModel):
|
108
|
+
SharingGroup: ShortSharingGroup
|
109
|
+
Organisation: ShortOrganisation
|
110
|
+
SharingGroupOrg: list[ViewUpdateSharingGroupLegacyResponseSharingGroupOrgItem]
|
111
|
+
SharingGroupServer: list[ViewUpdateSharingGroupLegacyResponseSharingGroupServerItem]
|
112
|
+
|
113
|
+
editable: bool | None = None
|
114
|
+
deletable: bool | None = None
|
115
|
+
|
116
|
+
class Config:
|
117
|
+
json_encoders = {datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S")}
|
118
|
+
|
119
|
+
|
120
|
+
class SingleSharingGroupResponse(BaseModel):
|
85
121
|
SharingGroup: SharingGroup
|
86
122
|
Organisation: Organisation
|
87
123
|
SharingGroupOrg: list[ViewUpdateSharingGroupLegacyResponseSharingGroupOrgItem]
|
88
124
|
SharingGroupServer: list[ViewUpdateSharingGroupLegacyResponseSharingGroupServerItem]
|
89
125
|
|
126
|
+
class Config:
|
127
|
+
json_encoders = {datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S")}
|
128
|
+
|
129
|
+
|
130
|
+
class ViewUpdateSharingGroupLegacyResponse(SharingGroupResponse):
|
131
|
+
pass
|
132
|
+
|
133
|
+
|
134
|
+
class GetSharingGroupsIndex(BaseModel):
|
135
|
+
response: list[SharingGroupResponse]
|
136
|
+
|
137
|
+
class Config:
|
138
|
+
json_encoders = {datetime: lambda v: v.strftime("%Y-%m-%d %H:%M:%S")}
|
139
|
+
|
90
140
|
|
91
141
|
class UpdateSharingGroupLegacyBody(BaseModel):
|
92
142
|
id: int | None = None
|
@@ -43,7 +43,7 @@ async def create_organisation(
|
|
43
43
|
sector: str | None = None,
|
44
44
|
contacts_email: str | None = None,
|
45
45
|
local: bool | None = None,
|
46
|
-
restricted_domain: str | None = None,
|
46
|
+
restricted_domain: list[str] | None = None,
|
47
47
|
landingpage: str | None = None,
|
48
48
|
) -> str:
|
49
49
|
"""create-organisation <name> [-admin_email <admin_email>] [- description <description>] [-type <type>]
|
@@ -115,7 +115,7 @@ async def edit_organisation(
|
|
115
115
|
sector: str | None = None,
|
116
116
|
contacts_email: str | None = None,
|
117
117
|
local: bool | None = None,
|
118
|
-
restricted_domain: str | None = None,
|
118
|
+
restricted_domain: list[str] | None = None,
|
119
119
|
landingpage: str | None = None,
|
120
120
|
) -> str:
|
121
121
|
"""edit-organisation <organisation> [-new_name <new_name>] [-admin_email <admin_email>] [-description <description>]
|
@@ -18,7 +18,7 @@ async def create(
|
|
18
18
|
sector: str | None,
|
19
19
|
contacts_email: str | None,
|
20
20
|
local: bool | None,
|
21
|
-
restricted_domain: str | None,
|
21
|
+
restricted_domain: list[str] | None,
|
22
22
|
landingpage: str | None,
|
23
23
|
) -> None:
|
24
24
|
organisation = Organisation()
|
@@ -67,7 +67,7 @@ async def edit_organisation(
|
|
67
67
|
sector: str | None,
|
68
68
|
contacts_email: str | None,
|
69
69
|
local: bool | None,
|
70
|
-
restricted_domain: str | None,
|
70
|
+
restricted_domain: list[str] | None,
|
71
71
|
landingpage: str | None,
|
72
72
|
) -> None:
|
73
73
|
if isinstance(organisation, str):
|
@@ -109,7 +109,7 @@ async def set_attributes(
|
|
109
109
|
sector: str | None,
|
110
110
|
contacts_email: str | None,
|
111
111
|
local: bool | None,
|
112
|
-
restricted_domain: str | None,
|
112
|
+
restricted_domain: list[str] | None,
|
113
113
|
landingpage: str | None,
|
114
114
|
) -> None:
|
115
115
|
if name is not None:
|
@@ -10,33 +10,38 @@ The following environment variables are supported:
|
|
10
10
|
"""
|
11
11
|
|
12
12
|
import logging
|
13
|
-
from dataclasses import dataclass
|
14
13
|
from os import getenv
|
15
14
|
|
16
15
|
from dotenv import load_dotenv
|
16
|
+
from pydantic import BaseSettings, Field, root_validator
|
17
17
|
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
19
|
+
class DatabaseConfig(BaseSettings):
|
20
|
+
DATABASE_URL: str | None = None
|
21
|
+
DEBUG: bool = False
|
22
|
+
RETRY_SLEEP: int = Field(5, env="DB_RETRY")
|
23
|
+
MAX_RETRIES: int = Field(100, env="DB_MAX_RETRIES")
|
24
|
+
CONNECTION_INIT: bool = True
|
25
25
|
DB_LOGLEVEL: str | None = None
|
26
26
|
|
27
|
+
@root_validator(skip_on_failure=True)
|
28
|
+
def require_db_url_or_no_connection(cls: "DatabaseConfig", values: dict) -> dict:
|
29
|
+
db_url = values.get("DATABASE_URL")
|
30
|
+
connection_init = values.get("CONNECTION_INIT")
|
31
|
+
if db_url is None and connection_init:
|
32
|
+
raise ValueError("Environment variable DATABASE_URL is required when CONNECTION_INIT is not False")
|
33
|
+
|
34
|
+
return values
|
35
|
+
|
27
36
|
|
28
37
|
load_dotenv(getenv("ENV_FILE", ".env"))
|
29
38
|
|
30
39
|
|
31
|
-
config: DatabaseConfig = DatabaseConfig(
|
32
|
-
|
33
|
-
DEBUG=bool(getenv("DEBUG", False)),
|
34
|
-
RETRY_SLEEP=int(getenv("DB_RETRY", 5)),
|
35
|
-
MAX_RETRIES=int(getenv("DB_MAX_RETRIES", 100)),
|
36
|
-
DB_LOGLEVEL=getenv("DB_LOGLEVEL", None),
|
37
|
-
)
|
40
|
+
config: DatabaseConfig = DatabaseConfig()
|
41
|
+
|
38
42
|
sqlalchemy_logger = logging.getLogger("sqlalchemy.engine")
|
39
43
|
sqlalchemy_logger.setLevel(logging.WARNING)
|
44
|
+
|
40
45
|
if config.DEBUG:
|
41
46
|
sqlalchemy_logger.setLevel(logging.INFO)
|
42
47
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import json
|
2
|
+
from typing import Any, Self
|
3
|
+
|
4
|
+
from sqlalchemy.engine import Dialect
|
5
|
+
from sqlalchemy.types import Text, TypeDecorator
|
6
|
+
|
7
|
+
|
8
|
+
class DBListJson(TypeDecorator):
|
9
|
+
impl = Text
|
10
|
+
|
11
|
+
def load_dialect_impl(self: Self, dialect: Dialect) -> Any:
|
12
|
+
return dialect.type_descriptor(Text)
|
13
|
+
|
14
|
+
def process_bind_param(self: Self, value: Any, dialect: Dialect) -> str | None:
|
15
|
+
"""Handle value before getting into the DB"""
|
16
|
+
if value is None:
|
17
|
+
return None
|
18
|
+
if not isinstance(value, list):
|
19
|
+
raise ValueError("this type should only be used for lists")
|
20
|
+
return json.dumps(value)
|
21
|
+
|
22
|
+
def process_result_value(self: Self, value: Any, dialect: Dialect) -> list | None:
|
23
|
+
"""Handle values from the database"""
|
24
|
+
if value is None:
|
25
|
+
return None
|
26
|
+
|
27
|
+
res = json.loads(value)
|
28
|
+
if not isinstance(res, list):
|
29
|
+
raise ValueError("this type should only be used for lists")
|
30
|
+
|
31
|
+
return res
|
@@ -1,10 +1,7 @@
|
|
1
|
-
import json
|
2
|
-
from typing import Self
|
3
|
-
|
4
1
|
from sqlalchemy import Boolean, ForeignKey, Integer, String, Text
|
5
|
-
from sqlalchemy.ext.hybrid import hybrid_property
|
6
2
|
from sqlalchemy.orm import relationship
|
7
3
|
|
4
|
+
from mmisp.db.list_json_type import DBListJson
|
8
5
|
from mmisp.db.mixins import DictMixin, UpdateMixin
|
9
6
|
from mmisp.db.mypy import Mapped, mapped_column
|
10
7
|
from mmisp.db.uuid_type import DBUUID
|
@@ -28,7 +25,7 @@ class GalaxyCluster(Base, UpdateMixin, DictMixin):
|
|
28
25
|
Integer, ForeignKey(Galaxy.id, ondelete="CASCADE"), nullable=False, index=True
|
29
26
|
)
|
30
27
|
source: Mapped[str] = mapped_column(String(255), nullable=False, default="")
|
31
|
-
|
28
|
+
authors: Mapped[list[str]] = mapped_column(DBListJson, nullable=False)
|
32
29
|
version: Mapped[int] = mapped_column(Integer, default=0, index=True)
|
33
30
|
distribution: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
34
31
|
sharing_group_id: Mapped[int] = mapped_column(Integer, index=True, nullable=True, default=None)
|
@@ -75,20 +72,6 @@ class GalaxyCluster(Base, UpdateMixin, DictMixin):
|
|
75
72
|
uselist=False,
|
76
73
|
) # type:ignore[assignment,var-annotated]
|
77
74
|
|
78
|
-
def __init__(self: Self, *arg, **kwargs) -> None:
|
79
|
-
if "authors" in kwargs:
|
80
|
-
self._authors = json.dumps(kwargs["authors"])
|
81
|
-
del kwargs["authors"]
|
82
|
-
super().__init__(*arg, **kwargs)
|
83
|
-
|
84
|
-
@hybrid_property
|
85
|
-
def authors(self: Self) -> list[str]:
|
86
|
-
return json.loads(self._authors)
|
87
|
-
|
88
|
-
@authors.setter # type: ignore[no-redef]
|
89
|
-
def authors(self: Self, value: list[str]) -> None:
|
90
|
-
self._authors = json.dumps(value)
|
91
|
-
|
92
75
|
|
93
76
|
class GalaxyElement(Base, DictMixin, UpdateMixin):
|
94
77
|
__tablename__ = "galaxy_elements"
|
@@ -3,6 +3,7 @@ from datetime import datetime
|
|
3
3
|
from sqlalchemy import Boolean, DateTime, Integer, String, Text
|
4
4
|
from sqlalchemy.orm import relationship
|
5
5
|
|
6
|
+
from mmisp.db.list_json_type import DBListJson
|
6
7
|
from mmisp.db.mixins import DictMixin
|
7
8
|
from mmisp.db.mypy import Mapped, mapped_column
|
8
9
|
|
@@ -26,7 +27,7 @@ class Organisation(Base, DictMixin):
|
|
26
27
|
uuid: Mapped[str] = mapped_column(String(255), unique=True)
|
27
28
|
contacts: Mapped[str] = mapped_column(Text)
|
28
29
|
local: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
|
29
|
-
restricted_to_domain: Mapped[str] = mapped_column(
|
30
|
+
restricted_to_domain: Mapped[list[str]] = mapped_column(DBListJson)
|
30
31
|
landingpage: Mapped[str] = mapped_column(Text)
|
31
32
|
|
32
33
|
# Relationship to users
|
@@ -1,12 +1,13 @@
|
|
1
1
|
from sqlalchemy import Boolean, Integer, String, Text
|
2
2
|
from sqlalchemy.orm import relationship
|
3
3
|
|
4
|
+
from mmisp.db.mixins import DictMixin
|
4
5
|
from mmisp.db.mypy import Mapped, mapped_column
|
5
6
|
|
6
7
|
from ..database import Base
|
7
8
|
|
8
9
|
|
9
|
-
class Server(Base):
|
10
|
+
class Server(Base, DictMixin):
|
10
11
|
__tablename__ = "servers"
|
11
12
|
|
12
13
|
id: Mapped[int] = mapped_column(Integer, primary_key=True, nullable=False)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from datetime import datetime
|
2
2
|
|
3
3
|
from sqlalchemy import Boolean, DateTime, Integer, String, Text
|
4
|
+
from sqlalchemy.orm import relationship
|
4
5
|
|
5
6
|
from mmisp.db.mixins import DictMixin
|
6
7
|
from mmisp.db.mypy import Mapped, mapped_column
|
@@ -18,7 +19,7 @@ class SharingGroup(Base, DictMixin):
|
|
18
19
|
description = mapped_column(Text, nullable=False, default="")
|
19
20
|
uuid = mapped_column(String(40), unique=True, default=uuid, nullable=False)
|
20
21
|
organisation_uuid = mapped_column(String(40), nullable=False)
|
21
|
-
org_id = mapped_column(Integer, nullable=False, index=True)
|
22
|
+
org_id = mapped_column(Integer, nullable=False, index=True) # the organisation that created the sharing group
|
22
23
|
sync_user_id = mapped_column(Integer, nullable=False, default=0, index=True)
|
23
24
|
active = mapped_column(Boolean, nullable=False, default=False)
|
24
25
|
created = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
|
@@ -26,6 +27,34 @@ class SharingGroup(Base, DictMixin):
|
|
26
27
|
local = mapped_column(Boolean, nullable=False, default=True)
|
27
28
|
roaming = mapped_column(Boolean, default=False, nullable=False)
|
28
29
|
|
30
|
+
creator_org = relationship(
|
31
|
+
"Organisation",
|
32
|
+
primaryjoin="SharingGroup.org_id == Organisation.id",
|
33
|
+
lazy="raise_on_sql",
|
34
|
+
foreign_keys="SharingGroup.org_id",
|
35
|
+
) # type:ignore[assignment,var-annotated]
|
36
|
+
organisations = relationship(
|
37
|
+
"Organisation",
|
38
|
+
primaryjoin="SharingGroup.id == SharingGroupOrg.sharing_group_id",
|
39
|
+
secondary="sharing_group_orgs",
|
40
|
+
secondaryjoin="SharingGroupOrg.org_id == Organisation.id",
|
41
|
+
lazy="raise_on_sql",
|
42
|
+
viewonly=True,
|
43
|
+
)
|
44
|
+
|
45
|
+
sharing_group_orgs = relationship(
|
46
|
+
"SharingGroupOrg",
|
47
|
+
primaryjoin="SharingGroup.id == SharingGroupOrg.sharing_group_id",
|
48
|
+
lazy="raise_on_sql",
|
49
|
+
foreign_keys="SharingGroupOrg.sharing_group_id",
|
50
|
+
) # type:ignore[assignment,var-annotated]
|
51
|
+
sharing_group_servers = relationship(
|
52
|
+
"SharingGroupServer",
|
53
|
+
primaryjoin="SharingGroup.id == SharingGroupServer.sharing_group_id",
|
54
|
+
lazy="raise_on_sql",
|
55
|
+
foreign_keys="SharingGroupServer.sharing_group_id",
|
56
|
+
) # type:ignore[assignment,var-annotated]
|
57
|
+
|
29
58
|
|
30
59
|
class SharingGroupOrg(Base, DictMixin):
|
31
60
|
__tablename__ = "sharing_group_orgs"
|
@@ -35,6 +64,13 @@ class SharingGroupOrg(Base, DictMixin):
|
|
35
64
|
org_id = mapped_column(Integer, index=True, nullable=False)
|
36
65
|
extend = mapped_column(Boolean, default=False, nullable=False)
|
37
66
|
|
67
|
+
organisation = relationship(
|
68
|
+
"Organisation",
|
69
|
+
primaryjoin="SharingGroupOrg.org_id == Organisation.id",
|
70
|
+
lazy="raise_on_sql",
|
71
|
+
foreign_keys="SharingGroupOrg.org_id",
|
72
|
+
) # type:ignore[assignment,var-annotated]
|
73
|
+
|
38
74
|
|
39
75
|
class SharingGroupServer(Base, DictMixin):
|
40
76
|
__tablename__ = "sharing_group_servers"
|
@@ -43,3 +79,10 @@ class SharingGroupServer(Base, DictMixin):
|
|
43
79
|
sharing_group_id = mapped_column(Integer, index=True, nullable=False)
|
44
80
|
server_id = mapped_column(Integer, index=True, nullable=False)
|
45
81
|
all_orgs = mapped_column(Boolean, index=True, nullable=False, default=False)
|
82
|
+
|
83
|
+
server = relationship(
|
84
|
+
"Server",
|
85
|
+
primaryjoin="SharingGroupServer.server_id == Server.id",
|
86
|
+
lazy="raise_on_sql",
|
87
|
+
foreign_keys="SharingGroupServer.server_id",
|
88
|
+
) # type:ignore[assignment,var-annotated]
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import json
|
2
|
+
|
1
3
|
import httpx
|
2
4
|
from deepdiff import DeepDiff
|
3
5
|
from icecream import ic
|
@@ -62,4 +64,15 @@ def get_legacy_modern_diff(http_method, path, body, auth_key, client, preprocess
|
|
62
64
|
if diff["dictionary_item_removed"] == {}:
|
63
65
|
del diff["dictionary_item_removed"]
|
64
66
|
|
67
|
+
# somehow misp manages to maintain the json encoded restricted_to_domain str in GalaxyCluster only.
|
68
|
+
# we will ignore this, this is too broken
|
69
|
+
if diff.get("type_changes", False):
|
70
|
+
diff["type_changes"] = {
|
71
|
+
k: v
|
72
|
+
for k, v in diff["type_changes"].items()
|
73
|
+
if not ("restricted_to_domain" in k and v["new_value"] == json.dumps(v["old_value"]))
|
74
|
+
}
|
75
|
+
if diff["type_changes"] == {}:
|
76
|
+
del diff["type_changes"]
|
77
|
+
|
65
78
|
return diff
|
@@ -55,7 +55,7 @@ async def test_create_organisation(db, site_admin_user) -> None:
|
|
55
55
|
sector = time_now
|
56
56
|
contacts_email = time_now
|
57
57
|
local = False
|
58
|
-
restricted_domain =
|
58
|
+
restricted_domain: list[str] = []
|
59
59
|
landingpage = time_now
|
60
60
|
await main.create_organisation(
|
61
61
|
name, admin_email, description, type, nationality, sector, contacts_email, local, restricted_domain, landingpage
|
@@ -157,7 +157,7 @@ async def test_edit_organisation(db, organisation, site_admin_user) -> None:
|
|
157
157
|
new_sector = time_now
|
158
158
|
new_contacts_email = time_now
|
159
159
|
new_local = False
|
160
|
-
new_restricted_domain =
|
160
|
+
new_restricted_domain: list[str] = []
|
161
161
|
new_landingpage = time_now
|
162
162
|
await main.edit_organisation(
|
163
163
|
organisation.name,
|
@@ -181,7 +181,7 @@ async def test_edit_organisation(db, organisation, site_admin_user) -> None:
|
|
181
181
|
assert organisation.sector == new_sector
|
182
182
|
assert organisation.contacts == new_contacts_email
|
183
183
|
assert bool(organisation.local) is new_local
|
184
|
-
assert
|
184
|
+
assert organisation.restricted_to_domain == new_restricted_domain
|
185
185
|
assert organisation.landingpage == new_landingpage
|
186
186
|
|
187
187
|
try:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/api_schemas/responses/standard_status_response.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/event_generator.py
RENAMED
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/galaxy_generator.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/object_generator.py
RENAMED
File without changes
|
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/post_generator.py
RENAMED
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/role_generator.py
RENAMED
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/server_generator.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/tag_generator.py
RENAMED
File without changes
|
File without changes
|
{mmisp_lib-0.8.0 → mmisp_lib-0.8.2}/src/mmisp/tests/generators/model_generators/user_generator.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|