secureapi 0.1.0__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.
Files changed (29) hide show
  1. secureapi-0.1.0/LICENSE +5 -0
  2. secureapi-0.1.0/PKG-INFO +21 -0
  3. secureapi-0.1.0/README.md +3 -0
  4. secureapi-0.1.0/pyproject.toml +25 -0
  5. secureapi-0.1.0/secureapi/__init__.py +1 -0
  6. secureapi-0.1.0/secureapi/config/__init__.py +0 -0
  7. secureapi-0.1.0/secureapi/config/loader.py +17 -0
  8. secureapi-0.1.0/secureapi/core/__init__.py +0 -0
  9. secureapi-0.1.0/secureapi/core/context.py +7 -0
  10. secureapi-0.1.0/secureapi/core/engine.py +36 -0
  11. secureapi-0.1.0/secureapi/core/exceptions.py +1 -0
  12. secureapi-0.1.0/secureapi/core/policy.py +9 -0
  13. secureapi-0.1.0/secureapi/core/validator.py +1 -0
  14. secureapi-0.1.0/secureapi/integrations/__init__.py +0 -0
  15. secureapi-0.1.0/secureapi/integrations/django/__init__.py +0 -0
  16. secureapi-0.1.0/secureapi/integrations/django/middleware.py +1 -0
  17. secureapi-0.1.0/secureapi/integrations/django/permission.py +41 -0
  18. secureapi-0.1.0/secureapi/integrations/fastapi/__init__.py +0 -0
  19. secureapi-0.1.0/secureapi/integrations/fastapi/dependency.py +23 -0
  20. secureapi-0.1.0/secureapi/integrations/flask/__init__.py +0 -0
  21. secureapi-0.1.0/secureapi/integrations/flask/decorator.py +32 -0
  22. secureapi-0.1.0/secureapi/utils/__init__.py +0 -0
  23. secureapi-0.1.0/secureapi/utils/helpers.py +1 -0
  24. secureapi-0.1.0/secureapi.egg-info/PKG-INFO +21 -0
  25. secureapi-0.1.0/secureapi.egg-info/SOURCES.txt +27 -0
  26. secureapi-0.1.0/secureapi.egg-info/dependency_links.txt +1 -0
  27. secureapi-0.1.0/secureapi.egg-info/requires.txt +11 -0
  28. secureapi-0.1.0/secureapi.egg-info/top_level.txt +1 -0
  29. secureapi-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,5 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge...
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: secureapi
3
+ Version: 0.1.0
4
+ Summary: A package for secure API access control.
5
+ Author-email: Your Name <your.email@example.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: pyyaml
10
+ Provides-Extra: django
11
+ Requires-Dist: django; extra == "django"
12
+ Requires-Dist: djangorestframework; extra == "django"
13
+ Provides-Extra: fastapi
14
+ Requires-Dist: fastapi; extra == "fastapi"
15
+ Provides-Extra: flask
16
+ Requires-Dist: flask; extra == "flask"
17
+ Dynamic: license-file
18
+
19
+ # secureapi
20
+
21
+ Secure API access control library.
@@ -0,0 +1,3 @@
1
+ # secureapi
2
+
3
+ Secure API access control library.
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "secureapi"
7
+ version = "0.1.0"
8
+ description = "A package for secure API access control."
9
+ authors = [
10
+ { name="Your Name", email="your.email@example.com" }
11
+ ]
12
+ readme = "README.md"
13
+ requires-python = ">=3.8"
14
+ dependencies = [
15
+ "pyyaml",
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ django = ["django", "djangorestframework"]
20
+ fastapi = ["fastapi"]
21
+ flask = ["flask"]
22
+
23
+ [tool.setuptools.packages.find]
24
+ where = ["."]
25
+ include = ["secureapi*"]
@@ -0,0 +1 @@
1
+ # secureapi package
File without changes
@@ -0,0 +1,17 @@
1
+ from secureapi.core.engine import SecureEngine
2
+ from secureapi.core.policy import PolicyLoader
3
+
4
+
5
+ _engine = None
6
+
7
+ def get_engine():
8
+ global _engine
9
+
10
+ if _engine is None:
11
+ _engine = SecureEngine(
12
+ policy_loader=PolicyLoader(),
13
+ role_resolver=default_role_resolver,
14
+ resource_resolver=default_resource_resolver,
15
+ )
16
+
17
+ return _engine
File without changes
@@ -0,0 +1,7 @@
1
+ class RequestContext:
2
+ def __init__(self, user, resource, action, resource_id, tenant_id):
3
+ self.user = user
4
+ self.resource = resource
5
+ self.action = action
6
+ self.resource_id = resource_id
7
+ self.tenant_id = tenant_id
@@ -0,0 +1,36 @@
1
+ class SecureEngine:
2
+ def __init__(self, policy_loader, role_resolver, resource_resolver):
3
+ self.policy_loader = policy_loader
4
+ self.role_resolver = role_resolver
5
+ self.resource_resolver = resource_resolver
6
+
7
+ def authorize(self, context):
8
+ user = context.user
9
+ resource = context.resource
10
+ action = context.action
11
+ resource_id = context.resource_id
12
+ tenant_id = context.tenant_id
13
+
14
+ # Step 1: Get role
15
+ role = self.role_resolver(user, tenant_id)
16
+
17
+ # Step 2: Get policy
18
+ allowed_roles = self.policy_loader(resource, action)
19
+
20
+ if role not in allowed_roles:
21
+ raise Exception(f"Role '{role}' not allowed")
22
+
23
+ # Step 3: Fetch object
24
+ obj = self.resource_resolver(resource, resource_id)
25
+
26
+ # Step 4: Tenant check
27
+ if hasattr(obj, "tenant_id") and obj.tenant_id != tenant_id:
28
+ raise Exception("Cross-tenant access denied")
29
+
30
+ # Step 5: Ownership check
31
+ if "owner" in allowed_roles:
32
+ if hasattr(obj, "created_by_id"):
33
+ if obj.created_by_id != user.id and role != "admin":
34
+ raise Exception("Not owner")
35
+
36
+ return True
@@ -0,0 +1 @@
1
+ """Custom exceptions used by the core engine."""
@@ -0,0 +1,9 @@
1
+ import yaml
2
+
3
+ class PolicyLoader:
4
+ def __init__(self, path="secureapi.yaml"):
5
+ with open(path) as f:
6
+ self.policies = yaml.safe_load(f)
7
+
8
+ def __call__(self, resource, action):
9
+ return self.policies.get(resource, {}).get(action, [])
@@ -0,0 +1 @@
1
+ """Validation utilities for secure API rules."""
File without changes
@@ -0,0 +1 @@
1
+ """Django middleware integration."""
@@ -0,0 +1,41 @@
1
+ from rest_framework.permissions import BasePermission
2
+ from secureapi.core.engine import SecureEngine
3
+ from secureapi.core.context import RequestContext
4
+ from secureapi.config.loader import get_engine
5
+
6
+
7
+ class SecurePermission(BasePermission):
8
+ def has_permission(self, request, view):
9
+ return True # allow, actual check in object level
10
+
11
+ def has_object_permission(self, request, view, obj):
12
+ engine = get_engine()
13
+
14
+ resource = view.basename # e.g., "form"
15
+ action = self.map_method(request.method)
16
+
17
+ context = RequestContext(
18
+ user=request.user,
19
+ resource=resource,
20
+ action=action,
21
+ resource_id=obj.id,
22
+ tenant_id=self.get_tenant(request),
23
+ )
24
+
25
+ try:
26
+ engine.authorize(context)
27
+ return True
28
+ except Exception as e:
29
+ return False
30
+
31
+ def map_method(self, method):
32
+ return {
33
+ "GET": "read",
34
+ "POST": "create",
35
+ "PUT": "update",
36
+ "PATCH": "update",
37
+ "DELETE": "delete",
38
+ }.get(method, "read")
39
+
40
+ def get_tenant(self, request):
41
+ return request.headers.get("X-Tenant-ID")
@@ -0,0 +1,23 @@
1
+ from fastapi import Depends, HTTPException
2
+ from secureapi.core.context import RequestContext
3
+ from secureapi.config.loader import get_engine
4
+
5
+
6
+ def secure_dependency(resource, action):
7
+ def wrapper(user=Depends(get_current_user), tenant_id=None, resource_id=None):
8
+ engine = get_engine()
9
+
10
+ context = RequestContext(
11
+ user=user,
12
+ resource=resource,
13
+ action=action,
14
+ resource_id=resource_id,
15
+ tenant_id=tenant_id,
16
+ )
17
+
18
+ try:
19
+ engine.authorize(context)
20
+ except Exception as e:
21
+ raise HTTPException(status_code=403, detail=str(e))
22
+
23
+ return wrapper
@@ -0,0 +1,32 @@
1
+ from functools import wraps
2
+ from flask import request, jsonify
3
+ from secureapi.core.context import RequestContext
4
+ from secureapi.config.loader import get_engine
5
+
6
+
7
+ def secure_endpoint(resource, action):
8
+ def decorator(func):
9
+ @wraps(func)
10
+ def wrapper(*args, **kwargs):
11
+ engine = get_engine()
12
+
13
+ user = request.user
14
+ tenant_id = request.headers.get("X-Tenant-ID")
15
+ resource_id = kwargs.get(f"{resource}_id")
16
+
17
+ context = RequestContext(
18
+ user=user,
19
+ resource=resource,
20
+ action=action,
21
+ resource_id=resource_id,
22
+ tenant_id=tenant_id,
23
+ )
24
+
25
+ try:
26
+ engine.authorize(context)
27
+ except Exception as e:
28
+ return jsonify({"error": str(e)}), 403
29
+
30
+ return func(*args, **kwargs)
31
+ return wrapper
32
+ return decorator
File without changes
@@ -0,0 +1 @@
1
+ """General helper utilities."""
@@ -0,0 +1,21 @@
1
+ Metadata-Version: 2.4
2
+ Name: secureapi
3
+ Version: 0.1.0
4
+ Summary: A package for secure API access control.
5
+ Author-email: Your Name <your.email@example.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: pyyaml
10
+ Provides-Extra: django
11
+ Requires-Dist: django; extra == "django"
12
+ Requires-Dist: djangorestframework; extra == "django"
13
+ Provides-Extra: fastapi
14
+ Requires-Dist: fastapi; extra == "fastapi"
15
+ Provides-Extra: flask
16
+ Requires-Dist: flask; extra == "flask"
17
+ Dynamic: license-file
18
+
19
+ # secureapi
20
+
21
+ Secure API access control library.
@@ -0,0 +1,27 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ secureapi/__init__.py
5
+ secureapi.egg-info/PKG-INFO
6
+ secureapi.egg-info/SOURCES.txt
7
+ secureapi.egg-info/dependency_links.txt
8
+ secureapi.egg-info/requires.txt
9
+ secureapi.egg-info/top_level.txt
10
+ secureapi/config/__init__.py
11
+ secureapi/config/loader.py
12
+ secureapi/core/__init__.py
13
+ secureapi/core/context.py
14
+ secureapi/core/engine.py
15
+ secureapi/core/exceptions.py
16
+ secureapi/core/policy.py
17
+ secureapi/core/validator.py
18
+ secureapi/integrations/__init__.py
19
+ secureapi/integrations/django/__init__.py
20
+ secureapi/integrations/django/middleware.py
21
+ secureapi/integrations/django/permission.py
22
+ secureapi/integrations/fastapi/__init__.py
23
+ secureapi/integrations/fastapi/dependency.py
24
+ secureapi/integrations/flask/__init__.py
25
+ secureapi/integrations/flask/decorator.py
26
+ secureapi/utils/__init__.py
27
+ secureapi/utils/helpers.py
@@ -0,0 +1,11 @@
1
+ pyyaml
2
+
3
+ [django]
4
+ django
5
+ djangorestframework
6
+
7
+ [fastapi]
8
+ fastapi
9
+
10
+ [flask]
11
+ flask
@@ -0,0 +1 @@
1
+ secureapi
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+