Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

Feature/aes signature #50

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Next Next commit
add files
  • Loading branch information
YoungWing committed Nov 7, 2022
commit 04b70462da4123895378cef56722fa2082520329
2 changes: 2 additions & 0 deletions aftership/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@
__version__ = '1.3.0'

api_key = None

api_secret = None
133 changes: 132 additions & 1 deletion aftership/const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,135 @@
API_KEY_FILED_NAME = 'aftership-api-key'
AS_API_KEY = 'as-api-key'
YoungWing marked this conversation as resolved.
Show resolved Hide resolved
AS_SIGNATURE_HMAC_SHA256 = 'as-signature-hmac-sha256'
AS_SIGNATURE_RSA_SHA256 = 'as-signature-rsa-sha256'

CONTENT_TYPE = "application/json"

API_VERSION = "v4"
API_ENDPOINT = "https://api.aftership.com/v4/"
API_ENDPOINT = "https://api.aftership.com/"

SIGNATURE_AES_HMAC_SHA256 = "AES-HMAC-SHA256"
SIGNATURE_RSA_HMAC_SHA256 = "RSA-HMAC-SHA256"


## guoqing test-rsa-guo-test-pro-key
RSA_PUBLIC_KEY22 = '''-----BEGIN RSA PUBLIC KEY-----
MIIBigKCAYEA2/A9bczEZ/e5K8TRp+olj9Xm4yecI2IGDMVRIBHQiKhFQBilI8SG
/YMDwNVarW7LOgQEnU7FE86TKMKN72JZU3+uP04+6m9emWlp7B3MHltREmoLufLR
MZGCUe0HCQqzy7hu5gV2ZVzFeuFUTagkeEgcl0K1NWmFMSGc4O32PwmJzToFZ9Ih
BSLHfdhGT62I0yohA6B+O5BuAQ3jMtRbDfL7uxMg4eK3QLawqkyMHfUzYYsXbxO6
GCmHKIx7kNfbjEcxMhlihOJBc8NpUyRF5YDvYgAuqjYC+visb54gFfKdFeIIB0NH
Gh4698h3F3mGGUa15SWIykINW3bqF7FzBlLJUjK3waaPbqR8rWiG+xSkM6xDktpZ
cvDKPHSd3+2iYuvYPyy3gYo33VWB3ynVozrul0oIVCRHcviOWVPS/VCRbgQonAAb
ymkDXhkC+lt2Jqxy397xG5sqMihPnYtMu2kde5HZWoYX5XXkbIUCIBX2ltaljIRJ
KYa7wI7szvITAgMBAAE=
-----END RSA PUBLIC KEY-----'''

## guoqing test-rsa-guo-test-pro-key
RSA_PRIVATE_KEY22 = '''-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----'''

## test-rsa-openssl-py
RSA_PUBLIC_KEY = '''-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3sAihz8uMxNboiUOncS5
H/EZeLzh5g6J2BBfWKxkvxmhCAUifoxH2CkE2Vx+e8kx3AigVhZ/nrrSls4oMBf2
LTz4M+o4Ldg0/6hBJ3g2kFAAEh+FJ8M7UM/g2VS0P0fDmZPl6Z9OAksF16UdvdoE
0sAtlIBbKD/wpDr/akLE2ExGgLi6jEj4DmRQHAQSbRjRQarPheQhcb8a7Syo31Nv
RLtwDUUvroh43lZPb1cA7MBrCSoKi5WzoylJdc4hiA2fPtqv+rT5FOkWy1Ydc7s9
IZrTVAkD5oqd56t5TMdFWeNPm4OSsYNWngOpTK6XUeaJnBkD+PzJoZ+kcyUj/9Ny
ZQIDAQAB
-----END PUBLIC KEY-----'''

