def delete(self): """ Call delete() to remove the Partner from Netki systems. :return: AttrDict for valid, non-error responses. Empty dict for 204 responses. Exception for error responses. """ process_request(self.netki_client, '/v1/admin/partner/' + self.name, 'DELETE')
def revoke(self, reason): """ Call revoke() to add the certificate to the revocation list, effectively invalidating it. :param reason: Provide a reason for revocation, such as private key lost. :return Exception for error responses or required missing data. """ if not self.id: raise ValueError('Missing ID - Order Not Yet Submitted') process_request(self.netki_client, '/v1/certificate/%s' % self.id, 'DELETE', {'revocation_reason': reason})
def submit_csr(self, pkey_obj): """ Call submit_csr() to generate and send a CSR to the API for use when creating the customer's certificate. :param pkey_obj: OpenSSL.crypto.PKEY object used to sign the CSR and be bound to the issued certificate. :return Exception for error responses or required missing data. """ if not self.id: raise ValueError('Missing ID - Order Not Yet Submitted') csr_pem = Certificate.generate_csr(self.customer_data, pkey_obj) process_request(self.netki_client, '/v1/certificate/%s/csr' % self.id, 'POST', {'signed_csr': csr_pem})
def test_certificate_auth_post_method_go_right(self): # Setup Test Case self.netki_client._auth_type = 'certificate' self.netki_client.user_key = self.user_key.to_der().encode('hex') ret_val = process_request(self.netki_client, 'uri', 'POST', self.request_data) # Validate submit_request data self.assertEqual(1, self.mockRequests.request.call_count) call_args = self.mockRequests.request.call_args[1] self.assertEqual(json.dumps(self.request_data), call_args.get('data')) self.assertTrue( # Validate that the Appropriate PK Was Used to Sign the Data self.user_key.get_verifying_key().verify( call_args['headers']['X-Signature'].decode('hex'), self.netki_client.api_url + 'uri' + json.dumps(self.request_data), hashfunc=hashlib.sha256, sigdecode=sigdecode_der ) ) del call_args['headers']['X-Signature'] # Delete sig and Validate Remaining Headers self.assertDictEqual(self.certificate_auth_headers, call_args.get('headers')) self.assertEqual('POST', call_args.get('method')) self.assertEqual('uri', call_args.get('url')) # Validate response self.assertDictEqual(ret_val, self.response_data)
def test_certificate_auth_post_method_go_right(self): # Setup Test Case self.netki_client._auth_type = 'certificate' self.netki_client.user_key = self.user_key.to_der().encode('hex') ret_val = process_request(self.netki_client, 'uri', 'POST', self.request_data) # Validate submit_request data self.assertEqual(1, self.mockRequests.request.call_count) call_args = self.mockRequests.request.call_args[1] self.assertEqual(json.dumps(self.request_data), call_args.get('data')) self.assertTrue( # Validate that the Appropriate PK Was Used to Sign the Data self.user_key.get_verifying_key().verify( call_args['headers']['X-Signature'].decode('hex'), self.netki_client.api_url + 'uri' + json.dumps(self.request_data), hashfunc=hashlib.sha256, sigdecode=sigdecode_der)) del call_args['headers'][ 'X-Signature'] # Delete sig and Validate Remaining Headers self.assertDictEqual(self.certificate_auth_headers, call_args.get('headers')) self.assertEqual('POST', call_args.get('method')) self.assertEqual('uri', call_args.get('url')) # Validate response self.assertDictEqual(ret_val, self.response_data)
def submit_customer_data(self): """ Call submit_customer_data() to submit customer information to the API for validation. A token representing the customer data is stored in the certificate object and used when submitting a certificate order. :return: Exception for error responses including data validation failures. """ if not self.customer_data: raise ValueError('customer_data must be set on Certificate object') post_data = dict() for key, value in self.customer_data.iteritems(): if key == 'partner_name': continue if isinstance(value, datetime): value = value.strftime('%Y-%m-%d') post_data[key] = value post_data['product'] = self.product_id response = process_request(self.netki_client, '/v1/certificate/token', 'POST', post_data) self.data_token = response.get('token')
def submit_certificate_order(self, stripe_token=None): """ Call submit_customer_data() to submit customer information to the API for validation. A token representing the customer data is stored in the certificate object and used when submitting a certificate order. :param stripe_token: If a user is being billed by Netki, submit the stripe_token returned from the Netki widget. :return Exception for error responses or required missing data. """ if self.id: raise Exception('Certificate Order Has Already Been Submitted') if not self.data_token: raise ValueError('Customer Data Submission Not Complete') if not self.customer_data.get('email'): raise ValueError('Email Required in customer_data For Order Submission') if not self.product_id: raise ValueError('Product ID required for Order Submission') post_data = { 'certdata_token': self.data_token, 'email': self.customer_data.get('email'), 'product': self.product_id, 'stripe_token': stripe_token } response = process_request(self.netki_client, '/v1/certificate', 'POST', post_data) self.id = response.get('order_id')
def save(self): """ Commit changes to a WalletName object by submitting them to the API. For new Wallet Names, an id will automatically be generated by the server. Run Netki.create_wallet_name() to create a new WalletName object, then run save() on your WalletName object to submit it to the API. To update a Wallet Name, run Netki.get_wallet_names() to retrieve the Wallet Name object, make your updates, then run save() on the WalletName object to commit changes to the API. """ wallet_data = [] for k in self.wallets.keys(): wallet_data.append({ 'currency': k, 'wallet_address': self.wallets[k] }) wallet_name_data = { 'domain_name': self.domain_name, 'name': self.name, 'wallets': wallet_data, 'external_id': self.external_id } wn_api_data = {'wallet_names': [wallet_name_data]} # If an ID is present it exists in Netki's systems, therefore submit an update if self.id: wallet_name_data['id'] = self.id response = process_request( self.netki_client, '/v1/partner/walletname', 'PUT', wn_api_data ) else: response = process_request( self.netki_client, '/v1/partner/walletname', 'POST', wn_api_data ) for wn in response.wallet_names: if wn.domain_name == self.domain_name and wn.name == self.name: self.id = wn.id
def get_available_products(self): """ Certificate Operation Get all available certificate products associated with your account including tier and pricing information. :return: Dictionary containing product details. """ return process_request(self, '/v1/certificate/products', 'GET').get('products')
def get_account_balance(self): """ Certificate Operation Get available balance for certificate purchases when using Deposit/Retainer billing. :return: Dictionary containing available balance. """ return process_request(self, '/v1/certificate/balance', 'GET').get('available_balance')
def get_ca_bundle(self): """ Certificate Operation Download the root bundle used to validate the certificate chain for Netki issued certificates. :return: Dictionary containing certificate bundle. """ return process_request(self, '/v1/certificate/cacert', 'GET').get('cacerts')
def delete(self): """ To delete a WalletName object, first run Netki.get_wallet_names() to retrieve the Wallet Name from the API, then run delete() on the WalletName object to delete it from Netki systems. """ if not self.id: raise Exception( 'Unable to Delete Object that Does Not Exist Remotely') wn_api_data = { 'wallet_names': [{ 'domain_name': self.domain_name, 'id': self.id }] } process_request(self.netki_client, '/v1/partner/walletname', 'DELETE', wn_api_data)
def get_wallet_names(self, domain_name=None, external_id=None): """ Wallet Name Operation Retrieve Wallet Names from the Netki API. Four options are available for retrieval: * Retrieve all Wallet Names associated with your partner_id by not specifying a domain_name or external_id. * Retrieve all Wallet Names associated with a particular partner domain_name by specifying a domain_name. * Retrieve all Wallet Names associated with a particular external_id by specifying an external_id. * Retrieve all Wallet Names associated with a domain_name and external_id by specifying both domain_name and external_id. :param domain_name: Domain name to which the requested Wallet Names belong. ``partnerdomain.com`` :param external_id: Your unique customer identifier specified when creating a Wallet Name. :return: List of WalletName objects. """ args = [] if domain_name: args.append('domain_name=%s' % domain_name) if external_id: args.append('external_id=%s' % external_id) uri = '/v1/partner/walletname' if args: uri = uri + '?' + '&'.join(args) response = process_request(self, uri, 'GET') if not response.wallet_name_count: return [] # Assemble and return a list of Wallet Name objects from the response data all_wallet_names = [] for wn in response.wallet_names: wallet_name = WalletName( domain_name=wn.domain_name, name=wn.name, external_id=wn.external_id, id=wn.id ) for wallet in wn.wallets: wallet_name.set_currency_address(wallet.currency, wallet.wallet_address) wallet_name.set_netki_client(self) all_wallet_names.append(wallet_name) return all_wallet_names
def save(self): """ Commit changes to a WalletName object by submitting them to the API. For new Wallet Names, an id will automatically be generated by the server. Run Netki.create_wallet_name() to create a new WalletName object, then run save() on your WalletName object to submit it to the API. To update a Wallet Name, run Netki.get_wallet_names() to retrieve the Wallet Name object, make your updates, then run save() on the WalletName object to commit changes to the API. """ wallet_data = [] for k in self.wallets.keys(): wallet_data.append({ 'currency': k, 'wallet_address': self.wallets[k] }) wallet_name_data = { 'domain_name': self.domain_name, 'name': self.name, 'wallets': wallet_data, 'external_id': self.external_id } wn_api_data = {'wallet_names': [wallet_name_data]} # If an ID is present it exists in Netki's systems, therefore submit an update if self.id: wallet_name_data['id'] = self.id response = process_request(self.netki_client, '/v1/partner/walletname', 'PUT', wn_api_data) else: response = process_request(self.netki_client, '/v1/partner/walletname', 'POST', wn_api_data) for wn in response.wallet_names: if wn.domain_name == self.domain_name and wn.name == self.name: self.id = wn.id
def load_status(self): """ Call load_status() to retrieve meta data about the domain. :return: AttrDict for valid, non-error responses. Empty dict for 204 responses. Exception for error responses. """ response = process_request(self.netki_client, '/v1/partner/domain/' + self.name, 'GET') self.status = response.get('status') self.delegation_status = response.get('delegation_status') self.delegation_message = response.get('delegation_message') self.wallet_name_count = response.get('wallet_name_count')
def load_dnssec_details(self): """ Call load_dnssec_details() to retrieve DNSSEC information required for secure DNS setup. :return: AttrDict for valid, non-error responses. Empty dict for 204 responses. Exception for error responses. """ response = process_request(self.netki_client, '/v1/partner/domain/dnssec/' + self.name, 'GET') self.public_key_signing_key = response.get('public_key_signing_key') self.ds_records = response.get('ds_records') self.nameservers = response.get('nameservers') self.next_roll = response.get('next_roll')
def delete(self): """ To delete a WalletName object, first run Netki.get_wallet_names() to retrieve the Wallet Name from the API, then run delete() on the WalletName object to delete it from Netki systems. """ if not self.id: raise Exception('Unable to Delete Object that Does Not Exist Remotely') wn_api_data = { 'wallet_names': [ { 'domain_name': self.domain_name, 'id': self.id } ] } process_request( self.netki_client, '/v1/partner/walletname', 'DELETE', wn_api_data )
def test_api_key_auth_put_method_go_right(self): ret_val = process_request(self.netki_client, 'uri', 'PUT', self.request_data) # Validate submit_request data self.assertEqual(1, self.mockRequests.request.call_count) call_args = self.mockRequests.request.call_args[1] self.assertEqual(json.dumps(self.request_data), call_args.get('data')) self.assertDictEqual(self.api_key_auth_headers, call_args.get('headers')) self.assertEqual('PUT', call_args.get('method')) self.assertEqual('uri', call_args.get('url')) # Validate response self.assertDictEqual(ret_val, self.response_data)
def create_partner(self, partner_name): """ Sub-partner Operation Create a sub-partner. :param partner_name: Partner Name :return: Partner object """ response = process_request(self, '/v1/admin/partner/' + partner_name, 'POST') partner = Partner(id=response.partner.id, name=response.partner.name) partner.set_netki_client(self) return partner
def test_api_key_auth_get_method_go_right(self): del self.api_key_auth_headers['Content-Type'] ret_val = process_request(self.netki_client, 'uri', 'GET') # Validate submit_request data self.assertEqual(1, self.mockRequests.request.call_count) call_args = self.mockRequests.request.call_args[1] self.assertIsNone(call_args.get('data')) self.assertDictEqual(self.api_key_auth_headers, call_args.get('headers')) self.assertEqual('GET', call_args.get('method')) self.assertEqual('uri', call_args.get('url')) # Validate response self.assertDictEqual(ret_val, self.response_data)
def test_delete_non_204_response(self): # Setup Test case self.mockRequests.request.return_value.status_code = 200 del self.api_key_auth_headers['Content-Type'] ret_val = process_request(self.netki_client, 'uri', 'DELETE') # Validate submit_request data self.assertEqual(1, self.mockRequests.request.call_count) call_args = self.mockRequests.request.call_args[1] self.assertIsNone(call_args.get('data')) self.assertDictEqual(self.api_key_auth_headers, call_args.get('headers')) self.assertEqual('DELETE', call_args.get('method')) self.assertEqual('uri', call_args.get('url')) # Validate response self.assertDictEqual(ret_val, self.response_data)
def get_status(self): """ Call get_status() to retrieve the order status. If an order is complete, the certificate bundle will be returned. :return Exception for error responses or required missing data. """ if not self.id: raise ValueError('Missing ID - Order Not Yet Submitted') response = process_request(self.netki_client, '/v1/certificate/%s' % self.id, 'GET') self.order_status = response.get('order_status') self.order_error = response.get('order_error') if response.get('certificate_bundle'): self.bundle['root'] = response['certificate_bundle'].get('root') self.bundle['intermediate'] = response['certificate_bundle'].get('intermediate') self.bundle['certificate'] = response['certificate_bundle'].get('certificate')
def get_partners(self): """ Sub-partner Operation Get all partners (partner and sub-partners) associated with your account. :return: List containing Partner objects """ response = process_request(self, '/v1/admin/partner', 'GET') partner_objects = list() for p in response.partners: partner = Partner(id=p.id, name=p.name) partner_objects.append(partner) partner.set_netki_client(self) return partner_objects
def get_domains(self, domain_name=None): """ Domain Operation Retrieve all domains associated with your partner_id or a specific domain_name if supplied :return: List of Domain objects. """ response = process_request(self, '/api/domain/%s' % domain_name if domain_name else '/api/domain', 'GET') if not response.get('domains'): return [] domain_list = list() for d in response.domains: domain = Domain(d.domain_name) domain.set_netki_client(self) domain_list.append(domain) return domain_list
def create_partner_domain(self, domain_name, sub_partner_id=None): """ Domain Operation Create a partner domain used to offer Wallet Names. :param domain_name: ``partnerdomain.com`` :param (Optional) sub_partner_id: When provided, create a domain_name under the sub_partner_id that you are managing. :return: Domain object with status and information required to complete domain setup. """ post_data = {'partner_id': sub_partner_id} if sub_partner_id else '' response = process_request(self, '/v1/partner/domain/' + domain_name, 'POST', post_data) domain = Domain(response.domain_name) domain.status = response.status domain.nameservers = response.nameservers domain.set_netki_client(self) return domain