Skip to content
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
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
author='Dev Piekstra',
author_email='piekstra.dev@gmail.com',
packages=find_packages(exclude=("tests",)),
package_data={
'tplinkcloud': ['certs/*.pem'],
},
version=__version__,
description='Python library for communicating with the TP-Link Cloud API to manage TP-Link Kasa Smart Home devices',
long_description=long_description,
Expand All @@ -21,7 +24,7 @@
'aiohttp>=3,<4'
],
url='https://github.com/piekstra/tplink-cloud-api',
python_requires='>=3.7',
python_requires='>=3.10',
zip_safe=False,
license='GPL-3',
classifiers=[
Expand Down
12 changes: 12 additions & 0 deletions tplinkcloud/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
from .device_manager import TPLinkDeviceManager
from .device_manager_power_tools import TPLinkDeviceManagerPowerTools
from .device_schedule_rule_builder import TPLinkDeviceScheduleRuleBuilder
from .exceptions import (
TPLinkAuthError,
TPLinkCloudError,
TPLinkDeviceOfflineError,
TPLinkMFARequiredError,
TPLinkTokenExpiredError,
)

__all__ = [
'TPLinkDeviceManager',
'TPLinkDeviceManagerPowerTools',
'TPLinkDeviceScheduleRuleBuilder',
'TPLinkAuthError',
'TPLinkCloudError',
'TPLinkDeviceOfflineError',
'TPLinkMFARequiredError',
'TPLinkTokenExpiredError',
]

# Windows OS-specific HACK to silence exception thrown on event loop being closed
Expand Down
8 changes: 8 additions & 0 deletions tplinkcloud/api_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ def __init__(self, response):
def successful(self):
return self._response.get('error_code') == 0

@property
def error_code(self):
return self._response.get('error_code')

@property
def result(self):
return self._response.get('result')

@property
def msg(self):
return self._response.get('msg')
19 changes: 19 additions & 0 deletions tplinkcloud/certs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""TP-Link CA certificate chain for V2 API SSL verification."""

from importlib import resources


def get_ca_cert_path() -> str:
"""Get the filesystem path to the bundled TP-Link CA certificate chain.

The V2 API servers (n-*.tplinkcloud.com) use TP-Link's private CA,
which is not in the system trust store. This chain includes:
- Root: tp-link-CA
- Intermediate: TP-LINK CA P1
- Leaf: *.tplinkcloud.com
"""
ref = resources.files(__package__) / "tplink-ca-chain.pem"
# resources.as_file extracts to a temp location if needed (e.g. from a zip)
# but for a regular install the path is stable
with resources.as_file(ref) as path:
return str(path)
70 changes: 70 additions & 0 deletions tplinkcloud/certs/tplink-ca-chain.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
-----BEGIN CERTIFICATE-----
MIIEfTCCA2WgAwIBAgITZAAAAVRNT7bhOPHCcwABAAABVDANBgkqhkiG9w0BAQsF
ADBaMRIwEAYKCZImiZPyLGQBGRYCY24xEzARBgoJkiaJk/IsZAEZFgNjb20xFzAV
BgoJkiaJk/IsZAEZFgd0cC1saW5rMRYwFAYDVQQDEw1UUC1MSU5LIENBIFAxMB4X
DTI1MTAyODAwMjY1MVoXDTI2MTAyODAwMjY1MVowWDELMAkGA1UEBhMCVVMxDzAN
BgNVBAcTBklydmluZTEcMBoGA1UEChMTVFAtTElOSyBHTE9CQUwgSU5DLjEaMBgG
A1UEAwwRKi50cGxpbmtjbG91ZC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCtdXbGKixzsYaEjaqs7TM/zUxRx9RcK/sKXJxUjZuIfhzo4KJ51d6D
OTkXdgcYdDdYh+1jpcetitHw/Jd8rUT4xdvpBVSEVFnK1x97ADaPrxd+o7LGpAi8
dlvPWO3d3zw4YdOTNVhcajCbuJ5sKV0HGSBzSPzYsqpghmwFB3Kfjtq/e4q1NVZw
WWFgzq3iZ2rmPYACrn/MoVRQlNzFdOZ/X0SrvjJbLTWbQ5TuUBpJEL21BEKHn0F+
Yo3Z+QPGRGiCV574xMgiGhMlkxGScS4y809HTvIz4AFbOOy6M2yJmS2x+fIkt//J
wMEkydfMcAhaz0JrevqVPEsrz3zaco+5AgMBAAGjggE8MIIBODAOBgNVHQ8BAf8E
BAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwLQYDVR0RBCYwJIIRKi50cGxpbmtj
bG91ZC5jb22CD3RwbGlua2Nsb3VkLmNvbTAdBgNVHQ4EFgQUp67HKroMq2OsBpcm
Ne64r49PjQ8wHwYDVR0jBBgwFoAUVQi1z4hvsNPAlOf6v6KN9JRW0l4wRwYDVR0f
BEAwPjA8oDqgOIY2aHR0cDovL3RwY3JsLnRwLWxpbmsuY29tLmNuL2NlcnRkYXRh
L1RQLUxJTktfQ0FfUDEuY3JsMDwGCSsGAQQBgjcVBwQvMC0GJSsGAQQBgjcVCIap
mz6E6u1+hsWVAbeERIfEoHBHhcD9C4XOlVMCAWQCAQswGwYJKwYBBAGCNxUKBA4w
DDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEAr4tMuesR2EoVFkZryo5U
49aOZ6mbLr0YTtRx3ZFJehXEPtzUAK2yDyXHLtiUQ1e2uBzJnqNB6Qi6lEISL9fu
nvd+xcZvE4H40Woj0TwT9GJwbHIrCu+1QmtJYCTWOjkjTb+kN8ueEHlTGaCn5W9B
2oQ0M0+MC1iKjAjYLJrnXnO63KVhfKFaCsys2tY7A9COA9y/JSX2JAdMoFQrygM6
X9lydmEhrzQT/n8uk6hiRDdeFm6jXEejQZ1GvFNwZDVIgUzlp8W9qQm3x6IDRTx7
ZE/Fwq/Ixk8WKwfPlJOhNsqKguwFPXe6S0pEMbOGX067yObBarULC4CCW+GRrdHJ
EA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIID+DCCAuCgAwIBAgITdAAAAAdZrje7ktFgcAAAAAAABzANBgkqhkiG9w0BAQsF
ADAVMRMwEQYDVQQDEwp0cC1saW5rLUNBMCAXDTIwMDUxOTA5MjEwMloYDzIwNjgw
MTE5MDgzNzUyWjBaMRIwEAYKCZImiZPyLGQBGRYCY24xEzARBgoJkiaJk/IsZAEZ
FgNjb20xFzAVBgoJkiaJk/IsZAEZFgd0cC1saW5rMRYwFAYDVQQDEw1UUC1MSU5L
IENBIFAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv4DMrSRNtjjt
P+1swNtCCthsOCiyy4+v5fFilnP5GPFbTgiOjUA1SMmWqrhDCHG8ZC2HrCIm7/Oj
O41M7IHbr0HHwMOrm4rkeucvuCu1Hmrh47L0YK872aWTlMcqL2Lt2sJJpl7kZhH0
LVWlYPQSXRgOZE6I+UsgUfksf4H7lH1mReYjTa8uzQJzN14IrCUzMc6lAZxMR/fr
zQ2hXbn4P+hGDBtw2k8Zj5rZJm6ALTpe/JGiR04ocOqRhldJYYoijhfqcpp7racT
tbo4wrz4dpfmZQv1K7ZOkAi79lEjTFE6OiSMJAkxL3ObOB3h7qkcjlb9xXgpGWJQ
ylLhFNHnzQIDAQABo4H5MIH2MBAGCSsGAQQBgjcVAQQDAgEBMCMGCSsGAQQBgjcV
AgQWBBRskYoxJ4QIQK+6xIr4syb5p3hJ+zAdBgNVHQ4EFgQUVQi1z4hvsNPAlOf6
v6KN9JRW0l4wGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGG
MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUxu2iBRTsef5iNnsADVhMJDQW
i6kwRAYDVR0fBD0wOzA5oDegNYYzaHR0cDovL3RwY3JsLnRwLWxpbmsuY29tLmNu
L2NlcnRkYXRhL3RwLWxpbmstQ0EuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQArzgXJ
ZORRDC3hSu0zoAWWn4bUaXy+1K2fbkkfceJc1yQUnx7WhVOtPiuCFYp5qraSUVHk
vFVFEUY2Jhdk1uP7lXQuU81XuCisMA2VoNcOL9blVyturewyN8YWmWhptjeYKEPy
SEUUTTkKjqdsWFwxqyDrwom70Ev+TOZfyF8O8IQCoj1Lv0wcEE1B+HGdVboitJUA
f4+tJg8bqahrZrFMSTVttuRxkIYupPlhFhY880/ptuUy2taRkhDP2717dUdB9KsQ
/xeRvYXgPbK1o4esNjmftMcziWanTLTT/DwQv/8j8J32gGojNtuX8NzYfqx8gxMQ
RUH9G1c+dc3etM0K
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDBzCCAe+gAwIBAgIQT5x0ma7QnINHCQvhnmzR9zANBgkqhkiG9w0BAQsFADAV
MRMwEQYDVQQDEwp0cC1saW5rLUNBMCAXDTE4MDExOTA4Mjc1MloYDzIwNjgwMTE5
MDgzNzUyWjAVMRMwEQYDVQQDEwp0cC1saW5rLUNBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAuGG8n5zEUN1j5wuvUz4pAIMurhKHbpfUUu+b2acFHKS6
iU9hNJWvDyhXcihY5Wz6aq9m4D5SZcgW3k31YoNNtrztDjdg2qw7AaX85S99/G0B
VbIXktrhs34OW19WA/haDwut3dFhLem+gCRRKUXcmuqchZc84dY7JFVfhPcJci4m
sRjLCFNO0ho9OX+MZwfO4BLaeAqKVoAor6rf4BXVtO0xjYHDKO0fb3AWLLJ4EjGe
q6YieqPiYlPFEqRm5PrvBXTm0IuQogygyVpK4LHr/K207ZLyV33DxLLbsUgSEJVn
pZUv/WUujXjlIDgxIvyZZCYiXO3dle2/MEvpmZk6JQIDAQABo1EwTzALBgNVHQ8E
BAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUxu2iBRTsef5iNnsADVhM
JDQWi6kwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQELBQADggEBAB52Majd
+wo3cb5BsTo63z2Psbbyl4ACMUaw68NxUMy61Oihx3mcLzLJqiIZcKePiHskLqLJ
F7QfT9TqjvizMjFJVgsLuVubUBXKBzqyN+3KKlQci0PO3mH+ObhyaE7BzV+qrS3P
dVTgsCWFv8DkgLTRudSWxL7VwVoedc7lRz5EroGgJ33nRGCR0ngcW919tLTARDQO
pULmzulcdWeZgG+0PLX0xjJQIjFEvbOxR1Z+gxMupBz0rWFokmWYrcga8eWiWzjQ
Ia3/ASBVJ69srV77trWlfLumkChbXk9i64NXBKnce0Jmll0Y9OC1nMPqrbQKnzcn
dSAA4fejD/qMQn0=
-----END CERTIFICATE-----
Loading
Loading