RSA_PRIVATE_KEY22 = '''-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDewCKHPy4zE1ui
JQ6dxLkf8Rl4vOHmDonYEF9YrGS/GaEIBSJ+jEfYKQTZXH57yTHcCKBWFn+eutKW
zigwF/YtPPgz6jgt2DT/qEEneDaQUAASH4UnwztQz+DZVLQ/R8OZk+Xpn04CSwXX
pR292gTSwC2UgFsoP/CkOv9qQsTYTEaAuLqMSPgOZFAcBBJtGNFBqs+F5CFxvxrt
LKjfU29Eu3ANRS+uiHjeVk9vVwDswGsJKgqLlbOjKUl1ziGIDZ8+2q/6tPkU6RbL
Vh1zuz0hmtNUCQPmip3nq3lMx0VZ40+bg5Kxg1aeA6lMrpdR5omcGQP4/Mmhn6Rz
JSP/03JlAgMBAAECggEAWaGQg0F+EplQfv9QUVWudFbsu/OtJohlGScFZsX/yBHF
BVgjmC5UXnuq8tfQIXlE8dgaxGlLMxDT2lDcRPXvXiaxbRprPq9ILDOE/B/YPNuk
G6bJSsW5YXw0at81pFz5LRwhII+0sSGFGU/clt9an38rGB1KEPkhmMQQsK5rTOks
Bv4X2V/MBvN/JSqcIls7Yb+op0OULS5KaODGfMlGlfQM9GdrHUkxt9LY51vI57be
SuECiLbaXSXCuRobHqa0B7yk43KWgb/718VhJprctOAKZgAGRXfPE4O2CoVZ8co0
gbbVvPHwEAOSq8YSeuXKWQNWL2yvsNu+Bxa/vq8wRQKBgQD4MKrtzrtjRf0WMuGK
N/Ol55nw36wL8NGS/N2CuvYQwKfoLQfSBhGDjvuX08OlNPvRlqpDTy4IqemsMNeq
tQSLGhdOjEvDbYMBacJKXFxYUiiGB0Dm5onXOVeww9oCklSilJWulEdery0Zkyi0
9s1q17hrX3hU3HhtywVfUgGIYwKBgQDlwojsWA2wXVohMsUI8NuvYrISHrLBTUxS
AF+eilYEVGzQETOOXTfC8lSQspD6Myd4uawtTgBKX3p2mHM2/UPwbMmMb2p7UoKt
LA6eABnyeLYT91ww3eO+t7J8UWewYxT1bWjQf0jUvkY9uJB9/6ZLwRHxY1SlGWHR
0MMtsSQAlwKBgGkKZ/1X5pUgdPnlNPGDtrn7qHp6n9054ej83l9K84Oplia8kDfC
W707UZ4zgPU11HIi+xKbu1btWrmGvnBARpj8xOp4lEQ04CJD+XfxWSAEPaRkA4L2
BVayrTth2K4H8owQqL0HgqE/MK5HSw4z+kKC5EmFUW9RFCMbrr1l/sITAoGAU2Do
XZSKyzDlb1zEQj1eC+SuKIM5bYrGoo9+I8Oh+YpFvrAvXH+Zp8ZXR/d1Q0bjER2Y
TQyccGD7ySQD07XPPOXNsogQRVapE30EhPQWdna15MMEkrtDVcfGHvVPwqQCTBp7
SgaXAJVYWjerP/5Rc/ZJs6bPZeazJ/gxjFhXb1sCgYEAg0DrENWlxMiaJt+mXxMw
vO66ZEnlEG0ra4UKYtNpzx1WXR3tz50CCOthszlKtZhiWBW3sMG/fPQOPBqUwMM3
K1yoOw6Rdx2QuA+ncQEZgcBCvTBmYIVO2P+9FqF4xXfXQuR8BL0i6cx2nHbfHmB5
JG1hQUS78CEeBVgCNKPkUV0=
-----END PRIVATE KEY-----'''

