awskit 0.0.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.
awskit-0.0.0/PKG-INFO ADDED
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.1
2
+ Name: awskit
3
+ Version: 0.0.0
4
+ Author: André Bienemann
5
+ Author-email: andre.bienemann@gmail.com
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Operating System :: OS Independent
8
+ Classifier: Programming Language :: Python :: 3.8
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Provides-Extra: dev
14
+ Provides-Extra: docs
awskit-0.0.0/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # AWS
2
+
3
+ AWS Docs
4
+
5
+ https://docs.aws.amazon.com/index.html
6
+
7
+ https://docs.aws.amazon.com/IAM/latest/UserGuide/create-signed-request.html
@@ -0,0 +1,5 @@
1
+ from .dynamodb import DynamoDb
2
+ from .sg import SecurityGroup
3
+ from .sqs import Sqs
4
+ from .subnet import Subnet
5
+ from .vpc import Vpc
@@ -0,0 +1,5 @@
1
+ from lib.interface import AwsInterface
2
+
3
+
4
+ class DynamoDb(AwsInterface):
5
+ pass
@@ -0,0 +1,14 @@
1
+ from lib.interface import AwsInterface
2
+
3
+
4
+ class S3(AwsInterface):
5
+
6
+ def __init__(self):
7
+ super().__init__("s3", "2006-03-01")
8
+
9
+ def CreateBucket(self, region: str, **kwargs) -> dict:
10
+ """
11
+ """
12
+
13
+ resp = self.post(region, "CreateBucket", **kwargs)
14
+ return resp["CreateSecurityGroupResponse"]
@@ -0,0 +1,31 @@
1
+ from lib.interface import AwsInterface
2
+
3
+
4
+ class SecurityGroup(AwsInterface):
5
+
6
+ def __init__(self):
7
+ super().__init__("ec2", "2016-11-15")
8
+
9
+ def CreateSecurityGroup(self, region: str, **kwargs) -> dict:
10
+ """
11
+ Given a region and request arguments, creates a security group
12
+ """
13
+
14
+ resp = self.post(region, "CreateSecurityGroup", **kwargs)
15
+ return resp["CreateSecurityGroupResponse"]
16
+
17
+ def DescribeSecurityGroups(self, region: str) -> list:
18
+ """
19
+ Given a region, returns a list of all security groups available in that region
20
+ """
21
+
22
+ resp = self.get(region, "DescribeSecurityGroups")
23
+ return resp["DescribeSecurityGroupsResponse"]
24
+
25
+ def DeleteSecurityGroup(self, region: str, **kwargs) -> dict:
26
+ """
27
+ Given a region and request arguments, deletes a security group
28
+ """
29
+
30
+ resp = self.post(region, "DeleteSecurityGroup", **kwargs)
31
+ return resp["DeleteSecurityGroupResponse"]
@@ -0,0 +1,59 @@
1
+ from lib.interface import AwsInterface
2
+
3
+
4
+ class Sqs(AwsInterface):
5
+
6
+ def __init__(self):
7
+ super().__init__("sqs", "2012-11-05")
8
+
9
+ def CreateQueue(self, region: str, **kwargs) -> dict:
10
+ """
11
+ Given a region and request arguments, creates a queue
12
+
13
+ QueueName
14
+ """
15
+
16
+ resp = self.post(region, "CreateQueue", **kwargs)
17
+ return resp["CreateQueueResponse"]
18
+
19
+ def ListQueues(self, region: str) -> list:
20
+ """
21
+ Given a region, returns a list of all queues available in that region
22
+ """
23
+
24
+ resp = self.get(region, "ListQueues")
25
+ return resp["ListQueuesResponse"]
26
+
27
+ def DeleteQueue(self, region: str, **kwargs) -> dict:
28
+ """
29
+ Given a region and request arguments, deletes a queue
30
+
31
+ QueueUrl
32
+ """
33
+
34
+ resp = self.post(region, "DeleteQueue", **kwargs)
35
+ return resp["DeleteQueueResponse"]
36
+
37
+ def SendMessage(self, region: str, **kwargs) -> dict:
38
+ """
39
+ Given a region and request arguments, sends a message
40
+ """
41
+
42
+ resp = self.post(region, "SendMessage", **kwargs)
43
+ return resp["SendMessageResponse"]
44
+
45
+ def ReceiveMessage(self, region: str, **kwargs) -> dict:
46
+ """
47
+ Given a region and request arguments, receives a message
48
+ """
49
+
50
+ resp = self.post(region, "ReceiveMessage", **kwargs)
51
+ return resp["ReceiveMessageResponse"]
52
+
53
+ def DeleteMessage(self, region: str, **kwargs) -> dict:
54
+ """
55
+ Given a region and request arguments, deletes a message
56
+ """
57
+
58
+ resp = self.post(region, "DeleteMessage", **kwargs)
59
+ return resp["DeleteMessageResponse"]
@@ -0,0 +1,31 @@
1
+ from lib.interface import AwsInterface
2
+
3
+
4
+ class Subnet(AwsInterface):
5
+
6
+ def __init__(self):
7
+ super().__init__("ec2", "2016-11-15")
8
+
9
+ def CreateSubnet(self, region: str, **kwargs) -> dict:
10
+ """
11
+ Given a region and request arguments, creates a subnet
12
+ """
13
+
14
+ resp = self.post(region, "CreateSubnet", **kwargs)
15
+ return resp["CreateSubnetResponse"]
16
+
17
+ def DescribeSubnets(self, region: str) -> list:
18
+ """
19
+ Given a region, returns a list of all subnets available in that region
20
+ """
21
+
22
+ resp = self.get(region, "DescribeSubnets")
23
+ return resp["DescribeSubnetsResponse"]
24
+
25
+ def DeleteSubnet(self, region: str,**kwargs) -> dict:
26
+ """
27
+ Given a region and request arguments, deletes a subnet
28
+ """
29
+
30
+ resp = self.post(region, "DeleteSubnet", **kwargs)
31
+ return resp["DeleteSubnetResponse"]
@@ -0,0 +1,31 @@
1
+ from lib.interface import AwsInterface
2
+
3
+
4
+ class Vpc(AwsInterface):
5
+
6
+ def __init__(self):
7
+ super().__init__("ec2", "2016-11-15")
8
+
9
+ def CreateVpc(self, region: str, **kwargs) -> dict:
10
+ """
11
+ Given a region and request arguments, creates a VPC
12
+ """
13
+
14
+ resp = self.post(region, "CreateVpc", **kwargs)
15
+ return resp["CreateVpcResponse"]
16
+
17
+ def DescribeVpcs(self, region: str) -> list:
18
+ """
19
+ Given a region, returns a list of all VPCs available in that region
20
+ """
21
+
22
+ resp = self.get(region, "DescribeVpcs")
23
+ return resp["DescribeVpcsResponse"]
24
+
25
+ def DeleteVpc(self, region: str,**kwargs) -> dict:
26
+ """
27
+ Given a region and request arguments, deletes a VPC
28
+ """
29
+
30
+ resp = self.post(region, "DeleteVpc", **kwargs)
31
+ return resp["DeleteVpcResponse"]
@@ -0,0 +1,123 @@
1
+ import os
2
+ import datetime
3
+ import hashlib
4
+ import hmac
5
+
6
+ from requests.auth import AuthBase
7
+ from requests.compat import urlparse
8
+
9
+
10
+ class AwsAuth(AuthBase):
11
+ """
12
+ AWS Authentification using AWS Signature Version 4
13
+ """
14
+
15
+ def __init__(self, service: str, region: str):
16
+ """
17
+ Parameters
18
+ service: AWS service name
19
+ region: AWS region name
20
+ """
21
+
22
+ self.service = service
23
+ self.region = region
24
+
25
+ def __call__(self, request):
26
+ """
27
+ Parameters
28
+ request: request to be signed
29
+ """
30
+
31
+ now = datetime.datetime.utcnow()
32
+
33
+ amz_date = now.strftime("%Y%m%dT%H%M%SZ")
34
+ datestamp = now.strftime("%Y%m%d")
35
+
36
+ url = urlparse(request.url)
37
+
38
+ if "Host" not in request.headers:
39
+ request.headers["Host"] = url.hostname
40
+
41
+ if "Content-Type" not in request.headers:
42
+ request.headers["Content-Type"] = (
43
+ "application/x-www-form-urlencoded; charset=utf-8"
44
+ )
45
+
46
+ if request.method == "GET":
47
+ payload_hash = hashlib.sha256("".encode("utf-8")).hexdigest()
48
+ else:
49
+ if request.body:
50
+ if isinstance(request.body, bytes):
51
+ payload_hash = hashlib.sha256(request.body).hexdigest()
52
+ else:
53
+ payload_hash = hashlib.sha256(
54
+ request.body.encode("utf-8")
55
+ ).hexdigest()
56
+ else:
57
+ payload_hash = hashlib.sha256(b"").hexdigest()
58
+
59
+ request.headers["x-amz-content-sha256"] = payload_hash
60
+ request.headers["X-AMZ-Date"] = amz_date
61
+
62
+ headers_to_sign = sorted(
63
+ (
64
+ header
65
+ for header in (header.lower() for header in request.headers.keys())
66
+ if header.startswith("x-amz-") or header == "host"
67
+ )
68
+ )
69
+
70
+ canonical_headers = "".join(
71
+ (f"{header}:{request.headers[header]}\n" for header in headers_to_sign)
72
+ )
73
+
74
+ canonical_query_string = "&".join(
75
+ ("=".join(t) for t in sorted((s.split("=") for s in url.query.split("&"))))
76
+ )
77
+
78
+ signed_headers = ";".join(headers_to_sign)
79
+
80
+ canonical_request = (
81
+ f"{request.method}\n"
82
+ f"{url.path}\n"
83
+ f"{canonical_query_string}\n"
84
+ f"{canonical_headers}\n"
85
+ f"{signed_headers}\n"
86
+ f"{payload_hash}"
87
+ )
88
+
89
+ credential_scope = f"{datestamp}/{self.region}/{self.service}/aws4_request"
90
+
91
+ string_to_sign = (
92
+ "AWS4-HMAC-SHA256\n"
93
+ f"{amz_date}\n"
94
+ f"{credential_scope}\n"
95
+ f"{hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()}"
96
+ ).encode("utf-8")
97
+
98
+ k_key = f"AWS4{os.getenv('AWS_SECRET_ACCESS_KEY')}".encode("utf-8")
99
+ k_date = self.sign_msg(k_key, datestamp)
100
+ k_region = self.sign_msg(k_date, self.region)
101
+ k_service = self.sign_msg(k_region, self.service)
102
+ k_signing = self.sign_msg(k_service, "aws4_request")
103
+ signature = hmac.new(k_signing, string_to_sign, hashlib.sha256).hexdigest()
104
+
105
+ request.headers["Authorization"] = (
106
+ "AWS4-HMAC-SHA256 Credential="
107
+ f"{os.getenv('AWS_ACCESS_KEY_ID')}/{credential_scope}, "
108
+ f"SignedHeaders={signed_headers}, "
109
+ f"Signature={signature}"
110
+ )
111
+
112
+ return request
113
+
114
+ def sign_msg(self, key: str, msg: str) -> str:
115
+ """
116
+ Given a key and a message returns a hash-based message authentication code
117
+
118
+ Parameters
119
+ key: key to be used for encryption
120
+ msg: message to be signed by the key
121
+ """
122
+
123
+ return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()
@@ -0,0 +1,114 @@
1
+ import requests
2
+ import xmltodict
3
+
4
+ from lib.auth import AwsAuth
5
+
6
+
7
+ class AwsInterface:
8
+
9
+ def __init__(self, service, version):
10
+ self.service = service
11
+ self.version = version
12
+
13
+ def post(self, region: str, action: str, **kwargs) -> dict:
14
+ """
15
+ Creates a POST request to AWS API
16
+
17
+ Parameters
18
+ region: geographic location
19
+ action: request action
20
+ """
21
+
22
+ return self._request("POST", region, action, **kwargs)
23
+
24
+ def get(self, region: str, action: str, **kwargs) -> dict:
25
+ """
26
+ Creates a GET request to AWS API
27
+
28
+ Parameters
29
+ region: geographic location
30
+ action: request action
31
+ """
32
+
33
+ return self._request("GET", region, action, **kwargs)
34
+
35
+ def _request(self, method: str, region: str, action: str, **kwargs) -> dict:
36
+ """
37
+ Creates a request to AWS API
38
+
39
+ Parameters
40
+ method: request method
41
+ region: geographic location
42
+ action: request action
43
+ """
44
+
45
+ auth = AwsAuth(self.service, region)
46
+ url = f"https://{self.service}.{region}.amazonaws.com"
47
+
48
+ if method == "GET":
49
+ params = self._params(action, **kwargs)
50
+ response = requests.request(method=method, auth=auth, url=url, params=params)
51
+ return self._parse(response)
52
+
53
+ elif method == "POST":
54
+ data = self._data(action, **kwargs)
55
+ response = requests.request(method=method, auth=auth, url=url, data=data)
56
+ return self._parse(response)
57
+
58
+ def _parse(self, response: requests.Response) -> dict:
59
+ """
60
+ Returns a parsed dictionary
61
+ """
62
+
63
+ data = xmltodict.parse(response.text)
64
+
65
+ if response.status_code != 200:
66
+
67
+ print(data)
68
+
69
+ if "Response" in data:
70
+ raise Exception(
71
+ data["Response"]
72
+ .get("Errors", {})
73
+ .get("Error", {})
74
+ .get("Message", "")
75
+ )
76
+
77
+ elif "ErrorResponse" in data:
78
+ raise Exception(
79
+ data["ErrorResponse"]
80
+ .get("Error", {})
81
+ .get("Message", "")
82
+ )
83
+
84
+ elif "Error" in data:
85
+ raise Exception(
86
+ data["Error"].
87
+ get("Message", "")
88
+ )
89
+
90
+ raise Exception("Failed to parse error message")
91
+
92
+ return data
93
+
94
+ def _data(self, action: str, **kwargs) -> dict:
95
+ """
96
+ Returns data dictionary
97
+ """
98
+
99
+ data = {"Version": self.version, "Action": action}
100
+
101
+ data.update(kwargs)
102
+
103
+ return data
104
+
105
+ def _params(self, action: str, **kwargs) -> str:
106
+ """
107
+ Returns URL query parameters
108
+ """
109
+
110
+ params = [f"Version={self.version}", f"Action={action}"]
111
+
112
+ params.extend([f"{key}={value}" for key, value in kwargs.items()])
113
+
114
+ return "&".join(params)
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.1
2
+ Name: awskit
3
+ Version: 0.0.0
4
+ Author: André Bienemann
5
+ Author-email: andre.bienemann@gmail.com
6
+ Classifier: License :: OSI Approved :: MIT License
7
+ Classifier: Operating System :: OS Independent
8
+ Classifier: Programming Language :: Python :: 3.8
9
+ Classifier: Programming Language :: Python :: 3.9
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Provides-Extra: dev
14
+ Provides-Extra: docs
@@ -0,0 +1,16 @@
1
+ README.md
2
+ setup.py
3
+ awesome/interfaces/__init__.py
4
+ awesome/interfaces/dynamodb.py
5
+ awesome/interfaces/s3.py
6
+ awesome/interfaces/sg.py
7
+ awesome/interfaces/sqs.py
8
+ awesome/interfaces/subnet.py
9
+ awesome/interfaces/vpc.py
10
+ awesome/lib/auth.py
11
+ awesome/lib/interface.py
12
+ awskit.egg-info/PKG-INFO
13
+ awskit.egg-info/SOURCES.txt
14
+ awskit.egg-info/dependency_links.txt
15
+ awskit.egg-info/requires.txt
16
+ awskit.egg-info/top_level.txt
@@ -0,0 +1,11 @@
1
+
2
+ [dev]
3
+ black
4
+ coverage
5
+ isort
6
+ twine
7
+ wheel
8
+
9
+ [docs]
10
+ mkdocs
11
+ mkdocs-material
@@ -0,0 +1 @@
1
+ awesome
awskit-0.0.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
awskit-0.0.0/setup.py ADDED
@@ -0,0 +1,30 @@
1
+ from setuptools import setup
2
+
3
+ setup(
4
+ name="awskit",
5
+ version="0.0.0",
6
+ author="André Bienemann",
7
+ author_email="andre.bienemann@gmail.com",
8
+ extras_require={
9
+ "dev": [
10
+ "black",
11
+ "coverage",
12
+ "isort",
13
+ "twine",
14
+ "wheel",
15
+ ],
16
+ "docs": [
17
+ "mkdocs",
18
+ "mkdocs-material",
19
+ ],
20
+ },
21
+ classifiers=[
22
+ "License :: OSI Approved :: MIT License",
23
+ "Operating System :: OS Independent",
24
+ "Programming Language :: Python :: 3.8",
25
+ "Programming Language :: Python :: 3.9",
26
+ "Programming Language :: Python :: 3.10",
27
+ "Programming Language :: Python :: 3.11",
28
+ "Programming Language :: Python :: 3.12",
29
+ ],
30
+ )