def test_init_PrivateKey(): privkey = bitjws.PrivateKey(bitjws.wif_to_privkey(wif)) client = BitJWSSwaggerClient.from_spec(load_file(specurl), 'https://0.0.0.0:8002', privkey=privkey) assert 'coin' in client.swagger_spec.definitions assert 'user' in client.swagger_spec.definitions ckey = client.coin.addCoin.swagger_spec.http_client.authenticator.privkey assert isinstance(ckey, bitjws.PrivateKey) assert bitjws.privkey_to_wif(privkey.private_key) == \ bitjws.privkey_to_wif(ckey.private_key)
def test_payload_expired(): key = bitjws.PrivateKey() print(bitjws.privkey_to_wif(key.private_key)) # expire_after must be greater than 0 or None. with pytest.raises(bitjws.jws.InvalidPayload): bitjws.sign_serialize(key, expire_after=0) ser = bitjws.sign_serialize(key, expire_after=0.01) time.sleep(0.02) with pytest.raises(bitjws.jws.InvalidPayload): # payload expired. bitjws.validate_deserialize(ser) # But the signature can still be verified and the msg decoded # if expiration checks are disabled. h, p = bitjws.validate_deserialize(ser, check_expiration=False) assert h and p # Check with multisig. ser = bitjws.multisig_sign_serialize([key], expire_after=0.01) time.sleep(0.02) with pytest.raises(bitjws.jws.InvalidPayload): # payload expired. bitjws.multisig_validate_deserialize(ser)
def test_bad_signature(): wif = 'L2Ai1TBwKfyPshmqosKRBvJ47qUCDKesfZXh2zLoYoB7NHgdPS6d' key = bitjws.PrivateKey(bitjws.wif_to_privkey(wif)) assert bitjws.privkey_to_wif(key.private_key) == wif ser = bitjws.sign_serialize(key) # Drop the last byte from the signature. ser = ser[:-1] with pytest.raises(bitjws.jws.InvalidMessage): # It will fail to decode as base64 due to padding. bitjws.validate_deserialize(ser) # Drop another byte. ser = ser[:-1] with pytest.raises(bitjws.jws.InvalidMessage): # Although it can be decoded now, the length is incorrect. bitjws.validate_deserialize(ser) # Replace the signature by something that has the correct # length before decoding but becomes invalid after it. dummy = bitjws.base64url_encode(b'a' * 88) ser = ser[:ser.rfind('.')] + '.' + dummy.decode('utf8') with pytest.raises(bitjws.jws.InvalidMessage): # Now it fails because the dummy signature above produces # 66 bytes (instead of 65) after being decoded. bitjws.validate_deserialize(ser)
def from_spec(cls, spec_dict, origin_url=None, http_client=None, privkey=None, **kwargs): """ Build a :class:`SwaggerClient` from swagger api docs :param spec_dict: a dict with a Swagger spec in json-like form :param origin_url: the url used to retrieve the spec_dict :type origin_url: str :param http_client: an HTTP client used to perform requests :type http_client: :class:`bravado.http_client.HttpClient` :param str privkey: The WIF private key to use for bitjws signing """ if privkey is None: privkey = bitjws.PrivateKey() elif isinstance(privkey, str): privkey = bitjws.PrivateKey(bitjws.wif_to_privkey(privkey)) if http_client is None: host = urlparse.urlsplit(origin_url).hostname http_client = BitJWSRequestsClient() private_key = bitjws.privkey_to_wif(privkey.private_key) http_client.set_bitjws_key(host, private_key) return SwaggerClient.from_spec(spec_dict, http_client=http_client, **kwargs)
def test_init_url_PrivateKey(): privkey = bitjws.PrivateKey(bitjws.wif_to_privkey(wif)) url = "http://spec.com/swagger.json" spec = load_file(specurl) httpretty.enable() httpretty.register_uri(httpretty.GET, url, body=json.dumps(spec)) client = BitJWSSwaggerClient.from_url(url, privkey=privkey) assert 'coin' in client.swagger_spec.definitions assert 'user' in client.swagger_spec.definitions ckey = client.coin.addCoin.swagger_spec.http_client.authenticator.privkey assert isinstance(ckey, bitjws.PrivateKey) assert bitjws.privkey_to_wif(privkey.private_key) == bitjws.privkey_to_wif(ckey.private_key) httpretty.disable() httpretty.reset()
def test_invalid_audience(): key = bitjws.PrivateKey() print(bitjws.privkey_to_wif(key.private_key)) ser = bitjws.sign_serialize(key, requrl='https://example.com/api/login') with pytest.raises(bitjws.jws.InvalidPayload): # audience not specified. bitjws.validate_deserialize(ser) with pytest.raises(bitjws.jws.InvalidPayload): # audience does not match. bitjws.validate_deserialize(ser, requrl='https://example.com/api')
def test_invalid_signature_key(): key = bitjws.PrivateKey() print(bitjws.privkey_to_wif(key.private_key)) ser = bitjws.sign_serialize(key) # Decode header. rawheader = ser.rsplit('.')[0] origheader = bitjws.base64url_decode(rawheader.encode('utf8')) header = json.loads(origheader.decode('utf8')) # Modify the key declared to be used in the signature. header['kid'] = '123' ser = _encode_header(header, ser) header, payload = bitjws.validate_deserialize(ser) # If both header or payload are None then it failed to validate # the signature (as expected). assert header is None assert payload is None
def test_invalid_header(): key = bitjws.PrivateKey() print(bitjws.privkey_to_wif(key.private_key)) ser = bitjws.sign_serialize(key) # Decode header. rawheader = ser.split('.')[0] origheader = bitjws.base64url_decode(rawheader.encode('utf8')) header = json.loads(origheader.decode('utf8')) # Modify the algorithm specified (by removing it). algorithm = header.pop('alg') # Encode header and try to deserialize. ser = _encode_header(header, ser) with pytest.raises(bitjws.jws.InvalidMessage): # Unknown algorithm. bitjws.validate_deserialize(ser) # Set some other algorithm. header['alg'] = 'SHA256' ser = _encode_header(header, ser) with pytest.raises(bitjws.jws.InvalidMessage): # Unknown algorithm. bitjws.validate_deserialize(ser) # Drop the key used to sign. header['alg'] = algorithm kid = header.pop('kid') ser = _encode_header(header, ser) with pytest.raises(bitjws.jws.InvalidMessage): # No address specified. bitjws.validate_deserialize(ser) # Try to decode the original one. ser = rawheader + '.' + ser.split('.', 1)[1] header, payload = bitjws.validate_deserialize(ser) assert header is not None assert payload is not None h, p = bitjws.validate_deserialize(ser, check_expiration=False) assert h == header assert p == payload
def test_malformed(): key = bitjws.PrivateKey() print(bitjws.privkey_to_wif(key.private_key)) ser = bitjws.sign_serialize(key) # Drop one of the segments. ser = ser.split('.', 1)[1] with pytest.raises(bitjws.jws.InvalidMessage): bitjws.validate_deserialize(ser) # Add an empty segment. ser = '.' + ser with pytest.raises(bitjws.jws.InvalidMessage): bitjws.validate_deserialize(ser) # Add an invalid segment. ser = ' ' + ser with pytest.raises(bitjws.jws.InvalidMessage): # This will fail while trying to parse it as JSON. bitjws.validate_deserialize(ser)
def from_url(cls, spec_url, http_client=None, privkey=None, **kwargs): """ Build a :class:`SwaggerClient` from a url to the Swagger specification for a RESTful API. :param spec_url: url pointing at the swagger API specification :type spec_url: str :param http_client: an HTTP client used to perform requests :type http_client: :class:`bravado.http_client.HttpClient` """ if privkey is None: privkey = bitjws.PrivateKey() elif isinstance(privkey, str): privkey = bitjws.PrivateKey(bitjws.wif_to_privkey(privkey)) if http_client is None: host = urlparse.urlsplit(spec_url).hostname http_client = BitJWSRequestsClient() private_key = bitjws.privkey_to_wif(privkey.private_key) http_client.set_bitjws_key(host, private_key) return SwaggerClient.from_url(spec_url, http_client=http_client, **kwargs)
# Install requirements: pip install requests import requests import bitjws # Load existing private key. In this example the server always # create a new private key while the client loads an existing one. wif = "KxZUqanyzZEGptbauar66cQo8bfGHwDauHogkxCaqTeMGY1stH6E" priv = bitjws.wif_to_privkey(wif) privkey = bitjws.PrivateKey(priv) assert wif == bitjws.privkey_to_wif(privkey.private_key) # The resulting bitcoin address can be derived for debugging # purposes. my_pubkey = privkey.pubkey.serialize() my_address = bitjws.pubkey_to_addr(my_pubkey) assert my_address == "1G9sChbyDSmuAXNVpjuRwakTmcHdxKGqpp" print("My WIF key: {}".format(wif)) print("My key address: {}".format(my_address)) # Prepare a request to be sent. This one uses a single custom # parameter named 'echo'. echo_msg = 'hello' data = bitjws.sign_serialize(privkey, echo=echo_msg) # Send and receive signed requests. resp = requests.post('http://localhost:8001/', data=data) headers, payload = bitjws.validate_deserialize(resp.content.decode('utf8')) print(headers) # headers['kid'] contains the key used by the server. print(payload) # In this example the server returns a response containing the # echo parameter specified earlier and also a param named 'address'. assert payload['echo'] == echo_msg
def test_init_WIF(): app = Flask(__name__) fbj = FlaskBitjws(app, privkey=wif) assert wif == bitjws.privkey_to_wif(app.bitjws._privkey.private_key)
def test_init_PrivateKey(): privkey = bitjws.PrivateKey(bitjws.wif_to_privkey(wif)) app = Flask(__name__) fbj = FlaskBitjws(app, privkey=privkey) assert wif == bitjws.privkey_to_wif(app.bitjws._privkey.private_key)
# Install requirements: pip install flask flask-login import flask from flask.ext import login import bitjws # Server key used to sign responses. The client can optionally # check that the response was signed by a key it knows to belong # to this server. privkey = bitjws.PrivateKey() print("Server WIF key: {}".format(bitjws.privkey_to_wif(privkey.private_key))) print("Server key address: {}".format( bitjws.pubkey_to_addr(privkey.pubkey.serialize()))) # Setup flask app with flask-login. app = flask.Flask(__name__) login_manager = login.LoginManager() login_manager.init_app(app) # Dummy User. class User(login.UserMixin): def __init__(self, address): self.id = address # Custom request authentication based on bitjws. @login_manager.request_loader def load_user_from_request(request): header, payload = bitjws.validate_deserialize(request.data.decode('utf8')) if header is None: # Validation failed. return None
# Install requirements: pip install flask flask-login import flask from flask.ext import login import bitjws # Server key used to sign responses. The client can optionally # check that the response was signed by a key it knows to belong # to this server. privkey = bitjws.PrivateKey() print("Server WIF key: {}".format(bitjws.privkey_to_wif(privkey.private_key))) print("Server key address: {}".format( bitjws.pubkey_to_addr(privkey.pubkey.serialize()))) # Setup flask app with flask-login. app = flask.Flask(__name__) login_manager = login.LoginManager() login_manager.init_app(app) # Dummy User. class User(login.UserMixin): def __init__(self, address): self.id = address # Custom request authentication based on bitjws. @login_manager.request_loader def load_user_from_request(request): header, payload = bitjws.validate_deserialize(request.data.decode('utf8')) if header is None: # Validation failed.
# Install requirements: pip install requests import requests import bitjws # Load existing private key. In this example the server always # create a new private key while the client loads an existing one. wif = "KxZUqanyzZEGptbauar66cQo8bfGHwDauHogkxCaqTeMGY1stH6E" priv = bitjws.wif_to_privkey(wif) privkey = bitjws.PrivateKey(priv) assert wif == bitjws.privkey_to_wif(privkey.private_key) # The resulting bitcoin address can be derived for debugging # purposes. my_pubkey = privkey.pubkey.serialize() my_address = bitjws.pubkey_to_addr(my_pubkey) assert my_address == "1G9sChbyDSmuAXNVpjuRwakTmcHdxKGqpp" print("My WIF key: {}".format(wif)) print("My key address: {}".format(my_address)) # Prepare a request to be sent. This one uses a single custom # parameter named 'echo'. echo_msg = "hello" data = bitjws.sign_serialize(privkey, echo=echo_msg) # Send and receive signed requests. resp = requests.post("http://localhost:8001/", data=data) headers, payload = bitjws.validate_deserialize(resp.content.decode("utf8")) print(headers) # headers['kid'] contains the key used by the server. print(payload) # In this example the server returns a response containing the # echo parameter specified earlier and also a param named 'address'. assert payload["echo"] == echo_msg