RSA_PRIVATE_KEY = '''-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA3sAihz8uMxNboiUOncS5H/EZeLzh5g6J2BBfWKxkvxmhCAUi
foxH2CkE2Vx+e8kx3AigVhZ/nrrSls4oMBf2LTz4M+o4Ldg0/6hBJ3g2kFAAEh+F
J8M7UM/g2VS0P0fDmZPl6Z9OAksF16UdvdoE0sAtlIBbKD/wpDr/akLE2ExGgLi6
jEj4DmRQHAQSbRjRQarPheQhcb8a7Syo31NvRLtwDUUvroh43lZPb1cA7MBrCSoK
i5WzoylJdc4hiA2fPtqv+rT5FOkWy1Ydc7s9IZrTVAkD5oqd56t5TMdFWeNPm4OS
sYNWngOpTK6XUeaJnBkD+PzJoZ+kcyUj/9NyZQIDAQABAoIBAFmhkINBfhKZUH7/
UFFVrnRW7LvzrSaIZRknBWbF/8gRxQVYI5guVF57qvLX0CF5RPHYGsRpSzMQ09pQ
3ET1714msW0aaz6vSCwzhPwf2DzbpBumyUrFuWF8NGrfNaRc+S0cISCPtLEhhRlP
3JbfWp9/KxgdShD5IZjEELCua0zpLAb+F9lfzAbzfyUqnCJbO2G/qKdDlC0uSmjg
xnzJRpX0DPRnax1JMbfS2OdbyOe23krhAoi22l0lwrkaGx6mtAe8pONyloG/+9fF
YSaa3LTgCmYABkV3zxODtgqFWfHKNIG21bzx8BADkqvGEnrlylkDVi9sr7DbvgcW
v76vMEUCgYEA+DCq7c67Y0X9FjLhijfzpeeZ8N+sC/DRkvzdgrr2EMCn6C0H0gYR
g477l9PDpTT70ZaqQ08uCKnprDDXqrUEixoXToxLw22DAWnCSlxcWFIohgdA5uaJ
1zlXsMPaApJUopSVrpRHXq8tGZMotPbNate4a194VNx4bcsFX1IBiGMCgYEA5cKI
7FgNsF1aITLFCPDbr2KyEh6ywU1MUgBfnopWBFRs0BEzjl03wvJUkLKQ+jMneLms
LU4ASl96dphzNv1D8GzJjG9qe1KCrSwOngAZ8ni2E/dcMN3jvreyfFFnsGMU9W1o
0H9I1L5GPbiQff+mS8ER8WNUpRlh0dDDLbEkAJcCgYBpCmf9V+aVIHT55TTxg7a5
+6h6ep/dOeHo/N5fSvODqZYmvJA3wlu9O1GeM4D1NdRyIvsSm7tW7Vq5hr5wQEaY
/MTqeJRENOAiQ/l38VkgBD2kZAOC9gVWsq07YdiuB/KMEKi9B4KhPzCuR0sOM/pC
guRJhVFvURQjG669Zf7CEwKBgFNg6F2Uissw5W9cxEI9XgvkriiDOW2KxqKPfiPD
ofmKRb6wL1x/mafGV0f3dUNG4xEdmE0MnHBg+8kkA9O1zzzlzbKIEEVWqRN9BIT0
FnZ2teTDBJK7Q1XHxh71T8KkAkwae0oGlwCVWFo3qz/+UXP2SbOmz2Xmsyf4MYxY
V29bAoGBAINA6xDVpcTImibfpl8TMLzuumRJ5RBtK2uFCmLTac8dVl0d7c+dAgjr
YbM5SrWYYlgVt7DBv3z0DjwalMDDNytcqDsOkXcdkLgPp3EBGYHAQr0wZmCFTtj/
vRaheMV310LkfAS9IunMdpx23x5geSRtYUFEu/AhHgVYAjSj5FFd
-----END RSA PRIVATE KEY-----'''
5 changes: 5 additions & 0 deletions aftership/courier.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from .request import make_request
from .response import process_response
import json

__all__ = ['list_couriers', 'list_all_couriers', 'detect_courier']

