-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d781a68
commit 36db6e7
Showing
9 changed files
with
269 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
class Device(object): | ||
"""Device. | ||
:param id: Unique identifier for the device. | ||
:type id: str | ||
:param name: The name of the device. | ||
:type name: str | ||
""" | ||
|
||
def __init__(self, data=None): | ||
if data is None: | ||
data = {} | ||
|
||
self.id = data.get('id', None) | ||
self.name = data.get('name', None) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
class DeviceCreateOptions(object): | ||
"""DeviceCreateOptions. | ||
:param name: A name used to identify the device. | ||
:type name: str | ||
:param shared_secret: The base32-encoded shared secret for this device. | ||
:type shared_secret: str | ||
""" | ||
|
||
def __init__(self, data=None): | ||
if data is None: | ||
data = {} | ||
|
||
self.name = data.get('name', None) | ||
self.shared_secret = data.get('shared_secret', None) | ||
|
||
def to_json(self): | ||
return { | ||
'name': self.name, | ||
'sharedSecret': self.shared_secret | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
class DeviceListResult(object): | ||
"""The result of a device listing request. | ||
:param items: The individual devices forming the result. | ||
:type items: list[~mailosaur.models.Device] | ||
""" | ||
|
||
def __init__(self, data=None): | ||
if data is None: | ||
data = {} | ||
|
||
self.items = data.get('items', None) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import dateutil.parser | ||
|
||
|
||
class OtpResult(object): | ||
"""OtpResult. | ||
:param code: The current one-time password. | ||
:type code: str | ||
:param expires: The expiry date/time of the current one-time password. | ||
:type expires: datetime | ||
""" | ||
|
||
def __init__(self, data=None): | ||
if data is None: | ||
data = {} | ||
|
||
self.code = data.get('code', None) | ||
self.expires = dateutil.parser.parse(data.get('expires', None)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
import os | ||
import random | ||
import string | ||
|
||
from mailosaur.models.otp_result import OtpResult | ||
from ..models import DeviceListResult | ||
from ..models import Device | ||
from ..models import OtpResult | ||
from ..models import MailosaurException | ||
|
||
|
||
class DevicesOperations(object): | ||
"""DevicesOperations operations. | ||
""" | ||
|
||
def __init__(self, session, base_url, handle_http_error): | ||
self.session = session | ||
self.base_url = base_url | ||
self.handle_http_error = handle_http_error | ||
|
||
def generate_email_address(self, server): | ||
host = os.getenv('MAILOSAUR_SMTP_HOST', 'mailosaur.net') | ||
randomString = ''.join(random.choice( | ||
string.ascii_uppercase + string.digits) for _ in range(10)) | ||
return "%s@%s.%s" % (randomString, server, host) | ||
|
||
def list(self): | ||
"""List all devices. | ||
Returns a list of your virtual security devices. | ||
:return: DeviceListResult | ||
:rtype: ~mailosaur.models.DeviceListResult | ||
:raises: | ||
:class:`MailosaurException<mailosaur.models.MailosaurException>` | ||
""" | ||
url = "%sapi/devices" % (self.base_url) | ||
response = self.session.get(url) | ||
|
||
if response.status_code not in [200]: | ||
self.handle_http_error(response) | ||
return | ||
|
||
data = response.json() | ||
|
||
return DeviceListResult(data) | ||
|
||
def create(self, device_create_options): | ||
"""Create a device. | ||
Creates a new virtual security device and returns it. | ||
:param device_create_options: | ||
:type device_create_options: ~mailosaur.models.DeviceCreateOptions | ||
:return: Device | ||
:rtype: ~mailosaur.models.Device | ||
:raises: | ||
:class:`MailosaurException<mailosaur.models.MailosaurException>` | ||
""" | ||
url = "%sapi/devices" % (self.base_url) | ||
response = self.session.post(url, json=device_create_options.to_json()) | ||
|
||
if response.status_code not in [200]: | ||
self.handle_http_error(response) | ||
return | ||
|
||
data = response.json() | ||
|
||
return Device(data) | ||
|
||
def otp(self, query): | ||
"""Retrieves the current one-time password for a saved device, or given base32-encoded shared secret. | ||
Retrieves the detail for a single server. Simply supply the unique | ||
identifier for the required server. | ||
:param query: Either the unique identifier of the device, or a base32-encoded shared secret. | ||
:type query: str | ||
:return: OtpResult | ||
:rtype: ~mailosaur.models.OtpResult | ||
:raises: | ||
:class:`MailosaurException<mailosaur.models.MailosaurException>` | ||
""" | ||
if "-" in query: | ||
url = "%sapi/devices/%s/otp" % (self.base_url, query) | ||
response = self.session.get(url) | ||
|
||
if response.status_code not in [200]: | ||
self.handle_http_error(response) | ||
return | ||
|
||
data = response.json() | ||
|
||
return OtpResult(data) | ||
|
||
url = "%sapi/devices/otp" % (self.base_url) | ||
response = self.session.post(url, json={'sharedSecret': query}) | ||
|
||
if response.status_code not in [200]: | ||
self.handle_http_error(response) | ||
return | ||
|
||
data = response.json() | ||
|
||
return OtpResult(data) | ||
|
||
def delete( | ||
self, id): | ||
"""Delete a device. | ||
Permanently delete a virtual security device. This operation cannot be undone. | ||
:param id: The identifier of the device to be deleted. | ||
:type id: str | ||
:return: None | ||
:rtype: None | ||
:raises: | ||
:class:`MailosaurException<mailosaur.models.MailosaurException>` | ||
""" | ||
url = "%sapi/devices/%s" % (self.base_url, id) | ||
response = self.session.delete(url) | ||
|
||
if response.status_code not in [204]: | ||
self.handle_http_error(response) | ||
return |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import os | ||
import numbers | ||
from unittest import TestCase | ||
from mailosaur import MailosaurClient | ||
from mailosaur.models import DeviceCreateOptions, MailosaurException | ||
|
||
|
||
class DevicesTest(TestCase): | ||
@classmethod | ||
def setUpClass(self): | ||
api_key = os.getenv('MAILOSAUR_API_KEY') | ||
base_url = os.getenv('MAILOSAUR_BASE_URL') | ||
|
||
if api_key is None: | ||
raise Exception( | ||
"Missing necessary environment variables - refer to README.md") | ||
|
||
self.client = MailosaurClient(api_key, base_url) | ||
|
||
def test_crud(self): | ||
device_name = "My test" | ||
shared_secret = "ONSWG4TFOQYTEMY=" | ||
|
||
# Create a new device | ||
options = DeviceCreateOptions() | ||
options.name = device_name | ||
options.shared_secret = shared_secret | ||
|
||
created_device = self.client.devices.create(options) | ||
self.assertIsNotNone(created_device.id) | ||
self.assertEqual(device_name, created_device.name) | ||
|
||
# Retrieve an otp via device ID | ||
otp_result = self.client.devices.otp(created_device.id) | ||
self.assertEqual(6, len(otp_result.code)) | ||
|
||
list_result = self.client.devices.list() | ||
self.assertEqual(1, len(list_result.items)) | ||
self.client.devices.delete(created_device.id) | ||
list_result = self.client.devices.list() | ||
self.assertEqual(0, len(list_result.items)) | ||
|
||
def test_otp_via_shared_secret(self): | ||
shared_secret = "ONSWG4TFOQYTEMY=" | ||
|
||
otp_result = self.client.devices.otp(shared_secret) | ||
self.assertEqual(6, len(otp_result.code)) |