Skip to content

Commit

Permalink
v0.8.0 - Default signing method is now HMAC-SHA256 for REST API and R…
Browse files Browse the repository at this point in the history
…estlet

Fixes #27
  • Loading branch information
jacobsvante committed Apr 28, 2021
1 parent f4e9f52 commit 49e0642
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 18 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Nothing

## [0.7.0](https://github.com/jmagnusson/netsuite/compare/v0.6.3...v0.7.0) - 2021-04-26
## [0.8.0](https://github.com/jmagnusson/netsuite/compare/v0.7.0...v0.8.0) - 2021-04-28

### Changed
- Default signing method is now HMAC-SHA256 for REST API and Restlet. The old default of HMAC-SHA1 can be set via the `signature_method` keyword argument. (Thanks to @zerodarkzone, issue #27)

### Added
- HMAC-SHA256 signing method when making requests to REST API and Restlets
- Dependency `oauthlib`

## [0.7.0](https://github.com/jmagnusson/netsuite/compare/v0.6.3...v0.7.0) - 2021-04-27

This release breaks a lot of things. Please read carefully.

Expand Down
6 changes: 4 additions & 2 deletions netsuite/rest_api.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import logging
from typing import Sequence

from . import rest_api_base
from .config import Config
from .rest_api_base import RestApiBase
from .util import cached_property

logger = logging.getLogger(__name__)

__all__ = ("NetSuiteRestApi",)


class NetSuiteRestApi(RestApiBase):
class NetSuiteRestApi(rest_api_base.RestApiBase):
def __init__(
self,
config: Config,
*,
default_timeout: int = 60,
concurrent_requests: int = 10,
signature_method: str = rest_api_base.DEFAULT_SIGNATURE_METHOD,
):
self._config = config
self._default_timeout = default_timeout
self._concurrent_requests = concurrent_requests
self._signature_method = signature_method

@cached_property
def hostname(self) -> str:
Expand Down
28 changes: 17 additions & 11 deletions netsuite/rest_api_base.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import asyncio
import logging

import httpx
from authlib.integrations.httpx_client import OAuth1Auth
from authlib.oauth1.rfc5849.client_auth import ClientAuth
from authlib.oauth1.rfc5849.signature import generate_signature_base_string
from oauthlib.oauth1.rfc5849.signature import sign_hmac_sha256

from . import json
from .exceptions import NetsuiteAPIRequestError, NetsuiteAPIResponseParsingError
from .util import cached_property

try:
import httpx
except ImportError:
__all__ = ("RestApiBase",)

DEFAULT_SIGNATURE_METHOD = "HMAC-SHA256"

class httpx: # type: ignore[no-redef]
Response = None
logger = logging.getLogger(__name__)


try:
from authlib.integrations.httpx_client import OAuth1Auth
except ImportError:
OAuth1Auth = None
def authlib_hmac_sha256_sign_method(client, request):
"""Sign a HMAC-SHA256 signature."""
base_string = generate_signature_base_string(request)
return sign_hmac_sha256(base_string, client.client_secret, client.token_secret)

__all__ = ("RestApiBase",)

logger = logging.getLogger(__name__)
ClientAuth.register_signature_method("HMAC-SHA256", authlib_hmac_sha256_sign_method)


class RestApiBase:
_concurrent_requests: int = 10
_default_timeout: int = 10
_signature_method: str = DEFAULT_SIGNATURE_METHOD

@cached_property
def _request_semaphore(self) -> asyncio.Semaphore:
Expand Down Expand Up @@ -93,6 +98,7 @@ def _make_auth(self):
token_secret=auth.token_secret,
realm=self._config.account,
force_include_body=True,
signature_method=self._signature_method,
)

def _make_default_headers(self):
Expand Down
6 changes: 4 additions & 2 deletions netsuite/restlet.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import logging

from . import rest_api_base
from .config import Config
from .rest_api_base import RestApiBase
from .util import cached_property

logger = logging.getLogger(__name__)

__all__ = ("NetSuiteRestlet",)


class NetSuiteRestlet(RestApiBase):
class NetSuiteRestlet(rest_api_base.RestApiBase):
def __init__(
self,
config: Config,
*,
default_timeout: int = 60,
concurrent_requests: int = 10,
signature_method: str = rest_api_base.DEFAULT_SIGNATURE_METHOD,
):
self._config = config
self._default_timeout = default_timeout
self._concurrent_requests = concurrent_requests
self._signature_method = signature_method

@cached_property
def hostname(self) -> str:
Expand Down
19 changes: 18 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "netsuite"
version = "0.7.0"
version = "0.8.0"
description = "Make async requests to NetSuite SuiteTalk SOAP/REST Web Services and Restlets"
authors = ["Jacob Magnusson <m@jacobian.se>"]
license = "MIT"
Expand Down Expand Up @@ -29,6 +29,7 @@ pydantic = "^1.8"
orjson = {version = "^3", optional = true}
ipython = {version = "^7", optional = true}
zeep = {version = "^4.0.0", optional = true, extras = ["async"]}
oauthlib = "^3.1.0"

[tool.poetry.extras]
soap_api = ["zeep"]
Expand Down

0 comments on commit 49e0642

Please sign in to comment.