Expand All @@ -24,3 +25,7 @@ def detect_courier(tracking, **kwargs):
"""
response = make_request('POST', 'couriers/detect', json=dict(tracking=tracking), **kwargs)
return process_response(response)

def post_orders(order, **kwargs):
response = make_request('POST', 'commerce/v1/orders', json=dict(order=json.loads(order)), **kwargs)
return process_response(response)
16 changes: 16 additions & 0 deletions aftership/hmac/hmac.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# coding=utf-8

import os
import hashlib
import base64
import hmac

class Hmac():
def __init__(self, api_secret):
self.api_secret = api_secret

def hmac_signature(self, sign_string: str) -> str:
if self.api_secret is None:
self.api_secret = os.getenv('AFTERSHIP_API_SECRET')
signature_str = hmac.new(bytes(self.api_secret.encode()), msg=bytes(sign_string.encode()), digestmod=hashlib.sha256).digest()
return base64.b64encode(signature_str).decode()
99 changes: 96 additions & 3 deletions aftership/request.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import requests
from urllib.parse import urljoin
from urllib.parse import urlparse
from aftership.hmac.hmac import Hmac
from aftership.rsa.rsa import Rsa

import requests
from aftership.signstring.signstring import SignString

from .const import API_KEY_FILED_NAME, API_ENDPOINT
from .util import get_api_key
from .const import API_KEY_FILED_NAME, API_ENDPOINT, AS_SIGNATURE_HMAC_SHA256, AS_SIGNATURE_RSA_SHA256, AS_API_KEY, CONTENT_TYPE, SIGNATURE_AES_HMAC_SHA256, SIGNATURE_RSA_HMAC_SHA256
from .util import get_api_key, get_api_secret


def build_request_url(path):
Expand All @@ -12,9 +16,98 @@ def build_request_url(path):

def make_request(method, path, **kwargs):
url = build_request_url(path)
res = urlparse(url)
path = res.path
if len(res.params)>0:
path = '{}?{}'.format(res.path, res.params)

signature_type = kwargs.pop('signature_type', None)
if signature_type is None:
return request_with_token(method, url, **kwargs)

body = kwargs.get('json', None)
content_type = None
if (method == "POST" or method == "PUT") and body is not None:
content_type = CONTENT_TYPE

res = urlparse(url)
path = res.path
if len(res.params)>0:
path = '{}?{}'.format(res.path, res.params)

# if using SignString, you must use AS_API_KEY header
if signature_type == SIGNATURE_AES_HMAC_SHA256:
return request_with_aes_hmac256_signature(method, url, path, content_type, **kwargs)

if signature_type == SIGNATURE_RSA_HMAC_SHA256:
return request_with_rsa_hmac256_signature(method, url, path, content_type, **kwargs)

return None


def request_with_token(method, url, **kwargs):
headers = kwargs.pop('headers', dict())
if headers.get(API_KEY_FILED_NAME) is None:
headers[API_KEY_FILED_NAME] = get_api_key()
elif headers.get(AS_API_KEY) is None:
YoungWing marked this conversation as resolved.
Show resolved Hide resolved
headers[AS_API_KEY] = get_api_key()

kwargs['headers'] = headers
return requests.request(method, url, **kwargs)

def request_with_aes_hmac256_signature(method, url, path, content_type, **kwargs):
headers = kwargs.pop('headers', dict())
if headers.get(AS_API_KEY, None) is None:
headers[AS_API_KEY] = get_api_key()

headers['as-store-id'] = 'dyson-production-sandbox-store'

body = kwargs.get('json', None)
date, sign_string = gen_sign_string(method, path, body, headers, content_type)

print("aes_private_key========", get_api_secret())
print('sign_string=====', sign_string)


hmac = Hmac(get_api_secret())
hmac_signature = hmac.hmac_signature(sign_string)
print('hmac_signature=====', hmac_signature)

headers[AS_SIGNATURE_HMAC_SHA256] = hmac_signature
headers['Date'] = date

if content_type is not None:
headers["Content-Type"] = content_type

kwargs['headers'] = headers
return requests.request(method, url, **kwargs)


def request_with_rsa_hmac256_signature(method, url, path, content_type, **kwargs):
headers = kwargs.pop('headers', dict())
if headers.get(AS_API_KEY, None) is None:
headers[AS_API_KEY] = get_api_key()

body = kwargs.get('json', None)
rsa_private_key = kwargs.pop('rsa_private_key', None)
if rsa_private_key is None:
return None

date, sign_string = gen_sign_string(method, path, body, headers, content_type)
sign_string = 'abc'
# sign_string = 'abc'
print("rsa_private_key========", rsa_private_key)
rsa = Rsa(rsa_private_key)
rsa_signature = rsa.rsa_signature(sign_string)
print('rsa_signature=====', rsa_signature)
headers[AS_SIGNATURE_RSA_SHA256] = rsa_signature
headers['Date'] = date
kwargs['headers'] = headers
if content_type is not None:
headers["Content-Type"] = content_type
rsa.verify(sign_string, rsa_signature)
return requests.request(method, url, **kwargs)

def gen_sign_string(method, path, body, headers, content_type):
s = SignString(headers[AS_API_KEY])
return s.gen_sign_string(method, path, body, headers, content_type)
2 changes: 1 addition & 1 deletion aftership/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def process_response(response):
json_content = response.json()
except json.JSONDecodeError:
raise InternalError

if response.status_code // 100 == 2:
return json_content['data']

Expand Down
72 changes: 72 additions & 0 deletions aftership/signstring/signstring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# coding=utf-8

import os
import hashlib
import urllib
import time
import json
from urllib import parse
from typing import Union,Text,Dict
from aftership.const import API_KEY_FILED_NAME, API_ENDPOINT, AS_SIGNATURE_HMAC_SHA256, AS_SIGNATURE_RSA_SHA256, AS_API_KEY

BODY = Union[Text,Dict]

class SignString():
def __init__(self, api_secret:str):
self.api_secret = api_secret

def _gen_sign_string(self, method: str, body:BODY, content_type: str, date: str, canonicalized_as_headers: str,
canonicalized_resource: str) -> str:
result = ''
result += method + '\n'
if body:
if isinstance(body, dict):
body = json.dumps(body)
body = hashlib.md5(body.encode()).hexdigest().upper()
else:
body = ''
content_type = ''

result += body + '\n'
result += content_type + '\n'
result += date + '\n'
result += canonicalized_as_headers + '\n'
result += canonicalized_resource

return result

def _get_canonicalized_as_headers(self, headers: dict) -> str:
new_header = {}
for k, v in headers.items():
new_key = k.lower()
new_value = v.strip()
new_header.update({new_key: new_value})

new_header = dict(sorted(new_header.items()))

result = '\n'.join([k + ':' + v for k, v in new_header.items()])
return result

def _get_canonicalized_resource(self, raw_url: str) -> str:
url_parse_result = parse.urlsplit(raw_url)
path = url_parse_result.path
query = urllib.parse.urlencode(sorted(dict(parse.parse_qsl(url_parse_result.query)).items()))
if query:
path = path + '?' + query

return path

def gen_sign_string(self, method: str, uri: str, body: str, as_header: dict, content_type: str) -> tuple:
if self.api_secret is None:
self.api_secret = os.getenv('AFTERSHIP_API_SECRET')

canonicalized_as_headers = self._get_canonicalized_as_headers(as_header)
canonicalized_resource = self._get_canonicalized_resource(uri)

date = time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime())
# date = "Tue, 29 Jun 2021 07:55:55 GMT"
YoungWing marked this conversation as resolved.
Show resolved Hide resolved
sign_string = self._gen_sign_string(method=method, body=body, content_type=content_type, date=date,
canonicalized_as_headers=canonicalized_as_headers,
canonicalized_resource=canonicalized_resource)

return date, sign_string
6 changes: 6 additions & 0 deletions aftership/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ def get_api_key():
if aftership.api_key is not None:
return aftership.api_key
return os.getenv('AFTERSHIP_API_KEY')

def get_api_secret():
"""Get AfterShip API secret"""
if aftership.api_secret is not None:
return aftership.api_secret
return os.getenv('AFTERSHIP_API_SECRET')
Loading