Skip to content

feat(sdk): Adding public key verification on check status #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,10 @@ config = (
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)
# Below is optional parameter
.with_timeout(10)
# Public key is optional, used only for callback signature verification
.with_public_key("SAT_PUBLIC_KEY")
.with_is_debug(True)
)

Expand All @@ -75,11 +74,10 @@ config = (
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)
# Below is optional parameter
.with_timeout(10)
# Public key is optional, used only for callback signature verification
.with_public_key("SAT_PUBLIC_KEY")
# Override SAT Base URL
.with_sat_base_url("https://b2b.tokopedia.com/api")
)
Expand Down Expand Up @@ -113,11 +111,10 @@ config = (
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)
# Below is optional parameter
.with_timeout(10)
# Public key is optional, used only for callback signature verification
.with_public_key("SAT_PUBLIC_KEY")
# Override SAT Base URL
.with_sat_base_url("https://b2b.tokopedia.com/api")
)
Expand Down Expand Up @@ -155,11 +152,10 @@ config = (
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)
# Below is optional parameter
.with_timeout(10)
# Public key is optional, used only for callback signature verification
.with_public_key("SAT_PUBLIC_KEY")
# Override SAT Base URL
.with_sat_base_url("https://b2b.tokopedia.com/api")
)
Expand Down Expand Up @@ -201,11 +197,10 @@ config = (
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)
# Below is optional parameter
.with_timeout(10)
# Public key is optional, used only for callback signature verification
.with_public_key("SAT_PUBLIC_KEY")
# Override SAT Base URL
.with_sat_base_url("https://b2b.tokopedia.com/api")
)
Expand Down Expand Up @@ -254,11 +249,10 @@ config = (
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)
# Below is optional parameter
.with_timeout(10)
# Public key is optional, used only for callback signature verification
.with_public_key("SAT_PUBLIC_KEY")
# Override SAT Base URL
.with_sat_base_url("https://b2b.tokopedia.com/api")
)
Expand All @@ -275,11 +269,10 @@ config = (
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)
# Below is optional parameter
.with_timeout(10)
# Public key is optional, used only for callback signature verification
.with_public_key("SAT_PUBLIC_KEY")
# Override SAT Base URL
.with_sat_base_url("https://b2b.tokopedia.com/api")
)
Expand All @@ -303,7 +296,8 @@ config = SATClientConfig(
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE_KEY", # required
).with_public_key("SAT_PUBLIC_KEY")
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)

sat_client = SATClient(config)

Expand Down Expand Up @@ -354,7 +348,8 @@ config = SATClientConfig(
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE", # required
).with_public_key("SAT_PUBLIC_KEY")
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)

sat_client = SATClient(config)

Expand Down Expand Up @@ -387,7 +382,8 @@ config = SATClientConfig(
client_id="YOUR_CLIENT_ID", # required
client_secret="YOUR_CLIENT_SECRET", # required
private_key="YOUR_PRIVATE", # required
).with_public_key("SAT_PUBLIC_KEY")
sat_public_key="SAT_PUBLIC_KEY", # required !IMPORTANT: This is SAT public key, NOT your public key
)

try:
sat_client = SATClient(config)
Expand Down
25 changes: 18 additions & 7 deletions py_sat/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ class SATClientConfig:
client_id: str
client_secret: str
private_key: str
sat_public_key: str

# Optional
public_key: Optional[str]
padding_type: SignatureType
is_debug: bool
sat_base_url: str
Expand All @@ -49,6 +49,7 @@ def __init__(
client_id: str,
client_secret: str,
private_key: str,
sat_public_key: str,
):
if not client_id or not isinstance(client_id, str):
raise InvalidInputException("Client ID are required and must be a string")
Expand All @@ -61,9 +62,13 @@ def __init__(
if not private_key or not isinstance(private_key, str):
raise InvalidInputException("Private key is required and must be a string")

if not sat_public_key or not isinstance(sat_public_key, str):
raise InvalidInputException("Public key is required and must be a string")

self.client_id = client_id
self.client_secret = client_secret
self.private_key = private_key
self.sat_public_key = sat_public_key

self._set_default_value()

Expand All @@ -73,7 +78,6 @@ def _set_default_value(self):
logger.setLevel(logging.DEBUG)
self.logger = logger

self.public_key = None
self.padding_type = SignatureType.PSS
self.is_debug = False
self.sat_base_url = PLAYGROUND_SAT_BASE_URL
Expand All @@ -84,10 +88,6 @@ def with_logger(self, logger: logging.Logger):
self.logger = logger
return self

def with_public_key(self, public_key: str):
self.public_key = public_key
return self

def with_padding_type(self, padding_type: SignatureType):
self.padding_type = padding_type
return self
Expand Down Expand Up @@ -122,7 +122,7 @@ class SATClient:
def __init__(self, config: SATClientConfig):
self._config = config
self.signature = Signature(
config.private_key, config.public_key, config.padding_type
config.private_key, config.sat_public_key, config.padding_type
)
self._logger = config.logger
self._http_client = HTTPClient(
Expand Down Expand Up @@ -235,7 +235,18 @@ def check_status(self, request_id: str) -> Union[OrderDetail, ErrorResponse]:
response = self._http_client.send_request(http_req)
response.raise_for_status()

signature = response.headers.get("signature")
if not signature:
raise UnauthenticatedException(
"Signature is not present in the header, please check the request"
)

valid = self.signature.verify(response.text, signature)
if not valid:
raise UnauthenticatedException("Signature is not valid")

json_response = response.json()

data = parse_json_api_response(json_response)

return OrderDetail.from_dict(data).with_raw_response(response)
Expand Down
4 changes: 2 additions & 2 deletions py_sat/signature/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ class Signature:
def __init__(
self,
private_key_str: Optional[str],
public_key_str: Optional[str],
sat_public_key_str: Optional[str],
padding_type: SignatureType,
):
if not padding_type:
raise InvalidInputException("Padding type is required")

self._private_key = self._parse_rsa_private_key_from_pem_str(private_key_str)
self._public_key = self._parse_public_key(public_key_str)
self._public_key = self._parse_public_key(sat_public_key_str)
self._algorithm = self.__decide_padding_algorithm(padding_type)

def verify(self, msg: str, signature: str) -> bool:
Expand Down
Loading
Loading